diff options
author | Federico Mena Quintero <federico@gnome.org> | 2022-07-13 03:08:23 +0000 |
---|---|---|
committer | Federico Mena Quintero <federico@gnome.org> | 2022-07-13 03:08:23 +0000 |
commit | 026ac28a2872619876faefaaccacd0d3f01abd91 (patch) | |
tree | ceea4a35bb3bdb7d1138c7c13bf44e59963a9a79 | |
parent | 7748c5b4417c239fab6d39a8efacb83f14f777ea (diff) | |
parent | 7afe89d2508d20d64785098fb7b737be40a72720 (diff) | |
download | at-spi2-core-026ac28a2872619876faefaaccacd0d3f01abd91.tar.gz |
Merge branch 'start-refactor' into 'main'
Start refactoring into marshalers and translators
See merge request GNOME/at-spi2-core!98
-rw-r--r-- | .gitlab-ci.yml | 13 | ||||
-rw-r--r-- | atspi/atspi-accessible.c | 3 | ||||
-rw-r--r-- | atspi/atspi-collection.c | 2 | ||||
-rw-r--r-- | atspi/atspi-event-listener.c | 2 | ||||
-rw-r--r-- | atspi/atspi-misc-private.h | 2 | ||||
-rw-r--r-- | atspi/atspi-misc.c | 119 | ||||
-rw-r--r-- | atspi/atspi-relation.c | 2 | ||||
-rw-r--r-- | atspi/atspi-table-cell.c | 2 | ||||
-rw-r--r-- | ci/container_builds.yml | 63 | ||||
-rwxr-xr-x | ci/run-registryd-tests.sh | 24 | ||||
-rw-r--r-- | dbind/dbtest.c | 5 | ||||
-rw-r--r-- | registryd/de-types.h | 18 | ||||
-rw-r--r-- | registryd/deviceeventcontroller-x11.c | 5 | ||||
-rw-r--r-- | registryd/deviceeventcontroller.c | 6 | ||||
-rw-r--r-- | registryd/event-source.c | 3 | ||||
-rw-r--r-- | registryd/registry.c | 458 | ||||
-rw-r--r-- | registryd/registry.h | 1 | ||||
-rw-r--r-- | tests/dbusmock/mock_accessible_app.py | 75 | ||||
-rw-r--r-- | tests/registryd/__init__.py | 1 | ||||
-rw-r--r-- | tests/registryd/conftest.py | 74 | ||||
-rw-r--r-- | tests/registryd/test_registry_startup.py | 26 | ||||
-rw-r--r-- | xml/Socket.xml | 41 |
22 files changed, 628 insertions, 317 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 962946a1..740bc14d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,15 +59,18 @@ opensuse-x86_64: - meson install -C _build - mkdir /tmp/test+dir+with+funny+chars - export XDG_RUNTIME_DIR=/tmp/test+dir+with+funny+chars # See https://gitlab.gnome.org/GNOME/at-spi2-core/-/issues/48 + - dbus-run-session -- ci/run-registryd-tests.sh - dbus-run-session -- ci/run-tests.sh artifacts: reports: - junit: "_build/meson-logs/testlog.junit.xml" + junit: + - "_build/meson-logs/testlog.junit.xml" + - "_build/tests/registryd/registryd-pytest.junit.xml" when: always name: "at-spi2-core-${CI_COMMIT_REF_NAME}" paths: - - "${CI_PROJECT_DIR}/_build/meson-logs" - - "${CI_PROJECT_DIR}/_build/atspi/Atspi-2.0.gir" + - "_build/meson-logs" + - "_build/tests/registryd" fedora-x86_64: stage: build @@ -87,8 +90,7 @@ fedora-x86_64: when: always name: "at-spi2-core-${CI_COMMIT_REF_NAME}" paths: - - "${CI_PROJECT_DIR}/_build/meson-logs" - - "${CI_PROJECT_DIR}/_build/atspi/Atspi-2.0.gir" + - "_build/meson-logs" # Run static analysis on the code. # @@ -153,6 +155,7 @@ coverage: - meson setup ${MESON_EXTRA_FLAGS} --prefix /usr _build . - meson compile -C _build - meson install -C _build + - dbus-run-session -- ci/run-registryd-tests.sh - dbus-run-session -- ci/run-tests.sh - mkdir -p public - grcov _build --source-dir ./ --prefix-dir ../ --output-type cobertura --branch --ignore-not-existing -o coverage.xml diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index 26cf0ba7..9c4725a4 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -424,7 +424,7 @@ atspi_accessible_get_parent (AtspiAccessible *obj, GError **error) dbus_message_iter_init (reply, &iter); dbus_message_iter_recurse (&iter, &iter_variant); g_clear_object (&obj->accessible_parent); - obj->accessible_parent = _atspi_dbus_return_accessible_from_iter (&iter_variant); + obj->accessible_parent = _atspi_dbus_consume_accessible (&iter_variant); dbus_message_unref (reply); _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT); } @@ -968,7 +968,6 @@ _atspi_accessible_is_a (AtspiAccessible *accessible, dbus_message_iter_init (reply, &iter); _atspi_dbus_set_interfaces (accessible, &iter); dbus_message_unref (reply); - _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES); } n = _atspi_get_iface_num (interface_name); diff --git a/atspi/atspi-collection.c b/atspi/atspi-collection.c index d4d15372..34fbbabe 100644 --- a/atspi/atspi-collection.c +++ b/atspi/atspi-collection.c @@ -91,7 +91,7 @@ return_accessibles (DBusMessage *message) while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) { AtspiAccessible *accessible; - accessible = _atspi_dbus_return_accessible_from_iter (&iter_array); + accessible = _atspi_dbus_consume_accessible (&iter_array); ret = g_array_append_val (ret, accessible); /* Iter was moved already, so no need to call dbus_message_iter_next */ } diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c index d591115c..68eb921e 100644 --- a/atspi/atspi-event-listener.c +++ b/atspi/atspi-event-listener.c @@ -1139,7 +1139,7 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message) else { AtspiAccessible *accessible; - accessible = _atspi_dbus_return_accessible_from_iter (&iter_variant); + accessible = _atspi_dbus_consume_accessible (&iter_variant); if (!strcmp (category, "ScreenReader")) { g_object_unref (e.source); diff --git a/atspi/atspi-misc-private.h b/atspi/atspi-misc-private.h index e76a1a94..b3040d5d 100644 --- a/atspi/atspi-misc-private.h +++ b/atspi/atspi-misc-private.h @@ -81,7 +81,7 @@ AtspiAccessible * _atspi_dbus_return_accessible_from_message (DBusMessage *message); AtspiAccessible * -_atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter); +_atspi_dbus_consume_accessible (DBusMessageIter *iter); AtspiHyperlink * _atspi_dbus_return_hyperlink_from_message (DBusMessage *message); diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index 1fb39929..18abfceb 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -410,7 +410,7 @@ add_app_to_desktop (AtspiAccessible *a, const char *bus_name) return (obj != NULL); } -void +static void get_reference_from_iter (DBusMessageIter *iter, const char **app_name, const char **path) { DBusMessageIter iter_struct; @@ -426,8 +426,8 @@ static void add_accessible_from_iter (DBusMessageIter *iter) { DBusMessageIter iter_struct, iter_array; - const char *app_name, *path; AtspiAccessible *accessible; + AtspiAccessible *parent; const char *name, *description; dbus_uint32_t role; gboolean children_cached = FALSE; @@ -436,8 +436,7 @@ add_accessible_from_iter (DBusMessageIter *iter) dbus_message_iter_recurse (iter, &iter_struct); /* get accessible */ - get_reference_from_iter (&iter_struct, &app_name, &path); - accessible = ref_accessible (app_name, path); + accessible = _atspi_dbus_consume_accessible (&iter_struct); if (!accessible) return; @@ -445,10 +444,10 @@ add_accessible_from_iter (DBusMessageIter *iter) dbus_message_iter_next (&iter_struct); /* get parent */ - get_reference_from_iter (&iter_struct, &app_name, &path); + parent = _atspi_dbus_consume_accessible (&iter_struct); if (accessible->accessible_parent) g_object_unref (accessible->accessible_parent); - accessible->accessible_parent = ref_accessible (app_name, path); + accessible->accessible_parent = parent; if (dbus_message_iter_get_arg_type (&iter_struct) == 'i') { @@ -487,8 +486,7 @@ add_accessible_from_iter (DBusMessageIter *iter) while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) { AtspiAccessible *child; - get_reference_from_iter (&iter_array, &app_name, &path); - child = ref_accessible (app_name, path); + child = _atspi_dbus_consume_accessible (&iter_array); g_ptr_array_remove (accessible->children, child); g_ptr_array_add (accessible->children, child); } @@ -661,7 +659,7 @@ _atspi_dbus_return_accessible_from_message (DBusMessage *message) if (!strcmp (signature, "(so)")) { dbus_message_iter_init (message, &iter); - retval = _atspi_dbus_return_accessible_from_iter (&iter); + retval = _atspi_dbus_consume_accessible (&iter); } else { @@ -671,8 +669,9 @@ _atspi_dbus_return_accessible_from_message (DBusMessage *message) return retval; } +/* Enters an iter which must be already pointing to a (so) and returns the accessible for it */ AtspiAccessible * -_atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter) +_atspi_dbus_consume_accessible (DBusMessageIter *iter) { const char *app_name, *path; @@ -1251,7 +1250,7 @@ _atspi_dbus_get_property (gpointer obj, const char *interface, const char *name, } if (!strcmp (type, "(so)")) { - *((AtspiAccessible **)data) = _atspi_dbus_return_accessible_from_iter (&iter_variant); + *((AtspiAccessible **)data) = _atspi_dbus_consume_accessible (&iter_variant); } else { @@ -1379,36 +1378,98 @@ _atspi_dbus_attribute_array_from_iter (DBusMessageIter *iter) return array; } -void -_atspi_dbus_set_interfaces (AtspiAccessible *accessible, DBusMessageIter *iter) +typedef enum { + DEMARSHAL_STATUS_SUCCESS, + DEMARSHAL_STATUS_INVALID_SIGNATURE, + DEMARSHAL_STATUS_INVALID_VALUE, +} DemarshalStatus; + +typedef struct { + /* array of (char *) */ + GPtrArray *names; +} InterfaceNames; + +static DemarshalStatus +interface_names_demarshal (DBusMessageIter *iter, InterfaceNames **out_interfaces) { - DBusMessageIter iter_array; - char *iter_sig = dbus_message_iter_get_signature (iter); + char *sig = dbus_message_iter_get_signature (iter); + gboolean matches = strcmp (sig, "as") == 0; + dbus_free (sig); - accessible->interfaces = 0; - if (strcmp (iter_sig, "as") != 0) + *out_interfaces = NULL; + + GPtrArray *names = g_ptr_array_new_with_free_func (g_free); + + if (!matches) { - g_warning ("_atspi_dbus_set_interfaces: Passed iterator with invalid signature %s", iter_sig); - dbus_free (iter_sig); - return; + return DEMARSHAL_STATUS_INVALID_SIGNATURE; } - dbus_free (iter_sig); + + DBusMessageIter iter_array; dbus_message_iter_recurse (iter, &iter_array); while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) { const char *iface; - gint n; dbus_message_iter_get_basic (&iter_array, &iface); - if (!strcmp (iface, "org.freedesktop.DBus.Introspectable")) continue; - n = _atspi_get_iface_num (iface); - if (n == -1) + g_ptr_array_add (names, g_strdup (iface)); + dbus_message_iter_next (&iter_array); + } + + InterfaceNames *ifaces = g_new0 (InterfaceNames, 1); + ifaces->names = names; + *out_interfaces = ifaces; + return DEMARSHAL_STATUS_SUCCESS; +} + +/* Converts an array of interface names to a value suitable for AtspiAccessible.interfaces */ +static gint +interface_names_to_bitmask (const InterfaceNames *ifaces) +{ + gint val = 0; + guint i; + + g_assert (ifaces->names != NULL); + + for (i = 0; i < ifaces->names->len; i++) { - g_warning ("AT-SPI: Unknown interface %s", iface); + const char *name = g_ptr_array_index (ifaces->names, i); + gint iface_num = _atspi_get_iface_num (name); + if (iface_num == -1) + { + g_warning ("AT-SPI: Unknown interface %s", name); + } + else + { + val |= (1 << iface_num); + } } - else - accessible->interfaces |= (1 << n); - dbus_message_iter_next (&iter_array); + + return val; +} + +static void +interface_names_free (InterfaceNames *ifaces) +{ + g_ptr_array_free (ifaces->names, TRUE); + g_free (ifaces); +} + +void +_atspi_dbus_set_interfaces (AtspiAccessible *accessible, DBusMessageIter *iter) +{ + InterfaceNames *ifaces; + + accessible->interfaces = 0; + + if (interface_names_demarshal (iter, &ifaces) != DEMARSHAL_STATUS_SUCCESS) + { + g_warning ("Passed iterator with invalid signature"); + return; } + + accessible->interfaces = interface_names_to_bitmask (ifaces); + interface_names_free (ifaces); + _atspi_accessible_add_cache (accessible, ATSPI_CACHE_INTERFACES); } diff --git a/atspi/atspi-relation.c b/atspi/atspi-relation.c index c441f2bb..10063439 100644 --- a/atspi/atspi-relation.c +++ b/atspi/atspi-relation.c @@ -99,7 +99,7 @@ _atspi_relation_new_from_iter (DBusMessageIter *iter) while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) { AtspiAccessible *accessible; - accessible = _atspi_dbus_return_accessible_from_iter (&iter_array); + accessible = _atspi_dbus_consume_accessible (&iter_array); relation->targets = g_array_append_val (relation->targets, accessible); /* Iter was moved already, so no need to call dbus_message_iter_next */ } diff --git a/atspi/atspi-table-cell.c b/atspi/atspi-table-cell.c index 83fe534c..a33e0a89 100644 --- a/atspi/atspi-table-cell.c +++ b/atspi/atspi-table-cell.c @@ -46,7 +46,7 @@ get_object_array_and_unref (DBusMessage *reply) dbus_message_iter_recurse (&iter, &iter_array); while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) { - AtspiAccessible *accessible = _atspi_dbus_return_accessible_from_iter (&iter_array); + AtspiAccessible *accessible = _atspi_dbus_consume_accessible (&iter_array); g_ptr_array_add (array, accessible); } dbus_message_unref (reply); diff --git a/ci/container_builds.yml b/ci/container_builds.yml index e9d268a0..40dc6f24 100644 --- a/ci/container_builds.yml +++ b/ci/container_builds.yml @@ -13,7 +13,7 @@ include: variables: # When branching change the suffix to avoid conflicts with images # from the main branch - BASE_TAG: "2022-07-07.0-main" + BASE_TAG: "2022-07-12.0-main" RUST_STABLE: "1.58.1" .container.opensuse@x86_64: @@ -23,11 +23,34 @@ variables: FDO_DISTRIBUTION_VERSION: "tumbleweed" FDO_UPSTREAM_REPO: "gnome/at-spi2-core" FDO_DISTRIBUTION_PACKAGES: >- - bzip2 clang clang-tools findutils gcc dbus-1 dbus-1-devel gettext git - glib2-devel gobject-introspection-devel - gsettings-desktop-schemas gtk-doc itstool libasan6 libxml2-devel - libxkbcommon-devel libXi-devel libXtst-devel lcov llvm meson ninja - python310 python310-python-dbusmock python310-gobject tar wget + bzip2 + clang + clang-tools + dbus-1 + dbus-1-devel + findutils + gcc + gettext + git + glib2-devel + gobject-introspection-devel + gsettings-desktop-schemas + gtk-doc + itstool + libXi-devel + libXtst-devel + libasan6 + libxkbcommon-devel + libxml2-devel + llvm + meson + ninja + python310 + python310-gobject + python310-pytest + python310-python-dbusmock + tar + wget FDO_DISTRIBUTION_EXEC: >- bash ci/install-rust.sh ${RUST_STABLE} x86_64-unknown-linux-gnu @@ -44,10 +67,30 @@ opensuse-container@x86_64: FDO_DISTRIBUTION_VERSION: "35" FDO_UPSTREAM_REPO: "gnome/at-spi2-core" FDO_DISTRIBUTION_PACKAGES: >- - clang clang-tools-extra findutils gcc dbus-daemon dbus-devel dbus-tools systemd-devel - gettext git glib2-devel gobject-introspection-devel - gsettings-desktop-schemas gtk-doc itstool libasan libxml2-devel - libxkbcommon-devel libXi-devel libXtst-devel lcov meson procps python38 + clang + clang-tools-extra + dbus-daemon + dbus-devel + dbus-tools + findutils + gcc + gettext + git + glib2-devel + gobject-introspection-devel + gsettings-desktop-schemas + gtk-doc + itstool + lcov + libXi-devel + libXtst-devel + libasan + libxkbcommon-devel + libxml2-devel + meson + procps + python38 + systemd-devel fedora-container@x86_64: extends: diff --git a/ci/run-registryd-tests.sh b/ci/run-registryd-tests.sh new file mode 100755 index 00000000..62eb1118 --- /dev/null +++ b/ci/run-registryd-tests.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +set -eu + +echo "About to run the tests. First we'll launch a gnome-session DBus mock." + +python3 -m dbusmock --session org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager & +sleep 1 + +gdbus call --session \ + --dest org.gnome.SessionManager \ + --object-path /org/gnome/SessionManager \ + --method org.freedesktop.DBus.Mock.AddTemplate 'tests/dbusmock/mock-gnome-session.py' '{}' + +gdbus call --session \ + --dest org.gnome.SessionManager \ + --object-path /org/gnome/SessionManager \ + --method org.freedesktop.DBus.Mock.SetSessionRunning true + +mkdir -p _build/tests/registryd + +cd tests/registryd + +pytest -v --junit-xml=../../_build/tests/registryd/registryd-pytest.junit.xml diff --git a/dbind/dbtest.c b/dbind/dbtest.c index d4f56906..22ea2165 100644 --- a/dbind/dbtest.c +++ b/dbind/dbtest.c @@ -367,9 +367,8 @@ void test_helpers () int main (int argc, char **argv) { - DBusConnection *bus; - - bus = dbus_bus_get (DBUS_BUS_SESSION, NULL); + DBusConnection *bus = dbus_bus_get (DBUS_BUS_SESSION, NULL); + g_assert (bus != NULL); test_helpers (); test_marshalling (); diff --git a/registryd/de-types.h b/registryd/de-types.h index ea05dda7..d26cc90f 100644 --- a/registryd/de-types.h +++ b/registryd/de-types.h @@ -51,9 +51,7 @@ typedef enum { Accessibility_KEY_UNLOCKMODIFIERS, } Accessibility_KeySynthType; -typedef struct _Accessibility_DeviceEvent Accessibility_DeviceEvent; -struct _Accessibility_DeviceEvent -{ +typedef struct { Accessibility_EventType type; dbus_uint32_t id; dbus_uint32_t hw_code; @@ -61,23 +59,19 @@ struct _Accessibility_DeviceEvent dbus_uint32_t timestamp; char * event_string; dbus_bool_t is_text; -}; +} Accessibility_DeviceEvent; -typedef struct _Accessibility_EventListenerMode Accessibility_EventListenerMode; -struct _Accessibility_EventListenerMode -{ +typedef struct { dbus_bool_t synchronous; dbus_bool_t preemptive; dbus_bool_t global; -}; +} Accessibility_EventListenerMode; -typedef struct _Accessibility_KeyDefinition Accessibility_KeyDefinition; -struct _Accessibility_KeyDefinition -{ +typedef struct { dbus_int32_t keycode; dbus_int32_t keysym; char *keystring; dbus_int32_t unused; -}; +} Accessibility_KeyDefinition; #endif /* SPI_DE_TYPES_H_ */ diff --git a/registryd/deviceeventcontroller-x11.c b/registryd/deviceeventcontroller-x11.c index 40973fa2..010fdf0a 100644 --- a/registryd/deviceeventcontroller-x11.c +++ b/registryd/deviceeventcontroller-x11.c @@ -64,11 +64,10 @@ static Accessibility_DeviceEvent pressed_event; static void wait_for_release_event (XEvent *event, SpiDEController *controller); static int spi_error_code = 0; -struct _SpiPoint { +typedef struct { gint x; gint y; -}; -typedef struct _SpiPoint SpiPoint; +} SpiPoint; static SpiPoint last_mouse_pos_static = {0, 0}; static SpiPoint *last_mouse_pos = &last_mouse_pos_static; static unsigned int mouse_mask_state = 0; diff --git a/registryd/deviceeventcontroller.c b/registryd/deviceeventcontroller.c index 0fe65556..740995f4 100644 --- a/registryd/deviceeventcontroller.c +++ b/registryd/deviceeventcontroller.c @@ -72,11 +72,11 @@ typedef struct { /* A pointer to our parent object class */ static int spi_error_code = 0; -struct _SpiPoint { + +typedef struct { gint x; gint y; -}; -typedef struct _SpiPoint SpiPoint; +} SpiPoint; static unsigned int mouse_mask_state = 0; static unsigned int key_modifier_mask = diff --git a/registryd/event-source.c b/registryd/event-source.c index e82908ae..ca4340c5 100644 --- a/registryd/event-source.c +++ b/registryd/event-source.c @@ -24,8 +24,7 @@ #include "event-source.h" -typedef struct _DisplaySource -{ +typedef struct { GSource source; Display *display; diff --git a/registryd/registry.c b/registryd/registry.c index b09c0e31..5e08f6e4 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -30,30 +30,17 @@ #include "registry.h" #include "introspection.h" -typedef struct event_data event_data; -struct event_data +typedef struct { gchar *listener_bus_name; gchar *app_bus_name; gchar **data; GSList *properties; -}; - -static void -children_added_listener (DBusConnection * bus, - gint index, - const gchar * name, - const gchar * path); - -static void -children_removed_listener (DBusConnection * bus, - gint index, - const gchar * name, - const gchar * path); +} EventData; /*---------------------------------------------------------------------------*/ -typedef struct _SpiReference +typedef struct { gchar *name; gchar *path; @@ -84,9 +71,24 @@ spi_reference_free (SpiReference *ref) G_DEFINE_TYPE(SpiRegistry, spi_registry, G_TYPE_OBJECT) static void +spi_registry_finalize (GObject *object) +{ + SpiRegistry *registry = SPI_REGISTRY (object); + + g_clear_pointer (®istry->bus_unique_name, g_free); + + G_OBJECT_CLASS (spi_registry_parent_class)->finalize (object); +} + +static void spi_registry_class_init (SpiRegistryClass *klass) { + GObjectClass *gobject_class; + spi_registry_parent_class = g_type_class_ref (G_TYPE_OBJECT); + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = spi_registry_finalize; } static void @@ -162,21 +164,58 @@ find_index_of_reference (GPtrArray *arr, const gchar *name, const gchar * path, } static void -add_application (SpiRegistry *reg, DBusConnection *bus, const gchar *name, const gchar *path) +emit_event (DBusConnection *bus, + const char *iface_name, + const char *signal_name, + const char *detail_str, + dbus_int32_t detail1, + dbus_int32_t detail2, + SpiReference *app) +{ + DBusMessage *sig; + DBusMessageIter iter, iter_variant, iter_array; + + sig = dbus_message_new_signal(SPI_DBUS_PATH_ROOT, iface_name, signal_name); + + dbus_message_iter_init_append(sig, &iter); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &detail_str); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(so)", + &iter_variant); + append_reference (&iter_variant, app->name, app->path); + dbus_message_iter_close_container (&iter, &iter_variant); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", + &iter_array); + dbus_message_iter_close_container (&iter, &iter_array); + + dbus_connection_send(bus, sig, NULL); + dbus_message_unref(sig); +} + +static void +add_application (SpiRegistry *registry, SpiReference *app_root) { - g_ptr_array_add (reg->apps, spi_reference_new (name, path)); - children_added_listener (bus, reg->apps->len - 1, name, path); + gint index; + + g_ptr_array_add (registry->apps, app_root); + index = registry->apps->len - 1; + + emit_event (registry->bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "add", index, 0, app_root); } static void -set_id (SpiRegistry *reg, DBusConnection *bus, const gchar *name, const gchar *path) +set_id (SpiRegistry *registry, SpiReference *app) { DBusMessage *message; DBusMessageIter iter, iter_variant; const char *iface_application = "org.a11y.atspi.Application"; const char *id = "Id"; - message = dbus_message_new_method_call (name, path, + message = dbus_message_new_method_call (app->name, app->path, DBUS_INTERFACE_PROPERTIES, "Set"); if (!message) return; @@ -184,22 +223,22 @@ set_id (SpiRegistry *reg, DBusConnection *bus, const gchar *name, const gchar *p dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface_application); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &id); dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "i", &iter_variant); - dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_INT32, ®->id); + dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_INT32, ®istry->id); /* TODO: This will cause problems if we cycle through 2^31 ids */ - reg->id++; + registry->id++; dbus_message_iter_close_container (&iter, &iter_variant); - dbus_connection_send (bus, message, NULL); + dbus_connection_send (registry->bus, message, NULL); dbus_message_unref (message); } static void -remove_application (SpiRegistry *reg, DBusConnection *bus, guint index) +remove_application (SpiRegistry *registry, guint index) { - SpiReference *ref = g_ptr_array_index (reg->apps, index); + SpiReference *ref = g_ptr_array_index (registry->apps, index); - spi_remove_device_listeners (reg->dec, ref->name); - children_removed_listener (bus, index, ref->name, ref->path); - g_ptr_array_remove_index (reg->apps, index); + spi_remove_device_listeners (registry->dec, ref->name); + emit_event (registry->bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "remove", index, 0, ref); + g_ptr_array_remove_index (registry->apps, index); } static gboolean @@ -241,7 +280,7 @@ remove_events (SpiRegistry *registry, const char *bus_name, const char *event) for (list = registry->events; list;) { - event_data *evdata = list->data; + EventData *evdata = list->data; list = list->next; if (!g_strcmp0 (evdata->listener_bus_name, bus_name) && event_is_subtype (evdata->data, remove_data)) @@ -275,10 +314,9 @@ remove_events (SpiRegistry *registry, const char *bus_name, const char *event) } static void -handle_disconnection (DBusConnection *bus, DBusMessage *message, void *user_data) +handle_disconnection (SpiRegistry *registry, DBusMessage *message) { char *name, *old, *new; - SpiRegistry *reg = SPI_REGISTRY (user_data); if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &name, @@ -290,17 +328,17 @@ handle_disconnection (DBusConnection *bus, DBusMessage *message, void *user_data { /* Remove all children with the application name the same as the disconnected application. */ guint i; - for (i = 0; i < reg->apps->len; i++) + for (i = 0; i < registry->apps->len; i++) { - SpiReference *ref = g_ptr_array_index (reg->apps, i); + SpiReference *ref = g_ptr_array_index (registry->apps, i); if (!g_strcmp0 (old, ref->name)) { - remove_application (reg, bus, i); + remove_application (registry, i); i--; } - } + } - remove_events (reg, old, ""); + remove_events (registry, old, ""); } } } @@ -343,7 +381,9 @@ ensure_proper_format (const char *name) static DBusHandlerResult signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data) { + SpiRegistry *reg = SPI_REGISTRY (user_data); guint res = DBUS_HANDLER_RESULT_HANDLED; + const gint type = dbus_message_get_type (message); const char *iface = dbus_message_get_interface (message); const char *member = dbus_message_get_member (message); @@ -353,58 +393,83 @@ signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data) if (!g_strcmp0(iface, DBUS_INTERFACE_DBUS) && !g_strcmp0(member, "NameOwnerChanged")) - handle_disconnection (bus, message, user_data); + handle_disconnection (reg, message); else res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; return res; } +typedef enum { + DEMARSHAL_STATUS_SUCCESS, + DEMARSHAL_STATUS_INVALID_SIGNATURE, + DEMARSHAL_STATUS_INVALID_VALUE, +} DemarshalStatus; + /* org.at_spi.Socket interface */ /*---------------------------------------------------------------------------*/ -static DBusMessage* -impl_Embed (DBusConnection *bus, DBusMessage *message, void *user_data) +static DemarshalStatus +socket_embed_demarshal (DBusMessage *message, SpiReference **out_app_root) { - SpiRegistry *reg = SPI_REGISTRY (user_data); DBusMessageIter iter, iter_struct; const gchar *app_name, *obj_path; - - DBusMessage *reply = NULL; - DBusMessageIter reply_iter; + SpiReference *app_root; dbus_message_iter_init (message, &iter); dbus_message_iter_recurse (&iter, &iter_struct); if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_STRING)) - goto error; + return DEMARSHAL_STATUS_INVALID_SIGNATURE; dbus_message_iter_get_basic (&iter_struct, &app_name); if (!app_name) app_name = dbus_message_get_sender (message); if (!dbus_message_iter_next (&iter_struct)) - goto error; + return DEMARSHAL_STATUS_INVALID_SIGNATURE; if (!(dbus_message_iter_get_arg_type (&iter_struct) == DBUS_TYPE_OBJECT_PATH)) - goto error; + return DEMARSHAL_STATUS_INVALID_SIGNATURE; dbus_message_iter_get_basic (&iter_struct, &obj_path); - add_application(reg, bus, app_name, obj_path); + app_root = spi_reference_new (app_name, obj_path); + *out_app_root = app_root; + + return DEMARSHAL_STATUS_SUCCESS; +} + +static SpiReference * +socket_embed (SpiRegistry *registry, SpiReference *app_root) +{ + add_application (registry, app_root); + set_id (registry, app_root); + return spi_reference_new (registry->bus_unique_name, SPI_DBUS_PATH_ROOT); +} + +static DBusMessage* +impl_Embed (DBusMessage *message, SpiRegistry *registry) +{ + SpiReference *app_root = NULL; + SpiReference *result; + + if (socket_embed_demarshal (message, &app_root) != DEMARSHAL_STATUS_SUCCESS) + { + return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments"); + } + + DBusMessage *reply = NULL; + DBusMessageIter reply_iter; - set_id (reg, bus, app_name, obj_path); + result = socket_embed (registry, app_root); /* takes ownership of the app_root */ reply = dbus_message_new_method_return (message); dbus_message_iter_init_append (reply, &reply_iter); - append_reference (&reply_iter, - dbus_bus_get_unique_name (bus), - SPI_DBUS_PATH_ROOT); + append_reference (&reply_iter, result->name, result->path); + spi_reference_free (result); return reply; -error: - return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Invalid arguments"); } static DBusMessage* -impl_Unembed (DBusConnection *bus, DBusMessage *message, void *user_data) +impl_Unembed (DBusMessage *message, SpiRegistry *registry) { - SpiRegistry *reg = SPI_REGISTRY (user_data); DBusMessageIter iter, iter_struct; gchar *app_name, *obj_path; guint index; @@ -420,8 +485,8 @@ impl_Unembed (DBusConnection *bus, DBusMessage *message, void *user_data) goto error; dbus_message_iter_get_basic (&iter_struct, &obj_path); - if (find_index_of_reference (reg->apps, app_name, obj_path, &index)) - remove_application(reg, bus, index); + if (find_index_of_reference (registry->apps, app_name, obj_path, &index)) + remove_application (registry, index); return NULL; error: @@ -432,7 +497,7 @@ error: /*---------------------------------------------------------------------------*/ static DBusMessage * -impl_Contains (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_Contains (DBusMessage * message, SpiRegistry *registry) { dbus_bool_t retval = FALSE; DBusMessage *reply; @@ -444,8 +509,7 @@ impl_Contains (DBusConnection * bus, DBusMessage * message, void *user_data) } static DBusMessage * -impl_GetAccessibleAtPoint (DBusConnection * bus, DBusMessage * message, - void *user_data) +impl_GetAccessibleAtPoint (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply = NULL; DBusMessageIter iter; @@ -453,14 +517,14 @@ impl_GetAccessibleAtPoint (DBusConnection * bus, DBusMessage * message, reply = dbus_message_new_method_return (message); dbus_message_iter_init_append (reply, &iter); append_reference (&iter, - dbus_bus_get_unique_name (bus), + registry->bus_unique_name, SPI_DBUS_PATH_NULL); return reply; } static DBusMessage * -impl_GetExtents (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_GetExtents (DBusMessage * message, SpiRegistry *registry) { dbus_int32_t x = 0, y = 0, width = 1024, height = 768; DBusMessage *reply; @@ -479,8 +543,7 @@ impl_GetExtents (DBusConnection * bus, DBusMessage * message, void *user_data) } static DBusMessage * -impl_GetPosition (DBusConnection * bus, DBusMessage * message, - void *user_data) +impl_GetPosition (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; dbus_int32_t x = 0, y = 0; @@ -492,7 +555,7 @@ impl_GetPosition (DBusConnection * bus, DBusMessage * message, } static DBusMessage * -impl_GetSize (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_GetSize (DBusMessage * message, SpiRegistry *registry) { /* TODO - Get the screen size */ DBusMessage *reply; @@ -507,7 +570,7 @@ impl_GetSize (DBusConnection * bus, DBusMessage * message, void *user_data) #define LAYER_WIDGET 3; static DBusMessage * -impl_GetLayer (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_GetLayer (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; dbus_uint32_t rv = LAYER_WIDGET; @@ -519,8 +582,7 @@ impl_GetLayer (DBusConnection * bus, DBusMessage * message, void *user_data) } static DBusMessage * -impl_GetMDIZOrder (DBusConnection * bus, DBusMessage * message, - void *user_data) +impl_GetMDIZOrder (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; dbus_int16_t rv = 0; @@ -532,7 +594,7 @@ impl_GetMDIZOrder (DBusConnection * bus, DBusMessage * message, } static DBusMessage * -impl_GrabFocus (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_GrabFocus (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; dbus_bool_t retval = FALSE; @@ -544,7 +606,7 @@ impl_GrabFocus (DBusConnection * bus, DBusMessage * message, void *user_data) } static DBusMessage * -impl_GetAlpha (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_GetAlpha (DBusMessage * message, SpiRegistry *registry) { double rv = 1.0; DBusMessage *reply; @@ -559,21 +621,21 @@ impl_GetAlpha (DBusConnection * bus, DBusMessage * message, void *user_data) /*---------------------------------------------------------------------------*/ static dbus_bool_t -impl_get_Name (DBusMessageIter * iter, void *user_data) +impl_get_Name (DBusMessageIter * iter, SpiRegistry *registry) { const gchar *name = "main"; return return_v_string (iter, name); } static dbus_bool_t -impl_get_Description (DBusMessageIter * iter, void *user_data) +impl_get_Description (DBusMessageIter * iter, SpiRegistry *registry) { const gchar *description = ""; return return_v_string (iter, description); } static dbus_bool_t -impl_get_Parent (DBusMessageIter * iter, void *user_data) +impl_get_Parent (DBusMessageIter * iter, SpiRegistry *registry) { const gchar *name = ""; DBusMessageIter iter_variant; @@ -588,10 +650,9 @@ impl_get_Parent (DBusMessageIter * iter, void *user_data) } static dbus_bool_t -impl_get_ChildCount (DBusMessageIter * iter, void *user_data) +impl_get_ChildCount (DBusMessageIter * iter, SpiRegistry *registry) { - SpiRegistry *reg = SPI_REGISTRY (user_data); - dbus_int32_t rv = reg->apps->len; + dbus_int32_t rv = registry->apps->len; dbus_bool_t result; DBusMessageIter iter_variant; @@ -604,22 +665,20 @@ impl_get_ChildCount (DBusMessageIter * iter, void *user_data) } static dbus_bool_t -impl_get_ToolkitName (DBusMessageIter * iter, void *user_data) +impl_get_ToolkitName (DBusMessageIter * iter, SpiRegistry *registry) { return return_v_string (iter, "at-spi-registry"); } static dbus_bool_t -impl_get_ToolkitVersion (DBusMessageIter * iter, void *user_data) +impl_get_ToolkitVersion (DBusMessageIter * iter, SpiRegistry *registry) { return return_v_string (iter, "2.0"); } static DBusMessage * -impl_GetChildAtIndex (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetChildAtIndex (DBusMessage * message, SpiRegistry *registry) { - SpiRegistry *reg = SPI_REGISTRY (user_data); DBusMessage *reply; DBusMessageIter iter; DBusError error; @@ -636,11 +695,11 @@ impl_GetChildAtIndex (DBusConnection * bus, reply = dbus_message_new_method_return (message); dbus_message_iter_init_append (reply, &iter); - if (i < 0 || i >= reg->apps->len) + if (i < 0 || i >= registry->apps->len) append_reference (&iter, SPI_DBUS_NAME_REGISTRY, SPI_DBUS_PATH_NULL); else { - ref = g_ptr_array_index (reg->apps, i); + ref = g_ptr_array_index (registry->apps, i); append_reference (&iter, ref->name, ref->path); } @@ -648,21 +707,19 @@ impl_GetChildAtIndex (DBusConnection * bus, } static DBusMessage * -impl_GetChildren (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetChildren (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply = NULL; DBusMessageIter iter, iter_array; - SpiRegistry *reg = SPI_REGISTRY (user_data); int i; reply = dbus_message_new_method_return (message); dbus_message_iter_init_append (reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array); - for (i=0; i < reg->apps->len; i++) + for (i=0; i < registry->apps->len; i++) { - SpiReference *current = g_ptr_array_index (reg->apps, i); + SpiReference *current = g_ptr_array_index (registry->apps, i); append_reference (&iter_array, current->name, current->path); } dbus_message_iter_close_container(&iter, &iter_array); @@ -670,8 +727,7 @@ impl_GetChildren (DBusConnection * bus, } static DBusMessage * -impl_GetIndexInParent (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetIndexInParent (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; dbus_uint32_t rv = 0; @@ -682,8 +738,7 @@ impl_GetIndexInParent (DBusConnection * bus, } static DBusMessage * -impl_GetRelationSet (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetRelationSet (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; DBusMessageIter iter, iter_array; @@ -697,7 +752,7 @@ impl_GetRelationSet (DBusConnection * bus, } static DBusMessage * -impl_GetRole (DBusConnection * bus, DBusMessage * message, void * user_data) +impl_GetRole (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; dbus_uint32_t rv = 14; /* TODO: Get DESKTOP_FRAME from somewhere */ @@ -708,8 +763,7 @@ impl_GetRole (DBusConnection * bus, DBusMessage * message, void * user_data) } static DBusMessage * -impl_GetRoleName (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetRoleName (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; const char *role_name = "desktop frame"; @@ -721,8 +775,7 @@ impl_GetRoleName (DBusConnection * bus, } static DBusMessage * -impl_GetLocalizedRoleName (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetLocalizedRoleName (DBusMessage * message, SpiRegistry *registry) { /* TODO - Localize this */ DBusMessage *reply; @@ -735,7 +788,7 @@ impl_GetLocalizedRoleName (DBusConnection * bus, } static DBusMessage * -impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_GetState (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply = NULL; DBusMessageIter iter, iter_array; @@ -757,8 +810,7 @@ impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data) } static DBusMessage * -impl_GetAttributes (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetAttributes (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply = NULL; DBusMessageIter iter, array; @@ -772,8 +824,7 @@ impl_GetAttributes (DBusConnection * bus, } static DBusMessage * -impl_GetApplication (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetApplication (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply = NULL; DBusMessageIter iter; @@ -781,15 +832,14 @@ impl_GetApplication (DBusConnection * bus, reply = dbus_message_new_method_return (message); dbus_message_iter_init_append (reply, &iter); append_reference (&iter, - dbus_bus_get_unique_name (bus), + registry->bus_unique_name, SPI_DBUS_PATH_NULL); return reply; } static DBusMessage * -impl_GetInterfaces (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_GetInterfaces (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; DBusMessageIter iter, iter_array; @@ -810,7 +860,7 @@ impl_GetInterfaces (DBusConnection * bus, } static DBusMessage * -impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_GetItems (DBusMessage * message, SpiRegistry *registry) { DBusMessage *reply; DBusMessageIter iter, iter_array; @@ -829,12 +879,11 @@ impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data) * a method call and signal for now. */ static DBusMessage * -impl_register_event (DBusConnection *bus, DBusMessage *message, void *user_data) +impl_RegisterEvent (DBusMessage *message, SpiRegistry *registry) { - SpiRegistry *registry = SPI_REGISTRY (user_data); const char *orig_name; gchar *name; - event_data *evdata; + EventData *evdata; gchar **data; DBusMessage *signal; const char *sender = dbus_message_get_sender (message); @@ -854,7 +903,7 @@ impl_register_event (DBusConnection *bus, DBusMessage *message, void *user_data) dbus_message_iter_next (&iter); name = ensure_proper_format (orig_name); - evdata = g_new0 (event_data, 1); + evdata = g_new0 (EventData, 1); data = g_strsplit (name, ":", 3); evdata->listener_bus_name = g_strdup (sender); evdata->data = data; @@ -907,7 +956,7 @@ impl_register_event (DBusConnection *bus, DBusMessage *message, void *user_data) ls = g_slist_next (ls); } dbus_message_iter_close_container (&iter, &iter_array); - dbus_connection_send (bus, signal, NULL); + dbus_connection_send (registry->bus, signal, NULL); dbus_message_unref (signal); } @@ -916,9 +965,8 @@ impl_register_event (DBusConnection *bus, DBusMessage *message, void *user_data) } static DBusMessage * -impl_deregister_event (DBusConnection *bus, DBusMessage *message, void *user_data) +impl_DeregisterEvent (DBusMessage *message, SpiRegistry *registry) { - SpiRegistry *registry = SPI_REGISTRY (user_data); const char *orig_name; gchar *name; const char *sender = dbus_message_get_sender (message); @@ -935,10 +983,9 @@ impl_deregister_event (DBusConnection *bus, DBusMessage *message, void *user_dat } static DBusMessage * -impl_get_registered_events (DBusConnection *bus, DBusMessage *message, void *user_data) +impl_GetRegisteredEvents (DBusMessage *message, SpiRegistry *registry) { - SpiRegistry *registry = SPI_REGISTRY (user_data); - event_data *evdata; + EventData *evdata; DBusMessage *reply; DBusMessageIter iter, iter_struct, iter_array; GList *list; @@ -999,8 +1046,7 @@ static const char *introspection_footer = "</node>"; static DBusMessage * -impl_Introspect_root (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_Introspect_root (DBusMessage * message, SpiRegistry *registry) { GString *output; gchar *final; @@ -1027,8 +1073,7 @@ impl_Introspect_root (DBusConnection * bus, } static DBusMessage * -impl_Introspect_registry (DBusConnection * bus, - DBusMessage * message, void *user_data) +impl_Introspect_registry (DBusMessage * message, SpiRegistry *registry) { GString *output; gchar *final; @@ -1055,88 +1100,10 @@ impl_Introspect_registry (DBusConnection * bus, /*---------------------------------------------------------------------------*/ -/* - * Emits an AT-SPI event. - * AT-SPI events names are split into three parts: - * class:major:minor - * This is mapped onto D-Bus events as: - * D-Bus Interface:Signal Name:Detail argument - * - * Marshals a basic type into the 'any_data' attribute of - * the AT-SPI event. - */ -static void -emit_event (DBusConnection *bus, - const char *klass, - const char *major, - const char *minor, - dbus_int32_t detail1, - dbus_int32_t detail2, - const char *name, - const char *path) -{ - DBusMessage *sig; - DBusMessageIter iter, iter_variant, iter_array; - - sig = dbus_message_new_signal(SPI_DBUS_PATH_ROOT, klass, major); - - dbus_message_iter_init_append(sig, &iter); - - dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor); - dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1); - dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2); - - dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, "(so)", - &iter_variant); - append_reference (&iter_variant, name, path); - dbus_message_iter_close_container (&iter, &iter_variant); - - dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", - &iter_array); - dbus_message_iter_close_container (&iter, &iter_array); - - dbus_connection_send(bus, sig, NULL); - dbus_message_unref(sig); -} - -/*---------------------------------------------------------------------------*/ - -/* - * Children changed signal converter and forwarder. - * - * Klass (Interface) org.a11y.atspi.Event.Object - * Major is the signal name. - * Minor is 'add' or 'remove' - * detail1 is the index. - * detail2 is 0. - * any_data is the child reference. - */ - -static void -children_added_listener (DBusConnection * bus, - gint index, - const gchar * name, - const gchar * path) -{ - emit_event (bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "add", index, 0, - name, path); -} - -static void -children_removed_listener (DBusConnection * bus, - gint index, - const gchar * name, - const gchar * path) -{ - emit_event (bus, SPI_DBUS_INTERFACE_EVENT_OBJECT, "ChildrenChanged", "remove", index, 0, - name, path); -} - -/*---------------------------------------------------------------------------*/ - static DBusHandlerResult handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) { + SpiRegistry *registry = SPI_REGISTRY (user_data); DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; const gchar *iface = dbus_message_get_interface (message); @@ -1177,13 +1144,13 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) if (!strcmp (prop_iface, SPI_DBUS_INTERFACE_ACCESSIBLE)) { if (!strcmp (prop_member, "Name")) - impl_get_Name (&iter, user_data); + impl_get_Name (&iter, registry); else if (!strcmp (prop_member, "Description")) - impl_get_Description (&iter, user_data); + impl_get_Description (&iter, registry); else if (!strcmp (prop_member, "Parent")) - impl_get_Parent (&iter, user_data); + impl_get_Parent (&iter, registry); else if (!strcmp (prop_member, "ChildCount")) - impl_get_ChildCount (&iter, user_data); + impl_get_ChildCount (&iter, registry); else { dbus_message_unref (reply); @@ -1193,9 +1160,9 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) else if (!strcmp (prop_iface, SPI_DBUS_INTERFACE_APPLICATION)) { if (!strcmp (prop_member, "ToolkitName")) - impl_get_ToolkitName (&iter, user_data); + impl_get_ToolkitName (&iter, registry); else if (!strcmp (prop_member, "ToolkitVersion")) - impl_get_ToolkitVersion (&iter, user_data); + impl_get_ToolkitVersion (&iter, registry); else { dbus_message_unref (reply); @@ -1224,27 +1191,27 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) { result = DBUS_HANDLER_RESULT_HANDLED; if (!strcmp (member, "GetChildAtIndex")) - reply = impl_GetChildAtIndex (bus, message, user_data); + reply = impl_GetChildAtIndex (message, registry); else if (!strcmp (member, "GetChildren")) - reply = impl_GetChildren (bus, message, user_data); + reply = impl_GetChildren (message, registry); else if (!strcmp (member, "GetIndexInParent")) - reply = impl_GetIndexInParent (bus, message, user_data); + reply = impl_GetIndexInParent (message, registry); else if (!strcmp (member, "GetRelationSet")) - reply = impl_GetRelationSet (bus, message, user_data); + reply = impl_GetRelationSet (message, registry); else if (!strcmp (member, "GetRole")) - reply = impl_GetRole (bus, message, user_data); + reply = impl_GetRole (message, registry); else if (!strcmp (member, "GetRoleName")) - reply = impl_GetRoleName (bus, message, user_data); + reply = impl_GetRoleName (message, registry); else if (!strcmp (member, "GetLocalizedRoleName")) - reply = impl_GetLocalizedRoleName (bus, message, user_data); + reply = impl_GetLocalizedRoleName (message, registry); else if (!strcmp (member, "GetState")) - reply = impl_GetState (bus, message, user_data); + reply = impl_GetState (message, registry); else if (!strcmp (member, "GetAttributes")) - reply = impl_GetAttributes (bus, message, user_data); + reply = impl_GetAttributes (message, registry); else if (!strcmp (member, "GetApplication")) - reply = impl_GetApplication (bus, message, user_data); + reply = impl_GetApplication (message, registry); else if (!strcmp (member, "GetInterfaces")) - reply = impl_GetInterfaces (bus, message, user_data); + reply = impl_GetInterfaces (message, registry); else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1253,23 +1220,23 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) { result = DBUS_HANDLER_RESULT_HANDLED; if (!strcmp (member, "Contains")) - reply = impl_Contains (bus, message, user_data); + reply = impl_Contains (message, registry); else if (!strcmp (member, "GetAccessibleAtPoint")) - reply = impl_GetAccessibleAtPoint (bus, message, user_data); + reply = impl_GetAccessibleAtPoint (message, registry); else if (!strcmp (member, "GetExtents")) - reply = impl_GetExtents (bus, message, user_data); + reply = impl_GetExtents (message, registry); else if (!strcmp (member, "GetPosition")) - reply = impl_GetPosition (bus, message, user_data); + reply = impl_GetPosition (message, registry); else if (!strcmp (member, "GetSize")) - reply = impl_GetSize (bus, message, user_data); + reply = impl_GetSize (message, registry); else if (!strcmp (member, "GetLayer")) - reply = impl_GetLayer (bus, message, user_data); + reply = impl_GetLayer (message, registry); else if (!strcmp (member, "GetMDIZOrder")) - reply = impl_GetMDIZOrder (bus, message, user_data); + reply = impl_GetMDIZOrder (message, registry); else if (!strcmp (member, "GrabFocus")) - reply = impl_GrabFocus (bus, message, user_data); + reply = impl_GrabFocus (message, registry); else if (!strcmp (member, "GetAlpha")) - reply = impl_GetAlpha (bus, message, user_data); + reply = impl_GetAlpha (message, registry); else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1278,9 +1245,9 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) { result = DBUS_HANDLER_RESULT_HANDLED; if (!strcmp (member, "Embed")) - reply = impl_Embed (bus, message, user_data); + reply = impl_Embed (message, registry); else if (!strcmp (member, "Unembed")) - reply = impl_Unembed (bus, message, user_data); + reply = impl_Unembed (message, registry); else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1289,7 +1256,7 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) { result = DBUS_HANDLER_RESULT_HANDLED; if (!strcmp (member, "Introspect")) - reply = impl_Introspect_root (bus, message, user_data); + reply = impl_Introspect_root (message, registry); else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1317,6 +1284,7 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) static DBusHandlerResult handle_method_cache (DBusConnection *bus, DBusMessage *message, void *user_data) { + SpiRegistry *registry = SPI_REGISTRY (user_data); DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; const gchar *iface = dbus_message_get_interface (message); @@ -1335,7 +1303,7 @@ handle_method_cache (DBusConnection *bus, DBusMessage *message, void *user_data) { result = DBUS_HANDLER_RESULT_HANDLED; if (!strcmp (member, "GetItems")) - reply = impl_GetItems (bus, message, user_data); + reply = impl_GetItems (message, registry); else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1356,6 +1324,7 @@ handle_method_cache (DBusConnection *bus, DBusMessage *message, void *user_data) static DBusHandlerResult handle_method_registry (DBusConnection *bus, DBusMessage *message, void *user_data) { + SpiRegistry *registry = SPI_REGISTRY (user_data); DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; const gchar *iface = dbus_message_get_interface (message); @@ -1374,11 +1343,11 @@ handle_method_registry (DBusConnection *bus, DBusMessage *message, void *user_da { result = DBUS_HANDLER_RESULT_HANDLED; if (!strcmp(member, "RegisterEvent")) - reply = impl_register_event (bus, message, user_data); + reply = impl_RegisterEvent (message, registry); else if (!strcmp(member, "DeregisterEvent")) - reply = impl_deregister_event (bus, message, user_data); + reply = impl_DeregisterEvent (message, registry); else if (!strcmp(member, "GetRegisteredEvents")) - reply = impl_get_registered_events (bus, message, user_data); + reply = impl_GetRegisteredEvents (message, registry); else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1387,7 +1356,7 @@ handle_method_registry (DBusConnection *bus, DBusMessage *message, void *user_da { result = DBUS_HANDLER_RESULT_HANDLED; if (!strcmp (member, "Introspect")) - reply = impl_Introspect_registry (bus, message, user_data); + reply = impl_Introspect_registry (message, registry); else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1441,24 +1410,29 @@ static gchar *app_sig_match_name_owner = SpiRegistry * spi_registry_new (DBusConnection *bus) { - SpiRegistry *reg = g_object_new (SPI_REGISTRY_TYPE, NULL); + SpiRegistry *registry = g_object_new (SPI_REGISTRY_TYPE, NULL); + const char *bus_unique_name; + + bus_unique_name = dbus_bus_get_unique_name (bus); + g_assert (bus_unique_name != NULL); - reg->bus = bus; + registry->bus = bus; + registry->bus_unique_name = g_strdup (bus_unique_name); dbus_bus_add_match (bus, app_sig_match_name_owner, NULL); - dbus_connection_add_filter (bus, signal_filter, reg, NULL); + dbus_connection_add_filter (bus, signal_filter, registry, NULL); - dbus_connection_register_object_path (bus, SPI_DBUS_PATH_ROOT, &root_vtable, reg); + dbus_connection_register_object_path (bus, SPI_DBUS_PATH_ROOT, &root_vtable, registry); - dbus_connection_register_object_path (bus, SPI_DBUS_PATH_CACHE, &cache_vtable, reg); + dbus_connection_register_object_path (bus, SPI_DBUS_PATH_CACHE, &cache_vtable, registry); - dbus_connection_register_object_path (bus, SPI_DBUS_PATH_REGISTRY, ®istry_vtable, reg); + dbus_connection_register_object_path (bus, SPI_DBUS_PATH_REGISTRY, ®istry_vtable, registry); emit_Available (bus); - reg->events = NULL; + registry->events = NULL; - return reg; + return registry; } /*END------------------------------------------------------------------------*/ diff --git a/registryd/registry.h b/registryd/registry.h index 19b1a8f0..394a9986 100644 --- a/registryd/registry.h +++ b/registryd/registry.h @@ -49,6 +49,7 @@ struct _SpiRegistry { dbus_int32_t id; DBusConnection *bus; + char *bus_unique_name; GList *events; }; diff --git a/tests/dbusmock/mock_accessible_app.py b/tests/dbusmock/mock_accessible_app.py new file mode 100644 index 00000000..11856865 --- /dev/null +++ b/tests/dbusmock/mock_accessible_app.py @@ -0,0 +1,75 @@ +import dbus +import dbus.service + +PROPERTIES_IFACE = 'org.freedesktop.DBus.Properties' +ACCESSIBLE_IFACE = 'org.a11y.atspi.Accessible' +APPLICATION_IFACE = 'org.a11y.atspi.Application' +SOCKET_IFACE = 'org.a11y.atspi.Socket' + +ROOT_PATH = '/org/a11y/atspi/accessible/root' + +def accessible_get_property(prop_name): + if prop_name == 'Name': + pass # s + elif prop_name == 'Description': + pass # s + elif prop_name == 'Parent': + pass # (so) + elif prop_name == 'ChildCount': + pass # i + elif prop_name == 'Locale': + pass # s + elif prop_name == 'AccessibleId': + pass # s + else: + raise ValueError(f'unknown property name {prop_name}') + +def application_get_property(prop_name): + return None + +@dbus.service.method(PROPERTIES_IFACE, in_signature='ss', out_signature='v') +def Get(self, iface_name, prop_name): + if iface_name == ACCESSIBLE_IFACE: + return accessible_get_property(prop_name) + elif iface_name == PROPERTY_IFACE: + return application_get_property(prop_name) + +@dbus.service.method(PROPERTIES_IFACE, in_signature='ssv', out_signature='') +def Set(self, iface_name, prop_name, value): + if iface_name == APPLICATION_IFACE: + pass # FIXME + +def get_accesssibility_bus_address(): + bus = dbus.SessionBus() + bus_launcher = bus.get_object('org.a11y.Bus', '/org/a11y/bus') + return str(bus_launcher.GetAddress(dbus_interface='org.a11y.Bus')) + +def get_registry_root(a11y_bus): + return a11y_bus.get_object('org.a11y.atspi.Registry', ROOT_PATH) + +class MyObject(dbus.service.Object): + def __init__(self, a11y_bus, path): + dbus.service.Object.__init__(self, a11y_bus, path) + +if __name__ == '__main__': + from dbus.mainloop.glib import DBusGMainLoop + from gi.repository import GLib + + DBusGMainLoop(set_as_default=True) + main_loop = GLib.MainLoop() + + a11y_address = get_accesssibility_bus_address() + a11y_bus = dbus.bus.BusConnection(a11y_address) + + registry = get_registry_root(a11y_bus) + assert registry is not None + + my_unique_name = a11y_bus.get_unique_name() + my_root = MyObject(a11y_bus, ROOT_PATH) + + (registry_bus_name, registry_root_path) = registry.Embed((my_unique_name, my_root), dbus_interface=SOCKET_IFACE) + + print("registry bus name:", registry_bus_name) + print("registry_root_path:", registry_root_path) + + # main_loop.run() diff --git a/tests/registryd/__init__.py b/tests/registryd/__init__.py new file mode 100644 index 00000000..d18f92c6 --- /dev/null +++ b/tests/registryd/__init__.py @@ -0,0 +1 @@ +dummy = "hello" diff --git a/tests/registryd/conftest.py b/tests/registryd/conftest.py new file mode 100644 index 00000000..a80af69f --- /dev/null +++ b/tests/registryd/conftest.py @@ -0,0 +1,74 @@ +# This file contains common test fixtures for registryd's tests. +# Using pytest's terminology for a test's steps: +# +# 1. Arrange: create a test fixture; this usually involves a running registry and an accessible app stub. +# +# 2. Act: manipulate the app or the registry. +# +# 3. Assert: ensure that the thing being manipulated is in the expected state. +# +# 4. Cleanup: Terminate the registry and the app. It is important that the registry exits cleanly, +# so it can write out its code coverage information. +# +# This module exports the following fixtures: +# +# * main_loop - a GLib.MainLoop integrated with the DBusGMainLoop. +# +# * session_manager - A mock gnome-session to control the lifetime of daemons. In +# reality, the fixture assumes that there is a gnome-session mock running (see +# ci/run-registryd-tests.sh) and just tells that mock to Logout at fixture teardown +# time, so that all daemons that monitor the session's lifetime will exit at teardown. +# +# * registry - A dbus.proxies.ProxyObject for the registry's root object. This automatically +# depends on a session_manager fixture to control its lifetime. + +import pytest +import dbus + +@pytest.fixture +def main_loop(): + from dbus.mainloop.glib import DBusGMainLoop + from gi.repository import GLib + + DBusGMainLoop(set_as_default=True) + loop = GLib.MainLoop() + return loop + +def get_accesssibility_bus_address(): + bus = dbus.SessionBus() + bus_launcher = bus.get_object('org.a11y.Bus', '/org/a11y/bus') + return str(bus_launcher.GetAddress(dbus_interface='org.a11y.Bus')) + +def get_registry_root(a11y_bus): + return a11y_bus.get_object('org.a11y.atspi.Registry', '/org/a11y/atspi/accessible/root') + +@pytest.fixture +def session_manager(): + # This assumes that pytest is running in this environment: + # + # * A session dbus daemon is running + # + # * There is a gnome-session mock running + # + # See the ci/run-registryd-tests.sh script to see how that environment is set up. + + import time + + bus = dbus.SessionBus() + mock_session = bus.get_object('org.gnome.SessionManager', '/org/gnome/SessionManager') + + # return a dummy object as a fixture + yield object() + + # Tell all session clients to terminate + mock_session.Logout(0, dbus_interface='org.gnome.SessionManager') + + # Reset mock session back to its starting state + mock_session.Reset(dbus_interface='org.freedesktop.DBus.Mock') + +@pytest.fixture +def registry(main_loop, session_manager): + a11y_address = get_accesssibility_bus_address() + a11y_bus = dbus.bus.BusConnection(a11y_address) + + return get_registry_root(a11y_bus) diff --git a/tests/registryd/test_registry_startup.py b/tests/registryd/test_registry_startup.py new file mode 100644 index 00000000..ee00c4b9 --- /dev/null +++ b/tests/registryd/test_registry_startup.py @@ -0,0 +1,26 @@ +# Pytest will pick up this module automatically when running just "pytest". +# +# Each test_*() function gets passed test fixtures, which are defined +# in conftest.py. So, a function "def test_foo(bar)" will get a bar() +# fixture created for it. + +PROPERTIES_IFACE = 'org.freedesktop.DBus.Properties' +ACCESSIBLE_IFACE = 'org.a11y.atspi.Accessible' + +def get_property(proxy, iface_name, prop_name): + return proxy.Get(iface_name, prop_name, dbus_interface=PROPERTIES_IFACE) + +def test_accessible_iface_properties(registry, session_manager): + values = [ + ('Name', 'main'), + ('Description', ''), + ] + + for prop_name, expected in values: + assert get_property(registry, ACCESSIBLE_IFACE, prop_name) == expected + +def test_registry_root_has_null_parent(registry, session_manager): + assert get_property(registry, ACCESSIBLE_IFACE, 'Parent') == ('', '/org/a11y/atspi/null') + +def test_empty_registry_has_zero_children(registry, session_manager): + assert get_property(registry, ACCESSIBLE_IFACE, 'ChildCount') == 0 diff --git a/xml/Socket.xml b/xml/Socket.xml index ab51850f..a1d19754 100644 --- a/xml/Socket.xml +++ b/xml/Socket.xml @@ -1,7 +1,30 @@ <?xml version="1.0" encoding="UTF-8"?> -<node> +<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> + <!-- + org.a11y.atspi.Socket: + @short_description: Interface to register an application on the registry. + --> <interface name="org.a11y.atspi.Socket"> + <!-- + Embed: + @plug: a string for the unique bus name of the application, and an object path + for the application's' root object. + + This is the entry point for an application that wants to register itself against + the accessibility registry. The application's root object, which it passes in + @plug, must support the org.a11y.atspi.Application interface. + + When an application calls this method on the registry, the following handshake happens: + + * Application calls this method on the registry to identify itself. + + * The registry sets the "Id" property on the org.a11y.atspi.Application interface on the @plug object. + + * The Embed method returns with the bus name and object path for the registry's root object. + + Returns: the bus name and object path of the registry's root object. + --> <method name="Embed"> <arg direction="in" name="plug" type="(so)"/> <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/> @@ -9,11 +32,27 @@ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QSpiObjectReference"/> </method> + <!-- + Unembed: + @plug: a string for the unique bus name of the application, and an object path + for the application's' root object. + + Unregisters an application from the accesibility registry. It is not necessary to + call this method; the accessibility registry detects when an application + disconnects from the bus. + --> <method name="Unembed"> <arg direction="in" name="plug" type="(so)"/> <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/> </method> + <!-- + Available: + @socket: application and object path for the registry's root object. + + The accessibility registry emits this signal early during startup, when it has + registered with the DBus daemon and is available for calls from applications. + --> <signal name="Available"> <arg name="socket" type="(so)"/> <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/> |