[at-spi2-core] Allow caching of data sent with events and requesting such data



commit 6395af932862454ed292d3623c18c59218ecbe7e
Author: Mike Gorse <mgorse suse com>
Date:   Sat Feb 1 17:39:34 2014 -0600

    Allow caching of data sent with events and requesting such data
    
    Add atspi_event_listener_register_full, to request that particular data
    be sent with an event, and cache the data for the duration of the event
    callback.
    
    This also extends the D-Bus protocol, adding an a{sv} to an event to send
    this data along, but we will still read events without this array added for
    backwards compatibility (and compatibilllity with QT-AT-SPI, which does not
    send this data for now).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=708695

 atspi/Makefile.am            |    1 +
 atspi/atspi-accessible.c     |   66 ++++++++++++++++++++++++----
 atspi/atspi-accessible.h     |    3 +
 atspi/atspi-component.c      |   12 +++++
 atspi/atspi-event-listener.c |   98 ++++++++++++++++++++++++++++++++++++-----
 atspi/atspi-event-listener.h |   14 ++++++
 atspi/atspi-matchrule.c      |    6 +--
 atspi/atspi-misc-private.h   |   11 ++++-
 atspi/atspi-misc.c           |   97 +++++++++++++++++++++++++++++++++++++++++
 atspi/atspi-private.h        |    1 +
 registryd/registry.c         |   47 ++++++++++++++++----
 11 files changed, 321 insertions(+), 35 deletions(-)
---
diff --git a/atspi/Makefile.am b/atspi/Makefile.am
index 2cb21da..bd5b279 100644
--- a/atspi/Makefile.am
+++ b/atspi/Makefile.am
@@ -54,6 +54,7 @@ libatspi_la_SOURCES =         \
        atspi.h \
        atspi-accessible.c \
        atspi-accessible.h \
+       atspi-accessible-private.h \
        atspi-action.c \
        atspi-action.h \
        atspi-application.c \
diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c
index b06a36c..bc0ad4d 100644
--- a/atspi/atspi-accessible.c
+++ b/atspi/atspi-accessible.c
@@ -23,6 +23,7 @@
  */
 
 #include "atspi-private.h"
+#include "atspi-accessible-private.h"
 #include <string.h>
 
 static gboolean enable_caching = FALSE;
@@ -84,6 +85,7 @@ atspi_value_interface_init (AtspiValue *value)
 }
 
 G_DEFINE_TYPE_WITH_CODE (AtspiAccessible, atspi_accessible, ATSPI_TYPE_OBJECT,
+                         G_ADD_PRIVATE (AtspiAccessible)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_ACTION, atspi_action_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COLLECTION, atspi_collection_interface_init)
                          G_IMPLEMENT_INTERFACE (ATSPI_TYPE_COMPONENT, atspi_component_interface_init)
@@ -108,6 +110,8 @@ atspi_accessible_init (AtspiAccessible *accessible)
   g_hash_table_insert (_atspi_get_live_refs (), accessible, NULL);
   g_print("at-spi: init: %d objects\n", accessible_count);
 #endif
+
+  accessible->priv = atspi_accessible_get_instance_private (accessible);
 }
 
 static void
@@ -592,6 +596,13 @@ atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error)
 
     g_return_val_if_fail (obj != NULL, NULL);
 
+  if (obj->priv->cache)
+  {
+    GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
+    if (val)
+      return g_value_dup_boxed (val);
+  }
+
   if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_ATTRIBUTES))
   {
     message = _atspi_dbus_call_partial (obj, atspi_interface_accessible,
@@ -632,15 +643,16 @@ atspi_accessible_get_attributes_as_array (AtspiAccessible *obj, GError **error)
 
     g_return_val_if_fail (obj != NULL, NULL);
 
-  if (_atspi_accessible_get_cache_mask (obj) & ATSPI_CACHE_ATTRIBUTES)
+  if (obj->priv->cache)
   {
-    GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
-    GHashTable *attributes = atspi_accessible_get_attributes (obj, error);
-    if (!attributes)
-      return NULL;
-    g_hash_table_foreach (attributes, add_to_attribute_array, &array);
-    g_hash_table_unref (attributes);
-    return array;
+    GValue *val = g_hash_table_lookup (obj->priv->cache, "Attributes");
+    if (val)
+    {
+      GArray *array = g_array_new (TRUE, TRUE, sizeof (gchar *));
+      GHashTable *attributes = g_value_get_boxed (val);
+      g_hash_table_foreach (attributes, add_to_attribute_array, &array);
+      return array;
+    }
   }
 
   message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, "");
@@ -1671,7 +1683,8 @@ _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag)
   AtspiCache result = accessible->cached_properties & mask & flag;
   if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT))
     return FALSE;
-  return (result != 0 && (atspi_main_loop || enable_caching) &&
+  return (result != 0 && (atspi_main_loop || enable_caching ||
+                          flag == ATSPI_CACHE_INTERFACES) &&
           !atspi_no_cache);
 }
 
@@ -1714,3 +1727,38 @@ atspi_accessible_get_object_locale (AtspiAccessible *accessible, GError **error)
   }
   return locale;
 }
+
+void
+free_value (gpointer data)
+{
+  GValue *value = data;
+
+  g_value_unset (value);
+  g_free (value);
+}
+
+GHashTable *
+_atspi_accessible_ref_cache (AtspiAccessible *accessible)
+{
+  AtspiAccessiblePrivate *priv = accessible->priv;
+
+  priv->cache_ref_count++;
+  if (priv->cache)
+    return g_hash_table_ref (priv->cache);
+  priv->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                       free_value);
+  return priv->cache;
+}
+
+void
+_atspi_accessible_unref_cache (AtspiAccessible *accessible)
+{
+  AtspiAccessiblePrivate *priv = accessible->priv;
+
+  if (priv->cache)
+  {
+    g_hash_table_unref (priv->cache);
+    if (--priv->cache_ref_count == 0)
+      priv->cache = NULL;
+  }
+}
diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h
index 0358950..32439ec 100644
--- a/atspi/atspi-accessible.h
+++ b/atspi/atspi-accessible.h
@@ -43,6 +43,8 @@ G_BEGIN_DECLS
 #define ATSPI_IS_ACCESSIBLE_CLASS(klass)             (G_TYPE_CHECK_CLASS_TYPE ((klass), 
ATSPI_TYPE_ACCESSIBLE))
 #define ATSPI_ACCESSIBLE_GET_CLASS(obj)              (G_TYPE_INSTANCE_GET_CLASS ((obj), 
ATSPI_TYPE_ACCESSIBLE, AtspiAccessibleClass))
 
+typedef struct _AtspiAccessiblePrivate AtspiAccessiblePrivate;
+
 struct _AtspiAccessible
 {
   AtspiObject parent;
@@ -55,6 +57,7 @@ struct _AtspiAccessible
   AtspiStateSet *states;
   GHashTable *attributes;
   guint cached_properties;
+  AtspiAccessiblePrivate *priv;
 };
 
 typedef struct _AtspiAccessibleClass AtspiAccessibleClass;
diff --git a/atspi/atspi-component.c b/atspi/atspi-component.c
index 9cdd896..31761cf 100644
--- a/atspi/atspi-component.c
+++ b/atspi/atspi-component.c
@@ -28,6 +28,7 @@
  */
 
 #include "atspi-private.h"
+#include "atspi-accessible-private.h"
 
 void
 atspi_rect_free (AtspiRect *rect)
@@ -136,10 +137,21 @@ atspi_component_get_extents (AtspiComponent *obj,
 {
   dbus_uint32_t d_ctype = ctype;
   AtspiRect bbox;
+  AtspiAccessible *accessible;
 
   bbox.x = bbox.y = bbox.width = bbox.height = -1;
   g_return_val_if_fail (obj != NULL, atspi_rect_copy (&bbox));
 
+  accessible = ATSPI_ACCESSIBLE (obj);
+  if (accessible->priv->cache && ctype == ATSPI_COORD_TYPE_SCREEN)
+  {
+    GValue *val = g_hash_table_lookup (accessible->priv->cache, "Component.ScreenExtents");
+    if (val)
+    {
+      return g_value_dup_boxed (val);
+    }
+  }
+
   _atspi_dbus_call (obj, atspi_interface_component, "GetExtents", error, "u=>(iiii)", d_ctype, &bbox);
   return atspi_rect_copy (&bbox);
 }
diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c
index a7a2336..3e6e73a 100644
--- a/atspi/atspi-event-listener.c
+++ b/atspi/atspi-event-listener.c
@@ -23,6 +23,7 @@
  */
 
 #include "atspi-private.h"
+#include "atspi-accessible-private.h"
 #include <string.h>
 #include <ctype.h>
 
@@ -35,6 +36,7 @@ typedef struct
   char *category;
   char *name;
   char *detail;
+  GArray *properties;
 } EventListenerEntry;
 
 G_DEFINE_TYPE (AtspiEventListener, atspi_event_listener, G_TYPE_OBJECT)
@@ -513,22 +515,49 @@ atspi_event_listener_register (AtspiEventListener *listener,
                                                       event_type, error);
 }
 
+/**
+ * atspi_event_listener_register_full:
+ * @listener: The #AtspiEventListener to register against an event type.
+ * @event_type: a character string indicating the type of events for which
+ *            notification is requested.  See #atspi_event_listener_register
+ * for a description of the format and legal event types.
+* @properties: (element-type gchar*) (transfer none) (allow-none): a list of
+ *             properties that should be sent along with the event. The
+ *             properties are valued for the duration of the event callback.k
+ *             TODO: Document.
+ *
+ * Adds an in-process callback function to an existing #AtspiEventListener.
+ *
+ * Returns: #TRUE if successful, otherwise #FALSE.
+ **/
+gboolean
+atspi_event_listener_register_full (AtspiEventListener *listener,
+                                            const gchar              *event_type,
+                                            GArray *properties,
+                                            GError **error)
+{
+  /* TODO: Keep track of which events have been registered, so that we
+ * deregister all of them when the event listener is destroyed */
+
+  return atspi_event_listener_register_from_callback_full (listener->callback,
+                                                           listener->user_data,
+                                                           listener->cb_destroyed,
+                                                           event_type,
+                                                           properties,
+                                                           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);
+  dbind_method_call_reentrant (_atspi_bus (), atspi_bus_registry,
+                              atspi_path_registry,
+                              atspi_interface_registry,
+                              "RegisterEvent",
+                              NULL, "sas", e->event_type,
+                               e->properties);
 
-  if (reply)
-    dbus_message_unref (reply);
   return TRUE;
 }
 
@@ -554,6 +583,38 @@ atspi_event_listener_register_from_callback (AtspiEventListenerCB callback,
                                             const gchar              *event_type,
                                             GError **error)
 {
+  return atspi_event_listener_register_from_callback_full (callback,
+                                                           user_data,
+                                                           callback_destroyed,
+                                                           event_type, NULL,
+                                                           error);
+}
+
+static GArray *
+copy_event_properties (GArray *src)
+{
+  gint i;
+
+  GArray *dst = g_array_new (FALSE, FALSE, sizeof (char *));
+
+  if (!src)
+    return dst;
+  for (i = 0; i < src->len; i++)
+    {
+      gchar *dup = g_strdup (g_array_index (src, char *, i));
+    g_array_append_val (dst, dup);
+    }
+  return dst;
+}
+
+gboolean
+atspi_event_listener_register_from_callback_full (AtspiEventListenerCB callback,
+                                                 void *user_data,
+                                                 GDestroyNotify callback_destroyed,
+                                                 const gchar              *event_type,
+                                                 GArray *properties,
+                                                 GError **error)
+{
   EventListenerEntry *e;
   DBusError d_error;
   GPtrArray *matchrule_array;
@@ -582,6 +643,7 @@ atspi_event_listener_register_from_callback (AtspiEventListenerCB callback,
     g_free (e);
     return FALSE;
   }
+  e->properties = copy_event_properties (properties);
   event_listeners = g_list_prepend (event_listeners, e);
   for (i = 0; i < matchrule_array->len; i++)
   {
@@ -871,8 +933,10 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
   AtspiEvent e;
   dbus_int32_t detail1, detail2;
   char *p;
+  GHashTable *cache = NULL;
 
-  if (strcmp (signature, "siiv(so)") != 0)
+  if (strcmp (signature, "siiv(so)") != 0 &&
+      strcmp (signature, "siiva{sv}") != 0)
   {
     g_warning ("Got invalid signature %s for signal %s from interface %s\n", signature, member, category);
     return DBUS_HANDLER_RESULT_HANDLED;
@@ -958,6 +1022,13 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
     break;
   }
 
+  dbus_message_iter_next (&iter);
+  if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY)
+  {
+    /* new form -- parse properties sent with event */
+    _atspi_dbus_update_cache_from_dict (e.source, &iter);
+  }
+
   if (!strncmp (e.type, "object:children-changed", 23))
   {
     cache_process_children_changed (&e);
@@ -978,6 +1049,9 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
 
   _atspi_send_event (&e);
 
+  if (cache)
+    _atspi_accessible_unref_cache (e.source);
+
   g_free (converted_type);
   g_free (name);
   g_free (detail);
diff --git a/atspi/atspi-event-listener.h b/atspi/atspi-event-listener.h
index 12d3c58..ee52fac 100644
--- a/atspi/atspi-event-listener.h
+++ b/atspi/atspi-event-listener.h
@@ -93,6 +93,12 @@ atspi_event_listener_register (AtspiEventListener *listener,
                                 GError **error);
 
 gboolean
+atspi_event_listener_register_full (AtspiEventListener *listener,
+                                     const gchar              *event_type,
+                                      GArray *properties,
+                                     GError **error);
+
+gboolean
 atspi_event_listener_register_from_callback (AtspiEventListenerCB callback,
                                             void *user_data,
                                             GDestroyNotify callback_destroyed,
@@ -100,6 +106,14 @@ atspi_event_listener_register_from_callback (AtspiEventListenerCB callback,
                                             GError **error);
 
 gboolean
+atspi_event_listener_register_from_callback_full (AtspiEventListenerCB callback,
+                                                 void *user_data,
+                                                 GDestroyNotify callback_destroyed,
+                                                 const gchar              *event_type,
+                                                  GArray *properties,
+                                                 GError **error);
+
+gboolean
 atspi_event_listener_register_no_data (AtspiEventListenerSimpleCB callback,
                                 GDestroyNotify callback_destroyed,
                                 const gchar              *event_type,
diff --git a/atspi/atspi-matchrule.c b/atspi/atspi-matchrule.c
index 1a17cf3..8abeb13 100644
--- a/atspi/atspi-matchrule.c
+++ b/atspi/atspi-matchrule.c
@@ -122,9 +122,6 @@ atspi_match_rule_new (AtspiStateSet *states,
   AtspiMatchRule *rule = g_object_new (ATSPI_TYPE_MATCH_RULE, NULL);
   int i;
 
-  if (!rule)
-    return NULL;
-
   if (states)
     rule->states = g_object_ref (states);
   rule->statematchtype = statematchtype;
@@ -219,7 +216,8 @@ _atspi_match_rule_marshal (AtspiMatchRule *rule, DBusMessageIter *iter)
   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "{ss}",
                                          &iter_dict))
     return FALSE;
-  g_hash_table_foreach (rule->attributes, append_entry, &iter_dict);
+  if (rule->attributes)
+    g_hash_table_foreach (rule->attributes, append_entry, &iter_dict);
   dbus_message_iter_close_container (&iter_struct, &iter_dict);
   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_attributematchtype);
 
diff --git a/atspi/atspi-misc-private.h b/atspi/atspi-misc-private.h
index ec6cef1..4e2df7b 100644
--- a/atspi/atspi-misc-private.h
+++ b/atspi/atspi-misc-private.h
@@ -147,7 +147,8 @@ GQuark _atspi_error_quark (void);
 typedef enum
 {
   ATSPI_ERROR_APPLICATION_GONE,
-  ATSPI_ERROR_IPC
+  ATSPI_ERROR_IPC,
+  ATSPI_ERROR_SYNC_NOT_ALLOWED,
 } AtspiError;
 
 extern GMainLoop *atspi_main_loop;
@@ -156,6 +157,14 @@ extern gboolean atspi_no_cache;
 GHashTable *_atspi_get_live_refs ();
 
 gchar *_atspi_name_compat (gchar *in);
+
+void _atspi_dbus_update_cache_from_dict (AtspiAccessible *accessible, DBusMessageIter *iter);
+
+gboolean _atspi_get_allow_sync ();
+
+gboolean _atspi_set_allow_sync (gboolean val);
+
+void _atspi_set_error_no_sync (GError **error);
 G_END_DECLS
 
 #endif /* _ATSPI_MISC_PRIVATE_H_ */
diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c
index 2da473c..28de86f 100644
--- a/atspi/atspi-misc.c
+++ b/atspi/atspi-misc.c
@@ -42,6 +42,7 @@ static DBusConnection *bus = NULL;
 static GHashTable *live_refs = NULL;
 static gint method_call_timeout = 800;
 static gint app_startup_time = 15000;
+static gboolean allow_sync = TRUE;
 
 GMainLoop *atspi_main_loop;
 GMainContext *atspi_main_context;
@@ -1071,6 +1072,12 @@ _atspi_dbus_call (gpointer obj, const char *interface, const char *method, GErro
   if (!check_app (aobj->app, error))
     return FALSE;
 
+  if (!allow_sync)
+  {
+    _atspi_set_error_no_sync (error);
+    return FALSE;
+  }
+
   va_start (args, type);
   dbus_error_init (&err);
   set_timeout (aobj->app);
@@ -1172,6 +1179,12 @@ _atspi_dbus_get_property (gpointer obj, const char *interface, const char *name,
   if (!check_app (aobj->app, error))
     return FALSE;
 
+  if (!allow_sync)
+  {
+    _atspi_set_error_no_sync (error);
+    return FALSE;
+  }
+
   message = dbus_message_new_method_call (aobj->app->bus_name,
                                           aobj->path,
                                           "org.freedesktop.DBus.Properties",
@@ -1346,6 +1359,11 @@ _atspi_dbus_set_interfaces (AtspiAccessible *accessible, DBusMessageIter *iter)
   DBusMessageIter iter_array;
 
   accessible->interfaces = 0;
+  if (strcmp (dbus_message_iter_get_signature (iter), "as") != 0)
+  {
+    g_warning ("_atspi_dbus_set_interfaces: Passed iterator with invalid signature %s", 
dbus_message_iter_get_signature (iter));
+    return;
+  }
   dbus_message_iter_recurse (iter, &iter_array);
   while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
   {
@@ -1679,3 +1697,82 @@ atspi_role_get_name (AtspiRole role)
 
   return NULL;
 }
+
+void
+_atspi_dbus_update_cache_from_dict (AtspiAccessible *accessible, DBusMessageIter *iter)
+{
+  GHashTable *cache = _atspi_accessible_ref_cache (accessible);
+  DBusMessageIter iter_dict, iter_dict_entry, iter_struct, iter_variant;
+
+  dbus_message_iter_recurse (iter, &iter_dict);
+  while (dbus_message_iter_get_arg_type (&iter_dict) != DBUS_TYPE_INVALID)
+  {
+    const char *key;
+    GValue *val = NULL;
+    dbus_message_iter_recurse (&iter_dict, &iter_dict_entry);
+    dbus_message_iter_get_basic (&iter_dict_entry, &key);
+    dbus_message_iter_next (&iter_dict_entry);
+    dbus_message_iter_recurse (&iter_dict_entry, &iter_variant);
+    if (!strcmp (key, "interfaces"))
+    {
+      _atspi_dbus_set_interfaces (accessible, &iter_variant);
+    }
+    else if (!strcmp (key, "Attributes"))
+    {
+      val = g_new0 (GValue, 1);;
+      g_value_init (val, G_TYPE_HASH_TABLE);
+      if (strcmp (dbus_message_iter_get_signature (&iter_variant),
+                                                   "a{ss}") != 0)
+        break;
+      g_value_take_boxed (val, _atspi_dbus_hash_from_iter (&iter_variant));
+    }
+    else if (!strcmp (key, "Component.ScreenExtents"))
+    {
+      dbus_int32_t d_int;
+      AtspiRect extents;
+      val = g_new0 (GValue, 1);;
+      g_value_init (val, ATSPI_TYPE_RECT);
+      if (strcmp (dbus_message_iter_get_signature (&iter_variant),
+                                                   "(iiii)") != 0)
+        break;
+      dbus_message_iter_recurse (&iter_variant, &iter_struct);
+      dbus_message_iter_get_basic (&iter_struct, &d_int);
+      extents.x = d_int;
+      dbus_message_iter_next (&iter_struct);
+      dbus_message_iter_get_basic (&iter_struct, &d_int);
+      extents.y = d_int;
+      dbus_message_iter_next (&iter_struct);
+      dbus_message_iter_get_basic (&iter_struct, &d_int);
+      extents.width = d_int;
+      dbus_message_iter_next (&iter_struct);
+      dbus_message_iter_get_basic (&iter_struct, &d_int);
+      extents.height = d_int;
+      g_value_set_boxed (val, &extents);
+    }
+    if (val)
+      g_hash_table_insert (cache, g_strdup (key), val); 
+    dbus_message_iter_next (&iter_dict);
+  }
+}
+
+gboolean
+_atspi_get_allow_sync ()
+{
+  return allow_sync;
+}
+
+gboolean
+_atspi_set_allow_sync (gboolean val)
+{
+  gboolean ret = allow_sync;
+
+  allow_sync = val;
+  return ret;
+}
+
+void
+_atspi_set_error_no_sync (GError **error)
+{
+  g_set_error_literal (error, ATSPI_ERROR, ATSPI_ERROR_SYNC_NOT_ALLOWED,
+                        _("Attempted synchronous call where prohibited"));
+}
diff --git a/atspi/atspi-private.h b/atspi/atspi-private.h
index b3f5682..2cf5693 100644
--- a/atspi/atspi-private.h
+++ b/atspi/atspi-private.h
@@ -34,6 +34,7 @@
 #include "glib/gi18n.h"
 
 #include "atspi.h"
+#include "atspi-accessible-private.h"
 
 G_BEGIN_DECLS
 void _atspi_reregister_device_listeners ();
diff --git a/registryd/registry.c b/registryd/registry.c
index 8448bb2..6f37a96 100644
--- a/registryd/registry.c
+++ b/registryd/registry.c
@@ -35,6 +35,7 @@ struct event_data
 {
   gchar *bus_name;
   gchar **data;
+  GSList *properties;
 };
 
 static void
@@ -244,6 +245,7 @@ remove_events (SpiRegistry *registry, const char *bus_name, const char *event)
         {
           g_strfreev (evdata->data);
           g_free (evdata->bus_name);
+          g_slist_free_full (evdata->properties, g_free);
           g_free (evdata);
           registry->events = g_list_remove (registry->events, evdata);
         }
@@ -832,19 +834,34 @@ impl_register_event (DBusConnection *bus, DBusMessage *message, void *user_data)
   gchar **data;
   DBusMessage *signal;
   const char *sender = dbus_message_get_sender (message);
+  DBusMessageIter iter, iter_array;
+  const char *signature = dbus_message_get_signature (message);
 
-  if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &orig_name,
-    DBUS_TYPE_INVALID))
+  if (strcmp (signature, "sas") != 0)
+  {
+    g_warning ("got RegisterEvent with invalid signature '%s'", signature);
     return NULL;
+  }
 
+  dbus_message_iter_init (message, &iter);
+  dbus_message_iter_get_basic (&iter, &orig_name);
+  dbus_message_iter_next (&iter);
+  dbus_message_iter_recurse (&iter, &iter_array);
   name = ensure_proper_format (orig_name);
 
-  evdata = (event_data *) g_malloc (sizeof (*evdata));
-  if (!evdata)
-    return NULL;
+  evdata = g_new0 (event_data, 1);
   data = g_strsplit (name, ":", 3);
   evdata->bus_name = g_strdup (sender);
   evdata->data = data;
+
+  while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
+  {
+    const char *property;
+    dbus_message_iter_get_basic (&iter_array, &property);
+    evdata->properties = g_slist_append (evdata->properties,
+                                         g_strdup (property));
+    dbus_message_iter_next (&iter_array);
+  }
   registry->events = g_list_append (registry->events, evdata);
 
   if (needs_mouse_poll (evdata->data))
@@ -855,10 +872,22 @@ impl_register_event (DBusConnection *bus, DBusMessage *message, void *user_data)
   signal = dbus_message_new_signal (SPI_DBUS_PATH_REGISTRY,
                                     SPI_DBUS_INTERFACE_REGISTRY,
                                     "EventListenerRegistered");
-  dbus_message_append_args (signal, DBUS_TYPE_STRING, &sender,
-                            DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
-  dbus_connection_send (bus, signal, NULL);
-  dbus_message_unref (signal);
+  if (signal)
+  {
+    GSList *ls = evdata->properties;
+    dbus_message_iter_init_append (signal, &iter);
+    dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &sender);
+    dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name);
+    dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &iter_array);
+    while (ls)
+    {
+      dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &ls->data);
+      ls = g_slist_next (ls);
+    }
+    dbus_message_iter_close_container (&iter, &iter_array);
+    dbus_connection_send (bus, signal, NULL);
+    dbus_message_unref (signal);
+  }
 
   g_free (name);
   return dbus_message_new_method_return (message);


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