feat(config): add window container behaviour rules

This commit adds a new static config option,
window_container_behaviour_rules, which similarly to layout_rules, takes
a map of window container count threshold => window container behaviour.

When the number of window containers on the screen meets a given
threshold, the new window container behaviour is applied to the
workspace.

This can be used to automatically change from creating new window
containers for new windows to appending new windows to existing window
containers when the number of window containers on the screen reaches
more than what can be comfortably laid out and viewed on a user's
screen.

resolve #953
This commit is contained in:
LGUG2Z
2025-01-25 20:24:52 -08:00
parent e2f7fe50c9
commit c364b90b3b
4 changed files with 66 additions and 8 deletions

View File

@@ -251,6 +251,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
.map(|b| b.window_kind == WindowKind::Floating)
.unwrap_or_default())
});
if !should_process_notification && switch_focus_to_from_floating_window {
should_process_notification = true;
}
@@ -488,7 +489,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
Some(last_focus_state) => last_focus_state != new_focus_state,
};
if new_border {
if new_border || should_invalidate {
border.set_position(&rect, reference_hwnd)?;
}

View File

@@ -125,7 +125,7 @@ pub struct WorkspaceConfig {
/// END OF LIFE FEATURE: Custom Layout (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_layout: Option<PathBuf>,
/// Layout rules (default: None)
/// Layout rules in the format of threshold => layout (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub layout_rules: Option<HashMap<usize, DefaultLayout>>,
/// END OF LIFE FEATURE: Custom layout rules (default: None)
@@ -149,8 +149,10 @@ pub struct WorkspaceConfig {
/// Determine what happens when a new window is opened (default: Create)
#[serde(skip_serializing_if = "Option::is_none")]
pub window_container_behaviour: Option<WindowContainerBehaviour>,
/// Enable or disable float override, which makes it so every new window opens in floating mode
/// (default: false)
/// Window container behaviour rules in the format of threshold => behaviour (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub window_container_behaviour_rules: Option<HashMap<usize, WindowContainerBehaviour>>,
/// Enable or disable float override, which makes it so every new window opens in floating mode (default: false)
#[serde(skip_serializing_if = "Option::is_none")]
pub float_override: Option<bool>,
/// Specify an axis on which to flip the selected layout (default: None)
@@ -170,6 +172,11 @@ impl From<&Workspace> for WorkspaceConfig {
}
}
let mut window_container_behaviour_rules = HashMap::new();
for (threshold, behaviour) in value.window_container_behaviour_rules().iter().flatten() {
window_container_behaviour_rules.insert(*threshold, *behaviour);
}
let default_container_padding = DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst);
let default_workspace_padding = DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst);
@@ -209,6 +216,7 @@ impl From<&Workspace> for WorkspaceConfig {
workspace_rules: None,
apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset()),
window_container_behaviour: *value.window_container_behaviour(),
window_container_behaviour_rules: Option::from(window_container_behaviour_rules),
float_override: *value.float_override(),
layout_flip: value.layout_flip(),
}

View File

@@ -89,6 +89,8 @@ pub struct Workspace {
#[getset(get = "pub", get_mut = "pub", set = "pub")]
window_container_behaviour: Option<WindowContainerBehaviour>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
window_container_behaviour_rules: Option<Vec<(usize, WindowContainerBehaviour)>>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
float_override: Option<bool>,
}
@@ -114,6 +116,7 @@ impl Default for Workspace {
tile: true,
apply_window_based_work_area_offset: true,
window_container_behaviour: None,
window_container_behaviour_rules: None,
float_override: None,
}
}
@@ -187,6 +190,19 @@ impl Workspace {
self.set_window_container_behaviour(config.window_container_behaviour);
}
if let Some(window_container_behaviour_rules) = &config.window_container_behaviour_rules {
if window_container_behaviour_rules.is_empty() {
self.set_window_container_behaviour_rules(None);
} else {
let mut all_rules = vec![];
for (count, behaviour) in window_container_behaviour_rules {
all_rules.push((*count, *behaviour));
}
self.set_window_container_behaviour_rules(Some(all_rules));
}
}
if config.float_override.is_some() {
self.set_float_override(config.float_override);
}
@@ -326,9 +342,9 @@ impl Workspace {
if !self.layout_rules().is_empty() {
let mut updated_layout = None;
for rule in self.layout_rules() {
if self.containers().len() >= rule.0 {
updated_layout = Option::from(rule.1.clone());
for (threshold, layout) in self.layout_rules() {
if self.containers().len() >= *threshold {
updated_layout = Option::from(layout.clone());
}
}
@@ -337,6 +353,17 @@ impl Workspace {
}
}
if let Some(window_container_behaviour_rules) = self.window_container_behaviour_rules() {
let mut updated_behaviour = None;
for (threshold, behaviour) in window_container_behaviour_rules {
if self.containers().len() >= *threshold {
updated_behaviour = Option::from(*behaviour);
}
}
self.set_window_container_behaviour(updated_behaviour);
}
let managed_maximized_window = self.maximized_window().is_some();
if *self.tile() {

View File

@@ -1284,7 +1284,7 @@
]
},
"layout_rules": {
"description": "Layout rules (default: None)",
"description": "Layout rules in the format of threshold => layout (default: None)",
"type": "object",
"additionalProperties": {
"type": "string",
@@ -1323,6 +1323,28 @@
}
]
},
"window_container_behaviour_rules": {
"description": "Window container behaviour rules in the format of threshold => behaviour (default: None)",
"type": "object",
"additionalProperties": {
"oneOf": [
{
"description": "Create a new container for each new window",
"type": "string",
"enum": [
"Create"
]
},
{
"description": "Append new windows to the focused window container",
"type": "string",
"enum": [
"Append"
]
}
]
}
},
"workspace_padding": {
"description": "Container padding (default: global)",
"type": "integer",