1 #include "AtspiAccessibleWatcher.h"
3 #include "AtspiAccessibleApplication.h"
4 #include "AtspiAccessibleWindow.h"
5 #include "AtspiAccessibleNode.h"
11 AtspiEventListener *AtspiAccessibleWatcher::listener = nullptr;
13 static bool iShowingNode(AtspiAccessible *node)
16 if (node) name = atspi_accessible_get_name(node, NULL);
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);
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);
27 // TODO : free states and stateSet
31 // TODO : free states and stateSet
35 static std::vector<AtspiAccessible *>
36 findActiveNode(AtspiAccessible *node, int depth,
39 LOG_SCOPE_F(INFO, "findActiveNode %p %d/%d", node, depth, max_depth);
41 std::vector<AtspiAccessible *> ret{};
43 if (iShowingNode(node)) {
45 char *name = atspi_accessible_get_name(node, NULL);
47 LOG_SCOPE_F(INFO, "%s", name);
54 if (depth >= max_depth) return ret;
56 int nchild = atspi_accessible_get_child_count(node, NULL);
57 if (nchild <= 0) return ret;
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);
71 AtspiAccessibleWatcher::AtspiAccessibleWatcher()
72 : mDbusProxy{nullptr}, mLock{}
74 GVariant *enabled_variant = nullptr, *result = nullptr;
75 GError * error = nullptr;
76 atspi_set_main_context (g_main_context_default ());
80 atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiWindowEvent, this, NULL);
81 LOG_SCOPE_F(INFO, "WKWK init this:%p", this);
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);
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",
95 enabled_variant = g_variant_new_boolean(true);
96 result = g_dbus_proxy_call_sync(
98 g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
99 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
101 g_variant_unref(enabled_variant);
102 g_variant_unref(result);
105 AtspiAccessibleWatcher::~AtspiAccessibleWatcher()
107 GVariant *enabled_variant = nullptr, *result = nullptr;
108 GError * error = nullptr;
110 enabled_variant = g_variant_new_boolean(false);
111 result = g_dbus_proxy_call_sync(
113 g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
114 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
116 atspi_event_listener_deregister(listener, "window:", NULL);
117 atspi_event_listener_deregister(listener, "object:", NULL);
119 g_object_unref(listener);
120 g_object_unref(mDbusProxy);
121 g_variant_unref(enabled_variant);
122 g_variant_unref(result);
129 void AtspiAccessibleWatcher::onAtspiWindowEvent(AtspiEvent *event, void *user_data)
131 char *name = NULL, *pname = NULL;
132 AtspiAccessibleWatcher *instance = (AtspiAccessibleWatcher *)user_data;
136 LOG_F(INFO, "event->source is NULL. Skip event handling");
141 AtspiAccessible *parent = atspi_accessible_get_parent(event->source, NULL);
143 name = atspi_accessible_get_name(event->source, NULL);
145 pname = atspi_accessible_get_name(parent, NULL);
146 g_object_unref(parent);
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);
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));
171 if (name) free(name);
172 if (pname) free(pname);
174 // instance->print_debug();
177 void AtspiAccessibleWatcher::print_debug()
179 LOG_F(INFO, "activatewindowlist-------------------");
180 std::for_each(mActivatedWindowList.begin(), mActivatedWindowList.end(), [](auto acc){
181 LOG_F(INFO, "child:%p", acc);
184 LOG_F(INFO, "mActivatedApplicationList--------------------------");
185 std::for_each(mActivatedApplicationList.begin(), mActivatedApplicationList.end(), [](auto acc){
186 LOG_F(INFO, "child:%p", acc);
189 LOG_F(INFO, "mWindowSet------------------------------");
190 std::for_each(mWindowSet.begin(), mWindowSet.end(), [](auto acc){
191 LOG_F(INFO, "child:%p", acc);
193 LOG_F(INFO, "------------------------------");
197 void AtspiAccessibleWatcher::onWindowActivated(AtspiAccessible *node,
198 WindowActivateInfoType type)
200 //std::unique_lock<std::mutex> lock(mLock);
201 LOG_SCOPE_F(INFO, "onWindowActivated obj:%p", node);
202 //addToActivatedList((node));
206 void AtspiAccessibleWatcher::onWindowDeactivated(AtspiAccessible *node)
208 std::unique_lock<std::mutex> lock(mLock);
209 LOG_SCOPE_F(INFO, "onWindowDeactivated obj:%p", node);
210 //removeFromActivatedList(node);
213 void AtspiAccessibleWatcher::onWindowCreated(AtspiAccessible *node)
215 std::unique_lock<std::mutex> lock(mLock);
216 LOG_SCOPE_F(INFO, "onWindowCreated obj:%p", node);
217 //addToWindowSet(node);
220 void AtspiAccessibleWatcher::onWindowDestroyed(AtspiAccessible *node)
222 std::unique_lock<std::mutex> lock(mLock);
223 LOG_SCOPE_F(INFO, "onWindowDestroyed obj:%p vis:%d", node);
224 //removeFromWindowSet(node);
227 void AtspiAccessibleWatcher::onVisibilityChanged(AtspiAccessible *node, bool visible)
229 std::unique_lock<std::mutex> lock(mLock);
230 LOG_SCOPE_F(INFO, "onVisibilityChanged obj:%p vis:%d", node, visible);
233 void AtspiAccessibleWatcher::onObjectDefunct(AtspiAccessible *node)
235 std::unique_lock<std::mutex> lock(mLock);
236 LOG_SCOPE_F(INFO, "onObjectDefunct obj:%p", node);
240 int AtspiAccessibleWatcher::getApplicationCount(void) const
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;
249 std::shared_ptr<AccessibleApplication> AtspiAccessibleWatcher::getApplicationAt(int index) const
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));
257 std::vector<std::shared_ptr<AccessibleApplication>> AtspiAccessibleWatcher::getApplications(void) const
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);
264 g_object_unref(root);
268 for (int i = 0; i < nchild; i++){
269 AtspiAccessible* child = atspi_accessible_get_child_at_index(root, i, NULL);
271 ret.push_back(std::make_shared<AtspiAccessibleApplication>(std::make_shared<AtspiAccessibleNode>(child)));
274 g_object_unref(root);
279 std::shared_ptr<AccessibleNode> AtspiAccessibleWatcher::getRootNode() const
281 auto node = atspi_get_desktop(0);
282 auto aNode = std::make_shared<AccessibleNode>(node);
286 std::vector<std::shared_ptr<AccessibleNode>> AtspiAccessibleWatcher::getTopNode() const
288 AtspiAccessible *topNode = nullptr, *activeNode = nullptr;
289 std::vector<std::shared_ptr<AccessibleNode>> ret;
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);
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));
311 LOG_F(INFO, "Mo activated window node or Invisible acticated window / topNdoe(%p)", topNode);
312 LOG_F(INFO, "Trying fallback logic");
314 auto rootNode = make_gobj_unique(atspi_get_desktop(0));
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);
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));
332 auto node = AccessibleNode::get(rootNode.get());
333 if (rootNode.get()) g_object_unref(rootNode.get());
334 ret.push_back((node));
341 void AtspiAccessibleWatcher::clearWindowList()
343 std::unique_lock<std::mutex> lock(mLock);
345 std::for_each(mActivatedWindowSet.begin(), mActivatedWindowSet.end(), [](auto window){
346 g_object_unref(window);
348 mActivatedWindowSet.clear();
354 bool AtspiAccessibleWatcher::removeFromActivatedList(AtspiAccessible *node)
356 LOG_SCOPE_F(INFO,"remove from activelist node %p", node);
357 mActivatedWindowList.remove_if([&](auto &n) { return n == node; });
359 AtspiAccessible *app = atspi_accessible_get_application(node, NULL);
360 LOG_F(INFO, "node:%p, app:%p", node, app);
362 mActivatedApplicationList.remove_if([&](auto &n) { return n == app; });
368 bool AtspiAccessibleWatcher::addToActivatedList(AtspiAccessible *node)
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);
374 auto iter = mWindowSet.find(node);
375 if ( iter == mWindowSet.end()) mWindowSet.insert(node);
377 AtspiAccessible *app = atspi_accessible_get_application(node, NULL);
378 LOG_F(INFO, "node:%p, app:%p", node, app);
380 mActivatedApplicationList.remove_if([&](auto &n) { if(n == app) { g_object_unref(app); return true;} else return false; });
381 mActivatedApplicationList.push_front(app);
387 bool AtspiAccessibleWatcher::removeFromWindowSet(AtspiAccessible *node)
389 removeFromActivatedList(node);
390 auto iter = mWindowSet.find(node);
391 if ( iter != mWindowSet.end()){
392 mWindowSet.erase(node);
398 bool AtspiAccessibleWatcher::addToWindowSet(AtspiAccessible *node)
400 auto iter = mWindowSet.find(node);
401 if ( iter == mWindowSet.end()){
402 mWindowSet.insert(node);