* 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
info = g_hash_table_lookup (callbacks, callback);
if (!info)
{
- g_warning ("Atspi: Dereferencing invalid callback %p\n", callback);
+ g_warning ("AT-SPI: Dereferencing invalid callback %p\n", callback);
return;
}
info->ref_count--;
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)
{
return;
child = g_value_get_object (&event->any_data);
+ if (child == NULL)
+ return;
if (!strncmp (event->type, "object:children-changed:add", 27))
{
- if (g_list_find (event->source->children, child))
+ g_ptr_array_remove (event->source->children, child); /* just to be safe */
+ if (event->detail1 < 0 || event->detail1 > event->source->children->len)
+ {
+ event->source->cached_properties &= ~ATSPI_CACHE_CHILDREN;
return;
- event->source->children = g_list_insert (event->source->children,
- g_object_ref (child),
- event->detail1);
+ }
+ /* Unfortunately, there's no g_ptr_array_insert or similar */
+ g_ptr_array_add (event->source->children, NULL);
+ memmove (event->source->children->pdata + event->detail1 + 1,
+ event->source->children->pdata + event->detail1,
+ (event->source->children->len - event->detail1 - 1) * sizeof (gpointer));
+ g_ptr_array_index (event->source->children, event->detail1) = g_object_ref (child);
}
- else if (g_list_find (event->source->children, child))
+ else
{
- event->source->children = g_list_remove (event->source->children, child);
+ g_ptr_array_remove (event->source->children, child);
if (child == child->parent.app->root)
g_object_run_dispose (G_OBJECT (child->parent.app));
- g_object_unref (child);
}
}
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);
* object:model-changed
* object:active-descendant-changed
*
+ * (screen reader events)
+* screen-reader:region-changed
+ *
* (window events)
*
* window:minimize
* 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.
**/
return dst;
}
+/**
+ * atspi_event_listener_register_from_callback_full:
+ * @callback: (scope async): an #AtspiEventListenerCB function pointer.
+ * @user_data: (closure callback)
+ * @callback_destroyed: (destroy callback)
+ * @event_type:
+ * @properties: (element-type utf8)
+ * @error:
+ *
+ * Returns: #TRUE if successful, otherwise #FALSE.
+ *
+ **/
gboolean
atspi_event_listener_register_from_callback_full (AtspiEventListenerCB callback,
void *user_data,
dbus_bus_add_match (_atspi_bus(), matchrule, &d_error);
if (dbus_error_is_set (&d_error))
{
- g_warning ("Atspi: Adding match: %s", d_error.message);
+ g_warning ("AT-SPI: Adding match: %s", d_error.message);
dbus_error_free (&d_error);
/* TODO: Set error */
}
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;
}
g_object_unref (event->source);
g_free (event->type);
g_value_unset (&event->any_data);
+ g_object_unref (event->sender);
g_free (event);
}
if (!convert_event_type_to_dbus (e->type, &category, &name, &detail, NULL))
{
- g_warning ("Atspi: Couldn't parse event: %s\n", e->type);
+ g_warning ("AT-SPI: Couldn't parse event: %s\n", e->type);
return;
}
for (l = event_listeners; l; l = g_list_next (l))
{
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;
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;
}
converted_type = p;
}
e.type = converted_type;
- e.source = _atspi_ref_accessible (dbus_message_get_sender(message), dbus_message_get_path(message));
+ if (strcmp (category, "ScreenReader") != 0)
+ {
+ 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);
switch (dbus_message_iter_get_arg_type (&iter_variant))
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;
+ }
+ 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;
}
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);
+ 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);