From d0f7dd49eebedc8c3993a116411f5a8320965968 Mon Sep 17 00:00:00 2001 From: Mike Gorse Date: Tue, 21 Jun 2011 17:16:07 -0500 Subject: [PATCH] Only register for events when something is listening 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 | 3 ++ atk-adaptor/adaptors/cache-adaptor.c | 3 ++ atk-adaptor/bridge.c | 75 ++++++++++++++++++++++++++++-- atk-adaptor/bridge.h | 3 ++ atk-adaptor/event.c | 18 +++++-- 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/atk-adaptor/adaptors/application-adaptor.c b/atk-adaptor/adaptors/application-adaptor.c index 897ed55..c686c31 100644 --- a/atk-adaptor/adaptors/application-adaptor.c +++ b/atk-adaptor/adaptors/application-adaptor.c @@ -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) { diff --git a/atk-adaptor/adaptors/cache-adaptor.c b/atk-adaptor/adaptors/cache-adaptor.c index 3b6b28c..0aff2bd 100644 --- a/atk-adaptor/adaptors/cache-adaptor.c +++ b/atk-adaptor/adaptors/cache-adaptor.c @@ -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); diff --git a/atk-adaptor/bridge.c b/atk-adaptor/bridge.c index 51b12bc..6aacd12 100644 --- a/atk-adaptor/bridge.c +++ b/atk-adaptor/bridge.c @@ -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------------------------------------------------------------------------*/ diff --git a/atk-adaptor/bridge.h b/atk-adaptor/bridge.h index 1a3ebee..c24183e 100644 --- a/atk-adaptor/bridge.h +++ b/atk-adaptor/bridge.h @@ -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 */ diff --git a/atk-adaptor/event.c b/atk-adaptor/event.c index a616879..e882edf 100644 --- a/atk-adaptor/event.c +++ b/atk-adaptor/event.c @@ -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; + } } /*---------------------------------------------------------------------------*/ -- 2.7.4