Socket's implementation of ref_state_set to return empty sets instead of NULL
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / bridge.c
index 86bfc47..a1ee202 100644 (file)
 #include "event.h"
 #include "adaptors.h"
 #include "object.h"
-#include "common/spi-stateset.h"
+#include "accessible-stateset.h"
 
 #include "accessible-register.h"
 #include "accessible-leasing.h"
 #include "accessible-cache.h"
 
-#include "common/spi-dbus.h"
+#include "spi-dbus.h"
 
 /*---------------------------------------------------------------------------*/
 
-SpiBridge *spi_global_app_data = NULL;
+static DBusHandlerResult
+signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data);
 
-static const AtkMisc *atk_misc = NULL;
+SpiBridge *spi_global_app_data = NULL;
 
 /*static Display *bridge_display = NULL;*/
 
@@ -119,6 +120,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;
@@ -135,6 +137,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)
 {
@@ -142,21 +146,24 @@ get_registered_event_listeners (SpiBridge *app)
   DBusMessageIter iter, iter_array, iter_struct;
 
   message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
-                                         SPI_DBUS_PATH_REGISTRY,
-                                         SPI_DBUS_INTERFACE_REGISTRY,
+                                         ATSPI_DBUS_PATH_REGISTRY,
+                                         ATSPI_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);
@@ -172,6 +179,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
@@ -227,12 +238,12 @@ register_application (SpiBridge * app)
 
   /* These will be overridden when we get a reply, but in practice these
      defaults should always be correct */
-  app->desktop_name = SPI_DBUS_NAME_REGISTRY;
-  app->desktop_path = SPI_DBUS_PATH_ROOT;
+  app->desktop_name = ATSPI_DBUS_NAME_REGISTRY;
+  app->desktop_path = ATSPI_DBUS_PATH_ROOT;
 
   message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
-                                          SPI_DBUS_PATH_ROOT,
-                                          SPI_DBUS_INTERFACE_SOCKET,
+                                          ATSPI_DBUS_PATH_ROOT,
+                                          ATSPI_DBUS_INTERFACE_SOCKET,
                                           "Embed");
 
   dbus_message_iter_init_append (message, &iter);
@@ -277,8 +288,8 @@ deregister_application (SpiBridge * app)
   dbus_error_init (&error);
 
   message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
-                                          SPI_DBUS_PATH_REGISTRY,
-                                          SPI_DBUS_INTERFACE_REGISTRY,
+                                          ATSPI_DBUS_PATH_REGISTRY,
+                                          ATSPI_DBUS_INTERFACE_REGISTRY,
                                           "DeregisterApplication");
   dbus_message_set_no_reply (message, TRUE);
 
@@ -293,28 +304,6 @@ deregister_application (SpiBridge * app)
 
 /*---------------------------------------------------------------------------*/
 
-static void
-exit_func (void)
-{
-  if (!spi_global_app_data)
-    {
-      return;
-    }
-
-  spi_atk_tidy_windows ();
-  spi_atk_deregister_event_listeners ();
-  deregister_application (spi_global_app_data);
-
-  g_free (spi_global_app_data);
-  spi_global_app_data = NULL;
-
-  /* Not currently creating an XDisplay */
-#if 0
-  if (bridge_display)
-    XCloseDisplay (bridge_display);
-#endif
-}
-
 /*---------------------------------------------------------------------------*/
 
 static AtkPlugClass *plug_class;
@@ -345,33 +334,33 @@ socket_ref_state_set (AtkObject *accessible)
   DBusMessageIter iter, iter_array;
   AtkStateSet *set;
 
+  set = atk_state_set_new ();
+
   if (!socket->embedded_plug_id)
-    return NULL;
+    return set;
 
   child_name = g_strdup (socket->embedded_plug_id);
   if (!child_name)
-    return NULL;
+    return set;
   child_path = g_utf8_strchr (child_name + 1, -1, ':');
   if (!child_path)
     {
       g_free (child_name);
-      return NULL;
+      return set;
     }
   *(child_path++) = '\0';
-  message = dbus_message_new_method_call (child_name, child_path, SPI_DBUS_INTERFACE_ACCESSIBLE, "GetState");
+  message = dbus_message_new_method_call (child_name, child_path, ATSPI_DBUS_INTERFACE_ACCESSIBLE, "GetState");
   g_free (child_name);
   reply = dbus_connection_send_with_reply_and_block (spi_global_app_data->bus, message, 1, NULL);
   dbus_message_unref (message);
   if (reply == NULL)
-    return NULL;
+    return set;
   if (strcmp (dbus_message_get_signature (reply), "au") != 0)
     {
       dbus_message_unref (reply);
-      return NULL;
+      return set;
     }
-  set = atk_state_set_new ();
-  if (!set)
-    return  NULL;
+
   dbus_message_iter_init (reply, &iter);
   dbus_message_iter_recurse (&iter, &iter_array);
   do
@@ -413,7 +402,7 @@ socket_embed_hook (AtkSocket * socket, gchar * plug_id)
     {
       DBusMessage *message;
       *(plug_path++) = '\0';
-      message = dbus_message_new_method_call (plug_name, plug_path, SPI_DBUS_INTERFACE_SOCKET, "Embedded");
+      message = dbus_message_new_method_call (plug_name, plug_path, ATSPI_DBUS_INTERFACE_SOCKET, "Embedded");
       dbus_message_append_args (message, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
       dbus_connection_send (spi_global_app_data->bus, message, NULL);
     }
@@ -490,9 +479,7 @@ new_connection_cb (DBusServer *server, DBusConnection *con, void *data)
   droute_intercept_dbus (con);
   droute_context_register (spi_global_app_data->droute, con);
 
-  new_list = g_list_append (spi_global_app_data->direct_connections, con);
-  if (new_list)
-    spi_global_app_data->direct_connections = new_list;
+  spi_global_app_data->direct_connections = g_list_append (spi_global_app_data->direct_connections, con);
 }
 
 static int
@@ -620,7 +607,7 @@ signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data)
   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-  if (!strcmp (interface, SPI_DBUS_INTERFACE_REGISTRY))
+  if (!strcmp (interface, ATSPI_DBUS_INTERFACE_REGISTRY))
     {
       result = DBUS_HANDLER_RESULT_HANDLED;
       if (!strcmp (member, "EventListenerRegistered"))
@@ -630,6 +617,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;
 }
 
@@ -679,7 +683,6 @@ adaptor_init (gint * argc, gchar ** argv[])
 
   /* Allocate global data and do ATK initializations */
   spi_global_app_data = g_new0 (SpiBridge, 1);
-  atk_misc = atk_misc_get_instance ();
   spi_global_app_data->root = g_object_ref (root);
 
   /* Set up D-Bus connection and register bus name */
@@ -827,8 +830,95 @@ gnome_accessibility_module_init (void)
 void
 gnome_accessibility_module_shutdown (void)
 {
+  GList *l;
+
+  if (!spi_global_app_data)
+      return;
+
+  spi_atk_tidy_windows ();
   spi_atk_deregister_event_listeners ();
-  exit_func ();
+
+  deregister_application (spi_global_app_data);
+
+  if (spi_global_app_data->bus)
+    {
+      dbus_connection_remove_filter (spi_global_app_data->bus, signal_filter, NULL);
+      droute_context_unregister (spi_global_app_data->droute, spi_global_app_data->bus);
+      dbus_connection_unref (spi_global_app_data->bus);
+    }
+
+  for (l = spi_global_app_data->direct_connections; l; l = l->next)
+    {
+      droute_context_unregister (spi_global_app_data->droute, l->data);
+      droute_unintercept_dbus (l->data);
+      dbus_connection_unref (l);
+    }
+  g_list_free (spi_global_app_data->direct_connections);
+
+  for (l = clients; l; l = l->next)
+     g_free (l->data);
+  g_list_free (clients);
+  clients = NULL;
+
+  g_object_unref (spi_global_cache);
+  g_object_unref (spi_global_leasing);
+  g_object_unref (spi_global_register);
+
+  if (spi_global_app_data->main_context)
+    g_main_context_unref (spi_global_app_data->main_context);
+
+  droute_free (spi_global_app_data->droute);
+
+  g_free (spi_global_app_data);
+  spi_global_app_data = NULL;
+
+  /* Not currently creating an XDisplay */
+#if 0
+  if (bridge_display)
+    XCloseDisplay (bridge_display);
+#endif
+}
+
+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------------------------------------------------------------------------*/