[at-spi2-core] Re-register keystroke listeners if the registry goes away and returns



commit 8846499e0aaae728fb460a8b27f6645dac55e91d
Author: Mike Gorse <mgorse suse com>
Date:   Tue Nov 20 16:29:50 2012 -0600

    Re-register keystroke listeners if the registry goes away and returns

 atspi/atspi-event-listener-private.h |    3 +
 atspi/atspi-event-listener.c         |   47 ++++++++---
 atspi/atspi-misc.c                   |   42 +++++++++
 atspi/atspi-private.h                |    4 +
 atspi/atspi-registry.c               |  160 ++++++++++++++++++++++++++--------
 5 files changed, 208 insertions(+), 48 deletions(-)
---
diff --git a/atspi/atspi-event-listener-private.h b/atspi/atspi-event-listener-private.h
index 0b29111..260db74 100644
--- a/atspi/atspi-event-listener-private.h
+++ b/atspi/atspi-event-listener-private.h
@@ -38,6 +38,9 @@ void _atspi_send_event (AtspiEvent *e);
 
 DBusHandlerResult _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data);
 
+void
+_atspi_reregister_event_listeners ();
+
 G_END_DECLS
 
 #endif	/* _ATSPI_EVENT_LISTENER_H_ */
diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c
index ba5d126..9152054 100644
--- a/atspi/atspi-event-listener.c
+++ b/atspi/atspi-event-listener.c
@@ -31,6 +31,7 @@ typedef struct
   AtspiEventListenerCB callback;
   void *user_data;
   GDestroyNotify callback_destroyed;
+  char *event_type;
   char *category;
   char *name;
   char *detail;
@@ -400,6 +401,7 @@ static void
 listener_entry_free (EventListenerEntry *e)
 {
   gpointer callback = (e->callback == remove_datum ? (gpointer)e->user_data : (gpointer)e->callback);
+  g_free (e->event_type);
   g_free (e->category);
   g_free (e->name);
   if (e->detail) g_free (e->detail);
@@ -511,6 +513,25 @@ atspi_event_listener_register (AtspiEventListener *listener,
                                                       event_type, error);
 }
 
+static gboolean
+notify_event_registered (EventListenerEntry *e)
+{
+  DBusMessage *message, *reply;
+
+  message = dbus_message_new_method_call (atspi_bus_registry,
+	atspi_path_registry,
+	atspi_interface_registry,
+	"RegisterEvent");
+  if (!message)
+    return FALSE;
+  dbus_message_append_args (message, DBUS_TYPE_STRING, &e->event_type, DBUS_TYPE_INVALID);
+  reply = _atspi_dbus_send_with_reply_and_block (message, NULL);
+
+  if (reply)
+    dbus_message_unref (reply);
+  return TRUE;
+}
+
 /**
  * atspi_event_listener_register_from_callback:
  * @callback: (scope notified): the #AtspiEventListenerCB to be registered 
@@ -551,6 +572,7 @@ atspi_event_listener_register_from_callback (AtspiEventListenerCB callback,
   }
 
   e = g_new (EventListenerEntry, 1);
+  e->event_type = g_strdup (event_type);
   e->callback = callback;
   e->user_data = user_data;
   e->callback_destroyed = callback_destroyed;
@@ -578,20 +600,23 @@ atspi_event_listener_register_from_callback (AtspiEventListenerCB callback,
   }
   g_ptr_array_free (matchrule_array, TRUE);
 
-  message = dbus_message_new_method_call (atspi_bus_registry,
-	atspi_path_registry,
-	atspi_interface_registry,
-	"RegisterEvent");
-  if (!message)
-    return FALSE;
-  dbus_message_append_args (message, DBUS_TYPE_STRING, &event_type, DBUS_TYPE_INVALID);
-  reply = _atspi_dbus_send_with_reply_and_block (message, error);
-  if (reply)
-    dbus_message_unref (reply);
-
+  notify_event_registered (e);
   return TRUE;
 }
 
+void
+_atspi_reregister_event_listeners ()
+{
+  GList *l;
+  EventListenerEntry *e;
+
+  for (l = event_listeners; l; l = l->next)
+    {
+      e = l->data;
+      notify_event_registered (e);
+    }
+}
+
 /**
  * atspi_event_listener_register_no_data:
  * @callback: (scope notified): the #AtspiEventListenerSimpleCB to be
diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c
index 4f09060..548cfde 100644
--- a/atspi/atspi-misc.c
+++ b/atspi/atspi-misc.c
@@ -328,6 +328,35 @@ handle_remove_accessible (DBusConnection *bus, DBusMessage *message, void *user_
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+static DBusHandlerResult
+handle_name_owner_changed (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+  const char *name, *new, *old;
+  static gboolean registry_lost = FALSE;
+
+  if (!dbus_message_get_args (message, NULL,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_STRING, &old,
+                              DBUS_TYPE_STRING, &new,
+                              DBUS_TYPE_INVALID))
+  {
+    return;
+  }
+
+  if (!strcmp (name, "org.a11y.atspi.Registry"))
+  {
+    if (registry_lost && !old[0])
+    {
+      _atspi_reregister_event_listeners ();
+      _atspi_reregister_device_listeners ();
+      registry_lost = FALSE;
+    }
+    else if (!new[0])
+      registry_lost = TRUE;
+  }
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
 static gboolean
 add_app_to_desktop (AtspiAccessible *a, const char *bus_name)
 {
@@ -702,6 +731,10 @@ process_deferred_message (BusDataClosure *closure)
   {
     handle_remove_accessible (closure->bus, closure->message, closure->data);
   }
+  if (dbus_message_is_signal (closure->message, "org.freedesktop.DBus", "NameOwnerChanged"))
+  {
+    handle_name_owner_changed (closure->bus, closure->message, closure->data);
+  }
 }
 
 static GQueue *deferred_messages = NULL;
@@ -768,6 +801,11 @@ atspi_dbus_filter (DBusConnection *bus, DBusMessage *message, void *data)
   {
     return defer_message (bus, message, data);
   }
+  if (dbus_message_is_signal (message, "org.freedesktop.DBus", "NameOwnerChanged"))
+  {
+    defer_message (bus, message, data);
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
@@ -865,6 +903,10 @@ atspi_init (void)
   dbus_bus_add_match (bus, match, NULL);
   g_free (match);
 
+  dbus_bus_add_match (bus,
+                      "type='signal', interface='org.freedesktop.DBus', member='NameOwnerChanged'",
+                      NULL);
+
   no_cache = g_getenv ("ATSPI_NO_CACHE");
   if (no_cache && g_strcmp0 (no_cache, "0") != 0)
     atspi_no_cache = TRUE;
diff --git a/atspi/atspi-private.h b/atspi/atspi-private.h
index 9977be7..c68e4be 100644
--- a/atspi/atspi-private.h
+++ b/atspi/atspi-private.h
@@ -34,4 +34,8 @@
 
 #include "atspi.h"
 
+G_BEGIN_DECLS
+void _atspi_reregister_device_listeners ();
+G_END_DECLS
+
 #endif	/* _ATSPI_PRIVATE_H_ */
diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c
index 67a7590..28a76e1 100644
--- a/atspi/atspi-registry.c
+++ b/atspi/atspi-registry.c
@@ -26,6 +26,17 @@
 
 #include "atspi-private.h"
 
+typedef struct
+{
+  AtspiDeviceListener *listener;
+  GArray             *key_set;
+  AtspiKeyMaskType         modmask;
+  AtspiKeyEventMask        event_types;
+  gint sync_type;
+} DeviceListenerEntry;
+
+static GList *device_listeners;
+
 /**
  * atspi_get_desktop_count:
  *
@@ -86,6 +97,70 @@ atspi_get_desktop_list ()
   return array;
 }
 
+static gboolean
+notify_keystroke_listener (DeviceListenerEntry *e)
+{
+  gchar *path = _atspi_device_listener_get_path (e->listener);
+  gint                                i;
+  dbus_uint32_t d_modmask = e->modmask;
+  dbus_uint32_t d_event_types = e->event_types;
+  AtspiEventListenerMode     listener_mode;
+  gboolean                          retval = FALSE;
+  DBusError d_error;
+
+  listener_mode.synchronous =
+	  (dbus_bool_t) ((e->sync_type & ATSPI_KEYLISTENER_SYNCHRONOUS)!=0);
+  listener_mode.preemptive =
+	  (dbus_bool_t) ((e->sync_type & ATSPI_KEYLISTENER_CANCONSUME)!=0);
+  listener_mode.global =
+	  (dbus_bool_t) ((e->sync_type & ATSPI_KEYLISTENER_ALL_WINDOWS)!=0);
+
+  dbus_error_init (&d_error);
+  dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry,
+                               atspi_path_dec, atspi_interface_dec,
+                               "RegisterKeystrokeListener", &d_error,
+                               "oa(iisi)uu(bbb)=>b", path, e->key_set,
+                               e->modmask, e->event_types, &listener_mode,
+                               &retval);
+  if (dbus_error_is_set (&d_error))
+    {
+      g_warning ("RegisterKeystrokeListener failed: %s", d_error.message);
+      dbus_error_free (&d_error);
+    }
+
+  g_free (path);
+
+  return retval;
+}
+
+static void
+device_listener_entry_free (DeviceListenerEntry *e)
+{
+  g_array_free (e->key_set, TRUE);
+  g_free (e);
+}
+
+static void
+unregister_listener (gpointer data, GObject *object)
+{
+  GList *l;
+  AtspiDeviceListener *listener = ATSPI_DEVICE_LISTENER (object);
+
+  for (l = device_listeners; l;)
+    {
+      DeviceListenerEntry *e = l->data;
+      if (e->listener == listener)
+        {
+          GList *next = l->next;
+          device_listener_entry_free (e);
+          device_listeners = g_list_delete_link (device_listeners, l);
+          l = next;
+        }
+      else
+        l = l->next;
+    }
+}
+
 /**
  * atspi_register_keystroke_listener:
  * @listener:  a pointer to the #AtspiDeviceListener for which
@@ -125,29 +200,25 @@ atspi_register_keystroke_listener (AtspiDeviceListener  *listener,
 					 AtspiKeyEventMask        event_types,
 					 gint sync_type, GError **error)
 {
-  GArray *d_key_set;
-  gchar *path = _atspi_device_listener_get_path (listener);
-  gint                                i;
-  dbus_uint32_t d_modmask = modmask;
-  dbus_uint32_t d_event_types = event_types;
-  AtspiEventListenerMode     listener_mode;
-  gboolean                          retval = FALSE;
-  DBusError d_error;
+  DeviceListenerEntry *e;
 
-  if (!listener)
-    {
-      return retval;
-    }
+  g_return_val_if_fail (listener != NULL, FALSE);
 
-  /* copy the keyval filter values from the C api into the DBind KeySet */
+  e = g_new0 (DeviceListenerEntry, 1);
+  e->listener = listener;
+  e->modmask = modmask;
+  e->event_types = event_types;
+  e->sync_type = sync_type;
   if (key_set)
     {
-      d_key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), key_set->len);
-      d_key_set->len = key_set->len;
-      for (i = 0; i < key_set->len; ++i)
+      gint i;
+      e->key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition),
+                                      key_set->len);
+      e->key_set->len = key_set->len;
+      for (i = 0; i < key_set->len; i++)
         {
 	  AtspiKeyDefinition *kd =  ((AtspiKeyDefinition *) key_set->data) + i;
-	  AtspiKeyDefinition *d_kd =  ((AtspiKeyDefinition *) d_key_set->data) + i;
+	  AtspiKeyDefinition *d_kd =  ((AtspiKeyDefinition *) e->key_set->data) + i;
           d_kd->keycode = kd->keycode;
 	  d_kd->keysym = kd->keysym;
 	  if (kd->keystring)
@@ -162,28 +233,12 @@ atspi_register_keystroke_listener (AtspiDeviceListener  *listener,
     }
   else
     {
-      d_key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), 0);
-    }
-	
-  listener_mode.synchronous =
-	  (dbus_bool_t) ((sync_type & ATSPI_KEYLISTENER_SYNCHRONOUS)!=0);
-  listener_mode.preemptive =
-	  (dbus_bool_t) ((sync_type & ATSPI_KEYLISTENER_CANCONSUME)!=0);
-  listener_mode.global =
-	  (dbus_bool_t) ((sync_type & ATSPI_KEYLISTENER_ALL_WINDOWS)!=0);
-
-  dbus_error_init (&d_error);
-  dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterKeystrokeListener", &d_error, "oa(iisi)uu(bbb)=>b", path, d_key_set, d_modmask, d_event_types, &listener_mode, &retval);
-  if (dbus_error_is_set (&d_error))
-    {
-      g_warning ("RegisterKeystrokeListener failed: %s", d_error.message);
-      dbus_error_free (&d_error);
+      e->key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), 0);
     }
 
-  g_array_free (d_key_set, TRUE);
-  g_free (path);
-
-  return retval;
+  g_object_weak_ref (G_OBJECT (listener), unregister_listener, NULL);
+  device_listeners = g_list_prepend (device_listeners, e);
+  return notify_keystroke_listener (e);
 }
 
 /**
@@ -219,6 +274,7 @@ atspi_deregister_keystroke_listener (AtspiDeviceListener *listener,
   dbus_uint32_t d_modmask = modmask;
   dbus_uint32_t d_event_types = event_types;
   DBusError d_error;
+  GList *l;
 
   dbus_error_init (&d_error);
   if (!listener)
@@ -263,6 +319,24 @@ atspi_deregister_keystroke_listener (AtspiDeviceListener *listener,
       dbus_error_free (&d_error);
     }
 
+  unregister_listener (listener, NULL);
+  for (l = device_listeners; l;)
+    {
+      /* TODO: This code is all wrong / doesn't match what is in
+ *       deviceeventcontroller.c. It would be nice to deprecate these methods
+ *       in favor of methods that return an ID for the registration that can
+ *       be passed to a deregister function, for instance. */
+      DeviceListenerEntry *e = l->data;
+      if (e->modmask == modmask && e->event_types == event_types)
+        {
+          GList *next = l->next;
+          device_listener_entry_free (e);
+          device_listeners = g_list_delete_link (device_listeners, l);
+          l = next;
+        }
+      else
+        l = l->next;
+    }
   g_array_free (d_key_set, TRUE);
   g_free (path);
   return TRUE;
@@ -452,4 +526,16 @@ atspi_key_definition_free (AtspiKeyDefinition *kd)
   g_free (kd);
 }
 
+void
+_atspi_reregister_device_listeners ()
+{
+  GList *l;
+  DeviceListenerEntry *e;
+
+  for (l = device_listeners; l; l = l->next)
+    {
+      e = l->data;
+      notify_keystroke_listener (e);
+    }
+}
 G_DEFINE_BOXED_TYPE (AtspiKeyDefinition, atspi_key_definition, atspi_key_definition_copy, atspi_key_definition_free)



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