Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions libs/cua-driver/rust/crates/platform-linux/src/health_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,29 @@ async fn check_wayland_backend() -> CheckEntry {
format!("All wlroots manager globals advertised ({msg})."),
);
}
// Input-injection backend check (#1982). A non-wlroots compositor
// (KWin/Plasma, Mutter/GNOME) advertises no zwlr_virtual_pointer; on those
// the ONLY working input path is libei via xdg-desktop-portal. If this
// binary was built without `portal-libei` (the published tarball is — see
// #1967), input injection has no backend and silently no-ops: the agent
// cursor renders but clicks/keys are never delivered, while list_windows
// and capture still work. Report that explicitly instead of the misleading
// "input may fall back" partial-pass below.
if !snap.virtual_pointer && !crate::wayland::PORTAL_LIBEI_ENABLED {
return CheckEntry::fail(
NAME_WAYLAND_BACKEND,
format!(
"Input injection has no backend on this compositor ({msg}): it \
advertises no zwlr_virtual_pointer and this build was compiled \
without libei/portal support, so clicks and key presses will not \
be delivered (the agent cursor still renders). list_windows and \
screen capture are unaffected."
),
"Use the portal-enabled Linux build (compiled with --features \
portal-libei) for input on KDE Plasma / GNOME, or a wlroots \
compositor (sway, labwc, hyprland) where zwlr_virtual_pointer exists.",
);
Comment on lines +292 to +305

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid unconditional “unaffected” wording for other capabilities.

Line [299]-Line [300] says list_windows and screen capture are unaffected, but this branch also runs when foreign_toplevel/screencopy/wl_shm are missing. That can mislead diagnosis on compositors missing additional globals.

Suggested wording fix
         return CheckEntry::fail(
             NAME_WAYLAND_BACKEND,
             format!(
                 "Input injection has no backend on this compositor ({msg}): it \
                  advertises no zwlr_virtual_pointer and this build was compiled \
                  without libei/portal support, so clicks and key presses will not \
-                 be delivered (the agent cursor still renders). list_windows and \
-                 screen capture are unaffected."
+                 be delivered (the agent cursor still renders). list_windows and \
+                 screen capture depend on foreign-toplevel/screencopy/wl_shm \
+                 availability."
             ),
             "Use the portal-enabled Linux build (compiled with --features \
              portal-libei) for input on KDE Plasma / GNOME, or a wlroots \
              compositor (sway, labwc, hyprland) where zwlr_virtual_pointer exists.",
         );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if !snap.virtual_pointer && !crate::wayland::PORTAL_LIBEI_ENABLED {
return CheckEntry::fail(
NAME_WAYLAND_BACKEND,
format!(
"Input injection has no backend on this compositor ({msg}): it \
advertises no zwlr_virtual_pointer and this build was compiled \
without libei/portal support, so clicks and key presses will not \
be delivered (the agent cursor still renders). list_windows and \
screen capture are unaffected."
),
"Use the portal-enabled Linux build (compiled with --features \
portal-libei) for input on KDE Plasma / GNOME, or a wlroots \
compositor (sway, labwc, hyprland) where zwlr_virtual_pointer exists.",
);
if !snap.virtual_pointer && !crate::wayland::PORTAL_LIBEI_ENABLED {
return CheckEntry::fail(
NAME_WAYLAND_BACKEND,
format!(
"Input injection has no backend on this compositor ({msg}): it \
advertises no zwlr_virtual_pointer and this build was compiled \
without libei/portal support, so clicks and key presses will not \
be delivered (the agent cursor still renders). list_windows and \
screen capture depend on foreign-toplevel/screencopy/wl_shm \
availability."
),
"Use the portal-enabled Linux build (compiled with --features \
portal-libei) for input on KDE Plasma / GNOME, or a wlroots \
compositor (sway, labwc, hyprland) where zwlr_virtual_pointer exists.",
);
🤖 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/health_report.rs` around lines
292 - 305, The error message in the CheckEntry::fail call for the
NAME_WAYLAND_BACKEND check unconditionally states that list_windows and screen
capture are unaffected, but this branch executes whenever virtual_pointer is
unavailable and portal_libei is disabled, regardless of whether
foreign_toplevel, screencopy, or wl_shm are present. Modify the message to
either conditionally include the "unaffected" statement only when those other
required globals are verified to exist, or remove the specific claim about which
capabilities are unaffected to avoid misleading diagnosis on compositors with
missing additional globals.

}
// Partial-pass: list_windows + capture both work, but virtual-pointer
// input is missing. Require `wl_shm` here too — `check_screen_capture_capability`
// gates on both `screencopy && wl_shm`, so excluding `wl_shm` from the
Expand Down
30 changes: 26 additions & 4 deletions libs/cua-driver/rust/crates/platform-linux/src/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ pub mod portal_screencast;
#[cfg(feature = "portal-libei")]
pub mod libei;

/// Whether this binary was compiled with the `portal-libei` feature — the
/// xdg-desktop-portal RemoteDesktop + libei input path. It is the ONLY input
/// backend that works on non-wlroots compositors (KWin/Plasma, Mutter/GNOME),
/// which do not implement `zwlr_virtual_pointer_v1`. The published
/// curl-pipe-bash tarball is built WITHOUT it (#1967 — debian:11 CD container
/// lacks a new-enough PipeWire/libei), so on those compositors input injection
/// has no backend and silently no-ops. Consulted by the doctor and the input
/// dispatch so that failure is reported instead of hidden. See #1982.
pub const PORTAL_LIBEI_ENABLED: bool = cfg!(feature = "portal-libei");

use std::collections::HashMap;

use wayland_client::{
Expand Down Expand Up @@ -786,10 +796,22 @@ pub fn open_vptr_session(activate_window_id: Option<u32>) -> anyhow::Result<Vptr
.seat
.clone()
.ok_or_else(|| anyhow::anyhow!("compositor exposed no wl_seat for virtual-pointer input"))?;
let mgr = state
.vptr_manager
.clone()
.ok_or_else(|| anyhow::anyhow!("compositor does not expose zwlr_virtual_pointer_manager_v1"))?;
let mgr = state.vptr_manager.clone().ok_or_else(|| {
if PORTAL_LIBEI_ENABLED {
anyhow::anyhow!("compositor does not expose zwlr_virtual_pointer_manager_v1")
} else {
// KWin/Plasma and Mutter/GNOME don't implement zwlr_virtual_pointer,
// and this build has no libei/portal fallback — so input has no
// backend at all rather than silently no-op'ing. See #1982.
anyhow::anyhow!(
"no input backend for this compositor: it exposes no \
zwlr_virtual_pointer_manager_v1 and this build was compiled \
without libei/portal support (#1982). Use the portal-enabled \
Linux build for input on KDE Plasma / GNOME, or a wlroots \
compositor (sway, labwc, hyprland)."
)
}
})?;

if let Some(id) = activate_window_id {
let handle = state
Expand Down
Loading