Skip to content

fix(cua-driver/linux): libxcb fallback for X11 connect so list_windows works where xdotool does (#1978)#1991

Open
f-trycua wants to merge 3 commits into
mainfrom
fix/x11-libxcb-fallback-1978
Open

fix(cua-driver/linux): libxcb fallback for X11 connect so list_windows works where xdotool does (#1978)#1991
f-trycua wants to merge 3 commits into
mainfrom
fix/x11-libxcb-fallback-1978

Conversation

@f-trycua

@f-trycua f-trycua commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

On some Linux/X11 setups (reported on Ubuntu 22.04 XFCE/lightdm), list_windows / get_window_state return 0 windows and cua-driver doctor reports "X11 is not reachable" — even though apps are running and xdotool / pyatspi enumerate windows fine on the same display. Fixes #1978.

Root cause

x11rb's pure-Rust RustConnection::connect(None) does strict Xauthority family/address cookie matching and returns Err in environments where libxcb-based clients (xdotool, pyatspi, Xlib) connect fine — e.g. an auth entry stored under a hostname/family that doesn't match how x11rb canonicalizes it. list_windows_inner propagated that Err, and list_windows swallowed it into an empty Vec, so the failure surfaced only as "0 windows".

Fix

  • libxcb fallback. Try RustConnection first; on connect failure, fall back to the libxcb-backed XCBConnection (enabled via the x11rb allow-unsafe-code feature) — the same client library xdotool/pyatspi use, so we connect in exactly the environments those tools work in.
  • Generic enumeration. The window-enumeration helpers (enumerate_windows, get_window_list, get_atom, get_window_pid, get_window_title, wm_class_inner) are now generic over C: Connection so both connection types share one code path.
  • No more silent zero. When both connects fail, surface a descriptive error (DISPLAY / XAUTHORITY + both underlying errors) instead of an empty list — so the next report like this is diagnosable from logs.
  • Doctor agreement. probe_x11_connect mirrors the fallback so the doctor verdict matches what list_windows can actually do.

Verification

  • Build-verified on Linux (Ubuntu, x11rb + system libxcb-dev): cargo build -p platform-linux is green with the allow-unsafe-code / XCBConnection path compiled in. Added libxcb-*-dev are standard X11 build deps.
  • Runtime repro not yet captured. The available test fleet has no logged-in X11 desktop session (Wayland greeters / no active seat), so I could not reproduce the original 0-window condition end-to-end. The fix routes through the same libxcb path the working tools use; a maintainer on the reported XFCE/lightdm setup can confirm list_windows now returns the live windows. Calling this out honestly rather than claiming a runtime pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved X11 connectivity reliability on Linux by implementing an alternative connection method when the primary method fails.
    • Enhanced error reporting for X11 connection issues, including diagnostic information to help troubleshoot connectivity problems.
  • Improvements

    • Made window enumeration more robust on Linux systems to align with actual platform capabilities.

@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Jun 24, 2026 2:36am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2c8d1e01-02f0-46bc-9654-0be70daf67f4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds allow-unsafe-code to the x11rb Cargo dependency, then refactors X11 window enumeration and WM_CLASS lookup to attempt a pure-Rust RustConnection first and fall back to XCBConnection (libxcb) when the pure-Rust connection fails. Helpers are generalized to C: Connection. The health probe is updated to match the same two-stage strategy.

Changes

X11 libxcb fallback for window enumeration and health probe

Layer / File(s) Summary
Cargo feature flag and module imports
libs/cua-driver/rust/crates/platform-linux/Cargo.toml, libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs
Adds allow-unsafe-code to the x11rb dependency and imports anyhow! and XCBConnection into x11/mod.rs.
Two-stage connection, generic helpers, and wm_class fallback
libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs
Replaces the single RustConnection flow with a RustConnection-first / XCBConnection-fallback strategy in list_windows and wm_class_for_window. Adds x11_connect_error for diagnostic output including DISPLAY/XAUTHORITY. Refactors enumerate_windows, get_window_list, get_atom, get_window_pid, and get_window_title to accept generic C: Connection.
Health probe update
libs/cua-driver/rust/crates/platform-linux/src/health_report.rs
probe_x11_connect returns true when either RustConnection or XCBConnection connects, aligning the health verdict with the new window-enumeration path.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant list_windows
  participant RustConnection
  participant XCBConnection
  participant enumerate_windows

  Caller->>list_windows: list_windows()
  list_windows->>RustConnection: connect(None)
  alt pure-Rust connection succeeds
    RustConnection-->>list_windows: Ok(conn)
    list_windows->>enumerate_windows: enumerate_windows(conn)
  else pure-Rust fails, try libxcb
    RustConnection-->>list_windows: Err(rust_err)
    list_windows->>XCBConnection: connect(None)
    alt libxcb succeeds
      XCBConnection-->>list_windows: Ok(conn)
      list_windows->>enumerate_windows: enumerate_windows(conn)
    else both fail
      XCBConnection-->>list_windows: Err(xcb_err)
      list_windows-->>Caller: Err(x11_connect_error(DISPLAY, XAUTHORITY, rust_err, xcb_err))
    end
  end
  enumerate_windows-->>Caller: Vec<WindowInfo>
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 When the cookie wouldn't match and the windows stayed hidden,
A fallback was added — libxcb unbidden!
RustConnection tries first, then xcb takes the stage,
Generic Connection helpers now span every page.
Zero windows no more — the rabbit hops free! 🪟✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title directly describes the main fix: adding libxcb fallback for X11 connection to enable list_windows in environments where xdotool works.
Linked Issues check ✅ Passed PR fully addresses issue #1978 requirements: implements libxcb fallback for X11 connection failures, refactors window enumeration to support both connection types, improves error messaging, and updates health diagnostics.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing X11 window enumeration via libxcb fallback. Modifications to Cargo.toml, health_report.rs, and x11/mod.rs are all necessary for the stated fix.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/x11-libxcb-fallback-1978

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Linux visual regression artifacts

Matrix jobs now run independently. Download visual artifacts from this workflow run.
Each background-GUI job uploads a .gif of the interaction plus two annotated PNGs (<app>.png raw, <app>-atspi.png with AT-SPI element boxes); the cua-driver-linux-som-overlays artifact adds <app>-som.png cua Set-of-Marks overlays:

  • cua-driver-linux-cursor-click-gif
  • cua-driver-linux-background-terminal-gif
  • cua-driver-linux-parallel-drag-xserver
  • cua-driver-linux-background-gui-chromium
  • cua-driver-linux-background-gui-tk
  • cua-driver-linux-background-gui-gtk3-gedit
  • cua-driver-linux-background-gui-gtk3-mousepad
  • cua-driver-linux-background-gui-gtk3-scite
  • cua-driver-linux-background-gui-gtk4-characters
  • cua-driver-linux-background-gui-qt5-manuskript
  • cua-driver-linux-background-gui-qt5-klog
  • cua-driver-linux-background-gui-qt5-openambit
  • cua-driver-linux-background-gui-qt6-kate
  • cua-driver-linux-background-gui-qt6-kcalc
  • cua-driver-linux-background-gui-qt6-okular
  • cua-driver-linux-background-gui-qt6-qownnotes
  • cua-driver-linux-background-gui-electron-zettlr
  • cua-driver-linux-background-gui-electron-joplin
  • cua-driver-linux-background-gui-electron-logseq
  • cua-driver-linux-som-overlays

Open workflow run and download artifacts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs (1)

160-169: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: factor out the duplicated connect-then-fallback logic.

wm_class_for_window repeats the same RustConnection→XCBConnection strategy as list_windows_inner, but in a different shape (sequential if let vs match). A small generic helper that runs a closure against whichever connection succeeds would keep the two call sites from drifting (e.g., if a third connect strategy or a timeout is added later).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs` around lines 160 -
169, The wm_class_for_window function duplicates the
RustConnection→XCBConnection fallback pattern already present in
list_windows_inner. Extract this common connection-retry logic into a generic
helper function that accepts a closure parameterized over the connection type,
then refactor both wm_class_for_window and list_windows_inner to use this shared
helper instead of repeating the sequential if-let connection attempts. This
prevents the two implementations from drifting apart if future changes (like
adding a third strategy or timeout handling) are needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/cua-driver/rust/crates/platform-linux/Cargo.toml`:
- Line 24: The x11rb dependency in Cargo.toml with the `allow-unsafe-code`
feature enabled requires the system libxcb library to be available at build time
for FFI bindings, but the build and CI environments do not currently provision
libxcb-dev. To fix this, update your Dockerfile to install libxcb-dev as part of
the build stage, and update all CI workflow manifests to install libxcb-dev
before running build and test steps. This ensures the system has the required
development headers available when linking against x11rb with
`allow-unsafe-code` enabled.

---

Nitpick comments:
In `@libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs`:
- Around line 160-169: The wm_class_for_window function duplicates the
RustConnection→XCBConnection fallback pattern already present in
list_windows_inner. Extract this common connection-retry logic into a generic
helper function that accepts a closure parameterized over the connection type,
then refactor both wm_class_for_window and list_windows_inner to use this shared
helper instead of repeating the sequential if-let connection attempts. This
prevents the two implementations from drifting apart if future changes (like
adding a third strategy or timeout handling) are needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: afb8f180-3c67-45d8-98df-ea7d14c850f0

📥 Commits

Reviewing files that changed from the base of the PR and between c898d7b and 4fb723d.

📒 Files selected for processing (3)
  • libs/cua-driver/rust/crates/platform-linux/Cargo.toml
  • libs/cua-driver/rust/crates/platform-linux/src/health_report.rs
  • libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs

# X11 background input + window enumeration.
# `allow-unsafe-code` enables the libxcb-backed `XCBConnection`, used as a
# fallback when the pure-Rust connect fails strict auth-cookie matching (#1978).
x11rb = { version = "0.13", features = ["xinput", "randr", "xfixes", "composite", "shape", "xtest", "allow-unsafe-code"] }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find build/CI/container manifests and check for libxcb provisioning.
fd -t f -i -e dockerfile -e yml -e yaml -e toml -e sh -e nix . \
  | xargs rg -nI -i 'libxcb|xcb-dev|xorg' 2>/dev/null

echo "---- CI workflow files ----"
fd -t f . .github 2>/dev/null | xargs rg -nI -i 'libxcb|apt|install' 2>/dev/null

Repository: trycua/cua

Length of output: 22534


🌐 Web query:

In x11rb 0.13, which Cargo feature enables the xcb_ffi module / XCBConnection, and does it require linking system libxcb?

💡 Result:

In x11rb 0.13, the xcb_ffi module and the XCBConnection struct are enabled by the allow-unsafe-code Cargo feature [1][2][3]. Without this feature, these components are unavailable because the crate disables all unsafe code by default [4][2]. Regarding system linking: - By default, enabling allow-unsafe-code will link the resulting executable against the system's libxcb [2][3]. - If you wish to avoid linking against the system libxcb at compile time, you can enable the dl-libxcb feature instead [2][3]. This feature dynamically loads libxcb at runtime and also enables allow-unsafe-code [5][6]. The dl-libxcb feature provides the load_libxcb function, which allows your application to handle cases where libxcb is not present on the system [1][2].

Citations:


Add libxcb-dev to build/CI environments before linking x11rb with allow-unsafe-code.

Enabling allow-unsafe-code activates x11rb's xcb_ffi::XCBConnection, which requires linking against the system libxcb library at build time. The Docker builds and CI workflows do not currently provision libxcb or libxcb-dev, meaning builds will fail on any system lacking it—despite the prior pure-Rust path requiring no such dependency. Update your Dockerfile and CI manifests to install libxcb-dev (or libxcb for runtime) in all build/test environments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-linux/Cargo.toml` at line 24, The x11rb
dependency in Cargo.toml with the `allow-unsafe-code` feature enabled requires
the system libxcb library to be available at build time for FFI bindings, but
the build and CI environments do not currently provision libxcb-dev. To fix
this, update your Dockerfile to install libxcb-dev as part of the build stage,
and update all CI workflow manifests to install libxcb-dev before running build
and test steps. This ensures the system has the required development headers
available when linking against x11rb with `allow-unsafe-code` enabled.

…s works where xdotool does (#1978)

x11rb's pure-Rust RustConnection::connect does strict Xauthority
family/address cookie matching and returns Err in some setups (XFCE/lightdm,
hostname-mismatched auth entries) where libxcb-based tools (xdotool, pyatspi)
connect fine. list_windows then silently returned 0 windows and the health
report said "X11 is not reachable", despite a working X session.

- Try RustConnection first, fall back to the libxcb XCBConnection (enabled via
  x11rb allow-unsafe-code) — same client lib xdotool/pyatspi use.
- Make the window-enumeration helpers generic over the connection type.
- When BOTH connects fail, surface a descriptive error (DISPLAY/XAUTHORITY +
  both underlying errors) instead of collapsing to an empty list.
- Mirror the fallback in the doctor's probe_x11_connect so the verdict matches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
@f-trycua f-trycua force-pushed the fix/x11-libxcb-fallback-1978 branch from 4fb723d to 28c55e6 Compare June 24, 2026 02:18
f-trycua and others added 2 commits June 23, 2026 19:21
… x11rb xcb-ffi (#1978)

Enabling the x11rb `allow-unsafe-code` feature pulls in the `xcb_ffi`
module, which depends on `as-raw-xcb-connection` (+ libc) — crates that
were not in the committed Cargo.lock. The earlier VM build that validated
this change ran online, so cargo fetched the new crate transparently; CI's
Nix build runs `cargo build --offline` against a vendored dir and failed
with "no matching package named `as-raw-xcb-connection` found", breaking
every Linux integration job (build-time, before any test ran).

Add the package + the two new x11rb dependency edges to Cargo.lock so the
offline/vendored build resolves. Minimal in-place update (cargo metadata),
no unrelated version churn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
…fi (#1978)

The x11rb `allow-unsafe-code` feature compiles its `xcb_ffi` module (the
libxcb-backed XCBConnection fallback for strict-Xauthority setups, #1978),
which emits `cargo:rustc-link-lib=xcb`. The cua-driver binary therefore now
hard-links libxcb, but none of the build manifests provided it:

- nix/cua-driver/package.nix: link failed with `-lxcb` and no matching `-L`
  ("collect2: ld returned 1 exit status") in every nix VM test. Add `libxcb`
  to buildInputs; update the stale "x11rb -> no libxcb C binding" comment.
- cd-rust-cua-driver.yml: the debian:11 release build would fail the same
  way. Add `libxcb1-dev`.
- ci-distro-compat-cua-driver.yml: the released binary now needs the libxcb
  runtime lib at load time; add `libxcb1` (deb) / `libxcb` (rpm) to every
  distro's runtime install so --version doesn't exit 127 on an ABI error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
@f-trycua

Copy link
Copy Markdown
Collaborator Author

CI now green (minus the known cursor-click-gif flake).

Root cause of the broad CI failure (real regression, not flake)

Enabling the x11rb allow-unsafe-code feature compiles its xcb_ffi module (the libxcb-backed XCBConnection fallback), which pulled in a new transitive crate and a new linked C library that no build manifest declared. This broke in two layers:

  1. Cargo.lock was missing as-raw-xcb-connection (+ the libc/as-raw-xcb-connection edges on x11rb). The original validation build ran online so cargo fetched it silently; CI’s Nix build runs cargo build --offline against a vendored dir and failed at dependency resolution (no matching package named as-raw-xcb-connection found) — before any test ran, which is why every Linux job failed identically.
  2. libxcb was not linked. xcb_ffi emits cargo:rustc-link-lib=xcb, so the binary now hard-links libxcb, but nix/cua-driver/package.nix (and the CD/distro-compat workflows) never provided it → collect2: ld returned 1 exit status (-lxcb with no matching -L).

Fix

  • Cargo.lock: vendor as-raw-xcb-connection (minimal in-place resolve).
  • nix/cua-driver/package.nix: add libxcb to buildInputs.
  • cd-rust-cua-driver.yml: add libxcb1-dev (release build).
  • ci-distro-compat-cua-driver.yml: add libxcb1/libxcb runtime lib for every distro (the released binary now loads libxcb at runtime).
  • Rebased onto current main (8 PRs merged since branch point; health_report.rs rebased clean).

Status

67 pass / 3 fail. The only red checks are gnome|kde|xfce-labwc / cursor-click-gif — the known flake (fails on current main and on Windows-only PRs too; was the sole red check on all 8 merged sibling PRs in this batch). Non-gif failures: 0.

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.

Linux: list_windows returns 0 despite apps running, AT-SPI tree accessible but no window elements

1 participant