aboutsummaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/mod.rs110
1 files changed, 78 insertions, 32 deletions
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<W: LayoutElement> {
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<W: LayoutElement> InteractiveMoveState<W> {
fn moving(&self) -> Option<&InteractiveMoveData<W>> {
match self {
@@ -383,6 +395,16 @@ impl<W: LayoutElement> InteractiveMoveData<W> {
}
}
+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<W: LayoutElement> Layout<W> {
window: W,
width: Option<ColumnWidth>,
is_full_width: bool,
+ activate: ActivateWindow,
) -> Option<&Output> {
let width = self.resolve_default_width(&window, width);
@@ -771,20 +794,27 @@ impl<W: LayoutElement> Layout<W> {
})
.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<W: LayoutElement> Layout<W> {
.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<W: LayoutElement> Layout<W> {
window: W,
width: Option<ColumnWidth>,
is_full_width: bool,
+ activate: ActivateWindow,
) -> Option<&Output> {
let width = self.resolve_default_width(&window, width);
@@ -846,12 +878,11 @@ impl<W: LayoutElement> Layout<W> {
} => {
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<W: LayoutElement> Layout<W> {
));
&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<W: LayoutElement> Layout<W> {
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<W: LayoutElement> Layout<W> {
window: W,
width: Option<ColumnWidth>,
is_full_width: bool,
+ activate: ActivateWindow,
) {
let width = self.resolve_default_width(&window, width);
@@ -950,16 +984,22 @@ impl<W: LayoutElement> Layout<W> {
.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());