From 305fc3b5576c4c6e3d899b3413dbbb8727922cfe Mon Sep 17 00:00:00 2001 From: Christian Meissl Date: Sat, 16 Nov 2024 22:35:34 +0100 Subject: Activate newly mapped windows with a valid activation token most of the time the activation token is passed while the window is still unmapped. in this case store the intend to activate the window for later retrieval on map. --- src/layout/mod.rs | 110 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 32 deletions(-) (limited to 'src/layout') diff --git a/src/layout/mod.rs b/src/layout/mod.rs index ad6f1b2b..c2424ba8 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -358,6 +358,18 @@ pub struct RemovedTile { is_full_width: bool, } +/// Whether to activate a newly added window. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub enum ActivateWindow { + /// Activate unconditionally. + Yes, + /// Activate based on heuristics. + #[default] + Smart, + /// Do not activate. + No, +} + impl InteractiveMoveState { fn moving(&self) -> Option<&InteractiveMoveData> { match self { @@ -383,6 +395,16 @@ impl InteractiveMoveData { } } +impl ActivateWindow { + pub fn map_smart(self, f: impl FnOnce() -> bool) -> bool { + match self { + ActivateWindow::Yes => true, + ActivateWindow::Smart => f(), + ActivateWindow::No => false, + } + } +} + impl Options { fn from_config(config: &Config) -> Self { let layout = &config.layout; @@ -753,6 +775,7 @@ impl Layout { window: W, width: Option, is_full_width: bool, + activate: ActivateWindow, ) -> Option<&Output> { let width = self.resolve_default_width(&window, width); @@ -771,20 +794,27 @@ impl Layout { }) .unwrap(); - // Don't steal focus from an active fullscreen window. - let mut activate = true; - let ws = &mon.workspaces[ws_idx]; - if mon_idx == *active_monitor_idx - && !ws.columns.is_empty() - && ws.columns[ws.active_column_idx].is_fullscreen - { - activate = false; + if activate == ActivateWindow::Yes { + *active_monitor_idx = mon_idx; } - // Don't activate if on a different workspace. - if mon.active_workspace_idx != ws_idx { - activate = false; - } + let activate = activate.map_smart(|| { + // Don't steal focus from an active fullscreen window. + let ws = &mon.workspaces[ws_idx]; + if mon_idx == *active_monitor_idx + && !ws.columns.is_empty() + && ws.columns[ws.active_column_idx].is_fullscreen + { + return false; + } + + // Don't activate if on a different workspace. + if mon.active_workspace_idx != ws_idx { + return false; + } + + true + }); mon.add_window(ws_idx, window, activate, width, is_full_width); Some(&mon.output) @@ -798,7 +828,8 @@ impl Layout { .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) }) .unwrap(); - ws.add_window(None, window, true, width, is_full_width); + let activate = activate.map_smart(|| true); + ws.add_window(None, window, activate, width, is_full_width); None } } @@ -835,6 +866,7 @@ impl Layout { window: W, width: Option, is_full_width: bool, + activate: ActivateWindow, ) -> Option<&Output> { let width = self.resolve_default_width(&window, width); @@ -846,12 +878,11 @@ impl Layout { } => { let mon = &mut monitors[*active_monitor_idx]; - // Don't steal focus from an active fullscreen window. - let mut activate = true; - let ws = &mon.workspaces[mon.active_workspace_idx]; - if !ws.columns.is_empty() && ws.columns[ws.active_column_idx].is_fullscreen { - activate = false; - } + let activate = activate.map_smart(|| { + // Don't steal focus from an active fullscreen window. + let ws = &mon.workspaces[mon.active_workspace_idx]; + ws.columns.is_empty() || !ws.columns[ws.active_column_idx].is_fullscreen + }); mon.add_window( mon.active_workspace_idx, @@ -872,7 +903,8 @@ impl Layout { )); &mut workspaces[0] }; - ws.add_window(None, window, true, width, is_full_width); + let activate = activate.map_smart(|| true); + ws.add_window(None, window, activate, width, is_full_width); None } } @@ -893,11 +925,12 @@ impl Layout { if let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move { if right_of == move_.tile.window().id() { let output = move_.output.clone(); + let activate = ActivateWindow::default(); if self.monitor_for_output(&output).is_some() { - self.add_window_on_output(&output, window, width, is_full_width); + self.add_window_on_output(&output, window, width, is_full_width, activate); return Some(&self.monitor_for_output(&output).unwrap().output); } else { - return self.add_window(window, width, is_full_width); + return self.add_window(window, width, is_full_width, activate); } } } @@ -932,6 +965,7 @@ impl Layout { window: W, width: Option, is_full_width: bool, + activate: ActivateWindow, ) { let width = self.resolve_default_width(&window, width); @@ -950,16 +984,22 @@ impl Layout { .find(|(_, mon)| mon.output == *output) .unwrap(); - // Don't steal focus from an active fullscreen window. - let mut activate = true; - let ws = &mon.workspaces[mon.active_workspace_idx]; - if mon_idx == *active_monitor_idx - && !ws.columns.is_empty() - && ws.columns[ws.active_column_idx].is_fullscreen - { - activate = false; + if activate == ActivateWindow::Yes { + *active_monitor_idx = mon_idx; } + let activate = activate.map_smart(|| { + // Don't steal focus from an active fullscreen window. + let ws = &mon.workspaces[mon.active_workspace_idx]; + if mon_idx == *active_monitor_idx + && !ws.columns.is_empty() + && ws.columns[ws.active_column_idx].is_fullscreen + { + return false; + } + true + }); + mon.add_window( mon.active_workspace_idx, window, @@ -4365,7 +4405,7 @@ mod tests { } let win = TestWindow::new(id, bbox, min_max_size.0, min_max_size.1); - layout.add_window(win, None, false); + layout.add_window(win, None, false, ActivateWindow::default()); } Op::AddWindowRightOf { id, @@ -4482,7 +4522,13 @@ mod tests { } let win = TestWindow::new(id, bbox, min_max_size.0, min_max_size.1); - layout.add_window_to_named_workspace(&ws_name, win, None, false); + layout.add_window_to_named_workspace( + &ws_name, + win, + None, + false, + ActivateWindow::default(), + ); } Op::CloseWindow(id) => { layout.remove_window(&id, Transaction::new()); -- cgit