Prevent context switing when unfocused window is added 63/318063/2
authorYoungsun Suh <youngsun.suh@samsung.com>
Wed, 2 Oct 2024 07:17:12 +0000 (16:17 +0900)
committerSeoyeon Kim <seoyeon2.kim@samsung.com>
Mon, 13 Jan 2025 02:37:06 +0000 (11:37 +0900)
There are cases "showing" events comes after a window is focused, which causes loss of focus of the currently focused window. To prevent this, updated to switch context on focused("activate") instead of on window shown.
Also, added a condition for "NameOwnerChanged" to prevent removing the window when a widget proxy is removed.

Change-Id: I2d1b24539b8b1504e878e84b2cfc06a2ee14a4bb

include/app_tracker.h
include/window_info.h
include/window_tracker.h
src/app_tracker.c
src/navigator.c
src/window_tracker.c

index 7cea472a5a626613e019f2475a99bf586912e9eb..1fde6f80bc9efd0ae98cc3cf1eb9e5dbef21abb0 100644 (file)
@@ -56,8 +56,9 @@ void app_tracker_scroll_gesture_required_object_info_send(App_Tracker_Data* atd)
  * @brief This function allows access to submodule functinality of app_tracker.
  *
  * @param atd internal data of app tracker module
+ * @param include_keyboard whether to include the keyboard window to the result or not.
  */
-AtspiAccessible* app_tracker_top_window_get(App_Tracker_Data *atd);
+AtspiAccessible* app_tracker_top_window_get(App_Tracker_Data *atd, Eina_Bool include_keyboard);
 
 /**
  * @brief This function allows access to submodule functinality of app_tracker.
index acaf89558a2367f9a093c15f091f802e8385c8d7..435327a2638fb084874332027e6440f53f8ba4ad 100644 (file)
@@ -18,6 +18,7 @@ typedef struct {
        WindowActivateInfoType window_activate_info_type;
        uint32_t resource_id;
        Eina_Bool defunct;
+       Eina_Bool is_focused;
 } WindowInfo;
 
 #endif
index 5bc26914d36a077c2896591a81ad48e92b3c1bbb..1b89c2e613dac5f8e90969153f16f38aa9d51535 100644 (file)
@@ -48,14 +48,15 @@ void window_tracker_active_window_request(WindowTrackerData *wtd);
 AtspiAccessible *window_tracker_top_win_get(WindowTrackerData *wtd);
 
 /*
- * @brief Return top accessible window
+ * @brief Return top focued window; If no focused window exist, returns the top window from the window stack.
+ * @param include_keyboard if true, search the window list including keyboard window; otherwise, exclude keyboard from the search.
  */
-AtspiAccessible *window_tracker_top_window_get(WindowTrackerData *wtd);
+AtspiAccessible *window_tracker_top_window_get(WindowTrackerData *wtd, Eina_Bool include_keyboard);
 
 /*
  * @brief Appends window from window list
  */
-void window_tracker_window_append(WindowTrackerData *wtd, AtspiAccessible *window);
+void window_tracker_window_append(WindowTrackerData *wtd, AtspiAccessible *window, Eina_Bool is_focused);
 
 /*
  * @brief Removes window from window list
index afcae8087b8198e5efefbd8c0bfb254fc96e5532..a1666dc020ff95ccf0c96c1e2670cb41ec458005 100644 (file)
@@ -327,7 +327,7 @@ static void _on_atspi_event_cb(AtspiEvent *event, void *user_data)
                                because the 'visible' callback of window tracker is not called on window tracker side,
                                if window object is removed. */
                                DEBUG("Append Window");
-                               window_tracker_window_append(atd->window_tracker_data, event->source);
+                               window_tracker_window_append(atd->window_tracker_data, event->source, EINA_FALSE);
                        } else if (role == ATSPI_ROLE_PAGE_TAB) {
                                // refresh default label for newly showing page tab
                                DEBUG("Refreshing TAB");
@@ -378,7 +378,7 @@ static void _on_atspi_event_cb(AtspiEvent *event, void *user_data)
                                        gchar *id = NULL;
 
                                        fn_context = navigator_get_flat_navi_context(atd->view_content_changed_ecd->user_data);
-                                       next_top_window = window_tracker_top_window_get(atd->window_tracker_data);
+                                       next_top_window = window_tracker_top_window_get(atd->window_tracker_data, EINA_FALSE);
                                        AtspiAccessibleDefaultLabelInfo *dli = atspi_accessible_get_default_label_info(atd->root, NULL);
                                        if (dli) {
                                                flat_navi_context_root_change(fn_context, dli->obj);
@@ -728,7 +728,7 @@ static void app_tracker_window_append(void *data, AtspiAccessible *root)
                ERROR("app_tracker module used without initialization");
                return;
        }
-       window_tracker_window_append(atd->window_tracker_data, root);
+       window_tracker_window_append(atd->window_tracker_data, root, EINA_TRUE);
 }
 #endif
 
@@ -830,9 +830,9 @@ void app_tracker_scroll_gesture_required_object_info_send(App_Tracker_Data *atd)
 #endif
 }
 
-AtspiAccessible* app_tracker_top_window_get(App_Tracker_Data *atd)
+AtspiAccessible* app_tracker_top_window_get(App_Tracker_Data *atd, Eina_Bool include_keyboard)
 {
-       return atd ? window_tracker_top_window_get(atd->window_tracker_data) : NULL;
+       return atd ? window_tracker_top_window_get(atd->window_tracker_data, include_keyboard) : NULL;
 }
 
 AtspiAccessible* app_tracker_at_point_window_get(App_Tracker_Data *atd, int x, int y)
index cc71134765b189699e413bd11e7bea429e5a205f..b270e7670b8dd54c10bdb1e92489f5810199f6da 100644 (file)
@@ -2210,7 +2210,7 @@ TIZEN_PROD_STATIC Eina_Bool _current_highlight_on_keyboard_is(NavigatorData *nd)
        gchar *top_bus_name;
        gchar *current_bus_name;
 
-       top_window = app_tracker_top_window_get(nd->app_tracker_data);
+       top_window = app_tracker_top_window_get(nd->app_tracker_data, EINA_TRUE);
        current = flat_navi_context_current_get(nd->flat_navi_context);
        if (!top_window || !current) return ret;
 
index 37693a0d9f23cfc94c574a5bfa1d0178b8f2baf2..088a659fe1d26324ae89e95f917e371d2e2a537b 100644 (file)
@@ -32,7 +32,6 @@ struct WindowTrackerDataImpl
        WindowTrackerCb user_cb;
        void *user_data; // App_Tracker_Data *
        AtspiEventListener *listener;
-       AtspiAccessible *last_active_win;
        AtspiAccessible *top_win;
        Eina_List *window_infos;
        AtspiAccessible *keyboard_window;
@@ -167,12 +166,12 @@ static void _window_info_print(WindowInfo *wi)
        gchar *id = atspi_accessible_get_unique_id(wi->window, NULL);
        AtspiRect extents;
        if (object_get_extents(wi->window, &extents)) {
-               DEBUG("Window: %s (%d, %d, %d, %d) view change need: %d, keyboard window: %d",
+               DEBUG("Window: %s (%d, %d, %d, %d) view change need: %d, keyboard window: %d, is_focused: %d",
                        id, extents.x, extents.y, extents.width, extents.height,
-                       wi->view_change_need, wi->keyboard_window_is);
+                       wi->view_change_need, wi->keyboard_window_is, wi->is_focused);
        } else {
-               DEBUG("Window: %s (no extents available) view change need: %d, keyboard window: %d",
-                       id, wi->view_change_need, wi->keyboard_window_is);
+               DEBUG("Window: %s (no extents available) view change need: %d, keyboard window: %d, is_focused: %d",
+                       id, wi->view_change_need, wi->keyboard_window_is, wi->is_focused);
        }
        g_free(id);
 }
@@ -207,7 +206,7 @@ static uint32_t _window_resource_id_get(AtspiAccessible *window)
 }
 
 static void _window_append(WindowTrackerData *wtd, AtspiAccessible *window, Eina_Bool view_change_need,
-                                                  Eina_Bool keyboard_window_is, WindowActivateInfoType window_activate_info_type)
+                                                  Eina_Bool keyboard_window_is, WindowActivateInfoType window_activate_info_type, Eina_Bool is_focused)
 {
        // Increase reference count immediately to guard against g_object_unref() in the loop below.
        // This is a danger only if 'window == wi->window', which is a stricter condition than
@@ -239,35 +238,75 @@ static void _window_append(WindowTrackerData *wtd, AtspiAccessible *window, Eina
        wi->view_change_need = view_change_need;
        wi->window_activate_info_type = window_activate_info_type;
        wi->resource_id = _window_resource_id_get(window);
+       wi->is_focused = is_focused;
 
        wtd->window_infos = eina_list_append(wtd->window_infos, wi);
 
-       if (view_change_need && wtd->user_cb)
-               wtd->user_cb(wtd->user_data, window);
-
        gchar *id = atspi_accessible_get_unique_id(window, NULL);
        DEBUG("Window appended: %s", id);
        g_free(id);
        _window_stack_print(wtd);
 }
 
-static AtspiAccessible *_top_window_get(WindowTrackerData *wtd)
+static AtspiAccessible *_top_focused_window_get(WindowTrackerData *wtd, Eina_Bool include_keyboard)
 {
        WindowInfo *wi = NULL;
+       Eina_List *l;
+       EINA_LIST_REVERSE_FOREACH(wtd->window_infos, l, wi) {
+               if (!wi) continue;
+               if (wi->is_focused && (include_keyboard || !wi->keyboard_window_is)) {
+                       return wi->window;
+               }
+       }
+
+       return NULL;
+}
+
+static AtspiAccessible *_top_window_get(WindowTrackerData *wtd, Eina_Bool include_keyboard)
+{
        _purge_windows_list(wtd);
-       wi = eina_list_last_data_get(wtd->window_infos);
-       if (wi)
-               return wi->window;
+
+       AtspiAccessible *top = _top_focused_window_get(wtd, include_keyboard);
+       if(top)
+               return top;
+
+       DEBUG("No focused window found. Try finding last window from the stack.");
+       WindowInfo *wi = NULL;
+       Eina_List *l;
+       EINA_LIST_REVERSE_FOREACH(wtd->window_infos, l, wi) {
+               if (!wi) continue;
+               if (include_keyboard || !wi->keyboard_window_is) {
+                       return wi->window;
+               }
+       }
 
        return NULL;
 }
 
+static void _switch_context_to_non_keyboard_top(WindowTrackerData *wtd)
+{
+       AtspiAccessible *top_window = _top_window_get(wtd, EINA_TRUE);
+       if (top_window) {
+               // If current top is keyboard window, use next top
+               if (atspi_accessible_is_equal(top_window, wtd->keyboard_window)) {
+                       top_window = _top_window_get(wtd, EINA_FALSE);
+               }
+
+               wtd->user_cb(wtd->user_data, top_window);
+               gchar *id = atspi_accessible_get_unique_id(top_window, NULL);
+               DEBUG("top window: %s", id);
+               g_free(id);
+       } else {
+               app_tracker_null_context_switch(wtd->user_data);
+       }
+}
+
 static void _window_remove(WindowTrackerData *wtd, AtspiAccessible *window)
 {
        Eina_Bool remove_from_top = EINA_FALSE;
        AtspiAccessible *top_window;
 
-       top_window = _top_window_get(wtd);
+       top_window = _top_window_get(wtd, EINA_FALSE);
        remove_from_top = atspi_accessible_is_equal(top_window, window);
 
        Eina_Bool window_removed = EINA_FALSE;
@@ -304,29 +343,7 @@ static void _window_remove(WindowTrackerData *wtd, AtspiAccessible *window)
                /* keyboard_window_is would be always FASLE because the
                window_tracker_keyboard_window_remove does not use this function */
                if (wtd->user_cb && !keyboard_window_is) {
-                       top_window = _top_window_get(wtd);
-                       if (top_window) {
-                               /* The current top could be keypad window,
-                               if so, use the second top window */
-                               wi = eina_list_last_data_get(wtd->window_infos);
-                               if (wi->keyboard_window_is) {
-                                       int count = eina_list_count(wtd->window_infos);
-                                       wi = eina_list_nth(wtd->window_infos, count - 2);
-                                       if (wi)
-                                               top_window = wi->window;
-                                       else
-                                               top_window = NULL;
-                               }
-                               if (top_window)
-                                       wtd->user_cb(wtd->user_data, top_window);
-                       }
-
-                       if (!top_window)
-                               app_tracker_null_context_switch(wtd->user_data);
-
-                       gchar *id = atspi_accessible_get_unique_id(top_window, NULL);
-                       DEBUG("top window: %s", id);
-                       g_free(id);
+                       _switch_context_to_non_keyboard_top(wtd);
                }
        } else {
                /* The removed window could be under the keyboard window,
@@ -354,6 +371,31 @@ static void _window_remove(WindowTrackerData *wtd, AtspiAccessible *window)
        _window_stack_print(wtd);
 }
 
+static void _active_window_set(WindowTrackerData *wtd, AtspiAccessible *window, Eina_Bool is_active)
+{
+       WindowInfo *wi;
+       Eina_List *l;
+       EINA_LIST_REVERSE_FOREACH(wtd->window_infos, l, wi) {
+               if (!wi) continue;
+               if (atspi_accessible_is_equal(wi->window, window)) {
+                       wi->is_focused = is_active;
+                       break;
+               }
+       }
+
+       if (wtd->user_cb) {
+               if (is_active)
+                       wtd->user_cb(wtd->user_data, window);
+               else
+                       _switch_context_to_non_keyboard_top(wtd);
+       }
+
+       gchar *id = atspi_accessible_get_unique_id(window, NULL);
+       DEBUG("active window set: %s[%d]", id, is_active);
+       g_free(id);
+       _window_stack_print(wtd);
+}
+
 static void _on_atspi_window_cb(AtspiEvent *event, void *user_data)
 {
        WindowTrackerData *wtd = user_data;
@@ -379,7 +421,10 @@ static void _on_atspi_window_cb(AtspiEvent *event, void *user_data)
                        window_tracker_keyboard_window_append(wtd);
                        goto end;
                }
-               _window_append(wtd, event->source, EINA_TRUE, EINA_FALSE, window_activate_info_type);
+               _window_append(wtd, event->source, EINA_TRUE, EINA_FALSE, window_activate_info_type, EINA_TRUE);
+               _active_window_set(wtd, event->source, EINA_TRUE);
+       } else if (!g_strcmp0(event->type, "window:deactivate")) {
+               _active_window_set(wtd, event->source, EINA_FALSE);
        } else if (!g_strcmp0(event->type, "window:destroy")) {
                DEBUG("Remove Window");
                _window_remove(wtd, event->source);
@@ -392,7 +437,7 @@ static void _on_atspi_window_cb(AtspiEvent *event, void *user_data)
                if (event->detail1) { /* Visible */
                        if (role == ATSPI_ROLE_WINDOW || keyboard_is) {
                                DEBUG("Append %sWindow", keyboard_is ? "Keyboard " : "");
-                               _window_append(wtd, event->source, !keyboard_is, keyboard_is, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED);
+                               _window_append(wtd, event->source, !keyboard_is, keyboard_is, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED, EINA_TRUE);
                        }
                } else { /* Invisible */
                        if (role == ATSPI_ROLE_WINDOW || keyboard_is) {
@@ -405,7 +450,7 @@ static void _on_atspi_window_cb(AtspiEvent *event, void *user_data)
                AtspiRole role = atspi_accessible_get_role(event->source, NULL);
                if (role == ATSPI_ROLE_FRAME) {
                        if (event->detail1)
-                               _window_append(wtd, event->source, EINA_TRUE, EINA_FALSE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED);
+                               _window_append(wtd, event->source, EINA_TRUE, EINA_FALSE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED, EINA_TRUE);
                        else
                                _window_remove(wtd, event->source);
                }
@@ -420,9 +465,7 @@ static void _active_window_append(WindowTrackerData *wtd)
        DEBUG("START");
        AtspiAccessible *activeWindow = atspi_get_active_window();
        if (activeWindow) {
-               //TODO: probably need to use other condition
-               DEBUG("active window: %p", activeWindow);
-               _window_append(wtd, activeWindow, EINA_TRUE, EINA_FALSE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED);
+               _active_window_set(wtd, activeWindow, EINA_TRUE);
                g_object_unref(activeWindow);
        }
 }
@@ -459,7 +502,7 @@ atspi_dbus_filter(DBusConnection *bus, DBusMessage *message, void *data)
                        DBUS_TYPE_STRING, &old,
                        DBUS_TYPE_STRING, &new,
                        DBUS_TYPE_INVALID)) {
-                       if (*old != '\0' && *new == '\0') {
+                       if (*old != '\0' && *new == '\0' && !g_strcmp0(old, name)) {
                                _remove_window_under_bus(wtd, old);
                        }
                }
@@ -520,7 +563,6 @@ WindowTrackerData *window_tracker_init(void)
 
        _name_owner_changed_listener_register(wtd);
 
-       wtd->last_active_win = NULL;
        wtd->top_win = NULL;
        wtd->window_infos = NULL;
        wtd->keyboard_window = NULL;
@@ -597,7 +639,7 @@ void window_tracker_active_window_request(WindowTrackerData *wtd)
                DEBUG("Foreground windows: %d", windows->len);
                for (i = 0; i < windows->len; i++) {
                        window = g_array_index(windows, AtspiAccessible *, i);
-                       _window_append(wtd, window, EINA_TRUE, EINA_FALSE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED);
+                       _window_append(wtd, window, EINA_TRUE, EINA_FALSE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED, EINA_FALSE);
                }
                for (i = 0; i< windows->len; ++i) {
                        g_object_unref(g_array_index(windows, AtspiAccessible*, i));
@@ -615,18 +657,22 @@ WindowInfo *window_tracker_top_window_info_get(WindowTrackerData *wtd)
        return eina_list_last_data_get(wtd->window_infos);
 }
 
-AtspiAccessible *window_tracker_top_window_get(WindowTrackerData *wtd)
+AtspiAccessible *window_tracker_top_window_get(WindowTrackerData *wtd, Eina_Bool include_keyboard)
 {
-       return _top_window_get(wtd);
+       return _top_window_get(wtd, include_keyboard);
 }
 
-void window_tracker_window_append(WindowTrackerData *wtd, AtspiAccessible *window)
+void window_tracker_window_append(WindowTrackerData *wtd, AtspiAccessible *window, Eina_Bool is_focused)
 {
        if (atspi_accessible_is_equal(wtd->keyboard_window, window)) {
                window_tracker_keyboard_window_append(wtd);
                return;
        }
-       _window_append(wtd, window, EINA_TRUE, EINA_FALSE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED);
+       _window_append(wtd, window, EINA_TRUE, EINA_FALSE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED, is_focused);
+
+       // is_focused is true when this is called from focus_widget. Hence, we should switch focus to the given window.
+       if (is_focused)
+               _active_window_set(wtd, window, EINA_TRUE);
 }
 
 void window_tracker_window_remove(WindowTrackerData *wtd, AtspiAccessible *window)
@@ -691,7 +737,7 @@ void window_tracker_keyboard_window_remove(WindowTrackerData *wtd)
 
 void window_tracker_keyboard_window_append(WindowTrackerData *wtd)
 {
-       _window_append(wtd, wtd->keyboard_window, FALSE, EINA_TRUE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED);
+       _window_append(wtd, wtd->keyboard_window, FALSE, EINA_TRUE, ACCESSIBLE_WINDOW_ACTIVATE_INFO_DEFAULT_LABEL_ENABLED, EINA_TRUE);
 }
 
 WindowActivateInfoType window_tracker_window_activate_info_type_get(WindowTrackerData *wtd, AtspiAccessible *window)