Merge pull request #9893 from TaylorBurke/fix/screen-picker-xwayland-8977

Screen picker: a Wayland desktop picks through the portal when the window runs on Xwayland (#8977)
This commit is contained in:
Dylan M. Taylor authored and GitHub committed 2026-10-30 14:42:04 -04:00
commit 952c328b3d
2 files changed
+23 -1

No files matched your search

+8 -1
View File
@@ -645,7 +645,14 @@ fn main() -> eframe::Result {
// Caps Lock state (X11/Windows/macOS; `None` on native Wayland): the canvas shows the
// precise crosshair for painting tools while it is toggled on (#1758).
app.services.caps_lock = caps_lock::service(cc);
app.services.screen_pick = screen_color::service(cc, app.services.is_wayland);
// Pick through the portal on a Wayland desktop even when the window went through
// Xwayland (a pen, or the X11 display-server preference): Xwayland's root window has
// no desktop pixels to read (#8977).
#[cfg(target_os = "linux")]
let portal = screen_color::uses_portal(native_session);
#[cfg(not(target_os = "linux"))]
let portal = false;
app.services.screen_pick = screen_color::service(cc, portal);
// Tablet pressure/tilt/eraser (winit drops them): the macOS monitor and the X11 reader
// write into the stylus feed. The monitor goes in here, not before the event loop:
// AppKit's shared application only exists once winit created it (#759).
+15
View File
@@ -38,6 +38,12 @@ pub fn service(cc: &eframe::CreationContext<'_>, wayland: bool) -> Option<Servic
Pending { receiver: rx, cancelled }
}))
}
/// Whether to pick through the desktop portal: on a Wayland desktop, whichever display server the
/// window opened on. Xwayland serves only its own windows, so reading its root window fails (#8977).
#[cfg(target_os = "linux")]
pub fn uses_portal(desktop: crate::linux_libs::DisplaySession) -> bool {
desktop == crate::linux_libs::DisplaySession::Wayland
}
#[derive(Clone, Copy)]
#[cfg_attr(not(any(target_os = "linux", target_os = "macos", target_os = "windows", test)), allow(dead_code))]
struct Placement {
@@ -480,6 +486,15 @@ mod tests {
let offset = (y * first.width + x) * 4;
assert_eq!(&first.rgba[offset..offset + 4], &[255, 128, 64, 255]);
}
#[cfg(target_os = "linux")]
#[test]
fn a_wayland_desktop_picks_through_the_portal_even_with_an_xwayland_window() {
use crate::linux_libs::DisplaySession;
// A pen or the X11 display-server preference opens the window through Xwayland, but the
// session is still Wayland: the X11 grab fails there with BadMatch (#8977).
assert!(uses_portal(DisplaySession::Wayland));
assert!(!uses_portal(DisplaySession::X11));
}
#[test]
fn screen_capture_matches_negative_and_hidpi_monitor_geometry() {
let m = [Placement { index: 2, x: -3840, y: 0, width: 3840, height: 2160 }];