2 * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Flora License, Version 1.1 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "window_tracker.h"
23 #include <Ecore_X_Atoms.h>
26 static Window_Tracker_Cb user_cb;
27 static void *user_data;
28 static AtspiEventListener *listener;
29 static AtspiAccessible *last_active_win;
31 static void _on_atspi_window_cb(const AtspiEvent * event)
33 DEBUG("Event: %s: %s", event->type, atspi_accessible_get_name(event->source, NULL));
35 if (!strcmp(event->type, "window:activate") && last_active_win != event->source) //if we got activate 2 times
39 user_cb(user_data, event->source);
40 last_active_win = event->source;
44 static AtspiAccessible *_get_active_win(void)
47 int i, j, desktop_children_count, app_children_count;
48 last_active_win = NULL;
49 AtspiAccessible *desktop = atspi_get_desktop(0);
51 ERROR("DESKTOP NOT FOUND");
55 unsigned int active_window_pid = 0;
57 Ecore_X_Window focus_window = ecore_x_window_focus_get();
60 //invoking atspi_accessible_get_child_count for non active apps results in very long screen-reader startup
61 //not active apps have low priority and dbus calls take a lot of time (a few hundred ms per call)
62 //Hence we first try to determine accessible window using pid of currently focused window
63 if (!ecore_x_window_prop_card32_get(focus_window, ECORE_X_ATOM_NET_WM_PID, &active_window_pid, 1))
64 active_window_pid = 0;
65 if (active_window_pid)
66 DEBUG("First we will try filter apps by PID: %i", active_window_pid);
69 desktop_children_count = atspi_accessible_get_child_count(desktop, NULL);
70 for (i = 0; i < desktop_children_count; i++) {
71 AtspiAccessible *app = atspi_accessible_get_child_at_index(desktop, i, NULL);
73 if (active_window_pid == 0 || active_window_pid == atspi_accessible_get_process_id(app, NULL))
74 app_children_count = atspi_accessible_get_child_count(app, NULL);
76 app_children_count = 0;
77 for (j = 0; j < app_children_count; j++) {
78 AtspiAccessible *win = atspi_accessible_get_child_at_index(app, j, NULL);
79 AtspiStateSet *states = atspi_accessible_get_state_set(win);
80 AtspiRole role = atspi_accessible_get_role(win, NULL);
81 if ((atspi_state_set_contains(states, ATSPI_STATE_ACTIVE)) && (role == ATSPI_ROLE_WINDOW))
82 last_active_win = win;
84 g_object_unref(states);
91 if (active_window_pid > 0 && (i == desktop_children_count - 1)) {
92 // we are in last iteration and we should fall back to normal iteration over child windows
93 // without filtering by focus windows PID
95 active_window_pid = 0;
100 g_object_unref(desktop);
101 DEBUG("END last_active_win: %p", last_active_win);
102 return last_active_win;
105 void window_tracker_init(void)
108 listener = atspi_event_listener_new_simple(_on_atspi_window_cb, NULL);
109 atspi_event_listener_register(listener, "window:activate", NULL);
112 void window_tracker_shutdown(void)
115 atspi_event_listener_deregister(listener, "window:activate", NULL);
116 g_object_unref(listener);
120 last_active_win = NULL;
123 void window_tracker_register(Window_Tracker_Cb cb, void *data)
130 void window_tracker_active_window_request(void)
135 user_cb(user_data, last_active_win);