Mercurial > hg > indyvon
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 wrap: on
line diff
--- a/project.clj Wed Sep 08 04:40:05 2010 +0400 +++ b/project.clj Fri Oct 01 18:45:17 2010 +0400 @@ -2,7 +2,8 @@ :description "INteractive DYnamic VisualizatiON library" ;;:warn-on-reflection true :dependencies [[org.clojure/clojure "1.2.0"] - [org.clojure/clojure-contrib "1.2.0"]] + [org.clojure/clojure-contrib "1.2.0"] + [com.google.guava/guava "r07"]] :dev-dependencies [[swank-clojure/swank-clojure "1.2.1"]] :namespaces [net.kryshen.indyvon.core net.kryshen.indyvon.async
--- a/src/net/kryshen/indyvon/async.clj Wed Sep 08 04:40:05 2010 +0400 +++ b/src/net/kryshen/indyvon/async.clj Fri Oct 01 18:45:17 2010 +0400 @@ -127,7 +127,7 @@ Layer (render! [layer] (repaint-on-update layer) - (add-context-observer content (fn [_] (draw-offscreen-async layer))) + (add-context-observer content (fn [_ _] (draw-offscreen-async layer))) (when-not @buffers ;; TODO: dynamic size, recreate buffers when size increases. (let [new-buffers (repeatedly 2 (partial create-buffer layer))]
--- a/src/net/kryshen/indyvon/component.clj Wed Sep 08 04:40:05 2010 +0400 +++ b/src/net/kryshen/indyvon/component.clj Fri Oct 01 18:45:17 2010 +0400 @@ -44,7 +44,12 @@ (let [s (root-size layer (font-context this) this)] (Dimension. (:width s) (:height s)))))] (.setBackground panel (:back-color *theme*)) - (add-observer panel layer (fn [_] (.repaint panel))) + (add-observer panel layer (fn [w _] + ;; Use the first observer argument + ;; instead of closing over panel to + ;; allow the panel and associated + ;; observer to be gc'd. + (.repaint ^Component w))) (listen! event-dispatcher panel) panel)))
--- a/src/net/kryshen/indyvon/core.clj Wed Sep 08 04:40:05 2010 +0400 +++ b/src/net/kryshen/indyvon/core.clj Fri Oct 01 18:45:17 2010 +0400 @@ -22,7 +22,8 @@ (java.awt Graphics2D RenderingHints Component Color Font Shape) (java.awt.geom AffineTransform Point2D$Double Rectangle2D$Double Area) (java.awt.event MouseListener MouseMotionListener) - (java.awt.font FontRenderContext))) + (java.awt.font FontRenderContext) + (com.google.common.collect MapMaker))) ;; ;; Layer context @@ -135,43 +136,43 @@ (defn- assoc-cons [m key val] (->> (get m key) (cons val) (assoc m key))) -(defn- assoc-in-cons [m keys val] - (->> (get-in m keys) (cons val) (assoc-in m keys))) - ;; ;; Observers +;; The mechanism used by layers to request repaints ;; -(def observers (atom nil)) +(def ^java.util.Map observers + (-> (MapMaker.) (.weakKeys) (.makeMap))) -;; TODO: groups should be weakly referenced. (defn add-observer - "Add observer fn for the target to the specified group." - [group target f] - (swap! observers assoc-in-cons [group target] f) + "Add observer fn for the target. Watcher identifies the group of + observers and could be used to remove the group. Watcher is weakly + referenced, all associated observers will be removed when the + wathcer is removed by gc. The observer fn will be called with + watcher and target arguments and any additional arguments specified + in update call." + [watcher target f] + (.put observers watcher (assoc-cons (.get observers watcher) target f)) nil) -(defn remove-observer-group - "Remove group of observers." - [group] - (swap! observers dissoc group) +(defn remove-observers + "Remove group of observers associated with the specified watcher." + [watcher] + (.remove observers watcher) nil) -(defn- replace-observer-group* - [observers old-id new-id] - (let [group (get observers old-id)] - (assoc (dissoc observers old-id) - new-id group))) - -(defn- replace-observer-group - [old-id new-id] - (swap! observers replace-observer-group* old-id new-id)) +(defn- replace-observers-watcher + [old-watcher new-watcher] + (if-let [old (.remove observers old-watcher)] + (.put observers new-watcher old)) + nil) (defn update "Notify observers." [target & args] - (doseq [f (reduce #(concat %1 (get %2 target)) nil (vals @observers))] - (apply f target args))) + (doseq [entry observers + f (get (val entry) target)] + (apply f (key entry) target args))) (defn add-context-observer "Observer registered with this function will be automatically @@ -185,7 +186,7 @@ [target] (let [root *root*] (if (not= root target) - (add-observer root target (fn [_] (update root)))))) + (add-observer root target (fn [w _] (update w)))))) (defn repaint "Repaint the current scene." @@ -347,15 +348,15 @@ (apply-theme) (with-color (:back-color *theme*) (.fillRect graphics 0 0 width height)) - (let [tmp-group (Object.)] - ;; Keep current context observers until the rendering is complete. - ;; Some observers may be invoked twice if they appear in both - ;; groups until tmp-group is removed. - (replace-observer-group layer tmp-group) + (let [tmp-watcher (Object.)] + ;; Keep current context observers until the rendering is + ;; complete. Some observers may be invoked twice if they + ;; appear in both groups until tmp-watcher is removed. + (replace-observers-watcher layer tmp-watcher) (try (render! layer) (finally - (remove-observer-group tmp-group) + (remove-observers tmp-watcher) (commit event-dispatcher))))))) (defn root-size