More work on cthulhu recognizing focused items that should be read.

This commit is contained in:
Storm Dragon committed 2026-11-01 18:31:58 -05:00
1 parent 9374b5a2e5
commit 300f4a7504
9 files changed
+456 -9

No files matched your search

+34 -3
View File
@@ -609,37 +609,68 @@ gboolean cthulhu_may_be_background_notification(AtspiAccessible *source) {
// Return the containing top-level window. An embedded web dialog is part of
// its frame; a standalone dialog directly below the application owns itself.
// GTK plugs also publish a frame, but its parent chain crosses the socket's
// provider before reaching the host window. Keep that host as the owner while
// retaining the source object's provider identity. Same-provider nested frames
// retain their existing nearest-window behavior.
AtspiAccessible *cthulhu_window_ancestor(AtspiAccessible *source) {
if (source == NULL) return NULL;
AtspiAccessible *current = g_object_ref(source);
AtspiAccessible *window = NULL;
for (gint depth = 0; current != NULL && depth < 256; depth++) {
GError *error = NULL;
AtspiRole role = atspi_accessible_get_role(current, &error);
if (error != NULL) {
g_clear_error(&error);
g_object_unref(current);
if (window != NULL) g_object_unref(window);
return NULL;
}
if (role == ATSPI_ROLE_FRAME || role == ATSPI_ROLE_WINDOW) {
return current;
if (role == ATSPI_ROLE_APPLICATION) {
g_object_unref(current);
return window;
}
if ((role == ATSPI_ROLE_FRAME || role == ATSPI_ROLE_WINDOW) &&
(window == NULL || g_strcmp0(cthulhu_accessible_bus_name(window),
cthulhu_accessible_bus_name(current)) != 0)) {
if (window != NULL) g_object_unref(window);
window = g_object_ref(current);
}
AtspiAccessible *parent = atspi_accessible_get_parent(current, &error);
// Only a frame with parents below the application can be a plug.
// Refresh that chain to reject detached sockets, without invalidating
// every ordinary top-level window for every accessibility event.
if (window != NULL && parent != NULL && error == NULL &&
atspi_accessible_get_role(parent, NULL) != ATSPI_ROLE_APPLICATION) {
g_object_unref(parent);
atspi_accessible_clear_cache_single(current);
parent = atspi_accessible_get_parent(current, &error);
}
// Qt can expose a top-level QWidget as a filler rather than a frame.
// Python's Qt utilities use the application-child boundary here.
if (parent != NULL && error == NULL && role != ATSPI_ROLE_APPLICATION &&
atspi_accessible_get_role(parent, NULL) == ATSPI_ROLE_APPLICATION) {
g_object_unref(parent);
return current;
if (window == NULL || g_strcmp0(cthulhu_accessible_bus_name(window),
cthulhu_accessible_bus_name(current)) != 0) {
if (window != NULL) g_object_unref(window);
return current;
}
g_object_unref(current);
return window;
}
g_object_unref(current);
if (error != NULL) {
g_clear_error(&error);
if (parent != NULL) g_object_unref(parent);
if (window != NULL) g_object_unref(window);
return NULL;
}
current = parent;
}
if (current != NULL) g_object_unref(current);
if (current == NULL) return window;
if (window != NULL) g_object_unref(window);
return NULL;
}