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

commit8648f4fc572709b60822058b45b04d78a98e622d
parent64836611b6
authorLucas Galante <[email protected]>
date2026-06-24 21:32
layer_shell: trigger dirty_windowing on scheduled_focus changes to fix focus on map

 src/server/layer_shell.rs | 124 ++++++++++++++++++++++++++++++----------------
 1 file changed, 80 insertions(+), 44 deletions(-)

diff --git a/src/server/layer_shell.rs b/src/server/layer_shell.rs
index 9adacab..12b90a4 100644
--- a/src/server/layer_shell.rs
+++ b/src/server/layer_shell.rs
@@ -433,6 +433,39 @@ unsafe extern "C" fn handle_animation_tick(data: *mut std::ffi::c_void) -> std::
     0
 }
 
+unsafe fn update_scheduled_focus_and_dirty_windowing<F>(server: *mut Server, f: F)
+where F: FnOnce() {
+    let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
+    let mut curr = (*seats).next;
+    let mut old_focuses = Vec::new();
+    while curr != seats {
+        let seat = crate::container_of!(curr, Seat, link);
+        old_focuses.push((*seat).layer_shell.scheduled_focus);
+        curr = (*curr).next;
+    }
+
+    f();
+
+    let mut changed = false;
+    let mut curr = (*seats).next;
+    let mut idx = 0;
+    while curr != seats {
+        let seat = crate::container_of!(curr, Seat, link);
+        if (*seat).layer_shell.scheduled_focus != old_focuses[idx] {
+            changed = true;
+        }
+        idx += 1;
+        curr = (*curr).next;
+    }
+
+    if changed {
+        (*server).wm.dirty_windowing();
+    } else {
+        (*server).wm.dirty_rendering();
+    }
+}
+
+
 unsafe extern "C" fn handle_layer_surface_map(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
     let layer_surface = crate::container_of!(listener, LayerSurface, map);
     let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
@@ -467,28 +500,29 @@ unsafe extern "C" fn handle_layer_surface_map(listener: *mut ffi::wl_listener, _
         }
     }
 
-    if (*wlr_layer_surface).current.keyboard_interactive == ffi::zwlr_layer_surface_v1_keyboard_interactivity_ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND {
-        let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
-        let mut curr = (*seats).next;
-        while curr != seats {
-            let next = (*curr).next;
-            let seat = crate::container_of!(curr, Seat, link);
-            if !matches!((*seat).layer_shell.scheduled_focus, LayerShellSeatFocus::Exclusive(_)) {
-                (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::NonExclusive((*layer_surface).ref_key);
+    update_scheduled_focus_and_dirty_windowing(server, || {
+        if (*wlr_layer_surface).current.keyboard_interactive == ffi::zwlr_layer_surface_v1_keyboard_interactivity_ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND {
+            let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
+            let mut curr = (*seats).next;
+            while curr != seats {
+                let next = (*curr).next;
+                let seat = crate::container_of!(curr, Seat, link);
+                if !matches!((*seat).layer_shell.scheduled_focus, LayerShellSeatFocus::Exclusive(_)) {
+                    (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::NonExclusive((*layer_surface).ref_key);
+                }
+                curr = next;
             }
-            curr = next;
         }
-    }
 
-    let wlr_output = (*wlr_layer_surface).output;
-    if !wlr_output.is_null() {
-        let output = ffi::river_wlr_output_get_data(wlr_output) as *mut Output;
-        if !output.is_null() {
-            (*output).layer_shell.arrange(output);
+        let wlr_output = (*wlr_layer_surface).output;
+        if !wlr_output.is_null() {
+            let output = ffi::river_wlr_output_get_data(wlr_output) as *mut Output;
+            if !output.is_null() {
+                (*output).layer_shell.arrange(output);
+            }
         }
-    }
-    (*server).layer_shell.check_exclusive_focus();
-    (*server).wm.dirty_rendering();
+        (*server).layer_shell.check_exclusive_focus();
+    });
 }
 
 unsafe extern "C" fn handle_layer_surface_unmap(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
@@ -504,34 +538,35 @@ unsafe extern "C" fn handle_layer_surface_unmap(listener: *mut ffi::wl_listener,
 
     let server = (*layer_surface).server;
 
-    let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
-    let mut curr = (*seats).next;
-    while curr != seats {
-        let next = (*curr).next;
-        let seat = crate::container_of!(curr, Seat, link);
-        if let crate::seat::Focus::LayerSurface(surface) = (*seat).focused {
-            if surface == (*wlr_layer_surface).surface {
-                (*seat).focus(crate::seat::Focus::None);
-                (*server).wm.focus_next_visible_window(seat);
+    update_scheduled_focus_and_dirty_windowing(server, || {
+        let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
+        let mut curr = (*seats).next;
+        while curr != seats {
+            let next = (*curr).next;
+            let seat = crate::container_of!(curr, Seat, link);
+            if let crate::seat::Focus::LayerSurface(surface) = (*seat).focused {
+                if surface == (*wlr_layer_surface).surface {
+                    (*seat).focus(crate::seat::Focus::None);
+                    (*server).wm.focus_next_visible_window(seat);
+                }
             }
-        }
-        if let LayerShellSeatFocus::NonExclusive(key) = (*seat).layer_shell.scheduled_focus {
-            if key == (*layer_surface).ref_key {
-                (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::None;
+            if let LayerShellSeatFocus::NonExclusive(key) = (*seat).layer_shell.scheduled_focus {
+                if key == (*layer_surface).ref_key {
+                    (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::None;
+                }
             }
+            curr = next;
         }
-        curr = next;
-    }
 
-    let wlr_output = (*wlr_layer_surface).output;
-    if !wlr_output.is_null() {
-        let output = ffi::river_wlr_output_get_data(wlr_output) as *mut Output;
-        if !output.is_null() {
-            (*output).layer_shell.arrange(output);
+        let wlr_output = (*wlr_layer_surface).output;
+        if !wlr_output.is_null() {
+            let output = ffi::river_wlr_output_get_data(wlr_output) as *mut Output;
+            if !output.is_null() {
+                (*output).layer_shell.arrange(output);
+            }
         }
-    }
-    (*server).layer_shell.check_exclusive_focus();
-    (*server).wm.dirty_rendering();
+        (*server).layer_shell.check_exclusive_focus();
+    });
 }
 
 unsafe extern "C" fn handle_layer_surface_commit(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
@@ -573,9 +608,10 @@ unsafe extern "C" fn handle_layer_surface_commit(listener: *mut ffi::wl_listener
     }
 
     if (*wlr_layer_surface).initial_commit || ((*wlr_layer_surface).current.committed != 0) {
-        (*output).layer_shell.arrange(output);
-        (*server).layer_shell.check_exclusive_focus();
-        (*server).wm.dirty_rendering();
+        update_scheduled_focus_and_dirty_windowing(server, || {
+            (*output).layer_shell.arrange(output);
+            (*server).layer_shell.check_exclusive_focus();
+        });
     }
 }