Fix memory management issues
[platform/upstream/at-spi2-core.git] / atspi / atspi-event-listener.c
index 065b4a0..e7e7116 100644 (file)
@@ -7,24 +7,25 @@
  * Copyright 2010, 2011 Novell, Inc.
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #include "atspi-private.h"
 #include "atspi-accessible-private.h"
 #include <string.h>
+#include <strings.h>
 #include <ctype.h>
 
 typedef struct
@@ -169,12 +170,15 @@ static GList *event_listeners = NULL;
 static gchar *
 convert_name_from_dbus (const char *name, gboolean path_hack)
 {
-  gchar *ret = g_malloc (g_utf8_strlen (name, -1) * 2 + 1);
+  gchar *ret;
   const char *p = name;
-  gchar *q = ret;
+  gchar *q;
 
-  if (!ret)
-    return NULL;
+  if (!name)
+    return g_strdup ("");
+
+ ret = g_malloc (g_utf8_strlen (name, -1) * 2 + 1);
+  q = ret;
 
   while (*p)
   {
@@ -378,14 +382,14 @@ convert_event_type_to_dbus (const char *eventType, char **categoryp, char **name
   if (matchrule_array)
   {
     gchar *matchrule;
+    (*matchrule_array) = g_ptr_array_new ();
     matchrule = g_strdup_printf ("type='signal',interface='org.a11y.atspi.Event.%s'", category);
     if (name && name [0])
     {
-      gchar *new_str = g_strconcat (matchrule, ",member='", name, "'", NULL);
-      g_free (matchrule);
-      matchrule = new_str;
+             gchar *new_str = g_strconcat (matchrule, ",member='", name, "'", NULL);
+             g_free (matchrule);
+             matchrule = new_str;
     }
-    (*matchrule_array) = g_ptr_array_new ();
     if (detail && detail [0])
     {
       gchar *new_str = g_strconcat (matchrule, ",arg0='", detail, "'", NULL);
@@ -467,6 +471,9 @@ listener_entry_free (EventListenerEntry *e)
  *            object:model-changed
  *            object:active-descendant-changed
  *
+ *  (screen reader events)
+*             screen-reader:region-changed
+ *
  *  (window events)
  *
  *            window:minimize
@@ -506,6 +513,9 @@ listener_entry_free (EventListenerEntry *e)
  *            In general, listening to
  *            toolkit-specific events is not recommended.
  *
+ * Currently, object:text-reading-position needs to be specified explicitly
+ * (it is not implied by object:text), since it is generated by the screen
+ * reader and is thus a special case internally.
  *
  * Returns: #TRUE if successful, otherwise #FALSE.
  **/
@@ -875,6 +885,7 @@ atspi_event_copy (AtspiEvent *src)
   dst->detail2 = src->detail2;
   g_value_init (&dst->any_data, G_VALUE_TYPE (&src->any_data));
   g_value_copy (&src->any_data, &dst->any_data);
+  dst->sender = g_object_ref (src->sender);
   return dst;
 }
 
@@ -884,6 +895,7 @@ atspi_event_free (AtspiEvent *event)
   g_object_unref (event->source);
   g_free (event->type);
   g_value_unset (&event->any_data);
+  g_object_unref (event->sender);
   g_free (event);
 }
 
@@ -954,6 +966,7 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
 {
   char *detail = NULL;
   const char *category = dbus_message_get_interface (message);
+  const char *sender = dbus_message_get_sender (message);
   const char *member = dbus_message_get_member (message);
   const char *signature = dbus_message_get_signature (message);
   gchar *name;
@@ -968,7 +981,7 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
   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);
+   g_warning ("Got invalid signature %s for signal %s from interface %s\n", signature, member, category);
     return DBUS_HANDLER_RESULT_HANDLED;
   }
 
@@ -1021,14 +1034,17 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
     converted_type = p;
   }
   e.type = converted_type;
-  e.source = _atspi_ref_accessible (dbus_message_get_sender(message), dbus_message_get_path(message));
-  if (e.source == NULL)
+  if (strcmp (category, "ScreenReader") != 0)
   {
-    g_warning ("Got no valid source accessible for signal for signal %s from interface %s\n", member, category);
-    g_free (converted_type);
-    g_free (name);
-    g_free (detail);
-    return DBUS_HANDLER_RESULT_HANDLED;
+    e.source = _atspi_ref_accessible (sender, dbus_message_get_path (message));
+    if (e.source == NULL)
+    {
+      g_warning ("Got no valid source accessible for signal %s from interface %s\n", member, category);
+      g_free (converted_type);
+      g_free (name);
+      g_free (detail);
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
   }
 
   dbus_message_iter_recurse (&iter, &iter_variant);
@@ -1039,17 +1055,32 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
       AtspiRect rect;
       if (demarshal_rect (&iter_variant, &rect))
       {
-       g_value_init (&e.any_data, ATSPI_TYPE_RECT);
-       g_value_set_boxed (&e.any_data, &rect);
+        g_value_init (&e.any_data, ATSPI_TYPE_RECT);
+        g_value_set_boxed (&e.any_data, &rect);
       }
       else
       {
         AtspiAccessible *accessible;
-       accessible = _atspi_dbus_return_accessible_from_iter (&iter_variant);
-       g_value_init (&e.any_data, ATSPI_TYPE_ACCESSIBLE);
-       g_value_set_instance (&e.any_data, accessible);
-       if (accessible)
-         g_object_unref (accessible);  /* value now owns it */
+       accessible = _atspi_dbus_return_accessible_from_iter (&iter_variant);
+        if (!strcmp (category, "ScreenReader"))
+        {
+          e.source = accessible;
+          if (e.source == NULL)
+          {
+            g_warning ("Got no valid source accessible for signal %s from interface %s\n", member, category);
+            g_free (converted_type);
+            g_free (name);
+            g_free (detail);
+            return DBUS_HANDLER_RESULT_HANDLED;
+          }
+        }
+        else
+        {
+          g_value_init (&e.any_data, ATSPI_TYPE_ACCESSIBLE);
+          g_value_set_instance (&e.any_data, accessible);
+          if (accessible)
+            g_object_unref (accessible);       /* value now owns it */
+        }
       }
       break;
     }
@@ -1071,6 +1102,8 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
     cache = _atspi_dbus_update_cache_from_dict (e.source, &iter);
   }
 
+  e.sender = _atspi_ref_accessible (sender, ATSPI_DBUS_PATH_ROOT);
+
   if (!strncmp (e.type, "object:children-changed", 23))
   {
     cache_process_children_changed (&e);