2 * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
4 * This file is a modified version of BSD licensed file and
5 * licensed under the Flora License, Version 1.1 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://floralicense.org/license/
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an AS IS BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * Please, see the LICENSE file for the original copyright owner and
21 #include "app_tracker.h"
26 AtspiAccessible *base_root;
27 AtspiAccessible *root;
34 AppTrackerEventCB func;
35 AtspiAccessible *root;
39 #define APP_TRACKER_INVACTIVITY_TIMEOUT 200
41 static int _init_count;
43 static AtspiEventListener *_listener;
46 _is_descendant(AtspiAccessible *ancestor, AtspiAccessible *descendant)
53 if (ancestor == descendant) return 1;
55 while ((descendant = atspi_accessible_get_parent(descendant, NULL)) != NULL);
62 static Eina_Bool _object_has_modal_state(AtspiAccessible *obj)
67 Eina_Bool ret = EINA_FALSE;
69 AtspiStateSet *ss = atspi_accessible_get_state_set(obj);
71 if (atspi_state_set_contains(ss, ATSPI_STATE_MODAL))
77 static Eina_Bool _object_has_showing_state(AtspiAccessible *obj)
82 Eina_Bool ret = EINA_FALSE;
84 AtspiStateSet *ss = atspi_accessible_get_state_set(obj);
86 if (atspi_state_set_contains(ss, ATSPI_STATE_SHOWING))
93 _subtree_callbacks_call(SubTreeRootData *std)
97 EventCallbackData *ecd;
99 for (l = std->callbacks; l != NULL; l = l->next)
102 ecd->func(std->root, ecd->user_data);
108 _on_timeout_cb(gpointer user_data)
111 SubTreeRootData *std = user_data;
113 _subtree_callbacks_call(std);
119 static void _print_event_object_info(const AtspiEvent *event)
121 gchar *name = atspi_accessible_get_name(event->source, NULL),
122 *role = atspi_accessible_get_role_name(event->source, NULL);
124 DEBUG("signal:%s, name: %s, role: %s, detail1:%i, detail2: %i", event->type, role, name, event->detail1, event->detail2);
130 _on_atspi_event_cb(const AtspiEvent *event)
134 SubTreeRootData *std;
139 ERROR("empty event source");
143 if ((atspi_accessible_get_role(event->source, NULL) == ATSPI_ROLE_DESKTOP_FRAME))
148 _print_event_object_info(event);
150 for (l = _roots; l != NULL; l = l->next)
154 if (!_object_has_showing_state(std->root) && std->base_root)
156 std->root = std->base_root;
157 std->base_root = NULL;
160 if (_is_descendant(std->root, event->source))
163 g_source_remove(std->timer);
165 DEBUG("Before Checking if modal is showing");
167 if (!strcmp("object:state-changed:showing",event->type))
170 DEBUG("Object is showing");
172 if (_object_has_modal_state(event->source))
174 DEBUG("Object is modal");
176 std->base_root = std->root;
177 std->root = event->source;
180 std->timer = g_timeout_add(APP_TRACKER_INVACTIVITY_TIMEOUT, _on_timeout_cb, std);
186 _app_tracker_init_internal(void)
189 _listener = atspi_event_listener_new_simple(_on_atspi_event_cb, NULL);
191 atspi_event_listener_register(_listener, "object:state-changed:showing", NULL);
192 atspi_event_listener_register(_listener, "object:state-changed:visible", NULL);
193 atspi_event_listener_register(_listener, "object:state-changed:defunct", NULL);
194 atspi_event_listener_register(_listener, "object:bounds-changed", NULL);
195 atspi_event_listener_register(_listener, "object:visible-data-changed", NULL);
201 _free_callbacks(gpointer data)
207 _free_rootdata(gpointer data)
209 SubTreeRootData *std = data;
210 g_list_free_full(std->callbacks, _free_callbacks);
212 g_source_remove(std->timer);
217 _app_tracker_shutdown_internal(void)
219 atspi_event_listener_deregister(_listener, "object:state-changed:showing", NULL);
220 atspi_event_listener_deregister(_listener, "object:state-changed:visible", NULL);
221 atspi_event_listener_deregister(_listener, "object:bounds-changed", NULL);
222 atspi_event_listener_deregister(_listener, "object:state-changed:defunct", NULL);
223 atspi_event_listener_deregister(_listener, "object:visible-data-changed", NULL);
225 g_object_unref(_listener);
228 g_list_free_full(_roots, _free_rootdata);
232 int app_tracker_init(void)
236 if (_app_tracker_init_internal()) return -1;
237 return ++_init_count;
240 void app_tracker_shutdown(void)
242 if (_init_count == 1)
243 _app_tracker_shutdown_internal();
244 if (--_init_count < 0) _init_count = 0;
247 void app_tracker_callback_register(AtspiAccessible *app, AppTrackerEventCB cb, void *user_data)
250 SubTreeRootData *rd = NULL;
251 EventCallbackData *cd;
254 if (!_init_count || !cb)
257 for (l = _roots; l != NULL; l = l->next)
260 if (((SubTreeRootData*)l->data)->root == app)
269 rd = g_new(SubTreeRootData, 1);
271 rd->base_root = NULL;
272 rd->callbacks = NULL;
274 _roots = g_list_append(_roots, rd);
277 cd = g_new(EventCallbackData, 1);
279 cd->user_data = user_data;
281 rd->callbacks = g_list_append(rd->callbacks, cd);
285 void app_tracker_callback_unregister(AtspiAccessible *app, AppTrackerEventCB cb, void *user_data)
289 EventCallbackData *ecd;
290 SubTreeRootData *std = NULL;
292 for (l = _roots; l != NULL; l = l->next)
294 if (((SubTreeRootData*)l->data)->root == app || ((SubTreeRootData*)l->data)->base_root == app)
303 for (l = std->callbacks; l != NULL; l = l->next)
306 if ((ecd->func == cb) && (ecd->user_data == user_data))
308 std->callbacks = g_list_delete_link(std->callbacks, l);
315 if (std->timer) g_source_remove(std->timer);
316 _roots = g_list_remove(_roots, std);