[geary/wip/disconnect-lambdas-726295] Rough stab at removing event listeners on shutdown



commit da71fb69602b28faad3bf75c719b98cab1d0e991
Author: Charles Lindsay <chaz yorba org>
Date:   Fri Mar 14 13:00:57 2014 -0700

    Rough stab at removing event listeners on shutdown

 .../conversation-viewer/conversation-viewer.vala   |   57 +++++++++++++-------
 src/client/util/util-webkit.vala                   |    6 ++-
 2 files changed, 42 insertions(+), 21 deletions(-)
---
diff --git a/src/client/conversation-viewer/conversation-viewer.vala 
b/src/client/conversation-viewer/conversation-viewer.vala
index d81fb1c..a91b086 100644
--- a/src/client/conversation-viewer/conversation-viewer.vala
+++ b/src/client/conversation-viewer/conversation-viewer.vala
@@ -148,6 +148,8 @@ public class ConversationViewer : Gtk.Box {
     private Geary.State.Machine fsm;
     private DisplayMode display_mode = DisplayMode.NONE;
     private uint select_conversation_timeout_id = 0;
+    private Gee.HashMap<WebKit.DOM.NodeList, Callback> bound_events
+        = new Gee.HashMap<WebKit.DOM.NodeList, Callback>();
     
     public ConversationViewer() {
         Object(orientation: Gtk.Orientation.VERTICAL, spacing: 0);
@@ -201,6 +203,16 @@ public class ConversationViewer : Gtk.Box {
         pack_start(conversation_find_bar, false);
     }
     
+    ~ConversationViewer() {
+        foreach (WebKit.DOM.NodeList list in bound_events.keys) {
+            for (int i = 0; i < list.length; ++i) {
+                WebKit.DOM.EventTarget node = list.item(i) as WebKit.DOM.EventTarget;
+                node.remove_event_listener("click", bound_events.get(list), false);
+                node.remove_event_listener("contextmenu", bound_events.get(list), false);
+            }
+        }
+    }
+    
     public Geary.Email? get_last_message() {
         return messages.is_empty ? null : messages.last();
     }
@@ -569,29 +581,36 @@ public class ConversationViewer : Gtk.Box {
         });
         
         // Attach to the click events for hiding/showing quotes, opening the menu, and so forth.
-        bind_event(web_view, ".email", "contextmenu", (Callback) on_context_menu, this);
-        bind_event(web_view, ".quote_container > .hider", "click", (Callback) on_hide_quote_clicked);
-        bind_event(web_view, ".quote_container > .shower", "click", (Callback) on_show_quote_clicked);
-        bind_event(web_view, ".email_container .menu", "click", (Callback) on_menu_clicked, this);
-        bind_event(web_view, ".email_container .starred", "click", (Callback) on_unstar_clicked, this);
-        bind_event(web_view, ".email_container .unstarred", "click", (Callback) on_star_clicked, this);
-        bind_event(web_view, ".email_container .draft_edit .button", "click", (Callback) on_draft_edit_menu, 
this);
-        bind_event(web_view, ".header .field .value", "click", (Callback) on_value_clicked, this);
-        bind_event(web_view, ".email:not(:only-of-type) .header_container, .email .email 
.header_container","click", (Callback) on_body_toggle_clicked, this);
-        bind_event(web_view, ".email .compressed_note", "click", (Callback) on_body_toggle_clicked, this);
-        bind_event(web_view, ".attachment_container .attachment", "click", (Callback) on_attachment_clicked, 
this);
-        bind_event(web_view, ".attachment_container .attachment", "contextmenu", (Callback) 
on_attachment_menu, this);
-        bind_event(web_view, "." + DATA_IMAGE_CLASS, "contextmenu", (Callback) on_data_image_menu, this);
-        bind_event(web_view, ".remote_images .show_images", "click", (Callback) on_show_images, this);
-        bind_event(web_view, ".remote_images .show_from", "click", (Callback) on_show_images_from, this);
-        bind_event(web_view, ".remote_images .close_show_images", "click", (Callback) on_close_show_images, 
this);
-        bind_event(web_view, ".body a", "click", (Callback) on_link_clicked, this);
+        bind_event(".email", "contextmenu", (Callback) on_context_menu, true);
+        bind_event(".quote_container > .hider", "click", (Callback) on_hide_quote_clicked, false);
+        bind_event(".quote_container > .shower", "click", (Callback) on_show_quote_clicked, false);
+        bind_event(".email_container .menu", "click", (Callback) on_menu_clicked, true);
+        bind_event(".email_container .starred", "click", (Callback) on_unstar_clicked, true);
+        bind_event(".email_container .unstarred", "click", (Callback) on_star_clicked, true);
+        bind_event(".email_container .draft_edit .button", "click", (Callback) on_draft_edit_menu, true);
+        bind_event(".header .field .value", "click", (Callback) on_value_clicked, true);
+        bind_event(".email:not(:only-of-type) .header_container, .email .email .header_container","click", 
(Callback) on_body_toggle_clicked, true);
+        bind_event(".email .compressed_note", "click", (Callback) on_body_toggle_clicked, true);
+        bind_event(".attachment_container .attachment", "click", (Callback) on_attachment_clicked, true);
+        bind_event(".attachment_container .attachment", "contextmenu", (Callback) on_attachment_menu, true);
+        bind_event("." + DATA_IMAGE_CLASS, "contextmenu", (Callback) on_data_image_menu, true);
+        bind_event(".remote_images .show_images", "click", (Callback) on_show_images, true);
+        bind_event(".remote_images .show_from", "click", (Callback) on_show_images_from, true);
+        bind_event(".remote_images .close_show_images", "click", (Callback) on_close_show_images, true);
+        bind_event(".body a", "click", (Callback) on_link_clicked, true);
         
         // Update the search results
         if (conversation_find_bar.visible)
             conversation_find_bar.commence_search();
     }
     
+    private void bind_event(string selector, string event, Callback callback, bool pass_this) {
+        WebKit.DOM.NodeList? node_list = global::bind_event(
+            web_view, selector, event, callback, (pass_this ? this : null));
+        if (node_list != null)
+            bound_events.set(node_list, callback);
+    }
+    
     private WebKit.DOM.HTMLElement make_email_div() {
         // The HTML is like this:
         // <div id="$MESSAGE_ID" class="email">
@@ -1277,8 +1296,8 @@ public class ConversationViewer : Gtk.Box {
         } catch (Error error) {
             warning("Error showing link warning dialog: %s", error.message);
         }
-        bind_event(web_view, ".link_warning .close_link_warning, .link_warning a", "click",
-            (Callback) on_close_link_warning, this);
+        bind_event(".link_warning .close_link_warning, .link_warning a", "click",
+            (Callback) on_close_link_warning, true);
         return true;
     }
     
diff --git a/src/client/util/util-webkit.vala b/src/client/util/util-webkit.vala
index 81bf5d8..390ee08 100644
--- a/src/client/util/util-webkit.vala
+++ b/src/client/util/util-webkit.vala
@@ -111,8 +111,8 @@ namespace Util.DOM {
     }
 }
 
-public void bind_event(WebKit.WebView view, string selector, string event, Callback callback,
-    Object? extra = null) {
+public WebKit.DOM.NodeList? bind_event(WebKit.WebView view, string selector,
+    string event, Callback callback, Object? extra = null) {
     try {
         WebKit.DOM.NodeList node_list = view.get_dom_document().query_selector_all(selector);
         for (int i = 0; i < node_list.length; ++i) {
@@ -120,8 +120,10 @@ public void bind_event(WebKit.WebView view, string selector, string event, Callb
             node.remove_event_listener(event, callback, false);
             node.add_event_listener(event, callback, false, extra);
         }
+        return node_list;
     } catch (Error error) {
         warning("Error setting up click handlers: %s", error.message);
+        return null;
     }
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]