diff options
Diffstat (limited to 'crates/wayland/src/winit')
| -rw-r--r-- | crates/wayland/src/winit/capture.rs | 48 | ||||
| -rw-r--r-- | crates/wayland/src/winit/connect.rs | 1 | ||||
| -rw-r--r-- | crates/wayland/src/winit/render.rs | 20 |
3 files changed, 65 insertions, 4 deletions
diff --git a/crates/wayland/src/winit/capture.rs b/crates/wayland/src/winit/capture.rs index d21ed72..c382190 100644 --- a/crates/wayland/src/winit/capture.rs +++ b/crates/wayland/src/winit/capture.rs @@ -17,10 +17,18 @@ impl WaylandPlatform { renderer.create_buffer(Fourcc::Abgr8888, (size.w, size.h).into()).map_err(err)?; let mut framebuffer = renderer.bind(&mut target).map_err(err)?; - // Not full parity with the on-screen render loop above (no border/ - // shadow strips here, same as before this function's content/opacity - // fix) - a real, pre-existing gap in what a screenshot shows on - // this backend, flagged rather than grown further in this pass. + // WHAT THIS PASS STILL DOES NOT DRAW: border strips, and the + // desktop icon grid. Everything else the on-screen loop draws is + // covered - content, titlebars, shadows, layer-shell surfaces, + // popups, both menus, the Snap-Layouts flyout and the drag snap + // preview. + // + // Keep this list honest. The whole reason the nested backend exists + // is checking behaviour with `grim`, and a tier missing here makes + // a working feature photograph as broken. That has now cost four + // separate investigations in one day (popups, shadows, the drag + // snap preview, the desktop menu), every one of them starting from + // a screenshot that was quietly lying. // Content (with each window's own `opacity`, unlike the // `self.state.space`-based single-alpha call this replaced) and the // bar/dock now render into the capture, at least: a screenshot used @@ -48,6 +56,38 @@ impl WaylandPlatform { // like the client never opened one. let popup_targets = crate::elements::popup_targets(&self.state); custom_elements.extend(crate::elements::popup_render_elements(&popup_targets, renderer, (0, 0))); + // The titlebar context menu and the desktop/desktop-icon menu, both + // topmost, in the same order the on-screen loop draws them. + for (menu_pos, buffer) in [ + (self.state.context_menu.as_ref().map(|m| m.pos), self.state.context_menu_buffer.as_ref()), + (self.state.desktop_menu.as_ref().map(|m| m.pos), self.state.desktop_menu_buffer.as_ref()), + ] { + let (Some(pos), Some(buffer)) = (menu_pos, buffer) else { continue }; + match MemoryRenderBufferRenderElement::from_buffer(renderer, (pos.0 as f64, pos.1 as f64), buffer, None, None, None, Kind::Unspecified) { + Ok(elem) => custom_elements.push(crate::elements::OverlayElement::Memory(elem)), + Err(e) => log::warn!("screencopy: failed to import menu buffer: {e}"), + } + } + // The Snap-Layouts flyout and the drag snap preview, in the same + // order the on-screen loop draws them. Both are drag-time overlays, + // and a screenshot that omits them cannot be used to check either + // one - which is exactly how this pass's missing popup tier wasted + // a session already. + if let (Some(flyout), Some(buffer)) = (self.state.snap_flyout.as_ref(), self.state.snap_flyout_buffer.as_ref()) { + let pos = (flyout.pos.0 as f64, flyout.pos.1 as f64); + match MemoryRenderBufferRenderElement::from_buffer(renderer, pos, buffer, None, None, None, Kind::Unspecified) { + Ok(elem) => custom_elements.push(crate::elements::OverlayElement::Memory(elem)), + Err(e) => log::warn!("screencopy: failed to import snap flyout buffer: {e}"), + } + } + if let Some(rect) = self.wm.borrow().drag_snap_preview() { + let accent = self.wm.borrow().theme.default_border_color; + custom_elements.extend( + crate::elements::snap_preview_elements(&mut self.state.snap_preview_buffers, rect, accent, (0, 0)) + .into_iter() + .map(crate::elements::OverlayElement::Solid), + ); + } if !hide_top_layers { custom_elements.extend(crate::elements::output_layer_elements(renderer, &self.output, |layer| matches!(layer, Layer::Top | Layer::Overlay))); } diff --git a/crates/wayland/src/winit/connect.rs b/crates/wayland/src/winit/connect.rs index 4c6954b..1648826 100644 --- a/crates/wayland/src/winit/connect.rs +++ b/crates/wayland/src/winit/connect.rs @@ -179,6 +179,7 @@ impl WaylandPlatform { content_epoch: HashMap::new(), rounded_content_buffers: HashMap::new(), border_side_buffers: HashMap::new(), + snap_preview_buffers: Vec::new(), color_filter_buffers: HashMap::new(), last_synced_size: HashMap::new(), provisional_size: HashSet::new(), diff --git a/crates/wayland/src/winit/render.rs b/crates/wayland/src/winit/render.rs index dff425f..ccc64a2 100644 --- a/crates/wayland/src/winit/render.rs +++ b/crates/wayland/src/winit/render.rs @@ -135,6 +135,26 @@ impl WaylandPlatform { Err(e) => log::warn!("failed to import context menu buffer: {e}"), } } + // ADDING A TIER HERE? THIS BACKEND RENDERS THE SCENE TWICE. What a + // screenshot shows comes from `winit/capture.rs`'s own separate + // offscreen pass, not from this loop, so anything pushed here and + // not there is on screen but invisible to `grim` - which reads as + // the feature being broken. That gap has now cost two separate + // investigations in one day (popups, then this very preview). The + // DRM backend has no equivalent trap: it serves screencopy out of + // the frame it just drew. + // + // The drag snap preview - below the flyout (which the pointer is + // actively aiming at) but above every window, since it is showing + // where one of them is about to go. + if let Some(rect) = self.wm.borrow().drag_snap_preview() { + let accent = self.wm.borrow().theme.default_border_color; + custom_elements.extend( + crate::elements::snap_preview_elements(&mut self.state.snap_preview_buffers, rect, accent, (0, 0)) + .into_iter() + .map(|e| crate::rounded_corners::WinitElement::Base(crate::elements::OverlayElement::Solid(e))), + ); + } // The Snap-Layouts flyout, if open - same topmost placement. if let (Some(flyout), Some(buffer)) = (self.state.snap_flyout.as_ref(), self.state.snap_flyout_buffer.as_ref()) { let pos = (flyout.pos.0 as f64, flyout.pos.1 as f64); |