From 0eccc2a9c3315e0b7a8d6faf4909d23af617d268 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 16 May 2024 11:58:51 +0200 Subject: [PATCH 01/86] initial commit --- komorebi-core/src/lib.rs | 1 + komorebi/src/process_command.rs | 1 + komorebi/src/static_config.rs | 1 + komorebi/src/window_manager.rs | 124 ++++++++++++++++++++++++++++++++ komorebi/src/workspace.rs | 2 +- komorebic/src/main.rs | 5 ++ 6 files changed, 133 insertions(+), 1 deletion(-) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 3f2431397..f7dda8a2a 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -71,6 +71,7 @@ pub enum SocketMessage { ToggleFloat, ToggleMonocle, ToggleMaximize, + ToggleAlwaysOnTop, ToggleWindowContainerBehaviour, WindowHidingBehaviour(HidingBehaviour), ToggleCrossMonitorMoveBehaviour, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 717a55e53..5e547ce0d 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -218,6 +218,7 @@ impl WindowManager { SocketMessage::ToggleFloat => self.toggle_float()?, SocketMessage::ToggleMonocle => self.toggle_monocle()?, SocketMessage::ToggleMaximize => self.toggle_maximize()?, + SocketMessage::ToggleAlwaysOnTop => self.toggle_always_on_top(), SocketMessage::ContainerPadding(monitor_idx, workspace_idx, size) => { self.set_container_padding(monitor_idx, workspace_idx, size)?; } diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 3ce2e8eca..59a7cdd1b 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -664,6 +664,7 @@ impl StaticConfig { has_pending_raise_op: false, pending_move_op: None, already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())), + always_on_display: None, }; match value.focus_follows_mouse { diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 10baa6bca..0cb2ad238 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -97,6 +97,8 @@ pub struct WindowManager { pub has_pending_raise_op: bool, pub pending_move_op: Option<(usize, usize, usize)>, pub already_moved_window_handles: Arc>>, + pub always_on_display: Option>, + } #[allow(clippy::struct_excessive_bools)] @@ -278,6 +280,7 @@ impl WindowManager { has_pending_raise_op: false, pending_move_op: None, already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())), + always_on_display: None, }) } @@ -1173,6 +1176,118 @@ impl WindowManager { self.update_focused_workspace(mouse_follows_focus, true) } + #[tracing::instrument(skip(self))] + pub fn send_always_on_display(&mut self, monitor_idx: Option, workspace_idx: Option, follows: Option) -> Result<()> { + let mut contains_always_on_top = false; + let last_window = if let Ok(window) = self.focused_window(){ + window.hwnd + + } else { + return Ok(()) + }; + + + for windows in self.always_on_display.clone(){ + for window in windows { + if let Some(monitor_idx) = monitor_idx { + if self + .monitors() + .get(monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor at this index"))?.focused_workspace().unwrap().contains_managed_window(window) { + let idx = self + .monitors() + .get(monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor at this index"))?.focused_workspace().unwrap().container_idx_for_window(window).ok_or_else(|| anyhow!("there is no container at this index"))?; + + let con = self + .monitors_mut() + .get_mut(monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor at this index"))?.focused_workspace_mut().unwrap().remove_container_by_idx(idx).unwrap(); + + self + .monitors_mut() + .get_mut(monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor at this index"))?.add_container(con, workspace_idx)?; + } + } else { + + if let Some(follow) = follows { + if follow { + let mut is_window = false; + if self.contains_always_on_display() { + self.focused_container()?.windows().iter().for_each(|w| { + if w.hwnd == window { + is_window = true; + } + }); + } + if is_window { + continue; + } + + } else { + return Ok(()) + } + } + + if self.focused_workspace().unwrap().contains_managed_window(window) { + + let idx = self.focused_workspace().unwrap().container_idx_for_window(window); + let con = self.focused_workspace_mut().unwrap().remove_container_by_idx(idx.unwrap()).ok_or_else(|| anyhow!("there is no container at this index"))?; + + + self.focused_monitor_mut().unwrap().add_container(con, workspace_idx)?; + + contains_always_on_top = true; + + //self.update_focused_workspace(mff, false).unwrap() + + } + + } + + } + + } + + if contains_always_on_top && self.focused_workspace()?.containers().len() != 0 && self.focused_workspace()?.contains_managed_window(last_window) { + self.focused_workspace_mut()?.focus_container_by_window(last_window)?; + } + Ok(()) + + } + + pub fn contains_always_on_display(&self) -> bool { + + if let Some(aot) = self.always_on_display.as_ref() { + self.focused_container().unwrap().windows().iter().any(|w| aot.contains(&w.hwnd)) + } else { false + + } + + + } + + + pub fn toggle_always_on_top(&mut self) { + + for window in self.focused_container().unwrap().windows().clone() { + + if let Some(always_on_display) = self.always_on_display.as_mut() { + + if always_on_display.contains(&window.hwnd) { + let idx = always_on_display.iter().position(|x| *x == window.hwnd).unwrap(); + always_on_display.remove(idx); + } else { + always_on_display.push(window.hwnd.clone()) + } + } else { + self.always_on_display = Some(vec![window.hwnd.clone()]) + } + } + } + + #[tracing::instrument(skip(self))] pub fn move_container_to_monitor( &mut self, @@ -1182,6 +1297,8 @@ impl WindowManager { ) -> Result<()> { self.handle_unmanaged_window_behaviour()?; + self.send_always_on_display(Some(monitor_idx),workspace_idx, Some(follow))?; + tracing::info!("moving container"); let offset = self.work_area_offset; @@ -1232,6 +1349,9 @@ impl WindowManager { tracing::info!("moving container"); + self.send_always_on_display(None, Some(idx), Some(follow))?; + + let mouse_follows_focus = self.mouse_follows_focus; let monitor = self .focused_monitor_mut() @@ -2308,6 +2428,8 @@ impl WindowManager { #[tracing::instrument(skip(self))] pub fn focus_monitor(&mut self, idx: usize) -> Result<()> { tracing::info!("focusing monitor"); + self.send_always_on_display(Some(idx), None, None)?; + if self.monitors().get(idx).is_some() { self.monitors.focus(idx); @@ -2391,6 +2513,8 @@ impl WindowManager { pub fn focus_workspace(&mut self, idx: usize) -> Result<()> { tracing::info!("focusing workspace"); + self.send_always_on_display(None, Some(idx), None)?; + let mouse_follows_focus = self.mouse_follows_focus; let monitor = self .focused_monitor_mut() diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 37bb78636..2c0f9fdd6 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -650,7 +650,7 @@ impl Workspace { None } - fn container_idx_for_window(&self, hwnd: isize) -> Option { + pub(crate) fn container_idx_for_window(&self, hwnd: isize) -> Option { let mut idx = None; for (i, x) in self.containers().iter().enumerate() { if x.contains_window(hwnd) { diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 06284d131..4a75f43af 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -1084,6 +1084,8 @@ enum SubCommand { ToggleMonocle, /// Toggle native maximization for the focused window ToggleMaximize, + /// Toggle Always on top mode for the focused window + ToggleAlwaysOnTop, /// Restore all hidden windows (debugging command) RestoreWindows, /// Force komorebi to manage the focused window @@ -1691,6 +1693,9 @@ fn main() -> Result<()> { SubCommand::ToggleMaximize => { send_message(&SocketMessage::ToggleMaximize.as_bytes()?)?; } + SubCommand::ToggleAlwaysOnTop => { + send_message(&SocketMessage::ToggleAlwaysOnTop.as_bytes()?)?; + } SubCommand::WorkspaceLayout(arg) => { send_message( &SocketMessage::WorkspaceLayout(arg.monitor, arg.workspace, arg.value) From 11a0dc7bf441cdfa4b8cd912b058af2a02bff605 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 16 May 2024 19:40:01 +0200 Subject: [PATCH 02/86] some fixes and event --- komorebi/src/process_command.rs | 2 +- komorebi/src/process_event.rs | 8 +++ komorebi/src/static_config.rs | 2 +- komorebi/src/window_manager.rs | 96 +++++++++++++++++---------------- 4 files changed, 61 insertions(+), 47 deletions(-) diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 5e547ce0d..327efc08c 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -218,7 +218,7 @@ impl WindowManager { SocketMessage::ToggleFloat => self.toggle_float()?, SocketMessage::ToggleMonocle => self.toggle_monocle()?, SocketMessage::ToggleMaximize => self.toggle_maximize()?, - SocketMessage::ToggleAlwaysOnTop => self.toggle_always_on_top(), + SocketMessage::ToggleAlwaysOnTop => self.toggle_always_on_top()?, SocketMessage::ContainerPadding(monitor_idx, workspace_idx, size) => { self.set_container_padding(monitor_idx, workspace_idx, size)?; } diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index d0f40bf45..2f61128a6 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -178,6 +178,14 @@ impl WindowManager { already_moved_window_handles.remove(&window.hwnd); } + + if let Some(aot) = self.always_on_top.as_mut() { + if aot.contains(&window.hwnd) { + let idx = aot.iter().position(|x| *x == window.hwnd).unwrap(); + aot.remove(idx); + } + + } } WindowManagerEvent::Minimize(_, window) => { let mut hide = false; diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 59a7cdd1b..b44beb15e 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -664,7 +664,7 @@ impl StaticConfig { has_pending_raise_op: false, pending_move_op: None, already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())), - always_on_display: None, + always_on_top: None, }; match value.focus_follows_mouse { diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 0cb2ad238..6140f594e 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -97,7 +97,7 @@ pub struct WindowManager { pub has_pending_raise_op: bool, pub pending_move_op: Option<(usize, usize, usize)>, pub already_moved_window_handles: Arc>>, - pub always_on_display: Option>, + pub always_on_top: Option>, } @@ -280,7 +280,7 @@ impl WindowManager { has_pending_raise_op: false, pending_move_op: None, already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())), - always_on_display: None, + always_on_top: None, }) } @@ -1177,7 +1177,7 @@ impl WindowManager { } #[tracing::instrument(skip(self))] - pub fn send_always_on_display(&mut self, monitor_idx: Option, workspace_idx: Option, follows: Option) -> Result<()> { + pub fn send_always_on_top(&mut self, monitor_idx: Option, workspace_idx: Option, follows: Option) -> Result<()> { let mut contains_always_on_top = false; let last_window = if let Ok(window) = self.focused_window(){ window.hwnd @@ -1185,10 +1185,36 @@ impl WindowManager { } else { return Ok(()) }; + if let Some(_aot) = self.always_on_top.as_ref() { + } else { + return Ok(()) + } + let flw = if let Some(follow) = follows { + if follow { + true + } else { + return Ok(()) + } + } else { + false + }; - for windows in self.always_on_display.clone(){ - for window in windows { + let aot = self.always_on_top.clone(); + + let contains_always_on_display_bool = self.contains_always_on_top(); + + let windows_vec = self.focused_container().unwrap().windows().into_iter().map(|w| w.hwnd).collect::>(); + + aot.ok_or_else(|| anyhow!("there is no always on Top windows"))?.iter().filter(|&&window| { + let mut is_window = false; + if contains_always_on_display_bool && flw { + if windows_vec.contains(&&window) { + is_window = true; + } + } + !is_window}) + .try_for_each(|&window| { if let Some(monitor_idx) = monitor_idx { if self .monitors() @@ -1210,28 +1236,7 @@ impl WindowManager { .ok_or_else(|| anyhow!("there is no monitor at this index"))?.add_container(con, workspace_idx)?; } } else { - - if let Some(follow) = follows { - if follow { - let mut is_window = false; - if self.contains_always_on_display() { - self.focused_container()?.windows().iter().for_each(|w| { - if w.hwnd == window { - is_window = true; - } - }); - } - if is_window { - continue; - } - - } else { - return Ok(()) - } - } - if self.focused_workspace().unwrap().contains_managed_window(window) { - let idx = self.focused_workspace().unwrap().container_idx_for_window(window); let con = self.focused_workspace_mut().unwrap().remove_container_by_idx(idx.unwrap()).ok_or_else(|| anyhow!("there is no container at this index"))?; @@ -1241,14 +1246,12 @@ impl WindowManager { contains_always_on_top = true; //self.update_focused_workspace(mff, false).unwrap() - } - } - } + Ok::<(), color_eyre::eyre::Error>(()) - } + })?; if contains_always_on_top && self.focused_workspace()?.containers().len() != 0 && self.focused_workspace()?.contains_managed_window(last_window) { self.focused_workspace_mut()?.focus_container_by_window(last_window)?; @@ -1257,9 +1260,9 @@ impl WindowManager { } - pub fn contains_always_on_display(&self) -> bool { + pub fn contains_always_on_top(&self) -> bool { - if let Some(aot) = self.always_on_display.as_ref() { + if let Some(aot) = self.always_on_top.as_ref() { self.focused_container().unwrap().windows().iter().any(|w| aot.contains(&w.hwnd)) } else { false @@ -1269,22 +1272,25 @@ impl WindowManager { } - pub fn toggle_always_on_top(&mut self) { + pub fn toggle_always_on_top(&mut self) -> Result<()> { - for window in self.focused_container().unwrap().windows().clone() { + let focused_con = self.focused_container().unwrap().clone(); - if let Some(always_on_display) = self.always_on_display.as_mut() { + focused_con.windows().iter().try_for_each(|window| { - if always_on_display.contains(&window.hwnd) { - let idx = always_on_display.iter().position(|x| *x == window.hwnd).unwrap(); - always_on_display.remove(idx); + if let Some(always_on_top) = self.always_on_top.as_mut() { + + if always_on_top.contains(&window.hwnd) { + let idx = always_on_top.iter().position(|x| *x == window.hwnd).unwrap(); + always_on_top.remove(idx); } else { - always_on_display.push(window.hwnd.clone()) + always_on_top.push(window.hwnd.clone()) } } else { - self.always_on_display = Some(vec![window.hwnd.clone()]) + self.always_on_top = Some(vec![window.hwnd.clone()]) } - } + Ok::<(), color_eyre::eyre::Error>(())})?; + Ok(()) } @@ -1297,7 +1303,7 @@ impl WindowManager { ) -> Result<()> { self.handle_unmanaged_window_behaviour()?; - self.send_always_on_display(Some(monitor_idx),workspace_idx, Some(follow))?; + self.send_always_on_top(Some(monitor_idx), workspace_idx, Some(follow))?; tracing::info!("moving container"); @@ -1349,7 +1355,7 @@ impl WindowManager { tracing::info!("moving container"); - self.send_always_on_display(None, Some(idx), Some(follow))?; + self.send_always_on_top(None, Some(idx), Some(follow))?; let mouse_follows_focus = self.mouse_follows_focus; @@ -2428,7 +2434,7 @@ impl WindowManager { #[tracing::instrument(skip(self))] pub fn focus_monitor(&mut self, idx: usize) -> Result<()> { tracing::info!("focusing monitor"); - self.send_always_on_display(Some(idx), None, None)?; + self.send_always_on_top(Some(idx), None, None)?; if self.monitors().get(idx).is_some() { @@ -2513,7 +2519,7 @@ impl WindowManager { pub fn focus_workspace(&mut self, idx: usize) -> Result<()> { tracing::info!("focusing workspace"); - self.send_always_on_display(None, Some(idx), None)?; + self.send_always_on_top(None, Some(idx), None)?; let mouse_follows_focus = self.mouse_follows_focus; let monitor = self From bc1a7d2a19759b68f9327e15c364111938b195a1 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 16 May 2024 20:33:28 +0200 Subject: [PATCH 03/86] some fixes --- komorebi/src/window_manager.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 6140f594e..a3196f575 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1185,7 +1185,10 @@ impl WindowManager { } else { return Ok(()) }; - if let Some(_aot) = self.always_on_top.as_ref() { + if let Some(aot) = self.always_on_top.as_ref() { + if aot.len() == 0 { + return Ok(()) + } } else { return Ok(()) From 1a00dd3de5dd1d5702a66df730d8aca809da5dc9 Mon Sep 17 00:00:00 2001 From: pro470 Date: Fri, 17 May 2024 19:48:00 +0200 Subject: [PATCH 04/86] some fixes --- komorebi/src/window_manager.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index a3196f575..422f94096 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1205,7 +1205,10 @@ impl WindowManager { let aot = self.always_on_top.clone(); - let contains_always_on_display_bool = self.contains_always_on_top(); + let contains_always_on_display_bool = if let Some(aot) = self.always_on_top.as_ref() { + self.focused_container().unwrap().windows().iter().any(|w| aot.contains(&w.hwnd)) + } else { false + }; let windows_vec = self.focused_container().unwrap().windows().into_iter().map(|w| w.hwnd).collect::>(); @@ -1263,18 +1266,6 @@ impl WindowManager { } - pub fn contains_always_on_top(&self) -> bool { - - if let Some(aot) = self.always_on_top.as_ref() { - self.focused_container().unwrap().windows().iter().any(|w| aot.contains(&w.hwnd)) - } else { false - - } - - - } - - pub fn toggle_always_on_top(&mut self) -> Result<()> { let focused_con = self.focused_container().unwrap().clone(); From d167e24f189bc479e4edd5cd8566e0ff30b2192f Mon Sep 17 00:00:00 2001 From: pro470 Date: Sat, 18 May 2024 00:00:46 +0200 Subject: [PATCH 05/86] some fixes and add always on top feature for floating windows --- komorebi/src/window_manager.rs | 37 ++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 422f94096..40d72aff7 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -20,6 +20,7 @@ use regex::Regex; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use tracing::info; use uds_windows::UnixListener; use komorebi_core::config_generation::MatchingRule; @@ -1183,7 +1184,11 @@ impl WindowManager { window.hwnd } else { - return Ok(()) + if self.focused_workspace()?.floating_windows().len() > 0 { + self.focused_workspace()?.floating_windows()[0].hwnd + }else { + return Ok(()) + } }; if let Some(aot) = self.always_on_top.as_ref() { if aot.len() == 0 { @@ -1197,7 +1202,7 @@ impl WindowManager { if follow { true } else { - return Ok(()) + return Err(anyhow!("cannot send an always on top window"))? } } else { false @@ -1206,11 +1211,22 @@ impl WindowManager { let aot = self.always_on_top.clone(); let contains_always_on_display_bool = if let Some(aot) = self.always_on_top.as_ref() { - self.focused_container().unwrap().windows().iter().any(|w| aot.contains(&w.hwnd)) - } else { false + if let Ok(fc) = self.focused_container() { + fc.windows().iter().any(|w| aot.contains(&w.hwnd)) + } else { + false + } + } + else { false + }; + + let windows_vec = if let Ok(fc) = self.focused_container() { + fc.windows().into_iter().map(|w| w.hwnd).collect::>() + + } else { + vec![] }; - let windows_vec = self.focused_container().unwrap().windows().into_iter().map(|w| w.hwnd).collect::>(); aot.ok_or_else(|| anyhow!("there is no always on Top windows"))?.iter().filter(|&&window| { let mut is_window = false; @@ -1247,11 +1263,20 @@ impl WindowManager { let con = self.focused_workspace_mut().unwrap().remove_container_by_idx(idx.unwrap()).ok_or_else(|| anyhow!("there is no container at this index"))?; - self.focused_monitor_mut().unwrap().add_container(con, workspace_idx)?; + self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no focused monitor"))?.add_container(con, workspace_idx)?; contains_always_on_top = true; //self.update_focused_workspace(mff, false).unwrap() + } else if self.focused_workspace()?.floating_windows().iter().any(|w| w.hwnd == window) { + info!("window is floating"); + let idx = self.focused_workspace_mut()?.floating_windows().iter().position(|x| x.hwnd == window).unwrap(); + let float_window = self.focused_workspace_mut()?.floating_windows_mut().remove(idx); + self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no focused workspace"))? + .workspaces_mut() + .get_mut(workspace_idx.unwrap()) + .ok_or_else(|| anyhow!("there is no workspace at this index"))? + .floating_windows_mut().push(float_window); } } From faf4efe4a2a05da4b991629c1b7ee2b582268e0a Mon Sep 17 00:00:00 2001 From: pro470 Date: Sat, 18 May 2024 00:27:05 +0200 Subject: [PATCH 06/86] some fixes --- komorebi/src/window_manager.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 2164ae544..df24f79af 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1269,7 +1269,6 @@ impl WindowManager { //self.update_focused_workspace(mff, false).unwrap() } else if self.focused_workspace()?.floating_windows().iter().any(|w| w.hwnd == window) { - info!("window is floating"); let idx = self.focused_workspace_mut()?.floating_windows().iter().position(|x| x.hwnd == window).unwrap(); let float_window = self.focused_workspace_mut()?.floating_windows_mut().remove(idx); self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no focused workspace"))? From b9478b0736ee9165c7659f60c9160b8ac7cec570 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 20 May 2024 13:03:27 +0200 Subject: [PATCH 07/86] some fixes --- komorebi/src/window_manager.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 961edf1ae..c037afbd2 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1047,17 +1047,24 @@ impl WindowManager { } else { return Ok(()) } + + let aot = self.always_on_top.clone(); + let flw = if let Some(follow) = follows { if follow { true } else { - return Err(anyhow!("cannot send an always on top window"))? + if self.focused_container()?.windows().iter().any(|w| aot.as_ref().unwrap().contains(&w.hwnd)) { + + return Err(anyhow!("cannot send an always on top window"))?; + } else { + false + } } } else { false }; - let aot = self.always_on_top.clone(); let contains_always_on_display_bool = if let Some(aot) = self.always_on_top.as_ref() { if let Ok(fc) = self.focused_container() { From 3de2a4cf0585371a84b70aadb4530da60104d121 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 20 May 2024 13:45:35 +0200 Subject: [PATCH 08/86] some fixes --- komorebi/src/window_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 9d4e004e5..8c893f011 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1062,7 +1062,7 @@ impl WindowManager { return Err(anyhow!("cannot send an always on top window"))?; } else { - false + return Ok(()); } } } else { From 6d4e548d695eb866c581c75bda550e197b847d45 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 20 May 2024 14:26:39 +0200 Subject: [PATCH 09/86] some fixes --- komorebi/src/window_manager.rs | 65 ++++++++++++++-------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 8c893f011..cfb87d8f7 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1043,54 +1043,41 @@ impl WindowManager { return Ok(()) } }; - if let Some(aot) = self.always_on_top.as_ref() { - if aot.len() == 0 { - return Ok(()) - } - - } else { - return Ok(()) - } - let aot = self.always_on_top.clone(); + let mut windows_vec = vec![]; - let flw = if let Some(follow) = follows { - if follow { - true - } else { - if self.focused_container()?.windows().iter().any(|w| aot.as_ref().unwrap().contains(&w.hwnd)) { + let flw_contains = - return Err(anyhow!("cannot send an always on top window"))?; + if let Some(aot) = self.always_on_top.as_ref() { + if aot.len() == 0 { + return Ok(()) + } + if let Some(flw) = follows { + if let Ok(fc) = self.focused_container() { + let contains = fc.windows().iter().any(|w| aot.contains(&w.hwnd)); + if flw && contains { + windows_vec = fc.windows().into_iter().map(|w| w.hwnd).collect::>(); + true + } else if !flw && !contains { + return Ok(()) + } else if !flw && contains { + Err(anyhow!("cannot send an always on top window"))? + } else { + false + } + } else { + false + } } else { - return Ok(()); + false } - } - } else { - false - }; - - - let contains_always_on_display_bool = if let Some(aot) = self.always_on_top.as_ref() { - if let Ok(fc) = self.focused_container() { - fc.windows().iter().any(|w| aot.contains(&w.hwnd)) } else { - false - } - } - else { false - }; - - let windows_vec = if let Ok(fc) = self.focused_container() { - fc.windows().into_iter().map(|w| w.hwnd).collect::>() - - } else { - vec![] - }; - + return Ok(()) + }; aot.ok_or_else(|| anyhow!("there is no always on Top windows"))?.iter().filter(|&&window| { let mut is_window = false; - if contains_always_on_display_bool && flw { + if flw_contains { if windows_vec.contains(&&window) { is_window = true; } From 57aeff186033e664bb42450bd0ba53de9db089b1 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 20 May 2024 15:05:28 +0200 Subject: [PATCH 10/86] some fixes --- komorebi/src/window_manager.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index cfb87d8f7..a77135f76 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -20,7 +20,6 @@ use regex::Regex; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; -use tracing::info; use uds_windows::UnixListener; use komorebi_core::config_generation::MatchingRule; From d243a70cfd2ac94dcbe3a43d135377a7912dc649 Mon Sep 17 00:00:00 2001 From: pro470 Date: Wed, 22 May 2024 22:14:41 +0200 Subject: [PATCH 11/86] some fixes --- komorebi/src/window_manager.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index a77135f76..9397c9780 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1051,6 +1051,7 @@ impl WindowManager { if aot.len() == 0 { return Ok(()) } + self.check_aot_windows()?; if let Some(flw) = follows { if let Ok(fc) = self.focused_container() { let contains = fc.windows().iter().any(|w| aot.contains(&w.hwnd)); @@ -1136,8 +1137,34 @@ impl WindowManager { } + + pub fn check_aot_windows(&mut self) -> Result<()> { + let mut not_contains = vec![]; + for (i, hwnd) in self.always_on_top.as_ref().unwrap().iter().enumerate() { + let mut not_contains_bool = true; + for monitor in self.monitors.elements().iter() { + for workspace in monitor.workspaces() { + if workspace.contains_managed_window(*hwnd) { + not_contains_bool = false; + break; + } + } + } + + if not_contains_bool { + not_contains.push(i); + } + } + not_contains.iter().for_each(|&i| { + self.always_on_top.as_mut().unwrap().remove(i); + }); + Ok(()) + } + pub fn toggle_always_on_top(&mut self) -> Result<()> { + self.check_aot_windows()?; + let focused_con = self.focused_container().unwrap().clone(); focused_con.windows().iter().try_for_each(|window| { From 48624a84341af4665a76623b3cd125fb6a1e3322 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 23 May 2024 11:38:14 +0200 Subject: [PATCH 12/86] some fixes --- komorebi/src/window_manager.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 9397c9780..d1ed57c12 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1051,7 +1051,6 @@ impl WindowManager { if aot.len() == 0 { return Ok(()) } - self.check_aot_windows()?; if let Some(flw) = follows { if let Ok(fc) = self.focused_container() { let contains = fc.windows().iter().any(|w| aot.contains(&w.hwnd)); @@ -1074,6 +1073,8 @@ impl WindowManager { } else { return Ok(()) }; + self.check_aot_windows()?; + aot.ok_or_else(|| anyhow!("there is no always on Top windows"))?.iter().filter(|&&window| { let mut is_window = false; From 458cac9ce7a6233ae4e440540515bbc7b92d017e Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 29 May 2024 13:10:05 -0700 Subject: [PATCH 13/86] fix(cli): respect named ws send behaviour This commit ensures that the "send" behaviour is respected in named-workspace command variants such as send-to-named-workspace. --- komorebi/src/window_manager.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index cef40c552..26a53bbee 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1065,14 +1065,14 @@ impl WindowManager { target_monitor.add_container(container, workspace_idx)?; - if let Some(workspace_idx) = workspace_idx { - target_monitor.focus_workspace(workspace_idx)?; - } + if follow { + if let Some(workspace_idx) = workspace_idx { + target_monitor.focus_workspace(workspace_idx)?; + } - target_monitor.load_focused_workspace(mouse_follows_focus)?; - target_monitor.update_focused_workspace(offset)?; + target_monitor.load_focused_workspace(mouse_follows_focus)?; + target_monitor.update_focused_workspace(offset)?; - if follow { self.focus_monitor(monitor_idx)?; } From c443972d0a43d18950f1be92037a8c53e26af856 Mon Sep 17 00:00:00 2001 From: pro470 Date: Fri, 31 May 2024 15:09:19 +0200 Subject: [PATCH 14/86] some fixes --- komorebi/src/window_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 606524ea8..f000848ef 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1242,6 +1242,7 @@ impl WindowManager { target_monitor.load_focused_workspace(mouse_follows_focus)?; target_monitor.update_focused_workspace(offset)?; + } // this second one is for DPI changes when the target is another monitor From 7c4cb79a098e1ae83d543d7ed4e4b60411de683b Mon Sep 17 00:00:00 2001 From: pro470 Date: Wed, 5 Jun 2024 23:24:10 +0200 Subject: [PATCH 15/86] added the command to change focus to the window with the specified executable --- komorebi-core/src/lib.rs | 1 + komorebi/src/process_command.rs | 3 +++ komorebi/src/window_manager.rs | 37 +++++++++++++++++++++++++++++++++ komorebic/src/main.rs | 11 ++++++++++ 4 files changed, 52 insertions(+) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 8203481f4..79381d962 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -45,6 +45,7 @@ pub enum SocketMessage { StackWindow(OperationDirection), StackAll, UnstackAll, + FocusExe(String), ResizeWindowEdge(OperationDirection, Sizing), ResizeWindowAxis(Axis, Sizing), UnstackWindow, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 30471c51d..a40842249 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -202,6 +202,9 @@ impl WindowManager { SocketMessage::FocusWindow(direction) => { self.focus_container_in_direction(direction)?; } + SocketMessage::FocusExe(ref exe) => { + self.focus_window_from_exe(exe)?; + } SocketMessage::MoveWindow(direction) => { self.move_container_in_direction(direction)?; } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 38ce9cb8c..502dc0e7a 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1031,6 +1031,43 @@ impl WindowManager { self.update_focused_workspace(mouse_follows_focus, true) } + + #[tracing::instrument(skip(self))] + pub fn focus_window_from_exe(&mut self, exe: &String) -> Result<()> { + + let mut monitor_idx = 0; + let mut workspace_idx = 0; + let mut hwnd_from_exe: isize = 0; + let mut bool = false; + + 'outer: for (i, m ) in self.monitors.elements().iter().enumerate(){ + for (j, w) in m.workspaces().iter().enumerate() { + if let Some(hwnd) = w.hwnd_from_exe(&exe) { + monitor_idx = i; + workspace_idx = j; + hwnd_from_exe = hwnd; + bool = true; + break 'outer; + } + } + } + + if bool { + self.focus_monitor(monitor_idx)?; + self.monitors_mut().get_mut(monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor"))?.focus_workspace(workspace_idx)?; + self.monitors_mut().get_mut(monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor"))? + .workspaces_mut().get_mut(workspace_idx) + .ok_or_else(|| anyhow!("there is no workspace"))? + .focus_container_by_window(hwnd_from_exe)?; + self.update_focused_workspace_by_monitor_idx(monitor_idx)?; + } else { + + } + Ok(()) + } + #[tracing::instrument(skip(self))] pub fn send_always_on_top(&mut self, monitor_idx: Option, workspace_idx: Option, follows: Option) -> Result<()> { let mut contains_always_on_top = false; diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 8fa2a25ea..0e1069e12 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -715,6 +715,11 @@ struct Stop { whkd: bool, } +#[derive(Parser)] +struct Exe { + /// executable name + exe: String, +} #[derive(Parser)] struct SaveResize { /// File to which the resize layout dimensions should be saved @@ -873,6 +878,9 @@ enum SubCommand { /// Change focus to the window in the specified direction #[clap(arg_required_else_help = true)] Focus(Focus), + /// Change focus to the window with the specified executable + #[clap(arg_required_else_help = true)] + FocusExe(Exe), /// Move the focused window in the specified direction #[clap(arg_required_else_help = true)] Move(Move), @@ -1495,6 +1503,9 @@ fn main() -> Result<()> { SubCommand::Focus(arg) => { send_message(&SocketMessage::FocusWindow(arg.operation_direction).as_bytes()?)?; } + SubCommand::FocusExe(arg) => { + send_message(&SocketMessage::FocusExe(arg.exe).as_bytes()?)?; + } SubCommand::ForceFocus => { send_message(&SocketMessage::ForceFocus.as_bytes()?)?; } From 3c1df8f426d59c0f65fb4246be458f4200fcbae5 Mon Sep 17 00:00:00 2001 From: pro470 Date: Wed, 5 Jun 2024 23:32:49 +0200 Subject: [PATCH 16/86] some fixes --- komorebi/src/window_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 502dc0e7a..e6799860f 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1063,7 +1063,7 @@ impl WindowManager { .focus_container_by_window(hwnd_from_exe)?; self.update_focused_workspace_by_monitor_idx(monitor_idx)?; } else { - + Err(anyhow!("there is no window with that exe"))? } Ok(()) } From 3fe0188d28b0750e6c4846173b05dd1440032de9 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 6 Jun 2024 00:27:57 +0200 Subject: [PATCH 17/86] some fixes --- komorebi/src/window_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index e6799860f..90b6c52db 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1061,7 +1061,7 @@ impl WindowManager { .workspaces_mut().get_mut(workspace_idx) .ok_or_else(|| anyhow!("there is no workspace"))? .focus_container_by_window(hwnd_from_exe)?; - self.update_focused_workspace_by_monitor_idx(monitor_idx)?; + self.update_focused_workspace(self.mouse_follows_focus, true)?; } else { Err(anyhow!("there is no window with that exe"))? } From 8f8fc21a40cf80d97e9954f8447d3dd31b327aa3 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 6 Jun 2024 00:40:32 +0200 Subject: [PATCH 18/86] some fixes --- komorebi/src/window_manager.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 90b6c52db..d50cb47ac 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1039,6 +1039,8 @@ impl WindowManager { let mut workspace_idx = 0; let mut hwnd_from_exe: isize = 0; let mut bool = false; + let mouse_follows_focus = self.mouse_follows_focus; + let offset = self.work_area_offset; 'outer: for (i, m ) in self.monitors.elements().iter().enumerate(){ for (j, w) in m.workspaces().iter().enumerate() { @@ -1053,14 +1055,16 @@ impl WindowManager { } if bool { + + let target_monitor = self.monitors_mut().get_mut(monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor"))?; self.focus_monitor(monitor_idx)?; - self.monitors_mut().get_mut(monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor"))?.focus_workspace(workspace_idx)?; - self.monitors_mut().get_mut(monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor"))? - .workspaces_mut().get_mut(workspace_idx) + target_monitor.focus_workspace(workspace_idx)?; + target_monitor.workspaces_mut().get_mut(workspace_idx) .ok_or_else(|| anyhow!("there is no workspace"))? .focus_container_by_window(hwnd_from_exe)?; + target_monitor.load_focused_workspace(mouse_follows_focus)?; + target_monitor.update_focused_workspace(offset)?; self.update_focused_workspace(self.mouse_follows_focus, true)?; } else { Err(anyhow!("there is no window with that exe"))? From 07ff5d479d440c4bcaf1832a95cf76c18d410be4 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 6 Jun 2024 11:40:34 +0200 Subject: [PATCH 19/86] some fixes --- komorebi/src/window_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index d50cb47ac..9657ea360 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1056,9 +1056,9 @@ impl WindowManager { if bool { + self.focus_monitor(monitor_idx)?; let target_monitor = self.monitors_mut().get_mut(monitor_idx) .ok_or_else(|| anyhow!("there is no monitor"))?; - self.focus_monitor(monitor_idx)?; target_monitor.focus_workspace(workspace_idx)?; target_monitor.workspaces_mut().get_mut(workspace_idx) .ok_or_else(|| anyhow!("there is no workspace"))? From 493531e764604a51cc8912c43239931855fbe453 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 8 Jun 2024 14:54:16 -0700 Subject: [PATCH 20/86] refactor(wm): use bounded channels --- komorebi/src/border_manager/mod.rs | 16 ++++++++++------ komorebi/src/stackbar_manager/mod.rs | 2 +- komorebi/src/transparency_manager.rs | 2 +- komorebi/src/winevent_listener.rs | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/komorebi/src/border_manager/mod.rs b/komorebi/src/border_manager/mod.rs index e84d13160..feb7a7b83 100644 --- a/komorebi/src/border_manager/mod.rs +++ b/komorebi/src/border_manager/mod.rs @@ -59,7 +59,7 @@ pub struct Notification; static CHANNEL: OnceLock<(Sender, Receiver)> = OnceLock::new(); pub fn channel() -> &'static (Sender, Receiver) { - CHANNEL.get_or_init(crossbeam_channel::unbounded) + CHANNEL.get_or_init(|| crossbeam_channel::bounded(5)) } pub fn event_tx() -> Sender { @@ -129,11 +129,16 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result // Check the wm state every time we receive a notification let state = wm.lock(); + let is_paused = state.is_paused; + let focused_monitor_idx = state.focused_monitor_idx(); + let monitors = state.monitors.elements().clone(); + let pending_move_op = state.pending_move_op.clone(); + drop(state); // If borders are disabled if !BORDER_ENABLED.load_consume() // Or if the wm is paused - || state.is_paused + || is_paused // Or if we are handling an alt-tab across workspaces || ALT_TAB_HWND.load().is_some() { @@ -146,9 +151,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result continue 'receiver; } - let focused_monitor_idx = state.focused_monitor_idx(); - - 'monitors: for (monitor_idx, m) in state.monitors.elements().iter().enumerate() { + 'monitors: for (monitor_idx, m) in monitors.iter().enumerate() { // Only operate on the focused workspace of each monitor if let Some(ws) = m.focused_workspace() { // Workspaces with tiling disabled don't have borders @@ -215,6 +218,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result for id in &to_remove { borders.remove(id); } + continue 'monitors; } @@ -261,7 +265,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result for (idx, c) in ws.containers().iter().enumerate() { // Update border when moving or resizing with mouse - if state.pending_move_op.is_some() && idx == ws.focused_container_idx() { + if pending_move_op.is_some() && idx == ws.focused_container_idx() { let restore_z_order = *Z_ORDER.lock(); *Z_ORDER.lock() = ZOrder::TopMost; diff --git a/komorebi/src/stackbar_manager/mod.rs b/komorebi/src/stackbar_manager/mod.rs index e7cbe2fe0..f4e0655fb 100644 --- a/komorebi/src/stackbar_manager/mod.rs +++ b/komorebi/src/stackbar_manager/mod.rs @@ -40,7 +40,7 @@ pub struct Notification; static CHANNEL: OnceLock<(Sender, Receiver)> = OnceLock::new(); pub fn channel() -> &'static (Sender, Receiver) { - CHANNEL.get_or_init(crossbeam_channel::unbounded) + CHANNEL.get_or_init(|| crossbeam_channel::bounded(5)) } pub fn event_tx() -> Sender { diff --git a/komorebi/src/transparency_manager.rs b/komorebi/src/transparency_manager.rs index bc7841bf7..8d9c5f0cc 100644 --- a/komorebi/src/transparency_manager.rs +++ b/komorebi/src/transparency_manager.rs @@ -29,7 +29,7 @@ pub fn known_hwnds() -> Vec { } pub fn channel() -> &'static (Sender, Receiver) { - CHANNEL.get_or_init(crossbeam_channel::unbounded) + CHANNEL.get_or_init(|| crossbeam_channel::bounded(5)) } pub fn event_tx() -> Sender { diff --git a/komorebi/src/winevent_listener.rs b/komorebi/src/winevent_listener.rs index 4b9220cf2..f74a7ddf7 100644 --- a/komorebi/src/winevent_listener.rs +++ b/komorebi/src/winevent_listener.rs @@ -50,7 +50,7 @@ pub fn start() { } fn channel() -> &'static (Sender, Receiver) { - CHANNEL.get_or_init(crossbeam_channel::unbounded) + CHANNEL.get_or_init(|| crossbeam_channel::bounded(5)) } pub fn event_tx() -> Sender { From e01e9e701931e96a2f56931c38dadffbed549da7 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 17 Jun 2024 00:58:26 +0200 Subject: [PATCH 21/86] some fixes --- komorebi/src/process_command.rs | 24 ++++++++++++++++++++++++ komorebi/src/window_manager.rs | 16 +++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 385611c32..50ec7eb7d 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -397,6 +397,7 @@ impl WindowManager { self.adjust_workspace_padding(sizing, adjustment)?; } SocketMessage::MoveContainerToWorkspaceNumber(workspace_idx) => { + self.send_always_on_top(None, Some(workspace_idx), Some(true))?; self.move_container_to_workspace(workspace_idx, true)?; } SocketMessage::CycleMoveContainerToWorkspace(direction) => { @@ -413,9 +414,12 @@ impl WindowManager { .ok_or_else(|| anyhow!("there must be at least one workspace"))?, ); + self.send_always_on_top(None, Some(workspace_idx), Some(true))?; + self.move_container_to_workspace(workspace_idx, true)?; } SocketMessage::MoveContainerToMonitorNumber(monitor_idx) => { + self.send_always_on_top(Some(monitor_idx), None, Some(true))?; self.move_container_to_monitor(monitor_idx, None, true)?; } SocketMessage::SwapWorkspacesToMonitorNumber(monitor_idx) => { @@ -428,9 +432,12 @@ impl WindowManager { .ok_or_else(|| anyhow!("there must be at least one monitor"))?, ); + self.send_always_on_top(Some(monitor_idx), None, Some(true))?; + self.move_container_to_monitor(monitor_idx, None, true)?; } SocketMessage::SendContainerToWorkspaceNumber(workspace_idx) => { + self.send_always_on_top(None, Some(workspace_idx), Some(false))?; self.move_container_to_workspace(workspace_idx, false)?; } SocketMessage::CycleSendContainerToWorkspace(direction) => { @@ -447,9 +454,12 @@ impl WindowManager { .ok_or_else(|| anyhow!("there must be at least one workspace"))?, ); + self.send_always_on_top(None, Some(workspace_idx), Some(false))?; + self.move_container_to_workspace(workspace_idx, false)?; } SocketMessage::SendContainerToMonitorNumber(monitor_idx) => { + self.send_always_on_top(Some(monitor_idx), None, Some(false))?; self.move_container_to_monitor(monitor_idx, None, false)?; } SocketMessage::CycleSendContainerToMonitor(direction) => { @@ -459,18 +469,23 @@ impl WindowManager { .ok_or_else(|| anyhow!("there must be at least one monitor"))?, ); + self.send_always_on_top(Some(monitor_idx), None, Some(false))?; + self.move_container_to_monitor(monitor_idx, None, false)?; } SocketMessage::SendContainerToMonitorWorkspaceNumber(monitor_idx, workspace_idx) => { + self.send_always_on_top(Some(monitor_idx), Some(workspace_idx), Some(false))?; self.move_container_to_monitor(monitor_idx, Option::from(workspace_idx), false)?; } SocketMessage::MoveContainerToMonitorWorkspaceNumber(monitor_idx, workspace_idx) => { + self.send_always_on_top(Some(monitor_idx), Some(workspace_idx), Some(true))?; self.move_container_to_monitor(monitor_idx, Option::from(workspace_idx), true)?; } SocketMessage::SendContainerToNamedWorkspace(ref workspace) => { if let Some((monitor_idx, workspace_idx)) = self.monitor_workspace_index_by_name(workspace) { + self.send_always_on_top(Some(monitor_idx), Some(workspace_idx), Some(false))?; self.move_container_to_monitor( monitor_idx, Option::from(workspace_idx), @@ -482,6 +497,7 @@ impl WindowManager { if let Some((monitor_idx, workspace_idx)) = self.monitor_workspace_index_by_name(workspace) { + self.send_always_on_top(Some(monitor_idx), Some(workspace_idx), Some(true))?; self.move_container_to_monitor(monitor_idx, Option::from(workspace_idx), true)?; } } @@ -650,6 +666,8 @@ impl WindowManager { .ok_or_else(|| anyhow!("there must be at least one workspace"))?, ); + self.send_always_on_top(None, Option::from(workspace_idx), None)?; + self.focus_workspace(workspace_idx)?; } SocketMessage::FocusLastWorkspace => { @@ -667,6 +685,7 @@ impl WindowManager { if let Some(monitor) = self.focused_monitor_mut() { if let Some(last_focused_workspace) = monitor.last_focused_workspace() { + self.send_always_on_top(None, Option::from(last_focused_workspace), None)?; self.focus_workspace(last_focused_workspace)?; } } @@ -684,6 +703,7 @@ impl WindowManager { } if self.focused_workspace_idx().unwrap_or_default() != workspace_idx { + self.send_always_on_top(None, Option::from(workspace_idx), None)?; self.focus_workspace(workspace_idx)?; } } @@ -699,11 +719,13 @@ impl WindowManager { for (i, monitor) in self.monitors_mut().iter_mut().enumerate() { if i != focused_monitor_idx { + //self.send_always_on_top(Option::from(i), Some(workspace_idx), None)?; monitor.focus_workspace(workspace_idx)?; monitor.load_focused_workspace(false)?; } } + self.send_always_on_top(Option::from(focused_monitor_idx), Some(workspace_idx), None)?; self.focus_workspace(workspace_idx)?; } SocketMessage::FocusMonitorWorkspaceNumber(monitor_idx, workspace_idx) => { @@ -713,6 +735,7 @@ impl WindowManager { let focused_pair = (focused_monitor_idx, focused_workspace_idx); if focused_pair != (monitor_idx, workspace_idx) { + self.send_always_on_top(Option::from(monitor_idx), Some(workspace_idx), None)?; self.focus_monitor(monitor_idx)?; self.focus_workspace(workspace_idx)?; } @@ -721,6 +744,7 @@ impl WindowManager { if let Some((monitor_idx, workspace_idx)) = self.monitor_workspace_index_by_name(name) { + self.send_always_on_top(Option::from(monitor_idx), Some(workspace_idx), None)?; self.focus_monitor(monitor_idx)?; self.focus_workspace(workspace_idx)?; } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index f7a651fce..64be480b7 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1184,13 +1184,16 @@ impl WindowManager { pub fn check_aot_windows(&mut self) -> Result<()> { let mut not_contains = vec![]; - for (i, hwnd) in self.always_on_top.as_ref().unwrap().iter().enumerate() { + if self.always_on_top.is_none() { + return Ok(()) + } + for (i, hwnd) in self.always_on_top.as_ref().ok_or_else(|| anyhow!("there is no always on top windows"))?.iter().enumerate() { let mut not_contains_bool = true; - for monitor in self.monitors.elements().iter() { - for workspace in monitor.workspaces() { + 'monitor: for monitor in self.monitors.elements().iter() { + for workspace in monitor.workspaces().iter() { if workspace.contains_managed_window(*hwnd) { not_contains_bool = false; - break; + break 'monitor; } } } @@ -1238,8 +1241,6 @@ impl WindowManager { ) -> Result<()> { self.handle_unmanaged_window_behaviour()?; - self.send_always_on_top(Some(monitor_idx), workspace_idx, Some(follow))?; - tracing::info!("moving container"); let focused_monitor_idx = self.focused_monitor_idx(); @@ -1323,7 +1324,6 @@ impl WindowManager { tracing::info!("moving container"); - self.send_always_on_top(None, Some(idx), Some(follow))?; let mouse_follows_focus = self.mouse_follows_focus; @@ -2496,7 +2496,6 @@ impl WindowManager { #[tracing::instrument(skip(self))] pub fn focus_monitor(&mut self, idx: usize) -> Result<()> { tracing::info!("focusing monitor"); - self.send_always_on_top(Some(idx), None, None)?; if self.monitors().get(idx).is_some() { @@ -2603,7 +2602,6 @@ impl WindowManager { pub fn focus_workspace(&mut self, idx: usize) -> Result<()> { tracing::info!("focusing workspace"); - self.send_always_on_top(None, Some(idx), None)?; let mouse_follows_focus = self.mouse_follows_focus; let monitor = self From 0c9a45b41e1d0ff445e6d341144c8f5249162079 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 17 Jun 2024 21:55:02 +0200 Subject: [PATCH 22/86] some fixes --- komorebi-core/src/lib.rs | 1 + komorebi/src/process_command.rs | 10 +++++++++- komorebi/src/window_manager.rs | 28 ++++++++++++++++++++++++---- komorebic/src/main.rs | 14 ++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 0939d3882..b43721a8e 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -46,6 +46,7 @@ pub enum SocketMessage { StackAll, UnstackAll, FocusExe(String), + DisplayMonitorWorkspaceNumber(usize,usize), ResizeWindowEdge(OperationDirection, Sizing), ResizeWindowAxis(Axis, Sizing), UnstackWindow, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 50ec7eb7d..05f5f057b 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -199,6 +199,9 @@ impl WindowManager { self.focus_container_in_direction(direction)?; self.promote_container_to_front()? } + SocketMessage::DisplayMonitorWorkspaceNumber(monitor_idx, workspace_idx) => { + self.display_monitor_workspace(monitor_idx, workspace_idx)?; + } SocketMessage::FocusWindow(direction) => { self.focus_container_in_direction(direction)?; } @@ -717,9 +720,14 @@ impl WindowManager { let focused_monitor_idx = self.focused_monitor_idx(); + for i in 0..self.monitors.elements().len() { + if i != focused_monitor_idx { + self.send_always_on_top(Option::from(i), Option::from(workspace_idx), None)?; + } + } + for (i, monitor) in self.monitors_mut().iter_mut().enumerate() { if i != focused_monitor_idx { - //self.send_always_on_top(Option::from(i), Some(workspace_idx), None)?; monitor.focus_workspace(workspace_idx)?; monitor.load_focused_workspace(false)?; } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 472c98d7e..c015c6154 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1056,10 +1056,14 @@ impl WindowManager { if bool { - self.focus_monitor(monitor_idx)?; - let target_monitor = self.monitors_mut().get_mut(monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor"))?; - target_monitor.focus_workspace(workspace_idx)?; + if self.focused_monitor_idx() != monitor_idx { + self.focus_monitor(monitor_idx)?; + + } + if self.focused_workspace_idx()? != workspace_idx { + self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no monitor"))?.focus_workspace(workspace_idx)?; + } + let target_monitor = self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no monitor"))?; target_monitor.workspaces_mut().get_mut(workspace_idx) .ok_or_else(|| anyhow!("there is no workspace"))? .focus_container_by_window(hwnd_from_exe)?; @@ -1072,6 +1076,22 @@ impl WindowManager { Ok(()) } + #[tracing::instrument(skip(self))] + pub fn display_monitor_workspace(&mut self, monitor_idx: usize, workspace_idx: usize) -> Result<()> { + + let monitor = self.monitors_mut() + .get_mut(monitor_idx) + .ok_or_else(|| anyhow!("There is no monitor"))?; + + monitor.focus_workspace(workspace_idx)?; + monitor.load_focused_workspace(false)?; + + let focused_workspace_idx = self.focused_workspace_idx()?; + self.focus_workspace(focused_workspace_idx)?; + + Ok(()) + } + #[tracing::instrument(skip(self))] pub fn send_always_on_top(&mut self, monitor_idx: Option, workspace_idx: Option, follows: Option) -> Result<()> { let mut contains_always_on_top = false; diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 0e1069e12..ea226f439 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -720,6 +720,14 @@ struct Exe { /// executable name exe: String, } + +#[derive(Parser)] +struct DisplayMonitorWorkspace { + /// Monitor index (zero-indexed) + monitor: usize, + /// Workspace index on the specified monitor (zero-indexed) + workspace: usize, +} #[derive(Parser)] struct SaveResize { /// File to which the resize layout dimensions should be saved @@ -875,6 +883,9 @@ enum SubCommand { #[clap(arg_required_else_help = true)] #[clap(alias = "load")] LoadResize(LoadResize), + /// Display the workspace index at monitor index + #[clap(arg_required_else_help = true)] + DisplayMonitorWorkspace(DisplayMonitorWorkspace), /// Change focus to the window in the specified direction #[clap(arg_required_else_help = true)] Focus(Focus), @@ -1500,6 +1511,9 @@ fn main() -> Result<()> { println!("{line}"); } } + SubCommand::DisplayMonitorWorkspace(arg) => { + send_message(&SocketMessage::DisplayMonitorWorkspaceNumber(arg.monitor, arg.workspace).as_bytes()?)?; + } SubCommand::Focus(arg) => { send_message(&SocketMessage::FocusWindow(arg.operation_direction).as_bytes()?)?; } From 5294e101ce776c729168d34484d38369ab67eb29 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 17 Jun 2024 21:59:25 +0200 Subject: [PATCH 23/86] some fixes --- komorebi/src/process_command.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 05f5f057b..f8d9a0dcf 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -200,6 +200,7 @@ impl WindowManager { self.promote_container_to_front()? } SocketMessage::DisplayMonitorWorkspaceNumber(monitor_idx, workspace_idx) => { + self.send_always_on_top(Option::from(monitor_idx), Option::from(workspace_idx), None)?; self.display_monitor_workspace(monitor_idx, workspace_idx)?; } SocketMessage::FocusWindow(direction) => { From 5ac0f08d1e91239d4c623872c22c4b0f870e133d Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 24 Jun 2024 13:35:04 +0200 Subject: [PATCH 24/86] some fixes --- komorebi/src/window_manager.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 0d8bdbd2d..af49ce39f 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -100,6 +100,7 @@ pub struct WindowManager { pub pending_move_op: Option<(usize, usize, usize)>, pub already_moved_window_handles: Arc>>, pub always_on_top: Option>, + pub last_focused_monitor: Option, } @@ -284,6 +285,7 @@ impl WindowManager { pending_move_op: None, already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())), always_on_top: None, + last_focused_monitor: None, }) } From 6c55a8e62b44d83b7b90c85651a03225b70ba0e1 Mon Sep 17 00:00:00 2001 From: pro470 Date: Mon, 24 Jun 2024 13:42:49 +0200 Subject: [PATCH 25/86] some fixes --- komorebi/src/window_manager.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 0fddb2a8f..433124b21 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -100,7 +100,6 @@ pub struct WindowManager { pub pending_move_op: Option<(usize, usize, usize)>, pub already_moved_window_handles: Arc>>, pub always_on_top: Option>, - pub last_focused_monitor: Option, } @@ -285,7 +284,6 @@ impl WindowManager { pending_move_op: None, already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())), always_on_top: None, - last_focused_monitor: None, }) } From d6ee0763445b817e72172a8dcafd445a0bc258df Mon Sep 17 00:00:00 2001 From: pro470 Date: Tue, 25 Jun 2024 01:55:38 +0200 Subject: [PATCH 26/86] some fixes --- komorebi-core/src/lib.rs | 2 +- komorebi/src/process_command.rs | 4 ++-- komorebi/src/window_manager.rs | 27 ++++++++++++++++++++------- komorebic/src/main.rs | 7 +++++-- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index b58bc2230..73b5aedcb 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -45,7 +45,7 @@ pub enum SocketMessage { StackWindow(OperationDirection), StackAll, UnstackAll, - FocusExe(String), + FocusExe(Option, Option), DisplayMonitorWorkspaceNumber(usize,usize), ResizeWindowEdge(OperationDirection, Sizing), ResizeWindowAxis(Axis, Sizing), diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 82f372bb6..992932d1e 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -208,8 +208,8 @@ impl WindowManager { SocketMessage::FocusWindow(direction) => { self.focus_container_in_direction(direction)?; } - SocketMessage::FocusExe(ref exe) => { - self.focus_window_from_exe(exe)?; + SocketMessage::FocusExe( ref exe, hwnd) => { + self.focus_window_from_exe(exe, hwnd)?; } SocketMessage::MoveWindow(direction) => { self.move_container_in_direction(direction)?; diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 433124b21..ac074f215 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1087,7 +1087,7 @@ impl WindowManager { #[tracing::instrument(skip(self))] - pub fn focus_window_from_exe(&mut self, exe: &String) -> Result<()> { + pub fn focus_window_from_exe(&mut self, exe: &Option, hwnd: Option) -> Result<()> { let mut monitor_idx = 0; let mut workspace_idx = 0; @@ -1098,12 +1098,25 @@ impl WindowManager { 'outer: for (i, m ) in self.monitors.elements().iter().enumerate(){ for (j, w) in m.workspaces().iter().enumerate() { - if let Some(hwnd) = w.hwnd_from_exe(&exe) { - monitor_idx = i; - workspace_idx = j; - hwnd_from_exe = hwnd; - bool = true; - break 'outer; + if let Some(hwnd) = hwnd { + if w.contains_managed_window(hwnd) { + monitor_idx = i; + workspace_idx = j; + hwnd_from_exe = hwnd; + bool = true; + break 'outer; + } + } + if let Some(exe) = exe { + if let Some(hwndexe) = w.hwnd_from_exe(&exe) { + monitor_idx = i; + workspace_idx = j; + hwnd_from_exe = hwndexe; + bool = true; + if !hwnd.is_some() { + break 'outer; + } + } } } } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index b66810ee1..8ba031558 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -731,7 +731,10 @@ struct Stop { #[derive(Parser)] struct Exe { /// executable name - exe: String, + exe: Option, + /// hwnd handle of the window + hwnd: Option, + } #[derive(Parser)] @@ -1537,7 +1540,7 @@ fn main() -> Result<()> { send_message(&SocketMessage::FocusWindow(arg.operation_direction).as_bytes()?)?; } SubCommand::FocusExe(arg) => { - send_message(&SocketMessage::FocusExe(arg.exe).as_bytes()?)?; + send_message(&SocketMessage::FocusExe(arg.exe,arg.hwnd).as_bytes()?)?; } SubCommand::ForceFocus => { send_message(&SocketMessage::ForceFocus.as_bytes()?)?; From 9eacd35e2c504049d0b15dfa50bb810484b1e806 Mon Sep 17 00:00:00 2001 From: pro470 Date: Tue, 25 Jun 2024 02:29:22 +0200 Subject: [PATCH 27/86] some fixes --- komorebic/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 8ba031558..198aa3c48 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -731,8 +731,10 @@ struct Stop { #[derive(Parser)] struct Exe { /// executable name + #[clap(short, long)] exe: Option, /// hwnd handle of the window + #[clap(long)] hwnd: Option, } From 3f839041b8d893855191f0e1e06697cd6f4f3ba2 Mon Sep 17 00:00:00 2001 From: pro470 Date: Tue, 9 Jul 2024 15:53:18 +0200 Subject: [PATCH 28/86] fixed the workspace rules but when komorebi stats but found out when you use the alt-tab feature it doesnt creates the container where the window should be in so it is still not managed when using alt-tab feature but for everything else it should work --- komorebi/src/window_manager.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 91bfcc5d7..333b5da00 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -531,6 +531,23 @@ impl WindowManager { // Parse the operation and remove any windows that are not placed according to their rules for op in &to_move { + let mut test: bool = false; + 'outer: for (i, m) in self.monitors().iter().enumerate() { + for (j, w) in m.workspaces().iter().enumerate() { + if focused_workspace_idx != j && focused_monitor_idx != i { + if w.contains_managed_window(op.hwnd) { + test = true; + break 'outer; + } + } + } + } + + if !test { + Window::from(op.hwnd).hide(); + should_update_focused_workspace = true; + } + let origin_workspace = self .monitors_mut() .get_mut(op.origin_monitor_idx) From bf59eb89d3b4a615b71c4e62bb519822a63ffa99 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Thu, 11 Jul 2024 20:51:40 -0700 Subject: [PATCH 29/86] fix(animation): disable on cross-monitor ops There are quite a lot of janky animation bugs when moving window containers across monitor and workspace boundaries. This commit disables animation on all of the main cross-border window container operations, meaning that animations should now only happen within the context of a single workspace. fix #912 --- komorebi/src/window_manager.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index d2cf2203c..135fe1175 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -65,6 +65,7 @@ use crate::BorderColours; use crate::Colour; use crate::Rgb; use crate::WorkspaceRule; +use crate::ANIMATION_ENABLED; use crate::CUSTOM_FFM; use crate::DATA_DIR; use crate::DISPLAY_INDEX_PREFERENCES; @@ -1108,6 +1109,7 @@ impl WindowManager { follow: bool, ) -> Result<()> { self.handle_unmanaged_window_behaviour()?; + let animation = ANIMATION_ENABLED.swap(false, Ordering::SeqCst); tracing::info!("moving container"); @@ -1177,12 +1179,17 @@ impl WindowManager { self.focus_monitor(monitor_idx)?; } - self.update_focused_workspace(self.mouse_follows_focus, true) + self.update_focused_workspace(self.mouse_follows_focus, true)?; + + ANIMATION_ENABLED.store(animation, Ordering::SeqCst); + + Ok(()) } #[tracing::instrument(skip(self))] pub fn move_container_to_workspace(&mut self, idx: usize, follow: bool) -> Result<()> { self.handle_unmanaged_window_behaviour()?; + let animation = ANIMATION_ENABLED.swap(false, Ordering::SeqCst); tracing::info!("moving container"); @@ -1194,7 +1201,11 @@ impl WindowManager { monitor.move_container_to_workspace(idx, follow)?; monitor.load_focused_workspace(mouse_follows_focus)?; - self.update_focused_workspace(mouse_follows_focus, true) + self.update_focused_workspace(mouse_follows_focus, true)?; + + ANIMATION_ENABLED.store(animation, Ordering::SeqCst); + + Ok(()) } pub fn remove_focused_workspace(&mut self) -> Option { @@ -1297,6 +1308,12 @@ impl WindowManager { let origin_monitor_idx = self.focused_monitor_idx(); let target_container_idx = workspace.new_idx_for_direction(direction); + let animation = if target_container_idx.is_none() { + Some(ANIMATION_ENABLED.swap(false, Ordering::SeqCst)) + } else { + None + }; + match target_container_idx { // If there is nowhere to move on the current workspace, try to move it onto the monitor // in that direction if there is one @@ -1421,7 +1438,13 @@ impl WindowManager { } } - self.update_focused_workspace(self.mouse_follows_focus, true) + self.update_focused_workspace(self.mouse_follows_focus, true)?; + + if let Some(animation) = animation { + ANIMATION_ENABLED.store(animation, Ordering::SeqCst); + } + + Ok(()) } #[tracing::instrument(skip(self))] From ff3555915b762bc04b640272f0dcb8ac8b986327 Mon Sep 17 00:00:00 2001 From: pro470 Date: Tue, 16 Jul 2024 23:04:28 +0200 Subject: [PATCH 30/86] fix merge conflicts --- komorebic/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index d1b7b08b2..54461e936 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -1574,13 +1574,13 @@ fn main() -> Result<()> { } } SubCommand::DisplayMonitorWorkspace(arg) => { - send_message(&SocketMessage::DisplayMonitorWorkspaceNumber(arg.monitor, arg.workspace).as_bytes()?)?; + send_message(&SocketMessage::DisplayMonitorWorkspaceNumber(arg.monitor, arg.workspace))?; } SubCommand::Focus(arg) => { send_message(&SocketMessage::FocusWindow(arg.operation_direction))?; } SubCommand::FocusExe(arg) => { - send_message(&SocketMessage::FocusExe(arg.exe,arg.hwnd).as_bytes()?)?; + send_message(&SocketMessage::FocusExe(arg.exe,arg.hwnd))?; } SubCommand::ForceFocus => { send_message(&SocketMessage::ForceFocus)?; @@ -1763,7 +1763,7 @@ fn main() -> Result<()> { send_message(&SocketMessage::ToggleMaximize)?; } SubCommand::ToggleAlwaysOnTop => { - send_message(&SocketMessage::ToggleAlwaysOnTop.as_bytes()?)?; + send_message(&SocketMessage::ToggleAlwaysOnTop)?; } SubCommand::WorkspaceLayout(arg) => { send_message(&SocketMessage::WorkspaceLayout( From e647d4e8796fe87ab0679886bc7b7396986dd17a Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 9 Aug 2024 20:11:06 -0700 Subject: [PATCH 31/86] fix(wm): socket cleanup on exit This commit ensures that Shutdown signals will be sent to subscriber sockets and that "komorebi.sock" will be cleaned up on exit. Alongside these changes, komorebi_client::send_message no longer retries so that integrators can receive feedback via io::Result errors when komorebi is not running. --- komorebi-client/src/lib.rs | 12 +++--------- komorebi/src/lib.rs | 2 +- komorebi/src/main.rs | 12 ++++++++++++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/komorebi-client/src/lib.rs b/komorebi-client/src/lib.rs index e57e5e0cf..9a9662e9b 100644 --- a/komorebi-client/src/lib.rs +++ b/komorebi-client/src/lib.rs @@ -57,16 +57,10 @@ const KOMOREBI: &str = "komorebi.sock"; pub fn send_message(message: &SocketMessage) -> std::io::Result<()> { let socket = DATA_DIR.join(KOMOREBI); - let mut connected = false; - while !connected { - if let Ok(mut stream) = UnixStream::connect(&socket) { - connected = true; - stream.write_all(serde_json::to_string(message)?.as_bytes())?; - } - } - - Ok(()) + let mut stream = UnixStream::connect(socket)?; + stream.write_all(serde_json::to_string(message)?.as_bytes()) } + pub fn send_query(message: &SocketMessage) -> std::io::Result { let socket = DATA_DIR.join(KOMOREBI); diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index a22d88bc8..e22bd0840 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -163,7 +163,7 @@ lazy_static! { ])); static ref SUBSCRIPTION_PIPES: Arc>> = Arc::new(Mutex::new(HashMap::new())); - static ref SUBSCRIPTION_SOCKETS: Arc>> = + pub static ref SUBSCRIPTION_SOCKETS: Arc>> = Arc::new(Mutex::new(HashMap::new())); static ref TCP_CONNECTIONS: Arc>> = Arc::new(Mutex::new(HashMap::new())); diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 13d4f288f..5f28bffcd 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -7,6 +7,7 @@ clippy::doc_markdown )] +use std::net::Shutdown; use std::path::PathBuf; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -23,6 +24,7 @@ use sysinfo::Process; use tracing_appender::non_blocking::WorkerGuard; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::EnvFilter; +use uds_windows::UnixStream; use komorebi::border_manager; use komorebi::focus_manager; @@ -287,5 +289,15 @@ fn main() -> Result<()> { WindowsApi::disable_focus_follows_mouse()?; } + let sockets = komorebi::SUBSCRIPTION_SOCKETS.lock(); + for path in (*sockets).values() { + if let Ok(stream) = UnixStream::connect(path) { + stream.shutdown(Shutdown::Both)?; + } + } + + let socket = DATA_DIR.join("komorebi.sock"); + let _ = std::fs::remove_file(socket); + std::process::exit(130); } From 9260b68e16b04bf01fd146b9f216cf537997e0cd Mon Sep 17 00:00:00 2001 From: thearturca Date: Tue, 23 Jul 2024 12:20:56 +0300 Subject: [PATCH 32/86] fix(animation): enable cross-monitor animations This commit is a squashed combination of the following commits from #920 by @thearturca. Thanks to both @thearturca for @amnweb for their work in fixing and thoroughly testing these changes respectively. 935079281a79bacdb8777c0a4606d221329dccc6 fix(animation): added pending cancel count to track `is_cancelled` state 84ad947e1fb773bf23d770608a72aa26abdbb0b7 refactor(animation): remove cancel idx decreasing 804b0380f709da94d8ec4ae9918dac7db0fd3590 refactor(animation): remove `ANIMATION_TEMPORARILY_DISABLED` global vars f25787393c6ecd7f48fade369f58fb671e1205b3 fix(animation): extend cancelling system to support multiple cancel call dfd6e98e9c0d077b871aaff8175d80aa024eca3c refactor(window): reuse window rect in `animate_position` method --- komorebi/src/animation.rs | 30 +++++++++++++++------ komorebi/src/animation_manager.rs | 43 ++++++++++++++++++++++++++----- komorebi/src/lib.rs | 1 - komorebi/src/process_event.rs | 5 ---- komorebi/src/window.rs | 21 +++++++-------- komorebi/src/window_manager.rs | 18 ------------- 6 files changed, 67 insertions(+), 51 deletions(-) diff --git a/komorebi/src/animation.rs b/komorebi/src/animation.rs index 3ebdd00e4..c0461d8b2 100644 --- a/komorebi/src/animation.rs +++ b/komorebi/src/animation.rs @@ -416,12 +416,15 @@ impl Animation { pub fn new(hwnd: isize) -> Self { Self { hwnd } } - pub fn cancel(&mut self) { + + /// Returns true if the animation needs to continue + pub fn cancel(&mut self) -> bool { if !ANIMATION_MANAGER.lock().in_progress(self.hwnd) { - return; + return true; } - ANIMATION_MANAGER.lock().cancel(self.hwnd); + // should be more than 0 + let cancel_idx = ANIMATION_MANAGER.lock().init_cancel(self.hwnd); let max_duration = Duration::from_secs(1); let spent_duration = Instant::now(); @@ -434,6 +437,12 @@ impl Animation { ANIMATION_DURATION.load(Ordering::SeqCst) / 2, )); } + + let latest_cancel_idx = ANIMATION_MANAGER.lock().latest_cancel_idx(self.hwnd); + + ANIMATION_MANAGER.lock().end_cancel(self.hwnd); + + latest_cancel_idx == cancel_idx } #[allow(clippy::cast_possible_truncation)] @@ -460,7 +469,11 @@ impl Animation { mut render_callback: impl FnMut(f64) -> Result<()>, ) -> Result<()> { if ANIMATION_MANAGER.lock().in_progress(self.hwnd) { - self.cancel(); + let should_animate = self.cancel(); + + if !should_animate { + return Ok(()); + } } ANIMATION_MANAGER.lock().start(self.hwnd); @@ -474,8 +487,7 @@ impl Animation { // check if animation is cancelled if ANIMATION_MANAGER.lock().is_cancelled(self.hwnd) { // cancel animation - // set all flags - ANIMATION_MANAGER.lock().end(self.hwnd); + ANIMATION_MANAGER.lock().cancel(self.hwnd); return Ok(()); } @@ -485,8 +497,10 @@ impl Animation { render_callback(progress).ok(); // sleep until next frame - if frame_start.elapsed() < target_frame_time { - std::thread::sleep(target_frame_time - frame_start.elapsed()); + let frame_time_elapsed = frame_start.elapsed(); + + if frame_time_elapsed < target_frame_time { + std::thread::sleep(target_frame_time - frame_time_elapsed); } } diff --git a/komorebi/src/animation_manager.rs b/komorebi/src/animation_manager.rs index 2fd3f7467..da6053a19 100644 --- a/komorebi/src/animation_manager.rs +++ b/komorebi/src/animation_manager.rs @@ -8,7 +8,8 @@ pub static ANIMATIONS_IN_PROGRESS: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, Clone, Copy)] struct AnimationState { pub in_progress: bool, - pub is_cancelled: bool, + pub cancel_idx_counter: usize, + pub pending_cancel_count: usize, } #[derive(Debug)] @@ -31,7 +32,7 @@ impl AnimationManager { pub fn is_cancelled(&self, hwnd: isize) -> bool { if let Some(animation_state) = self.animations.get(&hwnd) { - animation_state.is_cancelled + animation_state.pending_cancel_count > 0 } else { false } @@ -45,9 +46,35 @@ impl AnimationManager { } } + pub fn init_cancel(&mut self, hwnd: isize) -> usize { + if let Some(animation_state) = self.animations.get_mut(&hwnd) { + animation_state.pending_cancel_count += 1; + animation_state.cancel_idx_counter += 1; + + // return cancel idx + animation_state.cancel_idx_counter + } else { + 0 + } + } + + pub fn latest_cancel_idx(&mut self, hwnd: isize) -> usize { + if let Some(animation_state) = self.animations.get_mut(&hwnd) { + animation_state.cancel_idx_counter + } else { + 0 + } + } + + pub fn end_cancel(&mut self, hwnd: isize) { + if let Some(animation_state) = self.animations.get_mut(&hwnd) { + animation_state.pending_cancel_count -= 1; + } + } + pub fn cancel(&mut self, hwnd: isize) { if let Some(animation_state) = self.animations.get_mut(&hwnd) { - animation_state.is_cancelled = true; + animation_state.in_progress = false; } } @@ -55,7 +82,8 @@ impl AnimationManager { if let Entry::Vacant(e) = self.animations.entry(hwnd) { e.insert(AnimationState { in_progress: true, - is_cancelled: false, + cancel_idx_counter: 0, + pending_cancel_count: 0, }); ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); @@ -70,10 +98,11 @@ impl AnimationManager { pub fn end(&mut self, hwnd: isize) { if let Some(animation_state) = self.animations.get_mut(&hwnd) { animation_state.in_progress = false; - animation_state.is_cancelled = false; - self.animations.remove(&hwnd); - ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); + if animation_state.cancel_idx_counter == 0 { + self.animations.remove(&hwnd); + ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); + } } } } diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index e22bd0840..5000fd815 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -225,7 +225,6 @@ pub static SESSION_ID: AtomicU32 = AtomicU32::new(0); pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false); pub static ANIMATION_ENABLED: AtomicBool = AtomicBool::new(false); -pub static ANIMATION_TEMPORARILY_DISABLED: AtomicBool = AtomicBool::new(false); pub static ANIMATION_DURATION: AtomicU64 = AtomicU64::new(250); #[must_use] diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index c0479f988..9750d01e8 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -32,7 +32,6 @@ use crate::workspace_reconciliator::ALT_TAB_HWND; use crate::workspace_reconciliator::ALT_TAB_HWND_INSTANT; use crate::Notification; use crate::NotificationEvent; -use crate::ANIMATION_TEMPORARILY_DISABLED; use crate::DATA_DIR; use crate::HIDDEN_HWNDS; use crate::REGEX_IDENTIFIERS; @@ -478,8 +477,6 @@ impl WindowManager { origin_container_idx, )) = pending { - ANIMATION_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); - let target_workspace_idx = self .monitors() .get(target_monitor_idx) @@ -521,8 +518,6 @@ impl WindowManager { self.focus_monitor(target_monitor_idx)?; self.focus_workspace(target_workspace_idx)?; self.update_focused_workspace(false, false)?; - - ANIMATION_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst); } // Here we handle a simple move on the same monitor which is treated as // a container swap diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 9432e7a4c..4441f991e 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -5,7 +5,6 @@ use crate::stackbar_manager; use crate::ANIMATIONS_IN_PROGRESS; use crate::ANIMATION_DURATION; use crate::ANIMATION_ENABLED; -use crate::ANIMATION_TEMPORARILY_DISABLED; use std::collections::HashMap; use std::convert::TryFrom; use std::fmt::Display; @@ -172,11 +171,10 @@ impl Window { ) } - pub fn animate_position(&self, layout: &Rect, top: bool) -> Result<()> { + pub fn animate_position(&self, start_rect: &Rect, target_rect: &Rect, top: bool) -> Result<()> { let hwnd = self.hwnd(); - let curr_rect = WindowsApi::window_rect(hwnd).unwrap(); - - let target_rect = *layout; + let start_rect = *start_rect; + let target_rect = *target_rect; let duration = Duration::from_millis(ANIMATION_DURATION.load(Ordering::SeqCst)); let mut animation = self.animation; @@ -188,7 +186,7 @@ impl Window { std::thread::spawn(move || { animation.animate(duration, |progress: f64| { - let new_rect = Animation::lerp_rect(&curr_rect, &target_rect, progress); + let new_rect = Animation::lerp_rect(&start_rect, &target_rect, progress); if progress == 1.0 { WindowsApi::position_window(hwnd, &new_rect, top)?; @@ -209,7 +207,6 @@ impl Window { // using MoveWindow because it runs faster than SetWindowPos // so animation have more fps and feel smoother WindowsApi::move_window(hwnd, &new_rect, false)?; - // WindowsApi::position_window(hwnd, &new_rect, top)?; WindowsApi::invalidate_rect(hwnd, None, false); } @@ -221,14 +218,14 @@ impl Window { } pub fn set_position(&self, layout: &Rect, top: bool) -> Result<()> { - if WindowsApi::window_rect(self.hwnd())?.eq(layout) { + let window_rect = WindowsApi::window_rect(self.hwnd())?; + + if window_rect.eq(layout) { return Ok(()); } - if ANIMATION_ENABLED.load(Ordering::SeqCst) - && !ANIMATION_TEMPORARILY_DISABLED.load(Ordering::SeqCst) - { - self.animate_position(layout, top) + if ANIMATION_ENABLED.load(Ordering::SeqCst) { + self.animate_position(&window_rect, layout, top) } else { WindowsApi::position_window(self.hwnd(), layout, top) } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index c42a8b3ff..d05d3f59c 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -67,7 +67,6 @@ use crate::BorderColours; use crate::Colour; use crate::Rgb; use crate::WorkspaceRule; -use crate::ANIMATION_TEMPORARILY_DISABLED; use crate::CUSTOM_FFM; use crate::DATA_DIR; use crate::DISPLAY_INDEX_PREFERENCES; @@ -1113,7 +1112,6 @@ impl WindowManager { follow: bool, ) -> Result<()> { self.handle_unmanaged_window_behaviour()?; - ANIMATION_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); tracing::info!("moving container"); @@ -1185,15 +1183,12 @@ impl WindowManager { self.update_focused_workspace(self.mouse_follows_focus, true)?; - ANIMATION_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst); - Ok(()) } #[tracing::instrument(skip(self))] pub fn move_container_to_workspace(&mut self, idx: usize, follow: bool) -> Result<()> { self.handle_unmanaged_window_behaviour()?; - ANIMATION_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); tracing::info!("moving container"); @@ -1207,8 +1202,6 @@ impl WindowManager { self.update_focused_workspace(mouse_follows_focus, true)?; - ANIMATION_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst); - Ok(()) } @@ -1312,13 +1305,6 @@ impl WindowManager { let origin_monitor_idx = self.focused_monitor_idx(); let target_container_idx = workspace.new_idx_for_direction(direction); - let animation_temporarily_disabled = if target_container_idx.is_none() { - ANIMATION_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); - true - } else { - false - }; - match target_container_idx { // If there is nowhere to move on the current workspace, try to move it onto the monitor // in that direction if there is one @@ -1445,10 +1431,6 @@ impl WindowManager { self.update_focused_workspace(self.mouse_follows_focus, true)?; - if animation_temporarily_disabled { - ANIMATION_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst); - } - Ok(()) } From d1a2a1764825469b630784d7589b8429b7be2eec Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Mon, 16 Sep 2024 14:41:39 -0700 Subject: [PATCH 33/86] fix(bar): use custom windows-icons w/o panics This commit uses a custom fork of windows-icons which removes runtime panics and instead exposes a safe Option based API. --- Cargo.lock | 3 +-- komorebi-bar/Cargo.toml | 2 +- komorebi-bar/src/komorebi.rs | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e34a1f017..cba9db1d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6115,8 +6115,7 @@ dependencies = [ [[package]] name = "windows-icons" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8bbc62fa6f23804699b9559429f6f1eb761d215184e011cd365041d202e0b2e" +source = "git+https://github.com/LGUG2Z/windows-icons?rev=c70022b9d4badca863bd56862984a8582a4e5a15#c70022b9d4badca863bd56862984a8582a4e5a15" dependencies = [ "base64", "image", diff --git a/komorebi-bar/Cargo.toml b/komorebi-bar/Cargo.toml index 908f2bd55..a6c7ad512 100644 --- a/komorebi-bar/Cargo.toml +++ b/komorebi-bar/Cargo.toml @@ -33,4 +33,4 @@ tracing = "0.1" tracing-appender = "0.2" tracing-subscriber = { version = "0.3", features = ["env-filter"] } windows = { workspace = true } -windows-icons = "0.1" \ No newline at end of file +windows-icons = { git = "https://github.com/LGUG2Z/windows-icons", rev = "c70022b9d4badca863bd56862984a8582a4e5a15" } \ No newline at end of file diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index e9471605c..2c9f0ca42 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -223,8 +223,13 @@ impl KomorebiNotificationState { if let Ok(title) = window.title() { self.focused_window_title.clone_from(&title); self.focused_window_pid = Some(window.process_id()); - let img = windows_icons::get_icon_by_process_id(window.process_id()); - self.focused_window_icon = Some(img); + if let Some(img) = + windows_icons::get_icon_by_process_id(window.process_id()) + { + self.focused_window_icon = Some(img); + } else { + self.focused_window_icon = None; + } } } } else if let Some(container) = @@ -234,8 +239,13 @@ impl KomorebiNotificationState { if let Ok(title) = window.title() { self.focused_window_title.clone_from(&title); self.focused_window_pid = Some(window.process_id()); - let img = windows_icons::get_icon_by_process_id(window.process_id()); - self.focused_window_icon = Some(img); + if let Some(img) = + windows_icons::get_icon_by_process_id(window.process_id()) + { + self.focused_window_icon = Some(img); + } else { + self.focused_window_icon = None; + } } } } else { From 08f4fb12047e861b5d54a28765b0a11ec0fe6fc0 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 17 Sep 2024 21:09:11 -0700 Subject: [PATCH 34/86] feat(wm): add replace configuration socket message This commit introduces a new SocketMessage, ReplaceConfiguration, which attempts to replace a running instance of WindowManager with another created from a (presumably) different komorebi.json file. This will likely be useful for people who have multiple different monitor setups that they connect and disconnect from throughout the day, but definitely needs more testing. An experimental sub-widget which calls this SocketMessage has been added to komorebi-bar to aid with initial testing. --- Cargo.lock | 1 + komorebi-bar/Cargo.toml | 1 + komorebi-bar/src/bar.rs | 4 +- komorebi-bar/src/komorebi.rs | 145 +++++++++++++++++++++++++------- komorebi-bar/src/widget.rs | 2 +- komorebi/src/core/mod.rs | 1 + komorebi/src/main.rs | 1 + komorebi/src/process_command.rs | 28 ++++++ komorebi/src/static_config.rs | 30 ++++--- schema.bar.json | 46 +++++++++- 10 files changed, 208 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 978a322ec..496e75604 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2693,6 +2693,7 @@ dependencies = [ "color-eyre", "crossbeam-channel", "dirs", + "dunce", "eframe", "egui-phosphor", "font-loader", diff --git a/komorebi-bar/Cargo.toml b/komorebi-bar/Cargo.toml index 4c31aa802..a1a21edeb 100644 --- a/komorebi-bar/Cargo.toml +++ b/komorebi-bar/Cargo.toml @@ -14,6 +14,7 @@ clap = { version = "4", features = ["derive", "wrap_help"] } color-eyre = "0.6" crossbeam-channel = "0.5" dirs = { workspace = true } +dunce = "1" eframe = "0.28" egui-phosphor = "0.6.0" font-loader = "0.11" diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index a6f1d6a46..7bba98ad7 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -183,7 +183,7 @@ impl Komobar { for (idx, widget_config) in config.left_widgets.iter().enumerate() { if let WidgetConfig::Komorebi(config) = widget_config { - komorebi_widget = Some(Komorebi::from(*config)); + komorebi_widget = Some(Komorebi::from(config)); komorebi_widget_idx = Some(idx); side = Some(Side::Left); } @@ -191,7 +191,7 @@ impl Komobar { for (idx, widget_config) in config.right_widgets.iter().enumerate() { if let WidgetConfig::Komorebi(config) = widget_config { - komorebi_widget = Some(Komorebi::from(*config)); + komorebi_widget = Some(Komorebi::from(config)); komorebi_widget_idx = Some(idx); side = Some(Side::Right); } diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index c3b1aaf09..bd968c9cd 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -16,21 +16,26 @@ use eframe::egui::Ui; use image::RgbaImage; use komorebi_client::CycleDirection; use komorebi_client::NotificationEvent; +use komorebi_client::Rect; use komorebi_client::SocketMessage; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::cell::RefCell; +use std::collections::BTreeMap; +use std::path::PathBuf; use std::rc::Rc; -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct KomorebiConfig { /// Configure the Workspaces widget pub workspaces: KomorebiWorkspacesConfig, /// Configure the Layout widget - pub layout: KomorebiLayoutConfig, + pub layout: Option, /// Configure the Focused Window widget - pub focused_window: KomorebiFocusedWindowConfig, + pub focused_window: Option, + /// Configure the Configuration Switcher widget + pub configuration_switcher: Option, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -55,8 +60,37 @@ pub struct KomorebiFocusedWindowConfig { pub show_icon: bool, } -impl From for Komorebi { - fn from(value: KomorebiConfig) -> Self { +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct KomorebiConfigurationSwitcherConfig { + /// Enable the Komorebi Configurations widget + pub enable: bool, + /// A map of display friendly name => path to configuration.json + pub configurations: BTreeMap, +} + +impl From<&KomorebiConfig> for Komorebi { + fn from(value: &KomorebiConfig) -> Self { + let configuration_switcher = + if let Some(configuration_switcher) = &value.configuration_switcher { + let mut configuration_switcher = configuration_switcher.clone(); + for (_, location) in configuration_switcher.configurations.iter_mut() { + if let Ok(expanded) = std::env::var("KOMOREBI_CONFIG_HOME") { + *location = location.replace("$Env:KOMOREBI_CONFIG_HOME", &expanded); + } + + if let Ok(expanded) = std::env::var("USERPROFILE") { + *location = location.replace("$Env:USERPROFILE", &expanded); + } + + *location = dunce::simplified(&PathBuf::from(location.clone())) + .to_string_lossy() + .to_string(); + } + Some(configuration_switcher) + } else { + None + }; + Self { komorebi_notification_state: Rc::new(RefCell::new(KomorebiNotificationState { selected_workspace: String::new(), @@ -67,10 +101,12 @@ impl From for Komorebi { workspaces: vec![], hide_empty_workspaces: value.workspaces.hide_empty_workspaces, mouse_follows_focus: true, + work_area_offset: None, })), workspaces: value.workspaces, layout: value.layout, focused_window: value.focused_window, + configuration_switcher, } } } @@ -79,8 +115,9 @@ impl From for Komorebi { pub struct Komorebi { pub komorebi_notification_state: Rc>, pub workspaces: KomorebiWorkspacesConfig, - pub layout: KomorebiLayoutConfig, - pub focused_window: KomorebiFocusedWindowConfig, + pub layout: Option, + pub focused_window: Option, + pub configuration_switcher: Option, } impl BarWidget for Komorebi { @@ -103,9 +140,7 @@ impl BarWidget for Komorebi { .unwrap(); komorebi_client::send_message(&SocketMessage::FocusWorkspaceNumber(i)).unwrap(); komorebi_client::send_message(&SocketMessage::MouseFollowsFocus( - self.komorebi_notification_state - .borrow() - .mouse_follows_focus, + komorebi_notification_state.mouse_follows_focus, )) .unwrap(); komorebi_client::send_message(&SocketMessage::Retile).unwrap(); @@ -119,36 +154,78 @@ impl BarWidget for Komorebi { ui.add_space(WIDGET_SPACING); } - if self.layout.enable { - if ui - .add( - Label::new(&komorebi_notification_state.layout) - .selectable(false) - .sense(Sense::click()), - ) - .clicked() - { - komorebi_client::send_message(&SocketMessage::CycleLayout(CycleDirection::Next)) + if let Some(layout) = self.layout { + if layout.enable { + if ui + .add( + Label::new(&komorebi_notification_state.layout) + .selectable(false) + .sense(Sense::click()), + ) + .clicked() + { + komorebi_client::send_message(&SocketMessage::CycleLayout( + CycleDirection::Next, + )) .unwrap(); - } + } - ui.add_space(WIDGET_SPACING); + ui.add_space(WIDGET_SPACING); + } } - if self.focused_window.enable { - if self.focused_window.show_icon { - if let Some(img) = &komorebi_notification_state.focused_window_icon { - ui.add( - Image::from(&img_to_texture(ctx, img)) - .maintain_aspect_ratio(true) - .max_height(15.0), - ); + if let Some(configuration_switcher) = &self.configuration_switcher { + if configuration_switcher.enable { + for (name, location) in configuration_switcher.configurations.iter() { + let path = PathBuf::from(location); + if path.is_file() + && ui + .add(Label::new(name).selectable(false).sense(Sense::click())) + .clicked() + { + let canonicalized = dunce::canonicalize(path.clone()).unwrap_or(path); + komorebi_client::send_message(&SocketMessage::ReplaceConfiguration( + canonicalized, + )) + .unwrap(); + + if let Some(rect) = komorebi_notification_state.work_area_offset { + let monitor_index = komorebi_client::send_query(&SocketMessage::Query( + komorebi_client::StateQuery::FocusedMonitorIndex, + )) + .unwrap(); + + komorebi_client::send_message(&SocketMessage::MonitorWorkAreaOffset( + monitor_index.parse::().unwrap(), + rect, + )) + .unwrap(); + } + } } + + ui.add_space(WIDGET_SPACING); } + } + + if let Some(focused_window) = self.focused_window { + if focused_window.enable { + if focused_window.show_icon { + if let Some(img) = &komorebi_notification_state.focused_window_icon { + ui.add( + Image::from(&img_to_texture(ctx, img)) + .maintain_aspect_ratio(true) + .max_height(15.0), + ); + } + } - ui.add(Label::new(&komorebi_notification_state.focused_window_title).selectable(false)); + ui.add( + Label::new(&komorebi_notification_state.focused_window_title).selectable(false), + ); - ui.add_space(WIDGET_SPACING); + ui.add_space(WIDGET_SPACING); + } } } } @@ -170,6 +247,7 @@ pub struct KomorebiNotificationState { pub layout: String, pub hide_empty_workspaces: bool, pub mouse_follows_focus: bool, + pub work_area_offset: Option, } impl KomorebiNotificationState { @@ -199,6 +277,9 @@ impl KomorebiNotificationState { self.mouse_follows_focus = notification.state.mouse_follows_focus; let monitor = ¬ification.state.monitors.elements()[monitor_index]; + self.work_area_offset = + notification.state.monitors.elements()[monitor_index].work_area_offset(); + let focused_workspace_idx = monitor.focused_workspace_idx(); let mut workspaces = vec![]; diff --git a/komorebi-bar/src/widget.rs b/komorebi-bar/src/widget.rs index 33ffc6a11..c8ba21c5d 100644 --- a/komorebi-bar/src/widget.rs +++ b/komorebi-bar/src/widget.rs @@ -41,7 +41,7 @@ impl WidgetConfig { match self { WidgetConfig::Battery(config) => Box::new(Battery::from(*config)), WidgetConfig::Date(config) => Box::new(Date::from(config.clone())), - WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(*config)), + WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(config)), WidgetConfig::Media(config) => Box::new(Media::from(*config)), WidgetConfig::Memory(config) => Box::new(Memory::from(*config)), WidgetConfig::Network(config) => Box::new(Network::from(*config)), diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 4633ae282..b84748e3d 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -133,6 +133,7 @@ pub enum SocketMessage { ClearNamedWorkspaceLayoutRules(String), // Configuration ReloadConfiguration, + ReplaceConfiguration(PathBuf), ReloadStaticConfiguration(PathBuf), WatchConfiguration(bool), CompleteConfiguration, diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 5f28bffcd..269c81aea 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -220,6 +220,7 @@ fn main() -> Result<()> { Arc::new(Mutex::new(StaticConfig::preload( config, winevent_listener::event_rx(), + None, )?)) } else { Arc::new(Mutex::new(WindowManager::new( diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 60fd9e935..0c3ec4597 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -56,6 +56,7 @@ use crate::window::Window; use crate::window_manager; use crate::window_manager::WindowManager; use crate::windows_api::WindowsApi; +use crate::winevent_listener; use crate::GlobalState; use crate::Notification; use crate::NotificationEvent; @@ -1097,6 +1098,33 @@ impl WindowManager { SocketMessage::ReloadConfiguration => { Self::reload_configuration(); } + SocketMessage::ReplaceConfiguration(ref config) => { + // Check that this is a valid static config file first + if StaticConfig::read(config).is_ok() { + // Clear workspace rules; these will need to be replaced + WORKSPACE_RULES.lock().clear(); + // Pause so that restored windows come to the foreground from all workspaces + self.is_paused = true; + // Bring all windows to the foreground + self.restore_all_windows()?; + + // Create a new wm from the config path + let mut wm = StaticConfig::preload( + config, + winevent_listener::event_rx(), + self.command_listener.try_clone().ok(), + )?; + + // Initialize the new wm + wm.init()?; + + // This is equivalent to StaticConfig::postload for this use case + StaticConfig::reload(config, &mut wm)?; + + // Set self to the new wm instance + *self = wm; + } + } SocketMessage::ReloadStaticConfiguration(ref pathbuf) => { self.reload_static_configuration(pathbuf)?; } diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 84ec15982..e02082c21 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -1027,25 +1027,31 @@ impl StaticConfig { pub fn preload( path: &PathBuf, incoming: Receiver, + unix_listener: Option, ) -> Result { let content = std::fs::read_to_string(path)?; let mut value: Self = serde_json::from_str(&content)?; value.apply_globals()?; - let socket = DATA_DIR.join("komorebi.sock"); + let listener = match unix_listener { + Some(listener) => listener, + None => { + let socket = DATA_DIR.join("komorebi.sock"); - match std::fs::remove_file(&socket) { - Ok(()) => {} - Err(error) => match error.kind() { - // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ - ErrorKind::NotFound => {} - _ => { - return Err(error.into()); - } - }, - }; + match std::fs::remove_file(&socket) { + Ok(()) => {} + Err(error) => match error.kind() { + // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ + ErrorKind::NotFound => {} + _ => { + return Err(error.into()); + } + }, + }; - let listener = UnixListener::bind(&socket)?; + UnixListener::bind(&socket)? + } + }; let mut wm = WindowManager { monitors: Ring::default(), diff --git a/schema.bar.json b/schema.bar.json index 9f5502d13..cfa6d074b 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -150,11 +150,30 @@ "Komorebi": { "type": "object", "required": [ - "focused_window", - "layout", "workspaces" ], "properties": { + "configuration_switcher": { + "description": "Configure the Configuration Switcher widget", + "type": "object", + "required": [ + "configurations", + "enable" + ], + "properties": { + "configurations": { + "description": "A map of display friendly name => path to configuration.json", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "enable": { + "description": "Enable the Komorebi Configurations widget", + "type": "boolean" + } + } + }, "focused_window": { "description": "Configure the Focused Window widget", "type": "object", @@ -540,11 +559,30 @@ "Komorebi": { "type": "object", "required": [ - "focused_window", - "layout", "workspaces" ], "properties": { + "configuration_switcher": { + "description": "Configure the Configuration Switcher widget", + "type": "object", + "required": [ + "configurations", + "enable" + ], + "properties": { + "configurations": { + "description": "A map of display friendly name => path to configuration.json", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "enable": { + "description": "Enable the Komorebi Configurations widget", + "type": "boolean" + } + } + }, "focused_window": { "description": "Configure the Focused Window widget", "type": "object", From 0f3d703c9a6bb77cf5843d7b85aebd551b7543f7 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 17 Sep 2024 21:09:11 -0700 Subject: [PATCH 35/86] feat(wm): add replace configuration socket message This commit introduces a new SocketMessage, ReplaceConfiguration, which attempts to replace a running instance of WindowManager with another created from a (presumably) different komorebi.json file. This will likely be useful for people who have multiple different monitor setups that they connect and disconnect from throughout the day, but definitely needs more testing. An experimental sub-widget which calls this SocketMessage has been added to komorebi-bar to aid with initial testing. --- Cargo.lock | 1 + komorebi-bar/Cargo.toml | 1 + komorebi-bar/src/bar.rs | 4 +- komorebi-bar/src/komorebi.rs | 145 +++++++++++++++++++++++++------- komorebi-bar/src/widget.rs | 2 +- komorebi/src/core/mod.rs | 1 + komorebi/src/main.rs | 1 + komorebi/src/process_command.rs | 28 ++++++ komorebi/src/static_config.rs | 30 ++++--- komorebic/src/main.rs | 20 ++++- schema.bar.json | 46 +++++++++- 11 files changed, 224 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 978a322ec..496e75604 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2693,6 +2693,7 @@ dependencies = [ "color-eyre", "crossbeam-channel", "dirs", + "dunce", "eframe", "egui-phosphor", "font-loader", diff --git a/komorebi-bar/Cargo.toml b/komorebi-bar/Cargo.toml index 4c31aa802..a1a21edeb 100644 --- a/komorebi-bar/Cargo.toml +++ b/komorebi-bar/Cargo.toml @@ -14,6 +14,7 @@ clap = { version = "4", features = ["derive", "wrap_help"] } color-eyre = "0.6" crossbeam-channel = "0.5" dirs = { workspace = true } +dunce = "1" eframe = "0.28" egui-phosphor = "0.6.0" font-loader = "0.11" diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index a6f1d6a46..7bba98ad7 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -183,7 +183,7 @@ impl Komobar { for (idx, widget_config) in config.left_widgets.iter().enumerate() { if let WidgetConfig::Komorebi(config) = widget_config { - komorebi_widget = Some(Komorebi::from(*config)); + komorebi_widget = Some(Komorebi::from(config)); komorebi_widget_idx = Some(idx); side = Some(Side::Left); } @@ -191,7 +191,7 @@ impl Komobar { for (idx, widget_config) in config.right_widgets.iter().enumerate() { if let WidgetConfig::Komorebi(config) = widget_config { - komorebi_widget = Some(Komorebi::from(*config)); + komorebi_widget = Some(Komorebi::from(config)); komorebi_widget_idx = Some(idx); side = Some(Side::Right); } diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index c3b1aaf09..bd968c9cd 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -16,21 +16,26 @@ use eframe::egui::Ui; use image::RgbaImage; use komorebi_client::CycleDirection; use komorebi_client::NotificationEvent; +use komorebi_client::Rect; use komorebi_client::SocketMessage; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::cell::RefCell; +use std::collections::BTreeMap; +use std::path::PathBuf; use std::rc::Rc; -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct KomorebiConfig { /// Configure the Workspaces widget pub workspaces: KomorebiWorkspacesConfig, /// Configure the Layout widget - pub layout: KomorebiLayoutConfig, + pub layout: Option, /// Configure the Focused Window widget - pub focused_window: KomorebiFocusedWindowConfig, + pub focused_window: Option, + /// Configure the Configuration Switcher widget + pub configuration_switcher: Option, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -55,8 +60,37 @@ pub struct KomorebiFocusedWindowConfig { pub show_icon: bool, } -impl From for Komorebi { - fn from(value: KomorebiConfig) -> Self { +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct KomorebiConfigurationSwitcherConfig { + /// Enable the Komorebi Configurations widget + pub enable: bool, + /// A map of display friendly name => path to configuration.json + pub configurations: BTreeMap, +} + +impl From<&KomorebiConfig> for Komorebi { + fn from(value: &KomorebiConfig) -> Self { + let configuration_switcher = + if let Some(configuration_switcher) = &value.configuration_switcher { + let mut configuration_switcher = configuration_switcher.clone(); + for (_, location) in configuration_switcher.configurations.iter_mut() { + if let Ok(expanded) = std::env::var("KOMOREBI_CONFIG_HOME") { + *location = location.replace("$Env:KOMOREBI_CONFIG_HOME", &expanded); + } + + if let Ok(expanded) = std::env::var("USERPROFILE") { + *location = location.replace("$Env:USERPROFILE", &expanded); + } + + *location = dunce::simplified(&PathBuf::from(location.clone())) + .to_string_lossy() + .to_string(); + } + Some(configuration_switcher) + } else { + None + }; + Self { komorebi_notification_state: Rc::new(RefCell::new(KomorebiNotificationState { selected_workspace: String::new(), @@ -67,10 +101,12 @@ impl From for Komorebi { workspaces: vec![], hide_empty_workspaces: value.workspaces.hide_empty_workspaces, mouse_follows_focus: true, + work_area_offset: None, })), workspaces: value.workspaces, layout: value.layout, focused_window: value.focused_window, + configuration_switcher, } } } @@ -79,8 +115,9 @@ impl From for Komorebi { pub struct Komorebi { pub komorebi_notification_state: Rc>, pub workspaces: KomorebiWorkspacesConfig, - pub layout: KomorebiLayoutConfig, - pub focused_window: KomorebiFocusedWindowConfig, + pub layout: Option, + pub focused_window: Option, + pub configuration_switcher: Option, } impl BarWidget for Komorebi { @@ -103,9 +140,7 @@ impl BarWidget for Komorebi { .unwrap(); komorebi_client::send_message(&SocketMessage::FocusWorkspaceNumber(i)).unwrap(); komorebi_client::send_message(&SocketMessage::MouseFollowsFocus( - self.komorebi_notification_state - .borrow() - .mouse_follows_focus, + komorebi_notification_state.mouse_follows_focus, )) .unwrap(); komorebi_client::send_message(&SocketMessage::Retile).unwrap(); @@ -119,36 +154,78 @@ impl BarWidget for Komorebi { ui.add_space(WIDGET_SPACING); } - if self.layout.enable { - if ui - .add( - Label::new(&komorebi_notification_state.layout) - .selectable(false) - .sense(Sense::click()), - ) - .clicked() - { - komorebi_client::send_message(&SocketMessage::CycleLayout(CycleDirection::Next)) + if let Some(layout) = self.layout { + if layout.enable { + if ui + .add( + Label::new(&komorebi_notification_state.layout) + .selectable(false) + .sense(Sense::click()), + ) + .clicked() + { + komorebi_client::send_message(&SocketMessage::CycleLayout( + CycleDirection::Next, + )) .unwrap(); - } + } - ui.add_space(WIDGET_SPACING); + ui.add_space(WIDGET_SPACING); + } } - if self.focused_window.enable { - if self.focused_window.show_icon { - if let Some(img) = &komorebi_notification_state.focused_window_icon { - ui.add( - Image::from(&img_to_texture(ctx, img)) - .maintain_aspect_ratio(true) - .max_height(15.0), - ); + if let Some(configuration_switcher) = &self.configuration_switcher { + if configuration_switcher.enable { + for (name, location) in configuration_switcher.configurations.iter() { + let path = PathBuf::from(location); + if path.is_file() + && ui + .add(Label::new(name).selectable(false).sense(Sense::click())) + .clicked() + { + let canonicalized = dunce::canonicalize(path.clone()).unwrap_or(path); + komorebi_client::send_message(&SocketMessage::ReplaceConfiguration( + canonicalized, + )) + .unwrap(); + + if let Some(rect) = komorebi_notification_state.work_area_offset { + let monitor_index = komorebi_client::send_query(&SocketMessage::Query( + komorebi_client::StateQuery::FocusedMonitorIndex, + )) + .unwrap(); + + komorebi_client::send_message(&SocketMessage::MonitorWorkAreaOffset( + monitor_index.parse::().unwrap(), + rect, + )) + .unwrap(); + } + } } + + ui.add_space(WIDGET_SPACING); } + } + + if let Some(focused_window) = self.focused_window { + if focused_window.enable { + if focused_window.show_icon { + if let Some(img) = &komorebi_notification_state.focused_window_icon { + ui.add( + Image::from(&img_to_texture(ctx, img)) + .maintain_aspect_ratio(true) + .max_height(15.0), + ); + } + } - ui.add(Label::new(&komorebi_notification_state.focused_window_title).selectable(false)); + ui.add( + Label::new(&komorebi_notification_state.focused_window_title).selectable(false), + ); - ui.add_space(WIDGET_SPACING); + ui.add_space(WIDGET_SPACING); + } } } } @@ -170,6 +247,7 @@ pub struct KomorebiNotificationState { pub layout: String, pub hide_empty_workspaces: bool, pub mouse_follows_focus: bool, + pub work_area_offset: Option, } impl KomorebiNotificationState { @@ -199,6 +277,9 @@ impl KomorebiNotificationState { self.mouse_follows_focus = notification.state.mouse_follows_focus; let monitor = ¬ification.state.monitors.elements()[monitor_index]; + self.work_area_offset = + notification.state.monitors.elements()[monitor_index].work_area_offset(); + let focused_workspace_idx = monitor.focused_workspace_idx(); let mut workspaces = vec![]; diff --git a/komorebi-bar/src/widget.rs b/komorebi-bar/src/widget.rs index 33ffc6a11..c8ba21c5d 100644 --- a/komorebi-bar/src/widget.rs +++ b/komorebi-bar/src/widget.rs @@ -41,7 +41,7 @@ impl WidgetConfig { match self { WidgetConfig::Battery(config) => Box::new(Battery::from(*config)), WidgetConfig::Date(config) => Box::new(Date::from(config.clone())), - WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(*config)), + WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(config)), WidgetConfig::Media(config) => Box::new(Media::from(*config)), WidgetConfig::Memory(config) => Box::new(Memory::from(*config)), WidgetConfig::Network(config) => Box::new(Network::from(*config)), diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 4633ae282..b84748e3d 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -133,6 +133,7 @@ pub enum SocketMessage { ClearNamedWorkspaceLayoutRules(String), // Configuration ReloadConfiguration, + ReplaceConfiguration(PathBuf), ReloadStaticConfiguration(PathBuf), WatchConfiguration(bool), CompleteConfiguration, diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 5f28bffcd..269c81aea 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -220,6 +220,7 @@ fn main() -> Result<()> { Arc::new(Mutex::new(StaticConfig::preload( config, winevent_listener::event_rx(), + None, )?)) } else { Arc::new(Mutex::new(WindowManager::new( diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 60fd9e935..0c3ec4597 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -56,6 +56,7 @@ use crate::window::Window; use crate::window_manager; use crate::window_manager::WindowManager; use crate::windows_api::WindowsApi; +use crate::winevent_listener; use crate::GlobalState; use crate::Notification; use crate::NotificationEvent; @@ -1097,6 +1098,33 @@ impl WindowManager { SocketMessage::ReloadConfiguration => { Self::reload_configuration(); } + SocketMessage::ReplaceConfiguration(ref config) => { + // Check that this is a valid static config file first + if StaticConfig::read(config).is_ok() { + // Clear workspace rules; these will need to be replaced + WORKSPACE_RULES.lock().clear(); + // Pause so that restored windows come to the foreground from all workspaces + self.is_paused = true; + // Bring all windows to the foreground + self.restore_all_windows()?; + + // Create a new wm from the config path + let mut wm = StaticConfig::preload( + config, + winevent_listener::event_rx(), + self.command_listener.try_clone().ok(), + )?; + + // Initialize the new wm + wm.init()?; + + // This is equivalent to StaticConfig::postload for this use case + StaticConfig::reload(config, &mut wm)?; + + // Set self to the new wm instance + *self = wm; + } + } SocketMessage::ReloadStaticConfiguration(ref pathbuf) => { self.reload_static_configuration(pathbuf)?; } diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 84ec15982..e02082c21 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -1027,25 +1027,31 @@ impl StaticConfig { pub fn preload( path: &PathBuf, incoming: Receiver, + unix_listener: Option, ) -> Result { let content = std::fs::read_to_string(path)?; let mut value: Self = serde_json::from_str(&content)?; value.apply_globals()?; - let socket = DATA_DIR.join("komorebi.sock"); + let listener = match unix_listener { + Some(listener) => listener, + None => { + let socket = DATA_DIR.join("komorebi.sock"); - match std::fs::remove_file(&socket) { - Ok(()) => {} - Err(error) => match error.kind() { - // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ - ErrorKind::NotFound => {} - _ => { - return Err(error.into()); - } - }, - }; + match std::fs::remove_file(&socket) { + Ok(()) => {} + Err(error) => match error.kind() { + // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ + ErrorKind::NotFound => {} + _ => { + return Err(error.into()); + } + }, + }; - let listener = UnixListener::bind(&socket)?; + UnixListener::bind(&socket)? + } + }; let mut wm = WindowManager { monitors: Ring::default(), diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index b5a45132c..5f8c0920e 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -861,6 +861,12 @@ struct EnableAutostart { ahk: bool, } +#[derive(Parser)] +struct ReplaceConfiguration { + /// Static configuration file which should be used + path: PathBuf, +} + #[derive(Parser)] #[clap(author, about, version = build::CLAP_LONG_VERSION)] struct Opts { @@ -1168,12 +1174,15 @@ enum SubCommand { Manage, /// Unmanage a window that was forcibly managed Unmanage, - /// Reload ~/komorebi.ahk (if it exists) + /// Replace the configuration of a running instance of komorebi from a static configuration file + #[clap(arg_required_else_help = true)] + ReplaceConfiguration(ReplaceConfiguration), + /// Reload legacy komorebi.ahk or komorebi.ps1 configurations (if they exist) ReloadConfiguration, - /// Enable or disable watching of ~/komorebi.ahk (if it exists) + /// Enable or disable watching of legacy komorebi.ahk or komorebi.ps1 configurations (if they exist) #[clap(arg_required_else_help = true)] WatchConfiguration(WatchConfiguration), - /// Signal that the final configuration option has been sent + /// For legacy komorebi.ahk or komorebi.ps1 configurations, signal that the final configuration option has been sent CompleteConfiguration, /// DEPRECATED since v0.1.22 #[clap(arg_required_else_help = true)] @@ -1518,7 +1527,7 @@ fn main() -> Result<()> { // Check that this file adheres to the schema static config schema as the last step, // so that more basic errors above can be shown to the error before schema-specific // errors - let _ = serde_json::from_str::(&config_source)?; + let _ = serde_json::from_str::(&config_source)?; if config_whkd.exists() { println!("Found {}; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag\n", config_whkd.to_string_lossy()); @@ -2283,6 +2292,9 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue arg.boolean_state.into(), ))?; } + SubCommand::ReplaceConfiguration(arg) => { + send_message(&SocketMessage::ReplaceConfiguration(arg.path))?; + } SubCommand::ReloadConfiguration => { send_message(&SocketMessage::ReloadConfiguration)?; } diff --git a/schema.bar.json b/schema.bar.json index 9f5502d13..cfa6d074b 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -150,11 +150,30 @@ "Komorebi": { "type": "object", "required": [ - "focused_window", - "layout", "workspaces" ], "properties": { + "configuration_switcher": { + "description": "Configure the Configuration Switcher widget", + "type": "object", + "required": [ + "configurations", + "enable" + ], + "properties": { + "configurations": { + "description": "A map of display friendly name => path to configuration.json", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "enable": { + "description": "Enable the Komorebi Configurations widget", + "type": "boolean" + } + } + }, "focused_window": { "description": "Configure the Focused Window widget", "type": "object", @@ -540,11 +559,30 @@ "Komorebi": { "type": "object", "required": [ - "focused_window", - "layout", "workspaces" ], "properties": { + "configuration_switcher": { + "description": "Configure the Configuration Switcher widget", + "type": "object", + "required": [ + "configurations", + "enable" + ], + "properties": { + "configurations": { + "description": "A map of display friendly name => path to configuration.json", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "enable": { + "description": "Enable the Komorebi Configurations widget", + "type": "boolean" + } + } + }, "focused_window": { "description": "Configure the Focused Window widget", "type": "object", From a35f25e274f443a4df58f52053e76a622d526f15 Mon Sep 17 00:00:00 2001 From: pro470 Date: Thu, 19 Sep 2024 18:57:09 +0200 Subject: [PATCH 36/86] fix merge conflicts --- komorebic/src/main.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index dbeee9601..07b28de2f 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -886,12 +886,6 @@ struct EnableAutostart { bar: bool, } -#[derive(Parser)] -struct ReplaceConfiguration { - /// Static configuration JSON file from which the configuration should be loaded - path: PathBuf, -} - #[derive(Parser)] struct ReplaceConfiguration { /// Static configuration file which should be used From 22c1d5fc04af62aa0f75164b96e41f00377a5437 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 21 Sep 2024 10:20:26 -0700 Subject: [PATCH 37/86] fix(bar): use truncated labels for titles This commit introduces a new wrapper, CustomUi, which is used to implement custom methods on top of eframe::egui::Ui. The default ui::add_sized method always has the text in a label centered, which is not desirable for a status bar where the layout should be ltr. A new function CustomUi::add_sized_left_to_right has been added to ensure that labels can be truncated with a custom width (which requires allocate_ui_with_layout), while also retaining the ability for the text to be aligned to the left rather than the center of the allocated layout. --- komorebi-bar/src/bar.rs | 7 +++ komorebi-bar/src/config.rs | 2 + komorebi-bar/src/komorebi.rs | 88 ++++++++++++++++++++++++++---------- komorebi-bar/src/main.rs | 3 ++ komorebi-bar/src/media.rs | 15 +++++- komorebi-bar/src/ui.rs | 21 +++++++++ schema.bar.json | 5 ++ 7 files changed, 114 insertions(+), 27 deletions(-) create mode 100644 komorebi-bar/src/ui.rs diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index 0def1435c..ee6e61bd9 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -4,6 +4,7 @@ use crate::komorebi::Komorebi; use crate::komorebi::KomorebiNotificationState; use crate::widget::BarWidget; use crate::widget::WidgetConfig; +use crate::MAX_LABEL_WIDTH; use crossbeam_channel::Receiver; use eframe::egui::Align; use eframe::egui::CentralPanel; @@ -30,6 +31,7 @@ use komorebi_themes::CatppuccinValue; use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; +use std::sync::atomic::Ordering; use std::sync::Arc; pub struct Komobar { @@ -132,6 +134,11 @@ impl Komobar { config: &KomobarConfig, previous_notification_state: Option>>, ) { + MAX_LABEL_WIDTH.store( + config.max_label_width.unwrap_or(400.0) as i32, + Ordering::SeqCst, + ); + if let Some(font_family) = &config.font_family { tracing::info!("attempting to add custom font family: {font_family}"); Self::add_custom_font(ctx, font_family); diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index 07ff5be00..255edfc8f 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -21,6 +21,8 @@ pub struct KomobarConfig { pub font_family: Option, /// Font size (default: 12.5) pub font_size: Option, + /// Max label width before text truncation (default: 400.0) + pub max_label_width: Option, /// Theme pub theme: Option, /// Left side widgets (ordered left-to-right) diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index bc221eee5..22b942e40 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -1,6 +1,8 @@ use crate::bar::apply_theme; use crate::config::KomobarTheme; +use crate::ui::CustomUi; use crate::widget::BarWidget; +use crate::MAX_LABEL_WIDTH; use crate::WIDGET_SPACING; use crossbeam_channel::Receiver; use eframe::egui::text::LayoutJob; @@ -16,6 +18,7 @@ use eframe::egui::TextStyle; use eframe::egui::TextureHandle; use eframe::egui::TextureOptions; use eframe::egui::Ui; +use eframe::egui::Vec2; use image::RgbaImage; use komorebi_client::CycleDirection; use komorebi_client::NotificationEvent; @@ -28,6 +31,7 @@ use std::cell::RefCell; use std::collections::BTreeMap; use std::path::PathBuf; use std::rc::Rc; +use std::sync::atomic::Ordering; #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct KomorebiConfig { @@ -295,36 +299,70 @@ impl BarWidget for Komorebi { ); if titles.len() > 1 { - ui.add(Label::new(layout_job).selectable(false)); + let available_height = ui.available_height(); + let mut custom_ui = CustomUi(ui); + custom_ui.add_sized_left_to_right( + Vec2::new( + MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32, + available_height, + ), + Label::new(layout_job).selectable(false).truncate(), + ); } else { - ui.add(Label::new(title).selectable(false)); - } - } else if ui - .add(Label::new(title).selectable(false).sense(Sense::click())) - .clicked() - { - if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(false)) - .is_err() - { - tracing::error!( - "could not send message to komorebi: MouseFollowsFocus" + let available_height = ui.available_height(); + let mut custom_ui = CustomUi(ui); + custom_ui.add_sized_left_to_right( + Vec2::new( + MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32, + available_height, + ), + Label::new(title).selectable(false).truncate(), ); } - - if komorebi_client::send_message(&SocketMessage::FocusStackWindow(i)) - .is_err() + } else { + let available_height = ui.available_height(); + let mut custom_ui = CustomUi(ui); + + if custom_ui + .add_sized_left_to_right( + Vec2::new( + MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32, + available_height, + ), + Label::new(title) + .selectable(false) + .sense(Sense::click()) + .truncate(), + ) + .clicked() { - tracing::error!("could not send message to komorebi: FocusStackWindow"); - } + if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus( + false, + )) + .is_err() + { + tracing::error!( + "could not send message to komorebi: MouseFollowsFocus" + ); + } - if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus( - komorebi_notification_state.mouse_follows_focus, - )) - .is_err() - { - tracing::error!( - "could not send message to komorebi: MouseFollowsFocus" - ); + if komorebi_client::send_message(&SocketMessage::FocusStackWindow(i)) + .is_err() + { + tracing::error!( + "could not send message to komorebi: FocusStackWindow" + ); + } + + if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus( + komorebi_notification_state.mouse_follows_focus, + )) + .is_err() + { + tracing::error!( + "could not send message to komorebi: MouseFollowsFocus" + ); + } } } diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index 7fb124928..fea080292 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -8,6 +8,7 @@ mod memory; mod network; mod storage; mod time; +mod ui; mod widget; use crate::bar::Komobar; @@ -24,11 +25,13 @@ use schemars::gen::SchemaSettings; use std::io::BufReader; use std::io::Read; use std::path::PathBuf; +use std::sync::atomic::AtomicI32; use std::sync::Arc; use std::time::Duration; use tracing_subscriber::EnvFilter; pub static WIDGET_SPACING: f32 = 10.0; +pub static MAX_LABEL_WIDTH: AtomicI32 = AtomicI32::new(400); #[derive(Parser)] #[clap(author, about, version)] diff --git a/komorebi-bar/src/media.rs b/komorebi-bar/src/media.rs index f88b181b7..23f8f9595 100644 --- a/komorebi-bar/src/media.rs +++ b/komorebi-bar/src/media.rs @@ -1,4 +1,6 @@ +use crate::ui::CustomUi; use crate::widget::BarWidget; +use crate::MAX_LABEL_WIDTH; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; use eframe::egui::Context; @@ -8,9 +10,11 @@ use eframe::egui::Sense; use eframe::egui::TextFormat; use eframe::egui::TextStyle; use eframe::egui::Ui; +use eframe::egui::Vec2; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use std::sync::atomic::Ordering; use windows::Media::Control::GlobalSystemMediaTransportControlsSessionManager; #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -98,8 +102,15 @@ impl BarWidget for Media { TextFormat::simple(font_id, ctx.style().visuals.text_color()), ); - if ui - .add( + let available_height = ui.available_height(); + let mut custom_ui = CustomUi(ui); + + if custom_ui + .add_sized_left_to_right( + Vec2::new( + MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32, + available_height, + ), Label::new(layout_job) .selectable(false) .sense(Sense::click()) diff --git a/komorebi-bar/src/ui.rs b/komorebi-bar/src/ui.rs new file mode 100644 index 000000000..26f2e0c94 --- /dev/null +++ b/komorebi-bar/src/ui.rs @@ -0,0 +1,21 @@ +use eframe::egui::Align; +use eframe::egui::Layout; +use eframe::egui::Response; +use eframe::egui::Ui; +use eframe::egui::Vec2; +use eframe::egui::Widget; + +pub struct CustomUi<'ui>(pub &'ui mut Ui); + +impl CustomUi<'_> { + pub fn add_sized_left_to_right( + &mut self, + max_size: impl Into, + widget: impl Widget, + ) -> Response { + let layout = Layout::left_to_right(Align::Center); + self.0 + .allocate_ui_with_layout(max_size.into(), layout, |ui| ui.add(widget)) + .inner + } +} diff --git a/schema.bar.json b/schema.bar.json index 2b97bcc35..a591e5ad2 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -408,6 +408,11 @@ ] } }, + "max_label_width": { + "description": "Max label width before text truncation (default: 400.0)", + "type": "number", + "format": "float" + }, "monitor": { "description": "Monitor options", "type": "object", From 861d4155513338ffe67a10d76aa982923b84148b Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 5 Oct 2024 18:38:40 -0700 Subject: [PATCH 38/86] chore(cargo): enable lto for release builds --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7557f8606..761f1cb57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,3 +63,6 @@ features = [ "Media", "Media_Control" ] + +[profile.release] +lto = true From 75d5971cc82ed40f045d3a905777df539b3fa4d3 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sun, 6 Oct 2024 13:02:04 -0700 Subject: [PATCH 39/86] refactor(bar): use native apis for positioning This commit replaces almost all uses of the egui Viewport API for bar window positioning with calls to SetWindowPos via komorebi_client's Window struct. This seems to play much more smoothly with multi-monitor setups where each monitor has a different scaling factor, opening the door for multiple instances of komorebi-bar.exe to run against multiple monitors. As a result of this change, the "viewport" configuration option has been renamed to "position" and doc strings have been changed to remove the reference to the egui crate docs. Similarly, "viewport.position" and "viewport.inner_size" have been renamed to "position.start" and "position.end" respectively. Backwards-compatibility aliases have been included for all renames. --- Cargo.lock | 7 -- komorebi-bar/Cargo.toml | 1 - komorebi-bar/src/bar.rs | 58 ++++++++++---- komorebi-bar/src/config.rs | 43 +++++++++-- komorebi-bar/src/main.rs | 154 +++++++++++++++++++++++-------------- komorebic/src/main.rs | 20 ++++- 6 files changed, 197 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66aee854b..883566598 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -501,12 +501,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atomic_float" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" - [[package]] name = "atspi" version = "0.19.0" @@ -2711,7 +2705,6 @@ dependencies = [ name = "komorebi-bar" version = "0.1.30" dependencies = [ - "atomic_float", "chrono", "clap", "color-eyre", diff --git a/komorebi-bar/Cargo.toml b/komorebi-bar/Cargo.toml index 98a564fba..802e79fc6 100644 --- a/komorebi-bar/Cargo.toml +++ b/komorebi-bar/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" komorebi-client = { path = "../komorebi-client" } komorebi-themes = { path = "../komorebi-themes" } -atomic_float = "1" chrono = { workspace = true } clap = { workspace = true } color-eyre = { workspace = true } diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index d9c0a967c..698a94a8f 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -1,11 +1,17 @@ use crate::config::KomobarConfig; use crate::config::KomobarTheme; +use crate::config::Position; +use crate::config::PositionConfig; use crate::komorebi::Komorebi; use crate::komorebi::KomorebiNotificationState; +use crate::process_hwnd; use crate::widget::BarWidget; use crate::widget::WidgetConfig; -use crate::DPI; +use crate::BAR_HEIGHT; use crate::MAX_LABEL_WIDTH; +use crate::MONITOR_LEFT; +use crate::MONITOR_RIGHT; +use crate::MONITOR_TOP; use crossbeam_channel::Receiver; use eframe::egui::Align; use eframe::egui::CentralPanel; @@ -18,11 +24,8 @@ use eframe::egui::FontId; use eframe::egui::Frame; use eframe::egui::Layout; use eframe::egui::Margin; -use eframe::egui::Pos2; use eframe::egui::Style; use eframe::egui::TextStyle; -use eframe::egui::Vec2; -use eframe::egui::ViewportCommand; use font_loader::system_fonts; use font_loader::system_fonts::FontPropertyBuilder; use komorebi_client::KomorebiTheme; @@ -146,16 +149,43 @@ impl Komobar { Self::add_custom_font(ctx, font_family); } - if let Some(viewport) = &config.viewport { - let dpi = DPI.load(Ordering::SeqCst); - if let Some(position) = viewport.position { - let pos2 = Pos2::new(position.x / dpi, position.y / dpi); - ctx.send_viewport_cmd(ViewportCommand::OuterPosition(pos2)); - } + let position = config.position.clone().unwrap_or(PositionConfig { + start: Some(Position { + x: MONITOR_LEFT.load(Ordering::SeqCst) as f32, + y: MONITOR_TOP.load(Ordering::SeqCst) as f32, + }), + end: Some(Position { + x: MONITOR_RIGHT.load(Ordering::SeqCst) as f32, + y: BAR_HEIGHT, + }), + }); - if let Some(position) = viewport.inner_size { - let vec2 = Vec2::new(position.x / dpi, position.y / dpi); - ctx.send_viewport_cmd(ViewportCommand::InnerSize(vec2)); + if let Some(hwnd) = process_hwnd() { + let start = position.start.unwrap_or(Position { + x: MONITOR_LEFT.load(Ordering::SeqCst) as f32, + y: MONITOR_TOP.load(Ordering::SeqCst) as f32, + }); + + let end = position.end.unwrap_or(Position { + x: MONITOR_RIGHT.load(Ordering::SeqCst) as f32, + y: BAR_HEIGHT, + }); + + let rect = komorebi_client::Rect { + left: start.x as i32, + top: start.y as i32, + right: end.x as i32, + bottom: end.y as i32, + }; + + let window = komorebi_client::Window::from(hwnd); + match window.set_position(&rect, false) { + Ok(_) => { + tracing::info!("updated bar position"); + } + Err(error) => { + tracing::error!("{}", error.to_string()) + } } } @@ -294,6 +324,8 @@ impl Komobar { scale_factor: cc.egui_ctx.native_pixels_per_point().unwrap_or(1.0), }; + komobar.apply_config(&cc.egui_ctx, &config, None); + // needs a double apply the first time for some reason komobar.apply_config(&cc.egui_ctx, &config, None); komobar diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index dae9fc9dc..8d59f6fbf 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -7,13 +7,15 @@ use komorebi_client::Rect; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use std::collections::HashMap; use std::path::PathBuf; #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] /// The `komorebi.bar.json` configuration file reference for `v0.1.30` pub struct KomobarConfig { - /// Viewport options (see: https://docs.rs/egui/latest/egui/viewport/struct.ViewportBuilder.html) - pub viewport: Option, + /// Bar positioning options + #[serde(alias = "viewport")] + pub position: Option, /// Frame options (see: https://docs.rs/egui/latest/egui/containers/struct.Frame.html) pub frame: Option, /// Monitor options @@ -32,12 +34,43 @@ pub struct KomobarConfig { pub right_widgets: Vec, } +impl KomobarConfig { + pub fn aliases(raw: &str) { + let mut map = HashMap::new(); + map.insert("position", ["viewport"]); + map.insert("end", ["inner_frame"]); + + let mut display = false; + + for aliases in map.values() { + for a in aliases { + if raw.contains(a) { + display = true; + } + } + } + + if display { + println!("\nYour bar configuration file contains some options that have been renamed or deprecated:\n"); + for (canonical, aliases) in map { + for alias in aliases { + if raw.contains(alias) { + println!(r#""{alias}" is now "{canonical}""#); + } + } + } + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct ViewportConfig { +pub struct PositionConfig { /// The desired starting position of the bar (0,0 = top left of the screen) - pub position: Option, + #[serde(alias = "position")] + pub start: Option, /// The desired size of the bar from the starting position (usually monitor width x desired height) - pub inner_size: Option, + #[serde(alias = "inner_size")] + pub end: Option, } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index 7474a651f..c7f3aa260 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -14,9 +14,8 @@ mod widget; use crate::bar::Komobar; use crate::config::KomobarConfig; use crate::config::Position; -use atomic_float::AtomicF32; +use crate::config::PositionConfig; use clap::Parser; -use color_eyre::eyre::bail; use eframe::egui::ViewportBuilder; use font_loader::system_fonts; use hotwatch::EventKind; @@ -31,12 +30,23 @@ use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; use tracing_subscriber::EnvFilter; +use windows::Win32::Foundation::BOOL; +use windows::Win32::Foundation::HWND; +use windows::Win32::Foundation::LPARAM; +use windows::Win32::System::Threading::GetCurrentProcessId; +use windows::Win32::System::Threading::GetCurrentThreadId; use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext; use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; +use windows::Win32::UI::WindowsAndMessaging::EnumThreadWindows; +use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId; pub static WIDGET_SPACING: f32 = 10.0; + pub static MAX_LABEL_WIDTH: AtomicI32 = AtomicI32::new(400); -pub static DPI: AtomicF32 = AtomicF32::new(1.0); +pub static MONITOR_LEFT: AtomicI32 = AtomicI32::new(0); +pub static MONITOR_TOP: AtomicI32 = AtomicI32::new(0); +pub static MONITOR_RIGHT: AtomicI32 = AtomicI32::new(0); +pub static BAR_HEIGHT: f32 = 50.0; #[derive(Parser)] #[clap(author, about, version)] @@ -53,36 +63,41 @@ struct Opts { /// Write an example komorebi.bar.json to disk #[clap(long)] quickstart: bool, + /// Print a list of aliases that can be renamed to canonical variants + #[clap(long)] + #[clap(hide = true)] + aliases: bool, } -macro_rules! as_ptr { - ($value:expr) => { - $value as *mut core::ffi::c_void - }; +extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL { + unsafe { + let mut process_id = 0; + GetWindowThreadProcessId(hwnd, Some(&mut process_id)); + + if process_id == GetCurrentProcessId() { + *(lparam.0 as *mut HWND) = hwnd; + BOOL::from(false) // Stop enumeration + } else { + BOOL::from(true) // Continue enumeration + } + } } -pub fn dpi_for_monitor(hmonitor: isize) -> color_eyre::Result { - use windows::Win32::Graphics::Gdi::HMONITOR; - use windows::Win32::UI::HiDpi::GetDpiForMonitor; - use windows::Win32::UI::HiDpi::MDT_EFFECTIVE_DPI; - - let mut dpi_x = u32::default(); - let mut dpi_y = u32::default(); - +fn process_hwnd() -> Option { unsafe { - match GetDpiForMonitor( - HMONITOR(as_ptr!(hmonitor)), - MDT_EFFECTIVE_DPI, - std::ptr::addr_of_mut!(dpi_x), - std::ptr::addr_of_mut!(dpi_y), - ) { - Ok(_) => {} - Err(error) => bail!(error), + let mut hwnd = HWND::default(); + let _ = EnumThreadWindows( + GetCurrentThreadId(), + Some(enum_window), + LPARAM(&mut hwnd as *mut HWND as isize), + ); + + if hwnd.0 as isize == 0 { + None + } else { + Some(hwnd.0 as isize) } } - - #[allow(clippy::cast_precision_loss)] - Ok(dpi_y as f32 / 96.0) } fn main() -> color_eyre::Result<()> { @@ -166,7 +181,7 @@ fn main() -> color_eyre::Result<()> { Option::from, ); - let config = match config_path { + let mut config = match config_path { None => { let komorebi_bar_json = include_str!("../../docs/komorebi.bar.example.json").to_string(); @@ -180,10 +195,12 @@ fn main() -> color_eyre::Result<()> { KomobarConfig::read(&default_config_path)? } Some(ref config) => { - tracing::info!( - "found configuration file: {}", - config.as_path().to_string_lossy() - ); + if !opts.aliases { + tracing::info!( + "found configuration file: {}", + config.as_path().to_string_lossy() + ); + } KomobarConfig::read(config)? } @@ -191,46 +208,65 @@ fn main() -> color_eyre::Result<()> { let config_path = config_path.unwrap_or(default_config_path); + if opts.aliases { + KomobarConfig::aliases(&std::fs::read_to_string(&config_path)?); + std::process::exit(0); + } + let state = serde_json::from_str::(&komorebi_client::send_query( &SocketMessage::State, )?)?; - let dpi = dpi_for_monitor(state.monitors.elements()[config.monitor.index].id())?; - DPI.store(dpi, Ordering::SeqCst); + MONITOR_RIGHT.store( + state.monitors.elements()[config.monitor.index].size().right, + Ordering::SeqCst, + ); - let mut viewport_builder = ViewportBuilder::default() - .with_decorations(false) - // .with_transparent(config.transparent) - .with_taskbar(false) - .with_position(Position { - x: state.monitors.elements()[config.monitor.index].size().left as f32 / dpi, - y: state.monitors.elements()[config.monitor.index].size().top as f32 / dpi, - }) - .with_inner_size({ - Position { - x: state.monitors.elements()[config.monitor.index].size().right as f32 / dpi, - y: 50.0 / dpi, - } - }); + MONITOR_TOP.store( + state.monitors.elements()[config.monitor.index].size().top, + Ordering::SeqCst, + ); - if let Some(viewport) = &config.viewport { - if let Some(mut position) = &viewport.position { - position.x /= dpi; - position.y /= dpi; + MONITOR_TOP.store( + state.monitors.elements()[config.monitor.index].size().left, + Ordering::SeqCst, + ); - let b = viewport_builder.clone(); - viewport_builder = b.with_position(position); + match config.position { + None => { + config.position = Some(PositionConfig { + start: Some(Position { + x: state.monitors.elements()[config.monitor.index].size().left as f32, + y: state.monitors.elements()[config.monitor.index].size().top as f32, + }), + end: Some(Position { + x: state.monitors.elements()[config.monitor.index].size().right as f32, + y: 50.0, + }), + }) } + Some(ref mut position) => { + if position.start.is_none() { + position.start = Some(Position { + x: state.monitors.elements()[config.monitor.index].size().left as f32, + y: state.monitors.elements()[config.monitor.index].size().top as f32, + }); + } - if let Some(mut inner_size) = &viewport.inner_size { - inner_size.x /= dpi; - inner_size.y /= dpi; - - let b = viewport_builder.clone(); - viewport_builder = b.with_inner_size(inner_size); + if position.end.is_none() { + position.end = Some(Position { + x: state.monitors.elements()[config.monitor.index].size().right as f32, + y: 50.0, + }) + } } } + let viewport_builder = ViewportBuilder::default() + .with_decorations(false) + // .with_transparent(config.transparent) + .with_taskbar(false); + let native_options = eframe::NativeOptions { viewport: viewport_builder, ..Default::default() diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 12e188b4b..b914944ae 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -2050,7 +2050,7 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue)) println!("* Join the Discord https://discord.gg/mGkn66PHkx - Chat, ask questions, share your desktops"); println!("* Read the docs https://lgug2z.github.io/komorebi - Quickly search through all komorebic commands"); - let static_config = arg.config.map_or_else( + let static_config = arg.config.clone().map_or_else( || { let komorebi_json = HOME_DIR.join("komorebi.json"); if komorebi_json.is_file() { @@ -2062,12 +2062,30 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue)) Option::from, ); + let bar_config = arg.config.map_or_else( + || { + let bar_json = HOME_DIR.join("komorebi.bar.json"); + if bar_json.is_file() { + Option::from(bar_json) + } else { + None + } + }, + Option::from, + ); + if let Some(config) = static_config { let path = resolve_home_path(config)?; let raw = std::fs::read_to_string(path)?; StaticConfig::aliases(&raw); StaticConfig::deprecated(&raw); } + + if bar_config.is_some() { + let output = Command::new("komorebi-bar.exe").arg("--aliases").output()?; + let stdout = String::from_utf8(output.stdout)?; + println!("{stdout}"); + } } SubCommand::Stop(arg) => { if arg.whkd { From 2f0a93058fc8646fd65c7aa71cc183b31f65a36b Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sun, 6 Oct 2024 16:30:06 -0700 Subject: [PATCH 40/86] feat(config): add bar configurations opt This commit adds a "bar_configurations" option to the static config file which takes an array of PathBufs. If this option is defined and the --bar flag is passed to the "komorebic start" command, komorebic will attempt to launch multiple instances of komorebi-bar.exe with the --config flag pointing to the PathBufs given. This configuration option is only consumed by komorebic, not by the window manager directly, so it could also be used by other status bar projects to read configuration file locations from. There is no requirement for the PathBufs to point specifically to komorebi bar configuration files if the --bar flag is not being used with "komorebic start". --- komorebi/src/static_config.rs | 5 +++ komorebic/src/main.rs | 77 ++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index c920f84ee..8bc09cef6 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -341,6 +341,10 @@ pub struct StaticConfig { /// How long to wait when compensating for slow applications, in milliseconds (default: 20) #[serde(skip_serializing_if = "Option::is_none")] pub slow_application_compensation_time: Option, + /// Komorebi status bar configuration files for multiple instances on different monitors + #[serde(skip_serializing_if = "Option::is_none")] + // this option is a little special because it is only consumed by komorebic + pub bar_configurations: Option>, } #[derive(Debug, Serialize, Deserialize, JsonSchema)] @@ -556,6 +560,7 @@ impl From<&WindowManager> for StaticConfig { SLOW_APPLICATION_COMPENSATION_TIME.load(Ordering::SeqCst), ), slow_application_identifiers: Option::from(SLOW_APPLICATION_IDENTIFIERS.lock().clone()), + bar_configurations: None, } } } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index b914944ae..139ad10f6 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -2025,19 +2025,68 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue)) } } + let static_config = arg.config.clone().map_or_else( + || { + let komorebi_json = HOME_DIR.join("komorebi.json"); + if komorebi_json.is_file() { + Option::from(komorebi_json) + } else { + None + } + }, + Option::from, + ); + if arg.bar { - let script = r" + if let Some(config) = &static_config { + let mut config = StaticConfig::read(config)?; + if let Some(display_bar_configurations) = &mut config.bar_configurations { + for config_file_path in &mut *display_bar_configurations { + let mut normalized = config_file_path + .to_string_lossy() + .to_string() + .replace( + "$Env:USERPROFILE", + &dirs::home_dir().unwrap().to_string_lossy(), + ) + .replace('"', "") + .replace('\\', "/"); + + if let Ok(komorebi_config_home) = std::env::var("KOMOREBI_CONFIG_HOME") + { + normalized = normalized + .replace("$Env:KOMOREBI_CONFIG_HOME", &komorebi_config_home) + .replace('"', "") + .replace('\\', "/"); + } + + let script = r"Start-Process 'komorebi-bar' '--config CONFIGFILE' -WindowStyle hidden" + .replace("CONFIGFILE", &normalized); + + match powershell_script::run(&script) { + Ok(_) => { + println!("{script}"); + } + Err(error) => { + println!("Error: {error}"); + } + } + } + } else { + let script = r" if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue)) { Start-Process komorebi-bar -WindowStyle hidden } "; - match powershell_script::run(script) { - Ok(_) => { - println!("{script}"); - } - Err(error) => { - println!("Error: {error}"); + match powershell_script::run(script) { + Ok(_) => { + println!("{script}"); + } + Err(error) => { + println!("Error: {error}"); + } + } } } } @@ -2050,18 +2099,6 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue)) println!("* Join the Discord https://discord.gg/mGkn66PHkx - Chat, ask questions, share your desktops"); println!("* Read the docs https://lgug2z.github.io/komorebi - Quickly search through all komorebic commands"); - let static_config = arg.config.clone().map_or_else( - || { - let komorebi_json = HOME_DIR.join("komorebi.json"); - if komorebi_json.is_file() { - Option::from(komorebi_json) - } else { - None - } - }, - Option::from, - ); - let bar_config = arg.config.map_or_else( || { let bar_json = HOME_DIR.join("komorebi.bar.json"); @@ -2074,7 +2111,7 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue)) Option::from, ); - if let Some(config) = static_config { + if let Some(config) = &static_config { let path = resolve_home_path(config)?; let raw = std::fs::read_to_string(path)?; StaticConfig::aliases(&raw); From 46e6d8977087ce027356e07e6531c84810fad075 Mon Sep 17 00:00:00 2001 From: alex-ds13 <145657253+alex-ds13@users.noreply.github.com> Date: Mon, 7 Oct 2024 17:22:57 +0100 Subject: [PATCH 41/86] fix(wm): update monitor focus before focus-stack-window This commit fixes the cases where you'd call this command on a monitor which was not focused, for example by pressing a button on a bar like komorebi-bar or other when you had focus on another monitor. This change ensures that first we focus the monitor where the mouse cursor is, this way it will act on the monitor that you've just pressed instead of the monior that was focused before. --- komorebi/src/process_command.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 2169be974..77777bc85 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -232,6 +232,13 @@ impl WindowManager { self.focused_window()?.focus(self.mouse_follows_focus)?; } SocketMessage::FocusStackWindow(idx) => { + // In case you are using this command on a bar on a monitor + // different from the currently focused one, you'd want that + // monitor to be focused so that the FocusStackWindow happens + // on the monitor with the bar you just pressed. + if let Some(monitor_idx) = self.monitor_idx_from_current_pos() { + self.focus_monitor(monitor_idx)?; + } self.focus_container_window(idx)?; self.focused_window()?.focus(self.mouse_follows_focus)?; } From c6e76d2906210b92cfd68889d8ecd90841242b9a Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Mon, 7 Oct 2024 16:47:56 -0700 Subject: [PATCH 42/86] fix(wm): ignore minimize calls on komorebi-bar Hopefully I don't have to make this yet another configurable list... --- komorebi/src/window.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 336398a72..4069d8e87 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -280,7 +280,10 @@ impl Window { } pub fn minimize(self) { - WindowsApi::minimize_window(self.hwnd); + let exe = self.exe().unwrap_or_default(); + if !exe.contains("komorebi-bar") { + WindowsApi::minimize_window(self.hwnd); + } } pub fn close(self) -> Result<()> { From 400f90105a25fbda66365854cd24051c49f8a6d0 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Mon, 7 Oct 2024 18:14:42 -0700 Subject: [PATCH 43/86] refactor(wm): standardize config env var handling This commit ensures that whenever komorebi.json is read and deserialized into StaticConfig via StaticConfig::read, all known paths where $Env:KOMOREBI_CONFIG_HOME and $Env:USERPROFILE are accepted will be run through the resolve_home_path helper fn. --- komorebi-bar/src/komorebi.rs | 8 ------ komorebi/src/static_config.rs | 38 ++++++++++++++++++++++------ komorebic/src/main.rs | 47 +++++++---------------------------- 3 files changed, 40 insertions(+), 53 deletions(-) diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index a16db58c1..4c60e05a3 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -83,14 +83,6 @@ impl From<&KomorebiConfig> for Komorebi { if let Some(configuration_switcher) = &value.configuration_switcher { let mut configuration_switcher = configuration_switcher.clone(); for (_, location) in configuration_switcher.configurations.iter_mut() { - if let Ok(expanded) = std::env::var("KOMOREBI_CONFIG_HOME") { - *location = location.replace("$Env:KOMOREBI_CONFIG_HOME", &expanded); - } - - if let Ok(expanded) = std::env::var("USERPROFILE") { - *location = location.replace("$Env:USERPROFILE", &expanded); - } - *location = dunce::simplified(&PathBuf::from(location.clone())) .to_string_lossy() .to_string(); diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 8bc09cef6..1ca3633a5 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -934,7 +934,34 @@ impl StaticConfig { pub fn read(path: &PathBuf) -> Result { let content = std::fs::read_to_string(path)?; - let value: Self = serde_json::from_str(&content)?; + let mut value: Self = serde_json::from_str(&content)?; + + if let Some(path) = &mut value.app_specific_configuration_path { + *path = resolve_home_path(&*path)?; + } + + if let Some(monitors) = &mut value.monitors { + for m in monitors { + for w in &mut m.workspaces { + if let Some(path) = &mut w.custom_layout { + *path = resolve_home_path(&*path)?; + } + + if let Some(map) = &mut w.custom_layout_rules { + for path in map.values_mut() { + *path = resolve_home_path(&*path)?; + } + } + } + } + } + + if let Some(bar_configurations) = &mut value.bar_configurations { + for path in bar_configurations { + *path = resolve_home_path(&*path)?; + } + } + Ok(value) } @@ -944,8 +971,7 @@ impl StaticConfig { incoming: Receiver, unix_listener: Option, ) -> Result { - let content = std::fs::read_to_string(path)?; - let mut value: Self = serde_json::from_str(&content)?; + let mut value = Self::read(path)?; value.apply_globals()?; let listener = match unix_listener { @@ -1024,8 +1050,7 @@ impl StaticConfig { } pub fn postload(path: &PathBuf, wm: &Arc>) -> Result<()> { - let content = std::fs::read_to_string(path)?; - let value: Self = serde_json::from_str(&content)?; + let value = Self::read(path)?; let mut wm = wm.lock(); if let Some(monitors) = value.monitors { @@ -1092,8 +1117,7 @@ impl StaticConfig { } pub fn reload(path: &PathBuf, wm: &mut WindowManager) -> Result<()> { - let content = std::fs::read_to_string(path)?; - let mut value: Self = serde_json::from_str(&content)?; + let mut value = Self::read(path)?; value.apply_globals()?; diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 139ad10f6..248cf6b83 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -1517,26 +1517,15 @@ fn main() -> Result<()> { println!("Found komorebi.json; this file can be passed to the start command with the --config flag\n"); - if let Ok(config) = &parsed_config { - if let Some(asc_path) = config.get("app_specific_configuration_path") { - let mut normalized_asc_path = asc_path - .to_string() - .replace( - "$Env:USERPROFILE", - &dirs::home_dir().unwrap().to_string_lossy(), - ) - .replace('"', "") - .replace('\\', "/"); - - if let Ok(komorebi_config_home) = std::env::var("KOMOREBI_CONFIG_HOME") { - normalized_asc_path = normalized_asc_path - .replace("$Env:KOMOREBI_CONFIG_HOME", &komorebi_config_home) - .replace('"', "") - .replace('\\', "/"); + if let Ok(config) = StaticConfig::read(&static_config) { + match config.app_specific_configuration_path { + None => { + println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n"); } - - if !Path::exists(Path::new(&normalized_asc_path)) { - println!("Application specific configuration file path '{normalized_asc_path}' does not exist. Try running 'komorebic fetch-asc'\n"); + Some(path) => { + if !Path::exists(Path::new(&path)) { + println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display()); + } } } } @@ -2042,26 +2031,8 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue)) let mut config = StaticConfig::read(config)?; if let Some(display_bar_configurations) = &mut config.bar_configurations { for config_file_path in &mut *display_bar_configurations { - let mut normalized = config_file_path - .to_string_lossy() - .to_string() - .replace( - "$Env:USERPROFILE", - &dirs::home_dir().unwrap().to_string_lossy(), - ) - .replace('"', "") - .replace('\\', "/"); - - if let Ok(komorebi_config_home) = std::env::var("KOMOREBI_CONFIG_HOME") - { - normalized = normalized - .replace("$Env:KOMOREBI_CONFIG_HOME", &komorebi_config_home) - .replace('"', "") - .replace('\\', "/"); - } - let script = r"Start-Process 'komorebi-bar' '--config CONFIGFILE' -WindowStyle hidden" - .replace("CONFIGFILE", &normalized); + .replace("CONFIGFILE", &config_file_path.to_string_lossy()); match powershell_script::run(&script) { Ok(_) => { From 98a2aa4b234798d3df5a377bc0aa041209894013 Mon Sep 17 00:00:00 2001 From: Csaba Date: Tue, 8 Oct 2024 19:02:55 +0200 Subject: [PATCH 44/86] feat(bar): add cpu widget This commit adds a CPU widget, following the patterns of the Memory widget. --- komorebi-bar/src/cpu.rs | 107 +++++++++++++++++++++++++++++++++++++ komorebi-bar/src/main.rs | 1 + komorebi-bar/src/widget.rs | 4 ++ 3 files changed, 112 insertions(+) create mode 100644 komorebi-bar/src/cpu.rs diff --git a/komorebi-bar/src/cpu.rs b/komorebi-bar/src/cpu.rs new file mode 100644 index 000000000..58f77db94 --- /dev/null +++ b/komorebi-bar/src/cpu.rs @@ -0,0 +1,107 @@ +use crate::widget::BarWidget; +use crate::WIDGET_SPACING; +use eframe::egui::text::LayoutJob; +use eframe::egui::Context; +use eframe::egui::FontId; +use eframe::egui::Label; +use eframe::egui::Sense; +use eframe::egui::TextFormat; +use eframe::egui::TextStyle; +use eframe::egui::Ui; +use schemars::JsonSchema; +use serde::Deserialize; +use serde::Serialize; +use std::process::Command; +use std::time::Duration; +use std::time::Instant; +use sysinfo::RefreshKind; +use sysinfo::System; + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct CpuConfig { + /// Enable the Cpu widget + pub enable: bool, + /// Data refresh interval (default: 10 seconds) + pub data_refresh_interval: Option, +} + +impl From for Cpu { + fn from(value: CpuConfig) -> Self { + let mut system = + System::new_with_specifics(RefreshKind::default().without_memory().without_processes()); + + system.refresh_cpu_usage(); + + Self { + enable: value.enable, + system, + data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + last_updated: Instant::now(), + } + } +} + +pub struct Cpu { + pub enable: bool, + system: System, + data_refresh_interval: u64, + last_updated: Instant, +} + +impl Cpu { + fn output(&mut self) -> String { + let now = Instant::now(); + if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) { + self.system.refresh_cpu_usage(); + self.last_updated = now; + } + + let used = self.system.global_cpu_usage(); + format!("CPU: {:.0}%", used) + } +} + +impl BarWidget for Cpu { + fn render(&mut self, ctx: &Context, ui: &mut Ui) { + if self.enable { + let output = self.output(); + if !output.is_empty() { + let font_id = ctx + .style() + .text_styles + .get(&TextStyle::Body) + .cloned() + .unwrap_or_else(FontId::default); + + let mut layout_job = LayoutJob::simple( + egui_phosphor::regular::CIRCUITRY.to_string(), + font_id.clone(), + ctx.style().visuals.selection.stroke.color, + 100.0, + ); + + layout_job.append( + &output, + 10.0, + TextFormat::simple(font_id, ctx.style().visuals.text_color()), + ); + + if ui + .add( + Label::new(layout_job) + .selectable(false) + .sense(Sense::click()), + ) + .clicked() + { + if let Err(error) = Command::new("cmd.exe").args(["/C", "taskmgr.exe"]).spawn() + { + eprintln!("{}", error) + } + } + } + + ui.add_space(WIDGET_SPACING); + } + } +} diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index c7f3aa260..d3d7033c5 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -1,4 +1,5 @@ mod bar; +mod cpu; mod battery; mod config; mod date; diff --git a/komorebi-bar/src/widget.rs b/komorebi-bar/src/widget.rs index c8ba21c5d..491443abc 100644 --- a/komorebi-bar/src/widget.rs +++ b/komorebi-bar/src/widget.rs @@ -1,5 +1,7 @@ use crate::battery::Battery; use crate::battery::BatteryConfig; +use crate::cpu::Cpu; +use crate::cpu::CpuConfig; use crate::date::Date; use crate::date::DateConfig; use crate::komorebi::Komorebi; @@ -27,6 +29,7 @@ pub trait BarWidget { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub enum WidgetConfig { Battery(BatteryConfig), + Cpu(CpuConfig), Date(DateConfig), Komorebi(KomorebiConfig), Media(MediaConfig), @@ -40,6 +43,7 @@ impl WidgetConfig { pub fn as_boxed_bar_widget(&self) -> Box { match self { WidgetConfig::Battery(config) => Box::new(Battery::from(*config)), + WidgetConfig::Cpu(config) => Box::new(Cpu::from(*config)), WidgetConfig::Date(config) => Box::new(Date::from(config.clone())), WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(config)), WidgetConfig::Media(config) => Box::new(Media::from(*config)), From 8d5e40eb16de7c0b91fbf4acff2e72d5d1eea6c6 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 8 Oct 2024 16:12:49 -0700 Subject: [PATCH 45/86] chore(deps): bump eframe from 0.28 to 0.29 --- Cargo.lock | 1349 ++++++++++++++++-------------------- Cargo.toml | 4 +- komorebi-bar/Cargo.toml | 10 +- komorebi-gui/src/main.rs | 4 +- komorebi-themes/Cargo.toml | 5 +- komorebi-themes/src/lib.rs | 56 +- 6 files changed, 622 insertions(+), 806 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 883566598..086cea6f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.28" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb" +checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -20,76 +20,91 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "accesskit" -version = "0.12.3" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b76d84ee70e30a4a7e39ab9018e2b17a6a09e31084176cc7c0b2dec036ba45" + +[[package]] +name = "accesskit_atspi_common" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a4b14f3d99c1255dcba8f45621ab1a2e7540a0009652d33989005a4d0bfc6b" +checksum = "f5393c75d4666f580f4cac0a968bc97c36076bb536a129f28210dac54ee127ed" dependencies = [ - "enumn", + "accesskit", + "accesskit_consumer", + "atspi-common", "serde", + "thiserror", + "zvariant", ] [[package]] name = "accesskit_consumer" -version = "0.16.1" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c17cca53c09fbd7288667b22a201274b9becaa27f0b91bf52a526db95de45e6" +checksum = "7a12dc159d52233c43d9fe5415969433cbdd52c3d6e0df51bda7d447427b9986" dependencies = [ "accesskit", + "immutable-chunkmap", ] [[package]] name = "accesskit_macos" -version = "0.10.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3b6ae1eabbfbced10e840fd3fce8a93ae84f174b3e4ba892ab7bcb42e477a7" +checksum = "49509c722e8da39e6c569f7d13ec51620208988913e738abbc67e3c65f06e6d5" dependencies = [ "accesskit", "accesskit_consumer", - "objc2 0.3.0-beta.3.patch-leaks.3", + "objc2", + "objc2-app-kit", + "objc2-foundation", "once_cell", ] [[package]] name = "accesskit_unix" -version = "0.6.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f46c18d99ba61ad7123dd13eeb0c104436ab6af1df6a1cd8c11054ed394a08" +checksum = "be7f5cf6165be10a54b2655fa2e0e12b2509f38ed6fc43e11c31fdb7ee6230bb" dependencies = [ "accesskit", - "accesskit_consumer", + "accesskit_atspi_common", "async-channel", - "async-once-cell", + "async-executor", + "async-task", "atspi", - "futures-lite 1.13.0", - "once_cell", + "futures-lite", + "futures-util", "serde", "zbus", ] [[package]] name = "accesskit_windows" -version = "0.15.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcae27ec0974fc7c3b0b318783be89fd1b2e66dd702179fe600166a38ff4a0b" +checksum = "974e96c347384d9133427167fb8a58c340cb0496988dacceebdc1ed27071023b" dependencies = [ "accesskit", "accesskit_consumer", - "once_cell", "paste", "static_assertions", - "windows 0.48.0", + "windows 0.58.0", + "windows-core 0.58.0", ] [[package]] name = "accesskit_winit" -version = "0.16.1" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5284218aca17d9e150164428a0ebc7b955f70e3a9a78b4c20894513aabf98a67" +checksum = "9987e852fe7e4e5a493f8c8af0b729b47da2750f0dea10a4c8984fe1117ebaec" dependencies = [ "accesskit", "accesskit_macos", "accesskit_unix", "accesskit_windows", + "raw-window-handle", "winit", ] @@ -123,7 +138,6 @@ dependencies = [ "cfg-if 1.0.0", "getrandom", "once_cell", - "serde", "version_check", "zerocopy", ] @@ -166,9 +180,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-activity" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", "bitflags 2.6.0", @@ -180,7 +194,7 @@ dependencies = [ "log", "ndk", "ndk-context", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", "thiserror", ] @@ -275,7 +289,7 @@ checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "log", - "objc2 0.5.2", + "objc2", "objc2-app-kit", "objc2-foundation", "parking_lot", @@ -313,21 +327,23 @@ checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" [[package]] name = "ash" -version = "0.37.3+1.3.251" +version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading 0.7.4", + "libloading", ] [[package]] name = "async-broadcast" -version = "0.5.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" dependencies = [ - "event-listener 2.5.3", + "event-listener", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] @@ -350,41 +366,20 @@ checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.1", - "futures-lite 2.3.0", + "fastrand", + "futures-lite", "slab", ] [[package]] name = "async-fs" -version = "1.6.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ - "async-lock 2.8.0", - "autocfg", + "async-lock", "blocking", - "futures-lite 1.13.0", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if 1.0.0", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", + "futures-lite", ] [[package]] @@ -393,60 +388,47 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ - "async-lock 3.4.0", + "async-lock", "cfg-if 1.0.0", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "parking", - "polling 3.7.3", - "rustix 0.38.37", + "polling", + "rustix", "slab", "tracing", "windows-sys 0.59.0", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.3.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] -[[package]] -name = "async-once-cell" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9338790e78aa95a416786ec8389546c4b6a1dfc3dc36071ed9518a9413a542eb" - [[package]] name = "async-process" -version = "1.8.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ - "async-io 1.13.0", - "async-lock 2.8.0", + "async-channel", + "async-io", + "async-lock", "async-signal", + "async-task", "blocking", "cfg-if 1.0.0", - "event-listener 3.1.0", - "futures-lite 1.13.0", - "rustix 0.38.37", - "windows-sys 0.48.0", + "event-listener", + "futures-lite", + "rustix", + "tracing", ] [[package]] @@ -466,13 +448,13 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io", + "async-lock", "atomic-waker", "cfg-if 1.0.0", "futures-core", "futures-io", - "rustix 0.38.37", + "rustix", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -503,9 +485,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atspi" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6059f350ab6f593ea00727b334265c4dfc7fd442ee32d264794bd9bdc68e87ca" +checksum = "be534b16650e35237bb1ed189ba2aab86ce65e88cc84c66f4935ba38575cecbf" dependencies = [ "atspi-common", "atspi-connection", @@ -514,39 +496,42 @@ dependencies = [ [[package]] name = "atspi-common" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92af95f966d2431f962bc632c2e68eda7777330158bf640c4af4249349b2cdf5" +checksum = "1909ed2dc01d0a17505d89311d192518507e8a056a48148e3598fef5e7bb6ba7" dependencies = [ "enumflags2", "serde", "static_assertions", "zbus", + "zbus-lockstep", + "zbus-lockstep-macros", "zbus_names", "zvariant", ] [[package]] name = "atspi-connection" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c65e7d70f86d4c0e3b2d585d9bf3f979f0b19d635a336725a88d279f76b939" +checksum = "430c5960624a4baaa511c9c0fcc2218e3b58f5dbcc47e6190cafee344b873333" dependencies = [ "atspi-common", "atspi-proxies", - "futures-lite 1.13.0", + "futures-lite", "zbus", ] [[package]] name = "atspi-proxies" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52" +checksum = "a5e6c5de3e524cf967569722446bcd458d5032348554d9a17d7d72b041ab7496" dependencies = [ "atspi-common", "serde", "zbus", + "zvariant", ] [[package]] @@ -605,7 +590,7 @@ dependencies = [ [[package]] name = "base16-egui-themes" version = "0.1.0" -source = "git+https://github.com/LGUG2Z/base16-egui-themes?rev=a2c48f45782c5604bf5482d3873021a9fe45ea1a#a2c48f45782c5604bf5482d3873021a9fe45ea1a" +source = "git+https://github.com/LGUG2Z/base16-egui-themes?rev=57c38257cb0c6434321320d3746049bd58c34674#57c38257cb0c6434321320d3746049bd58c34674" dependencies = [ "egui", "schemars", @@ -620,18 +605,18 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bit-set" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" [[package]] name = "bit_field" @@ -675,51 +660,13 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-sys" -version = "0.1.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" -dependencies = [ - "objc-sys 0.2.0-beta.2", -] - -[[package]] -name = "block-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" -dependencies = [ - "objc-sys 0.3.5", -] - -[[package]] -name = "block2" -version = "0.2.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" -dependencies = [ - "block-sys 0.1.0-beta.1", - "objc2-encode 2.0.0-pre.2", -] - -[[package]] -name = "block2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" -dependencies = [ - "block-sys 0.2.1", - "objc2 0.4.1", -] - [[package]] name = "block2" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2 0.5.2", + "objc2", ] [[package]] @@ -731,7 +678,7 @@ dependencies = [ "async-channel", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "piper", ] @@ -779,9 +726,9 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", @@ -806,20 +753,6 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" -[[package]] -name = "calloop" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" -dependencies = [ - "bitflags 2.6.0", - "log", - "polling 3.7.3", - "rustix 0.38.37", - "slab", - "thiserror", -] - [[package]] name = "calloop" version = "0.13.0" @@ -828,50 +761,37 @@ checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ "bitflags 2.6.0", "log", - "polling 3.7.3", - "rustix 0.38.37", + "polling", + "rustix", "slab", "thiserror", ] -[[package]] -name = "calloop-wayland-source" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" -dependencies = [ - "calloop 0.12.4", - "rustix 0.38.37", - "wayland-backend", - "wayland-client", -] - [[package]] name = "calloop-wayland-source" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ - "calloop 0.13.0", - "rustix 0.38.37", + "calloop", + "rustix", "wayland-backend", "wayland-client", ] [[package]] name = "catppuccin-egui" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b812fd8e72d65e1afefd7c96ca4c919fe4dc34d470aed2cf459acbcb1cd8f64e" +version = "5.3.0" +source = "git+https://github.com/LGUG2Z/catppuccin-egui?rev=f579847bf2f552b144361d5a78ed8cf360b55cbb#f579847bf2f552b144361d5a78ed8cf360b55cbb" dependencies = [ "egui", ] [[package]] name = "cc" -version = "1.1.22" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" dependencies = [ "jobserver", "libc", @@ -943,9 +863,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -953,15 +873,15 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", - "terminal_size", + "terminal_size 0.4.0", ] [[package]] @@ -1274,7 +1194,7 @@ version = "3.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" dependencies = [ - "nix 0.29.0", + "nix", "windows-sys 0.59.0", ] @@ -1293,17 +1213,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -1347,7 +1256,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.5", + "libloading", ] [[package]] @@ -1376,6 +1285,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + [[package]] name = "dunce" version = "1.0.5" @@ -1390,20 +1305,19 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecolor" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e6b451ff1143f6de0f33fc7f1b68fecfd2c7de06e104de96c4514de3f5396f8" +checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b" dependencies = [ "bytemuck", "emath", - "serde", ] [[package]] name = "eframe" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6490ef800b2e41ee129b1f32f9ac15f713233fe3bc18e241a1afe1e4fb6811e0" +checksum = "8ac2645a9bf4826eb4e91488b1f17b8eaddeef09396706b2f14066461338e24f" dependencies = [ "ahash", "bytemuck", @@ -1412,33 +1326,33 @@ dependencies = [ "egui-wgpu", "egui-winit", "egui_glow", - "glow", + "glow 0.14.1", "glutin", "glutin-winit", "image", "js-sys", "log", - "objc2 0.5.2", + "objc2", "objc2-app-kit", "objc2-foundation", "parking_lot", "percent-encoding", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", + "raw-window-handle", "static_assertions", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "web-time", "winapi", + "windows-sys 0.52.0", "winit", ] [[package]] name = "egui" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c97e70a2768de630f161bb5392cbd3874fcf72868f14df0e002e82e06cb798" +checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974" dependencies = [ "accesskit", "ahash", @@ -1446,23 +1360,22 @@ dependencies = [ "epaint", "log", "nohash-hasher", - "serde", ] [[package]] name = "egui-phosphor" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7198d3a35fbe756a3daa10a98942159f70dce10d5f2f9ccdb11d242d3bf2fa47" +checksum = "b3e0a31856effd375729ef9fc853a2a1091708552968d0fc979873b8a1be8ef1" dependencies = [ "egui", ] [[package]] name = "egui-wgpu" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c7a7c707877c3362a321ebb4f32be811c0b91f7aebf345fb162405c0218b4c" +checksum = "d00fd5d06d8405397e64a928fa0ef3934b3c30273ea7603e3dc4627b1f7a1a82" dependencies = [ "ahash", "bytemuck", @@ -1479,16 +1392,16 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4e066af341bf92559f60dbdf2020b2a03c963415349af5f3f8d79ff7a4926" +checksum = "0a9c430f4f816340e8e8c1b20eec274186b1be6bc4c7dfc467ed50d57abc36c6" dependencies = [ "accesskit_winit", "ahash", "arboard", "egui", "log", - "raw-window-handle 0.6.2", + "raw-window-handle", "smithay-clipboard", "web-time", "webbrowser", @@ -1497,30 +1410,29 @@ dependencies = [ [[package]] name = "egui_extras" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb783d9fa348f69ed5c340aa25af78b5472043090e8b809040e30960cc2a746" +checksum = "bf3c1f5cd8dfe2ade470a218696c66cf556fcfd701e7830fa2e9f4428292a2a1" dependencies = [ "ahash", "egui", "enum-map", "log", "mime_guess2", - "serde", ] [[package]] name = "egui_glow" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2bdc8b38cfa17cc712c4ae079e30c71c00cd4c2763c9e16dc7860a02769103" +checksum = "0e39bccc683cd43adab530d8f21a13eb91e80de10bcc38c3f1c16601b6f62b26" dependencies = [ "ahash", "bytemuck", "egui", - "glow", + "glow 0.14.1", "log", - "memoffset 0.9.1", + "memoffset", "wasm-bindgen", "web-sys", "winit", @@ -1534,12 +1446,11 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "emath" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6" +checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3" dependencies = [ "bytemuck", - "serde", ] [[package]] @@ -1551,6 +1462,12 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + [[package]] name = "enum-map" version = "2.7.3" @@ -1593,34 +1510,29 @@ dependencies = [ "syn 2.0.79", ] -[[package]] -name = "enumn" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "epaint" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f0dcc0a0771e7500e94cd1cb797bd13c9f23b9409bdc3c824e2cbc562b7fa01" +checksum = "a32af8da821bd4f43f2c137e295459ee2e1661d87ca8779dfa0eaf45d870e20f" dependencies = [ "ab_glyph", "ahash", "bytemuck", "ecolor", "emath", + "epaint_default_fonts", "log", "nohash-hasher", "parking_lot", - "serde", ] +[[package]] +name = "epaint_default_fonts" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483440db0b7993cf77a20314f08311dbe95675092405518c0677aa08c151a3ea" + [[package]] name = "equivalent" version = "1.0.1" @@ -1643,23 +1555,6 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - [[package]] name = "event-listener" version = "5.3.1" @@ -1677,7 +1572,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.1", + "event-listener", "pin-project-lite", ] @@ -1717,15 +1612,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.1.1" @@ -1888,9 +1774,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1898,64 +1784,61 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.13.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 1.9.0", + "fastrand", "futures-core", "futures-io", - "memchr", "parking", "pin-project-lite", - "waker-fn", ] [[package]] -name = "futures-lite" -version = "2.3.0" +name = "futures-macro" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "fastrand 2.1.1", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", + "proc-macro2", + "quote", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -2059,57 +1942,70 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glow" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4a888dbe8181a7535853469c21c67ca9a1cea9460b16808fc018ea9e55d248" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glutin" -version = "0.31.3" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" +checksum = "ec69412a0bf07ea7607e638b415447857a808846c2b685a43c8aa18bc6d5e499" dependencies = [ "bitflags 2.6.0", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "cgl", "core-foundation 0.9.4", "dispatch", "glutin_egl_sys", "glutin_glx_sys", "glutin_wgl_sys", - "icrate", - "libloading 0.8.5", - "objc2 0.4.1", + "libloading", + "objc2", + "objc2-app-kit", + "objc2-foundation", "once_cell", - "raw-window-handle 0.5.2", + "raw-window-handle", "wayland-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", ] [[package]] name = "glutin-winit" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" +checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" dependencies = [ - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "glutin", - "raw-window-handle 0.5.2", + "raw-window-handle", "winit", ] [[package]] name = "glutin_egl_sys" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" +checksum = "cae99fff4d2850dbe6fb8c1fa8e4fead5525bab715beaacfccf3fb994e01c827" dependencies = [ "gl_generator", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "glutin_glx_sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a165fd686c10dcc2d45380b35796e577eacfd43d4660ee741ec8ebe2201b3b4f" +checksum = "9c2b2d3918e76e18e08796b55eb64e8fe6ec67d5a6b2e2a7e2edce224ad24c63" dependencies = [ "gl_generator", "x11-dl", @@ -2117,9 +2013,9 @@ dependencies = [ [[package]] name = "glutin_wgl_sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +checksum = "0a4e1951bbd9434a81aa496fe59ccc2235af3820d27b85f9314e279609211e2c" dependencies = [ "gl_generator", ] @@ -2145,9 +2041,9 @@ dependencies = [ [[package]] name = "gpu-allocator" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" +checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7" dependencies = [ "log", "presser", @@ -2164,7 +2060,7 @@ checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" dependencies = [ "bitflags 2.6.0", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -2215,6 +2111,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "hassle-rs" version = "0.11.0" @@ -2224,7 +2126,7 @@ dependencies = [ "bitflags 2.6.0", "com", "libc", - "libloading 0.8.5", + "libloading", "thiserror", "widestring", "winapi", @@ -2327,9 +2229,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" @@ -2397,7 +2299,7 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", "tower-service", "tracing", @@ -2426,17 +2328,6 @@ dependencies = [ "cc", ] -[[package]] -name = "icrate" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" -dependencies = [ - "block2 0.3.0", - "dispatch", - "objc2 0.4.1", -] - [[package]] name = "idna" version = "0.5.0" @@ -2486,6 +2377,15 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" +[[package]] +name = "immutable-chunkmap" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4419f022e55cc63d5bbd6b44b71e1d226b9c9480a47824c706e9d54e5c40c5eb" +dependencies = [ + "arrayvec", +] + [[package]] name = "indenter" version = "0.3.3" @@ -2494,12 +2394,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.0", ] [[package]] @@ -2522,15 +2422,6 @@ dependencies = [ "libc", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "interpolate_name" version = "0.2.4" @@ -2542,22 +2433,11 @@ dependencies = [ "syn 2.0.79", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_ci" @@ -2645,7 +2525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.5", + "libloading", "pkg-config", ] @@ -2867,16 +2747,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if 1.0.0", - "winapi", -] - [[package]] name = "libloading" version = "0.8.5" @@ -2906,7 +2776,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.6", + "redox_syscall 0.5.7", ] [[package]] @@ -2921,12 +2791,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -3015,15 +2879,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.1" @@ -3035,9 +2890,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" dependencies = [ "bitflags 2.6.0", "block", @@ -3062,7 +2917,7 @@ dependencies = [ "supports-color", "supports-hyperlinks", "supports-unicode", - "terminal_size", + "terminal_size 0.3.0", "textwrap", "thiserror", "unicode-width", @@ -3155,18 +3010,18 @@ dependencies = [ [[package]] name = "naga" -version = "0.20.0" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad" dependencies = [ "arrayvec", "bit-set", "bitflags 2.6.0", + "cfg_aliases 0.1.1", "codespan-reporting", "hexf-parse", "indexmap", "log", - "num-traits", "rustc-hash", "spirv", "termcolor", @@ -3202,17 +3057,16 @@ dependencies = [ [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.6.0", "jni-sys", "log", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", + "raw-window-handle", "thiserror", ] @@ -3231,6 +3085,15 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + [[package]] name = "net2" version = "0.2.39" @@ -3313,18 +3176,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if 1.0.0", - "libc", - "memoffset 0.7.1", -] - [[package]] name = "nix" version = "0.29.0" @@ -3335,6 +3186,7 @@ dependencies = [ "cfg-if 1.0.0", "cfg_aliases 0.2.1", "libc", + "memoffset", ] [[package]] @@ -3515,7 +3367,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.79", @@ -3539,12 +3391,6 @@ dependencies = [ "malloc_buf", ] -[[package]] -name = "objc-sys" -version = "0.2.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" - [[package]] name = "objc-sys" version = "0.3.5" @@ -3553,49 +3399,52 @@ checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" -version = "0.3.0-beta.3.patch-leaks.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ - "block2 0.2.0-alpha.6", - "objc-sys 0.2.0-beta.2", - "objc2-encode 2.0.0-pre.2", + "objc-sys", + "objc2-encode", ] [[package]] -name = "objc2" -version = "0.4.1" +name = "objc2-app-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "objc-sys 0.3.5", - "objc2-encode 3.0.0", + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] -name = "objc2" -version = "0.5.2" +name = "objc2-cloud-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "objc-sys 0.3.5", - "objc2-encode 4.0.3", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] -name = "objc2-app-kit" +name = "objc2-contacts" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", - "objc2-core-data", - "objc2-core-image", + "block2", + "objc2", "objc2-foundation", - "objc2-quartz-core", ] [[package]] @@ -3605,8 +3454,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", + "block2", + "objc2", "objc2-foundation", ] @@ -3616,68 +3465,133 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", + "block2", + "objc2", "objc2-foundation", "objc2-metal", ] [[package]] -name = "objc2-encode" -version = "2.0.0-pre.2" +name = "objc2-core-location" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "objc-sys 0.2.0-beta.2", + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", ] [[package]] name = "objc2-encode" -version = "3.0.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" [[package]] -name = "objc2-encode" -version = "4.0.3" +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] [[package]] -name = "objc2-foundation" +name = "objc2-ui-kit" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.6.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", ] [[package]] -name = "objc2-metal" +name = "objc2-uniform-type-identifiers" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", + "block2", + "objc2", "objc2-foundation", ] [[package]] -name = "objc2-quartz-core" +name = "objc2-user-notifications" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", + "block2", + "objc2", + "objc2-core-location", "objc2-foundation", - "objc2-metal", ] [[package]] @@ -3691,9 +3605,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" @@ -3783,9 +3697,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owned_ttf_parser" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" dependencies = [ "ttf-parser", ] @@ -3828,7 +3742,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "petgraph", - "redox_syscall 0.5.6", + "redox_syscall 0.5.7", "smallvec", "thread-id", "windows-targets 0.52.6", @@ -3856,6 +3770,26 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pin-project" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -3875,7 +3809,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.1", + "fastrand", "futures-io", ] @@ -3911,22 +3845,6 @@ dependencies = [ "miniz_oxide 0.8.0", ] -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if 1.0.0", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - [[package]] name = "polling" version = "3.7.3" @@ -3937,7 +3855,7 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.37", + "rustix", "tracing", "windows-sys 0.59.0", ] @@ -3969,23 +3887,13 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit", ] [[package]] @@ -4012,9 +3920,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -4053,6 +3961,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick-xml" version = "0.32.0" @@ -4173,12 +4091,6 @@ dependencies = [ "rgb", ] -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -4205,15 +4117,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -4225,9 +4128,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -4245,14 +4148,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -4266,13 +4169,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4283,9 +4186,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "renderdoc-sys" @@ -4295,9 +4198,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64", "bytes", @@ -4373,20 +4276,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - [[package]] name = "rustix" version = "0.38.37" @@ -4396,15 +4285,15 @@ dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "once_cell", "rustls-pki-types", @@ -4415,11 +4304,10 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64", "rustls-pki-types", ] @@ -4463,9 +4351,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] @@ -4508,14 +4396,14 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.8.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" dependencies = [ "ab_glyph", "log", "memmap2", - "smithay-client-toolkit 0.18.1", + "smithay-client-toolkit", "tiny-skia", ] @@ -4675,9 +4563,9 @@ dependencies = [ [[package]] name = "shadow-rs" -version = "0.35.0" +version = "0.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca0e9bdc073d7173ba993fb7886477af5df75588b57afcb4b96f21911ab0bfa" +checksum = "2311e39772c00391875f40e34d43efef247b23930143a70ca5fbec9505937420" dependencies = [ "const_format", "git2", @@ -4755,31 +4643,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" -[[package]] -name = "smithay-client-toolkit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" -dependencies = [ - "bitflags 2.6.0", - "calloop 0.12.4", - "calloop-wayland-source 0.2.0", - "cursor-icon", - "libc", - "log", - "memmap2", - "rustix 0.38.37", - "thiserror", - "wayland-backend", - "wayland-client", - "wayland-csd-frame", - "wayland-cursor", - "wayland-protocols 0.31.2", - "wayland-protocols-wlr 0.2.0", - "wayland-scanner", - "xkeysym", -] - [[package]] name = "smithay-client-toolkit" version = "0.19.2" @@ -4787,20 +4650,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ "bitflags 2.6.0", - "calloop 0.13.0", - "calloop-wayland-source 0.3.0", + "calloop", + "calloop-wayland-source", "cursor-icon", "libc", "log", "memmap2", - "rustix 0.38.37", + "rustix", "thiserror", "wayland-backend", "wayland-client", "wayland-csd-frame", "wayland-cursor", - "wayland-protocols 0.32.4", - "wayland-protocols-wlr 0.3.4", + "wayland-protocols", + "wayland-protocols-wlr", "wayland-scanner", "xkeysym", ] @@ -4812,7 +4675,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" dependencies = [ "libc", - "smithay-client-toolkit 0.19.2", + "smithay-client-toolkit", "wayland-backend", ] @@ -4825,16 +4688,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -4874,7 +4727,7 @@ dependencies = [ "lazycell", "libc", "mach2", - "nix 0.29.0", + "nix", "num-traits", "plist", "uom", @@ -5040,9 +4893,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if 1.0.0", - "fastrand 2.1.1", + "fastrand", "once_cell", - "rustix 0.38.37", + "rustix", "windows-sys 0.59.0", ] @@ -5061,10 +4914,20 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.37", + "rustix", "windows-sys 0.48.0", ] +[[package]] +name = "terminal_size" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +dependencies = [ + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "textwrap" version = "0.16.1" @@ -5211,7 +5074,7 @@ dependencies = [ "libc", "mio 1.0.2", "pin-project-lite", - "socket2 0.5.7", + "socket2", "windows-sys 0.52.0", ] @@ -5258,7 +5121,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit", ] [[package]] @@ -5270,17 +5133,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.22" @@ -5291,7 +5143,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow", ] [[package]] @@ -5391,9 +5243,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttf-parser" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" +checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" [[package]] name = "type-map" @@ -5445,7 +5297,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ - "memoffset 0.9.1", + "memoffset", "tempfile", "winapi", ] @@ -5461,9 +5313,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" @@ -5578,12 +5430,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -5684,7 +5530,7 @@ checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.37", + "rustix", "scoped-tls", "smallvec", "wayland-sys", @@ -5697,7 +5543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d" dependencies = [ "bitflags 2.6.0", - "rustix 0.38.37", + "rustix", "wayland-backend", "wayland-scanner", ] @@ -5719,23 +5565,11 @@ version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a94697e66e76c85923b0d28a0c251e8f0666f58fc47d316c0f4da6da75d37cb" dependencies = [ - "rustix 0.38.37", + "rustix", "wayland-client", "xcursor", ] -[[package]] -name = "wayland-protocols" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" -dependencies = [ - "bitflags 2.6.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - [[package]] name = "wayland-protocols" version = "0.32.4" @@ -5750,27 +5584,14 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" -dependencies = [ - "bitflags 2.6.0", - "wayland-backend", - "wayland-client", - "wayland-protocols 0.31.2", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.2.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +checksum = "8a0a41a6875e585172495f7a96dfa42ca7e0213868f4f15c313f7c33221a7eff" dependencies = [ "bitflags 2.6.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.31.2", + "wayland-protocols", "wayland-scanner", ] @@ -5783,7 +5604,7 @@ dependencies = [ "bitflags 2.6.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.4", + "wayland-protocols", "wayland-scanner", ] @@ -5822,9 +5643,9 @@ dependencies = [ [[package]] name = "web-time" -version = "0.2.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -5836,13 +5657,13 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e5f07fb9bc8de2ddfe6b24a71a75430673fd679e568c48b52716cef1cfae923" dependencies = [ - "block2 0.5.1", + "block2", "core-foundation 0.10.0", "home", "jni", "log", "ndk-context", - "objc2 0.5.2", + "objc2", "objc2-foundation", "url", "web-sys", @@ -5856,19 +5677,18 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "wgpu" -version = "0.20.1" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e37c7b9921b75dfd26dd973fdcbce36f13dfa6e2dc82aece584e0ed48c355c" +checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433" dependencies = [ "arrayvec", - "cfg-if 1.0.0", "cfg_aliases 0.1.1", "document-features", "js-sys", "log", "parking_lot", "profiling", - "raw-window-handle 0.6.2", + "raw-window-handle", "smallvec", "static_assertions", "wasm-bindgen", @@ -5881,15 +5701,14 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.21.1" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50819ab545b867d8a454d1d756b90cd5f15da1f2943334ca314af10583c9d39" +checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a" dependencies = [ "arrayvec", "bit-vec", "bitflags 2.6.0", "cfg_aliases 0.1.1", - "codespan-reporting", "document-features", "indexmap", "log", @@ -5897,20 +5716,19 @@ dependencies = [ "once_cell", "parking_lot", "profiling", - "raw-window-handle 0.6.2", + "raw-window-handle", "rustc-hash", "smallvec", "thiserror", - "web-sys", "wgpu-hal", "wgpu-types", ] [[package]] name = "wgpu-hal" -version = "0.21.1" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172e490a87295564f3fcc0f165798d87386f6231b04d4548bca458cbbfd63222" +checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f" dependencies = [ "android_system_properties", "arrayvec", @@ -5918,7 +5736,7 @@ dependencies = [ "bitflags 2.6.0", "cfg_aliases 0.1.1", "core-graphics-types", - "glow", + "glow 0.13.1", "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", @@ -5927,16 +5745,16 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.5", + "libloading", "log", "metal", "naga", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", "parking_lot", "profiling", - "raw-window-handle 0.6.2", + "raw-window-handle", "renderdoc-sys", "rustc-hash", "smallvec", @@ -5949,9 +5767,9 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.20.0" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" +checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d" dependencies = [ "bitflags 2.6.0", "js-sys", @@ -5966,7 +5784,7 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", - "rustix 0.38.37", + "rustix", "winsafe", ] @@ -6017,17 +5835,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-implement 0.48.0", - "windows-interface 0.48.0", - "windows-targets 0.48.5", -] - [[package]] name = "windows" version = "0.52.0" @@ -6103,17 +5910,6 @@ dependencies = [ "windows 0.58.0", ] -[[package]] -name = "windows-implement" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "windows-implement" version = "0.57.0" @@ -6136,17 +5932,6 @@ dependencies = [ "syn 2.0.79", ] -[[package]] -name = "windows-interface" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "windows-interface" version = "0.57.0" @@ -6424,62 +6209,56 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.29.15" +version = "0.30.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67" dependencies = [ "ahash", "android-activity", "atomic-waker", "bitflags 2.6.0", + "block2", "bytemuck", - "calloop 0.12.4", - "cfg_aliases 0.1.1", + "calloop", + "cfg_aliases 0.2.1", + "concurrent-queue", "core-foundation 0.9.4", "core-graphics 0.23.2", "cursor-icon", - "icrate", + "dpi", "js-sys", "libc", - "log", "memmap2", "ndk", - "ndk-sys", - "objc2 0.4.1", - "once_cell", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", "orbclient", "percent-encoding", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", - "redox_syscall 0.3.5", - "rustix 0.38.37", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix", "sctk-adwaita", - "smithay-client-toolkit 0.18.1", + "smithay-client-toolkit", "smol_str", + "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", "wayland-backend", "wayland-client", - "wayland-protocols 0.31.2", + "wayland-protocols", "wayland-protocols-plasma", "web-sys", "web-time", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", "x11rb", "xkbcommon-dl", ] -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.6.20" @@ -6534,9 +6313,9 @@ dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading 0.8.5", + "libloading", "once_cell", - "rustix 0.38.37", + "rustix", "x11rb-protocol", ] @@ -6589,30 +6368,27 @@ checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "zbus" -version = "3.15.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" dependencies = [ "async-broadcast", "async-executor", "async-fs", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "async-process", "async-recursion", "async-task", "async-trait", "blocking", - "byteorder", - "derivative", "enumflags2", - "event-listener 2.5.3", + "event-listener", "futures-core", "futures-sink", "futures-util", "hex", - "nix 0.26.4", - "once_cell", + "nix", "ordered-stream", "rand", "serde", @@ -6621,38 +6397,74 @@ dependencies = [ "static_assertions", "tracing", "uds_windows", - "winapi", + "windows-sys 0.52.0", "xdg-home", "zbus_macros", "zbus_names", "zvariant", ] +[[package]] +name = "zbus-lockstep" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca2c5dceb099bddaade154055c926bb8ae507a18756ba1d8963fd7b51d8ed1d" +dependencies = [ + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus-lockstep-macros" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", + "zbus-lockstep", + "zbus_xml", + "zvariant", +] + [[package]] name = "zbus_macros" -version = "3.15.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate", "proc-macro2", "quote", - "regex", - "syn 1.0.109", + "syn 2.0.79", "zvariant_utils", ] [[package]] name = "zbus_names" -version = "2.6.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", "zvariant", ] +[[package]] +name = "zbus_xml" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f374552b954f6abb4bd6ce979e6c9b38fb9d0cd7cc68a7d796e70c9f3a233" +dependencies = [ + "quick-xml 0.30.0", + "serde", + "static_assertions", + "zbus_names", + "zvariant", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -6706,13 +6518,12 @@ dependencies = [ [[package]] name = "zvariant" -version = "3.15.2" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" dependencies = [ - "byteorder", + "endi", "enumflags2", - "libc", "serde", "static_assertions", "zvariant_derive", @@ -6720,24 +6531,24 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "3.15.2" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.79", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "1.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.79", ] diff --git a/Cargo.toml b/Cargo.toml index 761f1cb57..75c57424f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ chrono = "0.4" crossbeam-channel = "0.5" crossbeam-utils = "0.8" color-eyre = "0.6" -eframe = "0.28" -egui_extras = "0.28" +eframe = "0.29" +egui_extras = "0.29" dirs = "5" dunce = "1" hotwatch = "0.5" diff --git a/komorebi-bar/Cargo.toml b/komorebi-bar/Cargo.toml index 802e79fc6..0b8622159 100644 --- a/komorebi-bar/Cargo.toml +++ b/komorebi-bar/Cargo.toml @@ -16,15 +16,15 @@ crossbeam-channel = { workspace = true } dirs = { workspace = true } dunce = { workspace = true } eframe = { workspace = true } -egui-phosphor = "0.6.0" +egui-phosphor = "0.7" font-loader = "0.11" hotwatch = { workspace = true } image = "0.25" netdev = "0.31" -num = "0.4.3" -num-derive = "0.4.2" -num-traits = "0.2.19" -random_word = { version = "0.4.3", features = ["en"] } +num = "0.4" +num-derive = "0.4" +num-traits = "0.2" +random_word = { version = "0.4", features = ["en"] } schemars = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/komorebi-gui/src/main.rs b/komorebi-gui/src/main.rs index 061717e20..a2681928b 100644 --- a/komorebi-gui/src/main.rs +++ b/komorebi-gui/src/main.rs @@ -27,7 +27,6 @@ fn main() { viewport: ViewportBuilder::default() .with_always_on_top() .with_inner_size([320.0, 500.0]), - follow_system_theme: true, ..Default::default() }; @@ -234,7 +233,8 @@ extern "system" fn enum_window( fn json_view_ui(ui: &mut egui::Ui, code: &str) { let language = "json"; - let theme = egui_extras::syntax_highlighting::CodeTheme::from_memory(ui.ctx()); + let theme = + egui_extras::syntax_highlighting::CodeTheme::from_memory(ui.ctx(), &ui.ctx().style()); egui_extras::syntax_highlighting::code_view_ui(ui, &theme, code, language); } diff --git a/komorebi-themes/Cargo.toml b/komorebi-themes/Cargo.toml index 9de14b9ab..73ff9842a 100644 --- a/komorebi-themes/Cargo.toml +++ b/komorebi-themes/Cargo.toml @@ -4,8 +4,9 @@ version = "0.1.30" edition = "2021" [dependencies] -base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "a2c48f45782c5604bf5482d3873021a9fe45ea1a" } -catppuccin-egui = { version = "5.1", default-features = false, features = ["egui28"] } +base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "57c38257cb0c6434321320d3746049bd58c34674" } +catppuccin-egui = { git = "https://github.com/LGUG2Z/catppuccin-egui", rev = "f579847bf2f552b144361d5a78ed8cf360b55cbb" } +#catppuccin-egui = { version = "5", default-features = false, features = ["egui28"] } eframe = { workspace = true } schemars = { workspace = true } serde = { workspace = true } diff --git a/komorebi-themes/src/lib.rs b/komorebi-themes/src/lib.rs index f87fef991..f8a20bb62 100644 --- a/komorebi-themes/src/lib.rs +++ b/komorebi-themes/src/lib.rs @@ -124,35 +124,39 @@ pub enum CatppuccinValue { Crust, } +pub fn color32_compat(rgba: [u8; 4]) -> Color32 { + Color32::from_rgba_unmultiplied(rgba[0], rgba[1], rgba[2], rgba[3]) +} + impl CatppuccinValue { pub fn color32(&self, theme: catppuccin_egui::Theme) -> Color32 { match self { - CatppuccinValue::Rosewater => theme.rosewater, - CatppuccinValue::Flamingo => theme.flamingo, - CatppuccinValue::Pink => theme.pink, - CatppuccinValue::Mauve => theme.mauve, - CatppuccinValue::Red => theme.red, - CatppuccinValue::Maroon => theme.maroon, - CatppuccinValue::Peach => theme.peach, - CatppuccinValue::Yellow => theme.yellow, - CatppuccinValue::Green => theme.green, - CatppuccinValue::Teal => theme.teal, - CatppuccinValue::Sky => theme.sky, - CatppuccinValue::Sapphire => theme.sapphire, - CatppuccinValue::Blue => theme.blue, - CatppuccinValue::Lavender => theme.lavender, - CatppuccinValue::Text => theme.text, - CatppuccinValue::Subtext1 => theme.subtext1, - CatppuccinValue::Subtext0 => theme.subtext0, - CatppuccinValue::Overlay2 => theme.overlay2, - CatppuccinValue::Overlay1 => theme.overlay1, - CatppuccinValue::Overlay0 => theme.overlay0, - CatppuccinValue::Surface2 => theme.surface2, - CatppuccinValue::Surface1 => theme.surface1, - CatppuccinValue::Surface0 => theme.surface0, - CatppuccinValue::Base => theme.base, - CatppuccinValue::Mantle => theme.mantle, - CatppuccinValue::Crust => theme.crust, + CatppuccinValue::Rosewater => color32_compat(theme.rosewater.to_srgba_unmultiplied()), + CatppuccinValue::Flamingo => color32_compat(theme.flamingo.to_srgba_unmultiplied()), + CatppuccinValue::Pink => color32_compat(theme.pink.to_srgba_unmultiplied()), + CatppuccinValue::Mauve => color32_compat(theme.mauve.to_srgba_unmultiplied()), + CatppuccinValue::Red => color32_compat(theme.red.to_srgba_unmultiplied()), + CatppuccinValue::Maroon => color32_compat(theme.maroon.to_srgba_unmultiplied()), + CatppuccinValue::Peach => color32_compat(theme.peach.to_srgba_unmultiplied()), + CatppuccinValue::Yellow => color32_compat(theme.yellow.to_srgba_unmultiplied()), + CatppuccinValue::Green => color32_compat(theme.green.to_srgba_unmultiplied()), + CatppuccinValue::Teal => color32_compat(theme.teal.to_srgba_unmultiplied()), + CatppuccinValue::Sky => color32_compat(theme.sky.to_srgba_unmultiplied()), + CatppuccinValue::Sapphire => color32_compat(theme.sapphire.to_srgba_unmultiplied()), + CatppuccinValue::Blue => color32_compat(theme.blue.to_srgba_unmultiplied()), + CatppuccinValue::Lavender => color32_compat(theme.lavender.to_srgba_unmultiplied()), + CatppuccinValue::Text => color32_compat(theme.text.to_srgba_unmultiplied()), + CatppuccinValue::Subtext1 => color32_compat(theme.subtext1.to_srgba_unmultiplied()), + CatppuccinValue::Subtext0 => color32_compat(theme.subtext0.to_srgba_unmultiplied()), + CatppuccinValue::Overlay2 => color32_compat(theme.overlay2.to_srgba_unmultiplied()), + CatppuccinValue::Overlay1 => color32_compat(theme.overlay1.to_srgba_unmultiplied()), + CatppuccinValue::Overlay0 => color32_compat(theme.overlay0.to_srgba_unmultiplied()), + CatppuccinValue::Surface2 => color32_compat(theme.surface2.to_srgba_unmultiplied()), + CatppuccinValue::Surface1 => color32_compat(theme.surface1.to_srgba_unmultiplied()), + CatppuccinValue::Surface0 => color32_compat(theme.surface0.to_srgba_unmultiplied()), + CatppuccinValue::Base => color32_compat(theme.base.to_srgba_unmultiplied()), + CatppuccinValue::Mantle => color32_compat(theme.mantle.to_srgba_unmultiplied()), + CatppuccinValue::Crust => color32_compat(theme.crust.to_srgba_unmultiplied()), } } } From 30e09d99464f9e1662912086de048abb8daa4164 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 8 Oct 2024 16:29:17 -0700 Subject: [PATCH 46/86] feat(wm): delete stale sub socket files --- komorebi/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index f2758daca..db019c340 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -316,6 +316,13 @@ pub fn notify_subscribers(notification: &str) -> Result<()> { for socket in stale_sockets { tracing::warn!("removing stale subscription: {socket}"); sockets.remove(&socket); + let socket_path = DATA_DIR.join(socket); + if let Err(error) = std::fs::remove_file(&socket_path) { + tracing::error!( + "could not remove stale subscriber socket file at {}: {error}", + socket_path.display() + ) + } } let mut stale_pipes = vec![]; From 8752bbbaf1eac5cdbffc974342f4bf7387389f09 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 9 Oct 2024 15:06:48 -0700 Subject: [PATCH 47/86] feat(bar): add more logging around error paths --- komorebi-bar/src/komorebi.rs | 161 +++++++++++++++++++---------------- komorebi-bar/src/main.rs | 25 +++--- 2 files changed, 101 insertions(+), 85 deletions(-) diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index 4c60e05a3..1d6040f01 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -5,6 +5,7 @@ use crate::widget::BarWidget; use crate::MAX_LABEL_WIDTH; use crate::WIDGET_SPACING; use crossbeam_channel::Receiver; +use crossbeam_channel::TryRecvError; use eframe::egui::text::LayoutJob; use eframe::egui::Color32; use eframe::egui::ColorImage; @@ -437,93 +438,105 @@ impl KomorebiNotificationState { rx_gui: Receiver, bg_color: Rc>, ) { - if let Ok(notification) = rx_gui.try_recv() { - if let NotificationEvent::Socket(SocketMessage::ReloadStaticConfiguration(path)) = - notification.event - { - if let Ok(config) = komorebi_client::StaticConfig::read(&path) { - if let Some(theme) = config.theme { - apply_theme(ctx, KomobarTheme::from(theme), bg_color); - tracing::info!("applied theme from updated komorebi.json"); + match rx_gui.try_recv() { + Err(error) => match error { + TryRecvError::Empty => {} + TryRecvError::Disconnected => { + tracing::error!( + "failed to receive komorebi notification on gui thread: {error}" + ); + } + }, + Ok(notification) => { + if let NotificationEvent::Socket(SocketMessage::ReloadStaticConfiguration(path)) = + notification.event + { + if let Ok(config) = komorebi_client::StaticConfig::read(&path) { + if let Some(theme) = config.theme { + apply_theme(ctx, KomobarTheme::from(theme), bg_color); + tracing::info!("applied theme from updated komorebi.json"); + } } } - } - self.mouse_follows_focus = notification.state.mouse_follows_focus; + self.mouse_follows_focus = notification.state.mouse_follows_focus; - let monitor = ¬ification.state.monitors.elements()[monitor_index]; - self.work_area_offset = - notification.state.monitors.elements()[monitor_index].work_area_offset(); + let monitor = ¬ification.state.monitors.elements()[monitor_index]; + self.work_area_offset = + notification.state.monitors.elements()[monitor_index].work_area_offset(); - let focused_workspace_idx = monitor.focused_workspace_idx(); + let focused_workspace_idx = monitor.focused_workspace_idx(); - let mut workspaces = vec![]; - self.selected_workspace = monitor.workspaces()[focused_workspace_idx] - .name() - .to_owned() - .unwrap_or_else(|| format!("{}", focused_workspace_idx + 1)); + let mut workspaces = vec![]; + self.selected_workspace = monitor.workspaces()[focused_workspace_idx] + .name() + .to_owned() + .unwrap_or_else(|| format!("{}", focused_workspace_idx + 1)); - for (i, ws) in monitor.workspaces().iter().enumerate() { - let should_add = if self.hide_empty_workspaces { - focused_workspace_idx == i || !ws.containers().is_empty() - } else { - true - }; + for (i, ws) in monitor.workspaces().iter().enumerate() { + let should_add = if self.hide_empty_workspaces { + focused_workspace_idx == i || !ws.containers().is_empty() + } else { + true + }; - if should_add { - workspaces.push(ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1))); + if should_add { + workspaces + .push(ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1))); + } } - } - self.workspaces = workspaces; - self.layout = match monitor.workspaces()[focused_workspace_idx].layout() { - komorebi_client::Layout::Default(layout) => KomorebiLayout::Default(*layout), - komorebi_client::Layout::Custom(_) => KomorebiLayout::Custom, - }; + self.workspaces = workspaces; + self.layout = match monitor.workspaces()[focused_workspace_idx].layout() { + komorebi_client::Layout::Default(layout) => KomorebiLayout::Default(*layout), + komorebi_client::Layout::Custom(_) => KomorebiLayout::Custom, + }; - if !*monitor.workspaces()[focused_workspace_idx].tile() { - self.layout = KomorebiLayout::Floating; - } + if !*monitor.workspaces()[focused_workspace_idx].tile() { + self.layout = KomorebiLayout::Floating; + } - if notification.state.is_paused { - self.layout = KomorebiLayout::Paused; - } + if notification.state.is_paused { + self.layout = KomorebiLayout::Paused; + } - if let Some(container) = monitor.workspaces()[focused_workspace_idx].monocle_container() - { - self.focused_container_information = ( - container - .windows() - .iter() - .map(|w| w.title().unwrap_or_default()) - .collect::>(), - container - .windows() - .iter() - .map(|w| windows_icons::get_icon_by_process_id(w.process_id())) - .collect::>(), - container.focused_window_idx(), - ); - } else if let Some(container) = - monitor.workspaces()[focused_workspace_idx].focused_container() - { - self.focused_container_information = ( - container - .windows() - .iter() - .map(|w| w.title().unwrap_or_default()) - .collect::>(), - container - .windows() - .iter() - .map(|w| windows_icons::get_icon_by_process_id(w.process_id())) - .collect::>(), - container.focused_window_idx(), - ); - } else { - self.focused_container_information.0.clear(); - self.focused_container_information.1.clear(); - self.focused_container_information.2 = 0; + if let Some(container) = + monitor.workspaces()[focused_workspace_idx].monocle_container() + { + self.focused_container_information = ( + container + .windows() + .iter() + .map(|w| w.title().unwrap_or_default()) + .collect::>(), + container + .windows() + .iter() + .map(|w| windows_icons::get_icon_by_process_id(w.process_id())) + .collect::>(), + container.focused_window_idx(), + ); + } else if let Some(container) = + monitor.workspaces()[focused_workspace_idx].focused_container() + { + self.focused_container_information = ( + container + .windows() + .iter() + .map(|w| w.title().unwrap_or_default()) + .collect::>(), + container + .windows() + .iter() + .map(|w| windows_icons::get_icon_by_process_id(w.process_id())) + .collect::>(), + container.focused_window_idx(), + ); + } else { + self.focused_container_information.0.clear(); + self.focused_container_information.1.clear(); + self.focused_container_information.2 = 0; + } } } } diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index d3d7033c5..da2b87ea5 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -1,7 +1,7 @@ mod bar; -mod cpu; mod battery; mod config; +mod cpu; mod date; mod komorebi; mod media; @@ -370,18 +370,21 @@ fn main() -> color_eyre::Result<()> { match String::from_utf8(buffer) { Ok(notification_string) => { - if let Ok(notification) = - serde_json::from_str::( - ¬ification_string, - ) - { - tracing::debug!("received notification from komorebi"); + match serde_json::from_str::( + ¬ification_string, + ) { + Ok(notification) => { + tracing::debug!("received notification from komorebi"); - if let Err(error) = tx_gui.send(notification) { - tracing::error!("could not send komorebi notification update to gui: {error}") - } + if let Err(error) = tx_gui.send(notification) { + tracing::error!("could not send komorebi notification update to gui thread: {error}") + } - ctx_komorebi.request_repaint(); + ctx_komorebi.request_repaint(); + } + Err(error) => { + tracing::error!("could not deserialize komorebi notification: {error}"); + } } } Err(error) => { From dc6e326e69308278c55ae6c0fdc4fcfc781392d1 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 9 Oct 2024 19:23:13 -0700 Subject: [PATCH 48/86] chore(deps): cargo update --- Cargo.lock | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 086cea6f7..8d52e1877 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1326,7 +1326,7 @@ dependencies = [ "egui-wgpu", "egui-winit", "egui_glow", - "glow 0.14.1", + "glow 0.14.2", "glutin", "glutin-winit", "image", @@ -1364,9 +1364,9 @@ dependencies = [ [[package]] name = "egui-phosphor" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e0a31856effd375729ef9fc853a2a1091708552968d0fc979873b8a1be8ef1" +checksum = "134c93958b82a3b486b1992636c44e585b8f22bdab845b7bf6fad69dc9b733a2" dependencies = [ "egui", ] @@ -1430,7 +1430,7 @@ dependencies = [ "ahash", "bytemuck", "egui", - "glow 0.14.1", + "glow 0.14.2", "log", "memoffset", "wasm-bindgen", @@ -1944,9 +1944,9 @@ dependencies = [ [[package]] name = "glow" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4a888dbe8181a7535853469c21c67ca9a1cea9460b16808fc018ea9e55d248" +checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483" dependencies = [ "js-sys", "slotmap", @@ -2511,9 +2511,9 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "0cb94a0ffd3f3ee755c20f7d8752f45cac88605a4dcf808abcff72873296ec7b" dependencies = [ "wasm-bindgen", ] @@ -5457,9 +5457,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "ef073ced962d62984fb38a36e5fdc1a2b23c9e0e1fa0689bb97afa4202ef6887" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -5468,9 +5468,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "c4bfab14ef75323f4eb75fa52ee0a3fb59611977fd3240da19b2cf36ff85030e" dependencies = [ "bumpalo", "log", @@ -5483,9 +5483,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "65471f79c1022ffa5291d33520cbbb53b7687b01c2f8e83b57d102eed7ed479d" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -5495,9 +5495,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "a7bec9830f60924d9ceb3ef99d55c155be8afa76954edffbb5936ff4509474e7" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5505,9 +5505,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "4c74f6e152a76a2ad448e223b0fc0b6b5747649c3d769cc6bf45737bf97d0ed6" dependencies = [ "proc-macro2", "quote", @@ -5518,9 +5518,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "a42f6c679374623f295a8623adfe63d9284091245c3504bde47c17a3ce2777d9" [[package]] name = "wayland-backend" @@ -5633,9 +5633,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "44188d185b5bdcae1052d08bcbcf9091a5524038d4572cc4f4f2bb9d5554ddd9" dependencies = [ "js-sys", "wasm-bindgen", From 24da24f177a202bdab887153c19e2b1f5ac08ca7 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 9 Oct 2024 20:13:27 -0700 Subject: [PATCH 49/86] docs(github): update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 52 -------------------- .github/ISSUE_TEMPLATE/bug_report.yml | 55 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 -------- .github/ISSUE_TEMPLATE/feature_request.yml | 18 +++++++ 5 files changed, 78 insertions(+), 72 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index a86e04fb9..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "[BUG]: Short descriptive title" -labels: bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See bug - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots and Videos** -Add screenshots and videos to help explain your problem. - -**Operating System** -Provide the output of `systeminfo | grep "^OS Name\|^OS Version"` - -For example: -``` -OS Name: Microsoft Windows 11 Pro -OS Version: 10.0.22000 N/A Build 22000 -``` - -**`komorebic check` Output** -Provide the output of `komorebic check` - -For example: -``` -No KOMOREBI_CONFIG_HOME detected, defaulting to C:\Users\LGUG2Z - -Looking for configuration files in C:\Users\LGUG2Z - -No komorebi configuration found in C:\Users\LGUG2Z - -If running 'komorebic start --await-configuration', you will manually have to call the following command to begin tiling: komorebic complete-configuration -``` - -**Additional context** -Add any other context about the problem here. - -In particular, if you have any other AHK scripts or software running that handle any aspect of window management or manipulation diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..ce2504003 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,55 @@ +name: Bug report +description: File a bug report +labels: [ bug ] +body: + - type: textarea + validations: + required: true + attributes: + label: Summary + description: > + Please provide a short summary of the bug, along with any information + you feel is relevant to replicating the bug. + + You may include screenshots and videos in this section. + - type: textarea + validations: + required: true + attributes: + label: Version Information + description: > + Please provide information about the versions of Windows and komorebi + running on your machine. + + Do not submit a bug if you are not using an official version of Windows + such as AtlasOS; only official versions of Windows are supported. + + ``` + systeminfo | findstr /B /C:"OS Name" /B /C:"OS Version" + ``` + + ``` + komorebic --version + ``` + - type: textarea + validations: + required: true + attributes: + label: Komorebi Configuration + description: > + Please provide your configuration file (komorebi.json or komorebi.bar.json) + render: json + - type: textarea + validations: + required: true + attributes: + label: Hotkey Configuration + description: > + Please provide your whkdrc or komorebi.ahk hotkey configuration file + - type: textarea + validations: + required: true + attributes: + label: Output of komorebic check + description: > + Please provide the output of `komorebic check` diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..7350ba88a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Komorebi Documentation + url: https://lgug2z.github.io/komorebi/ + about: Please search the documentation website before opening an issue \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 91c5647cf..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: "[FEAT]: Short descriptive title" -labels: enhancement -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..ac488f4e2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,18 @@ +name: Feature request +description: Suggest an improvement +labels: [ enhancement ] +body: + - type: textarea + validations: + required: true + attributes: + label: Suggestion + description: > + Please share your suggestion here. Be sure to include all necessary context. + - type: textarea + validations: + required: true + attributes: + label: Alternatives Considered + description: > + Please share share alternatives you have considered here. From 26a8912fc3d99ef39278a808dbc621515aee586c Mon Sep 17 00:00:00 2001 From: Csaba Date: Thu, 10 Oct 2024 00:23:01 +0200 Subject: [PATCH 50/86] feat(bar): add label prefix config opt This commit makes the label prefix configurable. Users can select if they want to show an icon, only text, or both text and an icon. --- komorebi-bar/src/battery.rs | 27 ++++- komorebi-bar/src/config.rs | 12 +++ komorebi-bar/src/cpu.rs | 17 +++- komorebi-bar/src/date.rs | 18 +++- komorebi-bar/src/memory.rs | 19 +++- komorebi-bar/src/network.rs | 190 ++++++++++++++++++++++++++++++------ komorebi-bar/src/storage.rs | 25 +++-- komorebi-bar/src/time.rs | 18 +++- 8 files changed, 276 insertions(+), 50 deletions(-) diff --git a/komorebi-bar/src/battery.rs b/komorebi-bar/src/battery.rs index 1b1517e07..0925b109e 100644 --- a/komorebi-bar/src/battery.rs +++ b/komorebi-bar/src/battery.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -23,6 +24,8 @@ pub struct BatteryConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Battery { @@ -30,6 +33,7 @@ impl From for Battery { let manager = Manager::new().unwrap(); let mut last_state = String::new(); let mut state = None; + let prefix = value.label_prefix.unwrap_or(LabelPrefix::Icon); if let Ok(mut batteries) = manager.batteries() { if let Some(Ok(first)) = batteries.nth(0) { @@ -39,8 +43,13 @@ impl From for Battery { State::Discharging => state = Some(BatteryState::Discharging), _ => {} } - - last_state = format!("{percentage}%"); + + last_state = match prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("BAT: {percentage:.0}%") + } + LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"), + } } } @@ -49,6 +58,7 @@ impl From for Battery { manager, last_state, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: prefix, state: state.unwrap_or(BatteryState::Discharging), last_updated: Instant::now(), } @@ -65,6 +75,7 @@ pub struct Battery { manager: Manager, pub state: BatteryState, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_state: String, last_updated: Instant, } @@ -86,7 +97,12 @@ impl Battery { _ => {} } - output = format!("{percentage:.0}%"); + output = match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("BAT: {percentage:.0}%") + } + LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"), + } } } @@ -116,7 +132,10 @@ impl BarWidget for Battery { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - emoji.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => emoji.to_string(), + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index 8d59f6fbf..cf18b707c 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -164,3 +164,15 @@ impl From for KomobarTheme { } } } + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub enum LabelPrefix { + /// Show no prefix + None, + /// Show an icon + Icon, + /// Show text + Text, + /// Show an icon and text + IconAndText, +} diff --git a/komorebi-bar/src/cpu.rs b/komorebi-bar/src/cpu.rs index 58f77db94..aedb6b067 100644 --- a/komorebi-bar/src/cpu.rs +++ b/komorebi-bar/src/cpu.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -23,6 +24,8 @@ pub struct CpuConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Cpu { @@ -36,6 +39,7 @@ impl From for Cpu { enable: value.enable, system, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), last_updated: Instant::now(), } } @@ -45,6 +49,7 @@ pub struct Cpu { pub enable: bool, system: System, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_updated: Instant, } @@ -57,7 +62,10 @@ impl Cpu { } let used = self.system.global_cpu_usage(); - format!("CPU: {:.0}%", used) + match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => format!("CPU: {:.0}%", used), + LabelPrefix::None | LabelPrefix::Icon => format!("{:.0}%", used), + } } } @@ -74,7 +82,12 @@ impl BarWidget for Cpu { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::CIRCUITRY.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::CIRCUITRY.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/date.rs b/komorebi-bar/src/date.rs index 1cf449af4..9a2727c39 100644 --- a/komorebi-bar/src/date.rs +++ b/komorebi-bar/src/date.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -19,6 +20,8 @@ pub struct DateConfig { pub enable: bool, /// Set the Date format pub format: DateFormat, + /// Display label prefix + pub label_prefix: Option, } impl From for Date { @@ -26,6 +29,7 @@ impl From for Date { Self { enable: value.enable, format: value.format, + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon), } } } @@ -70,6 +74,7 @@ impl DateFormat { pub struct Date { pub enable: bool, pub format: DateFormat, + label_prefix: LabelPrefix, } impl Date { @@ -83,7 +88,7 @@ impl Date { impl BarWidget for Date { fn render(&mut self, ctx: &Context, ui: &mut Ui) { if self.enable { - let output = self.output(); + let mut output = self.output(); if !output.is_empty() { let font_id = ctx .style() @@ -93,12 +98,21 @@ impl BarWidget for Date { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::CALENDAR_DOTS.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::CALENDAR_DOTS.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, ); + if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { + output.insert_str(0, "DATE: "); + } + layout_job.append( &output, 10.0, diff --git a/komorebi-bar/src/memory.rs b/komorebi-bar/src/memory.rs index 308f32110..f5261b804 100644 --- a/komorebi-bar/src/memory.rs +++ b/komorebi-bar/src/memory.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -23,6 +24,8 @@ pub struct MemoryConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Memory { @@ -36,6 +39,7 @@ impl From for Memory { enable: value.enable, system, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), last_updated: Instant::now(), } } @@ -45,6 +49,7 @@ pub struct Memory { pub enable: bool, system: System, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_updated: Instant, } @@ -58,7 +63,12 @@ impl Memory { let used = self.system.used_memory(); let total = self.system.total_memory(); - format!("RAM: {}%", (used * 100) / total) + match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("RAM: {}%", (used * 100) / total) + } + LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total), + } } } @@ -75,7 +85,12 @@ impl BarWidget for Memory { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::MEMORY.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::MEMORY.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/network.rs b/komorebi-bar/src/network.rs index 910b5f7b8..6f41fcb73 100644 --- a/komorebi-bar/src/network.rs +++ b/komorebi-bar/src/network.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -30,6 +31,8 @@ pub struct NetworkConfig { pub network_activity_fill_characters: Option, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Network { @@ -42,6 +45,8 @@ impl From for Network { let mut default_interface = String::new(); + let prefix = value.label_prefix.unwrap_or(LabelPrefix::Icon); + if let Ok(interface) = netdev::get_default_interface() { if let Some(friendly_name) = interface.friendly_name { default_interface.clone_from(&friendly_name); @@ -50,13 +55,32 @@ impl From for Network { networks_total_data_transmitted.refresh(); for (interface_name, data) in &networks_total_data_transmitted { if friendly_name.eq(interface_name) { - last_state_data.push(format!( - "{} {} / {} {}", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.total_received(), 1), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.total_transmitted(), 1), - )) + last_state_data.push(match prefix { + LabelPrefix::None => format!( + "{} | {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Icon => format!( + "{} {} | {} {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Text => format!( + "\u{2211}DOWN: {} | \u{2211}UP: {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::IconAndText => format!( + "{} \u{2211}DOWN: {} | {} \u{2211}UP: {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + }) } } } @@ -65,14 +89,40 @@ impl From for Network { networks_network_activity.refresh(); for (interface_name, data) in &networks_network_activity { if friendly_name.eq(interface_name) { - last_state_transmitted.push(format!( - "{} {: >width$}/s {} {: >width$}/s", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.received(), 1), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.transmitted(), 1), - width = value.network_activity_fill_characters.unwrap_or_default(), - )) + last_state_transmitted.push(match prefix { + LabelPrefix::None => format!( + "{: >width$}/s | {: >width$}/s", + to_pretty_bytes(data.received(), 1), + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + LabelPrefix::Icon => format!( + "{} {: >width$}/s | {} {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + LabelPrefix::Text => format!( + "DOWN: {: >width$}/s | UP: {: >width$}/s", + to_pretty_bytes(data.received(), 1), + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + LabelPrefix::IconAndText => format!( + "{} DOWN: {: >width$}/s | {} UP: {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + }) } } } @@ -85,6 +135,7 @@ impl From for Network { networks_network_activity, default_interface, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: prefix, show_total_data_transmitted: value.show_total_data_transmitted, show_network_activity: value.show_network_activity, network_activity_fill_characters: value @@ -105,6 +156,7 @@ pub struct Network { networks_total_data_transmitted: Networks, networks_network_activity: Networks, data_refresh_interval: u64, + label_prefix: LabelPrefix, default_interface: String, last_state_total_data_transmitted: Vec, last_state_network_activity: Vec, @@ -138,14 +190,62 @@ impl Network { self.networks_network_activity.refresh(); for (interface_name, data) in &self.networks_network_activity { if friendly_name.eq(interface_name) { - outputs.push(format!( - "{} {: >width$}/s {} {: >width$}/s", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.received(), self.data_refresh_interval), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.transmitted(), self.data_refresh_interval), - width = self.network_activity_fill_characters, - )) + outputs.push(match self.label_prefix { + LabelPrefix::None => format!( + "{: >width$}/s | {: >width$}/s", + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ), + LabelPrefix::Icon => format!( + "{} {: >width$}/s | {} {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ), + LabelPrefix::Text => format!( + "DOWN: {: >width$}/s | UP: {: >width$}/s", + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ), + LabelPrefix::IconAndText => { + format!( + "{} DOWN: {: >width$}/s | {} UP: {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ) + } + }) } } } @@ -176,13 +276,32 @@ impl Network { for (interface_name, data) in &self.networks_total_data_transmitted { if friendly_name.eq(interface_name) { - outputs.push(format!( - "{} {} / {} {}", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.total_received(), 1), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.total_transmitted(), 1), - )) + outputs.push(match self.label_prefix { + LabelPrefix::None => format!( + "{} | {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Icon => format!( + "{} {} | {} {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Text => format!( + "\u{2211}DOWN: {} | \u{2211}UP: {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::IconAndText => format!( + "{} \u{2211}DOWN: {} | {} \u{2211}UP: {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + }) } } } @@ -227,12 +346,21 @@ impl BarWidget for Network { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::WIFI_HIGH.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::WIFI_HIGH.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, ); + if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { + self.default_interface.insert_str(0, "NET: "); + } + layout_job.append( &self.default_interface, 10.0, diff --git a/komorebi-bar/src/storage.rs b/komorebi-bar/src/storage.rs index f2d9e1e1e..c81f66da8 100644 --- a/komorebi-bar/src/storage.rs +++ b/komorebi-bar/src/storage.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -22,6 +23,8 @@ pub struct StorageConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Storage { @@ -30,6 +33,7 @@ impl From for Storage { enable: value.enable, disks: Disks::new_with_refreshed_list(), data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), last_updated: Instant::now(), } } @@ -39,6 +43,7 @@ pub struct Storage { pub enable: bool, disks: Disks, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_updated: Instant, } @@ -57,12 +62,13 @@ impl Storage { let total = disk.total_space(); let available = disk.available_space(); let used = total - available; - - disks.push(format!( - "{} {}%", - mount.to_string_lossy(), - (used * 100) / total - )) + + disks.push(match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("{} {}%", mount.to_string_lossy(), (used * 100) / total) + } + LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total), + }) } disks.sort(); @@ -84,7 +90,12 @@ impl BarWidget for Storage { for output in self.output() { let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::HARD_DRIVES.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::HARD_DRIVES.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/time.rs b/komorebi-bar/src/time.rs index 85b5db8b5..37f4160e1 100644 --- a/komorebi-bar/src/time.rs +++ b/komorebi-bar/src/time.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -18,6 +19,8 @@ pub struct TimeConfig { pub enable: bool, /// Set the Time format pub format: TimeFormat, + /// Display label prefix + pub label_prefix: Option, } impl From for Time { @@ -25,6 +28,7 @@ impl From for Time { Self { enable: value.enable, format: value.format, + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon), } } } @@ -61,6 +65,7 @@ impl TimeFormat { pub struct Time { pub enable: bool, pub format: TimeFormat, + label_prefix: LabelPrefix, } impl Time { @@ -74,7 +79,7 @@ impl Time { impl BarWidget for Time { fn render(&mut self, ctx: &Context, ui: &mut Ui) { if self.enable { - let output = self.output(); + let mut output = self.output(); if !output.is_empty() { let font_id = ctx .style() @@ -84,12 +89,21 @@ impl BarWidget for Time { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::CLOCK.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::CLOCK.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, ); + if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { + output.insert_str(0, "TIME: "); + } + layout_job.append( &output, 10.0, From 0e1874de14e578788eb7ddcc70f2d579c6123113 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 9 Oct 2024 20:13:27 -0700 Subject: [PATCH 51/86] docs(github): update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 52 -------------------- .github/ISSUE_TEMPLATE/bug_report.yml | 56 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 ++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 -------- .github/ISSUE_TEMPLATE/feature_request.yml | 37 ++++++++++++++ 5 files changed, 101 insertions(+), 72 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index a86e04fb9..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "[BUG]: Short descriptive title" -labels: bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See bug - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots and Videos** -Add screenshots and videos to help explain your problem. - -**Operating System** -Provide the output of `systeminfo | grep "^OS Name\|^OS Version"` - -For example: -``` -OS Name: Microsoft Windows 11 Pro -OS Version: 10.0.22000 N/A Build 22000 -``` - -**`komorebic check` Output** -Provide the output of `komorebic check` - -For example: -``` -No KOMOREBI_CONFIG_HOME detected, defaulting to C:\Users\LGUG2Z - -Looking for configuration files in C:\Users\LGUG2Z - -No komorebi configuration found in C:\Users\LGUG2Z - -If running 'komorebic start --await-configuration', you will manually have to call the following command to begin tiling: komorebic complete-configuration -``` - -**Additional context** -Add any other context about the problem here. - -In particular, if you have any other AHK scripts or software running that handle any aspect of window management or manipulation diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..84d5f3d77 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,56 @@ +name: Bug report +description: File a bug report +labels: [ bug ] +title: "[BUG]: " +body: + - type: textarea + validations: + required: true + attributes: + label: Summary + description: > + Please provide a short summary of the bug, along with any information + you feel is relevant to replicating the bug. + + You may include screenshots and videos in this section. + - type: textarea + validations: + required: true + attributes: + label: Version Information + description: > + Please provide information about the versions of Windows and komorebi + running on your machine. + + Do not submit a bug if you are not using an official version of Windows + such as AtlasOS; only official versions of Windows are supported. + + ``` + systeminfo | findstr /B /C:"OS Name" /B /C:"OS Version" + ``` + + ``` + komorebic --version + ``` + - type: textarea + validations: + required: true + attributes: + label: Komorebi Configuration + description: > + Please provide your configuration file (komorebi.json or komorebi.bar.json) + render: json + - type: textarea + validations: + required: true + attributes: + label: Hotkey Configuration + description: > + Please provide your whkdrc or komorebi.ahk hotkey configuration file + - type: textarea + validations: + required: true + attributes: + label: Output of komorebic check + description: > + Please provide the output of `komorebic check` diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..195abe596 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Komorebi Documentation + url: https://lgug2z.github.io/komorebi/ + about: Please search the documentation website before opening an issue + - name: Komorebi Quickstart Tutorial Video + url: https://www.youtube.com/watch?v=MMZUAtHbTYY + about: If you are new, please make sure you watch the quickstart tutorial video \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 91c5647cf..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: "[FEAT]: Short descriptive title" -labels: enhancement -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..f3b2cfc8e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,37 @@ +name: Feature request +description: Suggest a new feature +labels: [ enhancement ] +title: "[FEAT]: " +body: + - type: dropdown + id: Sponsors + attributes: + label: Sponsorship Information + description: > + Feature requests are considered from individuals who are $5+ monthly sponsors to the project. + + Please specify the platform you use to sponsor the project. + options: + - GitHub Sponsors + - Ko-fi + - Discord + - YouTube + default: 0 + validations: + required: true + - type: textarea + validations: + required: true + attributes: + label: Suggestion + description: > + Please share your suggestion here. Be sure to include all necessary context. + + If you sponsor on a platform where you use a different username, please specify the username here. + - type: textarea + validations: + required: true + attributes: + label: Alternatives Considered + description: > + Please share share alternatives you have considered here. From 4aed288d4e8e0faff560586efc4fa9449337ec4b Mon Sep 17 00:00:00 2001 From: Csaba Date: Thu, 10 Oct 2024 00:23:01 +0200 Subject: [PATCH 52/86] feat(bar): add label prefix config opt This commit makes the label prefix configurable. Users can select if they want to show an icon, only text, or both text and an icon. --- komorebi-bar/src/battery.rs | 27 ++++- komorebi-bar/src/config.rs | 12 +++ komorebi-bar/src/cpu.rs | 17 +++- komorebi-bar/src/date.rs | 18 +++- komorebi-bar/src/memory.rs | 19 +++- komorebi-bar/src/network.rs | 190 ++++++++++++++++++++++++++++++------ komorebi-bar/src/storage.rs | 25 +++-- komorebi-bar/src/time.rs | 18 +++- 8 files changed, 276 insertions(+), 50 deletions(-) diff --git a/komorebi-bar/src/battery.rs b/komorebi-bar/src/battery.rs index 1b1517e07..0925b109e 100644 --- a/komorebi-bar/src/battery.rs +++ b/komorebi-bar/src/battery.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -23,6 +24,8 @@ pub struct BatteryConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Battery { @@ -30,6 +33,7 @@ impl From for Battery { let manager = Manager::new().unwrap(); let mut last_state = String::new(); let mut state = None; + let prefix = value.label_prefix.unwrap_or(LabelPrefix::Icon); if let Ok(mut batteries) = manager.batteries() { if let Some(Ok(first)) = batteries.nth(0) { @@ -39,8 +43,13 @@ impl From for Battery { State::Discharging => state = Some(BatteryState::Discharging), _ => {} } - - last_state = format!("{percentage}%"); + + last_state = match prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("BAT: {percentage:.0}%") + } + LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"), + } } } @@ -49,6 +58,7 @@ impl From for Battery { manager, last_state, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: prefix, state: state.unwrap_or(BatteryState::Discharging), last_updated: Instant::now(), } @@ -65,6 +75,7 @@ pub struct Battery { manager: Manager, pub state: BatteryState, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_state: String, last_updated: Instant, } @@ -86,7 +97,12 @@ impl Battery { _ => {} } - output = format!("{percentage:.0}%"); + output = match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("BAT: {percentage:.0}%") + } + LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"), + } } } @@ -116,7 +132,10 @@ impl BarWidget for Battery { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - emoji.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => emoji.to_string(), + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index 8d59f6fbf..cf18b707c 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -164,3 +164,15 @@ impl From for KomobarTheme { } } } + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub enum LabelPrefix { + /// Show no prefix + None, + /// Show an icon + Icon, + /// Show text + Text, + /// Show an icon and text + IconAndText, +} diff --git a/komorebi-bar/src/cpu.rs b/komorebi-bar/src/cpu.rs index 58f77db94..1a2c1d4d3 100644 --- a/komorebi-bar/src/cpu.rs +++ b/komorebi-bar/src/cpu.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -23,6 +24,8 @@ pub struct CpuConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Cpu { @@ -36,6 +39,7 @@ impl From for Cpu { enable: value.enable, system, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), last_updated: Instant::now(), } } @@ -45,6 +49,7 @@ pub struct Cpu { pub enable: bool, system: System, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_updated: Instant, } @@ -57,7 +62,10 @@ impl Cpu { } let used = self.system.global_cpu_usage(); - format!("CPU: {:.0}%", used) + match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => format!("CPU: {:.0}%", used), + LabelPrefix::None | LabelPrefix::Icon => format!("{:.0}%", used), + } } } @@ -74,7 +82,12 @@ impl BarWidget for Cpu { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::CIRCUITRY.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::CPU.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/date.rs b/komorebi-bar/src/date.rs index 1cf449af4..9a2727c39 100644 --- a/komorebi-bar/src/date.rs +++ b/komorebi-bar/src/date.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -19,6 +20,8 @@ pub struct DateConfig { pub enable: bool, /// Set the Date format pub format: DateFormat, + /// Display label prefix + pub label_prefix: Option, } impl From for Date { @@ -26,6 +29,7 @@ impl From for Date { Self { enable: value.enable, format: value.format, + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon), } } } @@ -70,6 +74,7 @@ impl DateFormat { pub struct Date { pub enable: bool, pub format: DateFormat, + label_prefix: LabelPrefix, } impl Date { @@ -83,7 +88,7 @@ impl Date { impl BarWidget for Date { fn render(&mut self, ctx: &Context, ui: &mut Ui) { if self.enable { - let output = self.output(); + let mut output = self.output(); if !output.is_empty() { let font_id = ctx .style() @@ -93,12 +98,21 @@ impl BarWidget for Date { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::CALENDAR_DOTS.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::CALENDAR_DOTS.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, ); + if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { + output.insert_str(0, "DATE: "); + } + layout_job.append( &output, 10.0, diff --git a/komorebi-bar/src/memory.rs b/komorebi-bar/src/memory.rs index 308f32110..f5261b804 100644 --- a/komorebi-bar/src/memory.rs +++ b/komorebi-bar/src/memory.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -23,6 +24,8 @@ pub struct MemoryConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Memory { @@ -36,6 +39,7 @@ impl From for Memory { enable: value.enable, system, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), last_updated: Instant::now(), } } @@ -45,6 +49,7 @@ pub struct Memory { pub enable: bool, system: System, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_updated: Instant, } @@ -58,7 +63,12 @@ impl Memory { let used = self.system.used_memory(); let total = self.system.total_memory(); - format!("RAM: {}%", (used * 100) / total) + match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("RAM: {}%", (used * 100) / total) + } + LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total), + } } } @@ -75,7 +85,12 @@ impl BarWidget for Memory { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::MEMORY.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::MEMORY.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/network.rs b/komorebi-bar/src/network.rs index 910b5f7b8..6f41fcb73 100644 --- a/komorebi-bar/src/network.rs +++ b/komorebi-bar/src/network.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -30,6 +31,8 @@ pub struct NetworkConfig { pub network_activity_fill_characters: Option, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Network { @@ -42,6 +45,8 @@ impl From for Network { let mut default_interface = String::new(); + let prefix = value.label_prefix.unwrap_or(LabelPrefix::Icon); + if let Ok(interface) = netdev::get_default_interface() { if let Some(friendly_name) = interface.friendly_name { default_interface.clone_from(&friendly_name); @@ -50,13 +55,32 @@ impl From for Network { networks_total_data_transmitted.refresh(); for (interface_name, data) in &networks_total_data_transmitted { if friendly_name.eq(interface_name) { - last_state_data.push(format!( - "{} {} / {} {}", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.total_received(), 1), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.total_transmitted(), 1), - )) + last_state_data.push(match prefix { + LabelPrefix::None => format!( + "{} | {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Icon => format!( + "{} {} | {} {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Text => format!( + "\u{2211}DOWN: {} | \u{2211}UP: {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::IconAndText => format!( + "{} \u{2211}DOWN: {} | {} \u{2211}UP: {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + }) } } } @@ -65,14 +89,40 @@ impl From for Network { networks_network_activity.refresh(); for (interface_name, data) in &networks_network_activity { if friendly_name.eq(interface_name) { - last_state_transmitted.push(format!( - "{} {: >width$}/s {} {: >width$}/s", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.received(), 1), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.transmitted(), 1), - width = value.network_activity_fill_characters.unwrap_or_default(), - )) + last_state_transmitted.push(match prefix { + LabelPrefix::None => format!( + "{: >width$}/s | {: >width$}/s", + to_pretty_bytes(data.received(), 1), + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + LabelPrefix::Icon => format!( + "{} {: >width$}/s | {} {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + LabelPrefix::Text => format!( + "DOWN: {: >width$}/s | UP: {: >width$}/s", + to_pretty_bytes(data.received(), 1), + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + LabelPrefix::IconAndText => format!( + "{} DOWN: {: >width$}/s | {} UP: {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.transmitted(), 1), + width = + value.network_activity_fill_characters.unwrap_or_default(), + ), + }) } } } @@ -85,6 +135,7 @@ impl From for Network { networks_network_activity, default_interface, data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: prefix, show_total_data_transmitted: value.show_total_data_transmitted, show_network_activity: value.show_network_activity, network_activity_fill_characters: value @@ -105,6 +156,7 @@ pub struct Network { networks_total_data_transmitted: Networks, networks_network_activity: Networks, data_refresh_interval: u64, + label_prefix: LabelPrefix, default_interface: String, last_state_total_data_transmitted: Vec, last_state_network_activity: Vec, @@ -138,14 +190,62 @@ impl Network { self.networks_network_activity.refresh(); for (interface_name, data) in &self.networks_network_activity { if friendly_name.eq(interface_name) { - outputs.push(format!( - "{} {: >width$}/s {} {: >width$}/s", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.received(), self.data_refresh_interval), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.transmitted(), self.data_refresh_interval), - width = self.network_activity_fill_characters, - )) + outputs.push(match self.label_prefix { + LabelPrefix::None => format!( + "{: >width$}/s | {: >width$}/s", + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ), + LabelPrefix::Icon => format!( + "{} {: >width$}/s | {} {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ), + LabelPrefix::Text => format!( + "DOWN: {: >width$}/s | UP: {: >width$}/s", + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ), + LabelPrefix::IconAndText => { + format!( + "{} DOWN: {: >width$}/s | {} UP: {: >width$}/s", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes( + data.received(), + self.data_refresh_interval + ), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes( + data.transmitted(), + self.data_refresh_interval + ), + width = self.network_activity_fill_characters, + ) + } + }) } } } @@ -176,13 +276,32 @@ impl Network { for (interface_name, data) in &self.networks_total_data_transmitted { if friendly_name.eq(interface_name) { - outputs.push(format!( - "{} {} / {} {}", - egui_phosphor::regular::ARROW_FAT_DOWN, - to_pretty_bytes(data.total_received(), 1), - egui_phosphor::regular::ARROW_FAT_UP, - to_pretty_bytes(data.total_transmitted(), 1), - )) + outputs.push(match self.label_prefix { + LabelPrefix::None => format!( + "{} | {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Icon => format!( + "{} {} | {} {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::Text => format!( + "\u{2211}DOWN: {} | \u{2211}UP: {}", + to_pretty_bytes(data.total_received(), 1), + to_pretty_bytes(data.total_transmitted(), 1), + ), + LabelPrefix::IconAndText => format!( + "{} \u{2211}DOWN: {} | {} \u{2211}UP: {}", + egui_phosphor::regular::ARROW_FAT_DOWN, + to_pretty_bytes(data.total_received(), 1), + egui_phosphor::regular::ARROW_FAT_UP, + to_pretty_bytes(data.total_transmitted(), 1), + ), + }) } } } @@ -227,12 +346,21 @@ impl BarWidget for Network { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::WIFI_HIGH.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::WIFI_HIGH.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, ); + if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { + self.default_interface.insert_str(0, "NET: "); + } + layout_job.append( &self.default_interface, 10.0, diff --git a/komorebi-bar/src/storage.rs b/komorebi-bar/src/storage.rs index f2d9e1e1e..c81f66da8 100644 --- a/komorebi-bar/src/storage.rs +++ b/komorebi-bar/src/storage.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -22,6 +23,8 @@ pub struct StorageConfig { pub enable: bool, /// Data refresh interval (default: 10 seconds) pub data_refresh_interval: Option, + /// Display label prefix + pub label_prefix: Option, } impl From for Storage { @@ -30,6 +33,7 @@ impl From for Storage { enable: value.enable, disks: Disks::new_with_refreshed_list(), data_refresh_interval: value.data_refresh_interval.unwrap_or(10), + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), last_updated: Instant::now(), } } @@ -39,6 +43,7 @@ pub struct Storage { pub enable: bool, disks: Disks, data_refresh_interval: u64, + label_prefix: LabelPrefix, last_updated: Instant, } @@ -57,12 +62,13 @@ impl Storage { let total = disk.total_space(); let available = disk.available_space(); let used = total - available; - - disks.push(format!( - "{} {}%", - mount.to_string_lossy(), - (used * 100) / total - )) + + disks.push(match self.label_prefix { + LabelPrefix::Text | LabelPrefix::IconAndText => { + format!("{} {}%", mount.to_string_lossy(), (used * 100) / total) + } + LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total), + }) } disks.sort(); @@ -84,7 +90,12 @@ impl BarWidget for Storage { for output in self.output() { let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::HARD_DRIVES.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::HARD_DRIVES.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, diff --git a/komorebi-bar/src/time.rs b/komorebi-bar/src/time.rs index 85b5db8b5..37f4160e1 100644 --- a/komorebi-bar/src/time.rs +++ b/komorebi-bar/src/time.rs @@ -1,3 +1,4 @@ +use crate::config::LabelPrefix; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; @@ -18,6 +19,8 @@ pub struct TimeConfig { pub enable: bool, /// Set the Time format pub format: TimeFormat, + /// Display label prefix + pub label_prefix: Option, } impl From for Time { @@ -25,6 +28,7 @@ impl From for Time { Self { enable: value.enable, format: value.format, + label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon), } } } @@ -61,6 +65,7 @@ impl TimeFormat { pub struct Time { pub enable: bool, pub format: TimeFormat, + label_prefix: LabelPrefix, } impl Time { @@ -74,7 +79,7 @@ impl Time { impl BarWidget for Time { fn render(&mut self, ctx: &Context, ui: &mut Ui) { if self.enable { - let output = self.output(); + let mut output = self.output(); if !output.is_empty() { let font_id = ctx .style() @@ -84,12 +89,21 @@ impl BarWidget for Time { .unwrap_or_else(FontId::default); let mut layout_job = LayoutJob::simple( - egui_phosphor::regular::CLOCK.to_string(), + match self.label_prefix { + LabelPrefix::Icon | LabelPrefix::IconAndText => { + egui_phosphor::regular::CLOCK.to_string() + } + LabelPrefix::None | LabelPrefix::Text => String::new(), + }, font_id.clone(), ctx.style().visuals.selection.stroke.color, 100.0, ); + if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { + output.insert_str(0, "TIME: "); + } + layout_job.append( &output, 10.0, From bb52183537c50e4f6c10df447095c5d32cf7a7ee Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 28 Sep 2024 17:03:37 -0700 Subject: [PATCH 53/86] 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: 17ea1e686926ac7edd0a9b16e56b9baa5a551618 feat(wm): separate floating and ignored apps 8b344496e618b7ae83c4b37911305657c54dbf00 feat(wm): allow ws moves of floating apps 7d8e2ad814f0cf407267e574c403a39daaf5ce38 refactor(wm): float_rules > ignore_rules w/ compat d68346a6405703efa1f5f3adfac12264a7f19276 fix(borders): no redraws on floating win title change a93e93777281d999d4fdb37b43c83fe1c3a4d43d fix(borders): update on floating win drag 68e9365ddacf7200c7208bfb60a98198a57c77ab fix(borders): send notif on ignored hwnd events --- komorebi/src/border_manager/mod.rs | 150 ++++++++++++++++++++-- komorebi/src/core/config_generation.rs | 23 ++-- komorebi/src/core/mod.rs | 4 +- komorebi/src/lib.rs | 4 +- komorebi/src/monitor.rs | 119 ++++++++++------- komorebi/src/monitor_reconciliator/mod.rs | 6 +- komorebi/src/process_command.rs | 21 +-- komorebi/src/process_event.rs | 95 +++++++++----- komorebi/src/reaper.rs | 2 +- komorebi/src/static_config.rs | 48 +++++-- komorebi/src/window.rs | 14 +- komorebi/src/window_manager.rs | 7 +- komorebi/src/workspace.rs | 33 +---- komorebi/src/workspace_reconciliator.rs | 2 +- komorebic/src/main.rs | 11 +- 15 files changed, 373 insertions(+), 166 deletions(-) diff --git a/komorebi/src/border_manager/mod.rs b/komorebi/src/border_manager/mod.rs index 42757fb49..2825d086d 100644 --- a/komorebi/src/border_manager/mod.rs +++ b/komorebi/src/border_manager/mod.rs @@ -49,6 +49,8 @@ lazy_static! { pub static ref MONOCLE: AtomicU32 = AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(255, 51, 153)))); pub static ref STACK: AtomicU32 = AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(0, 165, 66)))); + pub static ref FLOATING: AtomicU32 = + AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(245, 245, 165)))); } lazy_static! { @@ -57,7 +59,7 @@ lazy_static! { static ref FOCUS_STATE: Mutex> = Mutex::new(HashMap::new()); } -pub struct Notification; +pub struct Notification(pub Option); static CHANNEL: OnceLock<(Sender, Receiver)> = OnceLock::new(); @@ -73,8 +75,8 @@ fn event_rx() -> Receiver { channel().1.clone() } -pub fn send_notification() { - if event_tx().try_send(Notification).is_err() { +pub fn send_notification(hwnd: Option) { + if event_tx().try_send(Notification(hwnd)).is_err() { tracing::warn!("channel is full; dropping notification") } } @@ -118,6 +120,7 @@ fn window_kind_colour(focus_kind: WindowKind) -> u32 { WindowKind::Single => FOCUSED.load(Ordering::SeqCst), WindowKind::Stack => STACK.load(Ordering::SeqCst), WindowKind::Monocle => MONOCLE.load(Ordering::SeqCst), + WindowKind::Floating => FLOATING.load(Ordering::SeqCst), } } @@ -139,19 +142,29 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result BORDER_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst); let receiver = event_rx(); - event_tx().send(Notification)?; + event_tx().send(Notification(None))?; let mut previous_snapshot = Ring::default(); let mut previous_pending_move_op = None; let mut previous_is_paused = false; + let mut previous_notification: Option = None; - 'receiver: for _ in receiver { + 'receiver: for notification in receiver { // Check the wm state every time we receive a notification let state = wm.lock(); let is_paused = state.is_paused; let focused_monitor_idx = state.focused_monitor_idx(); + let focused_workspace_idx = + state.monitors.elements()[focused_monitor_idx].focused_workspace_idx(); let monitors = state.monitors.clone(); let pending_move_op = state.pending_move_op; + let floating_window_hwnds = state.monitors.elements()[focused_monitor_idx].workspaces() + [focused_workspace_idx] + .floating_windows() + .iter() + .map(|w| w.hwnd) + .collect::>(); + drop(state); match IMPLEMENTATION.load() { @@ -220,6 +233,21 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result should_process_notification = true; } + // when we switch focus to a floating window + if !should_process_notification + && floating_window_hwnds.contains(¬ification.0.unwrap_or_default()) + { + should_process_notification = true; + } + + if !should_process_notification { + if let Some(ref previous) = previous_notification { + if previous.0.unwrap_or_default() != notification.0.unwrap_or_default() { + should_process_notification = true; + } + } + } + if !should_process_notification { tracing::trace!("monitor state matches latest snapshot, skipping notification"); continue 'receiver; @@ -345,16 +373,20 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result } // Destroy any borders not associated with the focused workspace - let container_ids = ws + let mut container_and_floating_window_ids = ws .containers() .iter() .map(|c| c.id().clone()) .collect::>(); + for w in ws.floating_windows() { + container_and_floating_window_ids.push(w.hwnd.to_string()); + } + let mut to_remove = vec![]; for (id, border) in borders.iter() { if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx - && !container_ids.contains(id) + && !container_and_floating_window_ids.contains(id) { border.destroy()?; to_remove.push(id.clone()); @@ -366,8 +398,14 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result } for (idx, c) in ws.containers().iter().enumerate() { + let hwnd = c.focused_window().copied().unwrap_or_default().hwnd; + let notification_hwnd = notification.0.unwrap_or_default(); + // Update border when moving or resizing with mouse - if pending_move_op.is_some() && idx == ws.focused_container_idx() { + if pending_move_op.is_some() + && idx == ws.focused_container_idx() + && hwnd == notification_hwnd + { let restore_z_order = Z_ORDER.load(); Z_ORDER.store(ZOrder::TopMost); @@ -446,6 +484,101 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result border.update(&rect, should_invalidate)?; } + + { + let restore_z_order = Z_ORDER.load(); + Z_ORDER.store(ZOrder::TopMost); + + 'windows: for window in ws.floating_windows() { + let hwnd = window.hwnd; + let notification_hwnd = notification.0.unwrap_or_default(); + + if pending_move_op.is_some() && hwnd == notification_hwnd { + let mut rect = WindowsApi::window_rect(hwnd)?; + + while WindowsApi::lbutton_is_pressed() { + let border = match borders.entry(hwnd.to_string()) { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + if let Ok(border) = + Border::create(&hwnd.to_string()) + { + entry.insert(border) + } else { + continue 'monitors; + } + } + }; + + let new_rect = WindowsApi::window_rect(hwnd)?; + + if rect != new_rect { + rect = new_rect; + border.update(&rect, true)?; + } + } + + Z_ORDER.store(restore_z_order); + + continue 'monitors; + } + + let border = match borders.entry(window.hwnd.to_string()) { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + if let Ok(border) = Border::create(&window.hwnd.to_string()) + { + entry.insert(border) + } else { + continue 'monitors; + } + } + }; + + borders_monitors.insert(window.hwnd.to_string(), monitor_idx); + + let mut should_destroy = false; + + if let Some(notification_hwnd) = notification.0 { + if notification_hwnd != window.hwnd { + should_destroy = true; + } + } + + if WindowsApi::foreground_window().unwrap_or_default() + != window.hwnd + { + should_destroy = true; + } + + if should_destroy { + border.destroy()?; + borders.remove(&window.hwnd.to_string()); + borders_monitors.remove(&window.hwnd.to_string()); + continue 'windows; + } + + #[allow(unused_assignments)] + let mut last_focus_state = None; + let new_focus_state = WindowKind::Floating; + { + let mut focus_state = FOCUS_STATE.lock(); + last_focus_state = + focus_state.insert(border.hwnd, new_focus_state); + } + + let rect = WindowsApi::window_rect(window.hwnd)?; + + let should_invalidate = match last_focus_state { + None => true, + Some(last_focus_state) => last_focus_state != new_focus_state, + }; + + border.update(&rect, should_invalidate)?; + } + + Z_ORDER.store(restore_z_order); + } } } } @@ -454,6 +587,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result previous_snapshot = monitors; previous_pending_move_op = pending_move_op; previous_is_paused = is_paused; + previous_notification = Some(notification); } Ok(()) diff --git a/komorebi/src/core/config_generation.rs b/komorebi/src/core/config_generation.rs index fe67134fc..932a5f8a9 100644 --- a/komorebi/src/core/config_generation.rs +++ b/komorebi/src/core/config_generation.rs @@ -116,7 +116,8 @@ pub struct ApplicationConfiguration { #[serde(skip_serializing_if = "Option::is_none")] pub options: Option>, #[serde(skip_serializing_if = "Option::is_none")] - pub float_identifiers: Option>, + #[serde(alias = "float_identifiers")] + pub ignore_identifiers: Option>, } impl ApplicationConfiguration { @@ -187,7 +188,7 @@ impl ApplicationConfigurationGenerator { let mut lines = vec![String::from("# Generated by komorebic.exe"), String::new()]; - let mut float_rules = vec![]; + let mut ignore_rules = vec![]; for app in cfgen { lines.push(format!("# {}", app.name)); @@ -201,15 +202,15 @@ impl ApplicationConfigurationGenerator { } } - if let Some(float_identifiers) = app.float_identifiers { - for matching_rule in float_identifiers { + if let Some(ignore_identifiers) = app.ignore_identifiers { + for matching_rule in ignore_identifiers { if let MatchingRule::Simple(float) = matching_rule { let float_rule = format!("komorebic.exe float-rule {} \"{}\"", float.kind, float.id); // Don't want to send duped signals especially as configs get larger - if !float_rules.contains(&float_rule) { - float_rules.push(float_rule.clone()); + if !ignore_rules.contains(&float_rule) { + ignore_rules.push(float_rule.clone()); // if let Some(comment) = float.comment { // lines.push(format!("# {comment}")); @@ -238,7 +239,7 @@ impl ApplicationConfigurationGenerator { let mut lines = vec![String::from("; Generated by komorebic.exe"), String::new()]; - let mut float_rules = vec![]; + let mut ignore_rules = vec![]; for app in cfgen { lines.push(format!("; {}", app.name)); @@ -252,8 +253,8 @@ impl ApplicationConfigurationGenerator { } } - if let Some(float_identifiers) = app.float_identifiers { - for matching_rule in float_identifiers { + if let Some(ignore_identifiers) = app.ignore_identifiers { + for matching_rule in ignore_identifiers { if let MatchingRule::Simple(float) = matching_rule { let float_rule = format!( "RunWait('komorebic.exe float-rule {} \"{}\"', , \"Hide\")", @@ -261,8 +262,8 @@ impl ApplicationConfigurationGenerator { ); // Don't want to send duped signals especially as configs get larger - if !float_rules.contains(&float_rule) { - float_rules.push(float_rule.clone()); + if !ignore_rules.contains(&float_rule) { + ignore_rules.push(float_rule.clone()); // if let Some(comment) = float.comment { // lines.push(format!("; {comment}")); diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index b84748e3d..c08cb4b70 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -174,7 +174,8 @@ pub enum SocketMessage { ClearWorkspaceRules(usize, usize), ClearNamedWorkspaceRules(String), ClearAllWorkspaceRules, - FloatRule(ApplicationIdentifier, String), + #[serde(alias = "FloatRule")] + IgnoreRule(ApplicationIdentifier, String), ManageRule(ApplicationIdentifier, String), IdentifyObjectNameChangeApplication(ApplicationIdentifier, String), IdentifyTrayApplication(ApplicationIdentifier, String), @@ -294,6 +295,7 @@ pub enum WindowKind { Stack, Monocle, Unfocused, + Floating, } #[derive( diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index db019c340..b001e5776 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -139,7 +139,7 @@ lazy_static! { static ref REGEX_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(HashMap::new())); static ref MANAGE_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); - static ref FLOAT_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![ + static ref IGNORE_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![ // mstsc.exe creates these on Windows 11 when a WSL process is launched // https://github.com/LGUG2Z/komorebi/issues/74 MatchingRule::Simple(IdWithIdentifier { @@ -158,6 +158,7 @@ lazy_static! { matching_strategy: Option::from(MatchingStrategy::Equals), }) ])); + static ref FLOATING_APPLICATIONS: Arc>> = Arc::new(Mutex::new(Vec::new())); static ref PERMAIGNORE_CLASSES: Arc>> = Arc::new(Mutex::new(vec![ "Chrome_RenderWidgetHostHWND".to_string(), ])); @@ -224,7 +225,6 @@ lazy_static! { static ref WINDOWS_BY_BAR_HWNDS: Arc>>> = Arc::new(Mutex::new(HashMap::new())); - } pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10); diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index 090fe7ee0..5e40467ec 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -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, - }; + 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.insert_container_at_idx(0, container); - } else { + 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.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); } }, - 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 { + 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); } } - _ => { - 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); } } diff --git a/komorebi/src/monitor_reconciliator/mod.rs b/komorebi/src/monitor_reconciliator/mod.rs index c610a8bce..b15b452fb 100644 --- a/komorebi/src/monitor_reconciliator/mod.rs +++ b/komorebi/src/monitor_reconciliator/mod.rs @@ -172,7 +172,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result if should_update { tracing::info!("updated work area for {}", monitor.device_id()); monitor.update_focused_workspace(offset)?; - border_manager::send_notification(); + border_manager::send_notification(None); } else { tracing::debug!( "work areas match, reconciliation not required for {}", @@ -219,7 +219,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result ); monitor.update_focused_workspace(offset)?; - border_manager::send_notification(); + border_manager::send_notification(None); } else { tracing::debug!( "resolutions match, reconciliation not required for {}", @@ -406,7 +406,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result // Second retile to fix DPI/resolution related jank wm.retile_all(true)?; // Border updates to fix DPI/resolution related jank - border_manager::send_notification(); + border_manager::send_notification(None); } } } diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 77777bc85..09fa303ab 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -68,8 +68,8 @@ use crate::ANIMATION_STYLE; use crate::CUSTOM_FFM; use crate::DATA_DIR; use crate::DISPLAY_INDEX_PREFERENCES; -use crate::FLOAT_IDENTIFIERS; use crate::HIDING_BEHAVIOUR; +use crate::IGNORE_IDENTIFIERS; use crate::INITIAL_CONFIGURATION_LOADED; use crate::LAYERED_WHITELIST; use crate::MANAGE_IDENTIFIERS; @@ -394,20 +394,20 @@ impl WindowManager { })); } } - SocketMessage::FloatRule(identifier, ref id) => { - let mut float_identifiers = FLOAT_IDENTIFIERS.lock(); + SocketMessage::IgnoreRule(identifier, ref id) => { + let mut ignore_identifiers = IGNORE_IDENTIFIERS.lock(); let mut should_push = true; - for f in &*float_identifiers { - if let MatchingRule::Simple(f) = f { - if f.id.eq(id) { + for i in &*ignore_identifiers { + if let MatchingRule::Simple(i) = i { + if i.id.eq(id) { should_push = false; } } } if should_push { - float_identifiers.push(MatchingRule::Simple(IdWithIdentifier { + ignore_identifiers.push(MatchingRule::Simple(IdWithIdentifier { kind: identifier, id: id.clone(), matching_strategy: Option::from(MatchingStrategy::Legacy), @@ -1395,7 +1395,7 @@ impl WindowManager { } } - border_manager::send_notification(); + border_manager::send_notification(None); } } SocketMessage::BorderColour(kind, r, g, b) => match kind { @@ -1411,6 +1411,9 @@ impl WindowManager { WindowKind::Unfocused => { border_manager::UNFOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst); } + WindowKind::Floating => { + border_manager::FLOATING.store(Rgb::new(r, g, b).into(), Ordering::SeqCst); + } }, SocketMessage::BorderStyle(style) => { STYLE.store(style); @@ -1540,7 +1543,7 @@ impl WindowManager { }; notify_subscribers(&serde_json::to_string(¬ification)?)?; - border_manager::send_notification(); + border_manager::send_notification(None); transparency_manager::send_notification(); stackbar_manager::send_notification(); diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index fc3970a7e..30a8a952c 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -33,6 +33,7 @@ use crate::workspace_reconciliator::ALT_TAB_HWND_INSTANT; use crate::Notification; use crate::NotificationEvent; use crate::DATA_DIR; +use crate::FLOATING_APPLICATIONS; use crate::HIDDEN_HWNDS; use crate::REGEX_IDENTIFIERS; use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; @@ -101,6 +102,10 @@ impl WindowManager { } if !transparency_override { + if rule_debug.matches_ignore_identifier.is_some() { + border_manager::send_notification(Option::from(event.hwnd())); + } + return Ok(()); } } @@ -149,14 +154,6 @@ impl WindowManager { _ => {} } - for monitor in self.monitors_mut() { - for workspace in monitor.workspaces_mut() { - if let WindowManagerEvent::FocusChange(_, window) = event { - let _ = workspace.focus_changed(window.hwnd); - } - } - } - self.enforce_workspace_rules()?; if matches!(event, WindowManagerEvent::MouseCapture(..)) { @@ -246,24 +243,31 @@ impl WindowManager { self.update_focused_workspace(self.mouse_follows_focus, false)?; let workspace = self.focused_workspace_mut()?; - if !workspace + let floating_window_idx = workspace .floating_windows() .iter() - .any(|w| w.hwnd == window.hwnd) - { - if let Some(w) = workspace.maximized_window() { - if w.hwnd == window.hwnd { - return Ok(()); + .position(|w| w.hwnd == window.hwnd); + + match floating_window_idx { + None => { + if let Some(w) = workspace.maximized_window() { + if w.hwnd == window.hwnd { + return Ok(()); + } } - } - if let Some(monocle) = workspace.monocle_container() { - if let Some(window) = monocle.focused_window() { + if let Some(monocle) = workspace.monocle_container() { + if let Some(window) = monocle.focused_window() { + window.focus(false)?; + } + } else { + workspace.focus_container_by_window(window.hwnd)?; + } + } + Some(idx) => { + if let Some(window) = workspace.floating_windows().get(idx) { window.focus(false)?; } - } else { - self.focused_workspace_mut()? - .focus_container_by_window(window.hwnd)?; } } } @@ -336,19 +340,44 @@ impl WindowManager { let monocle_container = workspace.monocle_container().clone(); if !workspace_contains_window && !needs_reconciliation { - match behaviour { - WindowContainerBehaviour::Create => { - workspace.new_container_for_window(window); - self.update_focused_workspace(false, false)?; + let floating_applications = FLOATING_APPLICATIONS.lock(); + let regex_identifiers = REGEX_IDENTIFIERS.lock(); + let mut should_float = false; + + if !floating_applications.is_empty() { + if let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) = + (window.title(), window.exe(), window.class(), window.path()) + { + should_float = should_act( + &title, + &exe_name, + &class, + &path, + &floating_applications, + ®ex_identifiers, + ) + .is_some(); } - WindowContainerBehaviour::Append => { - workspace - .focused_container_mut() - .ok_or_else(|| anyhow!("there is no focused container"))? - .add_window(window); - self.update_focused_workspace(true, false)?; - - stackbar_manager::send_notification(); + } + + if should_float && !matches!(event, WindowManagerEvent::Manage(_)) { + workspace.floating_windows_mut().push(window); + self.update_focused_workspace(false, true)?; + } else { + match behaviour { + WindowContainerBehaviour::Create => { + workspace.new_container_for_window(window); + self.update_focused_workspace(false, false)?; + } + WindowContainerBehaviour::Append => { + workspace + .focused_container_mut() + .ok_or_else(|| anyhow!("there is no focused container"))? + .add_window(window); + self.update_focused_workspace(true, false)?; + + stackbar_manager::send_notification(); + } } } } @@ -642,7 +671,7 @@ impl WindowManager { }; notify_subscribers(&serde_json::to_string(¬ification)?)?; - border_manager::send_notification(); + border_manager::send_notification(Some(event.hwnd())); transparency_manager::send_notification(); stackbar_manager::send_notification(); diff --git a/komorebi/src/reaper.rs b/komorebi/src/reaper.rs index bf771e459..283417254 100644 --- a/komorebi/src/reaper.rs +++ b/komorebi/src/reaper.rs @@ -51,7 +51,7 @@ pub fn find_orphans(wm: Arc>) -> color_eyre::Result<()> { let reaped_orphans = workspace.reap_orphans()?; if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 { workspace.update(&work_area, offset, window_based_work_area_offset)?; - border_manager::send_notification(); + border_manager::send_notification(None); tracing::info!( "reaped {} orphan window(s) and {} orphaned container(s) on monitor: {}, workspace: {}", reaped_orphans.0, diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 1ca3633a5..2114bc6cd 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -35,8 +35,9 @@ use crate::DATA_DIR; use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_WORKSPACE_PADDING; use crate::DISPLAY_INDEX_PREFERENCES; -use crate::FLOAT_IDENTIFIERS; +use crate::FLOATING_APPLICATIONS; use crate::HIDING_BEHAVIOUR; +use crate::IGNORE_IDENTIFIERS; use crate::LAYERED_WHITELIST; use crate::MANAGE_IDENTIFIERS; use crate::MONITOR_INDEX_PREFERENCES; @@ -304,10 +305,14 @@ pub struct StaticConfig { pub global_work_area_offset: Option, /// Individual window floating rules #[serde(skip_serializing_if = "Option::is_none")] - pub float_rules: Option>, + #[serde(alias = "float_rules")] + pub ignore_rules: Option>, /// Individual window force-manage rules #[serde(skip_serializing_if = "Option::is_none")] pub manage_rules: Option>, + /// Identify applications which should be managed as floating windows + #[serde(skip_serializing_if = "Option::is_none")] + pub floating_applications: Option>, /// Identify border overflow applications #[serde(skip_serializing_if = "Option::is_none")] pub border_overflow_applications: Option>, @@ -371,6 +376,8 @@ pub enum KomorebiTheme { stack_border: Option, /// Border colour when the container is in monocle mode (default: Pink) monocle_border: Option, + /// Border colour when the window is floating (default: Yellow) + floating_border: Option, /// Border colour when the container is unfocused (default: Base) unfocused_border: Option, /// Stackbar focused tab text colour (default: Green) @@ -392,6 +399,8 @@ pub enum KomorebiTheme { stack_border: Option, /// Border colour when the container is in monocle mode (default: Base0F) monocle_border: Option, + /// Border colour when the window is floating (default: Base09) + floating_border: Option, /// Border colour when the container is unfocused (default: Base01) unfocused_border: Option, /// Stackbar focused tab text colour (default: Base0B) @@ -545,7 +554,8 @@ impl From<&WindowManager> for StaticConfig { monitors: Option::from(monitors), window_hiding_behaviour: Option::from(*HIDING_BEHAVIOUR.lock()), global_work_area_offset: value.work_area_offset, - float_rules: None, + ignore_rules: None, + floating_applications: None, manage_rules: None, border_overflow_applications: None, tray_and_multi_window_applications: None, @@ -654,7 +664,7 @@ impl StaticConfig { } } - border_manager::send_notification(); + border_manager::send_notification(None); } transparency_manager::TRANSPARENCY_ENABLED @@ -662,7 +672,7 @@ impl StaticConfig { transparency_manager::TRANSPARENCY_ALPHA .store(self.transparency_alpha.unwrap_or(200), Ordering::SeqCst); - let mut float_identifiers = FLOAT_IDENTIFIERS.lock(); + let mut ignore_identifiers = IGNORE_IDENTIFIERS.lock(); let mut regex_identifiers = REGEX_IDENTIFIERS.lock(); let mut manage_identifiers = MANAGE_IDENTIFIERS.lock(); let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); @@ -670,9 +680,14 @@ impl StaticConfig { let mut layered_identifiers = LAYERED_WHITELIST.lock(); let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock(); let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock(); + let mut floating_applications = FLOATING_APPLICATIONS.lock(); + + if let Some(rules) = &mut self.ignore_rules { + populate_rules(rules, &mut ignore_identifiers, &mut regex_identifiers)?; + } - if let Some(rules) = &mut self.float_rules { - populate_rules(rules, &mut float_identifiers, &mut regex_identifiers)?; + if let Some(rules) = &mut self.floating_applications { + populate_rules(rules, &mut floating_applications, &mut regex_identifiers)?; } if let Some(rules) = &mut self.manage_rules { @@ -752,6 +767,7 @@ impl StaticConfig { single_border, stack_border, monocle_border, + floating_border, unfocused_border, stackbar_focused_text, stackbar_unfocused_text, @@ -762,6 +778,7 @@ impl StaticConfig { single_border, stack_border, monocle_border, + floating_border, unfocused_border, stackbar_focused_text, stackbar_unfocused_text, @@ -780,6 +797,10 @@ impl StaticConfig { .unwrap_or(komorebi_themes::CatppuccinValue::Pink) .color32(name.as_theme()); + let floating_border = floating_border + .unwrap_or(komorebi_themes::CatppuccinValue::Yellow) + .color32(name.as_theme()); + let unfocused_border = unfocused_border .unwrap_or(komorebi_themes::CatppuccinValue::Base) .color32(name.as_theme()); @@ -800,6 +821,7 @@ impl StaticConfig { single_border, stack_border, monocle_border, + floating_border, unfocused_border, stackbar_focused_text, stackbar_unfocused_text, @@ -811,6 +833,7 @@ impl StaticConfig { single_border, stack_border, monocle_border, + floating_border, unfocused_border, stackbar_focused_text, stackbar_unfocused_text, @@ -833,6 +856,10 @@ impl StaticConfig { .unwrap_or(komorebi_themes::Base16Value::Base01) .color32(*name); + let floating_border = floating_border + .unwrap_or(komorebi_themes::Base16Value::Base09) + .color32(*name); + let stackbar_focused_text = stackbar_focused_text .unwrap_or(komorebi_themes::Base16Value::Base0B) .color32(*name); @@ -849,6 +876,7 @@ impl StaticConfig { single_border, stack_border, monocle_border, + floating_border, unfocused_border, stackbar_focused_text, stackbar_unfocused_text, @@ -861,6 +889,8 @@ impl StaticConfig { border_manager::MONOCLE .store(u32::from(Colour::from(monocle_border)), Ordering::SeqCst); border_manager::STACK.store(u32::from(Colour::from(stack_border)), Ordering::SeqCst); + border_manager::FLOATING + .store(u32::from(Colour::from(floating_border)), Ordering::SeqCst); border_manager::UNFOCUSED .store(u32::from(Colour::from(unfocused_border)), Ordering::SeqCst); @@ -886,8 +916,8 @@ impl StaticConfig { let asc = ApplicationConfigurationGenerator::load(&content)?; for mut entry in asc { - if let Some(rules) = &mut entry.float_identifiers { - populate_rules(rules, &mut float_identifiers, &mut regex_identifiers)?; + if let Some(rules) = &mut entry.ignore_identifiers { + populate_rules(rules, &mut ignore_identifiers, &mut regex_identifiers)?; } if let Some(ref options) = entry.options { diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 4069d8e87..912becb9d 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -41,9 +41,9 @@ use crate::styles::WindowStyle; use crate::transparency_manager; use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; -use crate::FLOAT_IDENTIFIERS; use crate::HIDDEN_HWNDS; use crate::HIDING_BEHAVIOUR; +use crate::IGNORE_IDENTIFIERS; use crate::LAYERED_WHITELIST; use crate::MANAGE_IDENTIFIERS; use crate::NO_TITLEBAR; @@ -181,7 +181,7 @@ impl Window { let mut animation = self.animation; border_manager::BORDER_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); - border_manager::send_notification(); + border_manager::send_notification(Some(self.hwnd)); stackbar_manager::STACKBAR_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); stackbar_manager::send_notification(); @@ -203,7 +203,7 @@ impl Window { stackbar_manager::STACKBAR_TEMPORARILY_DISABLED .store(false, Ordering::SeqCst); - border_manager::send_notification(); + border_manager::send_notification(Some(hwnd)); stackbar_manager::send_notification(); transparency_manager::send_notification(); } @@ -537,7 +537,7 @@ pub struct RuleDebug { pub class: Option, pub path: Option, pub matches_permaignore_class: Option, - pub matches_float_identifier: Option, + pub matches_ignore_identifier: Option, pub matches_managed_override: Option, pub matches_layered_whitelist: Option, pub matches_wsl2_gui: Option, @@ -566,16 +566,16 @@ fn window_is_eligible( let regex_identifiers = REGEX_IDENTIFIERS.lock(); - let float_identifiers = FLOAT_IDENTIFIERS.lock(); + let ignore_identifiers = IGNORE_IDENTIFIERS.lock(); let should_float = if let Some(rule) = should_act( title, exe_name, class, path, - &float_identifiers, + &ignore_identifiers, ®ex_identifiers, ) { - debug.matches_float_identifier = Some(rule); + debug.matches_ignore_identifier = Some(rule); true } else { false diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 4fefb4a5d..92f222a69 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -71,9 +71,9 @@ use crate::Rgb; use crate::CUSTOM_FFM; use crate::DATA_DIR; use crate::DISPLAY_INDEX_PREFERENCES; -use crate::FLOAT_IDENTIFIERS; use crate::HIDING_BEHAVIOUR; use crate::HOME_DIR; +use crate::IGNORE_IDENTIFIERS; use crate::LAYERED_WHITELIST; use crate::MANAGE_IDENTIFIERS; use crate::MONITOR_INDEX_PREFERENCES; @@ -136,7 +136,8 @@ pub struct GlobalState { pub stackbar_tab_width: i32, pub stackbar_height: i32, pub remove_titlebars: bool, - pub float_identifiers: Vec, + #[serde(alias = "float_identifiers")] + pub ignore_identifiers: Vec, pub manage_identifiers: Vec, pub layered_whitelist: Vec, pub tray_and_multi_window_identifiers: Vec, @@ -185,7 +186,7 @@ impl Default for GlobalState { stackbar_tab_width: STACKBAR_TAB_WIDTH.load(Ordering::SeqCst), stackbar_height: STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst), remove_titlebars: REMOVE_TITLEBARS.load(Ordering::SeqCst), - float_identifiers: FLOAT_IDENTIFIERS.lock().clone(), + ignore_identifiers: IGNORE_IDENTIFIERS.lock().clone(), manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(), layered_whitelist: LAYERED_WHITELIST.lock().clone(), tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock().clone(), diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 688c742f5..39a846e91 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -221,18 +221,19 @@ impl Workspace { container.restore(); } - for window in self.floating_windows() { - window.restore(); - } - if let Some(container) = self.focused_container_mut() { container.focus_window(container.focused_window_idx()); } + for window in self.floating_windows() { + window.restore(); + } + // Do this here to make sure that an error doesn't stop the restoration of other windows - // Maximised windows should always be drawn at the top of the Z order + // Maximised windows and floating windows should always be drawn at the top of the Z order + // when switching to a workspace if let Some(window) = to_focus { - if self.maximized_window().is_none() { + if self.maximized_window().is_none() && self.floating_windows().is_empty() { window.focus(mouse_follows_focus)?; } } @@ -393,26 +394,6 @@ impl Workspace { Ok(()) } - // focus_changed performs updates in response to the fact that a focus - // change event has occurred. The focus change is assumed to be valid, and - // should not result in a new focus change - the intent here is to update - // focus-reactive elements, such as the stackbar. - pub fn focus_changed(&mut self, hwnd: isize) -> Result<()> { - if !self.tile() { - return Ok(()); - } - - let containers = self.containers_mut(); - - for container in containers.iter_mut() { - if let Some(idx) = container.idx_for_window(hwnd) { - container.focus_window(idx); - container.restore(); - } - } - Ok(()) - } - pub fn reap_orphans(&mut self) -> Result<(usize, usize)> { let mut hwnds = vec![]; let mut floating_hwnds = vec![]; diff --git a/komorebi/src/workspace_reconciliator.rs b/komorebi/src/workspace_reconciliator.rs index 3842546a8..60cbf2fdb 100644 --- a/komorebi/src/workspace_reconciliator.rs +++ b/komorebi/src/workspace_reconciliator.rs @@ -118,7 +118,7 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result // Unblock the border manager ALT_TAB_HWND.store(None); // Send a notification to the border manager to update the borders - border_manager::send_notification(); + border_manager::send_notification(None); } } } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 248cf6b83..0079f43fc 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -583,7 +583,7 @@ macro_rules! gen_application_target_subcommand_args { } gen_application_target_subcommand_args! { - FloatRule, + IgnoreRule, ManageRule, IdentifyTrayApplication, IdentifyLayeredApplication, @@ -1208,9 +1208,10 @@ enum SubCommand { /// Set the operation behaviour when the focused window is not managed #[clap(arg_required_else_help = true)] UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour), - /// Add a rule to always float the specified application + /// Add a rule to ignore the specified application #[clap(arg_required_else_help = true)] - FloatRule(FloatRule), + #[clap(alias = "float-rule")] + IgnoreRule(IgnoreRule), /// Add a rule to always manage the specified application #[clap(arg_required_else_help = true)] ManageRule(ManageRule), @@ -2154,8 +2155,8 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue } } } - SubCommand::FloatRule(arg) => { - send_message(&SocketMessage::FloatRule(arg.identifier, arg.id))?; + SubCommand::IgnoreRule(arg) => { + send_message(&SocketMessage::IgnoreRule(arg.identifier, arg.id))?; } SubCommand::ManageRule(arg) => { send_message(&SocketMessage::ManageRule(arg.identifier, arg.id))?; From 51c3b12b30219cad37440cb28f3a0a15a132af73 Mon Sep 17 00:00:00 2001 From: alex-ds13 <145657253+alex-ds13@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:53:36 +0100 Subject: [PATCH 54/86] feat(wm): add float override option This commit introduces a new option `float_override`, which makes it so every every window opened, shown or uncloaked will be set to floating, but it won't be ignored. It will be added to the floating_windows of the workspace, meaning that the user can later tile that window with toggle-float command. This allows the users to have all windows open as floating and then manually tile the ones they want. This interactively rebased commit contains changes from the following individual commits: 0e8dc85fb146fba05b9aa509dc91a5432a4b2ba0 feat(wm): add new float override option 30bdaf33d5d2ce80b6f6e9a98aec745654c8159b feat(cli): add command for new option `ToggleFloatOverride` b7bedce1ca8472b9ed762d57f4d36e79eb156f8c feat(wm): add window_container_behaviour and float_override to workspaces 221e4ea545c383e0094bf04a34b698c0c8be7a46 feat(cli): add commands for workspace new window behaviour and float_override b182cb5818efc491e2f5088e56093bdd2ae4864b fix(wm): show floating apps in front of stacked windows as well 7c9cb11a9bdf536c9d59770f74c4589c379c4796 fix(wm): Remove unecessary duplicated code --- komorebi/src/core/mod.rs | 18 +++++++++++++- komorebi/src/process_command.rs | 33 ++++++++++++++++++++++--- komorebi/src/process_event.rs | 22 ++++++++++------- komorebi/src/static_config.rs | 30 +++++++++++++++++++---- komorebi/src/window_manager.rs | 43 +++++++++++++++++++++++++++------ komorebi/src/workspace.rs | 19 ++++++++++++--- komorebic/src/main.rs | 19 +++++++++++++++ 7 files changed, 154 insertions(+), 30 deletions(-) diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index c08cb4b70..7cbe78363 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -77,6 +77,7 @@ pub enum SocketMessage { ToggleMonocle, ToggleMaximize, ToggleWindowContainerBehaviour, + ToggleFloatOverride, WindowHidingBehaviour(HidingBehaviour), ToggleCrossMonitorMoveBehaviour, CrossMonitorMoveBehaviour(MoveBehaviour), @@ -90,6 +91,8 @@ pub enum SocketMessage { CycleLayout(CycleDirection), ChangeLayoutCustom(PathBuf), FlipLayout(Axis), + ToggleWorkspaceWindowContainerBehaviour, + ToggleWorkspaceFloatOverride, // Monitor and Workspace Commands MonitorIndexPreference(usize, i32, i32, i32, i32), DisplayIndexPreference(usize, String), @@ -343,10 +346,23 @@ pub enum FocusFollowsMouseImplementation { } #[derive( - Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, + Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, +)] +pub struct WindowManagementBehaviour { + /// The current WindowContainerBehaviour to be used + pub current_behaviour: WindowContainerBehaviour, + /// Override of `current_behaviour` to open new windows as floating windows + /// that can be later toggled to tiled, when false it will default to + /// `current_behaviour` again. + pub float_override: bool, +} + +#[derive( + Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, PartialEq )] pub enum WindowContainerBehaviour { /// Create a new container for each new window + #[default] Create, /// Append new windows to the focused window container Append, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 09fa303ab..ac0aa2425 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -1346,15 +1346,42 @@ impl WindowManager { self.resize_delta = delta; } SocketMessage::ToggleWindowContainerBehaviour => { - match self.window_container_behaviour { + match self.window_management_behaviour.current_behaviour { WindowContainerBehaviour::Create => { - self.window_container_behaviour = WindowContainerBehaviour::Append; + self.window_management_behaviour.current_behaviour = WindowContainerBehaviour::Append; } WindowContainerBehaviour::Append => { - self.window_container_behaviour = WindowContainerBehaviour::Create; + self.window_management_behaviour.current_behaviour = WindowContainerBehaviour::Create; } } } + SocketMessage::ToggleFloatOverride => { + self.window_management_behaviour.float_override = !self.window_management_behaviour.float_override; + } + SocketMessage::ToggleWorkspaceWindowContainerBehaviour => { + let current_global_behaviour = self.window_management_behaviour.current_behaviour; + if let Some(behaviour) = self.focused_workspace_mut()?.window_container_behaviour_mut() { + match behaviour { + WindowContainerBehaviour::Create => *behaviour = WindowContainerBehaviour::Append, + WindowContainerBehaviour::Append => *behaviour = WindowContainerBehaviour::Create, + } + } else { + self.focused_workspace_mut()?.set_window_container_behaviour( + Some(match current_global_behaviour { + WindowContainerBehaviour::Create => WindowContainerBehaviour::Append, + WindowContainerBehaviour::Append => WindowContainerBehaviour::Create, + }) + ); + }; + } + SocketMessage::ToggleWorkspaceFloatOverride => { + let current_global_override = self.window_management_behaviour.float_override; + if let Some(float_override) = self.focused_workspace_mut()?.float_override_mut() { + *float_override = !*float_override; + } else { + self.focused_workspace_mut()?.set_float_override(Some(!current_global_override)); + }; + } SocketMessage::WindowHidingBehaviour(behaviour) => { let mut hiding_behaviour = HIDING_BEHAVIOUR.lock(); *hiding_behaviour = behaviour; diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 30a8a952c..46fd9e038 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -333,8 +333,8 @@ impl WindowManager { } if proceed { - let behaviour = - self.window_container_behaviour(focused_monitor_idx, focused_workspace_idx); + let mut behaviour = + self.window_management_behaviour(focused_monitor_idx, focused_workspace_idx); let workspace = self.focused_workspace_mut()?; let workspace_contains_window = workspace.contains_window(window.hwnd); let monocle_container = workspace.monocle_container().clone(); @@ -360,11 +360,13 @@ impl WindowManager { } } - if should_float && !matches!(event, WindowManagerEvent::Manage(_)) { + behaviour.float_override = behaviour.float_override || (should_float && !matches!(event, WindowManagerEvent::Manage(_))); + + if behaviour.float_override { workspace.floating_windows_mut().push(window); - self.update_focused_workspace(false, true)?; + self.update_focused_workspace(false, false)?; } else { - match behaviour { + match behaviour.current_behaviour { WindowContainerBehaviour::Create => { workspace.new_container_for_window(window); self.update_focused_workspace(false, false)?; @@ -375,7 +377,6 @@ impl WindowManager { .ok_or_else(|| anyhow!("there is no focused container"))? .add_window(window); self.update_focused_workspace(true, false)?; - stackbar_manager::send_notification(); } } @@ -431,8 +432,8 @@ impl WindowManager { let focused_monitor_idx = self.focused_monitor_idx(); let focused_workspace_idx = self.focused_workspace_idx().unwrap_or_default(); - let window_container_behaviour = - self.window_container_behaviour(focused_monitor_idx, focused_workspace_idx); + let window_management_behaviour = + self.window_management_behaviour(focused_monitor_idx, focused_workspace_idx); let workspace = self.focused_workspace_mut()?; let focused_container_idx = workspace.focused_container_idx(); @@ -550,8 +551,11 @@ impl WindowManager { } // Here we handle a simple move on the same monitor which is treated as // a container swap + } else if window_management_behaviour.float_override { + workspace.floating_windows_mut().push(window); + self.update_focused_workspace(false, false)?; } else { - match window_container_behaviour { + match window_management_behaviour.current_behaviour { WindowContainerBehaviour::Create => { match workspace.container_idx_from_current_point() { Some(target_idx) => { diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 2114bc6cd..1e9ee0ad7 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -68,6 +68,7 @@ use crate::core::OperationBehaviour; use crate::core::Rect; use crate::core::SocketMessage; use crate::core::WindowContainerBehaviour; +use crate::core::WindowManagementBehaviour; use color_eyre::Result; use crossbeam_channel::Receiver; use hotwatch::EventKind; @@ -130,6 +131,13 @@ pub struct WorkspaceConfig { /// Apply this monitor's window-based work area offset (default: true) #[serde(skip_serializing_if = "Option::is_none")] pub apply_window_based_work_area_offset: Option, + /// Determine what happens when a new window is opened (default: Create) + #[serde(skip_serializing_if = "Option::is_none")] + pub window_container_behaviour: Option, + /// 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, } impl From<&Workspace> for WorkspaceConfig { @@ -182,6 +190,8 @@ impl From<&Workspace> for WorkspaceConfig { initial_workspace_rules: None, workspace_rules: None, apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset()), + window_container_behaviour: *value.window_container_behaviour(), + float_override: *value.float_override(), } } } @@ -235,6 +245,10 @@ pub struct StaticConfig { /// Determine what happens when a new window is opened (default: Create) #[serde(skip_serializing_if = "Option::is_none")] pub window_container_behaviour: Option, + /// 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, /// Determine what happens when a window is moved across a monitor boundary (default: Swap) #[serde(skip_serializing_if = "Option::is_none")] pub cross_monitor_move_behaviour: Option, @@ -520,7 +534,8 @@ impl From<&WindowManager> for StaticConfig { Self { invisible_borders: None, resize_delta: Option::from(value.resize_delta), - window_container_behaviour: Option::from(value.window_container_behaviour), + window_container_behaviour: Option::from(value.window_management_behaviour.current_behaviour), + float_override: Option::from(value.window_management_behaviour.float_override), cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour), cross_boundary_behaviour: Option::from(value.cross_boundary_behaviour), unmanaged_window_operation_behaviour: Option::from( @@ -1031,9 +1046,10 @@ impl StaticConfig { is_paused: false, virtual_desktop_id: current_virtual_desktop(), work_area_offset: value.global_work_area_offset, - window_container_behaviour: value - .window_container_behaviour - .unwrap_or(WindowContainerBehaviour::Create), + window_management_behaviour: WindowManagementBehaviour { + current_behaviour: value.window_container_behaviour.unwrap_or(WindowContainerBehaviour::Create), + float_override: value.float_override.unwrap_or_default(), + }, cross_monitor_move_behaviour: value .cross_monitor_move_behaviour .unwrap_or(MoveBehaviour::Swap), @@ -1208,7 +1224,11 @@ impl StaticConfig { } if let Some(val) = value.window_container_behaviour { - wm.window_container_behaviour = val; + wm.window_management_behaviour.current_behaviour = val; + } + + if let Some(val) = value.float_override { + wm.window_management_behaviour.float_override = val; } if let Some(val) = value.cross_monitor_move_behaviour { diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 92f222a69..4631ea7cc 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -39,6 +39,7 @@ use crate::core::Rect; use crate::core::Sizing; use crate::core::StackbarLabel; use crate::core::WindowContainerBehaviour; +use crate::core::WindowManagementBehaviour; use crate::border_manager; use crate::border_manager::STYLE; @@ -92,7 +93,7 @@ pub struct WindowManager { pub is_paused: bool, pub work_area_offset: Option, pub resize_delta: i32, - pub window_container_behaviour: WindowContainerBehaviour, + pub window_management_behaviour: WindowManagementBehaviour, pub cross_monitor_move_behaviour: MoveBehaviour, pub cross_boundary_behaviour: CrossBoundaryBehaviour, pub unmanaged_window_operation_behaviour: OperationBehaviour, @@ -112,6 +113,7 @@ pub struct State { pub is_paused: bool, pub resize_delta: i32, pub new_window_behaviour: WindowContainerBehaviour, + pub float_override: bool, pub cross_monitor_move_behaviour: MoveBehaviour, pub unmanaged_window_operation_behaviour: OperationBehaviour, pub work_area_offset: Option, @@ -215,7 +217,8 @@ impl From<&WindowManager> for State { is_paused: wm.is_paused, work_area_offset: wm.work_area_offset, resize_delta: wm.resize_delta, - new_window_behaviour: wm.window_container_behaviour, + new_window_behaviour: wm.window_management_behaviour.current_behaviour, + float_override: wm.window_management_behaviour.float_override, cross_monitor_move_behaviour: wm.cross_monitor_move_behaviour, focus_follows_mouse: wm.focus_follows_mouse, mouse_follows_focus: wm.mouse_follows_focus, @@ -275,7 +278,7 @@ impl WindowManager { is_paused: false, virtual_desktop_id: current_virtual_desktop(), work_area_offset: None, - window_container_behaviour: WindowContainerBehaviour::Create, + window_management_behaviour: WindowManagementBehaviour::default(), cross_monitor_move_behaviour: MoveBehaviour::Swap, cross_boundary_behaviour: CrossBoundaryBehaviour::Workspace, unmanaged_window_operation_behaviour: OperationBehaviour::Op, @@ -308,22 +311,44 @@ impl WindowManager { StaticConfig::reload(pathbuf, self) } - pub fn window_container_behaviour( + pub fn window_management_behaviour( &self, monitor_idx: usize, workspace_idx: usize, - ) -> WindowContainerBehaviour { + ) -> WindowManagementBehaviour { if let Some(monitor) = self.monitors().get(monitor_idx) { if let Some(workspace) = monitor.workspaces().get(workspace_idx) { - return if workspace.containers().is_empty() { + let current_behaviour = if let Some(behaviour) = workspace.window_container_behaviour() { + if workspace.containers().is_empty() && matches!(behaviour, WindowContainerBehaviour::Append) { + // You can't append to an empty workspace + WindowContainerBehaviour::Create + } else { + *behaviour + } + } else if workspace.containers().is_empty() && matches!(self.window_management_behaviour.current_behaviour, WindowContainerBehaviour::Append) { + // You can't append to an empty workspace WindowContainerBehaviour::Create } else { - self.window_container_behaviour + self.window_management_behaviour.current_behaviour + }; + + let float_override = if let Some(float_override) = workspace.float_override() { + *float_override + } else { + self.window_management_behaviour.float_override + }; + + return WindowManagementBehaviour { + current_behaviour, + float_override }; } } - WindowContainerBehaviour::Create + WindowManagementBehaviour { + current_behaviour: WindowContainerBehaviour::Create, + float_override: self.window_management_behaviour.float_override, + } } #[tracing::instrument(skip(self))] @@ -846,6 +871,8 @@ impl WindowManager { && self.focused_workspace()?.maximized_window().is_none() // and we don't have a monocle container && self.focused_workspace()?.monocle_container().is_none() + // and we don't have any floating windows that should show on top + && self.focused_workspace()?.floating_windows().is_empty() { if let Ok(window) = self.focused_window_mut() { if trigger_focus { diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 39a846e91..a7392159d 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -30,6 +30,7 @@ use crate::static_config::WorkspaceConfig; use crate::window::Window; use crate::window::WindowDetails; use crate::windows_api::WindowsApi; +use crate::WindowContainerBehaviour; use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_WORKSPACE_PADDING; use crate::INITIAL_CONFIGURATION_LOADED; @@ -83,6 +84,10 @@ pub struct Workspace { tile: bool, #[getset(get_copy = "pub", set = "pub")] apply_window_based_work_area_offset: bool, + #[getset(get = "pub", get_mut = "pub", set = "pub")] + window_container_behaviour: Option, + #[getset(get = "pub", get_mut = "pub", set = "pub")] + float_override: Option, } impl_ring_elements!(Workspace, Container); @@ -106,6 +111,8 @@ impl Default for Workspace { resize_dimensions: vec![], tile: true, apply_window_based_work_area_offset: true, + window_container_behaviour: None, + float_override: None, } } } @@ -162,6 +169,14 @@ impl Workspace { config.apply_window_based_work_area_offset.unwrap_or(true), ); + if config.window_container_behaviour.is_some() { + self.set_window_container_behaviour(config.window_container_behaviour); + } + + if config.float_override.is_some() { + self.set_float_override(config.float_override); + } + Ok(()) } @@ -217,10 +232,6 @@ impl Workspace { container.restore(); } - for container in self.containers_mut() { - container.restore(); - } - if let Some(container) = self.focused_container_mut() { container.focus_window(container.focused_window_idx()); } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 0079f43fc..f805de6d2 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -1167,6 +1167,16 @@ enum SubCommand { WorkspaceName(WorkspaceName), /// Toggle the behaviour for new windows (stacking or dynamic tiling) ToggleWindowContainerBehaviour, + /// Enable or disable float override, which makes it so every new window opens in floating mode + ToggleFloatOverride, + /// Toggle the behaviour for new windows (stacking or dynamic tiling) for currently focused + /// workspace. If there was no behaviour set for the workspace previously it takes the opposite + /// of the global value. + ToggleWorkspaceWindowContainerBehaviour, + /// Enable or disable float override, which makes it so every new window opens in floating + /// mode, for the currently focused workspace. If there was no override value set for the + /// workspace previously it takes the opposite of the global value. + ToggleWorkspaceFloatOverride, /// Toggle window tiling on the focused workspace TogglePause, /// Toggle window tiling on the focused workspace @@ -2470,6 +2480,15 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue SubCommand::ToggleWindowContainerBehaviour => { send_message(&SocketMessage::ToggleWindowContainerBehaviour)?; } + SubCommand::ToggleFloatOverride => { + send_message(&SocketMessage::ToggleFloatOverride)?; + } + SubCommand::ToggleWorkspaceWindowContainerBehaviour => { + send_message(&SocketMessage::ToggleWorkspaceWindowContainerBehaviour)?; + } + SubCommand::ToggleWorkspaceFloatOverride => { + send_message(&SocketMessage::ToggleWorkspaceFloatOverride)?; + } SubCommand::WindowHidingBehaviour(arg) => { send_message(&SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour))?; } From 4f0e204a84394ca36c16f5f663213e2f6f91f88f Mon Sep 17 00:00:00 2001 From: alex-ds13 <145657253+alex-ds13@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:48:23 +0100 Subject: [PATCH 55/86] fix(wm): check exhaustively for ws emptiness This commit creates a new function for the workspaces to check if they are empty or not. This function properly accounts for maximized windows, monocle windows and floating windows. This should fix the cases where the WM was checking if the workspace was empty to focus the desktop in order to loose focus from previously focused window. Previously it wasn't checking for floating windows so it cause continues focus flickering when there were only floating windows on the workspace. --- komorebi/src/window_manager.rs | 2 +- komorebi/src/workspace.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 4631ea7cc..949434dfe 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -852,7 +852,7 @@ impl WindowManager { } } } else { - if self.focused_workspace()?.containers().is_empty() { + if self.focused_workspace()?.is_empty() { let desktop_window = Window::from(WindowsApi::desktop_window()?); match WindowsApi::raise_and_focus_window(desktop_window.hwnd) { diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index a7392159d..18f1d5e13 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -597,6 +597,13 @@ impl Workspace { Ok(false) } + pub fn is_empty(&self) -> bool { + self.containers().is_empty() + && self.maximized_window().is_none() + && self.monocle_container().is_none() + && self.floating_windows().is_empty() + } + pub fn contains_window(&self, hwnd: isize) -> bool { for container in self.containers() { if container.contains_window(hwnd) { From 1406dbf11a22c8e0cf17c230e11e5f04b38c3ebc Mon Sep 17 00:00:00 2001 From: alex-ds13 <145657253+alex-ds13@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:04:10 +0100 Subject: [PATCH 56/86] fix(wm): allow cross-monitor floating window moves This commit changes the `move_container_to_monitor` from the WM to allow moving floating windows as well. It also adds a new method `move_to_area` to the `Window` that allows moving a window from one monitor to another keeping its size. --- komorebi/src/window.rs | 25 ++++++++++++++++ komorebi/src/window_manager.rs | 52 +++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 912becb9d..75f472af9 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -159,6 +159,31 @@ impl Window { HWND(windows_api::as_ptr!(self.hwnd)) } + pub fn move_to_area(&mut self, current_area: &Rect, target_area: &Rect) -> Result<()> { + let current_rect = WindowsApi::window_rect(self.hwnd)?; + let x_diff = target_area.left - current_area.left; + let y_diff = target_area.top - current_area.top; + let x_ratio = f32::abs((target_area.right as f32) / (current_area.right as f32)); + let y_ratio = f32::abs((target_area.bottom as f32) / (current_area.bottom as f32)); + let window_relative_x = current_rect.left - current_area.left; + let window_relative_y = current_rect.top - current_area.top; + let corrected_relative_x = (window_relative_x as f32 * x_ratio) as i32; + let corrected_relative_y = (window_relative_y as f32 * y_ratio) as i32; + let window_x = current_area.left + corrected_relative_x; + let window_y = current_area.top + corrected_relative_y; + + let new_rect = Rect { + left: x_diff + window_x, + top: y_diff + window_y, + right: current_rect.right, + bottom: current_rect.bottom, + }; + //TODO: We might need to take into account the differences in DPI for the new_rect, unless + //we can use the xy ratios above to the right/bottom (width/height of window) as well? + + self.set_position(&new_rect, true) + } + pub fn center(&mut self, work_area: &Rect) -> Result<()> { let half_width = work_area.right / 2; let half_weight = work_area.bottom / 2; diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 949434dfe..4761d10d4 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1177,6 +1177,8 @@ impl WindowManager { .focused_monitor_mut() .ok_or_else(|| anyhow!("there is no monitor"))?; + let current_area = *monitor.work_area_size(); + let workspace = monitor .focused_workspace_mut() .ok_or_else(|| anyhow!("there is no workspace"))?; @@ -1185,16 +1187,23 @@ impl WindowManager { 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 container_hwnds = container - .windows() + let foreground_hwnd = WindowsApi::foreground_window()?; + let floating_window_index = workspace + .floating_windows() .iter() - .map(|w| w.hwnd) - .collect::>(); + .position(|w| w.hwnd == foreground_hwnd); + let floating_window = floating_window_index.map(|idx| { + workspace.floating_windows_mut().remove(idx) + }); + let container = if floating_window_index.is_none() { + Some(workspace + .remove_focused_container() + .ok_or_else(|| anyhow!("there is no container"))?) + } else { + None + }; monitor.update_focused_workspace(offset)?; let target_monitor = self @@ -1202,18 +1211,33 @@ impl WindowManager { .get_mut(monitor_idx) .ok_or_else(|| anyhow!("there is no monitor"))?; - target_monitor.add_container(container, workspace_idx)?; - if let Some(workspace_idx) = workspace_idx { target_monitor.focus_workspace(workspace_idx)?; } - - if let Some(workspace) = target_monitor.focused_workspace() { - if !*workspace.tile() { - for hwnd in container_hwnds { - Window::from(hwnd).center(target_monitor.work_area_size())?; + let target_workspace = target_monitor.focused_workspace_mut() + .ok_or_else(|| anyhow!("there is no focused workspace on target monitor"))?; + + if let Some(window) = floating_window { + target_workspace.floating_windows_mut().push(window); + Window::from(window.hwnd).move_to_area(¤t_area, target_monitor.work_area_size())?; + } else if let Some(container) = container { + let container_hwnds = container + .windows() + .iter() + .map(|w| w.hwnd) + .collect::>(); + + target_monitor.add_container(container, workspace_idx)?; + + if let Some(workspace) = target_monitor.focused_workspace() { + if !*workspace.tile() { + for hwnd in container_hwnds { + Window::from(hwnd).move_to_area(¤t_area, target_monitor.work_area_size())?; + } } } + } else { + bail!("failed to find a window to move"); } target_monitor.load_focused_workspace(mouse_follows_focus)?; From 929c1c92b7e1fe874b49dcfcc4ae7fc646bcc4b1 Mon Sep 17 00:00:00 2001 From: alex-ds13 <145657253+alex-ds13@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:29:02 +0100 Subject: [PATCH 57/86] feat(config): add floating border colour opt --- komorebi/src/static_config.rs | 7 +++++++ komorebi/src/window_manager.rs | 3 +++ 2 files changed, 10 insertions(+) diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 1e9ee0ad7..dd1385f1e 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -96,6 +96,8 @@ pub struct BorderColours { pub stack: Option, /// Border colour when the container is in monocle mode pub monocle: Option, + /// Border colour when the container is in floating mode + pub floating: Option, /// Border colour when the container is unfocused pub unfocused: Option, } @@ -525,6 +527,7 @@ impl From<&WindowManager> for StaticConfig { single: Option::from(Colour::from(border_manager::FOCUSED.load(Ordering::SeqCst))), stack: Option::from(Colour::from(border_manager::STACK.load(Ordering::SeqCst))), monocle: Option::from(Colour::from(border_manager::MONOCLE.load(Ordering::SeqCst))), + floating: Option::from(Colour::from(border_manager::FLOATING.load(Ordering::SeqCst))), unfocused: Option::from(Colour::from( border_manager::UNFOCUSED.load(Ordering::SeqCst), )), @@ -652,6 +655,10 @@ impl StaticConfig { border_manager::MONOCLE.store(u32::from(monocle), Ordering::SeqCst); } + if let Some(floating) = colours.floating { + border_manager::FLOATING.store(u32::from(floating), Ordering::SeqCst); + } + if let Some(unfocused) = colours.unfocused { border_manager::UNFOCUSED.store(u32::from(unfocused), Ordering::SeqCst); } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 4761d10d4..3f69e233a 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -167,6 +167,9 @@ impl Default for GlobalState { monocle: Option::from(Colour::Rgb(Rgb::from( border_manager::MONOCLE.load(Ordering::SeqCst), ))), + floating: Option::from(Colour::Rgb(Rgb::from( + border_manager::FLOATING.load(Ordering::SeqCst), + ))), unfocused: Option::from(Colour::Rgb(Rgb::from( border_manager::UNFOCUSED.load(Ordering::SeqCst), ))), From f07e18d6e7dc529d7db144cf75744a4cf1a9b12f Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 11 Oct 2024 09:44:36 -0700 Subject: [PATCH 58/86] docs(schema): update all json schemas --- schema.asc.json | 8 +- schema.bar.json | 608 ++++++++++++++++++++++++++++++++++++++++++++---- schema.json | 517 ++++++++++++++++++++++++++++++++++------ 3 files changed, 1017 insertions(+), 116 deletions(-) diff --git a/schema.asc.json b/schema.asc.json index fb5f20120..1dffd1c5f 100644 --- a/schema.asc.json +++ b/schema.asc.json @@ -13,7 +13,10 @@ "name" ], "properties": { - "float_identifiers": { + "identifier": { + "$ref": "#/definitions/IdWithIdentifier" + }, + "ignore_identifiers": { "type": [ "array", "null" @@ -22,9 +25,6 @@ "$ref": "#/definitions/MatchingRule" } }, - "identifier": { - "$ref": "#/definitions/IdWithIdentifier" - }, "name": { "type": "string" }, diff --git a/schema.bar.json b/schema.bar.json index 3c0348de9..dd176d34d 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -73,6 +73,99 @@ "enable": { "description": "Enable the Battery widget", "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Cpu" + ], + "properties": { + "Cpu": { + "type": "object", + "required": [ + "enable" + ], + "properties": { + "data_refresh_interval": { + "description": "Data refresh interval (default: 10 seconds)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "enable": { + "description": "Enable the Cpu widget", + "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -141,6 +234,39 @@ "additionalProperties": false } ] + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -276,6 +402,39 @@ "enable": { "description": "Enable the Memory widget", "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -306,6 +465,39 @@ "description": "Enable the Network widget", "type": "boolean" }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] + }, "network_activity_fill_characters": { "description": "Characters to reserve for network activity data", "type": "integer", @@ -346,6 +538,39 @@ "enable": { "description": "Enable the Storage widget", "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -400,6 +625,39 @@ "additionalProperties": false } ] + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -461,6 +719,52 @@ } } }, + "position": { + "description": "Bar positioning options", + "type": "object", + "properties": { + "end": { + "description": "The desired size of the bar from the starting position (usually monitor width x desired height)", + "type": "object", + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "description": "X coordinate", + "type": "number", + "format": "float" + }, + "y": { + "description": "Y coordinate", + "type": "number", + "format": "float" + } + } + }, + "start": { + "description": "The desired starting position of the bar (0,0 = top left of the screen)", + "type": "object", + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "description": "X coordinate", + "type": "number", + "format": "float" + }, + "y": { + "description": "Y coordinate", + "type": "number", + "format": "float" + } + } + } + } + }, "right_widgets": { "description": "Right side widgets (ordered left-to-right)", "type": "array", @@ -487,6 +791,99 @@ "enable": { "description": "Enable the Battery widget", "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Cpu" + ], + "properties": { + "Cpu": { + "type": "object", + "required": [ + "enable" + ], + "properties": { + "data_refresh_interval": { + "description": "Data refresh interval (default: 10 seconds)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "enable": { + "description": "Enable the Cpu widget", + "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -555,6 +952,39 @@ "additionalProperties": false } ] + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -690,6 +1120,39 @@ "enable": { "description": "Enable the Memory widget", "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -720,6 +1183,39 @@ "description": "Enable the Network widget", "type": "boolean" }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] + }, "network_activity_fill_characters": { "description": "Characters to reserve for network activity data", "type": "integer", @@ -760,6 +1256,39 @@ "enable": { "description": "Enable the Storage widget", "type": "boolean" + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -814,6 +1343,39 @@ "additionalProperties": false } ] + }, + "label_prefix": { + "description": "Display label prefix", + "oneOf": [ + { + "description": "Show no prefix", + "type": "string", + "enum": [ + "None" + ] + }, + { + "description": "Show an icon", + "type": "string", + "enum": [ + "Icon" + ] + }, + { + "description": "Show text", + "type": "string", + "enum": [ + "Text" + ] + }, + { + "description": "Show an icon and text", + "type": "string", + "enum": [ + "IconAndText" + ] + } + ] } } } @@ -1194,52 +1756,6 @@ } } ] - }, - "viewport": { - "description": "Viewport options (see: https://docs.rs/egui/latest/egui/viewport/struct.ViewportBuilder.html)", - "type": "object", - "properties": { - "inner_size": { - "description": "The desired size of the bar from the starting position (usually monitor width x desired height)", - "type": "object", - "required": [ - "x", - "y" - ], - "properties": { - "x": { - "description": "X coordinate", - "type": "number", - "format": "float" - }, - "y": { - "description": "Y coordinate", - "type": "number", - "format": "float" - } - } - }, - "position": { - "description": "The desired starting position of the bar (0,0 = top left of the screen)", - "type": "object", - "required": [ - "x", - "y" - ], - "properties": { - "x": { - "description": "X coordinate", - "type": "number", - "format": "float" - }, - "y": { - "description": "Y coordinate", - "type": "number", - "format": "float" - } - } - } - } } } } diff --git a/schema.json b/schema.json index e6673284d..05ace759f 100644 --- a/schema.json +++ b/schema.json @@ -69,6 +69,13 @@ "description": "Path to applications.yaml from komorebi-application-specific-configurations (default: None)", "type": "string" }, + "bar_configurations": { + "description": "Komorebi status bar configuration files for multiple instances on different monitors", + "type": "array", + "items": { + "type": "string" + } + }, "border": { "description": "Display an active window border (default: false)", "type": "boolean" @@ -77,6 +84,45 @@ "description": "Active window border colours for different container types", "type": "object", "properties": { + "floating": { + "description": "Border colour when the container is in floating mode", + "anyOf": [ + { + "description": "Colour represented as RGB", + "type": "object", + "required": [ + "b", + "g", + "r" + ], + "properties": { + "b": { + "description": "Blue", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "g": { + "description": "Green", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "r": { + "description": "Red", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + { + "description": "Colour represented as Hex", + "type": "string", + "format": "color-hex" + } + ] + }, "monocle": { "description": "Border colour when the container is in monocle mode", "anyOf": [ @@ -445,8 +491,12 @@ "type": "string" } }, - "float_rules": { - "description": "Individual window floating rules", + "float_override": { + "description": "Enable or disable float override, which makes it so every new window opens in floating mode (default: false)", + "type": "boolean" + }, + "floating_applications": { + "description": "Identify applications which should be managed as floating windows", "type": "array", "items": { "anyOf": [ @@ -579,6 +629,89 @@ } } }, + "ignore_rules": { + "description": "Individual window floating rules", + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } + }, + { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } + } + } + ] + } + }, "invisible_borders": { "description": "DEPRECATED from v0.1.22: no longer required", "type": "object", @@ -929,44 +1062,91 @@ "type": "string" } }, + "float_override": { + "description": "Enable or disable float override, which makes it so every new window opens in floating mode (default: false)", + "type": "boolean" + }, "initial_workspace_rules": { "description": "Initial workspace application rules", "type": "array", "items": { - "type": "object", - "required": [ - "id", - "kind" - ], - "properties": { - "id": { - "type": "string" + "anyOf": [ + { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } }, - "kind": { - "type": "string", - "enum": [ - "Exe", - "Class", - "Title", - "Path" - ] - }, - "matching_strategy": { - "type": "string", - "enum": [ - "Legacy", - "Equals", - "StartsWith", - "EndsWith", - "Contains", - "Regex", - "DoesNotEndWith", - "DoesNotStartWith", - "DoesNotEqual", - "DoesNotContain" - ] + { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } + } } - } + ] } }, "layout": { @@ -1004,6 +1184,25 @@ "description": "Name", "type": "string" }, + "window_container_behaviour": { + "description": "Determine what happens when a new window is opened (default: Create)", + "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", @@ -1013,40 +1212,83 @@ "description": "Permanent workspace application rules", "type": "array", "items": { - "type": "object", - "required": [ - "id", - "kind" - ], - "properties": { - "id": { - "type": "string" - }, - "kind": { - "type": "string", - "enum": [ - "Exe", - "Class", - "Title", - "Path" - ] + "anyOf": [ + { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } }, - "matching_strategy": { - "type": "string", - "enum": [ - "Legacy", - "Equals", - "StartsWith", - "EndsWith", - "Contains", - "Regex", - "DoesNotEndWith", - "DoesNotStartWith", - "DoesNotEqual", - "DoesNotContain" - ] + { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } + } } - } + ] } } } @@ -1147,6 +1389,95 @@ "type": "integer", "format": "int32" }, + "slow_application_compensation_time": { + "description": "How long to wait when compensating for slow applications, in milliseconds (default: 20)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "slow_application_identifiers": { + "description": "Identify applications which are slow to send initial event notifications", + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } + }, + { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title", + "Path" + ] + }, + "matching_strategy": { + "type": "string", + "enum": [ + "Legacy", + "Equals", + "StartsWith", + "EndsWith", + "Contains", + "Regex", + "DoesNotEndWith", + "DoesNotStartWith", + "DoesNotEqual", + "DoesNotContain" + ] + } + } + } + } + ] + } + }, "stackbar": { "description": "Stackbar configuration options", "type": "object", @@ -1355,6 +1686,38 @@ "Crust" ] }, + "floating_border": { + "description": "Border colour when the window is floating (default: Yellow)", + "type": "string", + "enum": [ + "Rosewater", + "Flamingo", + "Pink", + "Mauve", + "Red", + "Maroon", + "Peach", + "Yellow", + "Green", + "Teal", + "Sky", + "Sapphire", + "Blue", + "Lavender", + "Text", + "Subtext1", + "Subtext0", + "Overlay2", + "Overlay1", + "Overlay0", + "Surface2", + "Surface1", + "Surface0", + "Base", + "Mantle", + "Crust" + ] + }, "monocle_border": { "description": "Border colour when the container is in monocle mode (default: Pink)", "type": "string", @@ -1627,6 +1990,28 @@ "Base0F" ] }, + "floating_border": { + "description": "Border colour when the window is floating (default: Base09)", + "type": "string", + "enum": [ + "Base00", + "Base01", + "Base02", + "Base03", + "Base04", + "Base05", + "Base06", + "Base07", + "Base08", + "Base09", + "Base0A", + "Base0B", + "Base0C", + "Base0D", + "Base0E", + "Base0F" + ] + }, "monocle_border": { "description": "Border colour when the container is in monocle mode (default: Base0F)", "type": "string", From 97e8c36b5ebe0c6eb0c7271c0e85528479740090 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 11 Oct 2024 10:30:35 -0700 Subject: [PATCH 59/86] chore(cargo): +nightly fmt --- komorebi-bar/src/battery.rs | 2 +- komorebi-bar/src/date.rs | 2 +- komorebi-bar/src/storage.rs | 2 +- komorebi/src/core/mod.rs | 16 +++++++--- komorebi/src/process_command.rs | 32 +++++++++++++------- komorebi/src/process_event.rs | 7 +++-- komorebi/src/static_config.rs | 12 ++++++-- komorebi/src/window_manager.rs | 53 ++++++++++++++++++++------------- komorebi/src/workspace.rs | 8 ++--- 9 files changed, 85 insertions(+), 49 deletions(-) diff --git a/komorebi-bar/src/battery.rs b/komorebi-bar/src/battery.rs index 0925b109e..3f1e198ee 100644 --- a/komorebi-bar/src/battery.rs +++ b/komorebi-bar/src/battery.rs @@ -43,7 +43,7 @@ impl From for Battery { State::Discharging => state = Some(BatteryState::Discharging), _ => {} } - + last_state = match prefix { LabelPrefix::Text | LabelPrefix::IconAndText => { format!("BAT: {percentage:.0}%") diff --git a/komorebi-bar/src/date.rs b/komorebi-bar/src/date.rs index 9a2727c39..666fb2f13 100644 --- a/komorebi-bar/src/date.rs +++ b/komorebi-bar/src/date.rs @@ -112,7 +112,7 @@ impl BarWidget for Date { if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix { output.insert_str(0, "DATE: "); } - + layout_job.append( &output, 10.0, diff --git a/komorebi-bar/src/storage.rs b/komorebi-bar/src/storage.rs index c81f66da8..a4498dc51 100644 --- a/komorebi-bar/src/storage.rs +++ b/komorebi-bar/src/storage.rs @@ -62,7 +62,7 @@ impl Storage { let total = disk.total_space(); let available = disk.available_space(); let used = total - available; - + disks.push(match self.label_prefix { LabelPrefix::Text | LabelPrefix::IconAndText => { format!("{} {}%", mount.to_string_lossy(), (used * 100) / total) diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 7cbe78363..93f785bdd 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -345,9 +345,7 @@ pub enum FocusFollowsMouseImplementation { Windows, } -#[derive( - Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, -)] +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)] pub struct WindowManagementBehaviour { /// The current WindowContainerBehaviour to be used pub current_behaviour: WindowContainerBehaviour, @@ -358,7 +356,17 @@ pub struct WindowManagementBehaviour { } #[derive( - Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, PartialEq + Clone, + Copy, + Debug, + Default, + Serialize, + Deserialize, + Display, + EnumString, + ValueEnum, + JsonSchema, + PartialEq, )] pub enum WindowContainerBehaviour { /// Create a new container for each new window diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index ac0aa2425..b3525c0b1 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -1348,30 +1348,39 @@ impl WindowManager { SocketMessage::ToggleWindowContainerBehaviour => { match self.window_management_behaviour.current_behaviour { WindowContainerBehaviour::Create => { - self.window_management_behaviour.current_behaviour = WindowContainerBehaviour::Append; + self.window_management_behaviour.current_behaviour = + WindowContainerBehaviour::Append; } WindowContainerBehaviour::Append => { - self.window_management_behaviour.current_behaviour = WindowContainerBehaviour::Create; + self.window_management_behaviour.current_behaviour = + WindowContainerBehaviour::Create; } } } SocketMessage::ToggleFloatOverride => { - self.window_management_behaviour.float_override = !self.window_management_behaviour.float_override; + self.window_management_behaviour.float_override = + !self.window_management_behaviour.float_override; } SocketMessage::ToggleWorkspaceWindowContainerBehaviour => { let current_global_behaviour = self.window_management_behaviour.current_behaviour; - if let Some(behaviour) = self.focused_workspace_mut()?.window_container_behaviour_mut() { + if let Some(behaviour) = self + .focused_workspace_mut()? + .window_container_behaviour_mut() + { match behaviour { - WindowContainerBehaviour::Create => *behaviour = WindowContainerBehaviour::Append, - WindowContainerBehaviour::Append => *behaviour = WindowContainerBehaviour::Create, + WindowContainerBehaviour::Create => { + *behaviour = WindowContainerBehaviour::Append + } + WindowContainerBehaviour::Append => { + *behaviour = WindowContainerBehaviour::Create + } } } else { - self.focused_workspace_mut()?.set_window_container_behaviour( - Some(match current_global_behaviour { + self.focused_workspace_mut()? + .set_window_container_behaviour(Some(match current_global_behaviour { WindowContainerBehaviour::Create => WindowContainerBehaviour::Append, WindowContainerBehaviour::Append => WindowContainerBehaviour::Create, - }) - ); + })); }; } SocketMessage::ToggleWorkspaceFloatOverride => { @@ -1379,7 +1388,8 @@ impl WindowManager { if let Some(float_override) = self.focused_workspace_mut()?.float_override_mut() { *float_override = !*float_override; } else { - self.focused_workspace_mut()?.set_float_override(Some(!current_global_override)); + self.focused_workspace_mut()? + .set_float_override(Some(!current_global_override)); }; } SocketMessage::WindowHidingBehaviour(behaviour) => { diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 46fd9e038..71d6e090c 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -333,8 +333,8 @@ impl WindowManager { } if proceed { - let mut behaviour = - self.window_management_behaviour(focused_monitor_idx, focused_workspace_idx); + let mut behaviour = self + .window_management_behaviour(focused_monitor_idx, focused_workspace_idx); let workspace = self.focused_workspace_mut()?; let workspace_contains_window = workspace.contains_window(window.hwnd); let monocle_container = workspace.monocle_container().clone(); @@ -360,7 +360,8 @@ impl WindowManager { } } - behaviour.float_override = behaviour.float_override || (should_float && !matches!(event, WindowManagerEvent::Manage(_))); + behaviour.float_override = behaviour.float_override + || (should_float && !matches!(event, WindowManagerEvent::Manage(_))); if behaviour.float_override { workspace.floating_windows_mut().push(window); diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index dd1385f1e..e3a0d70da 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -527,7 +527,9 @@ impl From<&WindowManager> for StaticConfig { single: Option::from(Colour::from(border_manager::FOCUSED.load(Ordering::SeqCst))), stack: Option::from(Colour::from(border_manager::STACK.load(Ordering::SeqCst))), monocle: Option::from(Colour::from(border_manager::MONOCLE.load(Ordering::SeqCst))), - floating: Option::from(Colour::from(border_manager::FLOATING.load(Ordering::SeqCst))), + floating: Option::from(Colour::from( + border_manager::FLOATING.load(Ordering::SeqCst), + )), unfocused: Option::from(Colour::from( border_manager::UNFOCUSED.load(Ordering::SeqCst), )), @@ -537,7 +539,9 @@ impl From<&WindowManager> for StaticConfig { Self { invisible_borders: None, resize_delta: Option::from(value.resize_delta), - window_container_behaviour: Option::from(value.window_management_behaviour.current_behaviour), + window_container_behaviour: Option::from( + value.window_management_behaviour.current_behaviour, + ), float_override: Option::from(value.window_management_behaviour.float_override), cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour), cross_boundary_behaviour: Option::from(value.cross_boundary_behaviour), @@ -1054,7 +1058,9 @@ impl StaticConfig { virtual_desktop_id: current_virtual_desktop(), work_area_offset: value.global_work_area_offset, window_management_behaviour: WindowManagementBehaviour { - current_behaviour: value.window_container_behaviour.unwrap_or(WindowContainerBehaviour::Create), + current_behaviour: value + .window_container_behaviour + .unwrap_or(WindowContainerBehaviour::Create), float_override: value.float_override.unwrap_or_default(), }, cross_monitor_move_behaviour: value diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 3f69e233a..2d3c7da3c 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -321,19 +321,27 @@ impl WindowManager { ) -> WindowManagementBehaviour { if let Some(monitor) = self.monitors().get(monitor_idx) { if let Some(workspace) = monitor.workspaces().get(workspace_idx) { - let current_behaviour = if let Some(behaviour) = workspace.window_container_behaviour() { - if workspace.containers().is_empty() && matches!(behaviour, WindowContainerBehaviour::Append) { + let current_behaviour = + if let Some(behaviour) = workspace.window_container_behaviour() { + if workspace.containers().is_empty() + && matches!(behaviour, WindowContainerBehaviour::Append) + { + // You can't append to an empty workspace + WindowContainerBehaviour::Create + } else { + *behaviour + } + } else if workspace.containers().is_empty() + && matches!( + self.window_management_behaviour.current_behaviour, + WindowContainerBehaviour::Append + ) + { // You can't append to an empty workspace WindowContainerBehaviour::Create } else { - *behaviour - } - } else if workspace.containers().is_empty() && matches!(self.window_management_behaviour.current_behaviour, WindowContainerBehaviour::Append) { - // You can't append to an empty workspace - WindowContainerBehaviour::Create - } else { - self.window_management_behaviour.current_behaviour - }; + self.window_management_behaviour.current_behaviour + }; let float_override = if let Some(float_override) = workspace.float_override() { *float_override @@ -343,7 +351,7 @@ impl WindowManager { return WindowManagementBehaviour { current_behaviour, - float_override + float_override, }; } } @@ -1190,20 +1198,20 @@ impl WindowManager { bail!("cannot move native maximized window to another monitor or workspace"); } - let foreground_hwnd = WindowsApi::foreground_window()?; let floating_window_index = workspace .floating_windows() .iter() .position(|w| w.hwnd == foreground_hwnd); - let floating_window = floating_window_index.map(|idx| { - workspace.floating_windows_mut().remove(idx) - }); + let floating_window = + floating_window_index.map(|idx| workspace.floating_windows_mut().remove(idx)); let container = if floating_window_index.is_none() { - Some(workspace - .remove_focused_container() - .ok_or_else(|| anyhow!("there is no container"))?) + Some( + workspace + .remove_focused_container() + .ok_or_else(|| anyhow!("there is no container"))?, + ) } else { None }; @@ -1217,12 +1225,14 @@ impl WindowManager { if let Some(workspace_idx) = workspace_idx { target_monitor.focus_workspace(workspace_idx)?; } - let target_workspace = target_monitor.focused_workspace_mut() + let target_workspace = target_monitor + .focused_workspace_mut() .ok_or_else(|| anyhow!("there is no focused workspace on target monitor"))?; if let Some(window) = floating_window { target_workspace.floating_windows_mut().push(window); - Window::from(window.hwnd).move_to_area(¤t_area, target_monitor.work_area_size())?; + Window::from(window.hwnd) + .move_to_area(¤t_area, target_monitor.work_area_size())?; } else if let Some(container) = container { let container_hwnds = container .windows() @@ -1235,7 +1245,8 @@ impl WindowManager { if let Some(workspace) = target_monitor.focused_workspace() { if !*workspace.tile() { for hwnd in container_hwnds { - Window::from(hwnd).move_to_area(¤t_area, target_monitor.work_area_size())?; + Window::from(hwnd) + .move_to_area(¤t_area, target_monitor.work_area_size())?; } } } diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 18f1d5e13..91e54d776 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -598,10 +598,10 @@ impl Workspace { } pub fn is_empty(&self) -> bool { - self.containers().is_empty() - && self.maximized_window().is_none() - && self.monocle_container().is_none() - && self.floating_windows().is_empty() + self.containers().is_empty() + && self.maximized_window().is_none() + && self.monocle_container().is_none() + && self.floating_windows().is_empty() } pub fn contains_window(&self, hwnd: isize) -> bool { From 39b549fa1cc8a9e884cc8d726a453fff52995fe2 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 11 Oct 2024 12:50:46 -0700 Subject: [PATCH 60/86] docs(cli): highlight eol features in start + check --- komorebi/src/static_config.rs | 26 +++++++++++++++++++++++--- komorebic/src/main.rs | 7 +++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index e3a0d70da..f5df1fe36 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -109,13 +109,13 @@ pub struct WorkspaceConfig { /// Layout (default: BSP) #[serde(skip_serializing_if = "Option::is_none")] pub layout: Option, - /// Custom Layout (default: None) + /// END OF LIFE FEATURE: Custom Layout (default: None) #[serde(skip_serializing_if = "Option::is_none")] pub custom_layout: Option, /// Layout rules (default: None) #[serde(skip_serializing_if = "Option::is_none")] pub layout_rules: Option>, - /// Layout rules (default: None) + /// END OF LIFE FEATURE: Custom layout rules (default: None) #[serde(skip_serializing_if = "Option::is_none")] pub custom_layout_rules: Option>, /// Container padding (default: global) @@ -260,7 +260,7 @@ pub struct StaticConfig { /// Determine what happens when commands are sent while an unmanaged window is in the foreground (default: Op) #[serde(skip_serializing_if = "Option::is_none")] pub unmanaged_window_operation_behaviour: Option, - /// Determine focus follows mouse implementation (default: None) + /// END OF LIFE FEATURE: Determine focus follows mouse implementation (default: None) #[serde(skip_serializing_if = "Option::is_none")] pub focus_follows_mouse: Option, /// Enable or disable mouse follows focus (default: true) @@ -431,6 +431,26 @@ pub enum KomorebiTheme { } impl StaticConfig { + pub fn end_of_life(raw: &str) { + let features = vec![ + "focus_follows_mouse", + "custom_layout", + "custom_layout_rules", + ]; + + let mut display = false; + + for feature in features { + if raw.contains(feature) { + display = true; + println!(r#""{feature}" is now end-of-life"#); + } + } + + if display { + println!("\nEnd-of-life features will not receive any further bug fixes or updates; they should not be used\n") + } + } pub fn aliases(raw: &str) { let mut map = HashMap::new(); map.insert("border", ["active_window_border"]); diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index f805de6d2..f3016595e 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -1546,6 +1546,12 @@ fn main() -> Result<()> { // errors let _ = serde_json::from_str::(&config_source)?; + let path = resolve_home_path(static_config)?; + let raw = std::fs::read_to_string(path)?; + StaticConfig::aliases(&raw); + StaticConfig::deprecated(&raw); + StaticConfig::end_of_life(&raw); + if config_whkd.exists() { println!("Found {}; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag\n", config_whkd.to_string_lossy()); } else { @@ -2098,6 +2104,7 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue)) let raw = std::fs::read_to_string(path)?; StaticConfig::aliases(&raw); StaticConfig::deprecated(&raw); + StaticConfig::end_of_life(&raw); } if bar_config.is_some() { From b5c0ae66c01aae39a578c24fff14bcaf3c06cf1d Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 11 Oct 2024 14:14:13 -0700 Subject: [PATCH 61/86] chore(cargo): suppress macro lint warnings --- komorebic/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/komorebic/Cargo.toml b/komorebic/Cargo.toml index bdffc6dd4..ec29e5053 100644 --- a/komorebic/Cargo.toml +++ b/komorebic/Cargo.toml @@ -38,4 +38,7 @@ windows = { workspace = true } [build-dependencies] reqwest = { version = "0.12", features = ["blocking"] } -shadow-rs = { workspace = true } \ No newline at end of file +shadow-rs = { workspace = true } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(FALSE)'] } \ No newline at end of file From dcd1144f8317f147eaba6f139b81f33909cad015 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 11 Oct 2024 15:28:28 -0700 Subject: [PATCH 62/86] fix(cli): update fetch-asc output to use '/' --- komorebic/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index f3016595e..d6fc5e8a1 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -2598,7 +2598,7 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue println!("Latest version of applications.yaml from https://github.com/LGUG2Z/komorebi-application-specific-configuration downloaded\n"); println!( "You can add this to your komorebi.json static configuration file like this: \n\n\"app_specific_configuration_path\": \"{}\"", - output_file.display() + output_file.display().to_string().replace("\\", "/") ); } SubCommand::ApplicationSpecificConfigurationSchema => { From 95fdb64797a04eb12d7e90550be927c4d5c79ff1 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 11 Oct 2024 10:32:01 -0700 Subject: [PATCH 63/86] feat(client): add subscribe_with_options This commit adds a new method, subscribe_with_options to komorebi-client. The first option introduced is to tell komorebi to only send notifications when the window manager state has been changed during the processing of an event. This new subscription option is now used with komorebi-bar to improve rendering and update performance. --- komorebi-bar/src/main.rs | 5 +++- komorebi-client/src/lib.rs | 27 +++++++++++++++++++ komorebi/src/container.rs | 8 +----- komorebi/src/core/mod.rs | 40 ++++++++++++++++++++++++--- komorebi/src/lib.rs | 34 +++++++++++++++++------ komorebi/src/process_command.rs | 26 ++++++++++++++---- komorebi/src/process_event.rs | 17 ++++++++---- komorebi/src/window_manager.rs | 48 +++++++++++++++++++++++++++++++++ 8 files changed, 176 insertions(+), 29 deletions(-) diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index da2b87ea5..f32c5937b 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -22,6 +22,7 @@ use font_loader::system_fonts; use hotwatch::EventKind; use hotwatch::Hotwatch; use komorebi_client::SocketMessage; +use komorebi_client::SubscribeOptions; use schemars::gen::SchemaSettings; use std::io::BufReader; use std::io::Read; @@ -328,7 +329,9 @@ fn main() -> color_eyre::Result<()> { std::thread::spawn(move || { let subscriber_name = format!("komorebi-bar-{}", random_word::gen(random_word::Lang::En)); - let listener = komorebi_client::subscribe(&subscriber_name) + let listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions { + filter_state_changes: true, + }) .expect("could not subscribe to komorebi notifications"); tracing::info!("subscribed to komorebi notifications: \"{}\"", subscriber_name); diff --git a/komorebi-client/src/lib.rs b/komorebi-client/src/lib.rs index 4344266ee..5870a7d2a 100644 --- a/komorebi-client/src/lib.rs +++ b/komorebi-client/src/lib.rs @@ -44,6 +44,7 @@ pub use komorebi::RuleDebug; pub use komorebi::StackbarConfig; pub use komorebi::State; pub use komorebi::StaticConfig; +pub use komorebi::SubscribeOptions; pub use komorebi::TabsConfig; use komorebi::DATA_DIR; @@ -96,3 +97,29 @@ pub fn subscribe(name: &str) -> std::io::Result { Ok(listener) } + +pub fn subscribe_with_options( + name: &str, + options: SubscribeOptions, +) -> std::io::Result { + let socket = DATA_DIR.join(name); + + match std::fs::remove_file(&socket) { + Ok(()) => {} + Err(error) => match error.kind() { + std::io::ErrorKind::NotFound => {} + _ => { + return Err(error); + } + }, + }; + + let listener = UnixListener::bind(&socket)?; + + send_message(&SocketMessage::AddSubscriberSocketWithOptions( + name.to_string(), + options, + ))?; + + Ok(listener) +} diff --git a/komorebi/src/container.rs b/komorebi/src/container.rs index 20283a252..6e9f07ef2 100644 --- a/komorebi/src/container.rs +++ b/komorebi/src/container.rs @@ -9,7 +9,7 @@ use serde::Serialize; use crate::ring::Ring; use crate::window::Window; -#[derive(Debug, Clone, Serialize, Deserialize, Getters, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters, JsonSchema)] pub struct Container { #[getset(get = "pub")] id: String, @@ -27,12 +27,6 @@ impl Default for Container { } } -impl PartialEq for Container { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - impl Container { pub fn hide(&self, omit: Option) { for window in self.windows().iter().rev() { diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 93f785bdd..ee9929016 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -196,6 +196,7 @@ pub enum SocketMessage { RemoveTitleBar(ApplicationIdentifier, String), ToggleTitleBars, AddSubscriberSocket(String), + AddSubscriberSocketWithOptions(String, SubscribeOptions), RemoveSubscriberSocket(String), AddSubscriberPipe(String), RemoveSubscriberPipe(String), @@ -221,6 +222,12 @@ impl FromStr for SocketMessage { } } +#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +pub struct SubscribeOptions { + /// Only emit notifications when the window manager state has changed + pub filter_state_changes: bool, +} + #[derive(Debug, Copy, Clone, Eq, PartialEq, Display, Serialize, Deserialize, JsonSchema)] pub enum StackbarMode { Always, @@ -336,7 +343,16 @@ pub enum ApplicationIdentifier { } #[derive( - Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, + Copy, + Clone, + Debug, + PartialEq, + Serialize, + Deserialize, + Display, + EnumString, + ValueEnum, + JsonSchema, )] pub enum FocusFollowsMouseImplementation { /// A custom FFM implementation (slightly more CPU-intensive) @@ -377,7 +393,16 @@ pub enum WindowContainerBehaviour { } #[derive( - Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, + Clone, + Copy, + Debug, + PartialEq, + Serialize, + Deserialize, + Display, + EnumString, + ValueEnum, + JsonSchema, )] pub enum MoveBehaviour { /// Swap the window container with the window container at the edge of the adjacent monitor @@ -411,7 +436,16 @@ pub enum HidingBehaviour { } #[derive( - Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, + Clone, + Copy, + Debug, + PartialEq, + Serialize, + Deserialize, + Display, + EnumString, + ValueEnum, + JsonSchema, )] pub enum OperationBehaviour { /// Process komorebic commands on temporarily unmanaged/floated windows diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index b001e5776..b7d318c99 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -177,6 +177,8 @@ lazy_static! { Arc::new(Mutex::new(HashMap::new())); pub static ref SUBSCRIPTION_SOCKETS: Arc>> = Arc::new(Mutex::new(HashMap::new())); + pub static ref SUBSCRIPTION_SOCKET_OPTIONS: Arc>> = + Arc::new(Mutex::new(HashMap::new())); static ref TCP_CONNECTIONS: Arc>> = Arc::new(Mutex::new(HashMap::new())); static ref HIDING_BEHAVIOUR: Arc> = @@ -297,18 +299,34 @@ pub struct Notification { pub state: State, } -pub fn notify_subscribers(notification: &str) -> Result<()> { +pub fn notify_subscribers(notification: Notification, state_has_been_modified: bool) -> Result<()> { + let is_subscription_event = matches!( + notification.event, + NotificationEvent::Socket(SocketMessage::AddSubscriberSocket(_)) + | NotificationEvent::Socket(SocketMessage::AddSubscriberSocketWithOptions(_, _)) + ); + + let notification = &serde_json::to_string(¬ification)?; let mut stale_sockets = vec![]; let mut sockets = SUBSCRIPTION_SOCKETS.lock(); + let options = SUBSCRIPTION_SOCKET_OPTIONS.lock(); for (socket, path) in &mut *sockets { - match UnixStream::connect(path) { - Ok(mut stream) => { - tracing::debug!("pushed notification to subscriber: {socket}"); - stream.write_all(notification.as_bytes())?; - } - Err(_) => { - stale_sockets.push(socket.clone()); + let apply_state_filter = (*options) + .get(socket) + .copied() + .unwrap_or_default() + .filter_state_changes; + + if !apply_state_filter || state_has_been_modified || is_subscription_event { + match UnixStream::connect(path) { + Ok(mut stream) => { + tracing::debug!("pushed notification to subscriber: {socket}"); + stream.write_all(notification.as_bytes())?; + } + Err(_) => { + stale_sockets.push(socket.clone()); + } } } } diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index b3525c0b1..0e79ee8cc 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -61,6 +61,7 @@ use crate::winevent_listener; use crate::GlobalState; use crate::Notification; use crate::NotificationEvent; +use crate::State; use crate::ANIMATION_DURATION; use crate::ANIMATION_ENABLED; use crate::ANIMATION_FPS; @@ -79,6 +80,7 @@ use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; use crate::REMOVE_TITLEBARS; use crate::SUBSCRIPTION_PIPES; use crate::SUBSCRIPTION_SOCKETS; +use crate::SUBSCRIPTION_SOCKET_OPTIONS; use crate::TCP_CONNECTIONS; use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; use crate::WINDOWS_11; @@ -187,6 +189,10 @@ impl WindowManager { } } + #[allow(clippy::useless_asref)] + // We don't have From implemented for &mut WindowManager + let initial_state = State::from(self.as_ref()); + match message { SocketMessage::CycleFocusWorkspace(_) | SocketMessage::FocusWorkspaceNumber(_) => { if let Some(monitor) = self.focused_monitor_mut() { @@ -1319,6 +1325,14 @@ impl WindowManager { let socket_path = DATA_DIR.join(socket); sockets.insert(socket.clone(), socket_path); } + SocketMessage::AddSubscriberSocketWithOptions(ref socket, options) => { + let mut sockets = SUBSCRIPTION_SOCKETS.lock(); + let socket_path = DATA_DIR.join(socket); + sockets.insert(socket.clone(), socket_path); + + let mut socket_options = SUBSCRIPTION_SOCKET_OPTIONS.lock(); + socket_options.insert(socket.clone(), options); + } SocketMessage::RemoveSubscriberSocket(ref socket) => { let mut sockets = SUBSCRIPTION_SOCKETS.lock(); sockets.remove(socket); @@ -1574,12 +1588,14 @@ impl WindowManager { | SocketMessage::IdentifyBorderOverflowApplication(_, _) => {} }; - let notification = Notification { - event: NotificationEvent::Socket(message.clone()), - state: self.as_ref().into(), - }; + notify_subscribers( + Notification { + event: NotificationEvent::Socket(message.clone()), + state: self.as_ref().into(), + }, + initial_state.has_been_modified(self.as_ref()), + )?; - notify_subscribers(&serde_json::to_string(¬ification)?)?; border_manager::send_notification(None); transparency_manager::send_notification(); stackbar_manager::send_notification(); diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 71d6e090c..8b05fd971 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -32,6 +32,7 @@ use crate::workspace_reconciliator::ALT_TAB_HWND; use crate::workspace_reconciliator::ALT_TAB_HWND_INSTANT; use crate::Notification; use crate::NotificationEvent; +use crate::State; use crate::DATA_DIR; use crate::FLOATING_APPLICATIONS; use crate::HIDDEN_HWNDS; @@ -122,6 +123,10 @@ impl WindowManager { } } + #[allow(clippy::useless_asref)] + // We don't have From implemented for &mut WindowManager + let initial_state = State::from(self.as_ref()); + // Make sure we have the most recently focused monitor from any event match event { WindowManagerEvent::FocusChange(_, window) @@ -670,12 +675,14 @@ impl WindowManager { serde_json::to_writer_pretty(&file, &known_hwnds)?; - let notification = Notification { - event: NotificationEvent::WindowManager(event), - state: self.as_ref().into(), - }; + notify_subscribers( + Notification { + event: NotificationEvent::WindowManager(event), + state: self.as_ref().into(), + }, + initial_state.has_been_modified(self.as_ref()), + )?; - notify_subscribers(&serde_json::to_string(¬ification)?)?; border_manager::send_notification(Some(event.hwnd())); transparency_manager::send_notification(); stackbar_manager::send_notification(); diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 2d3c7da3c..b44c0e9a4 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -122,6 +122,54 @@ pub struct State { pub has_pending_raise_op: bool, } +impl State { + pub fn has_been_modified(&self, wm: &WindowManager) -> bool { + let new = Self::from(wm); + + if self.monitors != new.monitors { + return true; + } + + if self.is_paused != new.is_paused { + return true; + } + + if self.new_window_behaviour != new.new_window_behaviour { + return true; + } + + if self.float_override != new.float_override { + return true; + } + + if self.cross_monitor_move_behaviour != new.cross_monitor_move_behaviour { + return true; + } + + if self.unmanaged_window_operation_behaviour != new.unmanaged_window_operation_behaviour { + return true; + } + + if self.work_area_offset != new.work_area_offset { + return true; + } + + if self.focus_follows_mouse != new.focus_follows_mouse { + return true; + } + + if self.mouse_follows_focus != new.mouse_follows_focus { + return true; + } + + if self.has_pending_raise_op != new.has_pending_raise_op { + return true; + } + + false + } +} + #[allow(clippy::struct_excessive_bools)] #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct GlobalState { From f1eae161755ccdbd7c97efcb4e1ba8aacf067d03 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 2 Nov 2024 18:40:30 -0700 Subject: [PATCH 64/86] chore(release): v0.1.30 --- Cargo.lock | 260 ++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 2 +- docs/komorebi.bar.example.json | 2 +- docs/komorebi.example.json | 2 +- komorebi/src/static_config.rs | 2 + 6 files changed, 128 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64f0f999f..fdd581158 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,9 +50,9 @@ dependencies = [ [[package]] name = "accesskit_macos" -version = "0.17.3" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49509c722e8da39e6c569f7d13ec51620208988913e738abbc67e3c65f06e6d5" +checksum = "bfc6c1ecd82053d127961ad80a8beaa6004fb851a3a5b96506d7a6bd462403f6" dependencies = [ "accesskit", "accesskit_consumer", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "accesskit_winit" -version = "0.22.3" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9987e852fe7e4e5a493f8c8af0b729b47da2750f0dea10a4c8984fe1117ebaec" +checksum = "aea3522719f1c44564d03e9469a8e2f3a98b3a8a880bd66d0789c6b9c4a669dd" dependencies = [ "accesskit", "accesskit_macos", @@ -222,9 +222,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -237,43 +237,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" [[package]] name = "arbitrary" @@ -304,7 +304,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -439,7 +439,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -474,7 +474,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -707,9 +707,9 @@ dependencies = [ [[package]] name = "built" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" +checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" [[package]] name = "bumpalo" @@ -734,7 +734,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -751,9 +751,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "calloop" @@ -792,9 +792,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" dependencies = [ "jobserver", "libc", @@ -896,7 +896,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -968,9 +968,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "com" @@ -1458,9 +1458,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if 1.0.0", ] @@ -1489,7 +1489,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -1510,7 +1510,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -1591,15 +1591,14 @@ dependencies = [ [[package]] name = "exr" -version = "1.72.0" +version = "1.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" dependencies = [ "bit_field", - "flume", "half", "lebe", - "miniz_oxide 0.7.4", + "miniz_oxide 0.8.0", "rayon-core", "smallvec", "zune-inflate", @@ -1623,9 +1622,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" +checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" dependencies = [ "simd-adler32", ] @@ -1667,15 +1666,6 @@ dependencies = [ "miniz_oxide 0.8.0", ] -[[package]] -name = "flume" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" -dependencies = [ - "spin", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1722,7 +1712,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -1799,9 +1789,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" dependencies = [ "fastrand", "futures-core", @@ -1818,7 +1808,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -1890,7 +1880,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2291,9 +2281,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -2382,9 +2372,9 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" [[package]] name = "immutable-chunkmap" -version = "2.0.5" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4419f022e55cc63d5bbd6b44b71e1d226b9c9480a47824c706e9d54e5c40c5eb" +checksum = "12f97096f508d54f8f8ab8957862eee2ccd628847b6217af1a335e1c44dee578" dependencies = [ "arrayvec", ] @@ -2433,7 +2423,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -2725,9 +2715,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libfuzzer-sys" @@ -2759,7 +2749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -2925,7 +2915,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -3303,7 +3293,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -3364,7 +3354,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -3605,9 +3595,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.67" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8cefcf97f41316955f9294cd61f639bdcfa9f2f230faac6cb896aa8ab64704" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if 1.0.0", @@ -3626,7 +3616,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -3766,29 +3756,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -3909,14 +3899,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -3937,7 +3927,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4073,9 +4063,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f0bfd976333248de2078d350bfdf182ff96e168a24d23d2436cef320dd4bdd" +checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" dependencies = [ "avif-serialize", "imgref", @@ -4192,9 +4182,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64", "bytes", @@ -4269,9 +4259,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" dependencies = [ "bitflags 2.6.0", "errno", @@ -4282,9 +4272,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.15" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "once_cell", "rustls-pki-types", @@ -4370,7 +4360,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4423,22 +4413,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4449,7 +4439,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4483,7 +4473,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4703,9 +4693,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] [[package]] name = "spirv" @@ -4771,7 +4758,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -4814,9 +4801,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.85" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -4941,22 +4928,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5065,9 +5052,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", @@ -5183,7 +5170,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5304,12 +5291,9 @@ dependencies = [ [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -5477,7 +5461,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -5511,7 +5495,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5538,9 +5522,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.6" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" dependencies = [ "bitflags 2.6.0", "rustix", @@ -5561,9 +5545,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.6" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a94697e66e76c85923b0d28a0c251e8f0666f58fc47d316c0f4da6da75d37cb" +checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" dependencies = [ "rustix", "wayland-client", @@ -5572,9 +5556,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.4" +version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5755d77ae9040bb872a25026555ce4cb0ae75fd923e90d25fba07d81057de0" +checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" dependencies = [ "bitflags 2.6.0", "wayland-backend", @@ -5584,9 +5568,9 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0a41a6875e585172495f7a96dfa42ca7e0213868f4f15c313f7c33221a7eff" +checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" dependencies = [ "bitflags 2.6.0", "wayland-backend", @@ -5597,9 +5581,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad87b5fd1b1d3ca2f792df8f686a2a11e3fe1077b71096f7a175ab699f89109" +checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" dependencies = [ "bitflags 2.6.0", "wayland-backend", @@ -5778,9 +5762,9 @@ dependencies = [ [[package]] name = "which" -version = "6.0.3" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +checksum = "c9cad3279ade7346b96e38731a641d7343dd6a53d55083dd54eadfa5a1b38c6b" dependencies = [ "either", "home", @@ -5918,7 +5902,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5929,7 +5913,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5940,7 +5924,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -5951,7 +5935,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -6422,7 +6406,7 @@ checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "zbus-lockstep", "zbus_xml", "zvariant", @@ -6437,7 +6421,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "zvariant_utils", ] @@ -6483,7 +6467,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] [[package]] @@ -6538,7 +6522,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", "zvariant_utils", ] @@ -6550,5 +6534,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.87", ] diff --git a/Cargo.toml b/Cargo.toml index ef4c9b8ec..224b6192f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ windows-implement = { version = "0.58" } windows-interface = { version = "0.58" } windows-core = { version = "0.58" } shadow-rs = "0.35" -which = "6" +which = "7" [workspace.dependencies.windows] version = "0.58" diff --git a/README.md b/README.md index 1a844fae2..eee8663e5 100644 --- a/README.md +++ b/README.md @@ -366,7 +366,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c Below is a simple example of how to use `komorebi-client` in a basic Rust application. ```rust -// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.29"} +// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.30"} use anyhow::Result; use komorebi_client::Notification; diff --git a/docs/komorebi.bar.example.json b/docs/komorebi.bar.example.json index 7ce3f1da7..39a114792 100644 --- a/docs/komorebi.bar.example.json +++ b/docs/komorebi.bar.example.json @@ -1,5 +1,5 @@ { - "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.29/schema.bar.json", + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.30/schema.bar.json", "monitor": { "index": 0, "work_area_offset": { diff --git a/docs/komorebi.example.json b/docs/komorebi.example.json index beb64eff1..ec8ec4768 100644 --- a/docs/komorebi.example.json +++ b/docs/komorebi.example.json @@ -1,5 +1,5 @@ { - "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.29/schema.json", + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.30/schema.json", "app_specific_configuration_path": "$Env:USERPROFILE/applications.json", "window_hiding_behaviour": "Cloak", "cross_monitor_move_behaviour": "Insert", diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 0f53bb7b4..93ff25523 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -458,6 +458,7 @@ impl StaticConfig { println!("\nEnd-of-life features will not receive any further bug fixes or updates; they should not be used\n") } } + pub fn aliases(raw: &str) { let mut map = HashMap::new(); map.insert("border", ["active_window_border"]); @@ -466,6 +467,7 @@ impl StaticConfig { map.insert("border_colours", ["active_window_border_colours"]); map.insert("border_style", ["active_window_border_style"]); map.insert("applications.json", ["applications.yaml"]); + map.insert("ignore_rules", ["float_rules"]); let mut display = false; From 1ef0630f9d860fb92a82c05f3db37b79a72cfc61 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 27 Nov 2024 12:07:10 -0800 Subject: [PATCH 65/86] feat(wm): listen to event_object_locationchange This commit adds a new WindowManagerEvent, LocationChange, which allows komorebi to listen to and dispatch events to border_manager when EVENT_OBJECT_LOCATIONCHANGE is emitted by the operating system. This is required because there is no other event which fires on window maximize/unmaximize. fix #1137 --- komorebi/src/process_event.rs | 2 ++ komorebi/src/window_manager_event.rs | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 93e339c1b..128cc053a 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -669,6 +669,7 @@ impl WindowManager { } WindowManagerEvent::MouseCapture(..) | WindowManagerEvent::Cloak(..) + | WindowManagerEvent::LocationChange(..) | WindowManagerEvent::TitleUpdate(..) => {} }; @@ -714,6 +715,7 @@ impl WindowManager { if !matches!( event, WindowManagerEvent::Show(WinEvent::ObjectNameChange, _) + | WindowManagerEvent::LocationChange(_, _) ) { tracing::info!("processed: {}", event.window().to_string()); } else { diff --git a/komorebi/src/window_manager_event.rs b/komorebi/src/window_manager_event.rs index 813625edf..68ebac50c 100644 --- a/komorebi/src/window_manager_event.rs +++ b/komorebi/src/window_manager_event.rs @@ -28,6 +28,7 @@ pub enum WindowManagerEvent { Unmanage(Window), Raise(Window), TitleUpdate(WinEvent, Window), + LocationChange(WinEvent, Window), } impl Display for WindowManagerEvent { @@ -78,6 +79,9 @@ impl Display for WindowManagerEvent { Self::TitleUpdate(winevent, window) => { write!(f, "TitleUpdate (WinEvent: {winevent}, Window: {window})") } + Self::LocationChange(winevent, window) => { + write!(f, "LocationChange (WinEvent: {winevent}, Window: {window})") + } } } } @@ -98,7 +102,8 @@ impl WindowManagerEvent { | Self::Raise(window) | Self::Manage(window) | Self::Unmanage(window) - | Self::TitleUpdate(_, window) => window, + | Self::TitleUpdate(_, window) + | Self::LocationChange(_, window) => window, } } @@ -122,6 +127,7 @@ impl WindowManagerEvent { WindowManagerEvent::Unmanage(_) => "Unmanage", WindowManagerEvent::Raise(_) => "Raise", WindowManagerEvent::TitleUpdate(_, _) => "TitleUpdate", + WindowManagerEvent::LocationChange(_, _) => "LocationChange", } } @@ -137,6 +143,7 @@ impl WindowManagerEvent { | WindowManagerEvent::MoveResizeStart(event, _) | WindowManagerEvent::MoveResizeEnd(event, _) | WindowManagerEvent::MouseCapture(event, _) + | WindowManagerEvent::LocationChange(event, _) | WindowManagerEvent::TitleUpdate(event, _) => Some(event.to_string()), WindowManagerEvent::Manage(_) | WindowManagerEvent::Unmanage(_) @@ -202,6 +209,7 @@ impl WindowManagerEvent { Option::from(Self::TitleUpdate(winevent, window)) } } + WinEvent::ObjectLocationChange => Option::from(Self::LocationChange(winevent, window)), _ => None, } } From cc186974601170e06904dd3c010d616871ec3be7 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 6 Dec 2024 17:44:17 -0800 Subject: [PATCH 66/86] fix(cli): handle spaces in bar config paths More PowerShell script username-with-spaces path handling shenanigans. re #1161 --- komorebic/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 7e090f2d3..2f7d4ea0d 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -2094,7 +2094,7 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue)) let mut config = StaticConfig::read(config)?; if let Some(display_bar_configurations) = &mut config.bar_configurations { for config_file_path in &mut *display_bar_configurations { - let script = r#"Start-Process 'komorebi-bar' '--config "CONFIGFILE"' -WindowStyle hidden"# + let script = r#"Start-Process '"komorebi-bar"' '"--config CONFIGFILE"' -WindowStyle hidden"# .replace("CONFIGFILE", &config_file_path.to_string_lossy()); match powershell_script::run(&script) { From a000fa77e34d27c191bc4f6f0c17ca4a472030ce Mon Sep 17 00:00:00 2001 From: pro470 Date: Fri, 27 Dec 2024 19:20:21 +0100 Subject: [PATCH 67/86] testing --- komorebi/src/core/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index ec814e25c..b1a8804f2 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -218,6 +218,7 @@ pub enum SocketMessage { StaticConfigSchema, GenerateStaticConfig, DebugWindow(isize), + } impl SocketMessage { From d0f9bc3c1a503f63fead21342537cbf9fea1730d Mon Sep 17 00:00:00 2001 From: pro470 Date: Fri, 3 Jan 2025 01:30:03 +0100 Subject: [PATCH 68/86] delete unnecessary whitespace --- komorebi/src/core/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index e9baffcc7..418d16573 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -219,7 +219,6 @@ pub enum SocketMessage { StaticConfigSchema, GenerateStaticConfig, DebugWindow(isize), - } impl SocketMessage { From 43aeba81170e3a0a016cebd1082fc3d6dad7d0c4 Mon Sep 17 00:00:00 2001 From: pro470 Date: Fri, 3 Jan 2025 01:51:22 +0100 Subject: [PATCH 69/86] Revert "delete unnecessary whitespace" This reverts commit d0f9bc3c1a503f63fead21342537cbf9fea1730d. --- komorebi/src/core/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 418d16573..e9baffcc7 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -219,6 +219,7 @@ pub enum SocketMessage { StaticConfigSchema, GenerateStaticConfig, DebugWindow(isize), + } impl SocketMessage { From dc2c70aa8ddc4e7831ec6ee3f0abcc2129884171 Mon Sep 17 00:00:00 2001 From: pro470 Date: Fri, 3 Jan 2025 19:37:54 +0100 Subject: [PATCH 70/86] some format cleanup need to do more later --- komorebi/src/core/mod.rs | 2 +- komorebi/src/process_command.rs | 12 +++++++++--- komorebi/src/window_manager.rs | 32 +++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index e9baffcc7..6b94d4a53 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -55,7 +55,7 @@ pub enum SocketMessage { StackAll, UnstackAll, FocusExe(Option, Option), - DisplayMonitorWorkspaceNumber(usize,usize), + DisplayMonitorWorkspaceNumber(usize, usize), ResizeWindowEdge(OperationDirection, Sizing), ResizeWindowAxis(Axis, Sizing), MoveContainerToMonitorNumber(usize), diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 3bdfc051e..b40723c8e 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -231,7 +231,10 @@ impl WindowManager { self.promote_container_to_front()? } SocketMessage::DisplayMonitorWorkspaceNumber(monitor_idx, workspace_idx) => { - self.send_always_on_top(Option::from(monitor_idx), Option::from(workspace_idx), None)?; + self.send_always_on_top( + Option::from(monitor_idx), + Option::from(workspace_idx), + None)?; self.display_monitor_workspace(monitor_idx, workspace_idx)?; } SocketMessage::EagerFocus(ref exe) => { @@ -296,7 +299,7 @@ impl WindowManager { SocketMessage::FocusWindow(direction) => { self.focus_container_in_direction(direction)?; } - SocketMessage::FocusExe( ref exe, hwnd) => { + SocketMessage::FocusExe(ref exe, hwnd) => { self.focus_window_from_exe(exe, hwnd)?; } SocketMessage::MoveWindow(direction) => { @@ -1006,7 +1009,10 @@ impl WindowManager { if let Some((monitor_idx, workspace_idx)) = self.monitor_workspace_index_by_name(name) { - self.send_always_on_top(Option::from(monitor_idx), Some(workspace_idx), None)?; + self.send_always_on_top( + Option::from(monitor_idx), + Some(workspace_idx), + None)?; self.focus_monitor(monitor_idx)?; self.focus_workspace(workspace_idx)?; } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 59d228293..88e9d273d 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1609,8 +1609,11 @@ impl WindowManager { #[tracing::instrument(skip(self))] - pub fn focus_window_from_exe(&mut self, exe: &Option, hwnd: Option) -> Result<()> { - + pub fn focus_window_from_exe( + &mut self, + exe: &Option, + hwnd: Option, + ) -> Result<()> { let mut monitor_idx = 0; let mut workspace_idx = 0; let mut hwnd_from_exe: isize = 0; @@ -1618,7 +1621,7 @@ impl WindowManager { let mouse_follows_focus = self.mouse_follows_focus; let offset = self.work_area_offset; - 'outer: for (i, m ) in self.monitors.elements().iter().enumerate(){ + 'outer: for (i, m) in self.monitors.elements().iter().enumerate(){ for (j, w) in m.workspaces().iter().enumerate() { if let Some(hwnd) = hwnd { if w.contains_managed_window(hwnd) { @@ -1650,10 +1653,16 @@ impl WindowManager { } if self.focused_workspace_idx()? != workspace_idx { - self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no monitor"))?.focus_workspace(workspace_idx)?; + self.focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no monitor"))? + .focus_workspace(workspace_idx)?; } - let target_monitor = self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no monitor"))?; - target_monitor.workspaces_mut().get_mut(workspace_idx) + let target_monitor = self + .focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no monitor"))?; + target_monitor + .workspaces_mut() + .get_mut(workspace_idx) .ok_or_else(|| anyhow!("there is no workspace"))? .focus_container_by_window(hwnd_from_exe)?; target_monitor.load_focused_workspace(mouse_follows_focus)?; @@ -1682,16 +1691,21 @@ impl WindowManager { } #[tracing::instrument(skip(self))] - pub fn send_always_on_top(&mut self, monitor_idx: Option, workspace_idx: Option, follows: Option) -> Result<()> { + pub fn send_always_on_top( + &mut self, + monitor_idx: Option, + workspace_idx: Option, + follows: Option + ) -> Result<()> { let mut contains_always_on_top = false; - let last_window = if let Ok(window) = self.focused_window(){ + let last_window = if let Ok(window) = self.focused_window() { window.hwnd } else { if self.focused_workspace()?.floating_windows().len() > 0 { self.focused_workspace()?.floating_windows()[0].hwnd }else { - return Ok(()) + return Ok(()); } }; let aot = self.always_on_top.clone(); From 89d1ffa598db45a4eddab61d7252423eea6ed810 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 3 Jan 2025 18:05:48 -0800 Subject: [PATCH 71/86] fix(cli): allow checking of arbitrary config files This commit adds an optional --komorebi-config flag to the check command to allow users to check a komorebi.json file in an arbitrary location. --- komorebic/src/main.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 8f6ce2ae2..eec27bf3f 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -922,6 +922,13 @@ struct EnableAutostart { masir: bool, } +#[derive(Parser)] +struct Check { + /// Path to a static configuration JSON file + #[clap(action, short, long)] + komorebi_config: Option, +} + #[derive(Parser)] struct ReplaceConfiguration { /// Static configuration JSON file from which the configuration should be loaded @@ -954,7 +961,7 @@ enum SubCommand { /// Kill background processes started by komorebic Kill(Kill), /// Check komorebi configuration and related files for common errors - Check, + Check(Check), /// Show the path to komorebi.json #[clap(alias = "config")] Configuration, @@ -1576,7 +1583,7 @@ fn main() -> Result<()> { std::fs::remove_file(shortcut_file)?; } } - SubCommand::Check => { + SubCommand::Check(args) => { let home_display = HOME_DIR.display(); if HAS_CUSTOM_CONFIG_HOME.load(Ordering::SeqCst) { println!("KOMOREBI_CONFIG_HOME detected: {home_display}\n"); @@ -1591,7 +1598,15 @@ fn main() -> Result<()> { println!("Looking for configuration files in {home_display}\n"); - let static_config = HOME_DIR.join("komorebi.json"); + let static_config = if let Some(static_config) = args.komorebi_config { + println!( + "Using an arbitrary configuration file passed to --komorebi-config flag\n" + ); + static_config + } else { + HOME_DIR.join("komorebi.json") + }; + let config_pwsh = HOME_DIR.join("komorebi.ps1"); let config_ahk = HOME_DIR.join("komorebi.ahk"); let config_whkd = WHKD_CONFIG_DIR.join("whkdrc"); From d4d72e4ecbccde853c3ef025026d2ff18c3d8e91 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 3 Jan 2025 18:16:30 -0800 Subject: [PATCH 72/86] feat(config): allow specifying layout flip on ws This commit adds support for specifying a layout flip axis for each workspace in the static configuration file. --- komorebi/src/static_config.rs | 5 +++++ komorebi/src/workspace.rs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 0cf04baf3..825f10e3b 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -35,6 +35,7 @@ use crate::window_manager::WindowManager; use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; use crate::workspace::Workspace; +use crate::Axis; use crate::CrossBoundaryBehaviour; use crate::DATA_DIR; use crate::DEFAULT_CONTAINER_PADDING; @@ -148,6 +149,9 @@ pub struct WorkspaceConfig { /// (default: false) #[serde(skip_serializing_if = "Option::is_none")] pub float_override: Option, + /// Specify an axis on which to flip the selected layout (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub layout_flip: Option, } impl From<&Workspace> for WorkspaceConfig { @@ -202,6 +206,7 @@ impl From<&Workspace> for WorkspaceConfig { apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset()), window_container_behaviour: *value.window_container_behaviour(), float_override: *value.float_override(), + layout_flip: value.layout_flip(), } } } diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index c3180a3e2..ce9d61ea6 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -187,6 +187,10 @@ impl Workspace { self.set_float_override(config.float_override); } + if config.layout_flip.is_some() { + self.set_layout_flip(config.layout_flip); + } + Ok(()) } From 7f518b92b2b21038b07024abee2d7c27abbf12a3 Mon Sep 17 00:00:00 2001 From: pro470 Date: Sat, 4 Jan 2025 05:49:34 +0100 Subject: [PATCH 73/86] fixed formating --- komorebi/src/core/mod.rs | 1 - komorebi/src/process_command.rs | 22 ++-- komorebi/src/process_event.rs | 1 - komorebi/src/window_manager.rs | 183 ++++++++++++++++++++------------ komorebic/src/main.rs | 8 +- 5 files changed, 133 insertions(+), 82 deletions(-) diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 6b94d4a53..3ec79e9c4 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -219,7 +219,6 @@ pub enum SocketMessage { StaticConfigSchema, GenerateStaticConfig, DebugWindow(isize), - } impl SocketMessage { diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index b40723c8e..887efd1b4 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -234,7 +234,8 @@ impl WindowManager { self.send_always_on_top( Option::from(monitor_idx), Option::from(workspace_idx), - None)?; + None, + )?; self.display_monitor_workspace(monitor_idx, workspace_idx)?; } SocketMessage::EagerFocus(ref exe) => { @@ -612,7 +613,6 @@ impl WindowManager { self.move_container_to_workspace(workspace_idx, true, None)?; self.send_always_on_top(None, Some(workspace_idx), Some(true))?; - } SocketMessage::MoveContainerToMonitorNumber(monitor_idx) => { self.send_always_on_top(Some(monitor_idx), None, Some(true))?; @@ -654,7 +654,6 @@ impl WindowManager { self.move_container_to_workspace(workspace_idx, false, None)?; self.send_always_on_top(None, Some(workspace_idx), Some(false))?; - } SocketMessage::SendContainerToMonitorNumber(monitor_idx) => { self.send_always_on_top(Some(monitor_idx), None, Some(false))?; @@ -979,7 +978,11 @@ impl WindowManager { for i in 0..self.monitors.elements().len() { if i != focused_monitor_idx { - self.send_always_on_top(Option::from(i), Option::from(workspace_idx), None)?; + self.send_always_on_top( + Option::from(i), + Option::from(workspace_idx), + None, + )?; } } @@ -990,7 +993,11 @@ impl WindowManager { } } - self.send_always_on_top(Option::from(focused_monitor_idx), Some(workspace_idx), None)?; + self.send_always_on_top( + Option::from(focused_monitor_idx), + Some(workspace_idx), + None, + )?; self.focus_workspace(workspace_idx)?; } SocketMessage::FocusMonitorWorkspaceNumber(monitor_idx, workspace_idx) => { @@ -1009,10 +1016,7 @@ impl WindowManager { if let Some((monitor_idx, workspace_idx)) = self.monitor_workspace_index_by_name(name) { - self.send_always_on_top( - Option::from(monitor_idx), - Some(workspace_idx), - None)?; + self.send_always_on_top(Option::from(monitor_idx), Some(workspace_idx), None)?; self.focus_monitor(monitor_idx)?; self.focus_workspace(workspace_idx)?; } diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index aace13f7c..d037472e6 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -188,7 +188,6 @@ impl WindowManager { let idx = aot.iter().position(|x| *x == window.hwnd).unwrap(); aot.remove(idx); } - } } WindowManagerEvent::Minimize(_, window) => { diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 88e9d273d..58e0ebdee 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -117,7 +117,6 @@ pub struct WindowManager { pub already_moved_window_handles: Arc>>, pub uncloack_to_ignore: usize, pub always_on_top: Option>, - } #[allow(clippy::struct_excessive_bools)] @@ -1607,7 +1606,6 @@ impl WindowManager { self.update_focused_workspace(mouse_follows_focus, true) } - #[tracing::instrument(skip(self))] pub fn focus_window_from_exe( &mut self, @@ -1621,7 +1619,7 @@ impl WindowManager { let mouse_follows_focus = self.mouse_follows_focus; let offset = self.work_area_offset; - 'outer: for (i, m) in self.monitors.elements().iter().enumerate(){ + 'outer: for (i, m) in self.monitors.elements().iter().enumerate() { for (j, w) in m.workspaces().iter().enumerate() { if let Some(hwnd) = hwnd { if w.contains_managed_window(hwnd) { @@ -1647,10 +1645,8 @@ impl WindowManager { } if bool { - if self.focused_monitor_idx() != monitor_idx { self.focus_monitor(monitor_idx)?; - } if self.focused_workspace_idx()? != workspace_idx { self.focused_monitor_mut() @@ -1675,9 +1671,13 @@ impl WindowManager { } #[tracing::instrument(skip(self))] - pub fn display_monitor_workspace(&mut self, monitor_idx: usize, workspace_idx: usize) -> Result<()> { - - let monitor = self.monitors_mut() + pub fn display_monitor_workspace( + &mut self, + monitor_idx: usize, + workspace_idx: usize, + ) -> Result<()> { + let monitor = self + .monitors_mut() .get_mut(monitor_idx) .ok_or_else(|| anyhow!("There is no monitor"))?; @@ -1695,41 +1695,35 @@ impl WindowManager { &mut self, monitor_idx: Option, workspace_idx: Option, - follows: Option + follows: Option, ) -> Result<()> { let mut contains_always_on_top = false; let last_window = if let Ok(window) = self.focused_window() { window.hwnd - } else { if self.focused_workspace()?.floating_windows().len() > 0 { self.focused_workspace()?.floating_windows()[0].hwnd - }else { + } else { return Ok(()); } }; let aot = self.always_on_top.clone(); let mut windows_vec = vec![]; - let flw_contains = - - if let Some(aot) = self.always_on_top.as_ref() { - if aot.len() == 0 { - return Ok(()) - } - if let Some(flw) = follows { - if let Ok(fc) = self.focused_container() { - let contains = fc.windows().iter().any(|w| aot.contains(&w.hwnd)); - if flw && contains { - windows_vec = fc.windows().into_iter().map(|w| w.hwnd).collect::>(); - true - } else if !flw && !contains { - return Ok(()) - } else if !flw && contains { - Err(anyhow!("cannot send an always on top window"))? - } else { - false - } + let flw_contains = if let Some(aot) = self.always_on_top.as_ref() { + if aot.len() == 0 { + return Ok(()); + } + if let Some(flw) = follows { + if let Ok(fc) = self.focused_container() { + let contains = fc.windows().iter().any(|w| aot.contains(&w.hwnd)); + if flw && contains { + windows_vec = fc.windows().into_iter().map(|w| w.hwnd).collect::>(); + true + } else if !flw && !contains { + return Ok(()); + } else if !flw && contains { + Err(anyhow!("cannot send an always on top window"))? } else { false } @@ -1737,80 +1731,133 @@ impl WindowManager { false } } else { - return Ok(()) - }; + false + } + } else { + return Ok(()); + }; self.check_aot_windows()?; - - aot.ok_or_else(|| anyhow!("there is no always on Top windows"))?.iter().filter(|&&window| { - let mut is_window = false; - if flw_contains { + aot.ok_or_else(|| anyhow!("there is no always on Top windows"))? + .iter() + .filter(|&&window| { + let mut is_window = false; + if flw_contains { if windows_vec.contains(&&window) { is_window = true; } - } - !is_window}) + } + !is_window + }) .try_for_each(|&window| { if let Some(monitor_idx) = monitor_idx { if self .monitors() .get(monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor at this index"))?.focused_workspace().unwrap().contains_managed_window(window) { + .ok_or_else(|| anyhow!("there is no monitor at this index"))? + .focused_workspace() + .unwrap() + .contains_managed_window(window) + { let idx = self .monitors() .get(monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor at this index"))?.focused_workspace().unwrap().container_idx_for_window(window).ok_or_else(|| anyhow!("there is no container at this index"))?; + .ok_or_else(|| anyhow!("there is no monitor at this index"))? + .focused_workspace() + .unwrap() + .container_idx_for_window(window) + .ok_or_else(|| anyhow!("there is no container at this index"))?; let con = self .monitors_mut() .get_mut(monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor at this index"))?.focused_workspace_mut().unwrap().remove_container_by_idx(idx).unwrap(); + .ok_or_else(|| anyhow!("there is no monitor at this index"))? + .focused_workspace_mut() + .unwrap() + .remove_container_by_idx(idx) + .unwrap(); - self - .monitors_mut() + self.monitors_mut() .get_mut(monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor at this index"))?.add_container(con, workspace_idx)?; + .ok_or_else(|| anyhow!("there is no monitor at this index"))? + .add_container(con, workspace_idx)?; } } else { - if self.focused_workspace().unwrap().contains_managed_window(window) { - let idx = self.focused_workspace().unwrap().container_idx_for_window(window); - let con = self.focused_workspace_mut().unwrap().remove_container_by_idx(idx.unwrap()).ok_or_else(|| anyhow!("there is no container at this index"))?; - + if self + .focused_workspace() + .unwrap() + .contains_managed_window(window) + { + let idx = self + .focused_workspace() + .unwrap() + .container_idx_for_window(window); + let con = self + .focused_workspace_mut() + .unwrap() + .remove_container_by_idx(idx.unwrap()) + .ok_or_else(|| anyhow!("there is no container at this index"))?; - self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no focused monitor"))?.add_container(con, workspace_idx)?; + self.focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no focused monitor"))? + .add_container(con, workspace_idx)?; contains_always_on_top = true; //self.update_focused_workspace(mff, false).unwrap() - } else if self.focused_workspace()?.floating_windows().iter().any(|w| w.hwnd == window) { - let idx = self.focused_workspace_mut()?.floating_windows().iter().position(|x| x.hwnd == window).unwrap(); - let float_window = self.focused_workspace_mut()?.floating_windows_mut().remove(idx); - self.focused_monitor_mut().ok_or_else(|| anyhow!("there is no focused workspace"))? + } else if self + .focused_workspace()? + .floating_windows() + .iter() + .any(|w| w.hwnd == window) + { + let idx = self + .focused_workspace_mut()? + .floating_windows() + .iter() + .position(|x| x.hwnd == window) + .unwrap(); + let float_window = self + .focused_workspace_mut()? + .floating_windows_mut() + .remove(idx); + self.focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no focused workspace"))? .workspaces_mut() .get_mut(workspace_idx.unwrap()) .ok_or_else(|| anyhow!("there is no workspace at this index"))? - .floating_windows_mut().push(float_window); + .floating_windows_mut() + .push(float_window); } } Ok::<(), color_eyre::eyre::Error>(()) + })?; - })?; - - if contains_always_on_top && self.focused_workspace()?.containers().len() != 0 && self.focused_workspace()?.contains_managed_window(last_window) { - self.focused_workspace_mut()?.focus_container_by_window(last_window)?; + if contains_always_on_top + && self.focused_workspace()?.containers().len() != 0 + && self + .focused_workspace()? + .contains_managed_window(last_window) + { + self.focused_workspace_mut()? + .focus_container_by_window(last_window)?; } Ok(()) - } - pub fn check_aot_windows(&mut self) -> Result<()> { let mut not_contains = vec![]; if self.always_on_top.is_none() { - return Ok(()) + return Ok(()); } - for (i, hwnd) in self.always_on_top.as_ref().ok_or_else(|| anyhow!("there is no always on top windows"))?.iter().enumerate() { + for (i, hwnd) in self + .always_on_top + .as_ref() + .ok_or_else(|| anyhow!("there is no always on top windows"))? + .iter() + .enumerate() + { let mut not_contains_bool = true; 'monitor: for monitor in self.monitors.elements().iter() { for workspace in monitor.workspaces().iter() { @@ -1832,17 +1879,17 @@ impl WindowManager { } pub fn toggle_always_on_top(&mut self) -> Result<()> { - self.check_aot_windows()?; let focused_con = self.focused_container().unwrap().clone(); focused_con.windows().iter().try_for_each(|window| { - if let Some(always_on_top) = self.always_on_top.as_mut() { - if always_on_top.contains(&window.hwnd) { - let idx = always_on_top.iter().position(|x| *x == window.hwnd).unwrap(); + let idx = always_on_top + .iter() + .position(|x| *x == window.hwnd) + .unwrap(); always_on_top.remove(idx); } else { always_on_top.push(window.hwnd.clone()) @@ -1850,11 +1897,11 @@ impl WindowManager { } else { self.always_on_top = Some(vec![window.hwnd.clone()]) } - Ok::<(), color_eyre::eyre::Error>(())})?; + Ok::<(), color_eyre::eyre::Error>(()) + })?; Ok(()) } - #[tracing::instrument(skip(self))] pub fn move_container_to_monitor( &mut self, diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index e05beb1aa..227ba773f 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -831,7 +831,6 @@ struct Exe { /// hwnd handle of the window #[clap(long)] hwnd: Option, - } #[derive(Parser)] @@ -1751,13 +1750,16 @@ fn main() -> Result<()> { } } SubCommand::DisplayMonitorWorkspace(arg) => { - send_message(&SocketMessage::DisplayMonitorWorkspaceNumber(arg.monitor, arg.workspace))?; + send_message(&SocketMessage::DisplayMonitorWorkspaceNumber( + arg.monitor, + arg.workspace, + ))?; } SubCommand::Focus(arg) => { send_message(&SocketMessage::FocusWindow(arg.operation_direction))?; } SubCommand::FocusExe(arg) => { - send_message(&SocketMessage::FocusExe(arg.exe,arg.hwnd))?; + send_message(&SocketMessage::FocusExe(arg.exe, arg.hwnd))?; } SubCommand::ForceFocus => { send_message(&SocketMessage::ForceFocus)?; From 40e157539d2a126968ca6d098da9ebce2d7d7197 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 4 Jan 2025 09:39:04 -0800 Subject: [PATCH 74/86] fix(wm): avoid focused ws rule enforcement deadlock This commit adds mutex lock scoping in WindowManager::enforce_workspace_rule to avoid a deadlock when should_update_focused_workspace evaluates to true. fix #1212 --- komorebi/src/window_manager.rs | 119 +++++++++++++++++---------------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 512026d58..0123b495a 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -720,53 +720,69 @@ impl WindowManager { .ok_or_else(|| anyhow!("there is no monitor with that index"))? .focused_workspace_idx(); - let workspace_matching_rules = WORKSPACE_MATCHING_RULES.lock(); - let regex_identifiers = REGEX_IDENTIFIERS.lock(); - // Go through all the monitors and workspaces - for (i, monitor) in self.monitors().iter().enumerate() { - for (j, workspace) in monitor.workspaces().iter().enumerate() { - // And all the visible windows (at the top of a container) - for window in workspace.visible_windows().into_iter().flatten() { - let mut already_moved_window_handles = self.already_moved_window_handles.lock(); - let exe_name = window.exe()?; - let title = window.title()?; - let class = window.class()?; - let path = window.path()?; - - for rule in &*workspace_matching_rules { - let matched = match &rule.matching_rule { - MatchingRule::Simple(r) => should_act_individual( - &title, - &exe_name, - &class, - &path, - r, - ®ex_identifiers, - ), - MatchingRule::Composite(r) => { - let mut composite_results = vec![]; - for identifier in r { - composite_results.push(should_act_individual( - &title, - &exe_name, - &class, - &path, - identifier, - ®ex_identifiers, - )); + // scope mutex locks to avoid deadlock if should_update_focused_workspace evaluates to true + // at the end of this function + { + let workspace_matching_rules = WORKSPACE_MATCHING_RULES.lock(); + let regex_identifiers = REGEX_IDENTIFIERS.lock(); + // Go through all the monitors and workspaces + for (i, monitor) in self.monitors().iter().enumerate() { + for (j, workspace) in monitor.workspaces().iter().enumerate() { + // And all the visible windows (at the top of a container) + for window in workspace.visible_windows().into_iter().flatten() { + let mut already_moved_window_handles = + self.already_moved_window_handles.lock(); + let exe_name = window.exe()?; + let title = window.title()?; + let class = window.class()?; + let path = window.path()?; + + for rule in &*workspace_matching_rules { + let matched = match &rule.matching_rule { + MatchingRule::Simple(r) => should_act_individual( + &title, + &exe_name, + &class, + &path, + r, + ®ex_identifiers, + ), + MatchingRule::Composite(r) => { + let mut composite_results = vec![]; + for identifier in r { + composite_results.push(should_act_individual( + &title, + &exe_name, + &class, + &path, + identifier, + ®ex_identifiers, + )); + } + + composite_results.iter().all(|&x| x) } - - composite_results.iter().all(|&x| x) - } - }; - - if matched { - let floating = workspace.floating_windows().contains(window); - - if rule.initial_only { - if !already_moved_window_handles.contains(&window.hwnd) { - already_moved_window_handles.insert(window.hwnd); - + }; + + if matched { + let floating = workspace.floating_windows().contains(window); + + if rule.initial_only { + if !already_moved_window_handles.contains(&window.hwnd) { + already_moved_window_handles.insert(window.hwnd); + + self.add_window_handle_to_move_based_on_workspace_rule( + &window.title()?, + window.hwnd, + i, + j, + rule.monitor_index, + rule.workspace_index, + floating, + &mut to_move, + ); + } + } else { self.add_window_handle_to_move_based_on_workspace_rule( &window.title()?, window.hwnd, @@ -778,17 +794,6 @@ impl WindowManager { &mut to_move, ); } - } else { - self.add_window_handle_to_move_based_on_workspace_rule( - &window.title()?, - window.hwnd, - i, - j, - rule.monitor_index, - rule.workspace_index, - floating, - &mut to_move, - ); } } } From 39c82bd663f5a333906ddaa677a7388f74f956c4 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 4 Jan 2025 10:17:31 -0800 Subject: [PATCH 75/86] fix(wm): add uncloak as a notif override event If a user triggers the workspace reconciliator by clicking on an app in the start bar or via alt-tab, a notification should be sent to subscribers such as komorebi-bar so that the focused workspace can be updated. The various komorebi reconciliators and manager modules don't emit events to subscribers themselves (yet?), so for now we can pass on the uncloak event. Maybe we can look into expanding the Notification enum in the future. fix #1211 --- komorebi/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index 42e39bad9..38a83c505 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -298,6 +298,7 @@ pub fn notify_subscribers(notification: Notification, state_has_been_modified: b | NotificationEvent::Socket(SocketMessage::ReloadStaticConfiguration(_)) | NotificationEvent::WindowManager(WindowManagerEvent::TitleUpdate(_, _)) | NotificationEvent::WindowManager(WindowManagerEvent::Show(_, _)) + | NotificationEvent::WindowManager(WindowManagerEvent::Uncloak(_, _)) ); let notification = &serde_json::to_string(¬ification)?; From 631d336f110c37d54cb376172ed397572c24fb7e Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 4 Jan 2025 10:56:44 -0800 Subject: [PATCH 76/86] feat(cli): add stackbar-mode command This commit adds a new komorebic command "stackbar-mode" to allow users to change stackbar modes programmatically. --- docs/cli/check.md | 5 ++++- docs/cli/stackbar-mode.md | 18 ++++++++++++++++++ komorebi/src/core/mod.rs | 4 +++- komorebi/src/process_command.rs | 1 + komorebic/src/main.rs | 13 +++++++++++++ mkdocs.yml | 1 + schema.bar.json | 2 +- schema.json | 11 ++++++++++- 8 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 docs/cli/stackbar-mode.md diff --git a/docs/cli/check.md b/docs/cli/check.md index 54d3cbbeb..f10b2cb38 100644 --- a/docs/cli/check.md +++ b/docs/cli/check.md @@ -3,9 +3,12 @@ ``` Check komorebi configuration and related files for common errors -Usage: komorebic.exe check +Usage: komorebic.exe check [OPTIONS] Options: + -k, --komorebi-config + Path to a static configuration JSON file + -h, --help Print help diff --git a/docs/cli/stackbar-mode.md b/docs/cli/stackbar-mode.md new file mode 100644 index 000000000..cb8801792 --- /dev/null +++ b/docs/cli/stackbar-mode.md @@ -0,0 +1,18 @@ +# stackbar-mode + +``` +Set the stackbar mode + +Usage: komorebic.exe stackbar-mode + +Arguments: + + Desired stackbar mode + + [possible values: always, never, on-stack] + +Options: + -h, --help + Print help + +``` diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 68025d514..d9bd230c2 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -238,7 +238,9 @@ pub struct SubscribeOptions { pub filter_state_changes: bool, } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Display, Serialize, Deserialize, JsonSchema)] +#[derive( + Debug, Copy, Clone, Eq, PartialEq, Display, Serialize, Deserialize, JsonSchema, ValueEnum, +)] pub enum StackbarMode { Always, Never, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 7053127a6..fc42105e0 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -1662,6 +1662,7 @@ impl WindowManager { } SocketMessage::StackbarMode(mode) => { STACKBAR_MODE.store(mode); + self.retile_all(true)?; } SocketMessage::StackbarLabel(label) => { STACKBAR_LABEL.store(label); diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index eec27bf3f..dcc641ef9 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -721,6 +721,13 @@ struct BorderImplementation { style: komorebi_client::BorderImplementation, } +#[derive(Parser)] +struct StackbarMode { + /// Desired stackbar mode + #[clap(value_enum)] + mode: komorebi_client::StackbarMode, +} + #[derive(Parser)] struct Animation { #[clap(value_enum)] @@ -1368,6 +1375,9 @@ enum SubCommand { /// Set the border implementation #[clap(arg_required_else_help = true)] BorderImplementation(BorderImplementation), + /// Set the stackbar mode + #[clap(arg_required_else_help = true)] + StackbarMode(StackbarMode), /// Enable or disable transparency for unfocused windows #[clap(arg_required_else_help = true)] Transparency(Transparency), @@ -2785,6 +2795,9 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) { SubCommand::BorderImplementation(arg) => { send_message(&SocketMessage::BorderImplementation(arg.style))?; } + SubCommand::StackbarMode(arg) => { + send_message(&SocketMessage::StackbarMode(arg.mode))?; + } SubCommand::Transparency(arg) => { send_message(&SocketMessage::Transparency(arg.boolean_state.into()))?; } diff --git a/mkdocs.yml b/mkdocs.yml index 4b8c1b72b..8988e36ab 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -212,6 +212,7 @@ nav: - cli/border-offset.md - cli/border-style.md - cli/border-implementation.md + - cli/stackbar-mode.md - cli/transparency.md - cli/transparency-alpha.md - cli/toggle-transparency.md diff --git a/schema.bar.json b/schema.bar.json index 1404dbe5d..a8663130e 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "KomobarConfig", - "description": "The `komorebi.bar.json` configuration file reference for `v0.1.32`", + "description": "The `komorebi.bar.json` configuration file reference for `v0.1.33`", "type": "object", "required": [ "left_widgets", diff --git a/schema.json b/schema.json index 80bd8a645..adecf401d 100644 --- a/schema.json +++ b/schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "StaticConfig", - "description": "The `komorebi.json` static configuration file reference for `v0.1.32`", + "description": "The `komorebi.json` static configuration file reference for `v0.1.33`", "type": "object", "properties": { "animation": { @@ -1227,6 +1227,15 @@ "RightMainVerticalStack" ] }, + "layout_flip": { + "description": "Specify an axis on which to flip the selected layout (default: None)", + "type": "string", + "enum": [ + "Horizontal", + "Vertical", + "HorizontalAndVertical" + ] + }, "layout_rules": { "description": "Layout rules (default: None)", "type": "object", From 6af70c828fb0768ff3e71d6e68f84b9255717cd0 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Thu, 23 Jan 2025 17:17:28 -0800 Subject: [PATCH 77/86] feat(config): add aspect ratios for float toggling This commit adds a new configuration option "floating_window_aspect_ratio", which users can manipulate to set their desired window size when using the toggle-float command. resolve #1230 --- komorebi/src/lib.rs | 2 + komorebi/src/static_config.rs | 10 ++ komorebi/src/window.rs | 55 +++++-- schema.bar.json | 280 +++++++++++++++++++++------------- schema.json | 35 ++++- 5 files changed, 264 insertions(+), 118 deletions(-) diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index 38a83c505..b6ad2f225 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -219,6 +219,8 @@ lazy_static! { static ref WINDOWS_BY_BAR_HWNDS: Arc>>> = Arc::new(Mutex::new(HashMap::new())); + + static ref FLOATING_WINDOW_TOGGLE_ASPECT_RATIO: Arc> = Arc::new(Mutex::new(AspectRatio::Standard)); } pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10); diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index bff6faa24..4987aebb2 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -35,6 +35,7 @@ use crate::window_manager::WindowManager; use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; use crate::workspace::Workspace; +use crate::AspectRatio; use crate::Axis; use crate::CrossBoundaryBehaviour; use crate::DATA_DIR; @@ -42,6 +43,7 @@ use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_WORKSPACE_PADDING; use crate::DISPLAY_INDEX_PREFERENCES; use crate::FLOATING_APPLICATIONS; +use crate::FLOATING_WINDOW_TOGGLE_ASPECT_RATIO; use crate::HIDING_BEHAVIOUR; use crate::IGNORE_IDENTIFIERS; use crate::LAYERED_WHITELIST; @@ -382,6 +384,9 @@ pub struct StaticConfig { /// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars #[serde(skip_serializing_if = "Option::is_none")] pub remove_titlebar_applications: Option>, + /// Aspect ratio to resize with when toggling floating mode for a window + #[serde(skip_serializing_if = "Option::is_none")] + pub floating_window_aspect_ratio: Option, } #[derive(Debug, Serialize, Deserialize, JsonSchema)] @@ -637,6 +642,7 @@ impl From<&WindowManager> for StaticConfig { slow_application_identifiers: Option::from(SLOW_APPLICATION_IDENTIFIERS.lock().clone()), bar_configurations: None, remove_titlebar_applications: Option::from(NO_TITLEBAR.lock().clone()), + floating_window_aspect_ratio: Option::from(*FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock()), } } } @@ -644,6 +650,10 @@ impl From<&WindowManager> for StaticConfig { impl StaticConfig { #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] fn apply_globals(&mut self) -> Result<()> { + *FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock() = self + .floating_window_aspect_ratio + .unwrap_or(AspectRatio::Widescreen); + if let Some(monitor_index_preferences) = &self.monitor_index_preferences { let mut preferences = MONITOR_INDEX_PREFERENCES.lock(); preferences.clone_from(monitor_index_preferences); diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 32af415a2..c1ab6176e 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -15,6 +15,7 @@ use crate::focus_manager; use crate::stackbar_manager; use crate::windows_api; use crate::AnimationStyle; +use crate::FLOATING_WINDOW_TOGGLE_ASPECT_RATIO; use crate::SLOW_APPLICATION_COMPENSATION_TIME; use crate::SLOW_APPLICATION_IDENTIFIERS; use std::collections::HashMap; @@ -296,6 +297,30 @@ impl RenderDispatcher for TransparencyRenderDispatcher { } } +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(untagged)] +pub enum AspectRatio { + /// 21:9 + Ultrawide, + /// 16:9 + Widescreen, + /// 4:3 + Standard, + /// A custom W:H aspect ratio + Custom(i32, i32), +} + +impl AspectRatio { + pub fn width_and_height(self) -> (i32, i32) { + match self { + AspectRatio::Ultrawide => (21, 9), + AspectRatio::Widescreen => (16, 9), + AspectRatio::Standard => (4, 3), + AspectRatio::Custom(w, h) => (w, h), + } + } +} + impl Window { pub const fn hwnd(self) -> HWND { HWND(windows_api::as_ptr!(self.hwnd)) @@ -369,15 +394,21 @@ impl Window { } pub fn center(&mut self, work_area: &Rect) -> Result<()> { - let half_width = work_area.right / 2; - let half_weight = work_area.bottom / 2; + let (aspect_ratio_width, aspect_ratio_height) = FLOATING_WINDOW_TOGGLE_ASPECT_RATIO + .lock() + .width_and_height(); + let target_height = work_area.bottom / 2; + let target_width = (target_height * aspect_ratio_width) / aspect_ratio_height; + + let x = work_area.left + ((work_area.right - target_width) / 2); + let y = work_area.top + ((work_area.bottom - target_height) / 2); self.set_position( &Rect { - left: work_area.left + ((work_area.right - half_width) / 2), - top: work_area.top + ((work_area.bottom - half_weight) / 2), - right: half_width, - bottom: half_weight, + left: x, + top: y, + right: target_width, + bottom: target_height, }, true, ) @@ -928,12 +959,12 @@ fn window_is_eligible( } if (allow_wsl2_gui || allow_titlebar_removed || style.contains(WindowStyle::CAPTION) && ex_style.contains(ExtendedWindowStyle::WINDOWEDGE)) - && !ex_style.contains(ExtendedWindowStyle::DLGMODALFRAME) - // Get a lot of dupe events coming through that make the redrawing go crazy - // on FocusChange events if I don't filter out this one. But, if we are - // allowing a specific layered window on the whitelist (like Steam), it should - // pass this check - && (allow_layered || !ex_style.contains(ExtendedWindowStyle::LAYERED)) + && !ex_style.contains(ExtendedWindowStyle::DLGMODALFRAME) + // Get a lot of dupe events coming through that make the redrawing go crazy + // on FocusChange events if I don't filter out this one. But, if we are + // allowing a specific layered window on the whitelist (like Steam), it should + // pass this check + && (allow_layered || !ex_style.contains(ExtendedWindowStyle::LAYERED)) || managed_override { return true; diff --git a/schema.bar.json b/schema.bar.json index 718029a9a..9599d49e7 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "KomobarConfig", - "description": "The `komorebi.bar.json` configuration file reference for `v0.1.33`", + "description": "The `komorebi.bar.json` configuration file reference for `v0.1.34`", "type": "object", "required": [ "left_widgets", @@ -1219,58 +1219,6 @@ "type": "number", "format": "float" }, - "horizontal_margin": { - "description": "Bar horizontal margin. Use one value for symmetric margin or use `[left, right]` to specify a different margin on each side (default: 0)", - "anyOf": [ - { - "description": "A symmetric spacing on some axis (horizontal or vertical), with the same size on both sides", - "type": "number", - "format": "float" - }, - { - "description": "A detailed spacing on some axis (horizontal or vertical), with a size for each side. If an horizontal spacing, then it will be (left, right), if vertical it will be (top, bottom)", - "type": "array", - "items": [ - { - "type": "number", - "format": "float" - }, - { - "type": "number", - "format": "float" - } - ], - "maxItems": 2, - "minItems": 2 - } - ] - }, - "horizontal_padding": { - "description": "Bar horizontal padding. Use one value for symmetric padding or use `[left, right]` to specify a different padding on each side (default: 10)", - "anyOf": [ - { - "description": "A symmetric spacing on some axis (horizontal or vertical), with the same size on both sides", - "type": "number", - "format": "float" - }, - { - "description": "A detailed spacing on some axis (horizontal or vertical), with a size for each side. If an horizontal spacing, then it will be (left, right), if vertical it will be (top, bottom)", - "type": "array", - "items": [ - { - "type": "number", - "format": "float" - }, - { - "type": "number", - "format": "float" - } - ], - "maxItems": 2, - "minItems": 2 - } - ] - }, "icon_scale": { "description": "Scale of the icons relative to the font_size [[1.0-2.0]]. (default: 1.4)", "type": "number", @@ -2141,6 +2089,93 @@ ] } }, + "margin": { + "description": "Bar margin. Use one value for all sides or use a grouped margin for horizontal and/or vertical definition which can each take a single value for a symmetric margin or two values for each side, i.e.: ```json \"margin\": { \"horizontal\": 10 } ``` or: ```json \"margin\": { \"vertical\": [top, bottom] } ``` You can also set individual margin on each side like this: ```json \"margin\": { \"top\": 10, \"bottom\": 10, \"left\": 10, \"right\": 10, } ``` By default, margin is set to 0 on all sides.", + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "object", + "required": [ + "bottom", + "left", + "right", + "top" + ], + "properties": { + "bottom": { + "type": "number", + "format": "float" + }, + "left": { + "type": "number", + "format": "float" + }, + "right": { + "type": "number", + "format": "float" + }, + "top": { + "type": "number", + "format": "float" + } + } + }, + { + "type": "object", + "properties": { + "horizontal": { + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "array", + "items": [ + { + "type": "number", + "format": "float" + }, + { + "type": "number", + "format": "float" + } + ], + "maxItems": 2, + "minItems": 2 + } + ] + }, + "vertical": { + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "array", + "items": [ + { + "type": "number", + "format": "float" + }, + { + "type": "number", + "format": "float" + } + ], + "maxItems": 2, + "minItems": 2 + } + ] + } + } + } + ] + }, "max_label_width": { "description": "Max label width before text truncation (default: 400.0)", "type": "number", @@ -2204,6 +2239,93 @@ } ] }, + "padding": { + "description": "Bar padding. Use one value for all sides or use a grouped padding for horizontal and/or vertical definition which can each take a single value for a symmetric padding or two values for each side, i.e.: ```json \"padding\": { \"horizontal\": 10 } ``` or: ```json \"padding\": { \"horizontal\": [left, right] } ``` You can also set individual padding on each side like this: ```json \"padding\": { \"top\": 10, \"bottom\": 10, \"left\": 10, \"right\": 10, } ``` By default, padding is set to 10 on all sides.", + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "object", + "required": [ + "bottom", + "left", + "right", + "top" + ], + "properties": { + "bottom": { + "type": "number", + "format": "float" + }, + "left": { + "type": "number", + "format": "float" + }, + "right": { + "type": "number", + "format": "float" + }, + "top": { + "type": "number", + "format": "float" + } + } + }, + { + "type": "object", + "properties": { + "horizontal": { + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "array", + "items": [ + { + "type": "number", + "format": "float" + }, + { + "type": "number", + "format": "float" + } + ], + "maxItems": 2, + "minItems": 2 + } + ] + }, + "vertical": { + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "array", + "items": [ + { + "type": "number", + "format": "float" + }, + { + "type": "number", + "format": "float" + } + ], + "maxItems": 2, + "minItems": 2 + } + ] + } + } + } + ] + }, "position": { "description": "Bar positioning options", "type": "object", @@ -3495,58 +3617,6 @@ "format": "uint8", "minimum": 0.0 }, - "vertical_margin": { - "description": "Bar vertical margin. Use one value for symmetric margin or use `[top, bottom]` to specify a different margin on each side (default: 0)", - "anyOf": [ - { - "description": "A symmetric spacing on some axis (horizontal or vertical), with the same size on both sides", - "type": "number", - "format": "float" - }, - { - "description": "A detailed spacing on some axis (horizontal or vertical), with a size for each side. If an horizontal spacing, then it will be (left, right), if vertical it will be (top, bottom)", - "type": "array", - "items": [ - { - "type": "number", - "format": "float" - }, - { - "type": "number", - "format": "float" - } - ], - "maxItems": 2, - "minItems": 2 - } - ] - }, - "vertical_padding": { - "description": "Bar vertical padding. Use one value for symmetric padding or use `[top, bottom]` to specify a different padding on each side (default: 10)", - "anyOf": [ - { - "description": "A symmetric spacing on some axis (horizontal or vertical), with the same size on both sides", - "type": "number", - "format": "float" - }, - { - "description": "A detailed spacing on some axis (horizontal or vertical), with a size for each side. If an horizontal spacing, then it will be (left, right), if vertical it will be (top, bottom)", - "type": "array", - "items": [ - { - "type": "number", - "format": "float" - }, - { - "type": "number", - "format": "float" - } - ], - "maxItems": 2, - "minItems": 2 - } - ] - }, "widget_spacing": { "description": "Spacing between widgets (default: 10.0)", "type": "number", diff --git a/schema.json b/schema.json index adecf401d..c9de2b2f3 100644 --- a/schema.json +++ b/schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "StaticConfig", - "description": "The `komorebi.json` static configuration file reference for `v0.1.33`", + "description": "The `komorebi.json` static configuration file reference for `v0.1.34`", "type": "object", "properties": { "animation": { @@ -642,6 +642,39 @@ ] } }, + "floating_window_aspect_ratio": { + "description": "Aspect ratio to resize with when toggling floating mode for a window", + "anyOf": [ + { + "description": "21:9", + "type": "null" + }, + { + "description": "16:9", + "type": "null" + }, + { + "description": "4:3", + "type": "null" + }, + { + "description": "A custom W:H aspect ratio", + "type": "array", + "items": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "integer", + "format": "int32" + } + ], + "maxItems": 2, + "minItems": 2 + } + ] + }, "focus_follows_mouse": { "description": "END OF LIFE FEATURE: Use https://github.com/LGUG2Z/masir instead", "oneOf": [ From 0119d297d4a67f742c37485b5575e95598818bf7 Mon Sep 17 00:00:00 2001 From: tieniu <781599863@qq.com> Date: Sun, 24 Nov 2024 16:10:08 +0800 Subject: [PATCH 78/86] docs(mkdocs): add note to update asc path Add note about updating app_specific_configuration_path when using KOMOREBI_CONFIG_HOME --- docs/common-workflows/komorebi-config-home.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/common-workflows/komorebi-config-home.md b/docs/common-workflows/komorebi-config-home.md index f49c4d47e..ad676bde0 100644 --- a/docs/common-workflows/komorebi-config-home.md +++ b/docs/common-workflows/komorebi-config-home.md @@ -26,5 +26,15 @@ If you already have configuration files that you wish to keep, move them to the The next time you run `komorebic start`, any files created by or loaded by _komorebi_ will be placed or expected to exist in this folder. +After setting `$Env:KOMOREBI_CONFIG_HOME`, make sure to update the path in komorebi.json: + +```json +{ + "app_specific_configuration_path": "$Env:KOMOREBI_CONFIG_HOME/applications.json" +} +``` + +This ensures that komorebi can locate all configuration files correctly. + [![Watch the tutorial video](https://img.youtube.com/vi/C_KWUqQ6kko/hqdefault.jpg)](https://www.youtube.com/watch?v=C_KWUqQ6kko) From a575b28422b45ca4dc3cabef55009fed59fcf3be Mon Sep 17 00:00:00 2001 From: Samu-K Date: Thu, 23 Jan 2025 22:07:05 +0200 Subject: [PATCH 79/86] feat(bar): add modifiers for strftime integer formatters Added the ability of use modifiers with custom format on the Date widget. For example if using %U returns 04, you can add a modifier so that bar date widget shows 05. --- komorebi-bar/src/date.rs | 57 ++++++++++++++++++++++-- schema.bar.json | 96 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 3 deletions(-) diff --git a/komorebi-bar/src/date.rs b/komorebi-bar/src/date.rs index b43711198..f68dc0eb5 100644 --- a/komorebi-bar/src/date.rs +++ b/komorebi-bar/src/date.rs @@ -13,6 +13,48 @@ use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +/// Custom format with additive modifiers for integer format specifiers +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct CustomModifiers { + /// Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html) + format: String, + /// Additive modifiers for integer format specifiers (e.g. { "%U": 1 } to increment the zero-indexed week number by 1) + modifiers: std::collections::HashMap, +} + +impl CustomModifiers { + fn apply(&self, output: &str) -> String { + let int_formatters = vec![ + "%Y", "%C", "%y", "%m", "%d", "%e", "%w", "%u", "%U", "%W", "%G", "%g", "%V", "%j", + "%H", "%k", "%I", "%l", "%M", "%S", "%f", + ]; + + let mut modified_output = output.to_string(); + + for (modifier, value) in &self.modifiers { + // check if formatter is integer type + if !int_formatters.contains(&modifier.as_str()) { + continue; + } + + // get the strftime value of modifier + let formatted_modifier = chrono::Local::now().format(modifier).to_string(); + + // find the gotten value in the original output + if let Some(pos) = modified_output.find(&formatted_modifier) { + let start = pos; + let end = start + formatted_modifier.len(); + // replace that value with the modified value + if let Ok(num) = formatted_modifier.parse::() { + modified_output.replace_range(start..end, &(num + value).to_string()); + } + } + } + + modified_output + } +} + #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct DateConfig { /// Enable the Date widget @@ -45,6 +87,8 @@ pub enum DateFormat { DayDateMonthYear, /// Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html) Custom(String), + /// Custom format with modifiers + CustomModifiers(CustomModifiers), } impl DateFormat { @@ -58,13 +102,14 @@ impl DateFormat { }; } - fn fmt_string(&self) -> String { + pub fn fmt_string(&self) -> String { match self { DateFormat::MonthDateYear => String::from("%D"), DateFormat::YearMonthDate => String::from("%F"), DateFormat::DateMonthYear => String::from("%v"), DateFormat::DayDateMonthYear => String::from("%A %e %B %Y"), DateFormat::Custom(custom) => custom.to_string(), + DateFormat::CustomModifiers(custom) => custom.format.clone(), } } } @@ -78,9 +123,15 @@ pub struct Date { impl Date { fn output(&mut self) -> String { - chrono::Local::now() + let formatted = chrono::Local::now() .format(&self.format.fmt_string()) - .to_string() + .to_string(); + + // if custom modifiers are used, apply them + match &self.format { + DateFormat::CustomModifiers(custom) => custom.apply(&formatted), + _ => formatted, + } } } diff --git a/schema.bar.json b/schema.bar.json index 9599d49e7..a49a55643 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -198,6 +198,38 @@ } }, "additionalProperties": false + }, + { + "description": "Custom format with modifiers", + "type": "object", + "required": [ + "CustomModifiers" + ], + "properties": { + "CustomModifiers": { + "description": "Custom format with additive modifiers for integer format specifiers", + "type": "object", + "required": [ + "format", + "modifiers" + ], + "properties": { + "format": { + "description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)", + "type": "string" + }, + "modifiers": { + "description": "Additive modifiers for integer format specifiers (e.g. { \"%U\": 1 } to increment the zero-indexed week number by 1)", + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "additionalProperties": false } ] }, @@ -1413,6 +1445,38 @@ } }, "additionalProperties": false + }, + { + "description": "Custom format with modifiers", + "type": "object", + "required": [ + "CustomModifiers" + ], + "properties": { + "CustomModifiers": { + "description": "Custom format with additive modifiers for integer format specifiers", + "type": "object", + "required": [ + "format", + "modifiers" + ], + "properties": { + "format": { + "description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)", + "type": "string" + }, + "modifiers": { + "description": "Additive modifiers for integer format specifiers (e.g. { \"%U\": 1 } to increment the zero-indexed week number by 1)", + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "additionalProperties": false } ] }, @@ -2561,6 +2625,38 @@ } }, "additionalProperties": false + }, + { + "description": "Custom format with modifiers", + "type": "object", + "required": [ + "CustomModifiers" + ], + "properties": { + "CustomModifiers": { + "description": "Custom format with additive modifiers for integer format specifiers", + "type": "object", + "required": [ + "format", + "modifiers" + ], + "properties": { + "format": { + "description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)", + "type": "string" + }, + "modifiers": { + "description": "Additive modifiers for integer format specifiers (e.g. { \"%U\": 1 } to increment the zero-indexed week number by 1)", + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "additionalProperties": false } ] }, From edcba65156fc7433e93e301455754732379696d4 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 24 Jan 2025 12:48:10 -0800 Subject: [PATCH 80/86] fix(bar): consider all window types when hiding empty ws This commit ensures that floating windows, monocle containers and maximized windows will be considered when the hide_empty_workspaces option is enabled for the komorebi widget. re #1131 --- komorebi-bar/src/komorebi.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index cef64196a..336f22dc2 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -570,7 +570,11 @@ impl KomorebiNotificationState { for (i, ws) in monitor.workspaces().iter().enumerate() { let should_show = if self.hide_empty_workspaces { - focused_workspace_idx == i || !ws.containers().is_empty() + focused_workspace_idx == i + || !ws.containers().is_empty() + || !ws.floating_windows().is_empty() + || ws.monocle_container().is_some() + || ws.maximized_window().is_some() } else { true }; From 367ae95cd418dfb157cc67eaa91e09881c81637d Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 24 Jan 2025 14:37:42 -0800 Subject: [PATCH 81/86] fix(wm): populate ws rules on config reload This commit fixes a bug where workspace rules would not be populated properly on file reloads, leading to issues with the ReplaceConfiguration message handler. --- komorebi/src/process_command.rs | 2 ++ komorebi/src/static_config.rs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index c9c40204d..4c10e15fe 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -1315,6 +1315,8 @@ impl WindowManager { // Initialize the new wm wm.init()?; + wm.restore_all_windows(true)?; + // This is equivalent to StaticConfig::postload for this use case StaticConfig::reload(config, &mut wm)?; diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index f9e965f9a..4397f49d9 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -1220,6 +1220,9 @@ impl StaticConfig { value.apply_globals()?; if let Some(monitors) = value.monitors { + let mut workspace_matching_rules = WORKSPACE_MATCHING_RULES.lock(); + workspace_matching_rules.clear(); + for (i, monitor) in monitors.iter().enumerate() { if let Some(m) = wm.monitors_mut().get_mut(i) { m.ensure_workspace_count(monitor.workspaces.len()); @@ -1238,8 +1241,6 @@ impl StaticConfig { } } - let mut workspace_matching_rules = WORKSPACE_MATCHING_RULES.lock(); - workspace_matching_rules.clear(); for (j, ws) in monitor.workspaces.iter().enumerate() { if let Some(rules) = &ws.workspace_rules { for r in rules { From 15e443a46b150cb8af175870a5c97844f0833da2 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 24 Jan 2025 15:50:43 -0800 Subject: [PATCH 82/86] feat(config): add object name change title ignore list This commit adds a title regex-based ignore list for applications identified in object_name_change_applications. When a title change on an EVENT_OBJECT_NAMECHANGE matches one of these regexes, the event will never be processed as a Show. This is an edge case workaround specifically targeting the issue of web apps in Gecko-based browsers which update their page titles at a fixed regular interval, which was highlighted in #1235. resolve #1235 --- komorebi/src/lib.rs | 1 + komorebi/src/static_config.rs | 28 ++++++++++++++++++- komorebi/src/window_manager_event.rs | 13 ++++++++- schema.json | 41 +++++++++++++++++++++------- 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index 2fa4b3cd0..b6c226a28 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -128,6 +128,7 @@ lazy_static! { matching_strategy: Option::from(MatchingStrategy::Equals), }), ])); + static ref OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST: Arc>> = Arc::new(Mutex::new(Vec::new())); static ref TRANSPARENCY_BLACKLIST: Arc>> = Arc::new(Mutex::new(Vec::new())); static ref MONITOR_INDEX_PREFERENCES: Arc>> = Arc::new(Mutex::new(HashMap::new())); diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 4397f49d9..81625c81a 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -52,6 +52,7 @@ use crate::MANAGE_IDENTIFIERS; use crate::MONITOR_INDEX_PREFERENCES; use crate::NO_TITLEBAR; use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; +use crate::OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST; use crate::REGEX_IDENTIFIERS; use crate::SLOW_APPLICATION_COMPENSATION_TIME; use crate::SLOW_APPLICATION_IDENTIFIERS; @@ -357,6 +358,9 @@ pub struct StaticConfig { /// Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare) #[serde(skip_serializing_if = "Option::is_none")] pub object_name_change_applications: Option>, + /// Do not process EVENT_OBJECT_NAMECHANGE events as Show events for identified applications matching these title regexes + #[serde(skip_serializing_if = "Option::is_none")] + pub object_name_change_title_ignore_list: Option>, /// Set monitor index preferences #[serde(skip_serializing_if = "Option::is_none")] pub monitor_index_preferences: Option>, @@ -631,7 +635,17 @@ impl From<&WindowManager> for StaticConfig { border_overflow_applications: None, tray_and_multi_window_applications: None, layered_applications: None, - object_name_change_applications: None, + object_name_change_applications: Option::from( + OBJECT_NAME_CHANGE_ON_LAUNCH.lock().clone(), + ), + object_name_change_title_ignore_list: Option::from( + OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST + .lock() + .clone() + .iter() + .map(|r| r.to_string()) + .collect::>(), + ), monitor_index_preferences: Option::from(MONITOR_INDEX_PREFERENCES.lock().clone()), display_index_preferences: Option::from(DISPLAY_INDEX_PREFERENCES.lock().clone()), stackbar: None, @@ -790,6 +804,7 @@ impl StaticConfig { let mut manage_identifiers = MANAGE_IDENTIFIERS.lock(); let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock(); + let mut object_name_change_title_ignore_list = OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST.lock(); let mut layered_identifiers = LAYERED_WHITELIST.lock(); let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock(); let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock(); @@ -816,6 +831,17 @@ impl StaticConfig { )?; } + if let Some(regexes) = &mut self.object_name_change_title_ignore_list { + let mut updated = vec![]; + for r in regexes { + if let Ok(regex) = Regex::new(r) { + updated.push(regex); + } + } + + *object_name_change_title_ignore_list = updated; + } + if let Some(rules) = &mut self.layered_applications { populate_rules(rules, &mut layered_identifiers, &mut regex_identifiers)?; } diff --git a/komorebi/src/window_manager_event.rs b/komorebi/src/window_manager_event.rs index 813625edf..0c02770c9 100644 --- a/komorebi/src/window_manager_event.rs +++ b/komorebi/src/window_manager_event.rs @@ -9,6 +9,7 @@ use crate::window::should_act; use crate::window::Window; use crate::winevent::WinEvent; use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; +use crate::OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST; use crate::REGEX_IDENTIFIERS; #[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)] @@ -176,6 +177,8 @@ impl WindowManagerEvent { // [yatta\src\windows_event.rs:110] event = 32779 ObjectLocationChange let object_name_change_on_launch = OBJECT_NAME_CHANGE_ON_LAUNCH.lock(); + let object_name_change_title_ignore_list = + OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST.lock(); let regex_identifiers = REGEX_IDENTIFIERS.lock(); let title = &window.title().ok()?; @@ -183,7 +186,7 @@ impl WindowManagerEvent { let class = &window.class().ok()?; let path = &window.path().ok()?; - let should_trigger_show = should_act( + let mut should_trigger_show = should_act( title, exe_name, class, @@ -193,6 +196,14 @@ impl WindowManagerEvent { ) .is_some(); + if should_trigger_show { + for r in &*object_name_change_title_ignore_list { + if r.is_match(title) { + should_trigger_show = false; + } + } + } + // should not trigger show on minimized windows, for example when firefox sends // this message due to youtube autoplay changing the window title // https://github.com/LGUG2Z/komorebi/issues/941 diff --git a/schema.json b/schema.json index c9de2b2f3..544954962 100644 --- a/schema.json +++ b/schema.json @@ -646,16 +646,30 @@ "description": "Aspect ratio to resize with when toggling floating mode for a window", "anyOf": [ { - "description": "21:9", - "type": "null" - }, - { - "description": "16:9", - "type": "null" - }, - { - "description": "4:3", - "type": "null" + "description": "A predefined aspect ratio", + "oneOf": [ + { + "description": "21:9", + "type": "string", + "enum": [ + "Ultrawide" + ] + }, + { + "description": "16:9", + "type": "string", + "enum": [ + "Widescreen" + ] + }, + { + "description": "4:3", + "type": "string", + "enum": [ + "Standard" + ] + } + ] }, { "description": "A custom W:H aspect ratio", @@ -1490,6 +1504,13 @@ ] } }, + "object_name_change_title_ignore_list": { + "description": "Do not process EVENT_OBJECT_NAMECHANGE events as Show events for identified applications matching these title regexes", + "type": "array", + "items": { + "type": "string" + } + }, "remove_titlebar_applications": { "description": "HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars", "type": "array", From 3d7843ef84a7652e4f8b31b55aca4ab752fb747d Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 18 Feb 2025 18:54:33 -0800 Subject: [PATCH 83/86] chore(release): v0.1.34 --- Cargo.lock | 109 +++++++++++++--------------- README.md | 2 +- docs/cli/flip-layout.md | 2 +- docs/cli/focus-monitor-at-cursor.md | 12 +++ docs/cli/query.md | 2 +- docs/komorebi.bar.example.json | 2 +- docs/komorebi.example.json | 2 +- mkdocs.yml | 1 + 8 files changed, 69 insertions(+), 63 deletions(-) create mode 100644 docs/cli/focus-monitor-at-cursor.md diff --git a/Cargo.lock b/Cargo.lock index 7de40c171..34082e080 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -704,9 +704,9 @@ dependencies = [ [[package]] name = "built" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" @@ -788,9 +788,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.11" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" dependencies = [ "jobserver", "libc", @@ -863,9 +863,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.28" +version = "4.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" +checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" dependencies = [ "clap_builder", "clap_derive", @@ -873,9 +873,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.27" +version = "4.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" dependencies = [ "anstream", "anstyle", @@ -913,9 +913,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.53" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24a03c8b52922d68a1589ad61032f2c1aa5a8158d2aa0d93c6e9534944bbad6" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -1252,9 +1252,9 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ "litrs", ] @@ -1528,9 +1528,9 @@ checksum = "66f6ddac3e6ac6fd4c3d48bb8b1943472f8da0f43a4303bcd8a18aa594401c80" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -1588,7 +1588,7 @@ dependencies = [ "bit_field", "half", "lebe", - "miniz_oxide 0.8.3", + "miniz_oxide 0.8.4", "rayon-core", "smallvec", "zune-inflate", @@ -1653,7 +1653,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide 0.8.3", + "miniz_oxide 0.8.4", ] [[package]] @@ -2089,9 +2089,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" dependencies = [ "atomic-waker", "bytes", @@ -2563,9 +2563,9 @@ checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" [[package]] name = "is_debug" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ea828c9d6638a5bd3d8b14e37502b4d56cae910ccf8a5b7f51c7a0eb1d0508" +checksum = "1fe266d2e243c931d8190177f20bf7f24eed45e96f39e87dc49a27b32d12d407" [[package]] name = "is_terminal_polyfill" @@ -3078,9 +3078,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" dependencies = [ "adler2", "simd-adler32", @@ -3716,15 +3716,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "openssl" -version = "0.10.70" +version = "0.10.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ "bitflags 2.8.0", "cfg-if 1.0.0", @@ -3754,9 +3754,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.105" +version = "0.9.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" dependencies = [ "cc", "libc", @@ -3953,7 +3953,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.8.3", + "miniz_oxide 0.8.4", ] [[package]] @@ -4355,15 +4355,14 @@ checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" [[package]] name = "ring" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" dependencies = [ "cc", "cfg-if 1.0.0", "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -4395,9 +4394,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.22" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "once_cell", "rustls-pki-types", @@ -4677,9 +4676,9 @@ dependencies = [ [[package]] name = "shadow-rs" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d433b5df1e1958a668457ebe4a9c5b7bcfe844f4eb2276ac43cf273baddd54" +checksum = "6ec14cc798c29f4bf74a6c4299c657c04d4e9fba03875c1f0eec569af03aed89" dependencies = [ "const_format", "git2", @@ -4747,9 +4746,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "smithay-client-toolkit" @@ -4806,12 +4805,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" @@ -4999,9 +4992,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.16.0" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if 1.0.0", "fastrand", @@ -5229,9 +5222,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -5250,9 +5243,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.23" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "serde", @@ -5394,9 +5387,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "tz-rs" @@ -5920,9 +5913,9 @@ dependencies = [ [[package]] name = "which" -version = "7.0.1" +version = "7.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a9e33648339dc1642b0e36e21b3385e6148e289226f657c809dee59df5028" +checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" dependencies = [ "either", "env_home", @@ -6464,9 +6457,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winit" -version = "0.30.8" +version = "0.30.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f" +checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" dependencies = [ "ahash", "android-activity", @@ -6516,9 +6509,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f" +checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" dependencies = [ "memchr", ] diff --git a/README.md b/README.md index 5969860a1..08e233630 100644 --- a/README.md +++ b/README.md @@ -389,7 +389,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c Below is a simple example of how to use `komorebi-client` in a basic Rust application. ```rust -// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.33"} +// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.34"} use anyhow::Result; use komorebi_client::Notification; diff --git a/docs/cli/flip-layout.md b/docs/cli/flip-layout.md index 57d96425b..18e1c265f 100644 --- a/docs/cli/flip-layout.md +++ b/docs/cli/flip-layout.md @@ -1,7 +1,7 @@ # flip-layout ``` -Flip the layout on the focused workspace (BSP only) +Flip the layout on the focused workspace Usage: komorebic.exe flip-layout diff --git a/docs/cli/focus-monitor-at-cursor.md b/docs/cli/focus-monitor-at-cursor.md new file mode 100644 index 000000000..57a98182b --- /dev/null +++ b/docs/cli/focus-monitor-at-cursor.md @@ -0,0 +1,12 @@ +# focus-monitor-at-cursor + +``` +Focus the monitor at the current cursor location + +Usage: komorebic.exe focus-monitor-at-cursor + +Options: + -h, --help + Print help + +``` diff --git a/docs/cli/query.md b/docs/cli/query.md index 58203b62f..2f6accf41 100644 --- a/docs/cli/query.md +++ b/docs/cli/query.md @@ -7,7 +7,7 @@ Usage: komorebic.exe query Arguments: - [possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index] + [possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index, focused-workspace-name] Options: -h, --help diff --git a/docs/komorebi.bar.example.json b/docs/komorebi.bar.example.json index 9ea414796..8917bec30 100644 --- a/docs/komorebi.bar.example.json +++ b/docs/komorebi.bar.example.json @@ -1,5 +1,5 @@ { - "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.33/schema.bar.json", + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.34/schema.bar.json", "monitor": 0, "font_family": "JetBrains Mono", "theme": { diff --git a/docs/komorebi.example.json b/docs/komorebi.example.json index 5c3c60511..71b1805d0 100644 --- a/docs/komorebi.example.json +++ b/docs/komorebi.example.json @@ -1,5 +1,5 @@ { - "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.33/schema.json", + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.34/schema.json", "app_specific_configuration_path": "$Env:USERPROFILE/applications.json", "window_hiding_behaviour": "Cloak", "cross_monitor_move_behaviour": "Insert", diff --git a/mkdocs.yml b/mkdocs.yml index 8988e36ab..c8336eb6e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -127,6 +127,7 @@ nav: - cli/send-to-monitor-workspace.md - cli/move-to-monitor-workspace.md - cli/focus-monitor.md + - cli/focus-monitor-at-cursor.md - cli/focus-last-workspace.md - cli/focus-workspace.md - cli/focus-workspaces.md From 21190776c377ca1fa63371a400d6d006185d26c5 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 5 Mar 2025 16:40:57 -0800 Subject: [PATCH 84/86] chore(deps): add deny.toml and dependencies.json --- .github/workflows/windows.yaml | 8 + deny.toml | 102 +++++ dependencies.json | 771 +++++++++++++++++++++++++++++++++ 3 files changed, 881 insertions(+) create mode 100644 deny.toml create mode 100644 dependencies.json diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index 849e305ff..4cd2bb501 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -18,6 +18,14 @@ on: workflow_dispatch: jobs: + cargo-deny: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: EmbarkStudios/cargo-deny-action@v2 + build: strategy: fail-fast: true diff --git a/deny.toml b/deny.toml new file mode 100644 index 000000000..dd86e5cbf --- /dev/null +++ b/deny.toml @@ -0,0 +1,102 @@ +[graph] +targets = [ + "x86_64-pc-windows-msvc", + "i686-pc-windows-msvc", + "aarch64-pc-windows-msvc", +] +all-features = false +no-default-features = false + +[output] +feature-depth = 1 + +[advisories] +ignore = [ + { id = "RUSTSEC-2020-0016", reason = "local tcp connectivity is an opt-in feature, and there is no upgrade path for TcpStreamExt" }, +] + +[licenses] +allow = [ + "0BSD", + "Apache-2.0", + "Artistic-2.0", + "BSD-2-Clause", + "BSD-3-Clause", + "BSL-1.0", + "CC0-1.0", + "ISC", + "MIT", + "MIT-0", + "MPL-2.0", + "OFL-1.1", + "Ubuntu-font-1.0", + "Unicode-3.0", + "Zlib", + "LicenseRef-Komorebi-1.0" +] +confidence-threshold = 0.8 + +[[licenses.clarify]] +crate = "komorebi" +expression = "LicenseRef-Komorebi-1.0" +license-files = [ + { path = "LICENSE.md", hash = 0x001c7e6c }, +] + +[[licenses.clarify]] +crate = "komorebi" +expression = "LicenseRef-Komorebi-1.0" +license-files = [] + +[[licenses.clarify]] +crate = "komorebi-client" +expression = "LicenseRef-Komorebi-1.0" +license-files = [] + +[[licenses.clarify]] +crate = "komorebic" +expression = "LicenseRef-Komorebi-1.0" +license-files = [] + +[[licenses.clarify]] +crate = "komorebic-no-console" +expression = "LicenseRef-Komorebi-1.0" +license-files = [] + +[[licenses.clarify]] +crate = "komorebi-themes" +expression = "LicenseRef-Komorebi-1.0" +license-files = [] + +[[licenses.clarify]] +crate = "komorebi-gui" +expression = "LicenseRef-Komorebi-1.0" +license-files = [] + +[[licenses.clarify]] +crate = "komorebi-bar" +expression = "LicenseRef-Komorebi-1.0" +license-files = [] + +[[licenses.clarify]] +crate = "base16-egui-themes" +expression = "MIT" +license-files = [] + +[bans] +multiple-versions = "allow" +wildcards = "allow" +highlight = "all" +workspace-default-features = "allow" +external-default-features = "allow" + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +allow-git = [ + "https://github.com/LGUG2Z/base16-egui-themes", + "https://github.com/LGUG2Z/catppuccin-egui", + "https://github.com/LGUG2Z/windows-icons", + "https://github.com/LGUG2Z/win32-display-data", +] diff --git a/dependencies.json b/dependencies.json new file mode 100644 index 000000000..f5eaf750b --- /dev/null +++ b/dependencies.json @@ -0,0 +1,771 @@ +{ + "licenses": [ + [ + "0BSD", + [ + "adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", + "win32-display-data 0.1.0 git+https://github.com/LGUG2Z/win32-display-data?rev=55cebdebfbd68dbd14945a1ba90f6b05b7be2893" + ] + ], + [ + "Apache-2.0", + [ + "ab_glyph 0.2.29 registry+https://github.com/rust-lang/crates.io-index", + "ab_glyph_rasterizer 0.1.8 registry+https://github.com/rust-lang/crates.io-index", + "accesskit 0.17.1 registry+https://github.com/rust-lang/crates.io-index", + "accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index", + "accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index", + "accesskit_winit 0.23.1 registry+https://github.com/rust-lang/crates.io-index", + "adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", + "ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index", + "anstream 0.6.18 registry+https://github.com/rust-lang/crates.io-index", + "anstyle 1.0.10 registry+https://github.com/rust-lang/crates.io-index", + "anstyle-parse 0.2.6 registry+https://github.com/rust-lang/crates.io-index", + "anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index", + "anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index", + "anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index", + "arboard 3.4.1 registry+https://github.com/rust-lang/crates.io-index", + "arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index", + "atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index", + "autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index", + "backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index", + "backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index", + "bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index", + "bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index", + "bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index", + "bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index", + "bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index", + "bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index", + "cc 1.2.16 registry+https://github.com/rust-lang/crates.io-index", + "cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index", + "cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index", + "chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index", + "clap 4.5.31 registry+https://github.com/rust-lang/crates.io-index", + "clap_builder 4.5.31 registry+https://github.com/rust-lang/crates.io-index", + "clap_derive 4.5.28 registry+https://github.com/rust-lang/crates.io-index", + "clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index", + "color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index", + "color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index", + "crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-channel 0.5.14 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index", + "ctrlc 3.4.5 registry+https://github.com/rust-lang/crates.io-index", + "cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "deranged 0.3.11 registry+https://github.com/rust-lang/crates.io-index", + "dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index", + "dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index", + "document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index", + "dpi 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index", + "dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index", + "ecolor 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "eframe 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index", + "egui-winit 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui_extras 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui_glow 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "either 1.14.0 registry+https://github.com/rust-lang/crates.io-index", + "emath 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index", + "enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index", + "enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index", + "env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "epaint 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index", + "eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index", + "fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index", + "fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index", + "filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index", + "flate2 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index", + "form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index", + "futures 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-channel 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-core 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-executor 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-io 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-macro 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index", + "getrandom 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index", + "git2 0.20.0 registry+https://github.com/rust-lang/crates.io-index", + "gl_generator 0.14.0 registry+https://github.com/rust-lang/crates.io-index", + "glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index", + "glutin 0.32.2 registry+https://github.com/rust-lang/crates.io-index", + "glutin_egl_sys 0.7.1 registry+https://github.com/rust-lang/crates.io-index", + "glutin_wgl_sys 0.6.1 registry+https://github.com/rust-lang/crates.io-index", + "half 2.4.1 registry+https://github.com/rust-lang/crates.io-index", + "hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index", + "heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index", + "hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "http 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index", + "hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index", + "iana-time-zone 0.1.61 registry+https://github.com/rust-lang/crates.io-index", + "idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index", + "idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "image 0.25.5 registry+https://github.com/rust-lang/crates.io-index", + "image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index", + "immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index", + "indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index", + "indexmap 2.7.1 registry+https://github.com/rust-lang/crates.io-index", + "ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index", + "is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index", + "itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index", + "itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index", + "itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index", + "jobserver 0.1.32 registry+https://github.com/rust-lang/crates.io-index", + "jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "khronos_api 3.1.0 registry+https://github.com/rust-lang/crates.io-index", + "lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "libc 0.2.170 registry+https://github.com/rust-lang/crates.io-index", + "libgit2-sys 0.18.0+1.9.0 registry+https://github.com/rust-lang/crates.io-index", + "libz-sys 1.1.21 registry+https://github.com/rust-lang/crates.io-index", + "litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index", + "log 0.4.26 registry+https://github.com/rust-lang/crates.io-index", + "miette 7.5.0 registry+https://github.com/rust-lang/crates.io-index", + "miette-derive 7.5.0 registry+https://github.com/rust-lang/crates.io-index", + "mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index", + "minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index", + "miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index", + "native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index", + "net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index", + "nohash-hasher 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "ntapi 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "num 0.4.3 registry+https://github.com/rust-lang/crates.io-index", + "num-bigint 0.4.6 registry+https://github.com/rust-lang/crates.io-index", + "num-complex 0.4.6 registry+https://github.com/rust-lang/crates.io-index", + "num-conv 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index", + "num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index", + "num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index", + "num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index", + "num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index", + "once_cell 1.20.3 registry+https://github.com/rust-lang/crates.io-index", + "owned_ttf_parser 0.25.0 registry+https://github.com/rust-lang/crates.io-index", + "parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index", + "parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index", + "paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index", + "percent-encoding 2.3.1 registry+https://github.com/rust-lang/crates.io-index", + "pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index", + "pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index", + "png 0.17.16 registry+https://github.com/rust-lang/crates.io-index", + "powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "ppv-lite86 0.2.20 registry+https://github.com/rust-lang/crates.io-index", + "proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", + "proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index", + "proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index", + "profiling 1.0.16 registry+https://github.com/rust-lang/crates.io-index", + "profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index", + "qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index", + "quote 1.0.39 registry+https://github.com/rust-lang/crates.io-index", + "rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index", + "rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index", + "raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index", + "rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index", + "rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index", + "regex 1.11.1 registry+https://github.com/rust-lang/crates.io-index", + "regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index", + "regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index", + "regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index", + "reqwest 0.12.12 registry+https://github.com/rust-lang/crates.io-index", + "rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index", + "rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index", + "rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index", + "rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index", + "ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index", + "scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "serde 1.0.218 registry+https://github.com/rust-lang/crates.io-index", + "serde_derive 1.0.218 registry+https://github.com/rust-lang/crates.io-index", + "serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index", + "serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index", + "serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index", + "serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index", + "serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index", + "serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index", + "shadow-rs 1.0.1 registry+https://github.com/rust-lang/crates.io-index", + "shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index", + "smallvec 1.14.0 registry+https://github.com/rust-lang/crates.io-index", + "smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index", + "socket2 0.5.8 registry+https://github.com/rust-lang/crates.io-index", + "stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "supports-color 3.0.2 registry+https://github.com/rust-lang/crates.io-index", + "supports-hyperlinks 3.1.0 registry+https://github.com/rust-lang/crates.io-index", + "supports-unicode 3.0.0 registry+https://github.com/rust-lang/crates.io-index", + "syn 2.0.99 registry+https://github.com/rust-lang/crates.io-index", + "sync_wrapper 1.0.2 registry+https://github.com/rust-lang/crates.io-index", + "tempfile 3.17.1 registry+https://github.com/rust-lang/crates.io-index", + "terminal_size 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index", + "thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index", + "thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index", + "thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index", + "thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index", + "time 0.3.37 registry+https://github.com/rust-lang/crates.io-index", + "time-core 0.1.2 registry+https://github.com/rust-lang/crates.io-index", + "ttf-parser 0.25.1 registry+https://github.com/rust-lang/crates.io-index", + "typenum 1.18.0 registry+https://github.com/rust-lang/crates.io-index", + "tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index", + "tzdb 0.7.2 registry+https://github.com/rust-lang/crates.io-index", + "unicase 2.8.1 registry+https://github.com/rust-lang/crates.io-index", + "unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index", + "unicode-linebreak 0.1.5 registry+https://github.com/rust-lang/crates.io-index", + "unicode-segmentation 1.12.0 registry+https://github.com/rust-lang/crates.io-index", + "unicode-width 0.1.14 registry+https://github.com/rust-lang/crates.io-index", + "unicode-width 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "unicode-xid 0.2.6 registry+https://github.com/rust-lang/crates.io-index", + "uom 0.36.0 registry+https://github.com/rust-lang/crates.io-index", + "url 2.5.4 registry+https://github.com/rust-lang/crates.io-index", + "utf16_iter 1.0.5 registry+https://github.com/rust-lang/crates.io-index", + "utf8_iter 1.0.4 registry+https://github.com/rust-lang/crates.io-index", + "utf8parse 0.2.2 registry+https://github.com/rust-lang/crates.io-index", + "vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index", + "version_check 0.9.5 registry+https://github.com/rust-lang/crates.io-index", + "web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "webbrowser 1.0.3 registry+https://github.com/rust-lang/crates.io-index", + "weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index", + "winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index", + "windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.52.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-interface 0.59.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-link 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-registry 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index", + "windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-result 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "winit 0.30.9 registry+https://github.com/rust-lang/crates.io-index", + "wmi 0.15.1 registry+https://github.com/rust-lang/crates.io-index", + "write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index", + "zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index", + "zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index", + "zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index", + "zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index", + "zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "Artistic-2.0", + [ + "file-id 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "notify-debouncer-full 0.1.0 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "BSD-2-Clause", + [ + "av1-grain 0.2.3 registry+https://github.com/rust-lang/crates.io-index", + "rav1e 0.7.1 registry+https://github.com/rust-lang/crates.io-index", + "v_frame 0.3.8 registry+https://github.com/rust-lang/crates.io-index", + "zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index", + "zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "BSD-3-Clause", + [ + "alloc-no-stdlib 2.0.4 registry+https://github.com/rust-lang/crates.io-index", + "alloc-stdlib 0.2.2 registry+https://github.com/rust-lang/crates.io-index", + "avif-serialize 0.8.3 registry+https://github.com/rust-lang/crates.io-index", + "brotli 3.5.0 registry+https://github.com/rust-lang/crates.io-index", + "brotli-decompressor 2.5.1 registry+https://github.com/rust-lang/crates.io-index", + "encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index", + "exr 1.73.0 registry+https://github.com/rust-lang/crates.io-index", + "lebe 0.5.2 registry+https://github.com/rust-lang/crates.io-index", + "ravif 0.11.11 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "BSL-1.0", + [ + "clipboard-win 5.4.0 registry+https://github.com/rust-lang/crates.io-index", + "error-code 3.3.1 registry+https://github.com/rust-lang/crates.io-index", + "ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "CC0-1.0", + [ + "dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index", + "file-id 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index", + "notify 6.1.1 registry+https://github.com/rust-lang/crates.io-index", + "notify-debouncer-full 0.1.0 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "ISC", + [ + "is_ci 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "libloading 0.8.6 registry+https://github.com/rust-lang/crates.io-index", + "rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index", + "starship-battery 0.10.0 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "MIT", + [ + "accesskit 0.17.1 registry+https://github.com/rust-lang/crates.io-index", + "accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index", + "accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index", + "adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", + "ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index", + "aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index", + "aligned-vec 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "anstream 0.6.18 registry+https://github.com/rust-lang/crates.io-index", + "anstyle 1.0.10 registry+https://github.com/rust-lang/crates.io-index", + "anstyle-parse 0.2.6 registry+https://github.com/rust-lang/crates.io-index", + "anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index", + "anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index", + "anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index", + "arboard 3.4.1 registry+https://github.com/rust-lang/crates.io-index", + "arg_enum_proc_macro 0.3.4 registry+https://github.com/rust-lang/crates.io-index", + "arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index", + "atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index", + "autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index", + "backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index", + "backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index", + "bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index", + "bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index", + "bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index", + "bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index", + "brotli 3.5.0 registry+https://github.com/rust-lang/crates.io-index", + "brotli-decompressor 2.5.1 registry+https://github.com/rust-lang/crates.io-index", + "built 0.7.7 registry+https://github.com/rust-lang/crates.io-index", + "bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index", + "bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index", + "byteorder 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "byteorder-lite 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "bytes 1.10.0 registry+https://github.com/rust-lang/crates.io-index", + "catppuccin-egui 5.3.1 git+https://github.com/LGUG2Z/catppuccin-egui?rev=bdaff30959512c4f7ee7304117076a48633d777f", + "cc 1.2.16 registry+https://github.com/rust-lang/crates.io-index", + "cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index", + "cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index", + "cfg_aliases 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index", + "clap 4.5.31 registry+https://github.com/rust-lang/crates.io-index", + "clap_builder 4.5.31 registry+https://github.com/rust-lang/crates.io-index", + "clap_derive 4.5.28 registry+https://github.com/rust-lang/crates.io-index", + "clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index", + "color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index", + "color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "color_quant 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index", + "crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-channel 0.5.14 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index", + "crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index", + "ctrlc 3.4.5 registry+https://github.com/rust-lang/crates.io-index", + "cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "deranged 0.3.11 registry+https://github.com/rust-lang/crates.io-index", + "dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index", + "dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index", + "document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index", + "dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index", + "ecolor 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "eframe 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index", + "egui-winit 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui_extras 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "egui_glow 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "either 1.14.0 registry+https://github.com/rust-lang/crates.io-index", + "emath 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index", + "enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index", + "enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index", + "env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "epaint 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index", + "equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index", + "eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index", + "fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index", + "fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index", + "filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index", + "flate2 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index", + "font-loader 0.11.0 registry+https://github.com/rust-lang/crates.io-index", + "form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index", + "fs-tail 0.1.4 registry+https://github.com/rust-lang/crates.io-index", + "futures 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-channel 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-core 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-executor 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-io 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-macro 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index", + "getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index", + "getrandom 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "getset 0.1.5 registry+https://github.com/rust-lang/crates.io-index", + "gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index", + "git2 0.20.0 registry+https://github.com/rust-lang/crates.io-index", + "glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index", + "glutin-winit 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "h2 0.4.8 registry+https://github.com/rust-lang/crates.io-index", + "half 2.4.1 registry+https://github.com/rust-lang/crates.io-index", + "hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index", + "heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index", + "hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index", + "http 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "http-body 1.0.1 registry+https://github.com/rust-lang/crates.io-index", + "http-body-util 0.1.2 registry+https://github.com/rust-lang/crates.io-index", + "httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index", + "hyper 1.6.0 registry+https://github.com/rust-lang/crates.io-index", + "hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index", + "hyper-util 0.1.10 registry+https://github.com/rust-lang/crates.io-index", + "iana-time-zone 0.1.61 registry+https://github.com/rust-lang/crates.io-index", + "idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index", + "idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "image 0.25.5 registry+https://github.com/rust-lang/crates.io-index", + "image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index", + "indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index", + "indexmap 2.7.1 registry+https://github.com/rust-lang/crates.io-index", + "ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index", + "is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index", + "itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index", + "itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index", + "itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index", + "jobserver 0.1.32 registry+https://github.com/rust-lang/crates.io-index", + "jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "libc 0.2.170 registry+https://github.com/rust-lang/crates.io-index", + "libgit2-sys 0.18.0+1.9.0 registry+https://github.com/rust-lang/crates.io-index", + "libz-sys 1.1.21 registry+https://github.com/rust-lang/crates.io-index", + "litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index", + "log 0.4.26 registry+https://github.com/rust-lang/crates.io-index", + "loop9 0.1.5 registry+https://github.com/rust-lang/crates.io-index", + "matchers 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "maybe-rayon 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "memchr 2.7.4 registry+https://github.com/rust-lang/crates.io-index", + "memoffset 0.9.1 registry+https://github.com/rust-lang/crates.io-index", + "mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index", + "mime_guess2 2.0.5 registry+https://github.com/rust-lang/crates.io-index", + "minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index", + "mio 1.0.3 registry+https://github.com/rust-lang/crates.io-index", + "miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index", + "nanoid 0.4.0 registry+https://github.com/rust-lang/crates.io-index", + "native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index", + "net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index", + "netdev 0.32.0 registry+https://github.com/rust-lang/crates.io-index", + "new_debug_unreachable 1.0.6 registry+https://github.com/rust-lang/crates.io-index", + "nohash-hasher 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "nom 7.1.3 registry+https://github.com/rust-lang/crates.io-index", + "noop_proc_macro 0.3.0 registry+https://github.com/rust-lang/crates.io-index", + "ntapi 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "nu-ansi-term 0.46.0 registry+https://github.com/rust-lang/crates.io-index", + "num 0.4.3 registry+https://github.com/rust-lang/crates.io-index", + "num-bigint 0.4.6 registry+https://github.com/rust-lang/crates.io-index", + "num-complex 0.4.6 registry+https://github.com/rust-lang/crates.io-index", + "num-conv 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index", + "num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index", + "num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index", + "num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index", + "num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index", + "once_cell 1.20.3 registry+https://github.com/rust-lang/crates.io-index", + "os_info 3.10.0 registry+https://github.com/rust-lang/crates.io-index", + "overload 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "owo-colors 3.5.0 registry+https://github.com/rust-lang/crates.io-index", + "owo-colors 4.2.0 registry+https://github.com/rust-lang/crates.io-index", + "parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index", + "parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index", + "paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index", + "percent-encoding 2.3.1 registry+https://github.com/rust-lang/crates.io-index", + "pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index", + "pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index", + "png 0.17.16 registry+https://github.com/rust-lang/crates.io-index", + "powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "powershell_script 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "ppv-lite86 0.2.20 registry+https://github.com/rust-lang/crates.io-index", + "proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", + "proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index", + "proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index", + "profiling 1.0.16 registry+https://github.com/rust-lang/crates.io-index", + "profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index", + "qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index", + "quote 1.0.39 registry+https://github.com/rust-lang/crates.io-index", + "rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index", + "rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index", + "random_word 0.4.3 registry+https://github.com/rust-lang/crates.io-index", + "raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index", + "rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index", + "rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index", + "regex 1.11.1 registry+https://github.com/rust-lang/crates.io-index", + "regex-automata 0.1.10 registry+https://github.com/rust-lang/crates.io-index", + "regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index", + "regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index", + "regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index", + "reqwest 0.12.12 registry+https://github.com/rust-lang/crates.io-index", + "rgb 0.8.50 registry+https://github.com/rust-lang/crates.io-index", + "rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index", + "rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index", + "rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index", + "rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index", + "same-file 1.0.6 registry+https://github.com/rust-lang/crates.io-index", + "schannel 0.1.27 registry+https://github.com/rust-lang/crates.io-index", + "schemars 0.8.22 registry+https://github.com/rust-lang/crates.io-index", + "schemars_derive 0.8.22 registry+https://github.com/rust-lang/crates.io-index", + "scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "serde 1.0.218 registry+https://github.com/rust-lang/crates.io-index", + "serde_derive 1.0.218 registry+https://github.com/rust-lang/crates.io-index", + "serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index", + "serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index", + "serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index", + "serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index", + "serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index", + "serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index", + "shadow-rs 1.0.1 registry+https://github.com/rust-lang/crates.io-index", + "sharded-slab 0.1.7 registry+https://github.com/rust-lang/crates.io-index", + "shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index", + "simd-adler32 0.3.7 registry+https://github.com/rust-lang/crates.io-index", + "simd_helpers 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "slab 0.4.9 registry+https://github.com/rust-lang/crates.io-index", + "smallvec 1.14.0 registry+https://github.com/rust-lang/crates.io-index", + "smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index", + "socket2 0.5.8 registry+https://github.com/rust-lang/crates.io-index", + "stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index", + "static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "strsim 0.11.1 registry+https://github.com/rust-lang/crates.io-index", + "strum 0.27.1 registry+https://github.com/rust-lang/crates.io-index", + "strum_macros 0.27.1 registry+https://github.com/rust-lang/crates.io-index", + "syn 2.0.99 registry+https://github.com/rust-lang/crates.io-index", + "synstructure 0.13.1 registry+https://github.com/rust-lang/crates.io-index", + "sysinfo 0.33.1 registry+https://github.com/rust-lang/crates.io-index", + "tempfile 3.17.1 registry+https://github.com/rust-lang/crates.io-index", + "terminal_size 0.4.1 registry+https://github.com/rust-lang/crates.io-index", + "textwrap 0.16.2 registry+https://github.com/rust-lang/crates.io-index", + "thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index", + "thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index", + "thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index", + "thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index", + "thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index", + "tiff 0.9.1 registry+https://github.com/rust-lang/crates.io-index", + "time 0.3.37 registry+https://github.com/rust-lang/crates.io-index", + "time-core 0.1.2 registry+https://github.com/rust-lang/crates.io-index", + "tokio 1.43.0 registry+https://github.com/rust-lang/crates.io-index", + "tokio-native-tls 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "tokio-util 0.7.13 registry+https://github.com/rust-lang/crates.io-index", + "tower 0.5.2 registry+https://github.com/rust-lang/crates.io-index", + "tower-layer 0.3.3 registry+https://github.com/rust-lang/crates.io-index", + "tower-service 0.3.3 registry+https://github.com/rust-lang/crates.io-index", + "tracing 0.1.41 registry+https://github.com/rust-lang/crates.io-index", + "tracing-appender 0.2.3 registry+https://github.com/rust-lang/crates.io-index", + "tracing-attributes 0.1.28 registry+https://github.com/rust-lang/crates.io-index", + "tracing-core 0.1.33 registry+https://github.com/rust-lang/crates.io-index", + "tracing-error 0.2.1 registry+https://github.com/rust-lang/crates.io-index", + "tracing-log 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "tracing-subscriber 0.3.19 registry+https://github.com/rust-lang/crates.io-index", + "try-lock 0.2.5 registry+https://github.com/rust-lang/crates.io-index", + "ttf-parser 0.25.1 registry+https://github.com/rust-lang/crates.io-index", + "typenum 1.18.0 registry+https://github.com/rust-lang/crates.io-index", + "tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index", + "uds_windows 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "unicase 2.8.1 registry+https://github.com/rust-lang/crates.io-index", + "unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index", + "unicode-segmentation 1.12.0 registry+https://github.com/rust-lang/crates.io-index", + "unicode-width 0.1.14 registry+https://github.com/rust-lang/crates.io-index", + "unicode-width 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "unicode-xid 0.2.6 registry+https://github.com/rust-lang/crates.io-index", + "unsafe-libyaml 0.2.11 registry+https://github.com/rust-lang/crates.io-index", + "uom 0.36.0 registry+https://github.com/rust-lang/crates.io-index", + "url 2.5.4 registry+https://github.com/rust-lang/crates.io-index", + "utf16_iter 1.0.5 registry+https://github.com/rust-lang/crates.io-index", + "utf8_iter 1.0.4 registry+https://github.com/rust-lang/crates.io-index", + "utf8parse 0.2.2 registry+https://github.com/rust-lang/crates.io-index", + "vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index", + "version_check 0.9.5 registry+https://github.com/rust-lang/crates.io-index", + "walkdir 2.5.0 registry+https://github.com/rust-lang/crates.io-index", + "want 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "webbrowser 1.0.3 registry+https://github.com/rust-lang/crates.io-index", + "weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index", + "which 7.0.2 registry+https://github.com/rust-lang/crates.io-index", + "winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index", + "winapi-util 0.1.9 registry+https://github.com/rust-lang/crates.io-index", + "windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.52.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=d67cc9920aa9b4883393e411fb4fa2ddd4c498b5", + "windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-interface 0.59.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-link 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-registry 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index", + "windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-result 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index", + "windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index", + "windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", + "windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", + "winput 0.2.5 registry+https://github.com/rust-lang/crates.io-index", + "winreg 0.55.0 registry+https://github.com/rust-lang/crates.io-index", + "winsafe 0.0.19 registry+https://github.com/rust-lang/crates.io-index", + "wmi 0.15.1 registry+https://github.com/rust-lang/crates.io-index", + "write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index", + "xml-rs 0.8.25 registry+https://github.com/rust-lang/crates.io-index", + "zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index", + "zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index", + "zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index", + "zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index", + "zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "MIT-0", + [ + "dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index", + "tzdb_data 0.2.1 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "MPL-2.0", + [ + "option-ext 0.2.0 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "OFL-1.1", + [ + "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "Ubuntu-font-1.0", + [ + "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "Unicode-3.0", + [ + "icu_collections 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_locid 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_locid_transform 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_locid_transform_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_normalizer 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_normalizer_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_properties 1.5.1 registry+https://github.com/rust-lang/crates.io-index", + "icu_properties_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_provider 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "icu_provider_macros 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "litemap 0.7.5 registry+https://github.com/rust-lang/crates.io-index", + "tinystr 0.7.6 registry+https://github.com/rust-lang/crates.io-index", + "unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index", + "writeable 0.5.5 registry+https://github.com/rust-lang/crates.io-index", + "yoke 0.7.5 registry+https://github.com/rust-lang/crates.io-index", + "yoke-derive 0.7.5 registry+https://github.com/rust-lang/crates.io-index", + "zerofrom 0.1.6 registry+https://github.com/rust-lang/crates.io-index", + "zerofrom-derive 0.1.6 registry+https://github.com/rust-lang/crates.io-index", + "zerovec 0.10.4 registry+https://github.com/rust-lang/crates.io-index", + "zerovec-derive 0.10.3 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "Unlicense", + [ + "aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index", + "byteorder 1.5.0 registry+https://github.com/rust-lang/crates.io-index", + "byteorder-lite 0.1.0 registry+https://github.com/rust-lang/crates.io-index", + "memchr 2.7.4 registry+https://github.com/rust-lang/crates.io-index", + "regex-automata 0.1.10 registry+https://github.com/rust-lang/crates.io-index", + "same-file 1.0.6 registry+https://github.com/rust-lang/crates.io-index", + "walkdir 2.5.0 registry+https://github.com/rust-lang/crates.io-index", + "winapi-util 0.1.9 registry+https://github.com/rust-lang/crates.io-index" + ] + ], + [ + "Zlib", + [ + "bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index", + "bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index", + "const_format 0.2.34 registry+https://github.com/rust-lang/crates.io-index", + "const_format_proc_macros 0.2.34 registry+https://github.com/rust-lang/crates.io-index", + "cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index", + "foldhash 0.1.4 registry+https://github.com/rust-lang/crates.io-index", + "glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index", + "miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index", + "raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index", + "zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index", + "zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index", + "zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index" + ] + ] + ] +} From 641190de500739f4d2907624fb0c88148d6a2c6e Mon Sep 17 00:00:00 2001 From: Jerry Kingsbury Date: Wed, 5 Mar 2025 01:39:58 -0600 Subject: [PATCH 85/86] test(wm): add window manager unit tests Created a test that creates the WM instance and ensures the instance is running. The test creates a custom socket and then cleans up the socket file after completion. Created a test that creates a WM instance, monitor instance, and workpace. The tests checks to ensure that the expected workspace is focused properly. Included recommended fixes to ensure that the focus_workspace function is used correctly and that the test accurately checks the workspaces length, current workspace index, and switching to an existing workspace. --- Cargo.lock | 10 ++++ komorebi/Cargo.toml | 1 + komorebi/src/main.rs | 1 + komorebi/src/window_manager.rs | 7 ++- komorebi/tests/window_manager.rs | 86 ++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 komorebi/tests/window_manager.rs diff --git a/Cargo.lock b/Cargo.lock index 30bbb77d9..c676027bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2678,6 +2678,7 @@ dependencies = [ "tracing-appender", "tracing-subscriber", "uds_windows", + "uuid", "which", "win32-display-data", "windows 0.60.0", @@ -5546,6 +5547,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" +dependencies = [ + "getrandom 0.3.1", +] + [[package]] name = "v_frame" version = "0.3.8" diff --git a/komorebi/Cargo.toml b/komorebi/Cargo.toml index 1d814ccea..54c002d4b 100644 --- a/komorebi/Cargo.toml +++ b/komorebi/Cargo.toml @@ -55,6 +55,7 @@ shadow-rs = { workspace = true } [dev-dependencies] reqwest = { version = "0.12", features = ["blocking"] } +uuid = { version = "1", features = ["v4"] } [features] default = ["schemars"] diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index a76d97f9f..40a8569b1 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -235,6 +235,7 @@ fn main() -> Result<()> { } else { Arc::new(Mutex::new(WindowManager::new( winevent_listener::event_rx(), + None, )?)) }; diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index fce739fba..6d53273a7 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -398,8 +398,11 @@ impl EnforceWorkspaceRuleOp { impl WindowManager { #[tracing::instrument] - pub fn new(incoming: Receiver) -> Result { - let socket = DATA_DIR.join("komorebi.sock"); + pub fn new( + incoming: Receiver, + custom_socket_path: Option, + ) -> Result { + let socket = custom_socket_path.unwrap_or_else(|| DATA_DIR.join("komorebi.sock")); match std::fs::remove_file(&socket) { Ok(()) => {} diff --git a/komorebi/tests/window_manager.rs b/komorebi/tests/window_manager.rs new file mode 100644 index 000000000..887d68943 --- /dev/null +++ b/komorebi/tests/window_manager.rs @@ -0,0 +1,86 @@ +#[cfg(test)] +mod window_manager_tests { + use color_eyre::eyre::anyhow; + use crossbeam_channel::bounded; + use crossbeam_channel::Receiver; + use crossbeam_channel::Sender; + use komorebi::monitor; + use komorebi::window_manager::WindowManager; + use komorebi::Rect; + use komorebi::WindowManagerEvent; + use komorebi::DATA_DIR; + use uuid::Uuid; + + #[test] + fn test_create_window_manager() { + let (_sender, receiver): (Sender, Receiver) = + bounded(1); + let socket_name = format!("komorebi-test-{}.sock", Uuid::new_v4()); + let socket = Some(DATA_DIR.join(socket_name)); + let wm = WindowManager::new(receiver, socket.clone()); + assert!(wm.is_ok()); + + if let Some(ref socket_path) = socket { + let _ = std::fs::remove_file(socket_path); + } + } + + #[test] + fn test_focus_workspace() { + let (_sender, receiver): (Sender, Receiver) = + bounded(1); + let socket_name = format!("komorebi-test-{}.sock", Uuid::new_v4()); + let socket = Some(DATA_DIR.join(socket_name)); + let mut wm = WindowManager::new(receiver, socket.clone()).unwrap(); + let m = monitor::new( + 0, + Rect::default(), + Rect::default(), + "TestMonitor".to_string(), + "TestDevice".to_string(), + "TestDeviceID".to_string(), + Some("TestMonitorID".to_string()), + ); + + wm.monitors.elements_mut().push_back(m); + + let workspace_idx = { + let monitor = wm + .focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no workspace")) + .unwrap(); + monitor.new_workspace_idx() + }; + + { + let monitor = wm + .focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no workspace")) + .unwrap(); + monitor + .focus_workspace(workspace_idx) + .expect("failed to focus workspace"); + } + + { + let monitor = wm + .focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no workspace")) + .unwrap(); + monitor + .focus_workspace(workspace_idx + 1) + .expect("failed to focus workspace"); + assert_eq!(monitor.workspaces().len(), 3) + } + + assert_eq!(wm.focused_workspace_idx().unwrap(), 2); + + wm.focus_workspace(0).ok(); + + assert_eq!(wm.focused_workspace_idx().unwrap(), 0); + + if let Some(ref socket_path) = socket { + let _ = std::fs::remove_file(socket_path); + } + } +} From e1eb3ca85d4924139a5fa1a8dd16d9ff4d9f4f85 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 5 Mar 2025 21:53:07 -0800 Subject: [PATCH 86/86] test(wm): colocate tests with src files, add socket msg test --- komorebi/src/process_command.rs | 71 ++++++++++++++++++++++++++ komorebi/src/static_config.rs | 33 ++++++++++++ komorebi/src/window_manager.rs | 78 +++++++++++++++++++++++++++++ komorebi/tests/compat.rs | 29 ----------- komorebi/tests/window_manager.rs | 86 -------------------------------- 5 files changed, 182 insertions(+), 115 deletions(-) delete mode 100644 komorebi/tests/compat.rs delete mode 100644 komorebi/tests/window_manager.rs diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index ac7bdf426..b6999f965 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -2069,3 +2069,74 @@ pub fn read_commands_tcp( Ok(()) } + +#[cfg(test)] +mod tests { + use crate::monitor; + use crate::window_manager::WindowManager; + use crate::Rect; + use crate::SocketMessage; + use crate::WindowManagerEvent; + use crate::DATA_DIR; + use crossbeam_channel::bounded; + use crossbeam_channel::Receiver; + use crossbeam_channel::Sender; + use std::io::BufRead; + use std::io::BufReader; + use std::io::Write; + use std::str::FromStr; + use std::time::Duration; + use uds_windows::UnixStream; + use uuid::Uuid; + + fn send_socket_message(socket: &str, message: SocketMessage) { + let socket = DATA_DIR.join(socket); + let mut stream = UnixStream::connect(socket).unwrap(); + stream + .set_write_timeout(Some(Duration::from_secs(1))) + .unwrap(); + stream + .write_all(serde_json::to_string(&message).unwrap().as_bytes()) + .unwrap(); + } + + #[test] + fn test_receive_socket_message() { + let (_sender, receiver): (Sender, Receiver) = + bounded(1); + let socket_name = format!("komorebi-test-{}.sock", Uuid::new_v4()); + let socket_path = DATA_DIR.join(&socket_name); + let mut wm = WindowManager::new(receiver, Some(socket_path.clone())).unwrap(); + let m = monitor::new( + 0, + Rect::default(), + Rect::default(), + "TestMonitor".to_string(), + "TestDevice".to_string(), + "TestDeviceID".to_string(), + Some("TestMonitorID".to_string()), + ); + + wm.monitors_mut().push_back(m); + + // send a message + send_socket_message(&socket_name, SocketMessage::FocusWorkspaceNumber(5)); + + let (stream, _) = wm.command_listener.accept().unwrap(); + let reader = BufReader::new(stream.try_clone().unwrap()); + let next = reader.lines().next(); + + // read and deserialize the message + let message_string = next.unwrap().unwrap(); + let message = SocketMessage::from_str(&message_string).unwrap(); + assert!(matches!(message, SocketMessage::FocusWorkspaceNumber(5))); + + // process the message + wm.process_command(message, stream).unwrap(); + + // check the updated window manager state + assert_eq!(wm.focused_workspace_idx().unwrap(), 5); + + std::fs::remove_file(socket_path).unwrap(); + } +} diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 8f75d5fae..594fbfb8b 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -1721,3 +1721,36 @@ fn populate_rules( Ok(()) } + +#[cfg(test)] +mod tests { + use crate::StaticConfig; + + #[test] + fn backwards_compat() { + let root = vec!["0.1.17", "0.1.18", "0.1.19"]; + let docs = vec![ + "0.1.20", "0.1.21", "0.1.22", "0.1.23", "0.1.24", "0.1.25", "0.1.26", "0.1.27", + "0.1.28", "0.1.29", "0.1.30", "0.1.31", "0.1.32", "0.1.33", "0.1.34", + ]; + + let mut versions = vec![]; + + let client = reqwest::blocking::Client::new(); + + for version in root { + let request = client.get(format!("https://raw.githubusercontent.com/LGUG2Z/komorebi/refs/tags/v{version}/komorebi.example.json")).header("User-Agent", "komorebi-backwards-compat-test").build().unwrap(); + versions.push((version, client.execute(request).unwrap().text().unwrap())); + } + + for version in docs { + let request = client.get(format!("https://raw.githubusercontent.com/LGUG2Z/komorebi/refs/tags/v{version}/docs/komorebi.example.json")).header("User-Agent", "komorebi-backwards-compat-test").build().unwrap(); + versions.push((version, client.execute(request).unwrap().text().unwrap())); + } + + for (version, config) in versions { + println!("{version}"); + StaticConfig::read_raw(&config).unwrap(); + } + } +} diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 6d53273a7..1ef4563d6 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -3660,3 +3660,81 @@ impl WindowManager { } } } + +#[cfg(test)] +mod tests { + use crate::monitor; + use crate::window_manager::WindowManager; + use crate::Rect; + use crate::WindowManagerEvent; + use crate::DATA_DIR; + use crossbeam_channel::bounded; + use crossbeam_channel::Receiver; + use crossbeam_channel::Sender; + use uuid::Uuid; + + #[test] + fn test_create_window_manager() { + let (_sender, receiver): (Sender, Receiver) = + bounded(1); + let socket_name = format!("komorebi-test-{}.sock", Uuid::new_v4()); + let socket = Some(DATA_DIR.join(socket_name)); + let wm = WindowManager::new(receiver, socket.clone()); + assert!(wm.is_ok()); + + if let Some(ref socket_path) = socket { + let _ = std::fs::remove_file(socket_path); + } + } + + #[test] + fn test_focus_workspace() { + let (_sender, receiver): (Sender, Receiver) = + bounded(1); + let socket_name = format!("komorebi-test-{}.sock", Uuid::new_v4()); + let socket_path = DATA_DIR.join(&socket_name); + let mut wm = WindowManager::new(receiver, Some(socket_path.clone())).unwrap(); + let m = monitor::new( + 0, + Rect::default(), + Rect::default(), + "TestMonitor".to_string(), + "TestDevice".to_string(), + "TestDeviceID".to_string(), + Some("TestMonitorID".to_string()), + ); + + // a new monitor should have a single workspace + assert_eq!(m.workspaces().len(), 1); + + // the next index on the monitor should be the not-yet-created second workspace + let new_workspace_index = m.new_workspace_idx(); + assert_eq!(new_workspace_index, 1); + + // add the monitor to the window manager + wm.monitors_mut().push_back(m); + + { + // focusing a workspace which doesn't yet exist should create it + let monitor = wm.focused_monitor_mut().unwrap(); + monitor.focus_workspace(new_workspace_index).unwrap(); + assert_eq!(monitor.workspaces().len(), 2); + } + assert_eq!(wm.focused_workspace_idx().unwrap(), 1); + + { + // focusing a workspace many indices ahead should create all workspaces + // required along the way + let monitor = wm.focused_monitor_mut().unwrap(); + monitor.focus_workspace(new_workspace_index + 2).unwrap(); + assert_eq!(monitor.workspaces().len(), 4); + } + assert_eq!(wm.focused_workspace_idx().unwrap(), 3); + + // we should be able to successfully focus an existing workspace too + wm.focus_workspace(0).unwrap(); + assert_eq!(wm.focused_workspace_idx().unwrap(), 0); + + std::fs::remove_file(socket_path).unwrap(); + } +} diff --git a/komorebi/tests/compat.rs b/komorebi/tests/compat.rs deleted file mode 100644 index 7d834e715..000000000 --- a/komorebi/tests/compat.rs +++ /dev/null @@ -1,29 +0,0 @@ -use komorebi::StaticConfig; - -#[test] -fn backwards_compat() { - let root = vec!["0.1.17", "0.1.18", "0.1.19"]; - let docs = vec![ - "0.1.20", "0.1.21", "0.1.22", "0.1.23", "0.1.24", "0.1.25", "0.1.26", "0.1.27", "0.1.28", - "0.1.29", "0.1.30", "0.1.31", "0.1.32", "0.1.33", - ]; - - let mut versions = vec![]; - - let client = reqwest::blocking::Client::new(); - - for version in root { - let request = client.get(format!("https://raw.githubusercontent.com/LGUG2Z/komorebi/refs/tags/v{version}/komorebi.example.json")).header("User-Agent", "komorebi-backwards-compat-test").build().unwrap(); - versions.push((version, client.execute(request).unwrap().text().unwrap())); - } - - for version in docs { - let request = client.get(format!("https://raw.githubusercontent.com/LGUG2Z/komorebi/refs/tags/v{version}/docs/komorebi.example.json")).header("User-Agent", "komorebi-backwards-compat-test").build().unwrap(); - versions.push((version, client.execute(request).unwrap().text().unwrap())); - } - - for (version, config) in versions { - println!("{version}"); - StaticConfig::read_raw(&config).unwrap(); - } -} diff --git a/komorebi/tests/window_manager.rs b/komorebi/tests/window_manager.rs deleted file mode 100644 index 887d68943..000000000 --- a/komorebi/tests/window_manager.rs +++ /dev/null @@ -1,86 +0,0 @@ -#[cfg(test)] -mod window_manager_tests { - use color_eyre::eyre::anyhow; - use crossbeam_channel::bounded; - use crossbeam_channel::Receiver; - use crossbeam_channel::Sender; - use komorebi::monitor; - use komorebi::window_manager::WindowManager; - use komorebi::Rect; - use komorebi::WindowManagerEvent; - use komorebi::DATA_DIR; - use uuid::Uuid; - - #[test] - fn test_create_window_manager() { - let (_sender, receiver): (Sender, Receiver) = - bounded(1); - let socket_name = format!("komorebi-test-{}.sock", Uuid::new_v4()); - let socket = Some(DATA_DIR.join(socket_name)); - let wm = WindowManager::new(receiver, socket.clone()); - assert!(wm.is_ok()); - - if let Some(ref socket_path) = socket { - let _ = std::fs::remove_file(socket_path); - } - } - - #[test] - fn test_focus_workspace() { - let (_sender, receiver): (Sender, Receiver) = - bounded(1); - let socket_name = format!("komorebi-test-{}.sock", Uuid::new_v4()); - let socket = Some(DATA_DIR.join(socket_name)); - let mut wm = WindowManager::new(receiver, socket.clone()).unwrap(); - let m = monitor::new( - 0, - Rect::default(), - Rect::default(), - "TestMonitor".to_string(), - "TestDevice".to_string(), - "TestDeviceID".to_string(), - Some("TestMonitorID".to_string()), - ); - - wm.monitors.elements_mut().push_back(m); - - let workspace_idx = { - let monitor = wm - .focused_monitor_mut() - .ok_or_else(|| anyhow!("there is no workspace")) - .unwrap(); - monitor.new_workspace_idx() - }; - - { - let monitor = wm - .focused_monitor_mut() - .ok_or_else(|| anyhow!("there is no workspace")) - .unwrap(); - monitor - .focus_workspace(workspace_idx) - .expect("failed to focus workspace"); - } - - { - let monitor = wm - .focused_monitor_mut() - .ok_or_else(|| anyhow!("there is no workspace")) - .unwrap(); - monitor - .focus_workspace(workspace_idx + 1) - .expect("failed to focus workspace"); - assert_eq!(monitor.workspaces().len(), 3) - } - - assert_eq!(wm.focused_workspace_idx().unwrap(), 2); - - wm.focus_workspace(0).ok(); - - assert_eq!(wm.focused_workspace_idx().unwrap(), 0); - - if let Some(ref socket_path) = socket { - let _ = std::fs::remove_file(socket_path); - } - } -}