srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/state
diff options
context:
space:
mode:
Diffstat (limited to 'crates/wayland/src/state')
-rw-r--r--crates/wayland/src/state/lifecycle.rs39
-rw-r--r--crates/wayland/src/state/menu.rs28
2 files changed, 64 insertions, 3 deletions
diff --git a/crates/wayland/src/state/lifecycle.rs b/crates/wayland/src/state/lifecycle.rs
index 0d301dc..db2de44 100644
--- a/crates/wayland/src/state/lifecycle.rs
+++ b/crates/wayland/src/state/lifecycle.rs
@@ -74,6 +74,33 @@ impl CompState {
let Some(w) = self.wm.borrow().window(id).cloned() else { return };
let focused = self.wm.borrow().focused_id() == Some(id);
let theme = self.wm.borrow().theme;
+ // `main.rs`'s `sync()` calls `Platform::redraw_decoration` - which
+ // always reaches here - for every visible window on every dirty
+ // tick, not only the window that actually changed (see `Comp
+ // State::decoration_signatures`'s own doc comment: a resize drag on
+ // one window re-renders every *other* open window's title text and
+ // border strips too, once per pointer-motion event, for pixels
+ // identical to what's already cached). Skipping the rebuild when
+ // nothing this function reads has actually changed since the last
+ // call turns those redundant calls into a cheap signature
+ // comparison instead of a full re-rasterization.
+ let signature = DecorationSignature {
+ width: w.geometry.width,
+ height: w.geometry.height,
+ decorated: w.decorated,
+ focused,
+ title: w.title.clone(),
+ border_color: w.border_color,
+ border_width: w.border_width,
+ corner_radius: w.corner_radius,
+ maximized: w.maximized,
+ fullscreen: w.fullscreen,
+ shadows_enabled: self.wm.borrow().shadows_enabled,
+ };
+ if self.decoration_signatures.get(&id) == Some(&signature) {
+ return;
+ }
+ self.decoration_signatures.insert(id, signature);
if w.decorated {
let fg = if focused { theme.titlebar_fg_focused } else { theme.titlebar_fg_unfocused };
let width = w.geometry.width.max(1);
@@ -82,7 +109,7 @@ impl CompState {
// cut, so there's no more square-frame-around-a-round-titlebar
// clash to avoid. See `render_titlebar`'s `round_corners` doc
// comment.
- let data = decoration::render_titlebar(width, TITLEBAR_HEIGHT, &w.title, theme.titlebar_bg, fg, true);
+ let data = decoration::render_titlebar(width, TITLEBAR_HEIGHT, &w.title, theme.titlebar_bg, fg, true, w.corner_radius);
let buffer = MemoryRenderBuffer::from_slice(&data, Fourcc::Argb8888, (width as i32, TITLEBAR_HEIGHT as i32), 1, Transform::Normal, None);
self.decorations.insert(id, buffer);
} else {
@@ -102,7 +129,7 @@ impl CompState {
let color = effective_border_color(w.border_color, focused);
let strips = decoration::border_strips(w.geometry, w.border_width);
if strips[0].width > 0 && strips[0].height > 0 {
- let data = decoration::render_border_top(strips[0].width, w.border_width, color);
+ let data = decoration::render_border_top(strips[0].width, w.border_width, color, w.corner_radius);
let buffer =
MemoryRenderBuffer::from_slice(&data, Fourcc::Argb8888, (strips[0].width as i32, w.border_width as i32), 1, Transform::Normal, None);
self.border_top_decorations.insert(id, buffer);
@@ -110,7 +137,7 @@ impl CompState {
self.border_top_decorations.remove(&id);
}
if strips[1].width > 0 && strips[1].height > 0 {
- let data = decoration::render_border_bottom(strips[1].width, w.border_width, color);
+ let data = decoration::render_border_bottom(strips[1].width, w.border_width, color, w.corner_radius);
let buffer =
MemoryRenderBuffer::from_slice(&data, Fourcc::Argb8888, (strips[1].width as i32, w.border_width as i32), 1, Transform::Normal, None);
self.border_bottom_decorations.insert(id, buffer);
@@ -150,6 +177,7 @@ impl CompState {
self.border_bottom_decorations.remove(&id);
self.shadow_buffers.remove(&id);
self.border_side_buffers.remove(&id);
+ self.decoration_signatures.remove(&id);
self.last_synced_size.remove(&id);
self.content_epoch.remove(&id);
self.rounded_content_buffers.remove(&id);
@@ -161,6 +189,11 @@ impl CompState {
if self.context_menu.as_ref().is_some_and(|m| m.window == id) {
self.close_context_menu();
}
+ // Same reasoning as the context menu above, for the Snap-Layouts
+ // flyout.
+ if self.snap_flyout.as_ref().is_some_and(|f| f.window == id) {
+ self.close_snap_flyout();
+ }
self.wm.borrow_mut().remove_window(id);
self.pending.borrow_mut().push(CoreEvent::WindowDestroyed(id));
foreign_toplevel::window_closed(self, id);
diff --git a/crates/wayland/src/state/menu.rs b/crates/wayland/src/state/menu.rs
index ccd784e..9f645a8 100644
--- a/crates/wayland/src/state/menu.rs
+++ b/crates/wayland/src/state/menu.rs
@@ -56,6 +56,34 @@ impl CompState {
}
}
+ /// Opens the Snap-Layouts flyout for `window`, top-left corner at `pos`
+ /// (global space, by convention the maximize button's own titlebar
+ /// position). Same build-once-on-open pattern as `open_context_menu`.
+ pub(crate) fn open_snap_flyout(&mut self, window: WindowId, pos: (i32, i32)) {
+ let flyout = crate::snap_flyout::SnapFlyout::open(window, pos);
+ let theme = self.wm.borrow().theme;
+ let labels: Vec<&str> = flyout.cells().iter().map(|z| z.label()).collect();
+ let data = decoration::render_snap_flyout(3, flyout.cell_width, flyout.cell_height, &labels, theme.titlebar_bg, theme.titlebar_fg_focused, theme.default_border_color);
+ let buffer = MemoryRenderBuffer::from_slice(&data, Fourcc::Argb8888, (flyout.width() as i32, flyout.height() as i32), 1, Transform::Normal, None);
+ self.snap_flyout_buffer = Some(buffer);
+ self.snap_flyout = Some(flyout);
+ }
+
+ pub(crate) fn close_snap_flyout(&mut self) {
+ self.snap_flyout = None;
+ self.snap_flyout_buffer = None;
+ }
+
+ /// Applies `zone` to `window` - the flyout's own equivalent of
+ /// `run_context_menu_action`, taking the target explicitly rather than
+ /// reading `self.snap_flyout` for the same borrow-conflict reason
+ /// documented on that function.
+ pub(crate) fn run_snap_flyout_action(&mut self, window: WindowId, zone: SnapZoneKind) {
+ self.wm.borrow_mut().apply_snap_zone(window, zone);
+ self.sync_geometry(window);
+ foreign_toplevel::send_state(self, window);
+ }
+
/// True when this titlebar press is the second of a double-click on the
/// same window. Threshold is the usual 400ms.
pub(crate) fn is_double_click(&mut self, id: WindowId, time: u32) -> bool {