From e6c9015e998bbee49260c6bfe228e82d1f39a999 Mon Sep 17 00:00:00 2001 From: Bartlomiej Grzelewski Date: Tue, 20 Oct 2020 15:28:42 +0200 Subject: [PATCH 01/16] Fix invalid memory access Change-Id: I36ca4b0ac8772ba9b7e34d60449971e0b681ceda --- atspi/atspi-accessible.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index 394913c..2cc4cb4 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -2410,12 +2410,41 @@ atspi_accessible_get_accessible_id (AtspiAccessible *obj, GError **error) gboolean atspi_accessible_is_equal (AtspiAccessible *obj, AtspiAccessible *other) { + static const char prefix[] = "/org/a11y/atspi/accessible/"; + static const size_t prefix_len = sizeof(prefix)/sizeof(char); + if (obj == other) return TRUE; if (!obj || !other) return FALSE; - return !g_strcmp0(obj->parent.app->bus_name, other->parent.app->bus_name) && - !g_strcmp0(obj->parent.path, other->parent.path); + + /* + * Is it possible to have 2 different objects representing + * the same application? If not we should compare only pointers + * (obj->parent.app and other->parent.app) + */ + + /* One of them is null */ + if ((obj->parent.app != other->parent.app) && (!obj->parent.app || !other->parent.app)) + return FALSE; + + /* Both are not null */ + if ((obj->parent.app != other->parent.app) && g_strcmp0(obj->parent.app->bus_name, other->parent.app->bus_name)) + return FALSE; + + const AtspiObject *o1 = ATSPI_OBJECT (obj); + const AtspiObject *o2 = ATSPI_OBJECT (other); + + const char *path1 = o1 ? o1->path : ""; + const char *path2 = o2 ? o2->path : ""; + + if (!strncmp(path1, prefix, prefix_len)) + path1 += prefix_len; + + if (!strncmp(path2, prefix, prefix_len)) + path2 += prefix_len; + + return !g_strcmp0(path1, path2); } void -- 2.7.4 From 6df6f666f6a0a33182ea69b27715e12e3e5a5ae1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Grzelewski Date: Thu, 5 Nov 2020 10:39:36 +0100 Subject: [PATCH 02/16] Prevent passing null to g_hash_table_unref This commit removes annoying message from glib2: "GLib-CRITICAL g_hash_table_unref: assertion 'hash_table != NULL' failed" Change-Id: Idf9eaaebc03f0b0fe8c6275c625d902e3361343a --- atspi/atspi-accessible.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index 2cc4cb4..c743d1e 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -1227,7 +1227,9 @@ atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error) { message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, ""); - g_hash_table_unref(obj->attributes); + if (obj->attributes) + g_hash_table_unref(obj->attributes); + obj->attributes = _atspi_dbus_return_hash_from_message (message); _atspi_accessible_add_cache (obj, ATSPI_CACHE_ATTRIBUTES); } -- 2.7.4 From 0ed32e954e09abf691bafdb01048bb06658ed161 Mon Sep 17 00:00:00 2001 From: Bartlomiej Grzelewski Date: Thu, 4 Mar 2021 10:43:37 +0100 Subject: [PATCH 03/16] 2.39.90.1 Change-Id: I3d30aea2ebdc1e9ff5d24b564c2977d798f285d6 --- NEWS | 76 ++++ atspi/atspi-accessible.c | 50 ++- atspi/atspi-accessible.h | 1 + atspi/atspi-constants.h | 20 +- atspi/atspi-device-legacy.c | 316 +++++++++++++++++ atspi/atspi-device-legacy.h | 59 ++++ atspi/atspi-device-listener.c | 13 +- atspi/atspi-device-x11.c | 712 ++++++++++++++++++++++++++++++++++++++ atspi/atspi-device-x11.h | 59 ++++ atspi/atspi-device.c | 399 +++++++++++++++++++++ atspi/atspi-device.h | 103 ++++++ atspi/atspi-enum-types.c.template | 2 +- atspi/atspi-event-listener.c | 87 ++--- atspi/atspi-misc-private.h | 2 + atspi/atspi-misc.c | 87 ++++- atspi/atspi-registry.c | 3 +- atspi/atspi-types.h | 9 +- atspi/atspimarshal.list | 1 + atspi/meson.build | 14 +- bus/accessibility.conf.in | 2 +- bus/at-spi-bus-launcher.c | 96 +++-- bus/at-spi-dbus-bus.desktop.in | 2 +- bus/meson.build | 15 +- dbind/dbtest.c | 18 +- meson.build | 6 +- po/gl.po | 89 +---- po/pt.po | 51 +-- po/uk.po | 165 ++++----- registryd/meson.build | 1 - registryd/ucs2keysym.c | 285 ++++++++------- registryd/ucs2keysym.sh | 38 ++ test/memory.c | 8 +- test/meson.build | 17 +- test/test-application.c | 105 ++++++ xml/Accessible.xml | 18 +- xml/Action.xml | 2 +- xml/Application.xml | 2 +- xml/Cache.xml | 12 +- xml/Collection.xml | 18 +- xml/Component.xml | 4 +- xml/DeviceEventController.xml | 24 +- xml/DeviceEventListener.xml | 2 +- xml/Document.xml | 2 +- xml/Event.xml | 112 +++--- xml/Hyperlink.xml | 2 +- xml/Hypertext.xml | 2 +- xml/Image.xml | 2 +- xml/Registry.xml | 4 +- xml/Selection.xml | 2 +- xml/Socket.xml | 22 +- xml/Table.xml | 14 +- xml/TableCell.xml | 8 +- xml/Text.xml | 9 +- 53 files changed, 2573 insertions(+), 599 deletions(-) create mode 100644 atspi/atspi-device-legacy.c create mode 100644 atspi/atspi-device-legacy.h create mode 100644 atspi/atspi-device-x11.c create mode 100644 atspi/atspi-device-x11.h create mode 100644 atspi/atspi-device.c create mode 100644 atspi/atspi-device.h create mode 100755 registryd/ucs2keysym.sh create mode 100644 test/test-application.c diff --git a/NEWS b/NEWS index f18af9a..d964ce2 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,79 @@ +What's new in at-spi2-core 2.39.90.1: + +* Fix a crash introduced in 2.39.90, along with a few warnings (#30). + +What's new in at-spi2-core 2.39.90: + +* Fix build with X11 disabled. + +* Various fixes for the new device API used for key monitoring and grabbing. + +* Fixed several memory leaks. + +What's new in at-spi2-core 2.39.1: + +* Don't use gdbus-broker if not running under systemd (#25). + +* Unref bus at the end of cleanup. + +* Fix XML interfaces (#26). + +* Use unix sockets instead of abstract sockets (#28). + +* Added a device API to replace the old API for capturing key + grabs. This is needed for toolkits that do not report keystrokes + to atk, such as gtk 4. + +What's new in at-spi2-core 2.37.92: + +* Fix a possible memory leak if an event name cannot be parsed. + +* _atspi_dbus_set_interfaces: fix memory leak when called with an invalid + DBus signature. + +* Fix a crash if an event listener is removed during an event callback. + + +What's new in at-spi2-core 2.37.90: + +* Add a mode-changed signal to allow a screen reader to indicate + that its mode has changed. + +* Fix use after free when a device listener is destroyed (#22). + +* Meson: de-duplicate deps of 'Requires' in pkgconfig file (!28). + +* Fix use after free when an event listener is destroyed. + +* Make at-spi-dbus-bus.desktop validate (!30). + +* atspi_accessible_set_cache_mask: relax assert that was generating a + warning and causing the function to fail in some cases. + +* Fixes for synthesizing keys. + +* Fix Qt annotations in DBus xml files. + +* Memory test: replace gedit with a light-weight test application. + +* dbtest: print to stdout instead of stderr. + +* Tests: make test a bit verbose. + +* Constants: fix typos in two _COUNT constants. + +What's new in at-spi2-core 2.35.92: + +* bus-launcher: make session management more robust. + +What's new in at-spi2-core 2.35.1: + +* Fix source reproducibility (!25). + +* Avoid depending on Meson 0.50 (#20). + +* Add ATSPI_ROLE_MARK and ATSPI_ROLE_SUGGESTION (!27). + What's new in at-spi2-core 2.34.0: * Fix a use after free when freeing an event. diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index fd6737d..b078688 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -28,6 +28,7 @@ enum { REGION_CHANGED, + MODE_CHANGED, LAST_SIGNAL }; @@ -48,21 +49,28 @@ screen_reader_signal_watcher (GSignalInvocationHint *signal_hint, const char *name; DBusMessage *signal; DBusMessageIter iter, iter_struct, iter_variant, iter_array; - dbus_int32_t detail1, detail2; + dbus_int32_t detail1 = 0, detail2 = 0; const char *detail = ""; + gchar *dbus_name; object = g_value_get_object (param_values + 0); g_return_val_if_fail (ATSPI_IS_ACCESSIBLE(object), FALSE); g_signal_query (signal_hint->signal_id, &signal_query); name = signal_query.signal_name; - detail1 = g_value_get_int (param_values + 1); - detail2 = g_value_get_int (param_values + 2); + if (signal_hint->detail) + detail = g_quark_to_string (signal_hint->detail); + if (n_param_values > 1) + detail1 = g_value_get_int (param_values + 1); + if (n_param_values > 2 && G_VALUE_HOLDS_INT (param_values + 2)) + detail2 = g_value_get_int (param_values + 2); accessible = ATSPI_ACCESSIBLE (object); + dbus_name = _atspi_strdup_and_adjust_for_dbus (name); signal = dbus_message_new_signal (ATSPI_DBUS_PATH_SCREEN_READER, ATSPI_DBUS_INTERFACE_EVENT_SCREEN_READER, - "RegionChanged"); + dbus_name); + g_free (dbus_name); dbus_message_iter_init_append (signal, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &detail); dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &detail1); @@ -180,7 +188,7 @@ atspi_accessible_init (AtspiAccessible *accessible) accessible->priv = atspi_accessible_get_instance_private (accessible); - accessible->children = g_ptr_array_new_with_free_func (atspi_accessible_unref); + accessible->children = g_ptr_array_new_with_free_func ((GDestroyNotify) atspi_accessible_unref); } static void @@ -287,9 +295,36 @@ atspi_accessible_class_init (AtspiAccessibleClass *klass) G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + /** + * AtspiAccessible::mode-changed: + * @atspiaccessible: the object which received the signal + * @arg1: a boolean specifying whether the mode is being toggled on or off. + * @why: an optional string explaining why the mode changed. + * + * The signal "mode-changed" is emitted by a screen reader to indicate + * that its mode has changed. This signal supports the following details: + * focus-tracking + * flat-review + * mouse-review + * say-all + * caret-tracking + */ + atspi_accessible_signals[MODE_CHANGED] = + g_signal_new ("mode_changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + G_STRUCT_OFFSET (AtspiAccessibleClass, mode_changed), + NULL, NULL, + atspi_marshal_VOID__INT_STRING, + G_TYPE_NONE, + 2, G_TYPE_INT, G_TYPE_STRING); + g_signal_add_emission_hook (atspi_accessible_signals[REGION_CHANGED], 0, screen_reader_signal_watcher, NULL, (GDestroyNotify) NULL); + g_signal_add_emission_hook (atspi_accessible_signals[MODE_CHANGED], 0, + screen_reader_signal_watcher, NULL, + (GDestroyNotify) NULL); } /** @@ -383,6 +418,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); dbus_message_unref (reply); _atspi_accessible_add_cache (obj, ATSPI_CACHE_PARENT); @@ -707,6 +743,8 @@ atspi_accessible_get_attributes (AtspiAccessible *obj, GError **error) { message = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetAttributes", error, ""); + g_clear_pointer (&(obj->attributes), g_hash_table_unref); + obj->attributes = _atspi_dbus_return_hash_from_message (message); _atspi_accessible_add_cache (obj, ATSPI_CACHE_ATTRIBUTES); } @@ -1706,7 +1744,7 @@ atspi_accessible_set_cache_mask (AtspiAccessible *accessible, AtspiCache mask) { g_return_if_fail (accessible != NULL); g_return_if_fail (accessible->parent.app != NULL); - g_return_if_fail (accessible == accessible->parent.app->root); + g_return_if_fail (accessible == accessible->parent.app->root || accessible->role == ATSPI_ROLE_APPLICATION); accessible->parent.app->cache = mask; enable_caching = TRUE; } diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index 13e4962..35c0d5b 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -66,6 +66,7 @@ struct _AtspiAccessibleClass AtspiObjectClass parent_class; void (*region_changed) (AtspiAccessible *accessible, gint current_offset, gint last_offset); + void (*mode_changed) (AtspiAccessible *accessible, gboolean enabled); }; GType atspi_accessible_get_type (void); diff --git a/atspi/atspi-constants.h b/atspi/atspi-constants.h index 8657ead..3a8da00 100644 --- a/atspi/atspi-constants.h +++ b/atspi/atspi-constants.h @@ -121,7 +121,7 @@ typedef enum { * * One higher than the highest valid value of #AtspiLocaleType. **/ -#define ATSPI_LOCALE_TYPE _COUNT(5+1) +#define ATSPI_LOCALE_TYPE_COUNT (5+1) /** * AtspiCoordType: @@ -241,7 +241,7 @@ typedef enum { * One higher than the highest valid value of * #AtspiCollection_TreeTraversalType. */ -#define ATSPI_TREETRAVERSALTYPE _COUNT(3+1) +#define ATSPI_TREETRAVERSALTYPE_COUNT (3+1) /** * AtspiComponentLayer: @@ -1240,6 +1240,18 @@ typedef enum { * @ATSPI_ROLE_CONTENT_INSERTION: Content previously inserted or proposed to be * inserted, e.g. in revision history or a content view providing suggestions * from reviewers. @Since: 2.34. + * @ATSPI_ROLE_MARK: A run of content that is marked or highlighted, such as for + * reference purposes, or to call it out as having a special purpose. If the + * marked content has an associated section in the document elaborating on the + * reason for the mark, then %ATSPI_RELATION_DETAILS should be used on the mark + * to point to that associated section. In addition, the reciprocal relation + * %ATSPI_RELATION_DETAILS_FOR should be used on the associated content section + * to point back to the mark. @Since: 2.36. + * @ATSPI_ROLE_SUGGESTION: A container for content that is called out as a proposed + * change from the current version of the document, such as by a reviewer of the + * content. This role should include either %ATSPI_ROLE_CONTENT_DELETION and/or + * %ATSPI_ROLE_CONTENT_INSERTION children, in any order, to indicate what the + * actual change is. @Since: 2.36 * @ATSPI_ROLE_LAST_DEFINED: Not a valid role, used for finding end of * enumeration. * @@ -1375,6 +1387,8 @@ typedef enum { ATSPI_ROLE_FOOTNOTE, ATSPI_ROLE_CONTENT_DELETION, ATSPI_ROLE_CONTENT_INSERTION, + ATSPI_ROLE_MARK, + ATSPI_ROLE_SUGGESTION, ATSPI_ROLE_LAST_DEFINED, } AtspiRole; @@ -1383,7 +1397,7 @@ typedef enum { * * One higher than the highest valid value of #AtspiRole. */ -#define ATSPI_ROLE_COUNT (127+1) +#define ATSPI_ROLE_COUNT (129+1) typedef enum { diff --git a/atspi/atspi-device-legacy.c b/atspi/atspi-device-legacy.c new file mode 100644 index 0000000..6950bc3 --- /dev/null +++ b/atspi/atspi-device-legacy.c @@ -0,0 +1,316 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2020 SUSE LLC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "atspi-private.h" +#include "atspi-device-legacy.h" + +#ifdef HAVE_X11 +#include +#include +#include +#include +#endif + +typedef struct +{ + guint keycode; + guint modifier; +} AtspiLegacyKeyModifier; + +typedef struct _AtspiDeviceLegacyPrivate AtspiDeviceLegacyPrivate; +struct _AtspiDeviceLegacyPrivate +{ + AtspiDeviceListener *listener; +#ifdef HAVE_X11 + Display *display; + Window window; +#endif + GSList *modifiers; + guint virtual_mods_enabled; + gboolean keyboard_grabbed; +}; + +GObjectClass *device_legacy_parent_class; + +G_DEFINE_TYPE_WITH_CODE (AtspiDeviceLegacy, atspi_device_legacy, + ATSPI_TYPE_DEVICE, + G_ADD_PRIVATE (AtspiDeviceLegacy)) + + +static guint +find_virtual_mapping (AtspiDeviceLegacy *legacy_device, gint keycode) +{ + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiLegacyKeyModifier *entry = l->data; + if (entry->keycode == keycode) + return entry->modifier; + } + + return 0; +} + +static void +set_virtual_modifier (AtspiDeviceLegacy *legacy_device, gint keycode, gboolean enabled) +{ + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + guint modifier = find_virtual_mapping (legacy_device, keycode); + + if (enabled) + priv->virtual_mods_enabled |= modifier; + else + priv->virtual_mods_enabled &= ~modifier; +} + + +gboolean +key_cb (const AtspiDeviceEvent *event, void *user_data) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (user_data); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + gboolean ret = priv->keyboard_grabbed; + + set_virtual_modifier (legacy_device, event->hw_code, + event->type == (AtspiEventType)ATSPI_KEY_PRESS); + ret |= atspi_device_notify_key (ATSPI_DEVICE (legacy_device), + event->type == (AtspiEventType)ATSPI_KEY_PRESS, + event->hw_code, event->id, + event->modifiers | priv->virtual_mods_enabled, + event->event_string); + + return ret; +} + +static guint +atspi_device_legacy_get_locked_modifiers (AtspiDevice *device) +{ +#ifdef HAVE_X11 + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + XkbStateRec state_rec; + + memset (&state_rec, 0, sizeof (state_rec)); + XkbGetState (priv->display, XkbUseCoreKbd, &state_rec); + return state_rec.locked_mods; +#else + return 0; +#endif +} + +static gboolean +check_virtual_modifier (AtspiDeviceLegacy *legacy_device, guint modifier) +{ + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiLegacyKeyModifier *entry = l->data; + if (entry->modifier == modifier) + return TRUE; + } + + return FALSE; +} + +static guint +get_unused_virtual_modifier (AtspiDeviceLegacy *legacy_device) +{ + guint ret = 0x1000; + + while (ret < 0x10000) + { + if (!check_virtual_modifier (legacy_device, ret)) + return ret; + ret <<= 1; + } + + return 0; +} + +static guint +atspi_device_legacy_map_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + guint ret; + AtspiLegacyKeyModifier *entry; +#ifdef HAVE_X11 + XkbDescPtr desc; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + + if (keycode < desc->min_key_code || keycode >= desc->max_key_code) + { + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + g_warning ("Passed invalid keycode %d", keycode); + return 0; + } + + ret = desc->map->modmap[keycode]; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + if (ret & (ShiftMask | ControlMask)) + return ret; +#endif + + ret = find_virtual_mapping (legacy_device, keycode); + if (ret) + return ret; + + ret = get_unused_virtual_modifier (legacy_device); + + entry = g_new (AtspiLegacyKeyModifier, 1); + entry->keycode = keycode; + entry->modifier = ret; + priv->modifiers = g_slist_append (priv->modifiers, entry); + + return ret; +} + +static void +atspi_device_legacy_unmap_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiLegacyKeyModifier *entry = l->data; + if (entry->keycode == keycode) + { + g_free (entry); + priv->modifiers = g_slist_remove (priv->modifiers, entry); + return; + } + } +} + +static guint +atspi_device_legacy_get_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); +#ifdef HAVE_X11 + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + XkbDescPtr desc; + guint ret; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + + if (keycode < desc->min_key_code || keycode >= desc->max_key_code) + { + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + g_warning ("Passed invalid keycode %d", keycode); + return 0; + } + + ret = desc->map->modmap[keycode]; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + if (ret) + return ret; +#endif + + return find_virtual_mapping (legacy_device, keycode); +} + +static gboolean +atspi_device_legacy_grab_keyboard (AtspiDevice *device) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + + priv->keyboard_grabbed = TRUE; + return TRUE; +} + +static void +atspi_device_legacy_ungrab_keyboard (AtspiDevice *device) +{ + AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (device); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); + + priv->keyboard_grabbed = FALSE; +} + +static void +atspi_device_legacy_init (AtspiDeviceLegacy *device) +{ + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (device); + gint i; + + priv->listener = atspi_device_listener_new (key_cb, device, NULL); + for (i = 0; i < 256; i++) + atspi_register_keystroke_listener (priv->listener, NULL, i, 3, ATSPI_KEYLISTENER_SYNCHRONOUS | ATSPI_KEYLISTENER_CANCONSUME, NULL); + +#ifdef HAVE_X11 + priv->display=XOpenDisplay(""); + if (priv->display) + priv->window = DefaultRootWindow(priv->display); +#endif + +} + +static void +atspi_device_legacy_finalize (GObject *object) +{ + AtspiDeviceLegacy *device = ATSPI_DEVICE_LEGACY (object); + AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (device); + + g_clear_object (&priv->listener); + device_legacy_parent_class->finalize (object); +} + + +static void +atspi_device_legacy_class_init (AtspiDeviceLegacyClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass); + + device_legacy_parent_class = g_type_class_peek_parent (klass); + object_class->finalize = atspi_device_legacy_finalize; + device_class->map_modifier = atspi_device_legacy_map_modifier; + device_class->unmap_modifier = atspi_device_legacy_unmap_modifier; + device_class->get_modifier = atspi_device_legacy_get_modifier; + device_class->get_locked_modifiers = atspi_device_legacy_get_locked_modifiers; + device_class->grab_keyboard = atspi_device_legacy_grab_keyboard; + device_class->ungrab_keyboard = atspi_device_legacy_ungrab_keyboard; +} + +/** + * atspi_device_legacy_new: + * + * Creates a new #AtspiDeviceLegacy. + * + * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceLegacy. + * + **/ +AtspiDeviceLegacy * +atspi_device_legacy_new () +{ + AtspiDeviceLegacy *device = g_object_new (atspi_device_legacy_get_type (), NULL); + + return device; +} diff --git a/atspi/atspi-device-legacy.h b/atspi/atspi-device-legacy.h new file mode 100644 index 0000000..50f777e --- /dev/null +++ b/atspi/atspi-device-legacy.h @@ -0,0 +1,59 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2020 SUSE LLC. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _ATSPI_DEVICE_LEGACY_H_ +#define _ATSPI_DEVICE_LEGACY_H_ + +#include "glib-object.h" + +#include "atspi-types.h" +#include "atspi-device.h" + +G_BEGIN_DECLS + +#define ATSPI_TYPE_DEVICE_LEGACY (atspi_device_legacy_get_type ()) +#define ATSPI_DEVICE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ATSPI_TYPE_DEVICE_LEGACY, AtspiDeviceLegacy)) +#define ATSPI_DEVICE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ATSPI_TYPE_DEVICE_LEGACY, AtspiDeviceLegacyClass)) +#define ATSPI_IS_DEVICE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ATSPI_TYPE_DEVICE_LEGACY)) +#define ATSPI_IS_DEVICE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ATSPI_TYPE_DEVICE_LEGACY)) +#define ATSPI_DEVICE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ATSPI_TYPE_DEVICE_LEGACY, AtspiDeviceLegacyClass)) + +typedef struct _AtspiDeviceLegacy AtspiDeviceLegacy; +struct _AtspiDeviceLegacy +{ + AtspiDevice parent; +}; + +typedef struct _AtspiDeviceLegacyClass AtspiDeviceLegacyClass; +struct _AtspiDeviceLegacyClass +{ + AtspiDeviceClass parent_class; +}; + +GType atspi_device_legacy_get_type (void); + +AtspiDeviceLegacy *atspi_device_legacy_new (); + +G_END_DECLS + +#endif /* _ATSPI_DEVICE_LEGACY_H_ */ diff --git a/atspi/atspi-device-listener.c b/atspi/atspi-device-listener.c index 8e04c41..69f77d1 100644 --- a/atspi/atspi-device-listener.c +++ b/atspi/atspi-device-listener.c @@ -32,7 +32,7 @@ typedef struct GDestroyNotify callback_destroyed; } DeviceEventHandler; -GObjectClass *device_parent_class; +GObjectClass *device_listener_parent_class; /* * Misc. helpers. @@ -177,7 +177,9 @@ atspi_device_listener_finalize (GObject *object) { AtspiDeviceListener *listener = (AtspiDeviceListener *) object; GList *l; - + + device_listeners = g_list_remove (device_listeners, listener); + for (l = listener->callbacks; l; l = l->next) { device_event_handler_free (l->data); @@ -185,7 +187,7 @@ atspi_device_listener_finalize (GObject *object) g_list_free (listener->callbacks); - device_parent_class->finalize (object); + device_listener_parent_class->finalize (object); } static void @@ -193,7 +195,7 @@ atspi_device_listener_class_init (AtspiDeviceListenerClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; - device_parent_class = g_type_class_peek_parent (klass); + device_listener_parent_class = g_type_class_peek_parent (klass); object_class->finalize = atspi_device_listener_finalize; klass->device_event = atspi_device_event_dispatch; @@ -396,7 +398,8 @@ done: gchar * _atspi_device_listener_get_path (AtspiDeviceListener *listener) -{ return g_strdup_printf ("/org/a11y/atspi/listeners/%d", listener->id); +{ + return g_strdup_printf ("/org/a11y/atspi/listeners/%d", listener->id); } G_DEFINE_BOXED_TYPE (AtspiDeviceEvent, diff --git a/atspi/atspi-device-x11.c b/atspi/atspi-device-x11.c new file mode 100644 index 0000000..e8f2199 --- /dev/null +++ b/atspi/atspi-device-x11.c @@ -0,0 +1,712 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2020 SUSE LLC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "atspi-private.h" +#include "atspi-device-x11.h" + +#include +#include +#include +#include + + +#define ATSPI_VIRTUAL_MODIFIER_MASK 0x0000f000 + +typedef struct _AtspiDeviceX11Private AtspiDeviceX11Private; +struct _AtspiDeviceX11Private +{ + Display *display; + Window window; + GSource *source; + int xi_opcode; + int device_id; + int device_id_alt; + GSList *modifiers; + GSList *key_grabs; + guint virtual_mods_enabled; + gboolean keyboard_grabbed; +}; + +GObjectClass *device_x11_parent_class; + +typedef struct _DisplaySource +{ + GSource source; + + Display *display; + GPollFD event_poll_fd; +} DisplaySource; + +typedef struct +{ + guint keycode; + guint modifier; +} AtspiX11KeyModifier; + +typedef struct +{ + AtspiKeyDefinition *kd; + gboolean enabled; +} AtspiX11KeyGrab; + +static gboolean +event_prepare (GSource *source, gint *timeout) +{ + Display *display = ((DisplaySource *)source)->display; + gboolean retval; + + *timeout = -1; + retval = XPending (display); + + return retval; +} + +static gboolean +event_check (GSource *source) +{ + DisplaySource *display_source = (DisplaySource*)source; + gboolean retval; + + if (display_source->event_poll_fd.revents & G_IO_IN) + retval = XPending (display_source->display); + else + retval = FALSE; + + return retval; +} + +static void +xi2keyevent (XIDeviceEvent *xievent, XEvent *xkeyevent) +{ + memset (xkeyevent, 0, sizeof (*xkeyevent)); + + switch (xievent->evtype) + { + case XI_KeyPress: + xkeyevent->type = KeyPress; + break; + case XI_KeyRelease: + xkeyevent->type = KeyRelease; + break; + default: + break; + } + xkeyevent->xkey.serial = xievent->serial; + xkeyevent->xkey.send_event = xievent->send_event; + xkeyevent->xkey.display = xievent->display; + xkeyevent->xkey.window = xievent->event; + xkeyevent->xkey.root = xievent->root; + xkeyevent->xkey.subwindow = xievent->child; + xkeyevent->xkey.time = xievent->time; + xkeyevent->xkey.x = xievent->event_x; + xkeyevent->xkey.y = xievent->event_y; + xkeyevent->xkey.x_root = xievent->root_x; + xkeyevent->xkey.y_root = xievent->root_y; + xkeyevent->xkey.state = xievent->mods.effective; + xkeyevent->xkey.keycode = xievent->detail; + xkeyevent->xkey.same_screen = 1; +} + +G_DEFINE_TYPE_WITH_CODE (AtspiDeviceX11, atspi_device_x11, + ATSPI_TYPE_DEVICE, + G_ADD_PRIVATE (AtspiDeviceX11)) + + +static guint +find_virtual_mapping (AtspiDeviceX11 *x11_device, gint keycode) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiX11KeyModifier *entry = l->data; + if (entry->keycode == keycode) + return entry->modifier; + } + + return 0; +} + +static gboolean +grab_should_be_enabled (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + + /* If the whole keyboard is grabbed, then all keys are grabbed elsewhere */ + if (priv->keyboard_grabbed) + return FALSE; + + guint virtual_mods_used = grab->kd->modifiers & ATSPI_VIRTUAL_MODIFIER_MASK; + return ((priv->virtual_mods_enabled & virtual_mods_used) == virtual_mods_used); +} + +static gboolean +grab_has_active_duplicate (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + GSList *l; + + for (l = priv->key_grabs; l; l = l->next) + { + AtspiX11KeyGrab *other = l->data; + if (other != grab && other->enabled && other->kd->keycode == grab->kd->keycode && (other->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK) == (grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK)) + return TRUE; + } + return FALSE; +} + +static void +grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + XIGrabModifiers xi_modifiers; + XIEventMask eventmask; + unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 }; + + xi_modifiers.modifiers = modmask; + xi_modifiers.status = 0; + + eventmask.deviceid = XIAllDevices; + eventmask.mask_len = sizeof(mask); + eventmask.mask = mask; + + XISetMask (mask, XI_KeyPress); + XISetMask (mask, XI_KeyRelease); + + XIGrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers); +} + +static void +enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + + g_return_if_fail (priv->display != NULL); + + if (!grab_has_active_duplicate (x11_device, grab)) + grab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); + grab->enabled = TRUE; +} + +static void +ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + XIGrabModifiers xi_modifiers; + + xi_modifiers.modifiers = modmask; + xi_modifiers.status = 0; + + XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, sizeof(xi_modifiers), &xi_modifiers); +} + +static void +disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + + g_return_if_fail (priv->display != NULL); + + if (!grab->enabled) + return; + + grab->enabled = FALSE; + + if (grab_has_active_duplicate (x11_device, grab)) + return; + + ungrab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); +} + +static void +refresh_key_grabs (AtspiDeviceX11 *x11_device) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + GSList *l; + + for (l = priv->key_grabs; l; l = l->next) + { + AtspiX11KeyGrab *grab = l->data; + gboolean new_enabled = grab_should_be_enabled (x11_device, grab); + if (new_enabled && !grab->enabled) + enable_key_grab (x11_device, grab); + else if (grab->enabled && !new_enabled) + disable_key_grab (x11_device, grab); + } +} + +static void +set_virtual_modifier (AtspiDeviceX11 *x11_device, gint keycode, gboolean enabled) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + guint modifier = find_virtual_mapping (x11_device, keycode); + + if (!modifier) + return; + + if (enabled) + { + if (priv->virtual_mods_enabled & modifier) + return; + priv->virtual_mods_enabled |= modifier; + } + else + { + if (!(priv->virtual_mods_enabled & modifier)) + return; + priv->virtual_mods_enabled &= ~modifier; + } + + refresh_key_grabs (x11_device); +} + +static gboolean +do_event_dispatch (gpointer user_data) +{ + AtspiDeviceX11 *device = user_data; + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device); + Display *display = priv->display; + XEvent xevent; + char text[10]; + KeySym keysym; + XComposeStatus status; + + while (XPending (display)) + { + XNextEvent (display, &xevent); + XEvent keyevent; + + switch (xevent.type) + { + case KeyPress: + case KeyRelease: + XLookupString(&xevent.xkey, text, sizeof (text), &keysym, &status); + atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, xevent.xkey.state | priv->virtual_mods_enabled, text); + break; + case GenericEvent: + if (xevent.xcookie.extension == priv->xi_opcode) + { + XGetEventData(priv->display, &xevent.xcookie); + XIRawEvent *xiRawEv = (XIRawEvent *) xevent.xcookie.data; + XIDeviceEvent *xiDevEv = (XIDeviceEvent *) xevent.xcookie.data; + switch (xevent.xcookie.evtype) + { + case XI_KeyPress: + case XI_KeyRelease: + xi2keyevent (xiDevEv, &keyevent); + XLookupString((XKeyEvent *)&keyevent, text, sizeof (text), &keysym, &status); + if (text[0] < ' ') + text[0] = '\0'; + /* The deviceid can change. Would be nice to find a better way of + handling this */ + if (priv->device_id && priv->device_id_alt && xiDevEv->deviceid != priv->device_id && xiDevEv->deviceid != priv->device_id_alt) + priv->device_id = priv->device_id_alt = 0; + else if (priv->device_id && !priv->device_id_alt && xiDevEv->deviceid != priv->device_id) + priv->device_id_alt = xiDevEv->deviceid; + if (!priv->device_id) + priv->device_id = xiDevEv->deviceid; + set_virtual_modifier (device, xiRawEv->detail, xevent.xcookie.evtype == XI_KeyPress); + if (xiDevEv->deviceid == priv->device_id) + atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.xcookie.evtype == XI_KeyPress), xiRawEv->detail, keysym, keyevent.xkey.state, text); + /* otherwise it's probably a duplicate event from a key grab */ + XFreeEventData (priv->display, &xevent.xcookie); + break; + } + } + default: + if (XFilterEvent (&xevent, None)) + continue; + } + } + return TRUE; +} + +static gboolean +event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) +{ + if (callback) + callback (user_data); + return G_SOURCE_CONTINUE; +} + +static GSourceFuncs event_funcs = { + event_prepare, + event_check, + event_dispatch, + NULL +}; + +static GSource * +display_source_new (Display *display) +{ + GSource *source = g_source_new (&event_funcs, sizeof (DisplaySource)); + DisplaySource *display_source = (DisplaySource *) source; + g_source_set_name (source, "[at-spi2-core] display_source_funcs"); + + display_source->display = display; + + return source; +} + +static void +create_event_source (AtspiDeviceX11 *device) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device); + DisplaySource *display_source; + + int connection_number = ConnectionNumber (priv->display); + + priv->source = display_source_new (priv->display); + display_source = (DisplaySource *)priv->source; + + g_source_set_priority (priv->source, G_PRIORITY_DEFAULT); + + display_source->event_poll_fd.fd = connection_number; + display_source->event_poll_fd.events = G_IO_IN; + + g_source_add_poll (priv->source, &display_source->event_poll_fd); + g_source_set_can_recurse (priv->source, TRUE); + g_source_set_callback (priv->source, do_event_dispatch, device, NULL); + g_source_attach (priv->source, NULL); +} + +static gboolean +check_virtual_modifier (AtspiDeviceX11 *x11_device, guint modifier) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiX11KeyModifier *entry = l->data; + if (entry->modifier == modifier) + return TRUE; + } + + return FALSE; +} + +static guint +get_unused_virtual_modifier (AtspiDeviceX11 *x11_device) +{ + guint ret = 0x1000; + + while (ret < 0x10000) + { + if (!check_virtual_modifier (x11_device, ret)) + return ret; + ret <<= 1; + } + + return 0; +} + +static guint +atspi_device_x11_map_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + XkbDescPtr desc; + guint ret; + AtspiX11KeyModifier *entry; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + + if (keycode < desc->min_key_code || keycode >= desc->max_key_code) + { + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + g_warning ("Passed invalid keycode %d", keycode); + return 0; + } + + ret = desc->map->modmap[keycode]; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + if (ret & (ShiftMask | ControlMask)) + return ret; + + ret = find_virtual_mapping (x11_device, keycode); + if (ret) + return ret; + + ret = get_unused_virtual_modifier (x11_device); + + entry = g_new (AtspiX11KeyModifier, 1); + entry->keycode = keycode; + entry->modifier = ret; + priv->modifiers = g_slist_append (priv->modifiers, entry); + + return ret; +} + +static void +atspi_device_x11_unmap_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + GSList *l; + + for (l = priv->modifiers; l; l = l->next) + { + AtspiX11KeyModifier *entry = l->data; + if (entry->keycode == keycode) + { + g_free (entry); + priv->modifiers = g_slist_remove (priv->modifiers, entry); + return; + } + } +} + +static guint +atspi_device_x11_get_modifier (AtspiDevice *device, gint keycode) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + XkbDescPtr desc; + guint ret; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + + if (keycode < desc->min_key_code || keycode >= desc->max_key_code) + { + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + g_warning ("Passed invalid keycode %d", keycode); + return 0; + } + + ret = desc->map->modmap[keycode]; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); + if (ret) + return ret; + + return find_virtual_mapping (x11_device, keycode); +} + +static void +atspi_device_x11_init (AtspiDeviceX11 *device) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device); + int first_event, first_error; + + priv->display=XOpenDisplay(""); + g_return_if_fail (priv->display != NULL); + priv->window = DefaultRootWindow(priv->display); + + if (XQueryExtension(priv->display, "XInputExtension", &priv->xi_opcode, &first_event, &first_error)) + { + int major = 2; + int minor = 1; + if (XIQueryVersion(priv->display, &major, &minor) != BadRequest) + { + XIEventMask eventmask; + unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 }; + + eventmask.deviceid = XIAllDevices; + eventmask.mask_len = sizeof(mask); + eventmask.mask = mask; + + XISetMask (mask, XI_KeyPress); + XISetMask (mask, XI_KeyRelease); + XISetMask (mask, XI_ButtonPress); + XISetMask (mask, XI_ButtonRelease); + XISetMask (mask, XI_Motion); + XISelectEvents (priv->display, priv->window, &eventmask, 1); + create_event_source (device); + } + } +} + +static void +atspi_device_x11_finalize (GObject *object) +{ + AtspiDeviceX11 *device = ATSPI_DEVICE_X11 (object); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device); + GSList *l; + + for (l = priv->key_grabs; l; l = l->next) + { + AtspiX11KeyGrab *grab = l->data; + disable_key_grab (device, grab); + g_boxed_free (ATSPI_TYPE_KEY_DEFINITION, grab->kd); + g_free (grab); + } + g_slist_free (priv->key_grabs); + priv->key_grabs = NULL; + + g_slist_free_full (priv->modifiers, g_free); + priv->modifiers = NULL; + + if (priv->source) + { + g_source_destroy ((GSource *) priv->source); + g_source_unref ((GSource *) priv->source); + priv->source = NULL; + } + + device_x11_parent_class->finalize (object); +} + + +static void +atspi_device_x11_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + AtspiX11KeyGrab *grab; + + grab = g_new (AtspiX11KeyGrab, 1); + grab->kd = g_boxed_copy (ATSPI_TYPE_KEY_DEFINITION, kd); + grab->enabled = FALSE; + priv->key_grabs = g_slist_append (priv->key_grabs, grab); + if (grab_should_be_enabled (x11_device, grab)) + enable_key_grab (x11_device, grab); +} + +static void +atspi_device_x11_remove_key_grab (AtspiDevice *device, guint id) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + AtspiKeyDefinition *kd; + GSList *l; + + kd = atspi_device_get_grab_by_id (device, id); + + for (l = priv->key_grabs; l; l = g_slist_next (l)) + { + AtspiX11KeyGrab *other = l->data; + if (other->kd->keycode == kd->keycode && other->kd->modifiers == kd->modifiers) + { + disable_key_grab (x11_device, other); + priv->key_grabs = g_slist_remove (priv->key_grabs, other); + return; + } + } +} + +static guint +atspi_device_x11_get_locked_modifiers (AtspiDevice *device) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + XkbStateRec state_rec; + + memset (&state_rec, 0, sizeof (state_rec)); + XkbGetState (priv->display, XkbUseCoreKbd, &state_rec); + return state_rec.locked_mods; +} + +static void +get_keycode_range (AtspiDeviceX11 *x11_device, int *min, int *max) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + XkbDescPtr desc; + + desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd); + *min = desc->min_key_code; + *max = desc->max_key_code; + XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE); +} + +static gboolean +atspi_device_x11_grab_keyboard (AtspiDevice *device) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + int min, max; + gint i; + + g_return_val_if_fail (priv->display != NULL, FALSE); +#if 0 + /* THis seems like the right thing to do, but it fails for me */ + return (XGrabKeyboard (priv->display, priv->window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0; +#else + if (priv->keyboard_grabbed) + return TRUE; + priv->keyboard_grabbed = TRUE; + refresh_key_grabs (x11_device); + + get_keycode_range (x11_device, &min, &max); + for (i = min; i < max; i++) + grab_key (x11_device, i, 0); + return TRUE; +#endif +} + +static void +atspi_device_x11_ungrab_keyboard (AtspiDevice *device) +{ + AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device); + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + int min, max; + gint i; + + g_return_if_fail (priv->display != NULL); +#if 0 + XUngrabKeyboard (priv->display, CurrentTime); +#else + if (!priv->keyboard_grabbed) + return; + priv->keyboard_grabbed = FALSE; + + get_keycode_range (x11_device, &min, &max); + for (i = min; i < max; i++) + ungrab_key (x11_device, i, 0); + + refresh_key_grabs (x11_device); +#endif +} + +static void +atspi_device_x11_class_init (AtspiDeviceX11Class *klass) +{ + AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass); + GObjectClass *object_class = (GObjectClass *) klass; + + device_x11_parent_class = g_type_class_peek_parent (klass); + device_class->add_key_grab = atspi_device_x11_add_key_grab; + device_class->map_modifier = atspi_device_x11_map_modifier; + device_class->unmap_modifier = atspi_device_x11_unmap_modifier; + device_class->get_modifier = atspi_device_x11_get_modifier; + device_class->remove_key_grab = atspi_device_x11_remove_key_grab; + device_class->get_locked_modifiers = atspi_device_x11_get_locked_modifiers; + device_class->grab_keyboard = atspi_device_x11_grab_keyboard; + device_class->ungrab_keyboard = atspi_device_x11_ungrab_keyboard; + object_class->finalize = atspi_device_x11_finalize; +} + +/** + * atspi_device_x11_new: + * + * Creates a new #AtspiDeviceX11. + * + * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceX11. + * + **/ +AtspiDeviceX11 * +atspi_device_x11_new () +{ + AtspiDeviceX11 *device = g_object_new (atspi_device_x11_get_type (), NULL); + + return device; +} diff --git a/atspi/atspi-device-x11.h b/atspi/atspi-device-x11.h new file mode 100644 index 0000000..3a91edc --- /dev/null +++ b/atspi/atspi-device-x11.h @@ -0,0 +1,59 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2020 SUSE LLC. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _ATSPI_DEVICE_X11_H_ +#define _ATSPI_DEVICE_X11_H_ + +#include "glib-object.h" + +#include "atspi-types.h" +#include "atspi-device.h" + +G_BEGIN_DECLS + +#define ATSPI_TYPE_DEVICE_X11 (atspi_device_x11_get_type ()) +#define ATSPI_DEVICE_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ATSPI_TYPE_DEVICE_X11, AtspiDeviceX11)) +#define ATSPI_DEVICE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ATSPI_TYPE_DEVICE_X11, AtspiDeviceX11Class)) +#define ATSPI_IS_DEVICE_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ATSPI_TYPE_DEVICE_X11)) +#define ATSPI_IS_DEVICE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ATSPI_TYPE_DEVICE_X11)) +#define ATSPI_DEVICE_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ATSPI_TYPE_DEVICE_X11, AtspiDeviceX11Class)) + +typedef struct _AtspiDeviceX11 AtspiDeviceX11; +struct _AtspiDeviceX11 +{ + AtspiDevice parent; +}; + +typedef struct _AtspiDeviceX11Class AtspiDeviceX11Class; +struct _AtspiDeviceX11Class +{ + AtspiDeviceClass parent_class; +}; + +GType atspi_device_x11_get_type (void); + +AtspiDeviceX11 *atspi_device_x11_new (); + +G_END_DECLS + +#endif /* _ATSPI_DEVICE_X11_H_ */ diff --git a/atspi/atspi-device.c b/atspi/atspi-device.c new file mode 100644 index 0000000..5f62dc3 --- /dev/null +++ b/atspi/atspi-device.c @@ -0,0 +1,399 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2020 SUSE LLC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "atspi-private.h" +#include "atspi-device.h" +#include "atspi-device-legacy.h" +#include "atspi-device-x11.h" + +typedef struct +{ + guint id; + guint keycode; + guint keysym; + guint modifiers; + AtspiKeyCallback callback; + void *callback_data; + GDestroyNotify callback_destroyed; +} AtspiKeyGrab; + +typedef struct _AtspiDevicePrivate AtspiDevicePrivate; +struct _AtspiDevicePrivate +{ + GSList *key_watchers; + GSList *keygrabs; + guint last_grab_id; +}; + +GObjectClass *device_parent_class; + +static void +atspi_device_init (AtspiDevice *device) +{ +} + +G_DEFINE_TYPE_WITH_CODE (AtspiDevice, atspi_device, + G_TYPE_OBJECT, + G_ADD_PRIVATE (AtspiDevice)) + +static void +atspi_device_finalize (GObject *object) +{ + AtspiDevice *device = (AtspiDevice *) object; + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + + g_slist_free_full (priv->keygrabs, g_free); + priv->keygrabs = NULL; + + device_parent_class->finalize (object); +} + +static void +atspi_device_real_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd) +{ +} + +static void +atspi_device_real_remove_key_grab (AtspiDevice *device, guint id) +{ +} + +static void +atspi_device_class_init (AtspiDeviceClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + device_parent_class = g_type_class_peek_parent (klass); + klass->add_key_grab = atspi_device_real_add_key_grab; + klass->remove_key_grab = atspi_device_real_remove_key_grab; + object_class->finalize = atspi_device_finalize; +} + +/** + * atspi_device_new: + * + * Creates a new #AtspiDevice with a specified callback function. + * + * Returns: (transfer full): a pointer to a newly-created #AtspiDevice. + * + **/ +AtspiDevice * +atspi_device_new () +{ +#ifdef HAVE_X11 + if (!g_getenv ("WAYLAND_DISPLAY") && !g_getenv ("ATSPI_USE_LEGACY_DEVICE")) + return ATSPI_DEVICE (atspi_device_x11_new ()); +#endif + + return ATSPI_DEVICE (atspi_device_legacy_new ()); +} + +gboolean +atspi_device_notify_key (AtspiDevice *device, gboolean pressed, int keycode, int keysym, gint state, gchar *text) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + GSList *l; + gboolean ret = FALSE; + + for (l = priv->key_watchers; l; l = l->next) + { + AtspiKeyGrab *grab = l->data; + grab->callback (device, pressed, keycode, keysym, state, text, grab->callback_data); + } + + for (l = priv->keygrabs; l; l = l->next) + { + AtspiKeyGrab *grab = l->data; + //if (keycode == grab->keycode && (grab->modifiers & state) == grab->modifiers) + if (keycode == grab->keycode && grab->modifiers == state) + { + if (grab->callback) + grab->callback (device, pressed, keycode, keysym, state, text, grab->callback_data); + ret = TRUE; + } + } + + return ret; +} + +static gboolean +is_id_used (AtspiDevice *device, guint id) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + GSList *l; + + for (l = priv->key_watchers; l; l = l->next) + { + AtspiKeyGrab *grab = l->data; + if (grab->id == id) + return TRUE; + } + + for (l = priv->keygrabs; l; l = l->next) + { + AtspiKeyGrab *grab = l->data; + if (grab->id == id) + return TRUE; + } + + return FALSE; +} + +static guint +get_grab_id (AtspiDevice *device) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + + while (is_id_used (device, priv->last_grab_id)) priv->last_grab_id++; + return priv->last_grab_id++; +} + +static gboolean +grab_has_duplicate (AtspiDevice *device, AtspiKeyGrab *grab) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + GSList *l; + + for (l = priv->keygrabs; l; l = l->next) + { + AtspiKeyGrab *other_grab = l->data; + if (other_grab->id != grab->id && other_grab->keycode == grab->keycode && other_grab->modifiers == grab->modifiers) + return TRUE; + } + + return FALSE; +} + +/** + *atspi_device_add_key_grab: +* @device: the device. + * @kd: a #AtspiKeyDefinition specifying the key code to grab. + * @callback: (scope notified) (allow-none): the function to call when the + * given key is pressed. + * @user_data: Data to be passed to @callback. + * @callback_destroyed: callback function to be called when @callback is + * destroyed. + * + * Returns: an identifier that can be later used to remove the grab. + * Add a key grab for the given key/modifier combination. + */ +guint +atspi_device_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd, AtspiKeyCallback callback, void *user_data, GDestroyNotify callback_destroyed) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + AtspiKeyGrab *grab = g_new (AtspiKeyGrab, 1); + grab->keycode = kd->keycode; + grab->keysym = kd->keysym; + grab->modifiers = kd->modifiers; + grab->callback = callback; + grab->callback_data = user_data; + grab->callback_destroyed = callback_destroyed; + grab->id = get_grab_id (device); + priv->keygrabs = g_slist_append (priv->keygrabs, grab); + + if (!grab_has_duplicate (device, grab)) + ATSPI_DEVICE_GET_CLASS (device)->add_key_grab (device, kd); + return grab->id; +} + +/** + * atspi_device_remove_key_grab: + * @device: the device. + * @id: the identifier of the grab to be removed. + * + * Removes the key grab specified by @id. + */ +void +atspi_device_remove_key_grab (AtspiDevice *device, guint id) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + GSList *l; + + for (l = priv->keygrabs; l; l = l->next) + { + AtspiKeyGrab *grab = l->data; + if (grab->id == id) + { + if (!grab_has_duplicate (device, grab)) + ATSPI_DEVICE_GET_CLASS (device)->remove_key_grab (device, id); + priv->keygrabs = g_slist_remove (priv->keygrabs, grab); + if (grab->callback_destroyed) + (*grab->callback_destroyed) (grab->callback); + g_free (grab); + return; + } + } +} + +/** + *atspi_device_add_key_watcher: +* @device: the device. + * @callback: (scope notified): the function to call when the given key is + * pressed. + * @user_data: (closure callback): Data to be passed to @callback. + * @callback_destroyed: (destroy callback): callback function to be called + * when @callback is destroyed. + * + * Add a callback that will receive a notification whenever a key is + * pressed or released. + */ +void +atspi_device_add_key_watcher (AtspiDevice *device, AtspiKeyCallback callback, void *user_data, GDestroyNotify callback_destroyed) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + AtspiKeyGrab *grab = g_new0 (AtspiKeyGrab, 1); + grab->id = get_grab_id (device); + grab->callback = callback; + grab->callback_data = user_data; + grab->callback_destroyed = callback_destroyed; + priv->key_watchers = g_slist_append (priv->key_watchers, grab); +} + +AtspiKeyDefinition * +atspi_device_get_grab_by_id (AtspiDevice *device, guint id) +{ + AtspiDevicePrivate *priv = atspi_device_get_instance_private (device); + GSList *l; + + for (l = priv->keygrabs; l; l = l->next) + { + AtspiKeyGrab *grab = l->data; + if (grab->id == id) + { + AtspiKeyDefinition *kd = g_new0 (AtspiKeyDefinition, 1); + kd->keycode = grab->keycode;\ + kd->modifiers = grab->modifiers; + return kd; + } + } + return NULL; +} + +/** + * atspi_device_map_modifier: + * @device: the device. + * @keycode: the keycode to map. + * + * Maps the specified key code to a modifier so that it can be used in + * conjunction with other keys to create a key grab. If the given keycode is + * already mapped, then this function will return the modifier that is + * currently mapped to the keycode, without doing anything else. Otherwise, + * it will use the last modifier that AT-SPI used to map a key. If no keys + * have yet been mapped using this device, then it will look for a modifier + * that is not currently being used. If no unused modifier can be found, + * then it will use the first modifier by default. + * + * Returns: the modifier that is now mapped to this keycode. This return + * value can be passed to atspi_device_add_key_grab. + */ +guint +atspi_device_map_modifier (AtspiDevice *device, gint keycode) +{ + if (ATSPI_DEVICE_GET_CLASS (device)->map_modifier) + return ATSPI_DEVICE_GET_CLASS (device)->map_modifier (device, keycode); + + return 0; +} + +/** + * atspi_device_unmap_modifier: + * @device: the device. + * @keycode: the keycode to unmap. + * + * Removes a mapped modifier from the given keycode. + */ +void +atspi_device_unmap_modifier (AtspiDevice *device, gint keycode) +{ + if (ATSPI_DEVICE_GET_CLASS (device)->unmap_modifier) + ATSPI_DEVICE_GET_CLASS (device)->unmap_modifier (device, keycode); +} + +/** + * atspi_device_get_modifier: + * @device: the device. + * @keycode: the keycode to map. + * + * Gets the modifier for a given keycode, if one exists. Does not creatt a new + * mapping. This function should be used when the intention is to query a + * locking modifier such as num lock via atspi_device_get_locked_modifiers, + * rather than to add key grabs. + * + * Returns: the modifier that is mapped to this keycode. + */ +guint +atspi_device_get_modifier (AtspiDevice *device, gint keycode) +{ + if (ATSPI_DEVICE_GET_CLASS (device)->get_modifier) + return ATSPI_DEVICE_GET_CLASS (device)->get_modifier (device, keycode); + + return 0; +} + +/** + * atspi_device_get_locked_modifiers: + * @device: the device. + * + * Returns the locked modifiers (ie, num lock, caps lock) associated with this + * keyboard. + * + * Returns: a guint of modifier flags. + */ +guint +atspi_device_get_locked_modifiers (AtspiDevice *device) +{ + if (ATSPI_DEVICE_GET_CLASS (device)->get_locked_modifiers) + return ATSPI_DEVICE_GET_CLASS (device)->get_locked_modifiers (device); + + return 0; +} + +/** + * atspi_device_grab_keyboard: + * + * Attempts to grab the entire keyboard. This should only be done + * temporarily, as it may conflict with other applications that also want to + * grab the keyboard. + * + * Returns: #TRUE if successful, #FALSE otherwise. + */ +gboolean +atspi_device_grab_keyboard (AtspiDevice *device) +{ + if (ATSPI_DEVICE_GET_CLASS (device)->grab_keyboard) + return ATSPI_DEVICE_GET_CLASS (device)->grab_keyboard (device); + + return FALSE; +} + +/** + * atspi_device_ungrab_keyboard: + * + * Removes a keyboard grab added via a call to atspi_device_add_keyboard. + */ +void +atspi_device_ungrab_keyboard (AtspiDevice *device) +{ + if (ATSPI_DEVICE_GET_CLASS (device)->ungrab_keyboard) + ATSPI_DEVICE_GET_CLASS (device)->ungrab_keyboard (device); +} + diff --git a/atspi/atspi-device.h b/atspi/atspi-device.h new file mode 100644 index 0000000..a246842 --- /dev/null +++ b/atspi/atspi-device.h @@ -0,0 +1,103 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2020 SUSE LLC. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _ATSPI_DEVICE_H_ +#define _ATSPI_DEVICE_H_ + +#include "glib-object.h" + +#include "atspi-types.h" + +G_BEGIN_DECLS + +#define ATSPI_TYPE_DEVICE (atspi_device_get_type ()) +#define ATSPI_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ATSPI_TYPE_DEVICE, AtspiDevice)) +#define ATSPI_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ATSPI_TYPE_DEVICE, AtspiDeviceClass)) +#define ATSPI_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ATSPI_TYPE_DEVICE)) +#define ATSPI_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ATSPI_TYPE_DEVICE)) +#define ATSPI_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ATSPI_TYPE_DEVICE, AtspiDeviceClass)) + +typedef struct _AtspiDevice AtspiDevice; +struct _AtspiDevice +{ + GObject parent; +}; + +typedef struct _AtspiDeviceClass AtspiDeviceClass; +struct _AtspiDeviceClass +{ + GObjectClass parent_class; + + void (*add_key_grab) (AtspiDevice *device, AtspiKeyDefinition *kd); + void (*remove_key_grab) (AtspiDevice *device, guint id); + guint (*map_modifier) (AtspiDevice *device, gint keycode); + void (*unmap_modifier) (AtspiDevice *device, gint keycode); + guint (*get_modifier) (AtspiDevice *device, gint keycode); + gboolean (*grab_keyboard) (AtspiDevice *device); + void (*ungrab_keyboard) (AtspiDevice *device); + guint (*get_locked_modifiers) (AtspiDevice *device); +}; + +GType atspi_device_get_type (void); + +/** + * AtspiKeyCallback: + * @device: the device. + * @pressed: TRUE if the key is being pressed, FALSE if being released. + * @keycode: the hardware code for the key. + * @keysym: the keysym for the key. + * @modifiers: a bitflag indicating which key modifiers are active. + * @keystring: the text corresponding to the keypress. + * @user_data: (closure): user-supplied data + * + * A callback that will be invoked when a key is pressed. + */ +typedef void (*AtspiKeyCallback) (AtspiDevice *device, gboolean pressed, guint keycode, guint keysym, guint modifiers, const gchar *keystring, void *user_data); + +AtspiDevice *atspi_device_new (); + +gboolean atspi_device_notify_key (AtspiDevice *device, gboolean pressed, int keycode, int keysym, gint state, gchar *text); + +guint atspi_device_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd, AtspiKeyCallback callback, void *user_data, GDestroyNotify callback_destroyed); + +void atspi_device_remove_key_grab (AtspiDevice *device, guint id); + +void atspi_device_add_key_watcher (AtspiDevice *device, AtspiKeyCallback callback, void *user_data, GDestroyNotify callback_destroyed); + +AtspiKeyDefinition *atspi_device_get_grab_by_id (AtspiDevice *device, guint id); + +guint atspi_device_map_modifier (AtspiDevice *device, gint keycode); + +void atspi_device_unmap_modifier (AtspiDevice *device, gint keycode); + +guint atspi_device_get_modifier (AtspiDevice *device, gint keycode); + +guint atspi_device_get_locked_modifiers (AtspiDevice *device); + +gboolean atspi_device_grab_keyboard (AtspiDevice *device); + +void atspi_device_ungrab_keyboard (AtspiDevice *device); + +G_END_DECLS + +#endif /* _ATSPI_DEVICE_H_ */ diff --git a/atspi/atspi-enum-types.c.template b/atspi/atspi-enum-types.c.template index 385d0ee..92e4937 100644 --- a/atspi/atspi-enum-types.c.template +++ b/atspi/atspi-enum-types.c.template @@ -5,7 +5,7 @@ /*** BEGIN file-production ***/ /* enumerations from "@basename@" */ -#include "@filename@" +#include "@basename@" /*** END file-production ***/ diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c index 249890b..ca6828f 100644 --- a/atspi/atspi-event-listener.c +++ b/atspi/atspi-event-listener.c @@ -166,6 +166,9 @@ atspi_event_listener_new_simple (AtspiEventListenerSimpleCB callback, } static GList *event_listeners = NULL; +static GList *pending_removals = NULL; +static int in_send = 0; + static gchar * convert_name_from_dbus (const char *name, gboolean path_hack) @@ -332,40 +335,10 @@ demarshal_rect (DBusMessageIter *iter, AtspiRect *rect) return TRUE; } -static gchar * -strdup_and_adjust_for_dbus (const char *s) -{ - gchar *d = g_strdup (s); - gchar *p; - int parts = 0; - - if (!d) - return NULL; - - for (p = d; *p; p++) - { - if (*p == '-') - { - memmove (p, p + 1, g_utf8_strlen (p, -1)); - *p = toupper (*p); - } - else if (*p == ':') - { - parts++; - if (parts == 2) - break; - p [1] = toupper (p [1]); - } - } - - d [0] = toupper (d [0]); - return d; -} - static gboolean convert_event_type_to_dbus (const char *eventType, char **categoryp, char **namep, char **detailp, GPtrArray **matchrule_array) { - gchar *tmp = strdup_and_adjust_for_dbus (eventType); + gchar *tmp = _atspi_strdup_and_adjust_for_dbus (eventType); char *category = NULL, *name = NULL, *detail = NULL; char *saveptr = NULL; @@ -420,6 +393,12 @@ listener_entry_free (EventListenerEntry *e) g_free (e->name); if (e->detail) g_free (e->detail); callback_unref (callback); + + for (int i=0; i < e->properties->len; i++) + g_free (g_array_index (e->properties, char*, i)); + + g_array_free (e->properties, TRUE); + g_free (e); } @@ -627,7 +606,7 @@ copy_event_properties (GArray *src) for (i = 0; i < src->len; i++) { gchar *dup = g_strdup (g_array_index (src, char *, i)); - g_array_append_val (dst, dup); + g_array_append_val (dst, dup); } return dst; } @@ -677,6 +656,7 @@ atspi_event_listener_register_from_callback_full (AtspiEventListenerCB callback, callback_destroyed); if (!convert_event_type_to_dbus (event_type, &e->category, &e->name, &e->detail, &matchrule_array)) { + g_free (e->event_type); g_free (e); return FALSE; } @@ -815,12 +795,12 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback, is_superset (name, e->name) && is_superset (detail, e->detail)) { - gboolean need_replace; DBusMessage *message, *reply; - need_replace = (l == event_listeners); - l = g_list_remove (l, e); - if (need_replace) - event_listeners = l; + l = g_list_next (l); + if (in_send) + pending_removals = g_list_append (pending_removals, e); + else + event_listeners = g_list_remove (event_listeners, e); for (i = 0; i < matchrule_array->len; i++) { char *matchrule = g_ptr_array_index (matchrule_array, i); @@ -837,9 +817,11 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback, if (reply) dbus_message_unref (reply); - listener_entry_free (e); + if (!in_send) + listener_entry_free (e); } - else l = g_list_next (l); + else + l = g_list_next (l); } g_free (category); g_free (name); @@ -882,7 +864,8 @@ atspi_event_copy (AtspiEvent *src) dst->detail2 = src->detail2; g_value_init (&dst->any_data, G_VALUE_TYPE (&src->any_data)); g_value_copy (&src->any_data, &dst->any_data); - dst->sender = g_object_ref (src->sender); + if (src->sender) + dst->sender = g_object_ref (src->sender); return dst; } @@ -892,7 +875,7 @@ atspi_event_free (AtspiEvent *event) g_object_unref (event->source); g_free (event->type); g_value_unset (&event->any_data); - g_object_unref (event->sender); + g_clear_object (&event->sender); g_free (event); } @@ -911,6 +894,13 @@ detail_matches_listener (const char *event_detail, const char *listener_detail) : strcmp (listener_detail, event_detail)); } +static void +resolve_pending_removal (gpointer data) +{ + event_listeners = g_list_remove (event_listeners, data); + listener_entry_free (data); +} + void _atspi_send_event (AtspiEvent *e) { @@ -931,6 +921,7 @@ _atspi_send_event (AtspiEvent *e) g_warning ("AT-SPI: Couldn't parse event: %s\n", e->type); return; } + in_send++; for (l = event_listeners; l; l = g_list_next (l)) { EventListenerEntry *entry = l->data; @@ -947,15 +938,27 @@ _atspi_send_event (AtspiEvent *e) } if (!l2) { + for (l2 = pending_removals; l2; l2 = l2->next) + { + if (l2->data == entry) + break; + } + } + if (!l2) + { entry->callback (atspi_event_copy (e), entry->user_data); called_listeners = g_list_prepend (called_listeners, entry); } } } + in_send--; if (detail) g_free (detail); g_free (name); g_free (category); g_list_free (called_listeners); + + g_list_free_full (pending_removals, resolve_pending_removal); + pending_removals = NULL; } DBusHandlerResult @@ -1057,6 +1060,7 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data) accessible = _atspi_dbus_return_accessible_from_iter (&iter_variant); if (!strcmp (category, "ScreenReader")) { + g_object_unref (e.source); e.source = accessible; } else @@ -1116,6 +1120,7 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data) g_free (name); g_free (detail); g_object_unref (e.source); + g_object_unref (e.sender); g_value_unset (&e.any_data); return DBUS_HANDLER_RESULT_HANDLED; } diff --git a/atspi/atspi-misc-private.h b/atspi/atspi-misc-private.h index f0b5adb..fb78b02 100644 --- a/atspi/atspi-misc-private.h +++ b/atspi/atspi-misc-private.h @@ -168,6 +168,8 @@ gboolean _atspi_set_allow_sync (gboolean val); void _atspi_set_error_no_sync (GError **error); gboolean _atspi_prepare_screen_reader_interface (); + +gchar * _atspi_strdup_and_adjust_for_dbus (const char *s); G_END_DECLS #endif /* _ATSPI_MISC_PRIVATE_H_ */ diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index 9e8595a..7af46e9 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -35,6 +35,7 @@ #include "atspi-gmain.h" #include #include +#include static void handle_get_items (DBusPendingCall *pending, void *user_data); @@ -132,6 +133,8 @@ _atspi_bus () static AtspiAccessible *desktop; +static void cleanup_deferred_message (void); + static void cleanup () { @@ -145,15 +148,8 @@ cleanup () g_hash_table_destroy (refs); } - if (bus) - { - dbus_connection_close (bus); - dbus_connection_unref (bus); - bus = NULL; - } - if (!desktop) - return; + goto end; /* TODO: Do we need this code, or should we just dispose the desktop? */ for (i = desktop->children->len - 1; i >= 0; i--) @@ -167,6 +163,14 @@ cleanup () g_object_run_dispose (G_OBJECT (desktop->parent.app)); g_object_unref (desktop); desktop = NULL; + +end: + if (bus) + { + dbus_connection_close (bus); + dbus_connection_unref (bus); + bus = NULL; + } } static gboolean atspi_inited = FALSE; @@ -454,7 +458,16 @@ add_accessible_from_iter (DBusMessageIter *iter) if (index >= 0 && accessible->accessible_parent) { if (index >= accessible->accessible_parent->children->len) + { + /* There is no room for this object */ g_ptr_array_set_size (accessible->accessible_parent->children, index + 1); + } + else + { + /* This place is already taken - let's free this place with dignity */ + if (g_ptr_array_index (accessible->accessible_parent->children, index)) + g_object_unref (g_ptr_array_index (accessible->accessible_parent->children, index)); + } g_ptr_array_index (accessible->accessible_parent->children, index) = g_object_ref (accessible); } @@ -763,6 +776,23 @@ process_deferred_message (BusDataClosure *closure) static GQueue *deferred_messages = NULL; +static void +destroy_deferred_message_item(gpointer ptr) +{ + /* TODO this is still memory leak on c->data */ + BusDataClosure *c = ptr; + dbus_message_unref (c->message); + dbus_connection_unref (c->bus); + g_free (c); +} + +static void +cleanup_deferred_message(void) +{ + g_queue_free_full (deferred_messages, destroy_deferred_message_item); + deferred_messages = NULL; +} + static gboolean process_deferred_messages (void) { @@ -1244,7 +1274,7 @@ _atspi_dbus_get_property (gpointer obj, const char *interface, const char *name, process_deferred_messages (); if (!reply) { - // TODO: throw exception + /* TODO: throw exception */ goto done; } @@ -1275,6 +1305,11 @@ _atspi_dbus_get_property (gpointer obj, const char *interface, const char *name, } else { + if (type [0] == 's') + { + *(char**) data = NULL; + } + dbus_message_iter_get_basic (&iter_variant, data); if (type [0] == 's') *(char **)data = g_strdup (*(char **)data); @@ -1403,7 +1438,7 @@ _atspi_dbus_set_interfaces (AtspiAccessible *accessible, DBusMessageIter *iter) accessible->interfaces = 0; if (strcmp (iter_sig, "as") != 0) { - g_warning ("_atspi_dbus_set_interfaces: Passed iterator with invalid signature %s", dbus_message_iter_get_signature (iter)); + g_warning ("_atspi_dbus_set_interfaces: Passed iterator with invalid signature %s", iter_sig); dbus_free (iter_sig); return; } @@ -1552,7 +1587,7 @@ get_accessibility_bus_address_dbus (void) address = g_strdup (tmp_address); dbus_message_unref (reply); } - + out: dbus_connection_unref (session_bus); return address; @@ -1899,3 +1934,33 @@ _atspi_prepare_screen_reader_interface () dbus_connection_add_filter (a11y_bus, screen_reader_filter, NULL, NULL); return TRUE; } + +gchar * +_atspi_strdup_and_adjust_for_dbus (const char *s) +{ + gchar *d = g_strdup (s); + gchar *p; + int parts = 0; + + if (!d) + return NULL; + + for (p = d; *p; p++) + { + if (*p == '-') + { + memmove (p, p + 1, g_utf8_strlen (p, -1)); + *p = toupper (*p); + } + else if (*p == ':') + { + parts++; + if (parts == 2) + break; + p [1] = toupper (p [1]); + } + } + + d [0] = toupper (d [0]); + return d; +} diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c index c50ae20..dea5878 100644 --- a/atspi/atspi-registry.c +++ b/atspi/atspi-registry.c @@ -528,7 +528,6 @@ atspi_generate_mouse_event (glong x, glong y, const gchar *name, GError **error) /** * atspi_set_reference_window: - * * @accessible: the #AtspiAccessible corresponding to the window to select. * should be a top-level window with a role of * ATSPI_ROLE_APPLICATION. @@ -557,7 +556,7 @@ atspi_key_definition_copy (AtspiKeyDefinition *src) dst->keysym = src->keysym; if (src->keystring) dst->keystring = g_strdup (src->keystring); - dst->unused = src->unused; + dst->modifiers = src->modifiers; return dst; } diff --git a/atspi/atspi-types.h b/atspi/atspi-types.h index 2631baf..ab43ca8 100644 --- a/atspi/atspi-types.h +++ b/atspi/atspi-types.h @@ -78,9 +78,16 @@ struct _AtspiKeyDefinition gint keycode; gint keysym; gchar *keystring; - gint unused; + guint modifiers; }; +/** + * ATSPI_TYPE_KEY_DEFINITION: + * + * The #GType for a boxed type holding a #AtspiKeyDefinition. + */ +#define ATSPI_TYPE_KEY_DEFINITION (atspi_key_definition_get_type ()) + typedef struct _AtspiEvent AtspiEvent; struct _AtspiEvent { diff --git a/atspi/atspimarshal.list b/atspi/atspimarshal.list index 2d9dd51..163720a 100644 --- a/atspi/atspimarshal.list +++ b/atspi/atspimarshal.list @@ -23,3 +23,4 @@ # BOOL deprecated alias for BOOLEAN VOID:INT,INT +VOID:INT,STRING diff --git a/atspi/meson.build b/atspi/meson.build index 8a2ca27..ace8502 100644 --- a/atspi/meson.build +++ b/atspi/meson.build @@ -4,6 +4,8 @@ atspi_sources = [ 'atspi-application.c', 'atspi-collection.c', 'atspi-component.c', + 'atspi-device.c', + 'atspi-device-legacy.c', 'atspi-device-listener.c', 'atspi-document.c', 'atspi-editabletext.c', @@ -34,6 +36,8 @@ atspi_headers = [ 'atspi-collection.h', 'atspi-component.h', 'atspi-constants.h', + 'atspi-device.h', + 'atspi-device-legacy.h', 'atspi-device-listener.h', 'atspi-document.h', 'atspi-editabletext.h', @@ -56,6 +60,14 @@ atspi_headers = [ 'atspi-value.h', ] +x11_option = get_option('x11') +if x11_option != 'no' + if x11_dep.found() + atspi_sources += ['atspi-device-x11.c'] + atspi_headers += ['atspi-device-x11.h'] + endif +endif + atspi_includedir = join_paths(get_option('prefix'), get_option('includedir'), 'at-spi-2.0', 'atspi') install_headers(atspi_headers, install_dir: atspi_includedir) @@ -127,7 +139,7 @@ pkgconfig.generate( description: 'Accessibility Technology software library', version: meson.project_version(), libraries: atspi, - requires: 'dbus-1 glib-2.0', + requires: ['dbus-1', 'glib-2.0'], subdirs: 'at-spi-2.0', filebase: 'atspi-2', ) diff --git a/bus/accessibility.conf.in b/bus/accessibility.conf.in index 31b6a79..79c5146 100644 --- a/bus/accessibility.conf.in +++ b/bus/accessibility.conf.in @@ -6,7 +6,7 @@ @DATADIR@/dbus-1/accessibility-services EXTERNAL - unix:tmpdir=/tmp + unix:dir=/tmp diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index b4f49b8..d7c6690 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -39,6 +39,9 @@ #include #include #endif +#ifdef DBUS_BROKER +#include +#endif typedef enum { A11Y_BUS_STATE_IDLE = 0, @@ -69,6 +72,7 @@ typedef struct { int pipefd[2]; int listenfd; char *a11y_launch_error_message; + GDBusProxy *sm_proxy; } A11yBusLauncher; static A11yBusLauncher *_global_app = NULL; @@ -140,27 +144,60 @@ client_proxy_ready_cb (GObject *source_object, } static void +client_registered (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + A11yBusLauncher *app = user_data; + GError *error = NULL; + GVariant *variant; + gchar *object_path; + GDBusProxyFlags flags; + + variant = g_dbus_proxy_call_finish (app->sm_proxy, result, &error); + if (!variant) + { + if (error != NULL) + { + g_warning ("Failed to register client: %s", error->message); + g_error_free (error); + } + } + else + { + g_variant_get (variant, "(o)", &object_path); + g_variant_unref (variant); + + flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES; + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, flags, NULL, + "org.gnome.SessionManager", object_path, + "org.gnome.SessionManager.ClientPrivate", + NULL, client_proxy_ready_cb, app); + + g_free (object_path); + } + g_clear_object (&app->sm_proxy); +} + +static void register_client (A11yBusLauncher *app) { GDBusProxyFlags flags; - GDBusProxy *sm_proxy; GError *error; const gchar *app_id; const gchar *autostart_id; gchar *client_startup_id; GVariant *parameters; - GVariant *variant; - gchar *object_path; flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS; error = NULL; - sm_proxy = g_dbus_proxy_new_sync (app->session_bus, flags, NULL, - "org.gnome.SessionManager", - "/org/gnome/SessionManager", - "org.gnome.SessionManager", - NULL, &error); + app->sm_proxy = g_dbus_proxy_new_sync (app->session_bus, flags, NULL, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + NULL, &error); if (error != NULL) { @@ -187,31 +224,11 @@ register_client (A11yBusLauncher *app) g_free (client_startup_id); error = NULL; - variant = g_dbus_proxy_call_sync (sm_proxy, - "RegisterClient", parameters, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, &error); - - g_object_unref (sm_proxy); - - if (error != NULL) - { - g_warning ("Failed to register client: %s", error->message); - g_error_free (error); - - return; - } - - g_variant_get (variant, "(o)", &object_path); - g_variant_unref (variant); - - flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES; - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, flags, NULL, - "org.gnome.SessionManager", object_path, - "org.gnome.SessionManager.ClientPrivate", - NULL, client_proxy_ready_cb, app); + g_dbus_proxy_call (app->sm_proxy, + "RegisterClient", parameters, + G_DBUS_CALL_FLAGS_NONE, + G_MAXINT, NULL, client_registered, app); - g_free (object_path); } static void @@ -378,11 +395,26 @@ static gboolean ensure_a11y_bus_broker (A11yBusLauncher *app, char *config_path) { char *argv[] = { DBUS_BROKER, config_path, "--scope", "user", NULL }; + char *unit; struct sockaddr_un addr = { .sun_family = AF_UNIX }; socklen_t addr_len = sizeof(addr); GPid pid; GError *error = NULL; + /* This detects whether we are running under systemd. We only try to + * use dbus-broker if we are running under systemd because D-Bus + * service activation won't work otherwise. + */ + if (sd_pid_get_user_unit (getpid (), &unit) >= 0) + { + free (unit); + } + else + { + app->state = A11Y_BUS_STATE_ERROR; + return FALSE; + } + if ((app->listenfd = socket (PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0) g_error ("Failed to create listening socket: %s", strerror (errno)); diff --git a/bus/at-spi-dbus-bus.desktop.in b/bus/at-spi-dbus-bus.desktop.in index b3c90bd..a45d27e 100644 --- a/bus/at-spi-dbus-bus.desktop.in +++ b/bus/at-spi-dbus-bus.desktop.in @@ -4,6 +4,6 @@ Name=AT-SPI D-Bus Bus Exec=@libexecdir@/at-spi-bus-launcher --launch-immediately OnlyShowIn=GNOME;Unity; NoDisplay=true -AutostartCondition=GSETTINGS org.gnome.desktop.interface toolkit-accessibility +AutostartCondition=GSettings org.gnome.desktop.interface toolkit-accessibility X-GNOME-AutoRestart=true X-GNOME-Autostart-Phase=Initialization diff --git a/bus/meson.build b/bus/meson.build index 155dc53..f6c32c9 100644 --- a/bus/meson.build +++ b/bus/meson.build @@ -10,25 +10,21 @@ session_dir = join_paths(atspi_sysconfdir, 'xdg/autostart') configure_file(input: 'accessibility.conf.in', output: 'accessibility.conf', configuration: accessibility_conf, - install: true, install_dir: busconfig_dir) configure_file(input: 'at-spi-dbus-bus.desktop.in', output: 'at-spi-dbus-bus.desktop', configuration: libexec_conf, - install: true, install_dir: session_dir) configure_file(input: 'org.a11y.Bus.service.in', output: 'org.a11y.Bus.service', configuration: libexec_conf, - install: true, install_dir: dbus_services_dir) configure_file(input: 'at-spi-dbus-bus.service.in', output: 'at-spi-dbus-bus.service', configuration: libexec_conf, - install: true, install_dir: systemd_user_dir) launcher_args = [ @@ -52,13 +48,16 @@ else endif endif +needs_systemd = false if get_option('dbus_broker') != 'default' launcher_args += '-DDBUS_BROKER="@0@"'.format(get_option('dbus_broker')) + needs_systemd = true else dbus_broker = find_program('dbus-broker-launch', required: false) if dbus_broker.found() launcher_args += '-DDBUS_BROKER="@0@"'.format(dbus_broker.path()) + needs_systemd = true endif endif @@ -66,9 +65,15 @@ if get_option('default_bus') == 'dbus-broker' launcher_args += '-DWANT_DBUS_BROKER' endif +if needs_systemd + systemd_dep = dependency('libsystemd') +else + systemd_dep = dependency('', required: false) +endif + executable('at-spi-bus-launcher', 'at-spi-bus-launcher.c', include_directories: [ root_inc, include_directories('.') ], - dependencies: [ gio_dep, x11_deps ], + dependencies: [ gio_dep, systemd_dep, x11_deps ], c_args: launcher_args, install: true, install_dir: atspi_libexecdir) diff --git a/dbind/dbtest.c b/dbind/dbtest.c index 4f58540..b338c03 100644 --- a/dbind/dbtest.c +++ b/dbind/dbtest.c @@ -86,7 +86,7 @@ void test_simple () dbind_any_free ("i", &v2); /* nop */ dbus_message_unref (msg); - fprintf (stderr, "simple ok\n"); + printf ("simple ok\n"); } void test_array () @@ -117,7 +117,7 @@ void test_array () dbind_any_free ("ai", &a2); dbus_message_unref (msg); - fprintf (stderr, "array ok\n"); + printf ("array ok\n"); } /* this taught me that the struct type is a mis-nomer, @@ -146,7 +146,7 @@ void test_struct_native () } dbus_message_iter_close_container (&iter, &arr); - fprintf (stderr, "native struct marshalling ok\n"); + printf ("native struct marshalling ok\n"); dbus_message_unref (msg); } @@ -185,7 +185,7 @@ void test_struct_simple () g_assert (!strcmp (g_array_index (a2, FooBaa, 1).baa, "baA")); g_assert (!strcmp (g_array_index (a2, FooBaa, 1).baz, "BaZ")); - fprintf (stderr, "simple struct ok\n"); + printf ("simple struct ok\n"); dbind_any_free ("a(sss)", &a2); dbus_message_unref (msg); @@ -248,7 +248,7 @@ void test_struct_complex () g_assert (c2.pad2 == 1); g_assert (!strcmp (c1.name, "stroustrup")); - fprintf (stderr, "complex struct ok\n"); + printf ("complex struct ok\n"); dbind_any_free (TYPEOF_COMPLEX, &c2); dbus_message_unref (msg); @@ -296,7 +296,7 @@ void test_struct_with_array () g_assert (p[0].pad1 == 2); g_assert (g_array_index (p[1].vals, dbus_uint32_t, 1) == 1000000000); - fprintf (stderr, "struct with array ok\n"); + printf ("struct with array ok\n"); dbind_any_free (TYPEOF_ARRAYSTRUCT, &a2); dbus_message_unref (msg); @@ -342,7 +342,7 @@ void test_twovals () dbind_any_free ("ii", &o); /* nop */ dbus_message_unref (msg); - fprintf (stderr, "two-val ok\n"); + printf ("two-val ok\n"); } void test_marshalling () @@ -355,7 +355,7 @@ void test_marshalling () test_struct_with_array (); test_twovals (); - fprintf (stderr, "Marshalling ok\n"); + printf ("Marshalling ok\n"); } void test_teamspaces (DBusConnection *bus) @@ -403,7 +403,7 @@ void test_helpers () dbind_find_c_alignment ("a(sss)"); dbind_find_c_alignment ("(s(s)yd(d)s)"); dbind_find_c_alignment ("a{ss}"); - fprintf (stderr, "helpers passed\n"); + printf ("helpers passed\n"); } int main (int argc, char **argv) diff --git a/meson.build b/meson.build index 0a2f75e..ca49dfb 100644 --- a/meson.build +++ b/meson.build @@ -1,12 +1,12 @@ project('at-spi2-core', 'c', - version: '2.34.0', + version: '2.39.90.1', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', 'warning_level=1', 'c_std=c99', ], - meson_version: '>= 0.50.0') + meson_version: '>= 0.46.0') add_project_arguments([ '-D_POSIX_C_SOURCE=200809L', '-D_DEFAULT_SOURCE' ], language: 'c') @@ -44,7 +44,7 @@ endif # Dependencies libdbus_req_version = '>= 1.5' -glib_req_version = '>= 2.32.0' +glib_req_version = '>= 2.62.0' gobject_req_version = '>= 2.0.0' gio_req_version = '>= 2.28.0' diff --git a/po/gl.po b/po/gl.po index d7a0cf4..932ffea 100644 --- a/po/gl.po +++ b/po/gl.po @@ -6,9 +6,9 @@ msgid "" msgstr "" "Project-Id-Version: at-spi 2-core\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-07 00:01+0100\n" -"PO-Revision-Date: 2014-02-07 00:01+0200\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/at-spi2-core/issues\n" +"POT-Creation-Date: 2018-10-05 04:46+0000\n" +"PO-Revision-Date: 2019-12-25 05:11+0100\n" "Last-Translator: Fran Dieguez \n" "Language-Team: gnome-l10n-gl@gnome.org\n" "Language: gl\n" @@ -16,87 +16,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Virtaal 0.7.1\n" +"X-Generator: Poedit 2.2.4\n" -#: ../atspi/atspi-component.c:325 ../atspi/atspi-misc.c:1034 -#: ../atspi/atspi-value.c:111 +#: atspi/atspi-component.c:326 atspi/atspi-misc.c:1073 atspi/atspi-value.c:111 msgid "The application no longer exists" -msgstr "O aplicativo xa non existe" +msgstr "A aplicación xa non existe" -#: ../atspi/atspi-misc.c:1777 +#: atspi/atspi-misc.c:1850 msgid "Attempted synchronous call where prohibited" msgstr "Tentouse unha chamada síncrona onde estaba prohibida" - -#~ msgid "AT-SPI: Unknown signature %s for RemoveAccessible" -#~ msgstr "AT-SPI: Sinatura %s descoñecida para RemoveAccessible" - -#~ msgid "AT-SPI: Error calling getRoot for %s: %s" -#~ msgstr "AT-SPI: Erro ao chamar a getRoot para %s: %s" - -#~ msgid "AT-SPI: Error in GetItems, sender=%s, error=%s" -#~ msgstr "AT-SPI: Erro en GetItems, emisor=%s, erro=%s" - -#~ msgid "" -#~ "AT-SPI: Called _atspi_dbus_return_accessible_from_message with strange " -#~ "signature %s" -#~ msgstr "" -#~ "AT-SPI: Chamouse a _atspi_dbus_return_accessible_from_message cunha " -#~ "sinatura estraña %s" - -#~ msgid "" -#~ "AT-SPI: Called _atspi_dbus_return_hyperlink_from_message with strange " -#~ "signature %s" -#~ msgstr "" -#~ "AT-SPI: Chamouse a _atspi_dbus_return_hyperlink_from_message cunha " -#~ "sinatura estraña %s" - -#~ msgid "AT-SPI: AddAccessible with unknown signature %s\n" -#~ msgstr "AT-SPI: AddAccessible con sinatura %s descoñecida\n" - -#~ msgid "AT-SPI: Could not get the display\n" -#~ msgstr "AT-SPI: Non é posíbel obter a pantalla\n" - -#~ msgid "AT-SPI: Accessibility bus not found - Using session bus.\n" -#~ msgstr "" -#~ "AT-SPI: Non foi posíbel atopar o bus de accesibilidade - Usando o bus de " -#~ "sesión.\n" - -#~ msgid "AT-SPI: Couldn't connect to bus: %s\n" -#~ msgstr "AT-SPI: Non foi posíbel conectarse ao bus: %s\n" - -#~ msgid "AT-SPI: Couldn't register with bus: %s\n" -#~ msgstr "AT-SPI: Non foi posíbel rexistrarse ao bus: %s\n" - -#~ msgid "" -#~ "AT-SPI: expected a variant when fetching %s from interface %s; got %s\n" -#~ msgstr "" -#~ "AT-SPI: agardábase unha variante ao obter %s desde a interface %s; porén " -#~ "obtívose %s\n" - -#~ msgid "atspi_dbus_get_property: Wrong type: expected %s, got %c\n" -#~ msgstr "" -#~ "atspi_dbus_get_property: Tipo incorrecto: esperábase %s, obtívose %c\n" - -#~ msgid "AT-SPI: Unknown interface %s" -#~ msgstr "AT-SPI: Interface %s descoñecida" - -#~ msgid "AT-SPI: expected 2 values in states array; got %d\n" -#~ msgstr "" -#~ "AT-SPI: agardábanse 2 valores na matriz de estados; porén obtivéronse %d\n" - -#~ msgid "Streamable content not implemented" -#~ msgstr "Contido en fluxo non implementado" - -#~ msgid "" -#~ "called atspi_event_listener_register_from_callback with a NULL event_type" -#~ msgstr "" -#~ "chamouse a atspi_event_listener_register_from_callback con un event_type " -#~ "nulo" - -#~ msgid "Got invalid signature %s for signal %s from interface %s\n" -#~ msgstr "" -#~ "Obtívose unha sinatura non válida %s para o sinal %s desde a interface " -#~ "%s\n" - -#~ msgid "AT-SPI: Got error: %s\n" -#~ msgstr "AT-SPI: Obtívose o erro: %s\n" diff --git a/po/pt.po b/po/pt.po index abe1ff6..9953a00 100644 --- a/po/pt.po +++ b/po/pt.po @@ -7,27 +7,25 @@ msgid "" msgstr "" "Project-Id-Version: 3.12\n" -"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=at-" -"spi&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2015-06-08 02:51+0000\n" -"PO-Revision-Date: 2015-06-24 06:27+0100\n" -"Last-Translator: Pedro Albuquerque \n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/at-spi2-core/issues\n" +"POT-Creation-Date: 2020-05-27 15:50+0000\n" +"PO-Revision-Date: 2020-06-24 11:33+0100\n" +"Last-Translator: Manuela Silva \n" "Language-Team: Português \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Gtranslator 2.91.6\n" +"X-Generator: Poedit 2.3.1\n" -#: ../atspi/atspi-component.c:326 ../atspi/atspi-misc.c:1037 -#: ../atspi/atspi-value.c:111 +#: atspi/atspi-component.c:332 atspi/atspi-misc.c:1075 atspi/atspi-value.c:111 msgid "The application no longer exists" msgstr "A aplicação já não existe" -#: ../atspi/atspi-misc.c:1795 +#: atspi/atspi-misc.c:1853 msgid "Attempted synchronous call where prohibited" -msgstr "Tentada uma chamada síncrona onde é proibida" +msgstr "Tentativa de chamada síncrona onde proibida" #~ msgid "AT-SPI: Unknown signature %s for RemoveAccessible" #~ msgstr "AT-SPI: Assinatura %s desconhecida para RemoveAccessible" @@ -38,19 +36,11 @@ msgstr "Tentada uma chamada síncrona onde é proibida" #~ msgid "AT-SPI: Error in GetItems, sender=%s, error=%s" #~ msgstr "AT-SPI: Erro em GetItems, invocador=%s, erro=%s" -#~ msgid "" -#~ "AT-SPI: Called _atspi_dbus_return_accessible_from_message with strange " -#~ "signature %s" -#~ msgstr "" -#~ "AT-SPI: Chamada de _atspi_dbus_return_accessible_from_message com " -#~ "assinatura incomun %s" +#~ msgid "AT-SPI: Called _atspi_dbus_return_accessible_from_message with strange signature %s" +#~ msgstr "AT-SPI: Chamada de _atspi_dbus_return_accessible_from_message com assinatura incomun %s" -#~ msgid "" -#~ "AT-SPI: Called _atspi_dbus_return_hyperlink_from_message with strange " -#~ "signature %s" -#~ msgstr "" -#~ "AT-SPI: Chamada de _atspi_dbus_return_hyperlink_from_message com " -#~ "assinatura incomun %s" +#~ msgid "AT-SPI: Called _atspi_dbus_return_hyperlink_from_message with strange signature %s" +#~ msgstr "AT-SPI: Chamada de _atspi_dbus_return_hyperlink_from_message com assinatura incomun %s" #~ msgid "AT-SPI: AddAccessible with unknown signature %s\n" #~ msgstr "AT-SPI: AddAccessible com assinatura %s desconhecida\n" @@ -59,9 +49,7 @@ msgstr "Tentada uma chamada síncrona onde é proibida" #~ msgstr "AT-SPI: Incapaz de obter o ecrã\n" #~ msgid "AT-SPI: Accessibility bus not found - Using session bus.\n" -#~ msgstr "" -#~ "AT-SPI: Incapaz de encontrar o canal de acessibilidade - A utilizar o " -#~ "canal de sessão.\n" +#~ msgstr "AT-SPI: Incapaz de encontrar o canal de acessibilidade - A utilizar o canal de sessão.\n" #~ msgid "AT-SPI: Couldn't connect to bus: %s\n" #~ msgstr "AT-SPI: Incapaz de se ligar ao canal: %s\n" @@ -69,10 +57,8 @@ msgstr "Tentada uma chamada síncrona onde é proibida" #~ msgid "AT-SPI: Couldn't register with bus: %s\n" #~ msgstr "AT-SPI: Incapaz de se registar no canal: %s\n" -#~ msgid "" -#~ "AT-SPI: expected a variant when fetching %s from interface %s; got %s\n" -#~ msgstr "" -#~ "AT-SPI: esperada uma variante ao obter %s do interface %s; obtida %s\n" +#~ msgid "AT-SPI: expected a variant when fetching %s from interface %s; got %s\n" +#~ msgstr "AT-SPI: esperada uma variante ao obter %s do interface %s; obtida %s\n" #~ msgid "atspi_dbus_get_property: Wrong type: expected %s, got %c\n" #~ msgstr "atspi_dbus_get_property: Tipo incorrecto: esperado %s, obtido %c\n" @@ -86,11 +72,8 @@ msgstr "Tentada uma chamada síncrona onde é proibida" #~ msgid "Streamable content not implemented" #~ msgstr "Conteúdo em fluxo (stream) não está implementado" -#~ msgid "" -#~ "called atspi_event_listener_register_from_callback with a NULL event_type" -#~ msgstr "" -#~ "invocação de atspi_event_listener_register_from_callback com event_type " -#~ "NULL" +#~ msgid "called atspi_event_listener_register_from_callback with a NULL event_type" +#~ msgstr "invocação de atspi_event_listener_register_from_callback com event_type NULL" #~ msgid "Got invalid signature %s for signal %s from interface %s\n" #~ msgstr "Obtida assinatura %s inválida para o sinal %s do interface %s\n" diff --git a/po/uk.po b/po/uk.po index 2da7bed..be0a057 100644 --- a/po/uk.po +++ b/po/uk.po @@ -5,112 +5,89 @@ msgid "" msgstr "" "Project-Id-Version: 1.1\n" -"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=at-" -"spi&component=general\n" -"POT-Creation-Date: 2011-02-04 22:21+0000\n" -"PO-Revision-Date: 2011-02-07 17:41+0300\n" -"Last-Translator: Korostil Daniel \n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/at-spi2-core/issues\n" +"POT-Creation-Date: 2018-06-10 15:50+0000\n" +"PO-Revision-Date: 2019-10-18 18:08+0300\n" +"Last-Translator: vikaig \n" "Language-Team: translation@linux.org.ua\n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" -"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Virtaal 0.6.1\n" - -#: ../atspi/atspi-misc.c:290 -#, c-format -msgid "AT-SPI: Unknown signature %s for RemoveAccessible" -msgstr "AT-SPI: невідомий підпис %s для RemoveAccessible" - -#: ../atspi/atspi-misc.c:327 -#, c-format -msgid "AT-SPI: Error calling getRoot for %s: %s" -msgstr "AT-SPI: помилка виклику getRoot для %s: %s" - -#: ../atspi/atspi-misc.c:485 -#, c-format -msgid "AT-SPI: Error in GetItems, sender=%s, error=%s" -msgstr "AT-SPI: помилка в GetItems, sender=%s, error=%s" - -#: ../atspi/atspi-misc.c:587 -#, c-format -msgid "" -"AT-SPI: Called _atspi_dbus_return_accessible_from_message with strange " -"signature %s" -msgstr "" -"AT-SPI: викликано _atspi_dbus_return_accessible_from_message з дивним " -"підписом %s" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 2.2.1\n" -#: ../atspi/atspi-misc.c:616 -#, c-format -msgid "" -"AT-SPI: Called _atspi_dbus_return_hyperlink_from_message with strange " -"signature %s" -msgstr "" -"AT-SPI: викликано _atspi_dbus_return_hyperlink_from_message з дивним " -"підписом %s" - -#: ../atspi/atspi-misc.c:641 -#, c-format -msgid "AT-SPI: AddAccessible with unknown signature %s\n" -msgstr "AT-SPI: AddAccessible з невідомим підписом %s\n" - -#: ../atspi/atspi-misc.c:826 -msgid "AT-SPI: Could not get the display\n" -msgstr "AT-SPI: неможливо перейти до показу\n" - -#: ../atspi/atspi-misc.c:844 -msgid "AT-SPI: Accessibility bus not found - Using session bus.\n" -msgstr "AT-SPI: не знайдено шини доступності — використовуйте шину сеансу.\n" - -#: ../atspi/atspi-misc.c:848 ../atspi/atspi-misc.c:857 -#, c-format -msgid "AT-SPI: Couldn't connect to bus: %s\n" -msgstr "AT-SPI: неможливо з'єднатись із шиною: %s\n" - -#: ../atspi/atspi-misc.c:864 -#, c-format -msgid "AT-SPI: Couldn't register with bus: %s\n" -msgstr "AT-SPI: неможливо зареєструватись із шиною: %s\n" - -#: ../atspi/atspi-misc.c:1002 ../atspi/atspi-misc.c:1053 -#: ../atspi/atspi-misc.c:1094 +#: atspi/atspi-component.c:326 atspi/atspi-misc.c:1073 atspi/atspi-value.c:111 msgid "The application no longer exists" msgstr "Програми більше не існує" -#: ../atspi/atspi-misc.c:1130 -#, c-format -msgid "AT-SPI: expected a variant when fetching %s from interface %s; got %s\n" -msgstr "AT-SPI: очікуваний варіант, коли звантажуємо %s з інтерфейсу %s; отримаємо %" -"s\n" +#: atspi/atspi-misc.c:1850 +msgid "Attempted synchronous call where prohibited" +msgstr "Спроба синхронного виклику там, де це заборонено" -#: ../atspi/atspi-misc.c:1136 -#, c-format -msgid "atspi_dbus_get_property: Wrong type: expected %s, got %c\n" -msgstr "atspi_dbus_get_property: неправильний тип: очікували %s, отримали %c\n" +#~ msgid "AT-SPI: Unknown signature %s for RemoveAccessible" +#~ msgstr "AT-SPI: невідомий підпис %s для RemoveAccessible" -#: ../atspi/atspi-misc.c:1279 -#, c-format -msgid "AT-SPI: Unknown interface %s" -msgstr "AT-SPI: невідомий інтерфейс %s" +#~ msgid "AT-SPI: Error calling getRoot for %s: %s" +#~ msgstr "AT-SPI: помилка виклику getRoot для %s: %s" -#: ../atspi/atspi-misc.c:1299 -#, c-format -msgid "AT-SPI: expected 2 values in states array; got %d\n" -msgstr "AT-SPI: очікувалось 2 значення в масиві станів; отримали %d\n" +#~ msgid "AT-SPI: Error in GetItems, sender=%s, error=%s" +#~ msgstr "AT-SPI: помилка в GetItems, sender=%s, error=%s" -#: ../atspi/atspi-accessible.c:997 -msgid "Streamable content not implemented" -msgstr "Потоковий вміст не реалізовано" +#~ msgid "" +#~ "AT-SPI: Called _atspi_dbus_return_accessible_from_message with strange " +#~ "signature %s" +#~ msgstr "" +#~ "AT-SPI: викликано _atspi_dbus_return_accessible_from_message з дивним " +#~ "підписом %s" -#: ../atspi/atspi-event-listener.c:510 -msgid "" -"called atspi_event_listener_register_from_callback with a NULL event_type" -msgstr "викликано atspi_event_listener_register_from_callback з NULL event_type" +#~ msgid "" +#~ "AT-SPI: Called _atspi_dbus_return_hyperlink_from_message with strange " +#~ "signature %s" +#~ msgstr "" +#~ "AT-SPI: викликано _atspi_dbus_return_hyperlink_from_message з дивним " +#~ "підписом %s" + +#~ msgid "AT-SPI: AddAccessible with unknown signature %s\n" +#~ msgstr "AT-SPI: AddAccessible з невідомим підписом %s\n" + +#~ msgid "AT-SPI: Could not get the display\n" +#~ msgstr "AT-SPI: неможливо перейти до показу\n" + +#~ msgid "AT-SPI: Accessibility bus not found - Using session bus.\n" +#~ msgstr "" +#~ "AT-SPI: не знайдено шини доступності — використовуйте шину сеансу.\n" + +#~ msgid "AT-SPI: Couldn't connect to bus: %s\n" +#~ msgstr "AT-SPI: неможливо з'єднатись із шиною: %s\n" + +#~ msgid "AT-SPI: Couldn't register with bus: %s\n" +#~ msgstr "AT-SPI: неможливо зареєструватись із шиною: %s\n" + +#~ msgid "" +#~ "AT-SPI: expected a variant when fetching %s from interface %s; got %s\n" +#~ msgstr "" +#~ "AT-SPI: очікуваний варіант, коли звантажуємо %s з інтерфейсу %s; " +#~ "отримаємо %s\n" + +#~ msgid "atspi_dbus_get_property: Wrong type: expected %s, got %c\n" +#~ msgstr "" +#~ "atspi_dbus_get_property: неправильний тип: очікували %s, отримали %c\n" + +#~ msgid "AT-SPI: Unknown interface %s" +#~ msgstr "AT-SPI: невідомий інтерфейс %s" + +#~ msgid "AT-SPI: expected 2 values in states array; got %d\n" +#~ msgstr "AT-SPI: очікувалось 2 значення в масиві станів; отримали %d\n" + +#~ msgid "Streamable content not implemented" +#~ msgstr "Потоковий вміст не реалізовано" + +#~ msgid "" +#~ "called atspi_event_listener_register_from_callback with a NULL event_type" +#~ msgstr "" +#~ "викликано atspi_event_listener_register_from_callback з NULL event_type" -#: ../atspi/atspi-event-listener.c:777 -#, c-format -msgid "Got invalid signature %s for signal %s from interface %s\n" -msgstr "Отримано неправильний підпис %s для сигналу %s з інтерфейсу %s\n" +#~ msgid "Got invalid signature %s for signal %s from interface %s\n" +#~ msgstr "Отримано неправильний підпис %s для сигналу %s з інтерфейсу %s\n" diff --git a/registryd/meson.build b/registryd/meson.build index c2404d2..739509f 100644 --- a/registryd/meson.build +++ b/registryd/meson.build @@ -41,5 +41,4 @@ libexec_conf.set('libexecdir', atspi_libexecdir) configure_file(input: 'org.a11y.atspi.Registry.service.in', output: 'org.a11y.atspi.Registry.service', configuration: libexec_conf, - install: true, install_dir: join_paths(atspi_datadir, 'dbus-1/accessibility-services')) diff --git a/registryd/ucs2keysym.c b/registryd/ucs2keysym.c index b4967be..29a92f3 100644 --- a/registryd/ucs2keysym.c +++ b/registryd/ucs2keysym.c @@ -34,128 +34,132 @@ #include #include "deviceeventcontroller.h" /* for prototype */ +/* DO NOT UPATE BY HAND! + * This table can be regenerated from Xorg's keysymdef.h with the ucs2keysym.sh + * script. */ struct codepair { unsigned short keysym; unsigned short ucs; } keysymtab[] = { + { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ - { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ - { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ - { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ - { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ - { 0x01a9, 0x0160 }, /* Scaron Å  LATIN CAPITAL LETTER S WITH CARON */ - { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ - { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ - { 0x01af, 0x017b }, /* Zabovedot Å» LATIN CAPITAL LETTER Z WITH DOT ABOVE */ - { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ - { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ - { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ - { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ - { 0x01b9, 0x0161 }, /* scaron Å¡ LATIN SMALL LETTER S WITH CARON */ - { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ - { 0x01bb, 0x0165 }, /* tcaron Å¥ LATIN SMALL LETTER T WITH CARON */ - { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ - { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ - { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ - { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ - { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ - { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ - { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ - { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ - { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ - { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ - { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ - { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ - { 0x01d9, 0x016e }, /* Uring Å® LATIN CAPITAL LETTER U WITH RING ABOVE */ - { 0x01db, 0x0170 }, /* Udoubleacute Å° LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ - { 0x01de, 0x0162 }, /* Tcedilla Å¢ LATIN CAPITAL LETTER T WITH CEDILLA */ - { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ - { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ - { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ - { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ - { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ - { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ - { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ - { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ - { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ - { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ - { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ - { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ - { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ - { 0x01fe, 0x0163 }, /* tcedilla Å£ LATIN SMALL LETTER T WITH CEDILLA */ - { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ - { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ - { 0x02a9, 0x0130 }, /* Iabovedot Ä° LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ - { 0x02ac, 0x0134 }, /* Jcircumflex Ä´ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ - { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ - { 0x02b6, 0x0125 }, /* hcircumflex Ä¥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ - { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ - { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ - { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ - { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ { 0x02d5, 0x0120 }, /* Gabovedot Ä  LATIN CAPITAL LETTER G WITH DOT ABOVE */ - { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ - { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ - { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ - { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ - { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ { 0x02f5, 0x0121 }, /* gabovedot Ä¡ LATIN SMALL LETTER G WITH DOT ABOVE */ - { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ - { 0x02fd, 0x016d }, /* ubreve Å­ LATIN SMALL LETTER U WITH BREVE */ - { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ - { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ - { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ - { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ - { 0x03a6, 0x013b }, /* Lcedilla Ä» LATIN CAPITAL LETTER L WITH CEDILLA */ - { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ { 0x03ab, 0x0122 }, /* Gcedilla Ä¢ LATIN CAPITAL LETTER G WITH CEDILLA */ - { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ - { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x03bb, 0x0123 }, /* gcedilla Ä£ LATIN SMALL LETTER G WITH CEDILLA */ + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + { 0x02b6, 0x0125 }, /* hcircumflex Ä¥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ { 0x03b5, 0x0129 }, /* itilde Ä© LATIN SMALL LETTER I WITH TILDE */ + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + { 0x03ef, 0x012b }, /* imacron Ä« LATIN SMALL LETTER I WITH MACRON */ + { 0x03c7, 0x012e }, /* Iogonek Ä® LATIN CAPITAL LETTER I WITH OGONEK */ + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + { 0x02a9, 0x0130 }, /* Iabovedot Ä° LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + { 0x02ac, 0x0134 }, /* Jcircumflex Ä´ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + { 0x03f3, 0x0137 }, /* kcedilla Ä· LATIN SMALL LETTER K WITH CEDILLA */ + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + { 0x03a6, 0x013b }, /* Lcedilla Ä» LATIN CAPITAL LETTER L WITH CEDILLA */ { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ - { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ - { 0x03bb, 0x0123 }, /* gcedilla Ä£ LATIN SMALL LETTER G WITH CEDILLA */ - { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ - { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ - { 0x03c7, 0x012e }, /* Iogonek Ä® LATIN CAPITAL LETTER I WITH OGONEK */ - { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ - { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ - { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ - { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ - { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ - { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ - { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ - { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ - { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ - { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ - { 0x03ef, 0x012b }, /* imacron Ä« LATIN SMALL LETTER I WITH MACRON */ - { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ - { 0x03f3, 0x0137 }, /* kcedilla Ä· LATIN SMALL LETTER K WITH CEDILLA */ - { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ - { 0x03fd, 0x0169 }, /* utilde Å© LATIN SMALL LETTER U WITH TILDE */ - { 0x03fe, 0x016b }, /* umacron Å« LATIN SMALL LETTER U WITH MACRON */ - { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + { 0x01a9, 0x0160 }, /* Scaron Å  LATIN CAPITAL LETTER S WITH CARON */ + { 0x01b9, 0x0161 }, /* scaron Å¡ LATIN SMALL LETTER S WITH CARON */ + { 0x01de, 0x0162 }, /* Tcedilla Å¢ LATIN CAPITAL LETTER T WITH CEDILLA */ + { 0x01fe, 0x0163 }, /* tcedilla Å£ LATIN SMALL LETTER T WITH CEDILLA */ + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + { 0x01bb, 0x0165 }, /* tcaron Å¥ LATIN SMALL LETTER T WITH CARON */ + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + { 0x03fd, 0x0169 }, /* utilde Å© LATIN SMALL LETTER U WITH TILDE */ + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + { 0x03fe, 0x016b }, /* umacron Å« LATIN SMALL LETTER U WITH MACRON */ + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + { 0x02fd, 0x016d }, /* ubreve Å­ LATIN SMALL LETTER U WITH BREVE */ + { 0x01d9, 0x016e }, /* Uring Å® LATIN CAPITAL LETTER U WITH RING ABOVE */ + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + { 0x01db, 0x0170 }, /* Udoubleacute Å° LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + { 0x01af, 0x017b }, /* Zabovedot Å» LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ @@ -196,7 +200,7 @@ struct codepair { { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ - { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + { 0x07a5, 0x03aa }, /* Greek_IOTAdieresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ @@ -326,6 +330,8 @@ struct codepair { { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + { 0x06bd, 0x0490 }, /* Ukrainian_GHE_WITH_UPTURN Ґ CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ + { 0x06ad, 0x0491 }, /* Ukrainian_ghe_with_upturn ґ CYRILLIC SMALL LETTER GHE WITH UPTURN */ { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ @@ -519,7 +525,6 @@ struct codepair { { 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */ { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ - { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ @@ -544,12 +549,13 @@ struct codepair { { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ { 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */ { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ + { 0x0ad5, 0x2030 }, /* permille ‰ PER MILLE SIGN */ { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ { 0x0afc, 0x2038 }, /* caret ‸ CARET */ { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ - { 0x13a4, 0x20ac }, /* Euro € EURO SIGN */ + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ @@ -574,15 +580,20 @@ struct codepair { { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ { 0x08dd, 0x222a }, /* union ∪ UNION */ { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ @@ -592,44 +603,51 @@ struct codepair { { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ - { 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */ - { 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */ - { 0x0bce, 0x22a4 }, /* uptack ⊤ DOWN TACK */ - { 0x0bc2, 0x22a5 }, /* downtack ⊥ UP TACK */ + { 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */ + { 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */ + { 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */ + { 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */ + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ - { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ - { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET, not U+27E8 per xterm source */ + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET, not U+27E9 per xterm source */ { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ - { 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */ - { 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */ - { 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */ - { 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */ - { 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */ - { 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */ - { 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */ - { 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */ - { 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */ - { 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */ - { 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */ - { 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ - { 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ - { 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ - { 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ + { 0x08ab, 0x239b }, /* topleftparens ⎛ LEFT PARENTHESIS UPPER HOOK */ + { 0x08ac, 0x239d }, /* botleftparens ⎝ LEFT PARENTHESIS LOWER HOOK */ + { 0x08ad, 0x239e }, /* toprightparens ⎞ RIGHT PARENTHESIS UPPER HOOK */ + { 0x08ae, 0x23a0 }, /* botrightparens ⎠ RIGHT PARENTHESIS LOWER HOOK */ + { 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ LEFT SQUARE BRACKET UPPER CORNER */ + { 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ LEFT SQUARE BRACKET LOWER CORNER */ + { 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ RIGHT SQUARE BRACKET UPPER CORNER */ + { 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ RIGHT SQUARE BRACKET LOWER CORNER */ + { 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ LEFT CURLY BRACKET MIDDLE PIECE */ + { 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ RIGHT CURLY BRACKET MIDDLE PIECE */ + { 0x08a1, 0x23b7 }, /* leftradical ⎷ RADICAL SYMBOL BOTTOM */ + { 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 */ + { 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 */ + { 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 */ + { 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 */ + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ - { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */ { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ - { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ { 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */ + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ { 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ @@ -638,8 +656,8 @@ struct codepair { { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ - { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ @@ -657,16 +675,29 @@ struct codepair { { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ + + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ - { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ + { 0x0abc, 0x27e8 }, /* leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET */ + { 0x0abe, 0x27e9 }, /* rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET */ { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ @@ -824,9 +855,7 @@ long ucs2keysym (long ucs) long keysym2ucs(long keysym) { - int min = 0; - int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; - int mid; + int i; /* first check for Latin-1 characters (1:1 mapping) */ if ((keysym >= 0x0020 && keysym <= 0x007e) || @@ -837,16 +866,10 @@ long keysym2ucs(long keysym) if ((keysym & 0xff000000) == 0x01000000) return keysym & 0x00ffffff; - /* binary search in table */ - while (max >= min) { - mid = (min + max) / 2; - if (keysymtab[mid].keysym < keysym) - min = mid + 1; - else if (keysymtab[mid].keysym > keysym) - max = mid - 1; - else { + for (i = 0; i < sizeof(keysymtab) / sizeof(keysymtab[0]); i++) { + if (keysymtab[i].keysym == keysym) { /* found it */ - return keysymtab[mid].ucs; + return keysymtab[i].ucs; } } diff --git a/registryd/ucs2keysym.sh b/registryd/ucs2keysym.sh new file mode 100755 index 0000000..ff37f53 --- /dev/null +++ b/registryd/ucs2keysym.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +if [ "$#" = 0 ] +then + echo "Usage: $0 /path/to/keysymdef.h" + exit 1 +fi + +# We are only interested in +# - keysyms which have well-defined unicode equivalent +# - and are not just trivial unicode keysyms +# - non-latin1 keysyms +# - not the lamda aliases +# and we tinker with the alias parentheses to make sorting easier + +grep '^#define' "$1" | \ + grep -i "U+" | \ + grep -vi "0x100[0-9a-f][0-9a-f][0-9a-f][0-9a-f]" | \ + grep -vi " 0x00[0-9a-f][0-9a-f] " | \ + grep -vi "_lamda " | \ + sed -e 's/\/\*(/& /' | \ + sed -e 's/)\*\// &/' | \ + sort -k 5 | \ + perl -CS -e ' +my $last = 0; +while (<>) { + chomp; + if ( /^\#define XK_([a-zA-Z_0-9]+)(\s*) 0x([0-9a-f]+)\s*\/\*(\(?) U\+([0-9A-F]{4,6}) (.*) \)?\*\/\s*$/ ) { + my ( $xk, $space, $keysym, $paren, $unicode, $unistr ) = ( $1, $2, $3, $4, $5, $6); + $unicode = hex("0x".$unicode); + + print "\n" if (int($unicode / 256) != int($last / 256)); + $last = $unicode; + + printf " { 0x$keysym, 0x%04x }, /* $space$xk %lc $unistr */\n", $unicode, $unicode; + } +} + ' diff --git a/test/memory.c b/test/memory.c index df5e0a1..2f53dd7 100644 --- a/test/memory.c +++ b/test/memory.c @@ -1,4 +1,5 @@ #include "atspi/atspi.h" +#include #include #include #include @@ -15,19 +16,24 @@ basic (AtspiAccessible *obj) AtspiAccessible *accessible; GError *error = NULL; + printf ("getting name\n"); str = atspi_accessible_get_name (obj, &error); if (str) g_free (str); + printf ("ok, getting parent\n"); accessible = atspi_accessible_get_parent (obj, NULL); if (accessible) g_object_unref (accessible); + printf ("ok, getting children\n"); count = atspi_accessible_get_child_count (obj, &error); for (i = 0; i < count; i++) { accessible = atspi_accessible_get_child_at_index (obj, i, &error); + printf ("ok %d\n", i); if (accessible) g_object_unref (accessible); } + printf ("ok\n"); } static gboolean @@ -78,7 +84,7 @@ main() atspi_event_listener_register (listener, "object:children-changed", NULL); child_pid = fork (); if (!child_pid) - execlp ("gedit", "gedit", NULL); + execlp ("test/test-application", "test/test-application", NULL); atspi_event_main (); return 0; } diff --git a/test/meson.build b/test/meson.build index 1fb35a8..cd3db66 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,4 +1,13 @@ -test('memory', - executable('memory', 'memory.c', - include_directories: root_inc, - dependencies: [ atspi_dep ])) +testapp = executable('test-application', + 'test-application.c', + include_directories: root_inc, + dependencies: [ atspi_dep ], + ) + +memory = executable('memory', + 'memory.c', + include_directories: root_inc, + dependencies: [ atspi_dep ], + ) + +test('memory', memory, depends: testapp) diff --git a/test/test-application.c b/test/test-application.c new file mode 100644 index 0000000..621d1de --- /dev/null +++ b/test/test-application.c @@ -0,0 +1,105 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; https://wiki.gnome.org/Accessibility) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* + * Simple test application for AT-SPI. + * + * The only thing this application does, is registering itself to the AT-SPI + * registry and then waiting to get killed by some external force. + */ + +#include +#include +#include +#include + +static GMainLoop *mainloop; + +int +register_app () +{ + DBusConnection *connection = NULL; + DBusMessage *message; + DBusMessageIter iter; + DBusMessageIter subiter; + DBusError error; + DBusMessage *reply; + const gchar *name; + gchar *path; + + + /* Set up D-Bus connection and register bus name */ + dbus_error_init (&error); + connection = atspi_get_a11y_bus (); + if (!connection) + { + printf("Couldn't get a11y bus!\n"); + return -1; + } + + /* Register this app by sending a signal out to AT-SPI registry daemon */ + message = dbus_message_new_method_call (ATSPI_DBUS_NAME_REGISTRY, + ATSPI_DBUS_PATH_ROOT, + ATSPI_DBUS_INTERFACE_SOCKET, + "Embed"); + + dbus_message_iter_init_append (message, &iter); + + name = dbus_bus_get_unique_name (connection); + path = g_strdup (ATSPI_DBUS_PATH_NULL); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL, + &subiter); + dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, &name); + dbus_message_iter_append_basic (&subiter, DBUS_TYPE_OBJECT_PATH, &path); + dbus_message_iter_close_container (&iter, &subiter); + + g_free (path); + + reply = dbus_connection_send_with_reply_and_block(connection, message, -1, &error); + if (!reply) + { + printf("Did not get a reply from the registry.\n"); + dbus_message_unref (message); + dbus_error_free (&error); + return -1; + } + + dbus_message_unref (message); + dbus_message_unref (reply); + dbus_error_free (&error); + return 0; +} + +int main (int argc, char *argv[]) +{ + int ret = register_app (); + if (ret) { + printf("Failed to send dbus signals. Aborting.\n"); + return ret; + } + + // This keeps the test-application runnig indefinitely, i.e. + // until killed by an external signal. + mainloop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (mainloop); + + return 0; +} diff --git a/xml/Accessible.xml b/xml/Accessible.xml index 7015466..b081bfd 100644 --- a/xml/Accessible.xml +++ b/xml/Accessible.xml @@ -7,7 +7,7 @@ - + @@ -19,12 +19,12 @@ - + - + @@ -33,7 +33,7 @@ - + @@ -50,17 +50,21 @@ - + - + - + + + + + diff --git a/xml/Action.xml b/xml/Action.xml index 0f5aa85..1626700 100644 --- a/xml/Action.xml +++ b/xml/Action.xml @@ -26,7 +26,7 @@ - + diff --git a/xml/Application.xml b/xml/Application.xml index 04a2e70..2191f08 100644 --- a/xml/Application.xml +++ b/xml/Application.xml @@ -7,7 +7,7 @@ - + diff --git a/xml/Cache.xml b/xml/Cache.xml index e693b54..ce06ba4 100644 --- a/xml/Cache.xml +++ b/xml/Cache.xml @@ -3,18 +3,18 @@ - - + + - - + + - - + + diff --git a/xml/Collection.xml b/xml/Collection.xml index 7b39776..a6dff74 100644 --- a/xml/Collection.xml +++ b/xml/Collection.xml @@ -4,44 +4,44 @@ - + - + - + - + - + - + - + - + - + diff --git a/xml/Component.xml b/xml/Component.xml index c1258d2..94056ff 100644 --- a/xml/Component.xml +++ b/xml/Component.xml @@ -14,13 +14,13 @@ - + - + diff --git a/xml/DeviceEventController.xml b/xml/DeviceEventController.xml index 0af9aac..460e79a 100644 --- a/xml/DeviceEventController.xml +++ b/xml/DeviceEventController.xml @@ -4,24 +4,20 @@ - - - + + - - - - - - + + + + - - - + + @@ -52,12 +48,12 @@ - + - + diff --git a/xml/DeviceEventListener.xml b/xml/DeviceEventListener.xml index a6dd3b6..2c72973 100644 --- a/xml/DeviceEventListener.xml +++ b/xml/DeviceEventListener.xml @@ -4,7 +4,7 @@ - + diff --git a/xml/Document.xml b/xml/Document.xml index d12a306..a82eb98 100644 --- a/xml/Document.xml +++ b/xml/Document.xml @@ -17,7 +17,7 @@ - + diff --git a/xml/Event.xml b/xml/Event.xml index fac67de..3614358 100644 --- a/xml/Event.xml +++ b/xml/Event.xml @@ -3,190 +3,190 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/xml/Hyperlink.xml b/xml/Hyperlink.xml index 75f8099..80d5777 100644 --- a/xml/Hyperlink.xml +++ b/xml/Hyperlink.xml @@ -11,7 +11,7 @@ - + diff --git a/xml/Hypertext.xml b/xml/Hypertext.xml index 18a3b34..79b5277 100644 --- a/xml/Hypertext.xml +++ b/xml/Hypertext.xml @@ -9,7 +9,7 @@ - + diff --git a/xml/Image.xml b/xml/Image.xml index 43536ee..1dd72f1 100644 --- a/xml/Image.xml +++ b/xml/Image.xml @@ -9,7 +9,7 @@ - + diff --git a/xml/Registry.xml b/xml/Registry.xml index a3ab93c..7603328 100644 --- a/xml/Registry.xml +++ b/xml/Registry.xml @@ -13,8 +13,8 @@ - - + + diff --git a/xml/Selection.xml b/xml/Selection.xml index 2e19187..7b0ad21 100644 --- a/xml/Selection.xml +++ b/xml/Selection.xml @@ -7,7 +7,7 @@ - + diff --git a/xml/Socket.xml b/xml/Socket.xml index 5f9367e..f9ac76d 100644 --- a/xml/Socket.xml +++ b/xml/Socket.xml @@ -3,25 +3,21 @@ - - - - - - + + + + - - - + + - - - - + + + diff --git a/xml/Table.xml b/xml/Table.xml index 181acaa..3b35989 100644 --- a/xml/Table.xml +++ b/xml/Table.xml @@ -7,11 +7,11 @@ - + - + @@ -22,7 +22,7 @@ - + @@ -66,23 +66,23 @@ - + - + - + - + diff --git a/xml/TableCell.xml b/xml/TableCell.xml index c60a074..dbdbe8c 100644 --- a/xml/TableCell.xml +++ b/xml/TableCell.xml @@ -4,11 +4,15 @@ - + + + - + + + diff --git a/xml/Text.xml b/xml/Text.xml index 313131e..fe9f44b 100644 --- a/xml/Text.xml +++ b/xml/Text.xml @@ -65,12 +65,12 @@ - + - + @@ -136,7 +136,7 @@ - + @@ -145,11 +145,12 @@ - + + -- 2.7.4 From a0687b8680a7bd816094590f9fedf34dff2d3d3d Mon Sep 17 00:00:00 2001 From: Bartlomiej Grzelewski Date: Thu, 4 Mar 2021 12:26:54 +0100 Subject: [PATCH 04/16] Version 2.39.90.1 Change-Id: I862adfd66284175a3696f90a7c669845735dd238 --- packaging/at-spi2-core.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/at-spi2-core.spec b/packaging/at-spi2-core.spec index bc859b6..939eb56 100644 --- a/packaging/at-spi2-core.spec +++ b/packaging/at-spi2-core.spec @@ -1,8 +1,8 @@ %bcond_with x Name: at-spi2-core -Version: 2.34.0 -Release: 0 +Version: 2.39.90 +Release: 1 Summary: Assistive Technology Service Provider Interface - D-Bus based implementation License: LGPL-2.1+ Group: System/Libraries -- 2.7.4 From 4043c5aff8bafc955b000aaaaa327a8634ff68bf Mon Sep 17 00:00:00 2001 From: Mike Gorse Date: Mon, 22 Feb 2021 15:53:35 -0600 Subject: [PATCH 05/16] atspi_accessible_get_(name|description): fix memory leak This is likely what the backed-out part of !53 was trying to do. Change-Id: Id6f8bc3eb34caaa8df8a8734a60ce24d7f64aa9f --- atspi/atspi-accessible.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index 958e578..eee40e9 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -340,8 +340,12 @@ gchar * atspi_accessible_get_name (AtspiAccessible *obj, GError **error) { g_return_val_if_fail (obj != NULL, g_strdup ("")); + if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_NAME)) { +if (obj->name) printf("free\n"); + g_free (obj->name); + obj->name = NULL; if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error, "s", &obj->name)) return g_strdup (""); @@ -886,6 +890,8 @@ atspi_accessible_get_description (AtspiAccessible *obj, GError **error) if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_DESCRIPTION)) { + g_free (obj->description); + obj->description = NULL; if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Description", error, "s", &obj->description)) -- 2.7.4 From 679efa8e2bd9455fb6242c4d2dabfdca2a0612ec Mon Sep 17 00:00:00 2001 From: Mike Gorse Date: Mon, 22 Feb 2021 15:55:11 -0600 Subject: [PATCH 06/16] Remove debug print Change-Id: I1f71997aaf68f2eab803827971ffc4f2d7332657 --- atspi/atspi-accessible.c | 1 - 1 file changed, 1 deletion(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index eee40e9..dddb8fe 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -343,7 +343,6 @@ atspi_accessible_get_name (AtspiAccessible *obj, GError **error) if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_NAME)) { -if (obj->name) printf("free\n"); g_free (obj->name); obj->name = NULL; if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error, -- 2.7.4 From ca48dcb6f2ab0aa08bb72711de6da044cd46d8fb Mon Sep 17 00:00:00 2001 From: Mike Gorse Date: Tue, 23 Feb 2021 10:12:15 -0600 Subject: [PATCH 07/16] AtspiDeviceListenerCB: remove const from event prototype The parameter is marked with (transfer full), and the code expects the caller to free the event, so adjust the prototype to clarify the expected behavior. Also fix a related memory leak in atspi-device-legacy.c. Fixes #31 Change-Id: I268c80df3f251ca99456827a878e78f191a18736 --- atspi/atspi-device-legacy.c | 3 ++- atspi/atspi-device-listener.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/atspi/atspi-device-legacy.c b/atspi/atspi-device-legacy.c index 6950bc3..6c19b79 100644 --- a/atspi/atspi-device-legacy.c +++ b/atspi/atspi-device-legacy.c @@ -86,7 +86,7 @@ set_virtual_modifier (AtspiDeviceLegacy *legacy_device, gint keycode, gboolean e gboolean -key_cb (const AtspiDeviceEvent *event, void *user_data) +key_cb (AtspiDeviceEvent *event, void *user_data) { AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (user_data); AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); @@ -100,6 +100,7 @@ key_cb (const AtspiDeviceEvent *event, void *user_data) event->modifiers | priv->virtual_mods_enabled, event->event_string); + g_boxed_free (ATSPI_TYPE_DEVICE_EVENT, event); return ret; } diff --git a/atspi/atspi-device-listener.h b/atspi/atspi-device-listener.h index d91a203..718a415 100644 --- a/atspi/atspi-device-listener.h +++ b/atspi/atspi-device-listener.h @@ -45,7 +45,7 @@ GType atspi_device_event_get_type (void); * Returns: #TRUE if the client wishes to consume/preempt the event, preventing it from being * relayed to the currently focussed application, #FALSE if the event delivery should proceed as normal. **/ -typedef gboolean (*AtspiDeviceListenerCB) (const AtspiDeviceEvent *stroke, +typedef gboolean (*AtspiDeviceListenerCB) (AtspiDeviceEvent *stroke, void *user_data); /** -- 2.7.4 From 636fb0bcf337fbf3c994f73d510d21e1c0f8b9b0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Grzelewski Date: Mon, 8 Mar 2021 10:20:39 +0100 Subject: [PATCH 08/16] Removed unused unref from _atspi_dbus_get_property Newest at-spi2-core does not contain path that is passing pointer to accessiblity object as "data" paramter. There is no point in releasing data under this pointer. Change-Id: I729db3a0aaef274657121084affb33a69fd8c02d --- atspi/atspi-misc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index f60d834..be8030e 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -1336,7 +1336,6 @@ _atspi_dbus_get_property (gpointer obj, const char *interface, const char *name, } if (!strcmp (type, "(so)")) { - g_object_unref(*(AtspiAccessible**)data); *((AtspiAccessible **)data) = _atspi_dbus_return_accessible_from_iter (&iter_variant); } else -- 2.7.4 From e25f9204dbdce46e27c11f1a25466dde883bc3fc Mon Sep 17 00:00:00 2001 From: Lukasz Oleksak Date: Mon, 12 Apr 2021 10:37:07 +0200 Subject: [PATCH 09/16] Removing formatted printing of accessible object path by at_spi2_tool Format of accessible object path (handle) may vary in different toolkits so hardcoded formatting "%llu" cannot be used. Additionaly, the information is redundant as unformatted (raw) object path is already printed as the last section (after last ":") of object unique id. Change-Id: Idedbea550e759335a10141adf4873a37737dde12 --- test/at_spi2_tool.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index e1e9fc8..e70cd82 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -309,10 +309,6 @@ static char *_get_info(AtspiAccessible *node, int length_limit, bool *attributes char *node_name = atspi_accessible_get_name(node, NULL); char *node_role_name = atspi_accessible_get_role_name(node, NULL); char *unique_id = atspi_accessible_get_unique_id(node, NULL); - char *path = atspi_accessible_get_path(node, NULL); - unsigned long long eo_ptr = 0; - sscanf(path, "%llu", &eo_ptr); - char *toolkit = atspi_accessible_get_toolkit_name(node, NULL); char *attributes = _get_attributes(node, length_limit, attributes_are_too_long); @@ -332,8 +328,8 @@ static char *_get_info(AtspiAccessible *node, int length_limit, bool *attributes } char result[SAFE_BUFFER_SIZE]; - int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s(%p)],[%s],[toolkit=%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s]]", - unique_id, (uintptr_t)eo_ptr, + int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[toolkit=%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s]]", + unique_id, node_role_name, toolkit, attributes, @@ -357,7 +353,6 @@ static char *_get_info(AtspiAccessible *node, int length_limit, bool *attributes free(node_name); free(node_role_name); free(unique_id); - free(path); free(toolkit); free(attributes); if (box_size) { -- 2.7.4 From 9a01117b5d428dbe9a09b85ed8d29263ab39daf1 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Fri, 6 Aug 2021 19:29:28 +0900 Subject: [PATCH 10/16] test: remove warning message This change is removing following message. GLib-CRITICAL: g_atomic_ref_count_dec: assertion 'g_atomic_int_get (arc) > 0' failed It seems that the variant is removed in g_dbus_proxy_call_sync. Change-Id: Ibf1c5990f32a7290aa40fbbdc413c29bb125f11e --- test/at_spi2_tool.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index e70cd82..0eaa284 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -741,7 +741,6 @@ static void _at_spi_client_enable(gboolean enabled) { static GDBusProxy *proxy = NULL; //we keep proxy (dbus connection) until program exits GVariant *result; - GVariant *enabled_variant; GError *error = NULL; GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_NONE; @@ -762,16 +761,13 @@ static void _at_spi_client_enable(gboolean enabled) } } - enabled_variant = g_variant_new_boolean(enabled); result = g_dbus_proxy_call_sync(proxy, "Set", - g_variant_new ("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant), + g_variant_new ("(ssv)", "org.a11y.Status", "IsEnabled", g_variant_new_boolean(enabled)), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - if (enabled_variant) - g_variant_unref(enabled_variant); if (result) g_variant_unref(result); -- 2.7.4 From ca3ab5aea45e50202be4547f090d737e72fe6f6b Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 1 Dec 2021 17:36:19 +0900 Subject: [PATCH 11/16] [Tizen] Provide GetActiveWindow interface If there are two AT clients, AT server does not send 'activate' signal for the second AT client. Because AT server send the 'activate' signal when the 'IsEnabled' status was set to be TRUE. AT client is able to search the 'activate' window using the desktop and its children - applications, but some times it is very slow. Probably.. It is caused by 'throttle' feature of EFL application. We need to keep the 'activate' window information for the second client. The at-spi2-registryd will keep the 'activate' window information. The AT client gets the information using atspi_get_activate_window. Change-Id: Ia5f22465b10a46411768866f245aa8309b2cc013 --- atspi/atspi-registry.c | 47 ++++++++++++++++++ atspi/atspi-registry.h | 4 ++ registryd/registry-main.c | 13 +++++ registryd/registry.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ registryd/registry.h | 14 ++++++ 5 files changed, 202 insertions(+) diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c index 2bb4d08..e9a47e5 100644 --- a/atspi/atspi-registry.c +++ b/atspi/atspi-registry.c @@ -98,6 +98,53 @@ atspi_get_desktop_list () return array; } + +//TIZEN_ONLY(20211206) Provide GetActiveWindow +/** + * atspi_get_active_window: + * + * Gets recently activated window. + * NOTE: the Tizen only interface for multiple AT-clients + * + * Returns: (transfer full): a pointer to active window's + * #AtspiAccessible representation. + **/ +AtspiAccessible* +atspi_get_active_window () +{ + DBusMessage *message, *reply; + DBusMessageIter iter; + AtspiAccessible* active_window; + + message = dbus_message_new_method_call (ATSPI_DBUS_NAME_REGISTRY, + ATSPI_DBUS_PATH_ROOT, + ATSPI_DBUS_INTERFACE_SOCKET, + "GetActiveWindow"); + if (!message) + return NULL; + + reply = _atspi_dbus_send_with_reply_and_block (message, NULL); + if (!reply) + return NULL; + + if (strcmp (dbus_message_get_signature (reply), "(so)") != 0) + { + dbus_message_unref (reply); + return NULL; + } + + dbus_message_iter_init (reply, &iter); + active_window = _atspi_dbus_return_accessible_from_iter (&iter); + + dbus_message_unref (reply); + + if (!active_window) + return NULL; + + return g_object_ref (active_window); +} +// + static gboolean notify_keystroke_listener (DeviceListenerEntry *e) { diff --git a/atspi/atspi-registry.h b/atspi/atspi-registry.h index 43150c2..b266c7b 100644 --- a/atspi/atspi-registry.h +++ b/atspi/atspi-registry.h @@ -39,6 +39,10 @@ AtspiAccessible* atspi_get_desktop (gint i); GArray *atspi_get_desktop_list (); +//TIZEN_ONLY(20211206) Provide GetActiveWindow +AtspiAccessible* atspi_get_active_window (); +// + gboolean atspi_register_keystroke_listener (AtspiDeviceListener *listener, GArray *key_set, diff --git a/registryd/registry-main.c b/registryd/registry-main.c index be01d2c..c137182 100644 --- a/registryd/registry-main.c +++ b/registryd/registry-main.c @@ -259,6 +259,19 @@ main (int argc, char **argv) g_main_loop_run (mainloop); + //TIZEN_ONLY(20211206) Provide GetActiveWindow + if (registry->active_window_name) + { + g_free (registry->active_window_name); + registry->active_window_name = NULL; + } + if (registry->active_window_path) + { + g_free (registry->active_window_path); + registry->active_window_path = NULL; + } + // + dbus_connection_close (bus); dbus_connection_unref (bus); g_object_unref (dec); diff --git a/registryd/registry.c b/registryd/registry.c index aa867ca..fa2d3a5 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -303,6 +303,63 @@ handle_disconnection (DBusConnection *bus, DBusMessage *message, void *user_data } } +//TIZEN_ONLY(20211206) Provide GetActiveWindow +static void +handle_activate_window (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + SpiRegistry *reg = SPI_REGISTRY (user_data); + + const char *sender = dbus_message_get_sender (message); + const char *path = dbus_message_get_path (message); + + if (!sender || !path) + return; + + char *detail = NULL; + dbus_int32_t detail1; + DBusMessageIter iter; + dbus_message_iter_init (message, &iter); + dbus_message_iter_get_basic (&iter, &detail); + dbus_message_iter_next (&iter); + dbus_message_iter_get_basic (&iter, &detail1); + + if (detail1 & ACCESSIBLE_WINDOW_ACTIVATE_INFO_KEYBOARD) + return; + + if (reg->active_window_name) + g_free (reg->active_window_name); + if (reg->active_window_path) + g_free (reg->active_window_path); + + reg->active_window_name = g_strdup(sender); + reg->active_window_path = g_strdup(path); +} + +static void +handle_deactivate_window (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + SpiRegistry *reg = SPI_REGISTRY (user_data); + + if (!reg->active_window_name || !reg->active_window_path) + return; + + const char *sender = dbus_message_get_sender (message); + const char *path = dbus_message_get_path (message); + + if (!sender || !path) + return; + + if (!g_strcmp0(reg->active_window_name, sender) && + !g_strcmp0(reg->active_window_path, path)) + { + g_free (reg->active_window_name); + g_free (reg->active_window_path); + reg->active_window_name = NULL; + reg->active_window_path = NULL; + } +} +// + /* * Converts names of the form "active-descendant-changed" to *" ActiveDescendantChanged" @@ -352,6 +409,15 @@ 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); + //TIZEN_ONLY(20211206) Provide GetActiveWindow + else if (!g_strcmp0(iface, "org.a11y.atspi.Event.Window")) + { + if (!g_strcmp0(member, "Activate")) + handle_activate_window (bus, message, user_data); + else if (!g_strcmp0(member, "Deactivate")) + handle_deactivate_window (bus, message, user_data); + } + // else res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -831,6 +897,27 @@ impl_GetInterfaces (DBusConnection * bus, return reply; } +//TIZEN_ONLY(20211206) Provide GetActiveWindow +static DBusMessage * +impl_GetActiveWindow (DBusConnection * bus, + DBusMessage * message, void *user_data) +{ + SpiRegistry *reg = SPI_REGISTRY (user_data); + DBusMessage *reply; + DBusMessageIter iter; + + reply = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply, &iter); + + if (!reg->active_window_name || !reg->active_window_path) + append_reference (&iter, SPI_DBUS_NAME_REGISTRY, SPI_DBUS_PATH_NULL); + else + append_reference (&iter, reg->active_window_name, reg->active_window_path); + + return reply; +} +// + static DBusMessage * impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data) { @@ -957,6 +1044,24 @@ impl_get_registered_events (DBusConnection *bus, DBusMessage *message, void *use dbus_message_iter_init_append (reply, &iter); dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ss)", &iter_array); + + //TIZEN_ONLY(20211206) Provide GetActiveWindow + //we need this part because EFL sends only registered event + const char *registry_bus_name = SPI_DBUS_NAME_REGISTRY; + const char *window_activate_event = "Window:Activate:"; + const char *window_deactivate_event = "Window:Deactivate:"; + + dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, ®istry_bus_name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &window_activate_event); + dbus_message_iter_close_container (&iter_array, &iter_struct); + + dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, ®istry_bus_name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &window_deactivate_event); + dbus_message_iter_close_container (&iter_array, &iter_struct); + // + for (list = registry->events; list; list = list->next) { gchar *str; @@ -1289,6 +1394,10 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) reply = impl_Embed (bus, message, user_data); else if (!strcmp (member, "Unembed")) reply = impl_Unembed (bus, message, user_data); + //TIZEN_ONLY(20211206) Provide GetActiveWindow + else if (!strcmp (member, "GetActiveWindow")) + reply = impl_GetActiveWindow (bus, message, user_data); + // else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1446,6 +1555,13 @@ static DBusObjectPathVTable cache_vtable = static gchar *app_sig_match_name_owner = "type='signal', interface='org.freedesktop.DBus', member='NameOwnerChanged'"; +//TIZEN_ONLY(20211206) Provide GetActivateWindow +static gchar *app_sig_match_window_activate = + "type='signal',interface='org.a11y.atspi.Event.Window',member='Activate'"; +static gchar *app_sig_match_window_deactivate = + "type='signal',interface='org.a11y.atspi.Event.Window',member='Deactivate'"; +// + SpiRegistry * spi_registry_new (DBusConnection *bus) { @@ -1456,6 +1572,13 @@ spi_registry_new (DBusConnection *bus) dbus_bus_add_match (bus, app_sig_match_name_owner, NULL); dbus_connection_add_filter (bus, signal_filter, reg, NULL); + //TIZEN_ONLY(20211206) Provide GetActiveWindow + reg->active_window_name = NULL; + reg->active_window_path = NULL; + dbus_bus_add_match (reg->bus, app_sig_match_window_activate, NULL); + dbus_bus_add_match (reg->bus, app_sig_match_window_deactivate, NULL); + // + dbus_connection_register_object_path (bus, SPI_DBUS_PATH_ROOT, &root_vtable, reg); dbus_connection_register_object_path (bus, SPI_DBUS_PATH_CACHE, &cache_vtable, reg); @@ -1468,5 +1591,6 @@ spi_registry_new (DBusConnection *bus) return reg; } +// /*END------------------------------------------------------------------------*/ diff --git a/registryd/registry.h b/registryd/registry.h index 19b1a8f..ee82ef5 100644 --- a/registryd/registry.h +++ b/registryd/registry.h @@ -50,8 +50,22 @@ struct _SpiRegistry { DBusConnection *bus; GList *events; + + //TIZEN_ONLY(20211206) Provide GetActiveWindow + gchar *active_window_name; + gchar *active_window_path; + // }; +//TIZEN_ONLY(20211206) Provide GetActiveWindow +typedef enum { + ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED = 0, + ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED_WITHOUT_WINDOW = 1 << 0, + ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_DISABLED = 1 << 1, + ACCESSIBLE_WINDOW_ACTIVATE_INFO_KEYBOARD = 1 << 2, +} WindowActivateInfoType; +// + struct _SpiRegistryClass { GObjectClass parent_class; }; -- 2.7.4 From dcf4342815f8921cdf37db7d7e6c4b5fd05b74ea Mon Sep 17 00:00:00 2001 From: =?utf8?q?Artur=20=C5=9Awigo=C5=84?= Date: Tue, 1 Feb 2022 11:01:46 +0100 Subject: [PATCH 12/16] 2.42.0 Change-Id: Ie3cf2615d77cd923b22e9f6c9a7233fe8682f95a --- NEWS | 29 ++++++++++++++++++ README | 24 ++++++--------- atspi/atspi-accessible.c | 5 +++ atspi/atspi-device-legacy.c | 19 ++++++++++-- atspi/atspi-device-listener.h | 2 +- atspi/atspi-device-x11.c | 57 ++++++++++++++++++++++++++++++++--- atspi/atspi-device.c | 16 ++++++++-- atspi/atspi-event-listener.c | 5 ++- bus/00-at-spi | 10 ++++++ bus/accessibility.conf.in | 2 +- bus/meson.build | 14 +++++++++ meson.build | 2 +- po/LINGUAS | 1 + po/ab.po | 28 +++++++++++++++++ po/be.po | 32 +++++++++++--------- po/gl.po | 8 ++--- registryd/de-marshaller.c | 6 +++- registryd/deviceeventcontroller-x11.c | 2 +- registryd/deviceeventcontroller.c | 2 +- xml/Collection.xml | 6 ++-- xml/Component.xml | 2 ++ xml/Document.xml | 2 +- xml/Text.xml | 2 ++ 23 files changed, 223 insertions(+), 53 deletions(-) create mode 100755 bus/00-at-spi create mode 100644 po/ab.po diff --git a/NEWS b/NEWS index d964ce2..6738a3d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,32 @@ +What's new in at-spi2-core 2.42.0: + +* Set X root property when Xwayland starts on demand. + +* Several dbus introspection fixes. + +What's new in at-spi2-core 2.40.3: + +* Use abstract sockets if libdbus is older than 1.12.0 (#37). + +What's new in at-spi2-core 2.40.2: + +* README: Remove outdated links. + +* Key grab fixes for the new API. + +* registryd: Add a missing call to va_end. + +What's new in at-spi2-core 2.40.1: + +* Fix double free when removing event listeners (#35). + +* Fix numlock detection. + +What's new in at-spi2-core 2.39.91: +* Fix a couple of memory leaks. + +* Remove const from AtspiDeviceListenerCB prototype (#31). + What's new in at-spi2-core 2.39.90.1: * Fix a crash introduced in 2.39.90, along with a few warnings (#30). diff --git a/README b/README index e41a5c6..b377fca 100644 --- a/README +++ b/README @@ -5,24 +5,22 @@ This version of at-spi is a major break from version 1.x. It has been completely rewritten to use D-Bus rather than ORBIT / CORBA for its transport protocol. -A page including instructions for testing, project status and -TODO items is kept up to date at: +An outdated page including instructions for testing, project status and +TODO items is at: - http://www.linuxfoundation.org/en/AT-SPI_on_D-Bus + https://wiki.linuxfoundation.org/accessibility/atk/at-spi/at-spi_on_d-bus The mailing list used for general questions is: - accessibility-atspi@lists.linux-foundation.org + https://lists.linuxfoundation.org/mailman/listinfo/accessibility-atspi -For bug reports, feature requests, patches or enhancements please use -the AT-SPI project on bugzilla.gnome.org. Use the at-spi2-core component for -bugs specific to this module. +For bug reports, feature requests, patches or enhancements please use: - http://bugzilla.gnome.org + https://gitlab.gnome.org/GNOME/at-spi2-core/ A git repository with the latest development code is available at: - git://git.gnome.org/at-spi2-core + https://gitlab.gnome.org/GNOME/at-spi2-core/ More information ---------------- @@ -32,15 +30,13 @@ the results of which are available on the GNOME wiki. Keep in mind that the D-Bus AT-SPI design documents on this page have not been kept up to date. - http://live.gnome.org/GAP/AtSpiDbusInvestigation/ + https://wiki.gnome.org/Accessibility/Documentation/GNOME2/ATSPI2-Investigation Other sources of relevant information about AT-SPI and Accessibility include: - http://live.gnome.org/Accessibility - http://www.sun.com/software/star/gnome/accessibility/architecture.xml - http://accessibility.kde.org/developer/atk.php - http://www.gnome.org/~billh/at-spi-idl/html/ + https://wiki.gnome.org/Accessibility + https://community.kde.org/Accessibility Contents of this package diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index b078688..26cf0ba 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -340,8 +340,11 @@ gchar * atspi_accessible_get_name (AtspiAccessible *obj, GError **error) { g_return_val_if_fail (obj != NULL, g_strdup ("")); + if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_NAME)) { + g_free (obj->name); + obj->name = NULL; if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Name", error, "s", &obj->name)) return g_strdup (""); @@ -366,6 +369,8 @@ atspi_accessible_get_description (AtspiAccessible *obj, GError **error) if (!_atspi_accessible_test_cache (obj, ATSPI_CACHE_DESCRIPTION)) { + g_free (obj->description); + obj->description = NULL; if (!_atspi_dbus_get_property (obj, atspi_interface_accessible, "Description", error, "s", &obj->description)) diff --git a/atspi/atspi-device-legacy.c b/atspi/atspi-device-legacy.c index 6950bc3..eb67768 100644 --- a/atspi/atspi-device-legacy.c +++ b/atspi/atspi-device-legacy.c @@ -47,6 +47,7 @@ struct _AtspiDeviceLegacyPrivate GSList *modifiers; guint virtual_mods_enabled; gboolean keyboard_grabbed; + unsigned int numlock_physical_mask; }; GObjectClass *device_legacy_parent_class; @@ -86,20 +87,27 @@ set_virtual_modifier (AtspiDeviceLegacy *legacy_device, gint keycode, gboolean e gboolean -key_cb (const AtspiDeviceEvent *event, void *user_data) +key_cb (AtspiDeviceEvent *event, void *user_data) { AtspiDeviceLegacy *legacy_device = ATSPI_DEVICE_LEGACY (user_data); AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); gboolean ret = priv->keyboard_grabbed; - + guint modifiers; + set_virtual_modifier (legacy_device, event->hw_code, event->type == (AtspiEventType)ATSPI_KEY_PRESS); + + modifiers = event->modifiers | priv->virtual_mods_enabled; + if (modifiers & (1 << ATSPI_MODIFIER_NUMLOCK)) + modifiers &= ~priv->numlock_physical_mask; + ret |= atspi_device_notify_key (ATSPI_DEVICE (legacy_device), event->type == (AtspiEventType)ATSPI_KEY_PRESS, event->hw_code, event->id, - event->modifiers | priv->virtual_mods_enabled, + modifiers, event->event_string); + g_boxed_free (ATSPI_TYPE_DEVICE_EVENT, event); return ret; } @@ -125,6 +133,9 @@ check_virtual_modifier (AtspiDeviceLegacy *legacy_device, guint modifier) AtspiDeviceLegacyPrivate *priv = atspi_device_legacy_get_instance_private (legacy_device); GSList *l; + if (modifier == (1 << ATSPI_MODIFIER_NUMLOCK)) + return TRUE; + for (l = priv->modifiers; l; l = l->next) { AtspiLegacyKeyModifier *entry = l->data; @@ -268,6 +279,8 @@ atspi_device_legacy_init (AtspiDeviceLegacy *device) priv->display=XOpenDisplay(""); if (priv->display) priv->window = DefaultRootWindow(priv->display); + priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display, + XK_Num_Lock); #endif } diff --git a/atspi/atspi-device-listener.h b/atspi/atspi-device-listener.h index d91a203..718a415 100644 --- a/atspi/atspi-device-listener.h +++ b/atspi/atspi-device-listener.h @@ -45,7 +45,7 @@ GType atspi_device_event_get_type (void); * Returns: #TRUE if the client wishes to consume/preempt the event, preventing it from being * relayed to the currently focussed application, #FALSE if the event delivery should proceed as normal. **/ -typedef gboolean (*AtspiDeviceListenerCB) (const AtspiDeviceEvent *stroke, +typedef gboolean (*AtspiDeviceListenerCB) (AtspiDeviceEvent *stroke, void *user_data); /** diff --git a/atspi/atspi-device-x11.c b/atspi/atspi-device-x11.c index e8f2199..4f88e60 100644 --- a/atspi/atspi-device-x11.c +++ b/atspi/atspi-device-x11.c @@ -44,6 +44,7 @@ struct _AtspiDeviceX11Private GSList *key_grabs; guint virtual_mods_enabled; gboolean keyboard_grabbed; + unsigned int numlock_physical_mask; }; GObjectClass *device_x11_parent_class; @@ -176,7 +177,7 @@ grab_has_active_duplicate (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) } static void -grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +grab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); XIGrabModifiers xi_modifiers; @@ -197,6 +198,22 @@ grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) } static void +grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + + grab_key_aux (x11_device, keycode, modmask); + if (!(modmask & LockMask)) + grab_key_aux (x11_device, keycode, modmask | LockMask); + if (!(modmask & priv->numlock_physical_mask)) + { + grab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask); + if (!(modmask & LockMask)) + grab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask); + } +} + +static void enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); @@ -209,7 +226,7 @@ enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) } static void -ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +ungrab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); XIGrabModifiers xi_modifiers; @@ -221,6 +238,22 @@ ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) } static void +ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +{ + AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); + + ungrab_key_aux (x11_device, keycode, modmask); + if (!(modmask & LockMask)) + ungrab_key_aux (x11_device, keycode, modmask | LockMask); + if (!(modmask & priv->numlock_physical_mask)) + { + ungrab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask); + if (!(modmask & LockMask)) + ungrab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask); + } +} + +static void disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); @@ -290,6 +323,7 @@ do_event_dispatch (gpointer user_data) char text[10]; KeySym keysym; XComposeStatus status; + guint modifiers; while (XPending (display)) { @@ -301,7 +335,13 @@ do_event_dispatch (gpointer user_data) case KeyPress: case KeyRelease: XLookupString(&xevent.xkey, text, sizeof (text), &keysym, &status); - atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, xevent.xkey.state | priv->virtual_mods_enabled, text); + modifiers = xevent.xkey.state | priv->virtual_mods_enabled; + if (modifiers & priv->numlock_physical_mask) + { + modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK); + modifiers &= ~priv->numlock_physical_mask; + } + atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, modifiers, text); break; case GenericEvent: if (xevent.xcookie.extension == priv->xi_opcode) @@ -326,8 +366,11 @@ do_event_dispatch (gpointer user_data) if (!priv->device_id) priv->device_id = xiDevEv->deviceid; set_virtual_modifier (device, xiRawEv->detail, xevent.xcookie.evtype == XI_KeyPress); + modifiers = keyevent.xkey.state | priv->virtual_mods_enabled; + if (modifiers & priv->numlock_physical_mask) + modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK); if (xiDevEv->deviceid == priv->device_id) - atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.xcookie.evtype == XI_KeyPress), xiRawEv->detail, keysym, keyevent.xkey.state, text); + atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.xcookie.evtype == XI_KeyPress), xiRawEv->detail, keysym, modifiers, text); /* otherwise it's probably a duplicate event from a key grab */ XFreeEventData (priv->display, &xevent.xcookie); break; @@ -396,6 +439,9 @@ check_virtual_modifier (AtspiDeviceX11 *x11_device, guint modifier) AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); GSList *l; + if (modifier == (1 << ATSPI_MODIFIER_NUMLOCK)) + return TRUE; + for (l = priv->modifiers; l; l = l->next) { AtspiX11KeyModifier *entry = l->data; @@ -534,6 +580,9 @@ atspi_device_x11_init (AtspiDeviceX11 *device) create_event_source (device); } } + + priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display, + XK_Num_Lock); } static void diff --git a/atspi/atspi-device.c b/atspi/atspi-device.c index 5f62dc3..e4a564c 100644 --- a/atspi/atspi-device.c +++ b/atspi/atspi-device.c @@ -107,6 +107,19 @@ atspi_device_new () return ATSPI_DEVICE (atspi_device_legacy_new ()); } +static gboolean +key_matches_modifiers (guint key_mods, guint grab_mods) +{ + /* The presence or lack thereof of locking modifiers should make no + difference when testing, but other modifiers should match. If the + keypress has modifiers that (a) the grab does not check for and (b) are + not lock modifiers, then we reject the match. Alt + left arrow should not + match a grab on left arrow, for instance, but whether numlock is on or + off would be irrelevant. */ + key_mods &= ~((1 << ATSPI_MODIFIER_SHIFTLOCK) | (1 << ATSPI_MODIFIER_NUMLOCK)); + return (key_mods == grab_mods); +} + gboolean atspi_device_notify_key (AtspiDevice *device, gboolean pressed, int keycode, int keysym, gint state, gchar *text) { @@ -123,8 +136,7 @@ atspi_device_notify_key (AtspiDevice *device, gboolean pressed, int keycode, int for (l = priv->keygrabs; l; l = l->next) { AtspiKeyGrab *grab = l->data; - //if (keycode == grab->keycode && (grab->modifiers & state) == grab->modifiers) - if (keycode == grab->keycode && grab->modifiers == state) + if (keycode == grab->keycode && key_matches_modifiers (state, grab->modifiers)) { if (grab->callback) grab->callback (device, pressed, keycode, keysym, state, text, grab->callback_data); diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c index ca6828f..5455b58 100644 --- a/atspi/atspi-event-listener.c +++ b/atspi/atspi-event-listener.c @@ -798,7 +798,10 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback, DBusMessage *message, *reply; l = g_list_next (l); if (in_send) - pending_removals = g_list_append (pending_removals, e); + { + pending_removals = g_list_remove (pending_removals, e); + pending_removals = g_list_append (pending_removals, e); + } else event_listeners = g_list_remove (event_listeners, e); for (i = 0; i < matchrule_array->len; i++) diff --git a/bus/00-at-spi b/bus/00-at-spi new file mode 100755 index 0000000..dc3bb60 --- /dev/null +++ b/bus/00-at-spi @@ -0,0 +1,10 @@ +#!/bin/sh + +# Copy a11y bus address from the DBus session bus to the X11 root property. +# This is useful when Xwayland is started on demand and if the user has an +# application with X11 access that does not have access to the session bus. + +ADDR="$( busctl call --user org.a11y.Bus /org/a11y/bus org.a11y.Bus GetAddress )" || exit 0 +ADDR="$( echo $ADDR | sed 's/s "\(.*\)"/\1/' )" || exit 0 + +exec xprop -root -format AT_SPI_BUS 8s -set AT_SPI_BUS "$ADDR" diff --git a/bus/accessibility.conf.in b/bus/accessibility.conf.in index 79c5146..33d6e1c 100644 --- a/bus/accessibility.conf.in +++ b/bus/accessibility.conf.in @@ -6,7 +6,7 @@ @DATADIR@/dbus-1/accessibility-services EXTERNAL - unix:dir=/tmp + @SOCKET_ADDRESS@ diff --git a/bus/meson.build b/bus/meson.build index f6c32c9..21408f2 100644 --- a/bus/meson.build +++ b/bus/meson.build @@ -4,8 +4,15 @@ libexec_conf.set('libexecdir', atspi_libexecdir) accessibility_conf = configuration_data() accessibility_conf.set('DATADIR', atspi_datadir) +if libdbus_dep.version().version_compare('>= 1.12.0') + accessibility_conf.set('SOCKET_ADDRESS', 'unix:dir=/tmp') +else + accessibility_conf.set('SOCKET_ADDRESS', 'unix:tmpdir=/tmp') +endif + busconfig_dir = join_paths(atspi_datadir, 'defaults/at-spi2') session_dir = join_paths(atspi_sysconfdir, 'xdg/autostart') +xwayland_session_dir = join_paths(atspi_sysconfdir, 'xdg/Xwayland-session.d') configure_file(input: 'accessibility.conf.in', output: 'accessibility.conf', @@ -27,6 +34,13 @@ configure_file(input: 'at-spi-dbus-bus.service.in', configuration: libexec_conf, install_dir: systemd_user_dir) +if x11_dep.found() + # Note: It is safe to always install it. However, we only need this on + # systemd enabled machines where Xwayland may be started on-demand. + install_data('00-at-spi', + install_dir: xwayland_session_dir) +endif + launcher_args = [ '-DSYSCONFDIR="@0@"'.format(atspi_sysconfdir), '-DDATADIR="@0@"'.format(atspi_datadir), diff --git a/meson.build b/meson.build index ca49dfb..b5104c8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('at-spi2-core', 'c', - version: '2.39.90.1', + version: '2.42.0', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', diff --git a/po/LINGUAS b/po/LINGUAS index 4e2efbd..328b6c4 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -1,3 +1,4 @@ +ab an as ast diff --git a/po/ab.po b/po/ab.po new file mode 100644 index 0000000..6f34b54 --- /dev/null +++ b/po/ab.po @@ -0,0 +1,28 @@ +# Abkhazian translation for at-spi2-core. +# Copyright (C) 2011 at-spi2-core's COPYRIGHT HOLDER +# This file is distributed under the same license as the at-spi2-core package. +# Nart Tlisha , 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: at-spi2-core master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=at-" +"spi&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2014-02-03 23:50+0000\n" +"PO-Revision-Date: 2021-08-16 13:50+0000\n" +"Last-Translator: Nart Tlisha \n" +"Language-Team: Abkhazian\n" +"Language: ab\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.4\n" + +#: ../atspi/atspi-component.c:325 ../atspi/atspi-misc.c:1034 +#: ../atspi/atspi-value.c:111 +msgid "The application no longer exists" +msgstr "Аԥшьы уаҳа ыҟаӡам" + +#: ../atspi/atspi-misc.c:1777 +msgid "Attempted synchronous call where prohibited" +msgstr "Синхронтәу асра аҟаҵара азин ыҟаӡам" diff --git a/po/be.po b/po/be.po index f7bc9c1..f0991f3 100644 --- a/po/be.po +++ b/po/be.po @@ -1,29 +1,31 @@ # Yuras Shumovich , 2017. msgid "" msgstr "" -"Project-Id-Version: at-spi2-core.master\n" -"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=at-" -"spi&keywords=I18N+L10N&component=at-spi2-core\n" -"POT-Creation-Date: 2017-03-13 21:58+0000\n" -"PO-Revision-Date: 2017-03-26 18:30+0300\n" +"Project-Id-Version: ab10e6d45488175674299c2d7fc854f6\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/at-spi2-core/issues\n" +"POT-Creation-Date: 2020-12-28 16:53+0000\n" +"PO-Revision-Date: 2021-06-15 12:46\n" "Last-Translator: Yuras Shumovich \n" -"Language-Team: Belarusian \n" +"Language-Team: Belarusian\n" "Language: be\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || n%10>=5 && n%10<=9 || n%100>=11 && n%100<=14 ? 2 : 3);\n" "X-Generator: Poedit 1.8.11\n" +"X-Crowdin-Project: ab10e6d45488175674299c2d7fc854f6\n" +"X-Crowdin-Project-ID: 104\n" +"X-Crowdin-Language: be\n" +"X-Crowdin-File: /Localizations/Gnome/Gnome development/in/at-spi2-core.master.be.po\n" +"X-Crowdin-File-ID: 2608\n" -#: ../atspi/atspi-component.c:326 ../atspi/atspi-misc.c:1073 -#: ../atspi/atspi-value.c:111 +#: atspi/atspi-component.c:332 atspi/atspi-misc.c:1077 atspi/atspi-value.c:111 msgid "The application no longer exists" msgstr "Праграма больш не існуе" -#: ../atspi/atspi-misc.c:1832 +#: atspi/atspi-misc.c:1855 msgid "Attempted synchronous call where prohibited" -msgstr "Спроба зрабіць сінхронны выклік, там дзе гэта забаронена" +msgstr "Спроба сінхроннага выкліку ў забароненым месцы" #~ msgid "AT-SPI: Unknown signature %s for RemoveAccessible" #~ msgstr "AT-SPI: Невядомы подпіс %s для RemoveAccessible" @@ -57,8 +59,7 @@ msgstr "Спроба зрабіць сінхронны выклік, там дз #~ "AT-SPI: пры сцягванні %s з інтэрфейсу %s чакаўся варыянт; атрыманы %s\n" #~ msgid "atspi_dbus_get_property: Wrong type: expected %s, got %c\n" -#~ msgstr "" -#~ "atspi_dbus_get_property: Няправільны тып: чакаўся %s, атрыманы %c\n" +#~ msgstr "atspi_dbus_get_property: Няправільны тып: чакаўся %s, атрыманы %c\n" #~ msgid "AT-SPI: Unknown interface %s" #~ msgstr "AT-SPI: Невядомы інтэрфейс %s" @@ -77,3 +78,4 @@ msgstr "Спроба зрабіць сінхронны выклік, там дз #~ msgid "Got invalid signature %s for signal %s from interface %s\n" #~ msgstr "Атрыманы хібны подпіс %s для сігналу %s інтэрфейсу %s\n" + diff --git a/po/gl.po b/po/gl.po index 932ffea..ed8f1fd 100644 --- a/po/gl.po +++ b/po/gl.po @@ -7,10 +7,10 @@ msgid "" msgstr "" "Project-Id-Version: at-spi 2-core\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/at-spi2-core/issues\n" -"POT-Creation-Date: 2018-10-05 04:46+0000\n" +"POT-Creation-Date: 2020-12-28 16:53+0000\n" "PO-Revision-Date: 2019-12-25 05:11+0100\n" "Last-Translator: Fran Dieguez \n" -"Language-Team: gnome-l10n-gl@gnome.org\n" +"Language-Team: Proxecto Trasno \n" "Language: gl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,10 +18,10 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.2.4\n" -#: atspi/atspi-component.c:326 atspi/atspi-misc.c:1073 atspi/atspi-value.c:111 +#: atspi/atspi-component.c:332 atspi/atspi-misc.c:1077 atspi/atspi-value.c:111 msgid "The application no longer exists" msgstr "A aplicación xa non existe" -#: atspi/atspi-misc.c:1850 +#: atspi/atspi-misc.c:1855 msgid "Attempted synchronous call where prohibited" msgstr "Tentouse unha chamada síncrona onde estaba prohibida" diff --git a/registryd/de-marshaller.c b/registryd/de-marshaller.c index 2f212b0..f109484 100644 --- a/registryd/de-marshaller.c +++ b/registryd/de-marshaller.c @@ -70,7 +70,11 @@ dbus_bool_t spi_dbus_message_iter_append_struct(DBusMessageIter *iter, ...) ptr = va_arg(args, void *); dbus_message_iter_append_basic(&iter_struct, type, ptr); } - if (!dbus_message_iter_close_container(iter, &iter_struct)) return FALSE; + if (!dbus_message_iter_close_container(iter, &iter_struct)) + { + va_end(args); + return FALSE; + } va_end(args); return TRUE; } diff --git a/registryd/deviceeventcontroller-x11.c b/registryd/deviceeventcontroller-x11.c index df16bd8..55239f4 100644 --- a/registryd/deviceeventcontroller-x11.c +++ b/registryd/deviceeventcontroller-x11.c @@ -82,7 +82,7 @@ static unsigned int mouse_button_mask = Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask; static unsigned int key_modifier_mask = Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask | SPI_KEYMASK_NUMLOCK; -static unsigned int _numlock_physical_mask = Mod2Mask; /* a guess, will be reset */ +extern unsigned int _numlock_physical_mask; static XModifierKeymap* xmkeymap = NULL; diff --git a/registryd/deviceeventcontroller.c b/registryd/deviceeventcontroller.c index acd089b..942f383 100644 --- a/registryd/deviceeventcontroller.c +++ b/registryd/deviceeventcontroller.c @@ -73,7 +73,7 @@ static unsigned int key_modifier_mask = SPI_KEYMASK_MOD1 | SPI_KEYMASK_MOD2 | SPI_KEYMASK_MOD3 | SPI_KEYMASK_MOD4 | SPI_KEYMASK_MOD5 | SPI_KEYMASK_SHIFT | SPI_KEYMASK_SHIFTLOCK | SPI_KEYMASK_CONTROL | SPI_KEYMASK_NUMLOCK; -static unsigned int _numlock_physical_mask = SPI_KEYMASK_MOD2; /* a guess, will be reset */ +unsigned int _numlock_physical_mask = SPI_KEYMASK_MOD2; /* a guess, will be reset */ static gboolean have_mouse_listener = FALSE; static gboolean have_mouse_event_listener = FALSE; diff --git a/xml/Collection.xml b/xml/Collection.xml index a6dff74..913ebcb 100644 --- a/xml/Collection.xml +++ b/xml/Collection.xml @@ -3,7 +3,7 @@ - + @@ -15,7 +15,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/xml/Component.xml b/xml/Component.xml index 94056ff..afefab8 100644 --- a/xml/Component.xml +++ b/xml/Component.xml @@ -74,12 +74,14 @@ + + diff --git a/xml/Document.xml b/xml/Document.xml index a82eb98..03c9693 100644 --- a/xml/Document.xml +++ b/xml/Document.xml @@ -16,7 +16,7 @@ - + diff --git a/xml/Text.xml b/xml/Text.xml index fe9f44b..da772ae 100644 --- a/xml/Text.xml +++ b/xml/Text.xml @@ -157,6 +157,7 @@ + @@ -165,6 +166,7 @@ + -- 2.7.4 From 6c0b52b2f7f16ecb6bfb60d1e95c68203c260971 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Artur=20=C5=9Awigo=C5=84?= Date: Mon, 21 Feb 2022 10:34:35 +0100 Subject: [PATCH 13/16] Fix meson 0.60.3 errors Change-Id: I74be6c48e1dd6a5120a506109a7b6849793d20ae --- bus/meson.build | 7 ------- packaging/at-spi2-core.spec | 18 +++++++++--------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/bus/meson.build b/bus/meson.build index 9981e3a..eae2e1d 100644 --- a/bus/meson.build +++ b/bus/meson.build @@ -34,13 +34,6 @@ configure_file(input: 'at-spi-dbus-bus.service.in', configuration: libexec_conf, install_dir: systemd_user_dir) -if x11_dep.found() - # Note: It is safe to always install it. However, we only need this on - # systemd enabled machines where Xwayland may be started on-demand. - install_data('00-at-spi', - install_dir: xwayland_session_dir) -endif - launcher_args = [ '-DSYSCONFDIR="@0@"'.format(atspi_sysconfdir), '-DDATADIR="@0@"'.format(atspi_datadir), diff --git a/packaging/at-spi2-core.spec b/packaging/at-spi2-core.spec index 09c3abb..3742942 100644 --- a/packaging/at-spi2-core.spec +++ b/packaging/at-spi2-core.spec @@ -73,21 +73,21 @@ to develop applications that require these. cp %{SOURCE1001} . %build -meson --prefix /usr --libdir %{_libdir} build -Dwith-dbus-daemondir=%{_bindir} -Ddbus_daemon=/usr/bin/dbus-daemon \ -%if !%{with x} - -Denable-x11=no \ -%else - -Denable-x11=yes \ -%endif - -Denable-static=no +meson setup \ + --prefix=/usr \ + --libdir=%{_libdir} \ + --default-library=shared \ + -Ddbus_daemon=/usr/bin/dbus-daemon \ + -Dx11=no \ + build -ninja -C build all +meson compile -C build %install find %{buildroot} -name '*.la' -or -name '*.a' | xargs rm -f export DESTDIR=%{buildroot} -ninja -C build install +meson install -C build %find_lang %{name} -- 2.7.4 From dd2dcd4f313f7d60020d4c04aa23789f7af9a7da Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 20 Apr 2022 17:22:12 +0900 Subject: [PATCH 14/16] [Tizen] Provide GetForegroundWindows interface This interface will work for selecting a window on x,y position. It will be needed in multi-window environment. Change-Id: Idc86f360de0d43c867dddec5f958a26aa2693c08 --- atspi/atspi-registry.c | 61 +++++++++++- atspi/atspi-registry.h | 1 + registryd/registry-main.c | 11 +-- registryd/registry.c | 244 +++++++++++++++++++++++++++++++++++++++------- registryd/registry.h | 6 +- 5 files changed, 276 insertions(+), 47 deletions(-) diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c index e9a47e5..c5153ae 100644 --- a/atspi/atspi-registry.c +++ b/atspi/atspi-registry.c @@ -117,8 +117,8 @@ atspi_get_active_window () AtspiAccessible* active_window; message = dbus_message_new_method_call (ATSPI_DBUS_NAME_REGISTRY, - ATSPI_DBUS_PATH_ROOT, - ATSPI_DBUS_INTERFACE_SOCKET, + ATSPI_DBUS_PATH_REGISTRY, + ATSPI_DBUS_INTERFACE_REGISTRY, "GetActiveWindow"); if (!message) return NULL; @@ -143,6 +143,63 @@ atspi_get_active_window () return g_object_ref (active_window); } + +/** + * atspi_get_foreground_windows: + * + * Gets the array of foreground windows On return, @array will point + * to a newly-created, NULL terminated array of foreground window + * pointers. + * It is the responsibility of the caller to free this array when + * it is no longer needed. + * + * Returns: (element-type AtspiAccessible*) (transfer full): a #GArray of + * foreground windows. + **/ +GArray * +atspi_get_foreground_windows () +{ + DBusMessage *message, *reply; + DBusMessageIter iter, iter_array, iter_dict; + GArray *ret; + + message = dbus_message_new_method_call (ATSPI_DBUS_NAME_REGISTRY, + ATSPI_DBUS_PATH_REGISTRY, + ATSPI_DBUS_INTERFACE_REGISTRY, + "GetForegroundWindows"); + if (!message) + return NULL; + + reply = _atspi_dbus_send_with_reply_and_block (message, NULL); + if (!reply) + return NULL; + + if (strcmp (dbus_message_get_signature (reply), "a(so)") != 0) + { + dbus_message_unref (reply); + return NULL; + } + + dbus_message_iter_init (reply, &iter); + ret = g_array_new (TRUE, TRUE, sizeof (AtspiAccessible *)); + + dbus_message_iter_recurse (&iter, &iter_array); + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + const char *name, *path; + AtspiAccessible *accessible; + dbus_message_iter_recurse (&iter_array, &iter_dict); + dbus_message_iter_get_basic (&iter_dict, &name); + dbus_message_iter_next (&iter_dict); + dbus_message_iter_get_basic (&iter_dict, &path); + accessible = ref_accessible(name, path); + ret = g_array_append_val (ret, accessible); + dbus_message_iter_next (&iter_array); + } + dbus_message_unref (reply); + + return ret; +} // static gboolean diff --git a/atspi/atspi-registry.h b/atspi/atspi-registry.h index b266c7b..877a685 100644 --- a/atspi/atspi-registry.h +++ b/atspi/atspi-registry.h @@ -41,6 +41,7 @@ GArray *atspi_get_desktop_list (); //TIZEN_ONLY(20211206) Provide GetActiveWindow AtspiAccessible* atspi_get_active_window (); +GArray* atspi_get_foreground_windows (); // gboolean diff --git a/registryd/registry-main.c b/registryd/registry-main.c index c137182..f364ac1 100644 --- a/registryd/registry-main.c +++ b/registryd/registry-main.c @@ -260,16 +260,7 @@ main (int argc, char **argv) g_main_loop_run (mainloop); //TIZEN_ONLY(20211206) Provide GetActiveWindow - if (registry->active_window_name) - { - g_free (registry->active_window_name); - registry->active_window_name = NULL; - } - if (registry->active_window_path) - { - g_free (registry->active_window_path); - registry->active_window_path = NULL; - } + spi_registry_free_active_window (registry); // dbus_connection_close (bus); diff --git a/registryd/registry.c b/registryd/registry.c index fa2d3a5..9757067 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -29,6 +29,26 @@ #include "paths.h" #include "registry.h" #include "introspection.h" +//TIZEN_ONLY(20220420) Provide GetForegroundWindows +#include "atspi/atspi.h" + +static gboolean +_is_same (const char *s1, const char *s2) +{ + size_t l1, l2; + + if (!s1 || !s2) + return (s1 == s2); + + l1 = strlen (s1); + l2 = strlen (s2); + + if (l1 != l2) + return FALSE; + + return !strncmp (s1, s2, l1); +} +// typedef struct event_data event_data; struct event_data @@ -92,6 +112,7 @@ static void spi_registry_init (SpiRegistry *registry) { registry->apps = g_ptr_array_new_with_free_func ((GDestroyNotify) spi_reference_free); + registry->wins = g_ptr_array_new_with_free_func ((GDestroyNotify) spi_reference_free); } /*---------------------------------------------------------------------------*/ @@ -299,22 +320,25 @@ handle_disconnection (DBusConnection *bus, DBusMessage *message, void *user_data } remove_events (reg, old, ""); + //TIZEN_ONLY(20220420) Provide GetForegroundWindows + for (i = 0; i < reg->wins->len; i++) + { + SpiReference *ref = g_ptr_array_index (reg->wins, i); + if (_is_same (old, ref->name)) + { + g_ptr_array_remove_index (reg->wins, i); + i--; + } + } + // } } } //TIZEN_ONLY(20211206) Provide GetActiveWindow static void -handle_activate_window (DBusConnection *bus, DBusMessage *message, void *user_data) +_set_active_window (SpiRegistry *reg, DBusMessage *message, const char* sender, const char *path) { - SpiRegistry *reg = SPI_REGISTRY (user_data); - - const char *sender = dbus_message_get_sender (message); - const char *path = dbus_message_get_path (message); - - if (!sender || !path) - return; - char *detail = NULL; dbus_int32_t detail1; DBusMessageIter iter; @@ -326,13 +350,58 @@ handle_activate_window (DBusConnection *bus, DBusMessage *message, void *user_da if (detail1 & ACCESSIBLE_WINDOW_ACTIVATE_INFO_KEYBOARD) return; - if (reg->active_window_name) - g_free (reg->active_window_name); - if (reg->active_window_path) - g_free (reg->active_window_path); + if (reg->active_win) spi_reference_free (reg->active_win); + reg->active_win = spi_reference_new (sender, path); +} + +static void +_unset_active_window (SpiRegistry *reg, const char* sender, const char *path) +{ + SpiReference *ref; + + if (!reg->active_win) + return; + + ref = spi_reference_new (sender, path); + + if (compare_reference (ref, reg->active_win)) + { + spi_reference_free (reg->active_win); + reg->active_win = NULL; + } +} + +static void +_add_window_info (SpiRegistry *reg, const char* sender, const char *path) +{ + guint index; + if (find_index_of_reference (reg->wins, sender, path, &index)) + return; + + g_ptr_array_add (reg->wins, spi_reference_new (sender, path)); +} - reg->active_window_name = g_strdup(sender); - reg->active_window_path = g_strdup(path); +static void +_remove_window_info (SpiRegistry *reg, const char* sender, const char *path) +{ + guint index; + if (find_index_of_reference (reg->wins, sender, path, &index)) + g_ptr_array_remove_index (reg->wins, index); +} + +static void +handle_activate_window (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + SpiRegistry *reg = SPI_REGISTRY (user_data); + + const char *sender = dbus_message_get_sender (message); + const char *path = dbus_message_get_path (message); + + if (!sender || !path) + return; + + _set_active_window (reg, message, sender, path); + _add_window_info (reg, sender, path); } static void @@ -340,23 +409,79 @@ handle_deactivate_window (DBusConnection *bus, DBusMessage *message, void *user_ { SpiRegistry *reg = SPI_REGISTRY (user_data); - if (!reg->active_window_name || !reg->active_window_path) + const char *sender = dbus_message_get_sender (message); + const char *path = dbus_message_get_path (message); + + if (!sender || !path) return; + _unset_active_window (reg, sender, path); + /* deactivate window can be showing, so no need _remove_window_info */ +} + +static void +handle_destroy_window (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + SpiRegistry *reg = SPI_REGISTRY (user_data); + const char *sender = dbus_message_get_sender (message); const char *path = dbus_message_get_path (message); if (!sender || !path) return; - if (!g_strcmp0(reg->active_window_name, sender) && - !g_strcmp0(reg->active_window_path, path)) + _unset_active_window (reg, sender, path); + _remove_window_info (reg, sender, path); +} + +static void +handle_state_changed (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + SpiRegistry *reg = SPI_REGISTRY (user_data); + + const char *sender = dbus_message_get_sender (message); + const char *path = dbus_message_get_path (message); + const char *signature = dbus_message_get_signature (message); + + if (!sender || !path || !signature) + return; + + if (!_is_same (signature, "siiv(so)") && + !_is_same (signature, "siiva{sv}")) + return; + + DBusMessageIter iter; + dbus_int32_t detail1, detail2; + char *detail = NULL; + + dbus_message_iter_init (message, &iter); + dbus_message_iter_get_basic (&iter, &detail); + dbus_message_iter_next (&iter); + dbus_message_iter_get_basic (&iter, &detail1); + dbus_message_iter_next (&iter); + dbus_message_iter_get_basic (&iter, &detail2); + dbus_message_iter_next (&iter); + + /* TODO: detail == showing */ + if (!detail || !_is_same (detail, "visible")) + return; + + AtspiAccessible *accessible; + AtspiRole role; + + accessible = ref_accessible (sender, path); + role = atspi_accessible_get_role (accessible, NULL); + + if (role == ATSPI_ROLE_WINDOW || + role == ATSPI_ROLE_INPUT_METHOD_WINDOW) { - g_free (reg->active_window_name); - g_free (reg->active_window_path); - reg->active_window_name = NULL; - reg->active_window_path = NULL; + if (detail1) + _add_window_info (reg, sender, path); + else + _remove_window_info (reg, sender, path); } + + g_object_unref (accessible); } // @@ -406,16 +531,28 @@ signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data) if (type != DBUS_MESSAGE_TYPE_SIGNAL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + //TIZEN_ONLY(20220420) Provide GetForegroundWindows + if (!iface || !member) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + // + if (!g_strcmp0(iface, DBUS_INTERFACE_DBUS) && !g_strcmp0(member, "NameOwnerChanged")) handle_disconnection (bus, message, user_data); //TIZEN_ONLY(20211206) Provide GetActiveWindow - else if (!g_strcmp0(iface, "org.a11y.atspi.Event.Window")) + else if (_is_same (iface, "org.a11y.atspi.Event.Window")) { - if (!g_strcmp0(member, "Activate")) + if (_is_same (member, "Activate")) handle_activate_window (bus, message, user_data); - else if (!g_strcmp0(member, "Deactivate")) + else if (_is_same (member, "Deactivate")) handle_deactivate_window (bus, message, user_data); + else if (_is_same (member, "Destroy")) + handle_destroy_window (bus, message, user_data); + } + else if (_is_same (iface, "org.a11y.atspi.Event.Object")) + { + if (_is_same (member, "StateChanged")) + handle_state_changed (bus, message, user_data); } // else @@ -909,13 +1046,40 @@ impl_GetActiveWindow (DBusConnection * bus, reply = dbus_message_new_method_return (message); dbus_message_iter_init_append (reply, &iter); - if (!reg->active_window_name || !reg->active_window_path) + SpiReference *active_window = reg->active_win; + if (!active_window) append_reference (&iter, SPI_DBUS_NAME_REGISTRY, SPI_DBUS_PATH_NULL); else - append_reference (&iter, reg->active_window_name, reg->active_window_path); + append_reference (&iter, active_window->name, active_window->path); return reply; } + +static DBusMessage * +impl_GetForegroundWindows (DBusConnection * bus, + DBusMessage * message, void *user_data) +{ + SpiRegistry *reg = SPI_REGISTRY (user_data); + DBusMessage *reply; + DBusMessageIter iter, iter_array, iter_struct; + guint i = 0; + + 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); + + SpiReference *win; + for (i = 0; i < reg->wins->len; i++) + { + win = g_ptr_array_index (reg->wins, i); + dbus_message_iter_open_container (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &win->name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &win->path); + dbus_message_iter_close_container (&iter_array, &iter_struct); + } + dbus_message_iter_close_container (&iter, &iter_array); + return reply; +} // static DBusMessage * @@ -1394,10 +1558,6 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data) reply = impl_Embed (bus, message, user_data); else if (!strcmp (member, "Unembed")) reply = impl_Unembed (bus, message, user_data); - //TIZEN_ONLY(20211206) Provide GetActiveWindow - else if (!strcmp (member, "GetActiveWindow")) - reply = impl_GetActiveWindow (bus, message, user_data); - // else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1496,6 +1656,12 @@ handle_method_registry (DBusConnection *bus, DBusMessage *message, void *user_da reply = impl_deregister_event (bus, message, user_data); else if (!strcmp(member, "GetRegisteredEvents")) reply = impl_get_registered_events (bus, message, user_data); + //TIZEN_ONLY(20211206) Provide GetActiveWindow + else if (_is_same(member, "GetActiveWindow")) + reply = impl_GetActiveWindow (bus, message, user_data); + else if (_is_same(member, "GetForegroundWindows")) + reply = impl_GetForegroundWindows(bus, message, user_data); + // else result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1560,6 +1726,16 @@ static gchar *app_sig_match_window_activate = "type='signal',interface='org.a11y.atspi.Event.Window',member='Activate'"; static gchar *app_sig_match_window_deactivate = "type='signal',interface='org.a11y.atspi.Event.Window',member='Deactivate'"; +static gchar *app_sig_match_window_destroy = + "type='signal',interface='org.a11y.atspi.Event.Window',member='Destroy'"; +static gchar *app_sig_match_state_changed = + "type='signal',interface='org.a11y.atspi.Event.Object',member='StateChanged'"; + +void spi_registry_free_active_window (SpiRegistry *reg) +{ + if (reg->active_win) + spi_reference_free (reg->active_win); +} // SpiRegistry * @@ -1573,10 +1749,12 @@ spi_registry_new (DBusConnection *bus) dbus_connection_add_filter (bus, signal_filter, reg, NULL); //TIZEN_ONLY(20211206) Provide GetActiveWindow - reg->active_window_name = NULL; - reg->active_window_path = NULL; + reg->active_win = NULL; + dbus_bus_add_match (reg->bus, app_sig_match_window_activate, NULL); dbus_bus_add_match (reg->bus, app_sig_match_window_deactivate, NULL); + dbus_bus_add_match (reg->bus, app_sig_match_window_destroy, NULL); + dbus_bus_add_match (reg->bus, app_sig_match_state_changed, NULL); // dbus_connection_register_object_path (bus, SPI_DBUS_PATH_ROOT, &root_vtable, reg); diff --git a/registryd/registry.h b/registryd/registry.h index ee82ef5..5b2f4ec 100644 --- a/registryd/registry.h +++ b/registryd/registry.h @@ -52,8 +52,8 @@ struct _SpiRegistry { GList *events; //TIZEN_ONLY(20211206) Provide GetActiveWindow - gchar *active_window_name; - gchar *active_window_path; + GPtrArray *wins; + gpointer active_win; // }; @@ -64,6 +64,8 @@ typedef enum { ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_DISABLED = 1 << 1, ACCESSIBLE_WINDOW_ACTIVATE_INFO_KEYBOARD = 1 << 2, } WindowActivateInfoType; + +void spi_registry_free_active_window (SpiRegistry *reg); // struct _SpiRegistryClass { -- 2.7.4 From 646910d52fccb983857e13e539ebe1950677cb4c Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Fri, 20 May 2022 16:05:10 +0900 Subject: [PATCH 15/16] Fix memory leak This patch is removing memory leak detected by analysis tool. Change-Id: I473e2a6d20b92a9e28300ed758e9bd3508b78fcb --- registryd/registry.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/registryd/registry.c b/registryd/registry.c index 9757067..0e1703e 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -369,6 +369,8 @@ _unset_active_window (SpiRegistry *reg, const char* sender, const char *path) spi_reference_free (reg->active_win); reg->active_win = NULL; } + + spi_reference_free (ref); } static void -- 2.7.4 From 902dc3558d17fce8d60117ca66c905fe8993f5c8 Mon Sep 17 00:00:00 2001 From: Lukasz Oleksak Date: Fri, 17 Jun 2022 11:11:42 +0200 Subject: [PATCH 16/16] Increasing cache maximum size to handle complex UIs Change-Id: I5a9072894df80214532c9521d0f30aa454d0a239 --- atspi/atspi-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index be8030e..ae2de51 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -38,7 +38,7 @@ #include /* This value is not fixed, could be changed. */ -#define HASH_TABLE_SIZE_MAX 1000 +#define HASH_TABLE_SIZE_MAX 3000 static void handle_get_items (DBusPendingCall *pending, void *user_data); -- 2.7.4