libaurum: apply smart pointer wider and extract impl out
[platform/core/uifw/aurum.git] / libaurum / src / Impl / Accessibility / AtspiAccessibleWatcher.cc
1 #include "AtspiAccessibleWatcher.h"
2
3 #include "AtspiAccessibleApplication.h"
4 #include "AtspiAccessibleWindow.h"
5 #include "AtspiAccessibleNode.h"
6
7 #include <algorithm>
8
9 #include <loguru.hpp>
10
11 AtspiEventListener *AtspiAccessibleWatcher::listener = nullptr;
12
13 static bool iShowingNode(AtspiAccessible *node)
14 {
15     char *name = NULL;
16     if (node) name = atspi_accessible_get_name(node, NULL);
17     else return false;
18
19     LOG_SCOPE_F(INFO, "isShowing %s", name);
20     auto stateSet = atspi_accessible_get_state_set(node);
21     auto states = atspi_state_set_get_states(stateSet);
22
23     if (atspi_state_set_contains(stateSet, ATSPI_STATE_ACTIVE)
24         && atspi_state_set_contains(stateSet, ATSPI_STATE_SHOWING)) {
25         LOG_F(INFO, "active and showing %p %s", node, name);
26         free(name);
27         // TODO : free states and stateSet
28         return true;
29     }
30     free(name);
31     // TODO : free states and stateSet
32     return false;
33 }
34
35 static std::vector<AtspiAccessible *>
36 findActiveNode(AtspiAccessible *node, int depth,
37                                        int max_depth)
38 {
39     LOG_SCOPE_F(INFO, "findActiveNode %p %d/%d", node, depth, max_depth);
40
41     std::vector<AtspiAccessible *> ret{};
42
43     if (iShowingNode(node)) {
44         g_object_ref(node);
45         char *name = atspi_accessible_get_name(node, NULL);
46         if (name) {
47             LOG_SCOPE_F(INFO, "%s", name);
48             free(name);
49         }
50         ret.push_back(node);
51         return ret;
52     }
53
54     if (depth >= max_depth) return ret;
55
56     int nchild = atspi_accessible_get_child_count(node, NULL);
57     if (nchild <= 0) return ret;
58
59     LOG_F(INFO, "findActiveNode node %p has %d children", node, nchild);
60     for (int i = 0; i < nchild; i++) {
61         AtspiAccessible* child = atspi_accessible_get_child_at_index(node, i, NULL);
62         LOG_F(INFO, "a child found @ %d : %p", i, child);
63         std::vector<AtspiAccessible *> childRet = findActiveNode(child, depth + 1, max_depth);
64         ret.insert(ret.end(), childRet.begin(), childRet.end());
65         g_object_unref(child);
66     }
67
68     return ret;
69 }
70
71 AtspiAccessibleWatcher::AtspiAccessibleWatcher()
72 : mDbusProxy{nullptr}, mLock{}
73 {
74     GVariant *enabled_variant = nullptr, *result = nullptr;
75     GError *  error = nullptr;
76     atspi_set_main_context (g_main_context_default ());
77     atspi_init();
78
79     listener =
80         atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiWindowEvent, this, NULL);
81     LOG_SCOPE_F(INFO, "WKWK init this:%p", this);
82
83     atspi_event_listener_register(listener, "window:create", NULL);
84     atspi_event_listener_register(listener, "window:destroy", NULL);
85     atspi_event_listener_register(listener, "window:activate", NULL);
86     atspi_event_listener_register(listener, "window:deactivate", NULL);
87     atspi_event_listener_register(listener, "object:", NULL);
88
89     mDbusProxy = g_dbus_proxy_new_for_bus_sync(
90         G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE,
91         NULL, /* GDBusInterfaceInfo */
92         "org.a11y.Bus", "/org/a11y/bus", "org.freedesktop.DBus.Properties",
93         NULL, &error);
94
95     enabled_variant = g_variant_new_boolean(true);
96     result = g_dbus_proxy_call_sync(
97         mDbusProxy, "Set",
98         g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
99         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
100
101     g_variant_unref(enabled_variant);
102     g_variant_unref(result);
103 }
104
105 AtspiAccessibleWatcher::~AtspiAccessibleWatcher()
106 {
107     GVariant *enabled_variant = nullptr, *result = nullptr;
108     GError *  error = nullptr;
109
110     enabled_variant = g_variant_new_boolean(false);
111     result = g_dbus_proxy_call_sync(
112         mDbusProxy, "Set",
113         g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
114         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
115
116     atspi_event_listener_deregister(listener, "window:", NULL);
117     atspi_event_listener_deregister(listener, "object:", NULL);
118
119     g_object_unref(listener);
120     g_object_unref(mDbusProxy);
121     g_variant_unref(enabled_variant);
122     g_variant_unref(result);
123
124     atspi_event_quit();
125     atspi_exit();
126 }
127
128
129 void AtspiAccessibleWatcher::onAtspiWindowEvent(AtspiEvent *event, void *user_data)
130 {
131     char *name = NULL, *pname = NULL;
132     AtspiAccessibleWatcher *instance = (AtspiAccessibleWatcher *)user_data;
133
134     if (!event->source)
135     {
136         LOG_F(INFO, "event->source is NULL. Skip event handling");
137         return;
138     }
139
140
141     AtspiAccessible *parent = atspi_accessible_get_parent(event->source, NULL);
142
143     name = atspi_accessible_get_name(event->source, NULL);
144     if (parent) {
145         pname = atspi_accessible_get_name(parent, NULL);
146         g_object_unref(parent);
147     }
148
149      LOG_SCOPE_F(INFO, "event:%s, src:%p(%s), p:%p(%s), d1:%p d2:%p instance:%p",
150                  event->type, event->source, name, parent, pname, event->detail1,
151                  event->detail2, instance);
152
153     if (!strcmp(event->type, "window:activate")) {
154         instance->onWindowActivated(
155             static_cast<AtspiAccessible *>(event->source),
156             static_cast<WindowActivateInfoType>(event->detail1));
157     } else if (!strcmp(event->type, "window:deactivate")) {
158         instance->onWindowDeactivated(static_cast<AtspiAccessible *>(event->source));
159     } else if (!strcmp(event->type, "window:create")) {
160         instance->onWindowCreated(static_cast<AtspiAccessible *>(event->source));
161     } else if (!strcmp(event->type, "window:destroy")) {
162         instance->onWindowDestroyed(static_cast<AtspiAccessible *>(event->source));
163     } else if (!strcmp(event->type, "object:state-changed:visible")) {
164         instance->onVisibilityChanged(
165             static_cast<AtspiAccessible *>(event->source),
166             (event->detail1 != 0));
167     } else if (!strcmp(event->type, "object:state-changed:defunct")) {
168         instance->onObjectDefunct(
169             static_cast<AtspiAccessible *>(event->source));
170     }
171     if (name) free(name);
172     if (pname) free(pname);
173
174 //    instance->print_debug();
175 }
176
177 void AtspiAccessibleWatcher::print_debug()
178 {
179     LOG_F(INFO, "activatewindowlist-------------------");
180     std::for_each(mActivatedWindowList.begin(), mActivatedWindowList.end(), [](auto acc){
181         LOG_F(INFO, "child:%p", acc);
182     });
183
184     LOG_F(INFO, "mActivatedApplicationList--------------------------");
185     std::for_each(mActivatedApplicationList.begin(), mActivatedApplicationList.end(), [](auto acc){
186         LOG_F(INFO, "child:%p", acc);
187     });
188
189     LOG_F(INFO, "mWindowSet------------------------------");
190     std::for_each(mWindowSet.begin(), mWindowSet.end(), [](auto acc){
191         LOG_F(INFO, "child:%p", acc);
192     });
193     LOG_F(INFO, "------------------------------");
194
195 }
196
197 void AtspiAccessibleWatcher::onWindowActivated(AtspiAccessible *node,
198                             WindowActivateInfoType type)
199 {
200     //std::unique_lock<std::mutex> lock(mLock);
201     LOG_SCOPE_F(INFO, "onWindowActivated obj:%p", node);
202     //addToActivatedList((node));
203     return;
204 }
205
206 void AtspiAccessibleWatcher::onWindowDeactivated(AtspiAccessible *node)
207 {
208     std::unique_lock<std::mutex> lock(mLock);
209     LOG_SCOPE_F(INFO, "onWindowDeactivated obj:%p", node);
210     //removeFromActivatedList(node);
211 }
212
213 void AtspiAccessibleWatcher::onWindowCreated(AtspiAccessible *node)
214 {
215     std::unique_lock<std::mutex> lock(mLock);
216     LOG_SCOPE_F(INFO, "onWindowCreated obj:%p", node);
217     //addToWindowSet(node);
218 }
219
220 void AtspiAccessibleWatcher::onWindowDestroyed(AtspiAccessible *node)
221 {
222     std::unique_lock<std::mutex> lock(mLock);
223     LOG_SCOPE_F(INFO, "onWindowDestroyed obj:%p vis:%d", node);
224     //removeFromWindowSet(node);
225 }
226
227 void AtspiAccessibleWatcher::onVisibilityChanged(AtspiAccessible *node, bool visible)
228 {
229     std::unique_lock<std::mutex> lock(mLock);
230     LOG_SCOPE_F(INFO, "onVisibilityChanged obj:%p vis:%d", node, visible);
231 }
232
233 void AtspiAccessibleWatcher::onObjectDefunct(AtspiAccessible *node)
234 {
235     std::unique_lock<std::mutex> lock(mLock);
236     LOG_SCOPE_F(INFO, "onObjectDefunct obj:%p", node);
237 }
238
239
240 int AtspiAccessibleWatcher::getApplicationCount(void) const
241 {
242     AtspiAccessible *root = atspi_get_desktop(0);
243     int nchild = atspi_accessible_get_child_count(root, NULL);
244     g_object_unref(root);
245     if (nchild <= 0) return 0;
246     return nchild;
247 }
248
249 std::shared_ptr<AccessibleApplication> AtspiAccessibleWatcher::getApplicationAt(int index) const
250 {
251     AtspiAccessible *root = atspi_get_desktop(0);
252     AtspiAccessible* child = atspi_accessible_get_child_at_index(root, index, NULL);
253     g_object_unref(root);
254     return std::make_shared<AtspiAccessibleApplication>(std::make_shared<AtspiAccessibleNode>(child));
255 }
256
257 std::vector<std::shared_ptr<AccessibleApplication>> AtspiAccessibleWatcher::getApplications(void) const
258 {
259     LOG_SCOPE_F(INFO, "getApplications for this(%p)", this);
260     std::vector<std::shared_ptr<AccessibleApplication>> ret{};
261     AtspiAccessible *root = atspi_get_desktop(0);
262     int nchild = atspi_accessible_get_child_count(root, NULL);
263     if (nchild <= 0) {
264         g_object_unref(root);
265         return ret;
266     }
267
268     for (int i = 0; i < nchild; i++){
269         AtspiAccessible* child = atspi_accessible_get_child_at_index(root, i, NULL);
270         if (child) {
271             ret.push_back(std::make_shared<AtspiAccessibleApplication>(std::make_shared<AtspiAccessibleNode>(child)));
272         }
273     }
274     g_object_unref(root);
275     return ret;
276 }
277
278 /*
279 std::shared_ptr<AccessibleNode> AtspiAccessibleWatcher::getRootNode() const
280 {
281     auto node = atspi_get_desktop(0);
282     auto aNode = std::make_shared<AccessibleNode>(node);
283     return accNode;
284 }
285
286 std::vector<std::shared_ptr<AccessibleNode>> AtspiAccessibleWatcher::getTopNode() const
287 {
288     AtspiAccessible *topNode = nullptr, *activeNode = nullptr;
289     std::vector<std::shared_ptr<AccessibleNode>> ret;
290
291     {
292         std::unique_lock<std::mutex> lock(mLock);
293         if (!mActivatedWindowList.empty()) {
294             topNode = mActivatedWindowList.front();
295             std::list<AtspiAccessible *>::const_iterator iterator;
296             for (iterator = mActivatedWindowList.begin(); iterator != mActivatedWindowList.end(); ++iterator){
297                 if (*iterator && iShowingNode(*iterator)) {
298                     AtspiAccessible *child = atspi_accessible_get_application(*iterator, NULL);
299                     if (child) {
300                         auto tmpNode = make_gobj_unique(child);
301                         auto node =  AccessibleNode::get(tmpNode.get());
302                         if (tmpNode.get()) g_object_unref(tmpNode.get());
303                         ret.push_back((node));
304                     }
305                 }
306             }
307             return ret;
308         }
309     }
310
311     LOG_F(INFO, "Mo activated window node or Invisible acticated window / topNdoe(%p)", topNode);
312     LOG_F(INFO, "Trying fallback logic");
313
314     auto rootNode = make_gobj_unique(atspi_get_desktop(0));
315
316     if (rootNode) {
317         std::vector<AtspiAccessible*> activeNodes = findActiveNode(rootNode.get(), 0, 2);
318         if (!activeNodes.empty()) {
319             std::set<AtspiAccessible*> appset{};
320             for (auto iterator = activeNodes.begin(); iterator != activeNodes.end(); ++iterator){
321                 //auto tmpNode = make_gobj_unique(atspi_accessible_get_application(*iterator, NULL));
322                 auto app = atspi_accessible_get_application(*iterator, NULL);
323                 appset.insert(app);
324             }
325             for (auto iterator = appset.begin(); iterator != appset.end(); ++iterator){
326                 auto node = AccessibleNode::get(*iterator);
327                 g_object_unref(*iterator);
328                 LOG_F(INFO, "app has showing window found %p %s %s", node.get(), node->getText().c_str(), node->getPkg().c_str());
329                 ret.push_back((node));
330             }
331         } else {
332             auto node = AccessibleNode::get(rootNode.get());
333             if (rootNode.get()) g_object_unref(rootNode.get());
334             ret.push_back((node));
335         }
336     }
337     return ret;
338 }
339 */
340 /*
341 void AtspiAccessibleWatcher::clearWindowList()
342 {
343     std::unique_lock<std::mutex> lock(mLock);
344
345     std::for_each(mActivatedWindowSet.begin(), mActivatedWindowSet.end(), [](auto window){
346         g_object_unref(window);
347     });
348     mActivatedWindowSet.clear();
349
350     mWindowSet.clear();
351 }
352 */
353
354 bool AtspiAccessibleWatcher::removeFromActivatedList(AtspiAccessible *node)
355 {
356     LOG_SCOPE_F(INFO,"remove from activelist node %p", node);
357     mActivatedWindowList.remove_if([&](auto &n) { return n == node; });
358
359     AtspiAccessible *app = atspi_accessible_get_application(node, NULL);
360     LOG_F(INFO, "node:%p, app:%p", node, app);
361     if (app) {
362         mActivatedApplicationList.remove_if([&](auto &n) { return n == app; });
363         g_object_unref(app);
364     }
365     return true;
366 }
367
368 bool AtspiAccessibleWatcher::addToActivatedList(AtspiAccessible *node)
369 {
370     LOG_SCOPE_F(INFO,"add to activelist node %p", node);
371     mActivatedWindowList.remove_if([&](auto &n) { return n == node; });
372     mActivatedWindowList.push_front(node);
373
374     auto iter = mWindowSet.find(node);
375     if ( iter == mWindowSet.end()) mWindowSet.insert(node);
376
377     AtspiAccessible *app = atspi_accessible_get_application(node, NULL);
378     LOG_F(INFO, "node:%p, app:%p", node, app);
379     if (app) {
380         mActivatedApplicationList.remove_if([&](auto &n) { if(n == app) { g_object_unref(app); return true;} else return false; });
381         mActivatedApplicationList.push_front(app);
382     }
383
384     return true;
385 }
386
387 bool AtspiAccessibleWatcher::removeFromWindowSet(AtspiAccessible *node)
388 {
389     removeFromActivatedList(node);
390     auto iter = mWindowSet.find(node);
391     if ( iter != mWindowSet.end()){
392         mWindowSet.erase(node);
393         return true;
394     }
395     return false;
396 }
397
398 bool AtspiAccessibleWatcher::addToWindowSet(AtspiAccessible *node)
399 {
400     auto iter = mWindowSet.find(node);
401     if ( iter == mWindowSet.end()){
402         mWindowSet.insert(node);
403         return true;
404     }
405     return false;
406 }