srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/udev/render.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/wayland/src/udev/render.rs')
-rw-r--r--crates/wayland/src/udev/render.rs84
1 files changed, 78 insertions, 6 deletions
diff --git a/crates/wayland/src/udev/render.rs b/crates/wayland/src/udev/render.rs
index caf0e0e..9642603 100644
--- a/crates/wayland/src/udev/render.rs
+++ b/crates/wayland/src/udev/render.rs
@@ -17,6 +17,15 @@ impl CompState {
// Same reason: the cursor needs the renderer that borrow owns.
let cursor_status = self.cursor_status.clone();
let cursor_buffers = self.cursor_buffers.clone();
+ // Same reason again: a native lock's capture step (below) needs
+ // this, and `self.wm` can't be borrowed once `self.udev` is.
+ let lock_blur_radius = self.wm.borrow().lock.blur_radius;
+ // Captured-and-blurred backgrounds collected during the per-head
+ // loop below, applied via `self.capture_output` only after it
+ // ends - `self.udev`'s mutable borrow is held for the whole loop
+ // body, and that method needs the whole of `self`, not just the
+ // one field the loop already has.
+ let mut new_captures: Vec<(String, smithay::backend::renderer::element::memory::MemoryRenderBuffer)> = Vec::new();
// Border geometry is in global space, independent of which head
// renders it, so it's gathered once here rather than per head.
@@ -77,6 +86,12 @@ impl CompState {
let mut presented: Vec<(Output, Vec<Rectangle<i32, Physical>>)> = Vec::new();
for (index, output) in ready {
let lock_surface = self.lock_surface_for(&output).cloned();
+ // Extracted before the `self.udev` borrow below starts - see
+ // `native_lock::native_lock_render_elements`'s own doc comment
+ // for why (cheap `MemoryRenderBuffer` clones, not a pixel copy).
+ let native_bg = self.native_lock_background(&output.name()).cloned();
+ let native_ui = self.native_lock_ui().map(|(buf, size)| (buf.clone(), size));
+ let native_needs_capture = self.native_lock_needs_capture(&output.name());
// Content/decoration elements are built per head: both need the
// renderer, and geometry is translated into head-local space.
@@ -112,6 +127,15 @@ impl CompState {
Err(e) => log::warn!("udev: failed to import context menu buffer: {e}"),
}
}
+ // The Snap-Layouts flyout, if open - same "topmost but
+ // never hides the cursor" placement as the context menu.
+ if let (Some(flyout), Some(buffer)) = (self.snap_flyout.as_ref(), self.snap_flyout_buffer.as_ref()) {
+ let pos = ((flyout.pos.0 - origin.x) as f64, (flyout.pos.1 - origin.y) as f64);
+ match MemoryRenderBufferRenderElement::from_buffer(&mut udev.renderer, pos, buffer, None, None, None, Kind::Unspecified) {
+ Ok(elem) => custom_elements.push(crate::elements::OverlayElement::Memory(elem)),
+ Err(e) => log::warn!("udev: failed to import snap flyout buffer: {e}"),
+ }
+ }
// Popups next: always above every window's own content,
// matching this codebase's long-standing behavior from
// before content moved into this same `custom_elements`
@@ -316,7 +340,7 @@ impl CompState {
// bitmap.
let corners = if w.decorated { crate::rounded_corners::RoundedCorners::BOTTOM_ONLY } else { crate::rounded_corners::RoundedCorners::ALL };
if let Some(buffer) =
- crate::elements::rounded_content_buffer(&mut self.rounded_content_buffers, epoch, id, &surface, decoration::CORNER_RADIUS as f32, corners)
+ crate::elements::rounded_content_buffer(&mut self.rounded_content_buffers, epoch, id, &surface, w.corner_radius as f32, corners)
{
match MemoryRenderBufferRenderElement::from_buffer(&mut udev.renderer, (pos.0 as f64, pos.1 as f64), buffer, Some(w.opacity), None, None, Kind::Unspecified)
{
@@ -327,7 +351,9 @@ impl CompState {
}
match rounded_elem {
Some(elem) => custom_elements.push(crate::elements::OverlayElement::Memory(elem)),
- None => custom_elements.extend(crate::elements::surface_content_elements(&mut udev.renderer, &surface, pos, w.opacity)),
+ None => {
+ custom_elements.extend(crate::elements::surface_content_elements(&mut udev.renderer, &surface, pos, w.opacity));
+ }
}
}
}
@@ -343,11 +369,23 @@ impl CompState {
|layer| matches!(layer, Layer::Background | Layer::Bottom),
));
}
- let lock_elements = if locked {
+ // Three genuinely different element types (external `LockSurface`
+ // content, srdwm's own memory-backed background+UI, or the
+ // normal desktop's `custom_elements`), so each is built and
+ // passed to its own `render_output` call below rather than
+ // forced into one shared, unified element list.
+ let is_native = self.lock.native.is_some();
+ let lock_elements = if locked && !is_native {
crate::lock::lock_render_elements(lock_surface.as_ref(), &mut udev.renderer)
} else {
Vec::new()
};
+ let native_elements = if locked && is_native {
+ let size = udev.heads[index].size;
+ crate::native_lock::native_lock_render_elements(native_bg.as_ref(), native_ui.as_ref().map(|(b, s)| (b, *s)), size, &mut udev.renderer)
+ } else {
+ Vec::new()
+ };
let head = &mut udev.heads[index];
let mut framebuffer = match udev.renderer.bind(&mut head.buffers[back].image) {
@@ -358,9 +396,18 @@ impl CompState {
}
};
- // Locked heads draw the lock surface over opaque black and
- // nothing else; unlocked heads draw the normal scene.
- let result = if locked {
+ // Locked heads draw either srdwm's own native lock UI (over
+ // opaque black - the background element covers the visible
+ // area, but the clear colour is still what shows through if a
+ // capture failed or hasn't happened for this output yet) or an
+ // external locker's surface the same way, and nothing else;
+ // unlocked heads draw the normal scene.
+ let result = if locked && is_native {
+ head.damage_tracker
+ .render_output(&mut udev.renderer, &mut framebuffer, 0, &native_elements, [0.0, 0.0, 0.0, 1.0])
+ .map(|r| (r.damage.is_some(), Vec::new()))
+ .map_err(|e| e.to_string())
+ } else if locked {
head.damage_tracker
.render_output(&mut udev.renderer, &mut framebuffer, 0, &lock_elements, [0.0, 0.0, 0.0, 1.0])
.map(|r| (r.damage.is_some(), Vec::new()))
@@ -401,6 +448,22 @@ impl CompState {
let (mine, rest): (Vec<_>, Vec<_>) = captures.into_iter().partition(|c| c.output == output);
captures = rest;
crate::screencopy::service_pending(mine, &mut udev.renderer, &framebuffer);
+
+ // A native lock is waiting on this output's background --
+ // this same freshly-rendered framebuffer (the ordinary
+ // desktop scene, not a lock scene: `locked` is still
+ // `false` here because `begin_native_lock` deliberately
+ // doesn't flip it until every output has one, see that
+ // function's own doc comment) is exactly "what's on
+ // screen right now" for this output.
+ if native_needs_capture {
+ let name = output.name();
+ let size = head.size;
+ match crate::native_lock::capture_and_blur(&mut udev.renderer, &framebuffer, size, lock_blur_radius) {
+ Ok(blurred) => new_captures.push((name, blurred)),
+ Err(e) => log::warn!("native lock: capture failed for output {name}: {e}"),
+ }
+ }
}
drop(framebuffer);
@@ -441,6 +504,15 @@ impl CompState {
}
}
+ // Applies every background captured during the loop above, now
+ // that `self.udev`'s borrow has ended and `self` (specifically
+ // `self.lock`) can be borrowed as a whole again - see
+ // `capture_output`'s own doc comment for what happens once every
+ // output has one (the lock actually engages).
+ for (name, blurred) in new_captures {
+ self.capture_output(&name, blurred);
+ }
+
// Frame callbacks + lock confirmation, once the `udev` borrow is done.
for (output, damage_rects) in presented {
if locked {