changeset 85:e718a69f7d99

Observers: use weak keys, renamed some fns.
author Mikhail Kryshen <mikhail@kryshen.net>
date Fri, 01 Oct 2010 18:45:17 +0400
parents b04bdeec5700
children 069ea63803a2
files project.clj src/net/kryshen/indyvon/async.clj src/net/kryshen/indyvon/component.clj src/net/kryshen/indyvon/core.clj
diffstat 4 files changed, 41 insertions(+), 34 deletions(-) [+]
line diff
     1.1 --- a/project.clj	Wed Sep 08 04:40:05 2010 +0400
     1.2 +++ b/project.clj	Fri Oct 01 18:45:17 2010 +0400
     1.3 @@ -2,7 +2,8 @@
     1.4    :description "INteractive DYnamic VisualizatiON library"
     1.5    ;;:warn-on-reflection true
     1.6    :dependencies [[org.clojure/clojure "1.2.0"]
     1.7 -                 [org.clojure/clojure-contrib "1.2.0"]]
     1.8 +                 [org.clojure/clojure-contrib "1.2.0"]
     1.9 +                 [com.google.guava/guava "r07"]]
    1.10    :dev-dependencies [[swank-clojure/swank-clojure "1.2.1"]]
    1.11    :namespaces [net.kryshen.indyvon.core
    1.12                 net.kryshen.indyvon.async
     2.1 --- a/src/net/kryshen/indyvon/async.clj	Wed Sep 08 04:40:05 2010 +0400
     2.2 +++ b/src/net/kryshen/indyvon/async.clj	Fri Oct 01 18:45:17 2010 +0400
     2.3 @@ -127,7 +127,7 @@
     2.4    Layer
     2.5    (render! [layer]
     2.6      (repaint-on-update layer)
     2.7 -    (add-context-observer content (fn [_] (draw-offscreen-async layer)))
     2.8 +    (add-context-observer content (fn [_ _] (draw-offscreen-async layer)))
     2.9      (when-not @buffers
    2.10        ;; TODO: dynamic size, recreate buffers when size increases.
    2.11        (let [new-buffers (repeatedly 2 (partial create-buffer layer))]
     3.1 --- a/src/net/kryshen/indyvon/component.clj	Wed Sep 08 04:40:05 2010 +0400
     3.2 +++ b/src/net/kryshen/indyvon/component.clj	Fri Oct 01 18:45:17 2010 +0400
     3.3 @@ -44,7 +44,12 @@
     3.4                 (let [s (root-size layer (font-context this) this)]
     3.5                   (Dimension. (:width s) (:height s)))))]
     3.6         (.setBackground panel (:back-color *theme*))
     3.7 -       (add-observer panel layer (fn [_] (.repaint panel)))
     3.8 +       (add-observer panel layer (fn [w _]
     3.9 +                                   ;; Use the first observer argument
    3.10 +                                   ;; instead of closing over panel to
    3.11 +                                   ;; allow the panel and associated
    3.12 +                                   ;; observer to be gc'd.
    3.13 +                                   (.repaint ^Component w)))
    3.14         (listen! event-dispatcher panel)
    3.15         panel)))
    3.16  
     4.1 --- a/src/net/kryshen/indyvon/core.clj	Wed Sep 08 04:40:05 2010 +0400
     4.2 +++ b/src/net/kryshen/indyvon/core.clj	Fri Oct 01 18:45:17 2010 +0400
     4.3 @@ -22,7 +22,8 @@
     4.4     (java.awt Graphics2D RenderingHints Component Color Font Shape)
     4.5     (java.awt.geom AffineTransform Point2D$Double Rectangle2D$Double Area)
     4.6     (java.awt.event MouseListener MouseMotionListener)
     4.7 -   (java.awt.font FontRenderContext)))
     4.8 +   (java.awt.font FontRenderContext)
     4.9 +   (com.google.common.collect MapMaker)))
    4.10  
    4.11  ;;
    4.12  ;; Layer context
    4.13 @@ -135,43 +136,43 @@
    4.14  (defn- assoc-cons [m key val]
    4.15    (->> (get m key) (cons val) (assoc m key)))
    4.16  
    4.17 -(defn- assoc-in-cons [m keys val]
    4.18 -  (->> (get-in m keys) (cons val) (assoc-in m keys)))
    4.19 -
    4.20  ;;
    4.21  ;; Observers
    4.22 +;; The mechanism used by layers to request repaints
    4.23  ;;
    4.24  
    4.25 -(def observers (atom nil))
    4.26 +(def ^java.util.Map observers
    4.27 +     (-> (MapMaker.) (.weakKeys) (.makeMap)))
    4.28  
    4.29 -;; TODO: groups should be weakly referenced.
    4.30  (defn add-observer
    4.31 -  "Add observer fn for the target to the specified group."
    4.32 -  [group target f]
    4.33 -  (swap! observers assoc-in-cons [group target] f)
    4.34 +  "Add observer fn for the target. Watcher identifies the group of
    4.35 +  observers and could be used to remove the group. Watcher is weakly
    4.36 +  referenced, all associated observers will be removed when the
    4.37 +  wathcer is removed by gc. The observer fn will be called with
    4.38 +  watcher and target arguments and any additional arguments specified
    4.39 +  in update call."
    4.40 +  [watcher target f]
    4.41 +  (.put observers watcher (assoc-cons (.get observers watcher) target f))
    4.42    nil)
    4.43  
    4.44 -(defn remove-observer-group
    4.45 -  "Remove group of observers."
    4.46 -  [group]
    4.47 -  (swap! observers dissoc group)
    4.48 +(defn remove-observers
    4.49 +  "Remove group of observers associated with the specified watcher."
    4.50 +  [watcher]
    4.51 +  (.remove observers watcher)
    4.52    nil)
    4.53  
    4.54 -(defn- replace-observer-group*
    4.55 -  [observers old-id new-id]
    4.56 -  (let [group (get observers old-id)]
    4.57 -    (assoc (dissoc observers old-id)
    4.58 -      new-id group)))
    4.59 -
    4.60 -(defn- replace-observer-group
    4.61 -  [old-id new-id]
    4.62 -  (swap! observers replace-observer-group* old-id new-id))
    4.63 +(defn- replace-observers-watcher
    4.64 +  [old-watcher new-watcher]
    4.65 +  (if-let [old (.remove observers old-watcher)]
    4.66 +    (.put observers new-watcher old))
    4.67 +  nil)
    4.68  
    4.69  (defn update
    4.70    "Notify observers."
    4.71    [target & args]
    4.72 -  (doseq [f (reduce #(concat %1 (get %2 target)) nil (vals @observers))]
    4.73 -    (apply f target args)))
    4.74 +  (doseq [entry observers
    4.75 +          f (get (val entry) target)]
    4.76 +    (apply f (key entry) target args)))
    4.77  
    4.78  (defn add-context-observer
    4.79    "Observer registered with this function will be automatically
    4.80 @@ -185,7 +186,7 @@
    4.81    [target]
    4.82    (let [root *root*]
    4.83      (if (not= root target)
    4.84 -      (add-observer root target (fn [_] (update root))))))
    4.85 +      (add-observer root target (fn [w _] (update w))))))
    4.86  
    4.87  (defn repaint
    4.88    "Repaint the current scene."
    4.89 @@ -347,15 +348,15 @@
    4.90         (apply-theme)
    4.91         (with-color (:back-color *theme*)
    4.92           (.fillRect graphics 0 0 width height))
    4.93 -       (let [tmp-group (Object.)]
    4.94 -         ;; Keep current context observers until the rendering is complete.
    4.95 -         ;; Some observers may be invoked twice if they appear in both
    4.96 -         ;; groups until tmp-group is removed.
    4.97 -         (replace-observer-group layer tmp-group)
    4.98 +       (let [tmp-watcher (Object.)]
    4.99 +         ;; Keep current context observers until the rendering is
   4.100 +         ;; complete. Some observers may be invoked twice if they
   4.101 +         ;; appear in both groups until tmp-watcher is removed.
   4.102 +         (replace-observers-watcher layer tmp-watcher)
   4.103           (try
   4.104             (render! layer)
   4.105             (finally
   4.106 -            (remove-observer-group tmp-group)
   4.107 +            (remove-observers tmp-watcher)
   4.108              (commit event-dispatcher)))))))
   4.109  
   4.110  (defn root-size