Skip to content

fix: use D-Bus auto-activation for AT-SPI bus in isolated sessions#14

Open
isac322 wants to merge 1 commit into
mainfrom
fix/atspi-auto-activation
Open

fix: use D-Bus auto-activation for AT-SPI bus in isolated sessions#14
isac322 wants to merge 1 commit into
mainfrom
fix/atspi-auto-activation

Conversation

@isac322
Copy link
Copy Markdown
Owner

@isac322 isac322 commented Apr 21, 2026

Summary

Replace the hardcoded /usr/lib/at-spi-bus-launcher path with D-Bus auto-activation so that accessibility_tree, find_ui_elements, wait_for_element, list_windows, and focus_window work in isolated virtual sessions on all distros — not just Arch.

Problem

_build_wrapper_script() in session.py:346 currently launches the AT-SPI bus by execing a hardcoded path:

/usr/lib/at-spi-bus-launcher --launch-immediately &

This path is only correct on Arch/Manjaro. Upstream at-spi2-core has migrated to /usr/libexec/, so on the following platforms the AT-SPI bus is never started:

  • Fedora (/usr/libexec/at-spi-bus-launcher)
  • Debian sid, Ubuntu 24.04 (noble) and later (/usr/libexec/at-spi-bus-launcher)
  • Flatpak runtimes (/app/libexec/at-spi-bus-launcher)

With no a11y bus, every subsequent _run_atspi() call crashes with "Couldn't connect to accessibility bus". The bug had been invisible because development happens on Arch, which still uses /usr/lib/.

Fix — delegate path resolution to D-Bus auto-activation

Don't try to resolve the binary path in kwin-mcp. Let dbus-daemon do it:

gdbus call --session \
    --dest=org.a11y.Bus \
    --object-path=/org/a11y/bus \
    --method=org.a11y.Bus.GetAddress >/dev/null 2>&1 || true

dbus-daemon reads /usr/share/dbus-1/services/org.a11y.Bus.service and execs the launcher at whatever path the current distro's package actually installed it to. Path resolution becomes the packaging layer's responsibility, which is how AT-SPI is designed to bootstrap.

The registry daemon (at-spi2-registryd) also does not need to be started manually — it is auto-activated on first access to the a11y bus through the same mechanism.

Incidental cleanup

  • Remove AT_SPI_PID from the cleanup trap. Auto-activated processes are torn down when dbus-run-session closes the session bus, so no explicit kill is needed.
  • Bump sleep 0.2sleep 0.3. gdbus call returns as soon as the bus address reply arrives, which is slightly earlier than full launcher initialization.

Relationship to #8

This PR is an alternative to #8, opened by @davidselassie after hitting the Fedora failure. #8 parses the Exec= line from the service file with sed and starts the launcher and registryd manually. The auto-activation approach here removes the need for the IsEnabled property flip, the --use-gnome-session workaround, and the manual registryd bootstrap — dbus-daemon picks all of that up from the same service files.

Testing

  1. Static checks:
    uv run ruff check .
    uv run ruff format --check .
    uv run ty check
    
  2. CLI smoke test — accessibility_tree should return a real widget tree, not "(no accessible applications found)":
    printf 'session_start app_command=kcalc\naccessibility_tree\nsession_stop\nquit\n' \
      | uv run kwin-mcp-cli
    

Verified locally on Arch (/usr/lib/). Cross-distro verification (Fedora in particular) is welcome.

Checklist

  • uv run ruff check . passes
  • uv run ruff format --check . passes
  • uv run ty check passes
  • CHANGELOG.md updated
  • README.md updated — N/A, no new tools or changed behavior

🤖 Generated with Claude Code

The hardcoded `/usr/lib/at-spi-bus-launcher` path is only correct on
Arch. Upstream at-spi2-core has migrated to `/usr/libexec/`, so on
Fedora, Debian sid, Ubuntu 24.04+, and Flatpak runtimes the AT-SPI
bus never starts and every AT-SPI tool (accessibility_tree,
find_ui_elements, wait_for_element, list_windows, focus_window)
fails with "Couldn't connect to accessibility bus".

Replace the manual launcher invocation with a D-Bus auto-activation
trigger (`gdbus call org.a11y.Bus.GetAddress`). dbus-daemon resolves
the service file and execs the launcher at whatever path the current
distro's package installed it to, so kwin-mcp no longer encodes any
binary path. at-spi2-registryd is auto-activated on first access by
the same mechanism, so no manual bootstrap is needed.

Also drop AT_SPI_PID from the cleanup trap — auto-activated processes
are torn down when dbus-run-session closes the session bus.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@isac322 isac322 force-pushed the fix/atspi-auto-activation branch from 61b7280 to 0b2de17 Compare April 21, 2026 05:36
@github-actions
Copy link
Copy Markdown

📝 Docs & SEO Review

Source files changed in this PR:

src/kwin_mcp/session.py

Consistency check results:

✅  All documentation SEO checks passed.

Run @docs-seo in Claude Code to perform a full documentation review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant