mobile-lua: add additional LABELLED_BY relation
[profile/tv/apps/native/screen-reader.git] / src / window_tracker.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
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
7  *
8  *     http://floralicense.org/license/
9  *
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.
15  */
16
17 #include <string.h>
18 #include "window_tracker.h"
19 #include "logger.h"
20
21 #ifdef X11_ENABLED
22 #include <Ecore_X.h>
23 #include <Ecore_X_Atoms.h>
24 #endif
25
26 static Window_Tracker_Cb user_cb;
27 static void *user_data;
28 static AtspiEventListener *listener;
29 static AtspiAccessible *last_active_win;
30
31 static void _on_atspi_window_cb(const AtspiEvent * event)
32 {
33         DEBUG("Event: %s: %s", event->type, atspi_accessible_get_name(event->source, NULL));
34
35         if (!strcmp(event->type, "window:activate") && last_active_win != event->source)        //if we got activate 2 times
36         {
37
38                 if (user_cb)
39                         user_cb(user_data, event->source);
40                 last_active_win = event->source;
41         }
42 }
43
44 static AtspiAccessible *_get_active_win(void)
45 {
46         DEBUG("START");
47         int i, j, desktop_children_count, app_children_count;
48         last_active_win = NULL;
49         AtspiAccessible *desktop = atspi_get_desktop(0);
50         if (!desktop) {
51                 ERROR("DESKTOP NOT FOUND");
52                 return NULL;
53         }
54
55         unsigned int active_window_pid = 0;
56 #ifdef X11_ENABLED
57         Ecore_X_Window focus_window = ecore_x_window_focus_get();
58
59         if (focus_window) {
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);
67         }
68 #endif
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);
72
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);
75                 else
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;
83
84                         g_object_unref(states);
85                         g_object_unref(win);
86
87                         if (last_active_win)
88                                 break;
89                 }
90                 g_object_unref(app);
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
94                         i = -1;
95                         active_window_pid = 0;
96                 }
97                 if (last_active_win)
98                         break;
99         }
100         g_object_unref(desktop);
101         DEBUG("END last_active_win: %p", last_active_win);
102         return last_active_win;
103 }
104
105 void window_tracker_init(void)
106 {
107         DEBUG("START");
108         listener = atspi_event_listener_new_simple(_on_atspi_window_cb, NULL);
109         atspi_event_listener_register(listener, "window:activate", NULL);
110 }
111
112 void window_tracker_shutdown(void)
113 {
114         DEBUG("START");
115         atspi_event_listener_deregister(listener, "window:activate", NULL);
116         g_object_unref(listener);
117         listener = NULL;
118         user_cb = NULL;
119         user_data = NULL;
120         last_active_win = NULL;
121 }
122
123 void window_tracker_register(Window_Tracker_Cb cb, void *data)
124 {
125         DEBUG("START");
126         user_cb = cb;
127         user_data = data;
128 }
129
130 void window_tracker_active_window_request(void)
131 {
132         DEBUG("START");
133         _get_active_win();
134         if (user_cb)
135                 user_cb(user_data, last_active_win);
136 }