Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Focus most recently focused window when closing pinned or system windows
src/server/seat.rs | 5 +++++
src/server/server.rs | 1 +
src/server/window.rs | 1 +
src/server/window_manager.rs | 28 +++++++++++++++++++++++++++-
4 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/src/server/seat.rs b/src/server/seat.rs
index 3e1b1e2..405c4eb 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -357,6 +357,11 @@ impl Seat {
}
self.focused = new_focus;
+ if let Focus::Window(window) = new_focus {
+ if !window.is_null() {
+ (*self.server).wm.record_focus(window);
+ }
+ }
(*self.server).wm.update_status();
match new_focus {
diff --git a/src/server/server.rs b/src/server/server.rs
index 07a0bd2..fd13441 100644
--- a/src/server/server.rs
+++ b/src/server/server.rs
@@ -826,6 +826,7 @@ impl Default for Server {
std::ptr::write_bytes(server.as_mut_ptr(), 0, 1);
// Overwrite collections and SlotMap with valid instances to avoid UB/segfaults from null pointers
std::ptr::write(&mut (*server.as_mut_ptr()).wm.windows, crate::slotmap::SlotMap::new());
+ std::ptr::write(&mut (*server.as_mut_ptr()).wm.focus_history, Vec::new());
std::ptr::write(&mut (*server.as_mut_ptr()).wm.mode_rules, Vec::new());
std::ptr::write(&mut (*server.as_mut_ptr()).wm.keybinds, Vec::new());
std::ptr::write(&mut (*server.as_mut_ptr()).wm.pointer_binds, Vec::new());
diff --git a/src/server/window.rs b/src/server/window.rs
index f31702c..7368a58 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -790,6 +790,7 @@ impl Window {
(*window).node.deinit();
+ (*(*window).server).wm.remove_from_history(window);
(*(*window).server).wm.windows.remove((*window).ref_key);
let _ = Box::from_raw(window);
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 741a36c..463d2ae 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -71,6 +71,7 @@ pub struct WindowManager {
pub object: *mut ffi::wl_resource,
pub state: WindowManagerState,
pub windows: SlotMap<*mut Window>,
+ pub focus_history: Vec<*mut Window>,
pub scheduled: WindowManagerScheduled,
pub sent: WindowManagerSent,
pub rendering_scheduled: WindowManagerRenderingScheduled,
@@ -121,6 +122,7 @@ impl WindowManager {
self.object = std::ptr::null_mut();
self.state = WindowManagerState::Idle;
self.windows = SlotMap::new();
+ self.focus_history = Vec::new();
self.scheduled = WindowManagerScheduled {
dirty: false,
dirty_lazy: false,
@@ -1233,14 +1235,38 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
}
}
+ pub unsafe fn record_focus(&mut self, window: *mut Window) {
+ if window.is_null() {
+ return;
+ }
+ self.focus_history.retain(|&w| w != window);
+ self.focus_history.insert(0, window);
+ }
+
+ pub unsafe fn remove_from_history(&mut self, window: *mut Window) {
+ self.focus_history.retain(|&w| w != window);
+ }
+
pub unsafe fn focus_next_visible_window(&mut self, seat: *mut crate::seat::Seat) {
let mut next_focus: *mut Window = std::ptr::null_mut();
- for &w in self.windows.iter() {
+ for &w in self.focus_history.iter() {
if !w.is_null() && !(*w).closed && !(*w).minimized && matches!((*w).state, crate::window::WindowState::Mapped) {
let app_id = (*w).get_app_id_string();
let is_status_bar = app_id.as_deref() == Some("cce-status-interface");
if !is_status_bar {
next_focus = w;
+ break;
+ }
+ }
+ }
+ if next_focus.is_null() {
+ for &w in self.windows.iter() {
+ if !w.is_null() && !(*w).closed && !(*w).minimized && matches!((*w).state, crate::window::WindowState::Mapped) {
+ let app_id = (*w).get_app_id_string();
+ let is_status_bar = app_id.as_deref() == Some("cce-status-interface");
+ if !is_status_bar {
+ next_focus = w;
+ }
}
}
}