git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitff09e840bbd2cbf8872748894b14e3737103af69
parent8efc395508
authorLucas Galante <[email protected]>
date2026-08-18 08:21
grid: shrink the patch envelope; never focus the grid at map

- Patch margin halved (0.5 viewports per side, cap 4096px, comfort
  margin 0.15): at output scale 2 the old 3x3-viewport envelope cost
  ~340MB per swapchain image — gigabytes resident in the client for
  scroll headroom the comfort margin rarely used.
- The grid layer no longer takes keyboard focus when it maps: it is
  input-transparent desktop furniture, so focus there was unreachable
  by click and stole the session's focus at every service (re)start.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/server/window.rs         |  6 +++++-
 src/server/window_manager.rs | 21 +++++++++++++--------
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/src/server/window.rs b/src/server/window.rs
index 3731886..13171c6 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -1250,7 +1250,11 @@ impl Window {
                 }
             }
 
-            if should_focus {
+            // The grid layer never takes focus — it is desktop furniture,
+            // not a window (it is also input-transparent, so focus here
+            // would be unreachable-by-click and unswitchable-away for
+            // keyboard input).
+            if should_focus && !self.is_grid() {
                 let seats = &mut (*self.server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
                 let mut curr = (*seats).next;
                 while curr != seats {
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 29dc9d0..9ba33e7 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -1968,8 +1968,8 @@ impl WindowManager {
         let period = self.layout.desktop_grid_scale
             + (self.layout.desktop_gap_width as f64).max(0.0);
         let covers = |p: &crate::policy::api::GridPatch| -> bool {
-            let mx = vw * 0.25;
-            let my = vh * 0.25;
+            let mx = vw * 0.15;
+            let my = vh * 0.15;
             p.x <= vx - mx
                 && p.y <= vy - my
                 && p.x + p.w >= vx + vw + mx
@@ -1997,12 +1997,17 @@ impl WindowManager {
                 let _ = (serial, acked);
                 continue;
             }
-            // One viewport of margin per side, shrunk if the buffer would
-            // exceed the cap; then period-aligned outward so the client
-            // draws whole cells.
-            const MAX_BUF: f64 = 8192.0;
-            let m = (((MAX_BUF / q) - vw) / (2.0 * vw)).clamp(0.0, 1.0)
-                .min((((MAX_BUF / q) - vh) / (2.0 * vh)).clamp(0.0, 1.0));
+            // Half a viewport of margin per side, shrunk if the buffer
+            // would exceed the cap; then period-aligned outward so the
+            // client draws whole cells. Margin and cap are a MEMORY knob:
+            // at output scale 2 the client's framebuffer is
+            // (patch * q * 2)^2 * 4B per swapchain image — the original
+            // 3x3-viewport margin cost ~340MB per image (gigabytes with
+            // swapchain + staging), for scroll headroom that the 0.15
+            // comfort margin above rarely used.
+            const MAX_BUF: f64 = 4096.0;
+            let m = (((MAX_BUF / q) - vw) / (2.0 * vw)).clamp(0.0, 0.5)
+                .min((((MAX_BUF / q) - vh) / (2.0 * vh)).clamp(0.0, 0.5));
             let x0 = ((vx - m * vw) / period).floor() * period;
             let y0 = ((vy - m * vh) / period).floor() * period;
             let x1 = ((vx + (1.0 + m) * vw) / period).ceil() * period;