diff --git a/Cargo.lock b/Cargo.lock index 412022e8..ca6e2f15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -407,18 +407,6 @@ dependencies = [ "winreg", ] -[[package]] -name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.103", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -2300,7 +2288,6 @@ dependencies = [ "ambassador", "anyhow", "clap", - "enum-as-inner", "futures-util", "home", "serde", diff --git a/packages/wm-macros/src/subenum/mod.rs b/packages/wm-macros/src/subenum/mod.rs index e6c49c72..3afcf392 100644 --- a/packages/wm-macros/src/subenum/mod.rs +++ b/packages/wm-macros/src/subenum/mod.rs @@ -265,6 +265,13 @@ fn from_sub_to_main_impl( } }); + let clone_variants = sub_enum.variants.iter().map(|v| { + let var_name = &v.name; + quote::quote! { + #sub_name::#var_name(v) => #name::#var_name(v.clone()) + } + }); + quote::quote! { impl From<#sub_name> for #name { fn from(value: #sub_name) -> Self { @@ -273,6 +280,14 @@ fn from_sub_to_main_impl( } } } + + impl From<&#sub_name> for #name { + fn from(value: &#sub_name) -> Self { + match value { + #(#clone_variants),* + } + } + } } } @@ -290,6 +305,13 @@ fn try_from_main_to_sub_impl( } }); + let clone_variants = sub_enum.variants.iter().map(|v| { + let var_name = &v.name; + quote::quote! { + #name::#var_name(v) => Ok(#sub_name::#var_name(v.clone())) + } + }); + let error = format!( "Cannot convert this variant of sub enum `{sub_name}` to main enum `{name}`." ); @@ -305,5 +327,16 @@ fn try_from_main_to_sub_impl( } } } + + impl TryFrom<&#name> for #sub_name { + type Error = &'static str; + + fn try_from(value: &#name) -> Result { + match value { + #(#clone_variants),*, + _ => Err(#error), + } + } + } } } diff --git a/packages/wm/Cargo.toml b/packages/wm/Cargo.toml index ad1dd7a4..43f1589f 100644 --- a/packages/wm/Cargo.toml +++ b/packages/wm/Cargo.toml @@ -21,7 +21,6 @@ tauri-winres = { workspace = true } anyhow = { workspace = true } ambassador = "0.4" clap = { workspace = true } -enum-as-inner = "0.6" futures-util = { workspace = true } home = { workspace = true } serde = { workspace = true } diff --git a/packages/wm/src/commands/container/detach_container.rs b/packages/wm/src/commands/container/detach_container.rs index 5c173c78..8ed268e5 100644 --- a/packages/wm/src/commands/container/detach_container.rs +++ b/packages/wm/src/commands/container/detach_container.rs @@ -2,7 +2,7 @@ use anyhow::Context; use super::flatten_split_container; use crate::{ - models::Container, + models::{Container, SplitContainer}, traits::{CommonGetters, TilingSizeGetters, MIN_TILING_SIZE}, }; @@ -16,7 +16,7 @@ pub fn detach_container(child_to_remove: Container) -> anyhow::Result<()> { // the child. if let Some(split_parent) = child_to_remove .parent() - .and_then(|parent| parent.as_split().cloned()) + .and_then(|parent| SplitContainer::try_from(parent.clone()).ok()) { if split_parent.child_count() == 1 { flatten_split_container(split_parent)?; diff --git a/packages/wm/src/commands/container/flatten_child_split_containers.rs b/packages/wm/src/commands/container/flatten_child_split_containers.rs index ff825b59..cb6ad912 100644 --- a/packages/wm/src/commands/container/flatten_child_split_containers.rs +++ b/packages/wm/src/commands/container/flatten_child_split_containers.rs @@ -1,6 +1,6 @@ use super::flatten_split_container; use crate::{ - models::Container, + models::{Container, SplitContainer}, traits::{CommonGetters, TilingDirectionGetters}, }; @@ -21,20 +21,24 @@ pub fn flatten_child_split_containers( let tiling_children = parent .children() .into_iter() - .filter(|child| child.is_tiling_window() || child.is_split()) + .filter(|child| { + matches!(child, Container::TilingWindow(_) | Container::Split(_)) + }) .collect::>(); if tiling_children.len() == 1 { // Handle case where the parent is a split container and has a // single split container child. - if let Some(split_child) = tiling_children[0].as_split() { + if let Ok(split_child) = + <&SplitContainer>::try_from(&tiling_children[0]) + { flatten_split_container(split_child.clone())?; parent.set_tiling_direction(parent.tiling_direction().inverse()); } } else { let split_children = tiling_children .into_iter() - .filter_map(|child| child.as_split().cloned()) + .filter_map(|child| SplitContainer::try_from(child.clone()).ok()) .collect::>(); for split_child in split_children.iter().filter(|split_child| { @@ -43,8 +47,8 @@ pub fn flatten_child_split_containers( // Additionally flatten redundant top-level split containers in // the child. if split_child.child_count() == 1 { - if let Some(split_grandchild) = - split_child.children()[0].as_split() + if let Ok(split_grandchild) = + <&SplitContainer>::try_from(&split_child.children()[0]) { flatten_split_container(split_grandchild.clone())?; } diff --git a/packages/wm/src/commands/container/focus_in_direction.rs b/packages/wm/src/commands/container/focus_in_direction.rs index 8ffda03d..6131ffbf 100644 --- a/packages/wm/src/commands/container/focus_in_direction.rs +++ b/packages/wm/src/commands/container/focus_in_direction.rs @@ -3,7 +3,7 @@ use wm_common::{Direction, TilingDirection, WindowState}; use super::set_focused_descendant; use crate::{ - models::{Container, TilingContainer}, + models::{Container, NonTilingWindow, TilingContainer}, traits::{CommonGetters, TilingDirectionGetters, WindowGetters}, wm_state::WmState, }; @@ -53,7 +53,7 @@ fn floating_focus_target( direction: &Direction, ) -> Option { let is_floating = |sibling: &Container| { - sibling.as_non_tiling_window().is_some_and(|window| { + <&NonTilingWindow>::try_from(sibling).is_ok_and(|window| { matches!(window.state(), WindowState::Floating(_)) }) }; @@ -87,7 +87,7 @@ fn tiling_focus_target( // Traverse upwards from the focused container. Stop searching when a // workspace is encountered. - while !origin_or_ancestor.is_workspace() { + while !matches!(origin_or_ancestor, Container::Workspace(_)) { let parent = origin_or_ancestor .parent() .and_then(|parent| parent.as_direction_container().ok()) diff --git a/packages/wm/src/commands/window/manage_window.rs b/packages/wm/src/commands/window/manage_window.rs index e08a4f17..a2a2be32 100644 --- a/packages/wm/src/commands/window/manage_window.rs +++ b/packages/wm/src/commands/window/manage_window.rs @@ -258,7 +258,7 @@ fn insertion_target( Container::TilingWindow(_) => Some(focused_container), _ => focused_workspace .descendant_focus_order() - .find(Container::is_tiling_window), + .find(|c| matches!(c, Container::TilingWindow(_))), }; if let Some(sibling) = sibling { diff --git a/packages/wm/src/commands/window/move_window_in_direction.rs b/packages/wm/src/commands/window/move_window_in_direction.rs index 93292674..c87d16aa 100644 --- a/packages/wm/src/commands/window/move_window_in_direction.rs +++ b/packages/wm/src/commands/window/move_window_in_direction.rs @@ -56,7 +56,7 @@ fn move_tiling_window( // Flatten the parent split container if it only contains the window. if let Some(split_parent) = window_to_move .parent() - .and_then(|parent| parent.as_split().cloned()) + .and_then(|parent| SplitContainer::try_from(parent).ok()) { if split_parent.child_count() == 1 { flatten_split_container(split_parent)?; @@ -87,7 +87,7 @@ fn move_tiling_window( // Attempt to move the window to workspace in given direction. if (has_matching_tiling_direction || window_to_move.tiling_siblings().count() == 0) - && parent.is_workspace() + && matches!(parent, DirectionContainer::Workspace(_)) { return move_to_workspace_in_direction( &window_to_move.into(), diff --git a/packages/wm/src/commands/window/move_window_to_workspace.rs b/packages/wm/src/commands/window/move_window_to_workspace.rs index fdcda8b2..f64df593 100644 --- a/packages/wm/src/commands/window/move_window_to_workspace.rs +++ b/packages/wm/src/commands/window/move_window_to_workspace.rs @@ -88,8 +88,8 @@ pub fn move_window_to_workspace( .find(|descendant| descendant.state() == WindowState::Tiling); // Insert the window into the target workspace. - match (window.is_tiling_window(), insertion_sibling.is_some()) { - (true, true) => { + match (&window, insertion_sibling.is_some()) { + (WindowContainer::TilingWindow(_), true) => { if let Some(insertion_sibling) = insertion_sibling { move_container_within_tree( &window.clone().into(), diff --git a/packages/wm/src/commands/window/update_window_state.rs b/packages/wm/src/commands/window/update_window_state.rs index 64ed1fd3..8b229cfc 100644 --- a/packages/wm/src/commands/window/update_window_state.rs +++ b/packages/wm/src/commands/window/update_window_state.rs @@ -6,7 +6,7 @@ use crate::{ commands::container::{ move_container_within_tree, replace_container, resize_tiling_container, }, - models::{Container, InsertionTarget, WindowContainer}, + models::{Container, InsertionTarget, NonTilingWindow, WindowContainer}, traits::{CommonGetters, TilingSizeGetters, WindowGetters}, user_config::UserConfig, wm_state::WmState, @@ -41,8 +41,8 @@ fn set_tiling( state: &mut WmState, config: &UserConfig, ) -> anyhow::Result { - let window = window - .as_non_tiling_window() + let window = <&NonTilingWindow>::try_from(window) + .map_err(|s| anyhow::anyhow!(s)) .context("Invalid window state.")? .clone(); @@ -73,7 +73,7 @@ fn set_tiling( .or_else(|| { let focused_window = workspace .descendant_focus_order() - .find(Container::is_tiling_window)?; + .find(|c| matches!(c, Container::TilingWindow(_)))?; Some((focused_window.parent()?, focused_window.index() + 1)) }) diff --git a/packages/wm/src/events/handle_window_location_changed.rs b/packages/wm/src/events/handle_window_location_changed.rs index 2dd87844..eebae8ed 100644 --- a/packages/wm/src/events/handle_window_location_changed.rs +++ b/packages/wm/src/events/handle_window_location_changed.rs @@ -11,7 +11,7 @@ use crate::{ container::{flatten_split_container, move_container_within_tree}, window::update_window_state, }, - models::{TilingWindow, WindowContainer}, + models::{SplitContainer, TilingWindow, WindowContainer}, traits::{CommonGetters, PositionGetters, WindowGetters}, user_config::UserConfig, wm_state::WmState, @@ -56,7 +56,7 @@ pub fn handle_window_location_changed( .context("Failed to get workspace of nearest monitor.")?; // TODO: Include this as part of the `match` statement below. - if let Some(tiling_window) = window.as_tiling_window() { + if let Ok(tiling_window) = <&TilingWindow>::try_from(&window) { update_drag_state( tiling_window, &frame_position, @@ -220,7 +220,7 @@ fn update_drag_state( .dequeue_container_from_redraw(window.clone()); // Flatten the parent split container if it only contains the window. - if let Some(split_parent) = parent.as_split() { + if let Ok(split_parent) = SplitContainer::try_from(parent) { if split_parent.child_count() == 1 { flatten_split_container(split_parent.clone())?; diff --git a/packages/wm/src/events/handle_window_moved_or_resized_end.rs b/packages/wm/src/events/handle_window_moved_or_resized_end.rs index aad8f9c6..20c6bd4f 100644 --- a/packages/wm/src/events/handle_window_moved_or_resized_end.rs +++ b/packages/wm/src/events/handle_window_moved_or_resized_end.rs @@ -12,8 +12,8 @@ use crate::{ window::{resize_window, update_window_state}, }, models::{ - DirectionContainer, NonTilingWindow, SplitContainer, TilingContainer, - WindowContainer, + Container, DirectionContainer, NonTilingWindow, SplitContainer, + TilingContainer, WindowContainer, }, traits::{ CommonGetters, PositionGetters, TilingDirectionGetters, WindowGetters, @@ -65,7 +65,9 @@ pub fn handle_window_moved_or_resized_end( // Snap window to its original position if it's the only window in // the workspace. - if parent.is_workspace() && window.tiling_siblings().count() == 0 { + if matches!(parent, Container::Workspace(_)) + && window.tiling_siblings().count() == 0 + { state.pending_sync.queue_container_to_redraw(window.clone()); return Ok(()); } @@ -157,17 +159,18 @@ fn drop_as_tiling_window( config, )?; - let should_split = nearest_container.is_tiling_window() - && match tiling_direction { - TilingDirection::Horizontal => { - drop_position == DropPosition::Top - || drop_position == DropPosition::Bottom - } - TilingDirection::Vertical => { - drop_position == DropPosition::Left - || drop_position == DropPosition::Right - } - }; + let should_split = + matches!(nearest_container, TilingContainer::TilingWindow(_)) + && match tiling_direction { + TilingDirection::Horizontal => { + drop_position == DropPosition::Top + || drop_position == DropPosition::Bottom + } + TilingDirection::Vertical => { + drop_position == DropPosition::Left + || drop_position == DropPosition::Right + } + }; if should_split { let split_container = SplitContainer::new( diff --git a/packages/wm/src/events/handle_window_moved_or_resized_start.rs b/packages/wm/src/events/handle_window_moved_or_resized_start.rs index ef8ee2dc..50ebe7b6 100644 --- a/packages/wm/src/events/handle_window_moved_or_resized_start.rs +++ b/packages/wm/src/events/handle_window_moved_or_resized_start.rs @@ -1,7 +1,9 @@ use wm_common::ActiveDrag; use wm_platform::NativeWindow; -use crate::{traits::WindowGetters, wm_state::WmState}; +use crate::{ + models::WindowContainer, traits::WindowGetters, wm_state::WmState, +}; /// Handles the event for when a window is started being moved or resized /// by the user (e.g. via the window's drag handles). @@ -19,7 +21,10 @@ pub fn handle_window_moved_or_resized_start( if let Some(found_window) = found_window { found_window.set_active_drag(Some(ActiveDrag { operation: None, - is_from_tiling: found_window.is_tiling_window(), + is_from_tiling: matches!( + found_window, + WindowContainer::TilingWindow(_) + ), })); } } diff --git a/packages/wm/src/models/container.rs b/packages/wm/src/models/container.rs index 086e623c..616d67d5 100644 --- a/packages/wm/src/models/container.rs +++ b/packages/wm/src/models/container.rs @@ -4,7 +4,6 @@ use std::{ }; use ambassador::Delegate; -use enum_as_inner::EnumAsInner; use uuid::Uuid; use wm_common::{ ActiveDrag, ContainerDto, Direction, DisplayState, GapsConfig, Rect, @@ -56,18 +55,13 @@ use crate::{ /// } /// ``` #[derive( - Clone, - Debug, - EnumAsInner, - wm_macros::EnumFromInner, - Delegate, - wm_macros::SubEnum, + Clone, Debug, wm_macros::EnumFromInner, Delegate, wm_macros::SubEnum, )] #[delegate(CommonGetters)] #[delegate(PositionGetters)] #[subenum(defaults, { /// Subenum of [Container] - #[derive(Clone, Debug, EnumAsInner, Delegate, wm_macros::EnumFromInner)] + #[derive(Clone, Debug, Delegate, wm_macros::EnumFromInner)] #[delegate(CommonGetters)] #[delegate(PositionGetters)] })] diff --git a/packages/wm/src/models/monitor.rs b/packages/wm/src/models/monitor.rs index 67c7f5b6..4e1050b8 100644 --- a/packages/wm/src/models/monitor.rs +++ b/packages/wm/src/models/monitor.rs @@ -54,14 +54,14 @@ impl Monitor { self .child_focus_order() .next() - .and_then(|child| child.as_workspace().cloned()) + .and_then(|child| Workspace::try_from(child).ok()) } pub fn workspaces(&self) -> Vec { self .children() .into_iter() - .filter_map(|container| container.as_workspace().cloned()) + .filter_map(|container| Workspace::try_from(container).ok()) .collect() } diff --git a/packages/wm/src/models/root_container.rs b/packages/wm/src/models/root_container.rs index 8ad60b2c..e42b45af 100644 --- a/packages/wm/src/models/root_container.rs +++ b/packages/wm/src/models/root_container.rs @@ -50,7 +50,7 @@ impl RootContainer { self .children() .into_iter() - .filter_map(|container| container.as_monitor().cloned()) + .filter_map(|container| Monitor::try_from(container).ok()) .collect() } diff --git a/packages/wm/src/traits/common_getters.rs b/packages/wm/src/traits/common_getters.rs index 86dcf073..10247bdd 100644 --- a/packages/wm/src/traits/common_getters.rs +++ b/packages/wm/src/traits/common_getters.rs @@ -226,7 +226,7 @@ pub trait CommonGetters { fn workspace(&self) -> Option { self .self_and_ancestors() - .find_map(|container| container.as_workspace().cloned()) + .find_map(|container| Workspace::try_from(container).ok()) } /// Monitor that this container belongs to. @@ -235,7 +235,7 @@ pub trait CommonGetters { fn monitor(&self) -> Option { self .self_and_ancestors() - .find_map(|container| container.as_monitor().cloned()) + .find_map(|container| Monitor::try_from(container).ok()) } /// Nearest direction container (i.e. split container or workspace) that