From f2de3ebc61cc3f5d4c4081e9aa22fb1b6623f24d Mon Sep 17 00:00:00 2001 From: natepayn3 <284325035+natepayn3@users.noreply.github.com> Date: Fri, 6 Nov 2026 08:42:58 -0700 Subject: [PATCH] Glass: a capture pleamar-wm took without our surface is the background as it is pleamar-wm marks a screencopy frame with flag 1<<16 when it left out the surfaces of the program that asked. Nothing of ours is then unmixed from it (opacity 0 in the unmix), so the holes under our opaque parts are gone. --- src/platform/wayland.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs index d88516c..2e0f197 100644 --- a/src/platform/wayland.rs +++ b/src/platform/wayland.rs @@ -514,8 +514,16 @@ struct CaptureFor { dmabuf: Mutex>, /// The buffer on the card it was asked to copy into. on_card: Mutex>>, + /// The compositor says the picture is of what is behind our surface, without it (pleamar-wm's + /// `WITHOUT_YOU` flag): it is the background as it is, and nothing of ours is unmixed from it. + without_us: std::sync::atomic::AtomicBool, } +/// pleamar-wm's flag on a screencopy frame (after `y_invert`, 1): the picture leaves out the surfaces of the +/// program that asked. Under our opaque parts —a grid of pictures— the background cannot be unmixed, and +/// left holes a dome magnified into view; with it there is nothing to unmix. +const WITHOUT_YOU: u32 = 1 << 16; + /// A capture made of several small ones: the glass of a shell is a frame round the screen, and the one box /// that holds it all is the whole screen, of which the compositor would read back (and we would upload) twenty /// times what is needed. Each part is photographed on its own and copied to where it goes in one buffer @@ -613,6 +621,13 @@ impl Dispatch2 for CaptureFor { *self.dmabuf.lock().unwrap() = Some((format, width, height)); CARD_OFFERED.store(true, Ordering::Relaxed); } + E::Flags { flags } => { + let bits = match flags { + wayland_client::WEnum::Value(f) => f.bits(), + wayland_client::WEnum::Unknown(v) => v, + }; + self.without_us.store(bits & WITHOUT_YOU != 0, Ordering::Relaxed); + } E::BufferDone => { let id = self.target.id; // On the card, if the render has made a buffer of the very size and format offered: @@ -672,7 +687,8 @@ impl Dispatch2 for CaptureFor { } E::Ready { .. } => { let id = self.target.id; - let opacity = *self.target.opacity.lock().unwrap(); + // Without us in it, there is nothing of ours to take out of it: as if ours were not there. + let opacity = if self.without_us.load(Ordering::Relaxed) { 0.0 } else { *self.target.opacity.lock().unwrap() }; let Some((parts, k)) = &self.part else { if let Some(card) = self.on_card.lock().unwrap().take() { let _ = e.to_render.send(ToRender::Backdrop(Box::new(super::Backdrop { sheet: id, width: card.size.0, height: card.size.1, stride: 0, opacity, data: None, rects: Vec::new(), card: Some(card), offer: None }))); @@ -929,10 +945,10 @@ impl PlatformWindow for WaylandWindow { if rects.len() >= 2 && !PARTS_BROKEN.load(Ordering::Relaxed) && !on_card { let parts = Arc::new(Mutex::new(Parts { hull: bounds, rects: rects.clone(), valid: Vec::new(), over: false })); for (k, r) in rects.iter().enumerate() { - frames.push(manager.capture_output_region(0, &output, x + r[0], y + r[1], r[2], r[3], &qh, CaptureFor { target: d.clone(), on_change, format: Mutex::new(None), part: Some((parts.clone(), k)), dmabuf: Mutex::new(None), on_card: Mutex::new(None) })); + frames.push(manager.capture_output_region(0, &output, x + r[0], y + r[1], r[2], r[3], &qh, CaptureFor { target: d.clone(), on_change, format: Mutex::new(None), part: Some((parts.clone(), k)), dmabuf: Mutex::new(None), on_card: Mutex::new(None), without_us: std::sync::atomic::AtomicBool::new(false) })); } } else { - frames.push(manager.capture_output_region(0, &output, x + bounds[0], y + bounds[1], bounds[2], bounds[3], &qh, CaptureFor { target: d.clone(), on_change, format: Mutex::new(None), part: None, dmabuf: Mutex::new(None), on_card: Mutex::new(None) })); + frames.push(manager.capture_output_region(0, &output, x + bounds[0], y + bounds[1], bounds[2], bounds[3], &qh, CaptureFor { target: d.clone(), on_change, format: Mutex::new(None), part: None, dmabuf: Mutex::new(None), on_card: Mutex::new(None), without_us: std::sync::atomic::AtomicBool::new(false) })); } }; // With frames of its own, after the frame just handed over, from the thread that hands