Only register for events when something is listening
authorMike Gorse <mgorse@novell.com>
Tue, 21 Jun 2011 22:16:07 +0000 (17:16 -0500)
committerMike Gorse <mgorse@novell.com>
Tue, 21 Jun 2011 22:16:07 +0000 (17:16 -0500)
Track whether clients are listening, based on calls to GetItems and
event listener registrations, and disable event handlers if no clients
are listening.  Note that this currently handles event listeners in bulk
and could be refined to only connect to individual signals that are
being listened to.

atk-adaptor/adaptors/application-adaptor.c
atk-adaptor/adaptors/cache-adaptor.c
atk-adaptor/bridge.c
atk-adaptor/bridge.h
atk-adaptor/event.c

index 897ed55..c686c31 100644 (file)
@@ -101,6 +101,9 @@ impl_get_app_bus(DBusConnection *bus, DBusMessage *msg, void *data)
 {
 DBusMessage *reply;
 
+  if (bus == spi_global_app_data->bus)
+    spi_atk_add_client (dbus_message_get_sender (msg));
+
 reply = dbus_message_new_method_return(msg);
 if (reply)
     {
index 3b6b28c..0aff2bd 100644 (file)
@@ -291,6 +291,9 @@ impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
   DBusMessage *reply;
   DBusMessageIter iter, iter_array;
 
+  if (bus == spi_global_app_data->bus)
+    spi_atk_add_client (dbus_message_get_sender (message));
+
   reply = dbus_message_new_method_return (message);
 
   dbus_message_iter_init_append (reply, &iter);
index 51b12bc..6aacd12 100644 (file)
@@ -117,6 +117,7 @@ add_event (const char *bus_name, const char *event)
   gchar **data;
   GList *new_list;
 
+  spi_atk_add_client (bus_name);
   evdata = (event_data *) g_malloc (sizeof (*evdata));
   if (!evdata)
     return;
@@ -133,6 +134,8 @@ add_event (const char *bus_name, const char *event)
     spi_global_app_data->events = new_list;
 }
 
+static GSList *clients = NULL;
+
 static void
 get_registered_event_listeners (SpiBridge *app)
 {
@@ -143,18 +146,21 @@ get_registered_event_listeners (SpiBridge *app)
                                          SPI_DBUS_PATH_REGISTRY,
                                          SPI_DBUS_INTERFACE_REGISTRY,
                                          "GetRegisteredEvents");
-  spi_global_app_data->events_initialized = TRUE;
   if (!message)
     return;
 
   reply = dbus_connection_send_with_reply_and_block (app->bus, message, 5000, NULL);
   dbus_message_unref (message);
   if (!reply)
-    return;
+    {
+      spi_global_app_data->events_initialized = TRUE;
+      return;
+    }
   if (strcmp (dbus_message_get_signature (reply), "a(ss)") != 0)
     {
-      /* TODO: Add a warning when it's okay to add strings */
+      g_warning ("atk-bridge: GetRegisteredEvents returned message with unknown signature");
       dbus_message_unref (reply);
+      spi_global_app_data->events_initialized = TRUE;
       return;
     }
   dbus_message_iter_init (reply, &iter);
@@ -170,6 +176,10 @@ get_registered_event_listeners (SpiBridge *app)
       dbus_message_iter_next (&iter_array);
     }
   dbus_message_unref (reply);
+
+  if (!clients)
+    spi_atk_deregister_event_listeners ();
+  spi_global_app_data->events_initialized = TRUE;
 }
 
 static void
@@ -628,6 +638,23 @@ signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data)
       else
         result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
+
+  if (!g_strcmp0(interface, DBUS_INTERFACE_DBUS) &&
+      !g_strcmp0(member, "NameOwnerChanged"))
+    {
+      char *name, *old, *new;
+      result = DBUS_HANDLER_RESULT_HANDLED;
+      if (dbus_message_get_args (message, NULL,
+                                 DBUS_TYPE_STRING, &name,
+                                 DBUS_TYPE_STRING, &old,
+                                 DBUS_TYPE_STRING, &new,
+                                 DBUS_TYPE_INVALID))
+        {
+          if (*old != '\0' && *new == '\0')
+              spi_atk_remove_client (old);
+        }
+    }
+
   return result;
 }
 
@@ -828,4 +855,46 @@ gnome_accessibility_module_shutdown (void)
   exit_func ();
 }
 
+static gchar *name_match_tmpl =
+       "type='signal', interface='org.freedesktop.DBus', member='NameOwnerChanged', arg0='%s'";
+
+void
+spi_atk_add_client (const char *bus_name)
+{
+  GSList *l;
+  gchar *match;
+
+  for (l = clients; l; l = l->next)
+  {
+    if (!g_strcmp0 (l->data, bus_name))
+      return;
+  }
+  if (!clients && spi_global_app_data->events_initialized)
+    spi_atk_register_event_listeners ();
+  clients = g_slist_append (clients, g_strdup (bus_name));
+  match = g_strdup_printf (name_match_tmpl, bus_name);
+  dbus_bus_add_match (spi_global_app_data->bus, match, NULL);
+  g_free (match);
+}
+
+void
+spi_atk_remove_client (const char *bus_name)
+{
+  GSList *l;
+
+  for (l = clients; l; l = l->next)
+  {
+    if (!g_strcmp0 (l->data, bus_name))
+    {
+      gchar *match = g_strdup_printf (name_match_tmpl, l->data);
+      dbus_bus_remove_match (spi_global_app_data->bus, match, NULL);
+  g_free (match);
+      g_free (l->data);
+      clients = g_slist_remove_link (clients, l);
+      if (!clients)
+        spi_atk_deregister_event_listeners ();
+    }
+  }
+}
+
 /*END------------------------------------------------------------------------*/
index 1a3ebee..c24183e 100644 (file)
@@ -66,6 +66,9 @@ char *app_bus_addr;
 
 extern SpiBridge *spi_global_app_data;
 
+void spi_atk_add_client (const char *bus_name);
+void spi_atk_remove_client (const char *bus_name);
+
 G_END_DECLS
 
 #endif /* BRIDGE_H */
index a616879..e882edf 100644 (file)
@@ -1096,6 +1096,12 @@ spi_atk_register_event_listeners (void)
   g_object_unref (G_OBJECT (bo));
   g_object_unref (ao);
 
+  if (listener_ids)
+  {
+    g_warning ("atk_bridge: spi_atk-register_event_listeners called multiple times");
+    return;
+  }
+
   /* Register for focus event notifications, and register app with central registry  */
   listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
 
@@ -1149,10 +1155,7 @@ spi_atk_register_event_listeners (void)
                        "Gtk:AtkTable:column-reordered");
   add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
   add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
-
-  /* Children signal listeners */
-  atk_add_global_event_listener (children_changed_event_listener,
-                                 "Gtk:AtkObject:children-changed");
+  add_signal_listener (children_changed_event_listener, "Gtk:AtkObject:children-changed");
 
 #if 0
   g_signal_connect (G_OBJECT (spi_global_app_data->root),
@@ -1187,15 +1190,22 @@ spi_atk_deregister_event_listeners (void)
   listener_ids = NULL;
 
   if (atk_bridge_focus_tracker_id)
+  {
     atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
+    atk_bridge_focus_tracker_id = 0;
+  }
 
   for (i = 0; ids && i < ids->len; i++)
     {
       atk_remove_global_event_listener (g_array_index (ids, guint, i));
     }
+  g_array_free (ids, TRUE);
 
   if (atk_bridge_key_event_listener_id)
+  {
     atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
+    atk_bridge_key_event_listener_id = 0;
+  }
 }
 
 /*---------------------------------------------------------------------------*/