2 #include "AccessibleWatcher.h"
10 AtspiEventListener *AccessibleWatcher::listener = nullptr;
14 static bool iShowingNode(AtspiAccessible *node)
17 if (node) name = atspi_accessible_get_name(node, NULL);
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()));
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);
34 static std::vector<AtspiAccessible *>
35 findActiveNode(AtspiAccessible *node, int depth,
38 std::vector<AtspiAccessible *> ret{};
39 if (depth >= max_depth) return ret;
41 if (iShowingNode(node)) {
43 char *name = atspi_accessible_get_name(node, NULL);
45 LOG_SCOPE_F(INFO, "%s", name);
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());
62 AccessibleWatcher::AccessibleWatcher() : mActivatedWindowList{}, mWindowSet{}
64 GVariant *enabled_variant = nullptr, *result = nullptr;
65 GError * error = nullptr;
66 atspi_set_main_context (g_main_context_default ());
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);
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",
83 enabled_variant = g_variant_new_boolean(true);
84 result = g_dbus_proxy_call_sync(
86 g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
87 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
89 g_variant_unref(enabled_variant);
90 g_variant_unref(result);
94 AccessibleWatcher::~AccessibleWatcher()
96 GVariant *enabled_variant = nullptr, *result = nullptr;
97 GError * error = nullptr;
99 enabled_variant = g_variant_new_boolean(false);
100 result = g_dbus_proxy_call_sync(
102 g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
103 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
106 for (auto it = mAccessibleNode.begin(); it != mAccessibleNode.end(); ++it) {
107 g_object_unref(it->first);
110 atspi_event_listener_deregister(listener, "window:", NULL);
111 atspi_event_listener_deregister(listener, "object:", NULL);
113 g_object_unref(listener);
114 g_object_unref(mDbusProxy);
115 g_variant_unref(enabled_variant);
116 g_variant_unref(result);
122 std::unique_ptr<AccessibleNode> AccessibleWatcher::getRootNode() const
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());
130 std::vector<std::unique_ptr<AccessibleNode>> AccessibleWatcher::getTopNode() const
132 AtspiAccessible *topNode = nullptr, *activeNode = nullptr;
133 std::vector<std::unique_ptr<AccessibleNode>> ret;
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);
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));
155 LOG_F(INFO, "Mo activated window node or Invisible acticated window / topNdoe(%p)", topNode);
156 LOG_F(INFO, "Trying fallback logic");
158 auto rootNode = make_gobj_unique(atspi_get_desktop(0));
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));
172 auto node = AccessibleNode::get(rootNode.get());
173 if (rootNode.get()) g_object_unref(rootNode.get());
174 ret.push_back(std::move(node));
180 void AccessibleWatcher::onAtspiWindowEvent(AtspiEvent *event, void *user_data)
182 char *name = NULL, *pname = NULL;
183 IAtspiEvents *instance = (IAtspiEvents *)user_data;
187 LOG_F(INFO, "event->source is NULL. Skip event handling");
191 auto p = make_gobj_unique(atspi_accessible_get_parent(event->source, NULL));
193 name = atspi_accessible_get_name(event->source, NULL);
194 if (p) pname = atspi_accessible_get_name(p.get(), NULL);
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);
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));
218 if (name) free(name);
219 if (pname) free(pname);
222 void AccessibleWatcher::printDbgInformation() const
224 LOG_SCOPE_F(INFO, "%d %d", mActivatedWindowList.size(), mWindowSet.size());
226 for (auto iter = mActivatedWindowList.begin(); iter != mActivatedWindowList.end(); ++iter) {
227 LOG_F(INFO, "%p", *iter);
229 LOG_F(INFO, "-----------");
231 for (auto iter = mWindowSet.begin(); iter != mWindowSet.end(); ++iter) {
232 LOG_F(INFO, "%p", *iter);
236 const AccessibleWatcher *AccessibleWatcher::getInstance()
238 static AccessibleWatcher *mInstance = nullptr;
239 if (!mInstance) mInstance = new AccessibleWatcher();
243 void AccessibleWatcher::clearWindowList() const
245 std::unique_lock<std::mutex> lock(mLock);
246 while (!mActivatedWindowList.empty()) {
247 AtspiAccessible *n = mActivatedWindowList.front();
248 mActivatedWindowList.pop_front();
255 bool AccessibleWatcher::removeFromActivatedList(AtspiAccessible *node)
257 mActivatedWindowList.remove_if([&](auto &n) { return n == node; });
261 bool AccessibleWatcher::addToActivatedList(AtspiAccessible *node)
263 mActivatedWindowList.remove_if([&](auto &n) { return n == node; });
264 mActivatedWindowList.push_front(node);
266 auto iter = mWindowSet.find(node);
267 if ( iter == mWindowSet.end()) mWindowSet.insert(node);
271 bool AccessibleWatcher::removeFromWindowSet(AtspiAccessible *node)
273 removeFromActivatedList(node);
274 auto iter = mWindowSet.find(node);
275 if ( iter != mWindowSet.end()){
276 mWindowSet.erase(node);
282 bool AccessibleWatcher::addToWindowSet(AtspiAccessible *node)
284 auto iter = mWindowSet.find(node);
285 if ( iter == mWindowSet.end()){
286 mWindowSet.insert(node);
292 void AccessibleWatcher::onWindowActivated(AtspiAccessible * node,
293 WindowActivateInfoType type)
295 std::unique_lock<std::mutex> lock(mLock);
296 addToActivatedList(node);
300 void AccessibleWatcher::onWindowDeactivated(AtspiAccessible *node)
302 std::unique_lock<std::mutex> lock(mLock);
303 removeFromActivatedList(node);
307 void AccessibleWatcher::onWindowCreated(AtspiAccessible *node)
309 std::unique_lock<std::mutex> lock(mLock);
310 addToWindowSet(node);
313 void AccessibleWatcher::onWindowDestroyed(AtspiAccessible *node)
315 std::unique_lock<std::mutex> lock(mLock);
316 removeFromWindowSet(node);
319 void AccessibleWatcher::onVisibilityChanged(AtspiAccessible *node, bool visible)
323 void AccessibleWatcher::onObjectDefunct(AtspiAccessible *node)
325 LOG_SCOPE_F(INFO, "object defuncted %p", node);