feat(wm): separate floating and ignored apps

This commit introduces a distinction between ignored applications
(previously identified with float_rules) and floating applications.

All instances of "float_" with the initial meaning of "ignored" have
been renamed with backwards compatibility aliases.

Floating applications will be managed under Workspace.floating_windows
if identified using a rule, and this allows them to now be moved across
workspaces.

A new border type has been added for floating applications, and the
colour can be configured via theme.floating_border.

This interactively rebased commit contains changes from the following
individual commits:

17ea1e6869
feat(wm): separate floating and ignored apps

8b344496e6
feat(wm): allow ws moves of floating apps

7d8e2ad814
refactor(wm): float_rules > ignore_rules w/ compat

d68346a640
fix(borders): no redraws on floating win title change

a93e937772
fix(borders): update on floating win drag

68e9365dda
fix(borders): send notif on ignored hwnd events
This commit is contained in:
LGUG2Z
2024-09-28 17:03:37 -07:00
parent 07a1538905
commit 6db317d425
15 changed files with 374 additions and 167 deletions

View File

@@ -20,6 +20,7 @@ use crate::workspace::Workspace;
use crate::DefaultLayout;
use crate::Layout;
use crate::OperationDirection;
use crate::WindowsApi;
#[derive(
Debug,
@@ -178,66 +179,90 @@ impl Monitor {
bail!("cannot move native maximized window to another monitor or workspace");
}
let container = workspace
.remove_focused_container()
.ok_or_else(|| anyhow!("there is no container"))?;
let foreground_hwnd = WindowsApi::foreground_window()?;
let floating_window_index = workspace
.floating_windows()
.iter()
.position(|w| w.hwnd == foreground_hwnd);
let workspaces = self.workspaces_mut();
if let Some(idx) = floating_window_index {
let window = workspace.floating_windows_mut().remove(idx);
#[allow(clippy::option_if_let_else)]
let target_workspace = match workspaces.get_mut(target_workspace_idx) {
None => {
workspaces.resize(target_workspace_idx + 1, Workspace::default());
workspaces.get_mut(target_workspace_idx).unwrap()
}
Some(workspace) => workspace,
};
match direction {
Some(OperationDirection::Left) => match target_workspace.layout() {
Layout::Default(layout) => match layout {
DefaultLayout::RightMainVerticalStack => {
target_workspace.add_container_to_front(container);
}
DefaultLayout::UltrawideVerticalStack => {
if target_workspace.containers().len() == 1 {
target_workspace.insert_container_at_idx(0, container);
} else {
target_workspace.add_container_to_back(container);
}
}
_ => {
target_workspace.add_container_to_back(container);
}
},
Layout::Custom(_) => {
target_workspace.add_container_to_back(container);
let workspaces = self.workspaces_mut();
#[allow(clippy::option_if_let_else)]
let target_workspace = match workspaces.get_mut(target_workspace_idx) {
None => {
workspaces.resize(target_workspace_idx + 1, Workspace::default());
workspaces.get_mut(target_workspace_idx).unwrap()
}
},
Some(OperationDirection::Right) => match target_workspace.layout() {
Layout::Default(layout) => {
let target_index = layout.leftmost_index(target_workspace.containers().len());
Some(workspace) => workspace,
};
match layout {
DefaultLayout::RightMainVerticalStack
| DefaultLayout::UltrawideVerticalStack => {
target_workspace.floating_windows_mut().push(window);
} else {
let container = workspace
.remove_focused_container()
.ok_or_else(|| anyhow!("there is no container"))?;
let workspaces = self.workspaces_mut();
#[allow(clippy::option_if_let_else)]
let target_workspace = match workspaces.get_mut(target_workspace_idx) {
None => {
workspaces.resize(target_workspace_idx + 1, Workspace::default());
workspaces.get_mut(target_workspace_idx).unwrap()
}
Some(workspace) => workspace,
};
match direction {
Some(OperationDirection::Left) => match target_workspace.layout() {
Layout::Default(layout) => match layout {
DefaultLayout::RightMainVerticalStack => {
target_workspace.add_container_to_front(container);
}
DefaultLayout::UltrawideVerticalStack => {
if target_workspace.containers().len() == 1 {
target_workspace.add_container_to_back(container);
target_workspace.insert_container_at_idx(0, container);
} else {
target_workspace.insert_container_at_idx(target_index, container);
target_workspace.add_container_to_back(container);
}
}
_ => {
target_workspace.insert_container_at_idx(target_index, container);
target_workspace.add_container_to_back(container);
}
},
Layout::Custom(_) => {
target_workspace.add_container_to_back(container);
}
},
Some(OperationDirection::Right) => match target_workspace.layout() {
Layout::Default(layout) => {
let target_index =
layout.leftmost_index(target_workspace.containers().len());
match layout {
DefaultLayout::RightMainVerticalStack
| DefaultLayout::UltrawideVerticalStack => {
if target_workspace.containers().len() == 1 {
target_workspace.add_container_to_back(container);
} else {
target_workspace
.insert_container_at_idx(target_index, container);
}
}
_ => {
target_workspace.insert_container_at_idx(target_index, container);
}
}
}
Layout::Custom(_) => {
target_workspace.add_container_to_front(container);
}
},
_ => {
target_workspace.add_container_to_back(container);
}
Layout::Custom(_) => {
target_workspace.add_container_to_front(container);
}
},
_ => {
target_workspace.add_container_to_back(container);
}
}