From dd2dcd4f313f7d60020d4c04aa23789f7af9a7da Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 20 Apr 2022 17:22:12 +0900 Subject: [PATCH] [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