From 84e421741dd862b66b7c9589e5c43d30381079ab Mon Sep 17 00:00:00 2001 From: David Selassie Date: Sat, 4 Apr 2026 13:00:59 -0700 Subject: [PATCH] fix: accessibility tree in isolated sessions on Fedora MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Fix `accessibility_tree` (and all AT-SPI tools) returning empty results or crashing in isolated virtual sessions on Fedora - Extract AT-SPI binary paths from D-Bus service files instead of hardcoding distro-specific paths - Explicitly bootstrap the AT-SPI registryd in isolated sessions where no session manager is present to auto-activate it ## What broke Two problems prevented the accessibility tree from working in isolated virtual sessions on Fedora (and potentially other distros): 1. **Wrong binary path**: `at-spi-bus-launcher` was hardcoded to `/usr/lib/at-spi-bus-launcher`, but Fedora installs it at `/usr/libexec/at-spi-bus-launcher`. The launcher silently failed to start, so the AT-SPI bus was never created. AT-SPI queries crashed with "Couldn't connect to accessibility bus". 2. **Missing registryd**: Even with the bus launcher running, the `at-spi2-registryd` daemon was never started. D-Bus auto-activation fails because the `.service` file uses `--use-gnome-session`, which requires a GNOME session manager that doesn't exist in isolated sessions. Without the registryd, no applications register their accessibility trees, so `accessibility_tree` returned "(no accessible applications found)". ## How it's fixed - Binary paths for both `at-spi-bus-launcher` and `at-spi2-registryd` are now extracted from their D-Bus service files (`/usr/share/dbus-1/services/org.a11y.Bus.service` and `/usr/share/dbus-1/accessibility-services/org.a11y.atspi.Registry.service`). These file locations are standardized by the D-Bus spec, so this works on any distro without hardcoding paths. - The wrapper script now explicitly sets `IsEnabled=true` on the AT-SPI bus and starts `at-spi2-registryd` without `--use-gnome-session`, ensuring apps register their accessibility trees. - Process cleanup is unchanged: `session.stop()` kills the entire process group via `os.killpg()`, which covers the registryd. ## How to test Verify path extraction resolves to a real binary on your system: sed -n 's/^Exec=\([^ ]*\).*/\1/p' /usr/share/dbus-1/services/org.a11y.Bus.service Smoke test — should print an accessibility tree with elements, not "(no accessible applications found)": printf 'session_start app_command=kcalc\naccessibility_tree\nsession_stop\nquit\n' \ | uv run kwin-mcp-cli Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 5 +++++ src/kwin_mcp/session.py | 27 ++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7acf4c5..586dffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- `accessibility_tree`, `find_ui_elements`, `wait_for_element`, `list_windows`, and `focus_window` now work in isolated virtual sessions on Fedora and other distros that install AT-SPI binaries outside `/usr/lib` (e.g. `/usr/libexec`). Binary paths are now extracted from D-Bus service files instead of being hardcoded. +- Isolated virtual sessions now explicitly start `at-spi2-registryd` and set `IsEnabled=true` on the AT-SPI bus. Without a session manager, the registryd auto-activation failed silently, causing `accessibility_tree` to return "(no accessible applications found)". + ## [0.7.0] - 2026-03-29 ### Added diff --git a/src/kwin_mcp/session.py b/src/kwin_mcp/session.py index 8d0582b..f969d01 100644 --- a/src/kwin_mcp/session.py +++ b/src/kwin_mcp/session.py @@ -343,9 +343,30 @@ def _build_wrapper_script(self, config: SessionConfig) -> str: # Start the AT-SPI accessibility bus. # ATSPI_DBUS_IMPLEMENTATION is set in _build_env() to force dbus-daemon # instead of dbus-broker (which reuses the host's AT-SPI bus). -/usr/lib/at-spi-bus-launcher --launch-immediately & -AT_SPI_PID=$! -sleep 0.2 +# Extract the binary path from the D-Bus service file so this works on +# any distro (Fedora /usr/libexec, Arch /usr/lib, Debian /usr/lib/at-spi2-core, etc.) +AT_SPI_LAUNCHER=$(sed -n 's/^Exec=\\([^ ]*\\).*/\\1/p' \\ + /usr/share/dbus-1/services/org.a11y.Bus.service 2>/dev/null) +if [ -x "$AT_SPI_LAUNCHER" ]; then + "$AT_SPI_LAUNCHER" --launch-immediately & + AT_SPI_PID=$! + sleep 0.2 + + # Enable AT-SPI so apps register with the accessibility bus + dbus-send --session --dest=org.a11y.Bus --type=method_call \\ + /org/a11y/bus org.freedesktop.DBus.Properties.Set \\ + string:org.a11y.Status string:IsEnabled variant:boolean:true 2>/dev/null + + # Start the AT-SPI registry daemon. The .service file specifies + # --use-gnome-session which fails without a session manager, so we + # extract just the binary path and start it without that flag. + AT_SPI_REGISTRYD=$(sed -n 's/^Exec=\\([^ ]*\\).*/\\1/p' \\ + /usr/share/dbus-1/accessibility-services/org.a11y.atspi.Registry.service 2>/dev/null) + if [ -x "$AT_SPI_REGISTRYD" ]; then + "$AT_SPI_REGISTRYD" & + fi + sleep 0.2 +fi # Pre-set D-Bus activation environment BEFORE starting KWin. # When KWin triggers portal auto-activation, portal-kde will get