diff --git a/packages/wm/src/common/commands/reload_config.rs b/packages/wm/src/common/commands/reload_config.rs index be50ab30..501da221 100644 --- a/packages/wm/src/common/commands/reload_config.rs +++ b/packages/wm/src/common/commands/reload_config.rs @@ -2,6 +2,7 @@ use anyhow::Context; use tracing::{info, warn}; use crate::{ + common::vec_deque_ext::VecDequeExt, containers::traits::{CommonGetters, TilingSizeGetters}, user_config::{ParsedConfig, UserConfig, WindowRuleEvent}, windows::{commands::run_window_rules, traits::WindowGetters}, @@ -92,6 +93,20 @@ fn update_workspace_configs( if *workspace_config != workspace.config() { workspace.set_config(workspace_config.clone()); + let mut workspaces = monitor.workspaces(); + config.sort_workspaces(&mut workspaces); + + let target_index = workspaces + .iter() + .position(|sorted_workspace| { + sorted_workspace.id() == workspace.id() + }) + .context("Failed to get workspace target index.")?; + + monitor + .borrow_children_mut() + .shift_to_index(target_index, workspace.clone().into()); + state.emit_event(WmEvent::WorkspaceUpdated { updated_workspace: workspace.to_dto()?, }); diff --git a/packages/wm/src/monitors/commands/remove_monitor.rs b/packages/wm/src/monitors/commands/remove_monitor.rs index ebca1944..ee1e7c73 100644 --- a/packages/wm/src/monitors/commands/remove_monitor.rs +++ b/packages/wm/src/monitors/commands/remove_monitor.rs @@ -31,11 +31,8 @@ pub fn remove_monitor( .context("No target monitor to move workspaces.")?; // Avoid moving empty workspaces. - let workspaces_to_move = monitor - .children() - .into_iter() - .filter_map(|container| container.as_workspace().cloned()) - .filter(|workspace| { + let workspaces_to_move = + monitor.workspaces().into_iter().filter(|workspace| { workspace.has_children() || workspace.config().keep_alive }); diff --git a/packages/wm/src/monitors/monitor.rs b/packages/wm/src/monitors/monitor.rs index 445b86ad..89dfbad6 100644 --- a/packages/wm/src/monitors/monitor.rs +++ b/packages/wm/src/monitors/monitor.rs @@ -81,6 +81,14 @@ impl Monitor { .and_then(|child| child.as_workspace().cloned()) } + pub fn workspaces(&self) -> Vec { + self + .children() + .into_iter() + .filter_map(|container| container.as_workspace().cloned()) + .collect::>() + } + /// Whether there is a difference in DPI between this monitor and the /// parent monitor of another container. pub fn has_dpi_difference( diff --git a/packages/wm/src/user_config.rs b/packages/wm/src/user_config.rs index fc1523de..f1732ef5 100644 --- a/packages/wm/src/user_config.rs +++ b/packages/wm/src/user_config.rs @@ -309,6 +309,23 @@ impl UserConfig { .or(inactive_configs.first()) .cloned() } + + pub fn workspace_config_index( + &self, + workspace_name: &str, + ) -> Option { + self + .value + .workspaces + .iter() + .position(|config| config.name == workspace_name) + } + + pub fn sort_workspaces(&self, workspaces: &mut Vec) { + workspaces.sort_by_key(|workspace| { + self.workspace_config_index(&workspace.config().name) + }); + } } #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/packages/wm/src/wm_state.rs b/packages/wm/src/wm_state.rs index 2c9edf28..60ebb973 100644 --- a/packages/wm/src/wm_state.rs +++ b/packages/wm/src/wm_state.rs @@ -154,7 +154,7 @@ impl WmState { .root_container .children() .iter() - .filter_map(|c| c.as_monitor().cloned()) + .filter_map(|container| container.as_monitor().cloned()) .collect() } @@ -162,22 +162,14 @@ impl WmState { self .monitors() .iter() - .flat_map(|c| c.children()) - .filter_map(|c| c.as_workspace().cloned()) + .flat_map(|monitor| monitor.workspaces()) .collect() } /// Gets workspaces sorted by their position in the user config. pub fn sorted_workspaces(&self, config: &UserConfig) -> Vec { - let workspace_configs = &config.value.workspaces; let mut workspaces = self.workspaces(); - - workspaces.sort_by_key(|workspace| { - workspace_configs - .iter() - .position(|config| config.name == workspace.config().name) - }); - + config.sort_workspaces(&mut workspaces); workspaces } @@ -210,7 +202,7 @@ impl WmState { self .monitors() .into_iter() - .find(|m| m.native() == *native_monitor) + .find(|monitor| monitor.native() == *native_monitor) } /// Gets the closest monitor in a given direction. diff --git a/packages/wm/src/workspaces/commands/activate_workspace.rs b/packages/wm/src/workspaces/commands/activate_workspace.rs index 14bc0c30..2d2be2ac 100644 --- a/packages/wm/src/workspaces/commands/activate_workspace.rs +++ b/packages/wm/src/workspaces/commands/activate_workspace.rs @@ -2,7 +2,10 @@ use anyhow::Context; use crate::{ common::TilingDirection, - containers::{commands::attach_container, traits::PositionGetters}, + containers::{ + commands::attach_container, + traits::{CommonGetters, PositionGetters}, + }, monitors::Monitor, user_config::{UserConfig, WorkspaceConfig}, wm_event::WmEvent, @@ -36,11 +39,21 @@ pub fn activate_workspace( tiling_direction, ); + // Get the existing workspaces + the new workspace, and sort them. + let mut workspaces = target_monitor.workspaces(); + workspaces.extend([workspace.clone()]); + config.sort_workspaces(&mut workspaces); + + let target_index = workspaces + .iter() + .position(|sorted_workspace| sorted_workspace.id() == workspace.id()) + .context("Failed to get workspace target index.")?; + // Attach the created workspace to the specified monitor. attach_container( &workspace.clone().into(), &target_monitor.clone().into(), - None, + Some(target_index), )?; state.emit_event(WmEvent::WorkspaceActivated {