Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Fix compositor focus capture in monolithic mode and untangle pointer hover focus
src/server/cursor.rs | 29 ++---------------------------
src/server/seat.rs | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 27 deletions(-)
diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index fedd515..7d47b2b 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -309,33 +309,8 @@ impl Cursor {
}
pub unsafe fn update_hovered(&mut self) {
- let lx = self.x();
- let ly = self.y();
- let server = (*self.seat).server;
-
- let at_res = (*server).scene.at(lx, ly);
- let current_focused = &(*self.seat).focused;
-
- if let Some(result) = at_res {
- // Find window/surface under cursor and focus
- match result.data {
- SceneNodeDataVal::Window(_) => {
- // Update hover or click focus
- }
- SceneNodeDataVal::LayerSurface(_) => {
- let surface = result.surface;
- if !matches!(current_focused, Focus::LayerSurface(s) if *s == surface) {
- (*self.seat).focus(Focus::LayerSurface(surface));
- }
- }
- SceneNodeDataVal::LockSurface(lock_surf) => {
- if !matches!(current_focused, Focus::LockSurface(s) if *s == lock_surf) {
- (*self.seat).focus(Focus::LockSurface(lock_surf));
- }
- }
- _ => {}
- }
- }
+ // Keyboard focus remains stable on pointer hover/motion.
+ // It is only changed on mapping, click, touch, or shortcut focus transitions.
}
pub unsafe fn update_state(&mut self) {
diff --git a/src/server/seat.rs b/src/server/seat.rs
index 1fd310d..28d3204 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -302,6 +302,37 @@ impl Seat {
return;
}
+ // If an exclusive layer surface is active and scheduled for focus,
+ // block any window manager or other client focus requests (via focus_requested)
+ // from stealing focus back to a regular window or shell surface.
+ if self.focus_requested {
+ if let crate::layer_shell::LayerShellSeatFocus::Exclusive(key) = self.layer_shell.scheduled_focus {
+ let server = self.server;
+ if let Some(&layer_surface) = (*server).layer_shell.surfaces.get(key) {
+ let wlr_surf = (*(*layer_surface).wlr_layer_surface).surface;
+ if new_focus != Focus::LayerSurface(wlr_surf) {
+ if let Focus::Window(_) | Focus::ShellSurface(_) | Focus::OverrideRedirect(_) | Focus::None = new_focus {
+ log::info!("[FocusDebug] Blocking window manager focus request because Exclusive layer surface {:?} is active", key);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ match new_focus {
+ Focus::None => log::info!("[FocusDebug] Seat::focus set to None"),
+ Focus::LayerSurface(surface) => log::info!("[FocusDebug] Seat::focus set to LayerSurface {:?}", surface),
+ Focus::Window(window) => {
+ let title = if window.is_null() { "null".to_string() } else { (*window).get_title_string().unwrap_or_default() };
+ let app_id = if window.is_null() { "null".to_string() } else { (*window).get_app_id_string().unwrap_or_default() };
+ log::info!("[FocusDebug] Seat::focus set to Window {:?} (title={:?}, app_id={:?})", window, title, app_id);
+ }
+ Focus::LockSurface(lock) => log::info!("[FocusDebug] Seat::focus set to LockSurface {:?}", lock),
+ Focus::OverrideRedirect(or) => log::info!("[FocusDebug] Seat::focus set to OverrideRedirect {:?}", or),
+ Focus::ShellSurface(ss) => log::info!("[FocusDebug] Seat::focus set to ShellSurface {:?}", ss),
+ }
+
match self.focused {
Focus::None => {}
Focus::LayerSurface(_) | Focus::Window(_) | Focus::LockSurface(_) | Focus::OverrideRedirect(_) | Focus::ShellSurface(_) => {
@@ -642,6 +673,10 @@ impl Seat {
self.wm_sent_y = y;
}
}
+ } else {
+ crate::server::wl_list_remove(&mut self.link_sent as *mut ffi::wl_list as *mut crate::server::WlList);
+ let sent_seats = &mut (*self.server).wm.sent.seats as *mut ffi::wl_list as *mut crate::server::WlList;
+ crate::server::wl_list_insert((*sent_seats).prev, &mut self.link_sent as *mut ffi::wl_list as *mut crate::server::WlList);
}
}