From 9eae1f7c2b818b5bd702f99ed97056ca76ea01f6 Mon Sep 17 00:00:00 2001 From: Mike Gorse Date: Fri, 20 Sep 2013 12:16:31 -0500 Subject: [PATCH] Support sending data with events Handle requests for additional data from event listeners (ie, registered with atspi_event_listener_register_full), and allow sending interfaces and screen extents in this way. https://bugzilla.gnome.org/show_bug.cgi?id=708695 --- atk-adaptor/adaptors/accessible-adaptor.c | 31 +++- atk-adaptor/adaptors/action-adaptor.c | 3 +- atk-adaptor/adaptors/collection-adaptor.c | 224 +++++++++++++++++++++++++++- atk-adaptor/adaptors/component-adaptor.c | 37 ++++- atk-adaptor/adaptors/document-adaptor.c | 1 + atk-adaptor/adaptors/editabletext-adaptor.c | 5 +- atk-adaptor/adaptors/hyperlink-adaptor.c | 9 +- atk-adaptor/adaptors/hypertext-adaptor.c | 5 +- atk-adaptor/adaptors/image-adaptor.c | 5 +- atk-adaptor/adaptors/selection-adaptor.c | 9 +- atk-adaptor/adaptors/table-adaptor.c | 5 +- atk-adaptor/adaptors/text-adaptor.c | 5 +- atk-adaptor/adaptors/value-adaptor.c | 9 +- atk-adaptor/bridge.c | 189 +++++++++++++++++++++-- atk-adaptor/bridge.h | 20 +++ atk-adaptor/event.c | 78 ++++++++-- 16 files changed, 576 insertions(+), 59 deletions(-) diff --git a/atk-adaptor/adaptors/accessible-adaptor.c b/atk-adaptor/adaptors/accessible-adaptor.c index 64face9..058b116 100644 --- a/atk-adaptor/adaptors/accessible-adaptor.c +++ b/atk-adaptor/adaptors/accessible-adaptor.c @@ -24,12 +24,14 @@ #include #include +#include "bridge.h" #include "atspi/atspi.h" #include "spi-dbus.h" #include "accessible-stateset.h" #include "object.h" #include "introspection.h" +#include static dbus_bool_t impl_get_Name (DBusMessageIter * iter, void *user_data) @@ -472,6 +474,26 @@ impl_GetAttributes (DBusConnection * bus, return reply; } +static dbus_bool_t +impl_get_Attributes (DBusMessageIter * iter, void *user_data) +{ + DBusMessageIter iter_variant; + AtkObject *object = (AtkObject *) user_data; + AtkAttributeSet *attributes; + + g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE); + + attributes = atk_object_get_attributes (object); + + dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "a{ss}", &iter_variant); + spi_object_append_attribute_set (&iter_variant, attributes); + dbus_message_iter_close_container (iter, &iter_variant); + + atk_attribute_set_free (attributes); + + return TRUE; +} + static DBusMessage * impl_GetApplication (DBusConnection * bus, DBusMessage * message, void *user_data) @@ -522,14 +544,15 @@ static DRouteProperty properties[] = { {impl_get_Locale, NULL, "Locale"}, {impl_get_Parent, NULL, "Parent"}, {impl_get_ChildCount, NULL, "ChildCount"}, + {impl_get_Attributes, NULL, "Attributes"}, {NULL, NULL, NULL} }; void spi_initialize_accessible (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_ACCESSIBLE, - spi_org_a11y_atspi_Accessible, - methods, properties); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_ACCESSIBLE, + spi_org_a11y_atspi_Accessible, + methods, properties); }; diff --git a/atk-adaptor/adaptors/action-adaptor.c b/atk-adaptor/adaptors/action-adaptor.c index ff28fdc..a6c409d 100644 --- a/atk-adaptor/adaptors/action-adaptor.c +++ b/atk-adaptor/adaptors/action-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" @@ -250,7 +251,7 @@ static DRouteProperty properties[] = { void spi_initialize_action (DRoutePath * path) { - droute_path_add_interface (path, + spi_atk_add_interface (path, ATSPI_DBUS_INTERFACE_ACTION, spi_org_a11y_atspi_Action, methods, properties); }; diff --git a/atk-adaptor/adaptors/collection-adaptor.c b/atk-adaptor/adaptors/collection-adaptor.c index c49b502..11c73d8 100644 --- a/atk-adaptor/adaptors/collection-adaptor.c +++ b/atk-adaptor/adaptors/collection-adaptor.c @@ -26,6 +26,7 @@ #include #include +#include "bridge.h" #include "bitarray.h" #include "spi-dbus.h" @@ -1070,6 +1071,224 @@ impl_GetMatchesTo (DBusConnection * bus, DBusMessage * message, } } +static void +append_accessible_properties (DBusMessageIter *iter, AtkObject *obj, + GArray *properties) +{ + DBusMessageIter iter_struct, iter_dict, iter_dict_entry; + AtkStateSet *set; + gint i; + gint count; + + dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &iter_struct); + spi_object_append_reference (&iter_struct, obj); + dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_dict); + if (properties && properties->len) + { + gint i; + for (i = 0; i < properties->len; i++) + { + gchar *prop = g_array_index (properties, char *, i); + DRoutePropertyFunction func; + GType type; + func = _atk_bridge_find_property_func (prop, &type); + if (func && G_TYPE_CHECK_INSTANCE_TYPE (obj, type)) + { + dbus_message_iter_open_container (&iter_dict, DBUS_TYPE_DICT_ENTRY, + NULL, &iter_dict_entry); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop); + func (&iter_dict_entry, obj); + dbus_message_iter_close_container (&iter_dict, &iter_dict_entry); + } + } + } + else + { + GHashTableIter hi; + gpointer key, value; + g_hash_table_iter_init (&hi, spi_global_app_data->property_hash); + while (g_hash_table_iter_next (&hi, &key, &value)) + { + const DRouteProperty *prop = value; + GType type = _atk_bridge_type_from_iface (key); + if (!G_TYPE_CHECK_INSTANCE_TYPE (obj, type)) + continue; + for (;prop->name; prop++) + { + const char *p = key + strlen (key); + gchar *property_name; + while (p[-1] != '.') + p--; + if (!strcmp (p, "Accessible")) + property_name = g_strdup (prop->name); + else + property_name = g_strconcat (p, ".", prop->name, NULL); + dbus_message_iter_open_container (&iter_dict, DBUS_TYPE_DICT_ENTRY, + NULL, &iter_dict_entry); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &property_name); + g_free (property_name); + prop->get (&iter_dict_entry, obj); + dbus_message_iter_close_container (&iter_dict, &iter_dict_entry); + } + } + } + dbus_message_iter_close_container (&iter_struct, &iter_dict); + dbus_message_iter_close_container (iter, &iter_struct); + + set = atk_object_ref_state_set (obj); + if (set) + { + gboolean md = atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS); + g_object_unref (set); + if (md) + return; + } + count = atk_object_get_n_accessible_children (obj); + for (i = 0; i < count; i++) + { + AtkObject *child = atk_object_ref_accessible_child (obj, i); + if (child) + { + append_accessible_properties (iter, child, properties); + g_object_unref (child); + } + } +} + +static void +skip (const char **p) +{ + const char *sig = *p; + gint nest = (*sig != 'a'); + + sig++; + while (*sig) + { + if (*sig == '(' || *sig == '{') + nest++; + else if (*sig == ')' || *sig == '}') + nest--; + sig++; + } + *p = sig; +} + +static gboolean +types_match (DBusMessageIter *iter, char c) +{ + char t = dbus_message_iter_get_arg_type (iter); + + if (t == 'r' && c == '(') + return TRUE; + else if (t != c) + return FALSE; +} + +static void +walk (DBusMessageIter *iter, const char *sig, gboolean array) +{ + while (*sig && *sig != ')' && *sig != '}') + { + if (array && dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_INVALID) + break; + if (!types_match (iter, *sig)) + { + g_error ("Expected %s, got %c", sig, dbus_message_iter_get_arg_type (iter)); + } + switch (*sig) + { + case 's': + { + const char *str; + DBusError error; + dbus_error_init (&error); + dbus_message_iter_get_basic (iter, &str); + g_print ("%s\n", str); + if (!dbus_validate_utf8 (str, &error)) + g_error ("Bad UTF-8 string"); + } + break; + case 'a': + { + DBusMessageIter iter_array; + dbus_message_iter_recurse (iter, &iter_array); + walk (&iter_array, sig + 1, TRUE); + skip (&sig); + } + break; + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + { + DBusMessageIter iter_struct; + dbus_message_iter_recurse (iter, &iter_struct); + walk (&iter_struct, sig + 1, FALSE); + skip (&sig); + } + } + dbus_message_iter_next (iter); + if (!array) + sig++; + } + if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_INVALID) + g_error ("Unexpected data '%c'", dbus_message_iter_get_arg_type (iter)); +} + +static void +walkm (DBusMessage *message) +{ + DBusMessageIter iter; + const char *sig = dbus_message_get_signature (message); + + g_print ("sig: %s\n", sig); + dbus_message_iter_init (message, &iter); + walk (&iter, sig, FALSE); +} + +static DBusMessage * +impl_GetTree (DBusConnection * bus, + DBusMessage * message, void *user_data) +{ + AtkObject *object = (AtkObject *) user_data; + DBusMessage *reply; + DBusMessageIter iter, iter_array; + MatchRulePrivate rule; + GArray *properties; + + g_return_val_if_fail (ATK_IS_OBJECT (user_data), + droute_not_yet_handled_error (message)); + + if (strcmp (dbus_message_get_signature (message), "(aiia{ss}iaiiasib)as") != 0) + return droute_invalid_arguments_error (message); + + properties = g_array_new (TRUE, TRUE, sizeof (char *)); + dbus_message_iter_init (message, &iter); + if (!read_mr (&iter, &rule)) + { + return spi_dbus_general_error (message); + } + + dbus_message_iter_recurse (&iter, &iter_array); + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + const char *prop; + dbus_message_iter_get_basic (&iter_array, &prop); + g_array_append_val (properties, prop); + dbus_message_iter_next (&iter_array); + } + + reply = dbus_message_new_method_return (message); + if (reply) + { + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "((so)a{sv})", + &iter_array); + append_accessible_properties (&iter_array, object, properties); + dbus_message_iter_close_container (&iter, &iter_array); + } +//walkm (reply); + return reply; +} + static DBusMessage * impl_GetMatches (DBusConnection * bus, DBusMessage * message, void *user_data) { @@ -1113,6 +1332,7 @@ impl_GetMatches (DBusConnection * bus, DBusMessage * message, void *user_data) static DRouteMethod methods[] = { {impl_GetMatchesFrom, "GetMatchesFrom"}, {impl_GetMatchesTo, "GetMatchesTo"}, + {impl_GetTree, "GetTree"}, {impl_GetMatches, "GetMatches"}, {NULL, NULL} }; @@ -1120,6 +1340,6 @@ static DRouteMethod methods[] = { void spi_initialize_collection (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_COLLECTION, spi_org_a11y_atspi_Collection, methods, NULL); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_COLLECTION, spi_org_a11y_atspi_Collection, methods, NULL); }; diff --git a/atk-adaptor/adaptors/component-adaptor.c b/atk-adaptor/adaptors/component-adaptor.c index 76b0f7c..192a589 100644 --- a/atk-adaptor/adaptors/component-adaptor.c +++ b/atk-adaptor/adaptors/component-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include #include "spi-dbus.h" @@ -359,6 +360,34 @@ impl_SetPosition (DBusConnection * bus, DBusMessage * message, void *user_data) return reply; } +static dbus_bool_t +impl_get_ScreenExtents (DBusMessageIter * iter, void *user_data) +{ + AtkComponent *component = (AtkComponent *) user_data; + DBusMessageIter iter_variant, iter_struct; + gint ix = -1, iy = -1, iwidth = -1, iheight = -1; + dbus_uint32_t x, y, width, height; + + g_return_val_if_fail (ATK_IS_COMPONENT (user_data), FALSE); + + atk_component_get_extents (component, &ix, &iy, &iwidth, &iheight, ATK_XY_SCREEN); + x = ix; + y = iy; + width = iwidth; + height = iheight; + dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(uuuu)", + &iter_variant); + dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL, + &iter_struct); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &x); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &y); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &width); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &height); + dbus_message_iter_close_container (&iter_variant, &iter_struct); + dbus_message_iter_close_container (iter, &iter_variant); + return TRUE; +} + static DBusMessage * impl_SetSize (DBusConnection * bus, DBusMessage * message, void *user_data) { @@ -407,9 +436,13 @@ static DRouteMethod methods[] = { {NULL, NULL} }; +static DRouteProperty properties[] = { + {impl_get_ScreenExtents, NULL, "ScreenExtents"}, + {NULL, NULL, NULL} +}; void spi_initialize_component (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_COMPONENT, spi_org_a11y_atspi_Component, methods, NULL); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_COMPONENT, spi_org_a11y_atspi_Component, methods, properties); }; diff --git a/atk-adaptor/adaptors/document-adaptor.c b/atk-adaptor/adaptors/document-adaptor.c index f44f0c6..020512b 100644 --- a/atk-adaptor/adaptors/document-adaptor.c +++ b/atk-adaptor/adaptors/document-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "object.h" diff --git a/atk-adaptor/adaptors/editabletext-adaptor.c b/atk-adaptor/adaptors/editabletext-adaptor.c index a983fdc..2e264fc 100644 --- a/atk-adaptor/adaptors/editabletext-adaptor.c +++ b/atk-adaptor/adaptors/editabletext-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "introspection.h" #include "spi-dbus.h" @@ -201,6 +202,6 @@ static DRouteMethod methods[] = { void spi_initialize_editabletext (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_EDITABLE_TEXT, spi_org_a11y_atspi_EditableText, methods, NULL); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_EDITABLE_TEXT, spi_org_a11y_atspi_EditableText, methods, NULL); }; diff --git a/atk-adaptor/adaptors/hyperlink-adaptor.c b/atk-adaptor/adaptors/hyperlink-adaptor.c index e397e1f..0d0dc37 100644 --- a/atk-adaptor/adaptors/hyperlink-adaptor.c +++ b/atk-adaptor/adaptors/hyperlink-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "introspection.h" @@ -148,8 +149,8 @@ static DRouteProperty properties[] = { void spi_initialize_hyperlink (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_HYPERLINK, - spi_org_a11y_atspi_Hyperlink, - methods, properties); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_HYPERLINK, + spi_org_a11y_atspi_Hyperlink, + methods, properties); }; diff --git a/atk-adaptor/adaptors/hypertext-adaptor.c b/atk-adaptor/adaptors/hypertext-adaptor.c index 80d0c52..e31266f 100644 --- a/atk-adaptor/adaptors/hypertext-adaptor.c +++ b/atk-adaptor/adaptors/hypertext-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "object.h" @@ -106,6 +107,6 @@ static DRouteMethod methods[] = { void spi_initialize_hypertext (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_HYPERTEXT, spi_org_a11y_atspi_Hypertext, methods, NULL); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_HYPERTEXT, spi_org_a11y_atspi_Hypertext, methods, NULL); }; diff --git a/atk-adaptor/adaptors/image-adaptor.c b/atk-adaptor/adaptors/image-adaptor.c index c28fd91..89ac20f 100644 --- a/atk-adaptor/adaptors/image-adaptor.c +++ b/atk-adaptor/adaptors/image-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "object.h" @@ -134,6 +135,6 @@ static DRouteProperty properties[] = { void spi_initialize_image (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_IMAGE, spi_org_a11y_atspi_Image, methods, properties); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_IMAGE, spi_org_a11y_atspi_Image, methods, properties); }; diff --git a/atk-adaptor/adaptors/selection-adaptor.c b/atk-adaptor/adaptors/selection-adaptor.c index 33c696d..4776ebc 100644 --- a/atk-adaptor/adaptors/selection-adaptor.c +++ b/atk-adaptor/adaptors/selection-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "object.h" @@ -249,8 +250,8 @@ static DRouteProperty properties[] = { void spi_initialize_selection (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_SELECTION, - spi_org_a11y_atspi_Selection, - methods, properties); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_SELECTION, + spi_org_a11y_atspi_Selection, + methods, properties); }; diff --git a/atk-adaptor/adaptors/table-adaptor.c b/atk-adaptor/adaptors/table-adaptor.c index 9569c9d..d3bbba5 100644 --- a/atk-adaptor/adaptors/table-adaptor.c +++ b/atk-adaptor/adaptors/table-adaptor.c @@ -24,6 +24,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "object.h" @@ -667,6 +668,6 @@ static DRouteProperty properties[] = { void spi_initialize_table (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_TABLE, spi_org_a11y_atspi_Table, methods, properties); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_TABLE, spi_org_a11y_atspi_Table, methods, properties); }; diff --git a/atk-adaptor/adaptors/text-adaptor.c b/atk-adaptor/adaptors/text-adaptor.c index 80bb921..be10349 100644 --- a/atk-adaptor/adaptors/text-adaptor.c +++ b/atk-adaptor/adaptors/text-adaptor.c @@ -26,6 +26,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "object.h" @@ -886,6 +887,6 @@ static DRouteProperty properties[] = { void spi_initialize_text (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_TEXT, spi_org_a11y_atspi_Text, methods, properties); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_TEXT, spi_org_a11y_atspi_Text, methods, properties); }; diff --git a/atk-adaptor/adaptors/value-adaptor.c b/atk-adaptor/adaptors/value-adaptor.c index cf51014..9767fc4 100644 --- a/atk-adaptor/adaptors/value-adaptor.c +++ b/atk-adaptor/adaptors/value-adaptor.c @@ -26,6 +26,7 @@ #include #include +#include "bridge.h" #include "spi-dbus.h" #include "introspection.h" @@ -40,6 +41,7 @@ impl_get_MinimumValue (DBusMessageIter * iter, void *user_data) g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE); + g_value_init (&src, G_TYPE_DOUBLE); atk_value_get_minimum_value (value, &src); g_value_init (&dest, G_TYPE_DOUBLE); @@ -64,6 +66,7 @@ impl_get_MaximumValue (DBusMessageIter * iter, void *user_data) g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE); + g_value_init (&src, G_TYPE_DOUBLE); atk_value_get_maximum_value (value, &src); g_value_init (&dest, G_TYPE_DOUBLE); @@ -84,6 +87,7 @@ impl_get_MinimumIncrement (DBusMessageIter * iter, void *user_data) g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE); + g_value_init (&src, G_TYPE_DOUBLE); atk_value_get_minimum_increment (value, &src); g_value_init (&dest, G_TYPE_DOUBLE); @@ -104,6 +108,7 @@ impl_get_CurrentValue (DBusMessageIter * iter, void *user_data) g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE); + g_value_init (&src, G_TYPE_DOUBLE); atk_value_get_current_value (value, &src); g_value_init (&dest, G_TYPE_DOUBLE); @@ -198,6 +203,6 @@ static DRouteProperty properties[] = { void spi_initialize_value (DRoutePath * path) { - droute_path_add_interface (path, - ATSPI_DBUS_INTERFACE_VALUE, spi_org_a11y_atspi_Value, methods, properties); + spi_atk_add_interface (path, + ATSPI_DBUS_INTERFACE_VALUE, spi_org_a11y_atspi_Value, methods, properties); }; diff --git a/atk-adaptor/bridge.c b/atk-adaptor/bridge.c index 5bcd630..9f5977b 100644 --- a/atk-adaptor/bridge.c +++ b/atk-adaptor/bridge.c @@ -60,25 +60,24 @@ static gboolean inited = FALSE; /*---------------------------------------------------------------------------*/ -static void +static event_data * add_event (const char *bus_name, const char *event) { event_data *evdata; gchar **data; spi_atk_add_client (bus_name); - evdata = (event_data *) g_malloc (sizeof (*evdata)); - if (!evdata) - return; + evdata = g_new0 (event_data, 1); data = g_strsplit (event, ":", 3); if (!data) { g_free (evdata); - return; + return NULL; } evdata->bus_name = g_strdup (bus_name); evdata->data = data; spi_global_app_data->events = g_list_append (spi_global_app_data->events, evdata); + return evdata; } static GSList *clients = NULL; @@ -100,6 +99,135 @@ tally_event_reply () } } +GType +_atk_bridge_type_from_iface (const char *iface) +{ + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_ACCESSIBLE)) + return ATK_TYPE_OBJECT; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_ACTION)) + return ATK_TYPE_ACTION; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_COMPONENT)) + return ATK_TYPE_COMPONENT; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_DOCUMENT)) + return ATK_TYPE_DOCUMENT; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_HYPERTEXT)) + return ATK_TYPE_HYPERTEXT; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_HYPERLINK)) + return ATK_TYPE_HYPERLINK; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_IMAGE)) + return ATK_TYPE_IMAGE; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_SELECTION)) + return ATK_TYPE_SELECTION; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_TABLE)) + return ATK_TYPE_TABLE; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_TEXT)) + return ATK_TYPE_TEXT; + if (!strcmp (iface, ATSPI_DBUS_INTERFACE_VALUE)) + return ATK_TYPE_VALUE; + return 0; +} + +DRoutePropertyFunction +_atk_bridge_find_property_func (const char *property, GType *type) +{ + const char *iface; + const char *member; + DRouteProperty *dp; + + if (!strncasecmp (property, "action.", 7)) + { + iface = ATSPI_DBUS_INTERFACE_ACTION; + member = property + 7; + } + else if (!strncasecmp (property, "component.", 10)) + { + iface = ATSPI_DBUS_INTERFACE_COMPONENT; + member = property + 10; + } + else if (!strncasecmp (property, "selection.", 10)) + { + iface = ATSPI_DBUS_INTERFACE_SELECTION; + member = property + 10; + } + else if (!strncasecmp (property, "table.", 6)) + { + iface = ATSPI_DBUS_INTERFACE_TABLE; + member = property + 6; + } + else if (!strncasecmp (property, "text.", 5)) + { + iface = ATSPI_DBUS_INTERFACE_TEXT; + member = property + 5; + } + else if (!strncasecmp (property, "value.", 6)) + { + iface = ATSPI_DBUS_INTERFACE_VALUE; + member = property + 6; + } + else + { + iface = ATSPI_DBUS_INTERFACE_ACCESSIBLE; + member = property; + } + + *type = _atk_bridge_type_from_iface (iface); + + dp = g_hash_table_lookup (spi_global_app_data->property_hash, iface); + + if (!dp) + return NULL; + + for (;dp->name; dp++) + { + if (!strcasecmp (dp->name, member)) + { + return dp->get; + } + } + return NULL; +} + +static void +add_property_to_event (event_data *evdata, const char *property) +{ + AtspiPropertyDefinition *prop = g_new0 (AtspiPropertyDefinition, 1); + prop->func = _atk_bridge_find_property_func (property, &prop->type); + if (!prop->func) + { + g_warning ("atk-bridge: Request for unknown property '%s'", property); + g_free (prop); + return; + } + + prop->name = g_strdup (property); + evdata->properties = g_slist_append (evdata->properties, prop); +} + +static void +add_event_from_iter (DBusMessageIter *iter) +{ + const char *bus_name, *event; + event_data *evdata; + + dbus_message_iter_get_basic (iter, &bus_name); + dbus_message_iter_next (iter); + dbus_message_iter_get_basic (iter, &event); + dbus_message_iter_next (iter); + evdata = add_event (bus_name, event); + if (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY) + { + DBusMessageIter iter_sub_array; + dbus_message_iter_recurse (iter, &iter_sub_array); + while (dbus_message_iter_get_arg_type (&iter_sub_array) != DBUS_TYPE_INVALID) + { + const char *property; + dbus_message_iter_get_basic (&iter_sub_array, &property); + add_property_to_event (evdata, property); + dbus_message_iter_next (&iter_sub_array); + } + } +} + static void get_events_reply (DBusPendingCall *pending, void *user_data) { @@ -109,7 +237,8 @@ get_events_reply (DBusPendingCall *pending, void *user_data) if (!reply || !spi_global_app_data) goto done; - if (strcmp (dbus_message_get_signature (reply), "a(ss)") != 0) + if (strcmp (dbus_message_get_signature (reply), "a(ss)") != 0 && + strcmp (dbus_message_get_signature (reply), "a(ssas)") != 0) { g_warning ("atk-bridge: GetRegisteredEvents returned message with unknown signature"); goto done; @@ -119,12 +248,8 @@ get_events_reply (DBusPendingCall *pending, void *user_data) dbus_message_iter_recurse (&iter, &iter_array); while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) { - char *bus_name, *event; dbus_message_iter_recurse (&iter_array, &iter_struct); - dbus_message_iter_get_basic (&iter_struct, &bus_name); - dbus_message_iter_next (&iter_struct); - dbus_message_iter_get_basic (&iter_struct, &event); - add_event (bus_name, event); + add_event_from_iter (&iter_struct); dbus_message_iter_next (&iter_array); } @@ -568,14 +693,26 @@ static void handle_event_listener_registered (DBusConnection *bus, DBusMessage *message, void *user_data) { - const char *name; - char *sender; + DBusMessageIter iter; + const char *signature = dbus_message_get_signature (message); - if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &sender, - DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) + if (strcmp (signature, "ssas") != 0) + { + g_warning ("got RegisterEvent with invalid signature '%s'", signature); return; + } - add_event (sender, name); + dbus_message_iter_init (message, &iter); + add_event_from_iter (&iter); +} + +static void +free_property_definition (void *data) +{ + AtspiPropertyDefinition *pd = data; + + g_free (pd->name); + g_free (pd); } static void @@ -599,6 +736,7 @@ remove_events (const char *bus_name, const char *event) GList *events = spi_global_app_data->events; g_strfreev (evdata->data); g_free (evdata->bus_name); + g_slist_free_full (evdata->properties, free_property_definition); g_free (evdata); if (list->prev) { @@ -1066,4 +1204,23 @@ spi_atk_remove_client (const char *bus_name) } } +void +spi_atk_add_interface (DRoutePath *path, + const char *name, + const char *introspect, + const DRouteMethod *methods, + const DRouteProperty *properties) +{ + droute_path_add_interface (path, name, introspect, methods, properties); + + if (properties) + { + if (!spi_global_app_data->property_hash) + spi_global_app_data->property_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, NULL); + g_hash_table_insert (spi_global_app_data->property_hash, g_strdup (name), + (gpointer) properties); + } +} /*END------------------------------------------------------------------------*/ diff --git a/atk-adaptor/bridge.h b/atk-adaptor/bridge.h index ddc79f5..64882e4 100644 --- a/atk-adaptor/bridge.h +++ b/atk-adaptor/bridge.h @@ -33,11 +33,20 @@ typedef struct _SpiBridgeClass SpiBridgeClass; G_BEGIN_DECLS +typedef struct _AtspiPropertyDefinition AtspiPropertyDefinition; +struct _AtspiPropertyDefinition +{ + char *name; + GType type; + DRoutePropertyFunction func; +}; + typedef struct _event_data event_data; struct _event_data { gchar *bus_name; gchar **data; + GSList *properties; }; struct _SpiBridge @@ -63,6 +72,7 @@ gchar *app_tmp_dir; gchar *app_bus_addr; GList *events; gboolean events_initialized; + GHashTable *property_hash; }; extern SpiBridge *spi_global_app_data; @@ -72,6 +82,16 @@ void spi_atk_remove_client (const char *bus_name); int spi_atk_create_socket (SpiBridge *app); +void spi_atk_add_interface (DRoutePath *path, + const char *name, + const char *introspect, + const DRouteMethod *methods, + const DRouteProperty *properties); + +DRoutePropertyFunction _atk_bridge_find_property_func (const char *property, + GType *type); + +GType _atk_bridge_type_from_iface (const char *iface); G_END_DECLS #endif /* BRIDGE_H */ diff --git a/atk-adaptor/event.c b/atk-adaptor/event.c index fa7cbbd..0430271 100644 --- a/atk-adaptor/event.c +++ b/atk-adaptor/event.c @@ -353,13 +353,37 @@ ensure_proper_format (const char *name) return ret; } +void +append_properties (GArray *properties, event_data *evdata) +{ + GSList *ls; + gint i; + + for (ls = evdata->properties; ls; ls = ls->next) + { + gboolean dup = FALSE; + for (i = 0; i < properties->len; i++) + { + if (ls->data == g_array_index (properties, AtspiPropertyDefinition *, i)) + { + dup = TRUE; + break; + } + } + if (!dup) + g_array_append_val (properties, ls->data); + } +} + static gboolean -signal_is_needed (const gchar *klass, const gchar *major, const gchar *minor) +signal_is_needed (const gchar *klass, const gchar *major, const gchar *minor, + GArray **properties) { gchar *data [4]; event_data *evdata; gboolean ret = FALSE; GList *list; + GArray *props = NULL; if (!spi_global_app_data->events_initialized) return TRUE; @@ -379,32 +403,28 @@ signal_is_needed (const gchar *klass, const gchar *major, const gchar *minor) !g_strcmp0 (data [2], "accessible-parent") || !g_strcmp0 (data [2], "accessible-role"))) || !g_strcmp0 (data [1], "StateChanged")) - { - g_free (data [2]); - g_free (data [1]); - g_free (data [0]); - return TRUE; - } + ret = TRUE; /* Hack: events such as "object::text-changed::insert:system" as generated by Gecko */ data [2][strcspn (data [2], ":")] = '\0'; + for (list = spi_global_app_data->events; list; list = list->next) { evdata = list->data; if (spi_event_is_subtype (data, evdata->data)) { ret = TRUE; - break; + if (!props) + props = g_array_new (TRUE, TRUE, sizeof (AtspiPropertyDefinition *)); + append_properties (props, evdata); } } -#if 0 - g_print("event: %s %s %s: %d\n", data[0], data[1], data[2], ret); -#endif g_free (data [2]); g_free (data [1]); g_free (data [0]); + *properties = props; return ret; } @@ -420,6 +440,14 @@ adapt_minor_for_dbus (const char *source) return ret; } +static void +open_variant (DBusMessageIter *iter, const char *name, const char *type, + DBusMessageIter *out) +{ + dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &name); + dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, type, out); +} + /* * Emits an AT-SPI event. * AT-SPI events names are split into three parts: @@ -447,14 +475,15 @@ emit_event (AtkObject *obj, gchar *cname; DBusMessage *sig; - DBusMessageIter iter; + DBusMessageIter iter, iter_dict, iter_dict_entry, iter_variant, iter_array; + GArray *properties = NULL; if (!klass) klass = ""; if (!major) major = ""; if (!minor) minor = ""; if (!type) type = "u"; - if (!signal_is_needed (klass, major, minor)) + if (!signal_is_needed (klass, major, minor, &properties)) return; path = spi_register_object_to_path (spi_global_register, G_OBJECT (obj)); @@ -476,7 +505,28 @@ emit_event (AtkObject *obj, dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1); dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2); append_variant (&iter, type, val); - spi_object_append_reference (&iter, spi_global_app_data->root); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict); + /* Add requested properties, unless the object is being marked defunct, in + which case it's safest not to touch it */ + if (minor == NULL || strcmp (minor, "defunct") != 0 || detail1 == 0) + { + if (properties) + { + gint i; + for (i = 0; i < properties->len; i++) + { + AtspiPropertyDefinition *prop = g_array_index (properties, AtspiPropertyDefinition *, i); + dbus_message_iter_open_container (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, + &iter_dict_entry); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop->name); + prop->func (&iter_dict_entry, obj); + dbus_message_iter_close_container (&iter_dict, &iter_dict_entry); + } + g_array_free (properties, TRUE); + } + } + dbus_message_iter_close_container (&iter, &iter_dict); dbus_connection_send(bus, sig, NULL); dbus_message_unref(sig); -- 2.7.4