build: get doxygen generating selective
[platform/core/uifw/aurum.git] / libaurum / src / AccessibleWatcher.cc
1
2 #include "AccessibleWatcher.h"
3
4 #include <string.h>
5 #include <iostream>
6 #include <utility>
7
8 #include <loguru.hpp>
9
10 AtspiEventListener *AccessibleWatcher::listener = nullptr;
11
12
13
14 static bool iShowingNode(AtspiAccessible *node)
15 {
16     char *name = NULL;
17     if (node) name = atspi_accessible_get_name(node, NULL);
18     else return false;
19
20     LOG_SCOPE_F(INFO, "isShowing %s", name);
21     auto stateSet = make_gobj_unique(atspi_accessible_get_state_set(node));
22     auto states = make_garray_unique(atspi_state_set_get_states(stateSet.get()));
23
24     if (atspi_state_set_contains(stateSet.get(), ATSPI_STATE_ACTIVE)
25         && atspi_state_set_contains(stateSet.get(), ATSPI_STATE_SHOWING)) {
26         LOG_F(INFO, "active and showing %p %s", node, name);
27         free(name);
28         return true;
29     }
30     free(name);
31     return false;
32 }
33
34 static std::vector<AtspiAccessible *>
35 findActiveNode(AtspiAccessible *node, int depth,
36                                        int max_depth)
37 {
38     std::vector<AtspiAccessible *> ret{};
39     if (depth >= max_depth) return ret;
40
41     if (iShowingNode(node)) {
42         g_object_ref(node);
43         char *name = atspi_accessible_get_name(node, NULL);
44         if (name) {
45             LOG_SCOPE_F(INFO, "%s", name);
46             free(name);
47         }
48         ret.push_back(node);
49         return ret;
50     }
51
52     int nchild = atspi_accessible_get_child_count(node, NULL);
53     for (int i = 0; i < nchild; i++) {
54         auto child = make_gobj_unique(atspi_accessible_get_child_at_index(node, i, NULL));
55         std::vector<AtspiAccessible *> childRet = findActiveNode(child.get(), depth + 1, max_depth);
56         ret.insert(ret.end(), childRet.begin(), childRet.end());
57     }
58
59     return ret;
60 }
61
62 AccessibleWatcher::AccessibleWatcher() : mActivatedWindowList{}, mWindowSet{}
63 {
64     GVariant *enabled_variant = nullptr, *result = nullptr;
65     GError *  error = nullptr;
66     atspi_set_main_context (g_main_context_default ());
67     atspi_init();
68
69     listener =
70         atspi_event_listener_new(AccessibleWatcher::onAtspiWindowEvent, this, NULL);
71     atspi_event_listener_register(listener, "window:create", NULL);
72     atspi_event_listener_register(listener, "window:destroy", NULL);
73     atspi_event_listener_register(listener, "window:activate", NULL);
74     atspi_event_listener_register(listener, "window:deactivate", NULL);
75     atspi_event_listener_register(listener, "object:", NULL);
76
77     mDbusProxy = g_dbus_proxy_new_for_bus_sync(
78         G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE,
79         NULL, /* GDBusInterfaceInfo */
80         "org.a11y.Bus", "/org/a11y/bus", "org.freedesktop.DBus.Properties",
81         NULL, &error);
82
83     enabled_variant = g_variant_new_boolean(true);
84     result = g_dbus_proxy_call_sync(
85         mDbusProxy, "Set",
86         g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
87         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
88
89     g_variant_unref(enabled_variant);
90     g_variant_unref(result);
91
92 }
93
94 AccessibleWatcher::~AccessibleWatcher()
95 {
96     GVariant *enabled_variant = nullptr, *result = nullptr;
97     GError *  error = nullptr;
98
99     enabled_variant = g_variant_new_boolean(false);
100     result = g_dbus_proxy_call_sync(
101         mDbusProxy, "Set",
102         g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
103         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
104
105
106     for (auto it = mAccessibleNode.begin(); it != mAccessibleNode.end(); ++it) {
107         g_object_unref(it->first);
108         delete it->second;
109     }
110     atspi_event_listener_deregister(listener, "window:", NULL);
111     atspi_event_listener_deregister(listener, "object:", NULL);
112
113     g_object_unref(listener);
114     g_object_unref(mDbusProxy);
115     g_variant_unref(enabled_variant);
116     g_variant_unref(result);
117
118     atspi_event_quit();
119     atspi_exit();
120 }
121
122 std::unique_ptr<AccessibleNode> AccessibleWatcher::getRootNode() const
123 {
124     auto node = make_gobj_unique(atspi_get_desktop(0));
125     auto accNode = AccessibleNode::get(node.get());
126     if(node.get()) g_object_unref(node.get());
127     return accNode;
128 }
129
130 std::vector<std::unique_ptr<AccessibleNode>> AccessibleWatcher::getTopNode() const
131 {
132     AtspiAccessible *topNode = nullptr, *activeNode = nullptr;
133     std::vector<std::unique_ptr<AccessibleNode>> ret;
134
135     {
136         std::unique_lock<std::mutex> lock(mLock);
137         if (!mActivatedWindowList.empty()) {
138             topNode = mActivatedWindowList.front();
139             std::list<AtspiAccessible *>::const_iterator iterator;
140             for (iterator = mActivatedWindowList.begin(); iterator != mActivatedWindowList.end(); ++iterator){
141                 if (*iterator && iShowingNode(*iterator)) {
142                     AtspiAccessible *child = atspi_accessible_get_application(*iterator, NULL);
143                     if (child) {
144                         auto tmpNode = make_gobj_unique(child);
145                         auto node =  AccessibleNode::get(tmpNode.get());
146                         if (tmpNode.get()) g_object_unref(tmpNode.get());
147                         ret.push_back(std::move(node));
148                     }
149                 }
150             }
151             return ret;
152         }
153     }
154
155     LOG_F(INFO, "Mo activated window node or Invisible acticated window / topNdoe(%p)", topNode);
156     LOG_F(INFO, "Trying fallback logic");
157
158     auto rootNode = make_gobj_unique(atspi_get_desktop(0));
159
160     if (rootNode) {
161         std::vector<AtspiAccessible*> activeNodes = findActiveNode(rootNode.get(), 0, 2);
162         if (!activeNodes.empty()) {
163             std::vector<AtspiAccessible*>::const_iterator iterator;
164             for (iterator = activeNodes.begin(); iterator != activeNodes.end(); ++iterator){
165                 auto tmpNode = make_gobj_unique(atspi_accessible_get_application(*iterator, NULL));
166                 auto node = AccessibleNode::get(tmpNode.get());
167                 if (tmpNode.get()) g_object_unref(tmpNode.get());
168                 g_object_unref(*iterator);
169                 ret.push_back(std::move(node));
170             }
171         } else {
172             auto node = AccessibleNode::get(rootNode.get());
173             if (rootNode.get()) g_object_unref(rootNode.get());
174             ret.push_back(std::move(node));
175         }
176     }
177     return ret;
178 }
179
180 void AccessibleWatcher::onAtspiWindowEvent(AtspiEvent *event, void *user_data)
181 {
182     char *name = NULL, *pname = NULL;
183     IAtspiEvents *instance = (IAtspiEvents *)user_data;
184
185     if (!event->source)
186     {
187         LOG_F(INFO, "event->source is NULL. Skip event handling");
188         return;
189     }
190
191     auto p = make_gobj_unique(atspi_accessible_get_parent(event->source, NULL));
192
193     name = atspi_accessible_get_name(event->source, NULL);
194     if (p) pname = atspi_accessible_get_name(p.get(), NULL);
195
196      LOG_SCOPE_F(INFO, "event:%s, src:%p(%s), p:%p(%s), d1:%p d2:%p instance:%p",
197                  event->type, event->source, name, p.get(), pname, event->detail1,
198                  event->detail2, instance);
199
200     if (!strcmp(event->type, "window:activate")) {
201         instance->onWindowActivated(
202             static_cast<AtspiAccessible *>(event->source),
203             static_cast<WindowActivateInfoType>(event->detail1));
204     } else if (!strcmp(event->type, "window:deactivate")) {
205         instance->onWindowDeactivated(static_cast<AtspiAccessible *>(event->source));
206     } else if (!strcmp(event->type, "window:create")) {
207         instance->onWindowCreated(static_cast<AtspiAccessible *>(event->source));
208     } else if (!strcmp(event->type, "window:destroy")) {
209         instance->onWindowDestroyed(static_cast<AtspiAccessible *>(event->source));
210     } else if (!strcmp(event->type, "object:state-changed:visible")) {
211         instance->onVisibilityChanged(
212             static_cast<AtspiAccessible *>(event->source),
213             (event->detail1 != 0));
214     } else if (!strcmp(event->type, "object:state-changed:defunct")) {
215         instance->onObjectDefunct(
216             static_cast<AtspiAccessible *>(event->source));
217     }
218     if (name) free(name);
219     if (pname) free(pname);
220 }
221
222 void AccessibleWatcher::printDbgInformation() const
223 {
224     LOG_SCOPE_F(INFO, "%d %d", mActivatedWindowList.size(),  mWindowSet.size());
225
226     for (auto iter = mActivatedWindowList.begin(); iter != mActivatedWindowList.end(); ++iter) {
227         LOG_F(INFO, "%p", *iter);
228     }
229         LOG_F(INFO, "-----------");
230
231     for (auto iter = mWindowSet.begin(); iter != mWindowSet.end(); ++iter) {
232         LOG_F(INFO, "%p", *iter);
233     }
234 }
235
236 const AccessibleWatcher *AccessibleWatcher::getInstance()
237 {
238     static AccessibleWatcher *mInstance = nullptr;
239     if (!mInstance) mInstance = new AccessibleWatcher();
240     return mInstance;
241 }
242
243 void AccessibleWatcher::clearWindowList() const
244 {
245     std::unique_lock<std::mutex> lock(mLock);
246     while (!mActivatedWindowList.empty()) {
247         AtspiAccessible *n = mActivatedWindowList.front();
248         mActivatedWindowList.pop_front();
249         g_object_unref(n);
250     }
251
252     mWindowSet.clear();
253 }
254
255 bool AccessibleWatcher::removeFromActivatedList(AtspiAccessible *node)
256 {
257     mActivatedWindowList.remove_if([&](auto &n) { return n == node; });
258     return true;
259 }
260
261 bool AccessibleWatcher::addToActivatedList(AtspiAccessible *node)
262 {
263     mActivatedWindowList.remove_if([&](auto &n) { return n == node; });
264     mActivatedWindowList.push_front(node);
265
266     auto iter = mWindowSet.find(node);
267     if ( iter == mWindowSet.end()) mWindowSet.insert(node);
268     return true;
269 }
270
271 bool AccessibleWatcher::removeFromWindowSet(AtspiAccessible *node)
272 {
273     removeFromActivatedList(node);
274     auto iter = mWindowSet.find(node);
275     if ( iter != mWindowSet.end()){
276         mWindowSet.erase(node);
277         return true;
278     }
279     return false;
280 }
281
282 bool AccessibleWatcher::addToWindowSet(AtspiAccessible *node)
283 {
284     auto iter = mWindowSet.find(node);
285     if ( iter == mWindowSet.end()){
286         mWindowSet.insert(node);
287         return true;
288     }
289     return false;
290 }
291
292 void AccessibleWatcher::onWindowActivated(AtspiAccessible *      node,
293                             WindowActivateInfoType type)
294 {
295     std::unique_lock<std::mutex> lock(mLock);
296     addToActivatedList(node);
297     return;
298 }
299
300 void AccessibleWatcher::onWindowDeactivated(AtspiAccessible *node)
301 {
302     std::unique_lock<std::mutex> lock(mLock);
303     removeFromActivatedList(node);
304     return;
305 }
306
307 void AccessibleWatcher::onWindowCreated(AtspiAccessible *node)
308 {
309     std::unique_lock<std::mutex> lock(mLock);
310     addToWindowSet(node);
311 }
312
313 void AccessibleWatcher::onWindowDestroyed(AtspiAccessible *node)
314 {
315     std::unique_lock<std::mutex> lock(mLock);
316     removeFromWindowSet(node);
317 }
318
319 void AccessibleWatcher::onVisibilityChanged(AtspiAccessible *node, bool visible)
320 {
321 }
322
323 void AccessibleWatcher::onObjectDefunct(AtspiAccessible *node)
324 {
325     LOG_SCOPE_F(INFO, "object defuncted %p", node);
326 }