diff --git a/crates/pi-natives/src/desktop/linux/wayland/mod.rs b/crates/pi-natives/src/desktop/linux/wayland/mod.rs index 5638fc936..05042729e 100644 --- a/crates/pi-natives/src/desktop/linux/wayland/mod.rs +++ b/crates/pi-natives/src/desktop/linux/wayland/mod.rs @@ -100,12 +100,19 @@ impl Backend for WaylandBackend { DesktopCapabilities { backend: "wayland".to_string(), display_server: Some("wayland".to_string()), - capture: true, + // The PipeWire screencast path is compiled in only under the + // wayland-pipewire feature; without it capture() hard-errors, so the + // capability report must not advertise a capture the binary cannot do. + capture: cfg!(feature = "wayland-pipewire"), input: self.input.is_some(), ax: self.ax.is_some(), background_window_input: false, delivery_modes: vec!["background".to_string()], - capture_permission: "prompt-or-granted".to_string(), + capture_permission: if cfg!(feature = "wayland-pipewire") { + "prompt-or-granted".to_string() + } else { + "unavailable".to_string() + }, input_permission: if self.input.is_some() { "granted".to_string() } else { @@ -289,4 +296,26 @@ mod tests { let mut backend = backend_without_services(); assert_eq!(backend.capabilities().delivery_modes, ["background"]); } + + #[test] + #[cfg(not(feature = "wayland-pipewire"))] + fn capabilities_report_no_capture_without_pipewire_feature() { + let mut backend = WaylandBackend { + display: DisplaySelector::All, + ax: None, + ax_error: None, + input: None, + input_error: None, + displays: Vec::new(), + }; + let caps = backend.capabilities(); + // Shipped builds compile without wayland-pipewire, so the capture path is + // absent; capabilities() must not advertise capture the binary cannot do. + assert!(!caps.capture, "capture must be false when the pipewire feature is off"); + assert_eq!(caps.capture_permission, "unavailable"); + let err = backend + .capture(&Target::Desktop, &CaptureCaps::default()) + .expect_err("capture must fail without the pipewire feature"); + assert_eq!(err.code.as_str(), "CaptureFailed"); + } } diff --git a/docs/computer-use.md b/docs/computer-use.md index e320b0e30..55b3a1e27 100644 --- a/docs/computer-use.md +++ b/docs/computer-use.md @@ -131,11 +131,11 @@ await wait( | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | macOS x64/arm64 | ScreenCapture/Quartz plus native AX and input. Grant Screen Recording for capture and Accessibility for input/AX, then restart the launching host. | | Linux X11 x64/arm64 | X11 capture/input and AT-SPI accessibility. Requires a readable display plus RandR/XTEST. | -| Linux Wayland x64/arm64 | ScreenCast portal/PipeWire capture, RemoteDesktop portal or `LIBEI_SOCKET` input, and AT-SPI accessibility. Portal permission prompts and compositor restrictions apply; background per-window native input is unavailable. | +| Linux Wayland x64/arm64 | RemoteDesktop portal or `LIBEI_SOCKET` input and AT-SPI accessibility. ScreenCast portal/PipeWire capture ships only in builds compiled with the `wayland-pipewire` Cargo feature; released binaries omit it, so `capabilities()` reports `capture: false` there. Portal permission prompts and compositor restrictions apply; background per-window native input is unavailable. | | Windows x64 | Native display/window capture, Win32 input, and UI Automation accessibility. | | Other published targets | Unsupported unless the native addon reports capabilities. | -Inspect `desktop.capabilities()` rather than assuming capture, input, AX, or permission state. On Wayland, a missing portal/PipeWire feature or denied RemoteDesktop portal is reported as a capture/input/permission failure rather than falling back to X11. +Inspect `desktop.capabilities()` rather than assuming capture, input, AX, or permission state. On Wayland, released builds are compiled without the `wayland-pipewire` feature, so `capabilities()` reports `capture: false`; where the feature is present, a missing portal/PipeWire feature or denied RemoteDesktop portal is reported as a capture/input/permission failure rather than falling back to X11. ## Safety and troubleshooting diff --git a/packages/natives/CHANGELOG.md b/packages/natives/CHANGELOG.md index 435139530..83f9bcef3 100644 --- a/packages/natives/CHANGELOG.md +++ b/packages/natives/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Fixed per-window capture always failing on Wayland with `InvalidTarget` for window ids that omp's own `desktop.windows()` minted. The shared capture request path pre-parsed every window id as a `u64` before consulting the backend, which no composite AT-SPI Wayland id (e.g. `atspi::1.31:/org/a11y/atspi/accessible/1`) could satisfy; id validation now belongs to the backend that minted the id, matching X11/Win32/macOS behavior ([#7701](https://github.com/can1357/oh-my-pi/issues/7701)). +- Fixed Wayland `desktop.capabilities()` reporting `capture: true` on builds compiled without the `wayland-pipewire` feature (all released binaries), where every capture call hard-fails with `CaptureFailed`. The `capture` flag and `capture_permission` now reflect the compiled-in feature ([#7700](https://github.com/can1357/oh-my-pi/issues/7700)). ## [17.2.9] - 2026-08-05