From c08ee2cfae9dc77df190de31cbe7914472dfdcfa Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 31 Oct 2026 10:09:50 -0700 Subject: [PATCH] refactor(kde): the Backend names windows and monitors with the shared ids KDE's Backend took and returned bare u32 ids and answered window_workspace and current_workspaces without a Result. The operations that the shared trait has now use komorebi_backend's WindowId and MonitorId, window_workspace and current_workspaces return its Result, and the look/drag/wallpaper methods that only KDE has take the same id types. So the Shared wrapper no longer converts ids or results: it is down to the window info mapping. The window manager core keeps its u32 ids (Window { id: u32 }); the conversion is at the backend call (Window::window_id, From for Window, WindowId::from_u32 / to_u32 at the remaining call sites). KWin's table stays keyed by u32; an id too wide for a u32 is a window it never had (WindowGone, or None for a query). Test call sites got .into() on the ids and unwrap on the two results. No behaviour change. Verified: KDE cargo test --workspace --no-fail-fast (unit, integration, doc) 881 passed, 0 failed, native with FakeBackend. Not run: KDE VM suites. --- komorebi-for-kde/komorebi/src/backend/fake.rs | 206 ++++++++++-------- komorebi-for-kde/komorebi/src/backend/mod.rs | 111 +++++----- .../komorebi/src/backend/shared.rs | 52 ++--- .../komorebi/src/border_manager/mod.rs | 3 +- komorebi-for-kde/komorebi/src/desktop.rs | 14 +- komorebi-for-kde/komorebi/src/kwin/mod.rs | 178 +++++++++------ komorebi-for-kde/komorebi/src/monitor.rs | 15 +- .../komorebi/src/process_event.rs | 23 +- .../komorebi/src/transparency_manager.rs | 11 +- komorebi-for-kde/komorebi/src/window.rs | 54 +++-- .../komorebi/src/window_manager.rs | 12 +- komorebi-for-kde/komorebi/src/workspace.rs | 9 +- .../komorebi/tests/maximize_commands.rs | 15 +- komorebi-for-kde/komorebi/tests/monitors.rs | 20 +- komorebi-for-kde/komorebi/tests/monocle.rs | 10 +- komorebi-for-kde/komorebi/tests/stacks.rs | 30 ++- komorebi-for-kde/komorebi/tests/workspaces.rs | 2 +- 17 files changed, 459 insertions(+), 306 deletions(-) diff --git a/komorebi-for-kde/komorebi/src/backend/fake.rs b/komorebi-for-kde/komorebi/src/backend/fake.rs index 43b153b0..cd67ae3a 100644 --- a/komorebi-for-kde/komorebi/src/backend/fake.rs +++ b/komorebi-for-kde/komorebi/src/backend/fake.rs @@ -18,7 +18,7 @@ //! fake.open_window(1, "foot", "foot", "a terminal"); //! //! let tile = Rect { left: 0, top: 0, right: 960, bottom: 1050 }; -//! fake.set_rect(1, &tile)?; +//! fake.set_rect(1.into(), &tile)?; //! //! assert_eq!(fake.rect_of(1), Some(tile)); //! assert_eq!(fake.commands(), [Command::SetRect(1, tile)]); @@ -406,12 +406,12 @@ impl Backend for FakeBackend { self.inner.windows().into_iter().map(window_info).collect() } - fn window(&self, id: u32) -> Option { - self.inner.window(wid(id)).map(window_info) + fn window(&self, id: WindowId) -> Option { + self.inner.window(id).map(window_info) } - fn foreground_window(&self) -> Option { - self.inner.foreground_window().map(raw) + fn foreground_window(&self) -> Option { + self.inner.foreground_window() } fn monitors(&self) -> shared::Result> { @@ -433,41 +433,40 @@ impl Backend for FakeBackend { self.inner.cursor_pos() } - fn drag_end(&self, id: u32) -> Option { - self.kde.lock().drag_ends.get(&id).copied() + fn drag_end(&self, id: WindowId) -> Option { + self.kde.lock().drag_ends.get(&raw(id)).copied() } - fn set_rect(&self, id: u32, rect: &Rect) -> shared::Result<()> { - self.inner.set_rect(wid(id), rect) + fn set_rect(&self, id: WindowId, rect: &Rect) -> shared::Result<()> { + self.inner.set_rect(id, rect) } - fn focus(&self, id: u32, mouse_follows_focus: bool) -> shared::Result<()> { - self.inner - .focus(wid(id), mouse_follows_focus) + fn focus(&self, id: WindowId, mouse_follows_focus: bool) -> shared::Result<()> { + self.inner.focus(id, mouse_follows_focus) } - fn raise(&self, id: u32) -> shared::Result<()> { - self.inner.raise(wid(id)) + fn raise(&self, id: WindowId) -> shared::Result<()> { + self.inner.raise(id) } - fn hide(&self, id: u32) -> shared::Result<()> { - self.inner.hide(wid(id)) + fn hide(&self, id: WindowId) -> shared::Result<()> { + self.inner.hide(id) } - fn restore(&self, id: u32) -> shared::Result<()> { - self.inner.restore(wid(id)) + fn restore(&self, id: WindowId) -> shared::Result<()> { + self.inner.restore(id) } - fn minimize(&self, id: u32) -> shared::Result<()> { - self.inner.minimize(wid(id)) + fn minimize(&self, id: WindowId) -> shared::Result<()> { + self.inner.minimize(id) } - fn unminimize(&self, id: u32) -> shared::Result<()> { - self.inner.unminimize(wid(id)) + fn unminimize(&self, id: WindowId) -> shared::Result<()> { + self.inner.unminimize(id) } - fn close(&self, id: u32) -> shared::Result<()> { - self.inner.close(wid(id)) + fn close(&self, id: WindowId) -> shared::Result<()> { + self.inner.close(id) } fn center_cursor_in(&self, rect: &Rect) -> shared::Result<()> { @@ -478,31 +477,24 @@ impl Backend for FakeBackend { self.inner.ensure_workspaces(names) } - fn switch_workspace(&self, monitor_id: u32, idx: usize) -> shared::Result<()> { - self.inner - .switch_workspace(MonitorId::from_u32(monitor_id), idx) + fn switch_workspace(&self, monitor_id: MonitorId, idx: usize) -> shared::Result<()> { + self.inner.switch_workspace(monitor_id, idx) } - fn set_window_workspace(&self, id: u32, idx: usize) -> shared::Result<()> { - self.inner - .set_window_workspace(wid(id), idx) + fn set_window_workspace(&self, id: WindowId, idx: usize) -> shared::Result<()> { + self.inner.set_window_workspace(id, idx) } - fn window_workspace(&self, id: u32) -> Option { - self.inner.window_workspace(wid(id)).ok().flatten() + fn window_workspace(&self, id: WindowId) -> komorebi_backend::Result> { + self.inner.window_workspace(id) } - fn current_workspaces(&self) -> Vec<(u32, usize)> { - self.inner - .current_workspaces() - .unwrap_or_default() - .into_iter() - .map(|(monitor, idx)| (raw_monitor(monitor), idx)) - .collect() + fn current_workspaces(&self) -> shared::Result> { + self.inner.current_workspaces() } - fn maximize(&self, id: u32, maximize: bool) -> shared::Result<()> { - self.inner.maximize(wid(id), maximize) + fn maximize(&self, id: WindowId, maximize: bool) -> shared::Result<()> { + self.inner.maximize(id, maximize) } fn apply_look(&self, look: &Look) -> eyre::Result { @@ -519,18 +511,20 @@ impl Backend for FakeBackend { self.inner.set_focus_follows_mouse(enable) } - fn set_wallpaper(&self, monitor_id: u32, path: &Path) -> eyre::Result<()> { + fn set_wallpaper(&self, monitor_id: MonitorId, path: &Path) -> eyre::Result<()> { self.kde .lock() .wallpapers - .insert(monitor_id, path.to_path_buf()); - self.inner - .record_ext(KdeCommand::SetWallpaper(monitor_id, path.to_path_buf())); + .insert(raw_monitor(monitor_id), path.to_path_buf()); + self.inner.record_ext(KdeCommand::SetWallpaper( + raw_monitor(monitor_id), + path.to_path_buf(), + )); Ok(()) } - fn set_opacity(&self, id: u32, alpha: u8) -> shared::Result<()> { - self.inner.set_opacity(wid(id), alpha) + fn set_opacity(&self, id: WindowId, alpha: u8) -> shared::Result<()> { + self.inner.set_opacity(id, alpha) } fn set_border_colours(&self, colours: &[(u32, u32)]) -> eyre::Result { @@ -571,7 +565,7 @@ mod tests { fn a_window_asked_to_move_is_where_it_was_asked() -> eyre::Result<()> { let fake = fake_with(&[1]); - fake.set_rect(1, &tile(10, 500))?; + fake.set_rect(1.into(), &tile(10, 500))?; assert_eq!(fake.rect_of(1), Some(tile(10, 500))); Ok(()) @@ -582,7 +576,7 @@ mod tests { let fake = fake_with(&[1]); fake.set_min_size(1, 600, 400); - fake.set_rect(1, &tile(0, 300))?; + fake.set_rect(1.into(), &tile(0, 300))?; let rect = fake.rect_of(1).expect("window 1 was opened"); assert_eq!((rect.right, rect.bottom), (600, 1050)); @@ -593,11 +587,11 @@ mod tests { fn every_command_is_recorded_in_order() -> eyre::Result<()> { let fake = fake_with(&[1, 2]); - fake.focus(1, false)?; - fake.raise(2)?; - fake.minimize(1)?; - fake.unminimize(1)?; - fake.close(2)?; + fake.focus(1.into(), false)?; + fake.raise(2.into())?; + fake.minimize(1.into())?; + fake.unminimize(1.into())?; + fake.close(2.into())?; assert_eq!( fake.commands(), @@ -617,16 +611,16 @@ mod tests { #[test] fn a_maximized_window_has_the_work_area_and_gets_its_frame_back() -> eyre::Result<()> { let fake = fake_with(&[1]); - fake.set_rect(1, &tile(100, 200))?; + fake.set_rect(1.into(), &tile(100, 200))?; - fake.maximize(1, true)?; + fake.maximize(1.into(), true)?; // a second maximize does not make the maximized frame the one to give back - fake.maximize(1, true)?; + fake.maximize(1.into(), true)?; assert!(fake.is_maximized(1)); assert_eq!(fake.rect_of(1), Some(tile(0, 1920))); - fake.maximize(1, false)?; + fake.maximize(1.into(), false)?; assert!(!fake.is_maximized(1)); assert_eq!(fake.rect_of(1), Some(tile(100, 200))); @@ -645,32 +639,45 @@ mod tests { #[test] fn a_window_the_user_maximizes_is_maximized_and_no_command_is_recorded() { let fake = fake_with(&[1]); - fake.set_rect(1, &tile(100, 200)).unwrap(); + fake.set_rect(1.into(), &tile(100, 200)).unwrap(); fake.clear_commands(); fake.user_maximize(1, true); assert!(fake.is_maximized(1)); - assert!(fake.window(1).expect("window 1 was opened").maximized); + assert!( + fake.window(1.into()) + .expect("window 1 was opened") + .maximized + ); assert!(fake.windows()[0].maximized); assert_eq!(fake.rect_of(1), Some(tile(0, 1920))); assert!(fake.commands().is_empty()); fake.user_maximize(1, false); - assert!(!fake.window(1).expect("window 1 was opened").maximized); + assert!( + !fake + .window(1.into()) + .expect("window 1 was opened") + .maximized + ); assert_eq!(fake.rect_of(1), Some(tile(100, 200))); } #[test] fn a_fullscreen_window_covers_its_monitor_and_gets_its_frame_back() { let fake = fake_with(&[1]); - fake.set_rect(1, &tile(100, 200)).unwrap(); + fake.set_rect(1.into(), &tile(100, 200)).unwrap(); fake.clear_commands(); fake.set_fullscreen(1, true); - assert!(fake.window(1).expect("window 1 was opened").fullscreen); + assert!( + fake.window(1.into()) + .expect("window 1 was opened") + .fullscreen + ); assert!(fake.windows()[0].fullscreen); assert_eq!( fake.rect_of(1), @@ -686,7 +693,12 @@ mod tests { fake.set_fullscreen(1, false); - assert!(!fake.window(1).expect("window 1 was opened").fullscreen); + assert!( + !fake + .window(1.into()) + .expect("window 1 was opened") + .fullscreen + ); assert_eq!(fake.rect_of(1), Some(tile(100, 200))); } @@ -694,7 +706,9 @@ mod tests { fn a_command_about_a_window_nobody_opened_is_an_error() { let fake = fake_with(&[1]); - let error = fake.focus(9, false).expect_err("window 9 does not exist"); + let error = fake + .focus(9.into(), false) + .expect_err("window 9 does not exist"); assert_eq!(error.to_string(), "no such window: 9"); } @@ -704,17 +718,20 @@ mod tests { let fake = fake_with(&[1]); fake.close_window_now(1); - assert!(fake.raise(1).is_err()); + assert!(fake.raise(1.into()).is_err()); } #[test] fn a_permissive_fake_creates_the_windows_it_is_asked_about() -> eyre::Result<()> { let fake = FakeBackend::permissive(); - fake.focus(77, false)?; + fake.focus(77.into(), false)?; - assert!(fake.is_window(77)); - assert_eq!(fake.foreground_window(), Some(77)); + assert!(fake.is_window(77.into())); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(77) + ); Ok(()) } @@ -722,9 +739,9 @@ mod tests { fn focusing_with_the_mouse_following_puts_the_pointer_in_the_middle_of_the_window() -> eyre::Result<()> { let fake = fake_with(&[1]); - fake.set_rect(1, &tile(100, 200))?; + fake.set_rect(1.into(), &tile(100, 200))?; - fake.focus(1, true)?; + fake.focus(1.into(), true)?; assert_eq!(fake.cursor_pos(), Some((200, 525))); Ok(()) @@ -735,7 +752,7 @@ mod tests { let fake = fake_with(&[1]); fake.set_cursor(5, 5); - fake.focus(1, false)?; + fake.focus(1.into(), false)?; assert_eq!(fake.cursor_pos(), Some((5, 5))); Ok(()) @@ -761,7 +778,7 @@ mod tests { assert!(fake.commands().is_empty()); assert_eq!(fake.rect_of(1), Some(tile(300, 300))); - let window = fake.window(1).expect("window 1 was opened"); + let window = fake.window(1.into()).expect("window 1 was opened"); assert_eq!(window.title, "renamed"); assert!(!window.normal); } @@ -784,22 +801,25 @@ mod tests { fake.open_window(1, "foot", "foot", "window 1"); assert_eq!(fake.workspace_of(1), Some(2)); - assert_eq!(fake.window_workspace(1), Some(2)); + assert_eq!(fake.window_workspace(1.into()).unwrap(), Some(2)); assert!(fake.on_screen(1)); } #[test] fn a_monitor_shows_the_windows_of_its_workspace_and_no_others() -> eyre::Result<()> { let fake = fake_with(&[1, 2]); - fake.set_window_workspace(2, 1)?; + fake.set_window_workspace(2.into(), 1)?; assert!(fake.on_screen(1) && !fake.on_screen(2)); - fake.switch_workspace(1, 1)?; + fake.switch_workspace(1.into(), 1)?; assert!(!fake.on_screen(1) && fake.on_screen(2)); assert_eq!(fake.shown_workspace(1), 1); - assert_eq!(fake.current_workspaces(), [(1, 1)]); + assert_eq!( + fake.current_workspaces().unwrap(), + [(MonitorId::from_u32(1), 1)] + ); assert_eq!( fake.commands(), [ @@ -816,7 +836,10 @@ mod tests { fake.show_workspace_by_user(1, 3); - assert_eq!(fake.current_workspaces(), [(1, 3)]); + assert_eq!( + fake.current_workspaces().unwrap(), + [(MonitorId::from_u32(1), 3)] + ); assert!(fake.commands().is_empty()); } @@ -824,7 +847,7 @@ mod tests { fn a_minimized_window_or_one_that_closed_is_not_on_screen() -> eyre::Result<()> { let fake = fake_with(&[1, 2]); - fake.minimize(1)?; + fake.minimize(1.into())?; fake.close_window_now(2); assert!(!fake.on_screen(1) && !fake.on_screen(2)); @@ -835,14 +858,17 @@ mod tests { fn a_hidden_window_is_out_of_sight_on_its_workspace_until_it_is_restored() -> eyre::Result<()> { let fake = fake_with(&[1]); - fake.hide(1)?; - fake.hide(1)?; + fake.hide(1.into())?; + fake.hide(1.into())?; assert!(fake.is_hidden(1) && !fake.on_screen(1)); - assert_eq!(fake.window_workspace(1), Some(0)); - assert!(fake.window(1).is_some_and(|w| w.alive && !w.minimized)); + assert_eq!(fake.window_workspace(1.into()).unwrap(), Some(0)); + assert!( + fake.window(1.into()) + .is_some_and(|w| w.alive && !w.minimized) + ); - fake.restore(1)?; + fake.restore(1.into())?; assert!(!fake.is_hidden(1) && fake.on_screen(1)); assert_eq!( @@ -856,15 +882,15 @@ mod tests { fn hiding_or_restoring_a_window_nobody_opened_is_an_error() { let fake = fake_with(&[1]); - assert!(fake.hide(9).is_err()); - assert!(fake.restore(9).is_err()); + assert!(fake.hide(9.into()).is_err()); + assert!(fake.restore(9.into()).is_err()); } #[test] fn putting_a_window_nobody_opened_on_a_workspace_is_an_error() { let fake = fake_with(&[1]); - assert!(fake.set_window_workspace(9, 1).is_err()); + assert!(fake.set_window_workspace(9.into(), 1).is_err()); assert_eq!(fake.workspace_of(9), None); } @@ -926,11 +952,11 @@ mod tests { let fake = fake_with(&[1]); assert_eq!(fake.opacity_of(1), 255); - fake.set_opacity(1, 100)?; + fake.set_opacity(1.into(), 100)?; assert_eq!(fake.opacity_of(1), 100); assert_eq!(fake.commands(), [Command::SetOpacity(1, 100)]); - assert!(fake.set_opacity(9, 100).is_err()); + assert!(fake.set_opacity(9.into(), 100).is_err()); Ok(()) } @@ -939,7 +965,7 @@ mod tests { let fake = fake_with(&[1]); fake.apply_look(&Look::default())?; - fake.focus(1, false)?; + fake.focus(1.into(), false)?; fake.set_border_colours(&[(1, 0xFF0000)])?; assert_eq!(fake.commands().len(), 3); diff --git a/komorebi-for-kde/komorebi/src/backend/mod.rs b/komorebi-for-kde/komorebi/src/backend/mod.rs index 893ce846..1ce213c4 100644 --- a/komorebi-for-kde/komorebi/src/backend/mod.rs +++ b/komorebi-for-kde/komorebi/src/backend/mod.rs @@ -51,6 +51,8 @@ use crate::core::Rect; use color_eyre::eyre; +use komorebi_backend::MonitorId; +use komorebi_backend::WindowId; use parking_lot::RwLock; use std::cell::RefCell; use std::path::Path; @@ -212,28 +214,29 @@ pub struct BorderLook { /// # use color_eyre::eyre; /// # use komorebi::backend::{Backend, MonitorInfo, WindowInfo}; /// # use komorebi::core::Rect; +/// # use komorebi_backend::{MonitorId, WindowId}; /// struct NotShareable(Rc); /// /// # impl Backend for NotShareable { /// # fn windows(&self) -> Vec { vec![] } -/// # fn window(&self, _: u32) -> Option { None } -/// # fn foreground_window(&self) -> Option { None } +/// # fn window(&self, _: WindowId) -> Option { None } +/// # fn foreground_window(&self) -> Option { None } /// # fn monitors(&self) -> komorebi_backend::Result> { Ok(vec![]) } /// # fn cursor_pos(&self) -> Option<(i32, i32)> { None } -/// # fn set_rect(&self, _: u32, _: &Rect) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn focus(&self, _: u32, _: bool) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn raise(&self, _: u32) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn hide(&self, _: u32) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn restore(&self, _: u32) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn minimize(&self, _: u32) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn unminimize(&self, _: u32) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn close(&self, _: u32) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn set_rect(&self, _: WindowId, _: &Rect) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn focus(&self, _: WindowId, _: bool) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn raise(&self, _: WindowId) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn hide(&self, _: WindowId) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn restore(&self, _: WindowId) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn minimize(&self, _: WindowId) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn unminimize(&self, _: WindowId) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn close(&self, _: WindowId) -> komorebi_backend::Result<()> { Ok(()) } /// # fn center_cursor_in(&self, _: &Rect) -> komorebi_backend::Result<()> { Ok(()) } /// # fn ensure_workspaces(&self, _: &[String]) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn switch_workspace(&self, _: u32, _: usize) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn set_window_workspace(&self, _: u32, _: usize) -> komorebi_backend::Result<()> { Ok(()) } -/// # fn window_workspace(&self, _: u32) -> Option { None } -/// # fn current_workspaces(&self) -> Vec<(u32, usize)> { vec![] } +/// # fn switch_workspace(&self, _: MonitorId, _: usize) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn set_window_workspace(&self, _: WindowId, _: usize) -> komorebi_backend::Result<()> { Ok(()) } +/// # fn window_workspace(&self, _: WindowId) -> komorebi_backend::Result> { Ok(None) } +/// # fn current_workspaces(&self) -> komorebi_backend::Result> { Ok(vec![]) } /// # } /// ``` pub trait Backend: Send + Sync + 'static { @@ -243,10 +246,10 @@ pub trait Backend: Send + Sync + 'static { fn windows(&self) -> Vec; /// Returns what is known about the window, or `None` if the compositor has never heard of it. - fn window(&self, id: u32) -> Option; + fn window(&self, id: WindowId) -> Option; /// Returns the id of the window that has the focus, if any window does. - fn foreground_window(&self) -> Option; + fn foreground_window(&self) -> Option; /// Returns every connected monitor. /// @@ -276,9 +279,9 @@ pub trait Backend: Send + Sync + 'static { /// let fake = FakeBackend::with_one_monitor(); /// fake.open_window(1, "foot", "foot", "a terminal"); /// - /// assert_eq!(fake.drag_origin(1), None); + /// assert_eq!(fake.drag_origin(1.into()), None); /// ``` - fn drag_origin(&self, _id: u32) -> Option { + fn drag_origin(&self, _id: WindowId) -> Option { None } @@ -303,13 +306,13 @@ pub trait Backend: Send + Sync + 'static { /// /// let fake = FakeBackend::with_one_monitor(); /// fake.open_window(1, "foot", "foot", "a terminal"); - /// assert_eq!(fake.drag_end(1), None); + /// assert_eq!(fake.drag_end(1.into()), None); /// /// let asked = Rect { left: 0, top: 0, right: 672, bottom: 704 }; /// fake.set_drag_end(1, asked); - /// assert_eq!(fake.drag_end(1), Some(asked)); + /// assert_eq!(fake.drag_end(1.into()), Some(asked)); /// ``` - fn drag_end(&self, _id: u32) -> Option { + fn drag_end(&self, _id: WindowId) -> Option { None } @@ -323,21 +326,21 @@ pub trait Backend: Send + Sync + 'static { /// # Errors /// /// When the window does not exist or is no longer alive. - fn set_rect(&self, id: u32, rect: &Rect) -> komorebi_backend::Result<()>; + fn set_rect(&self, id: WindowId, rect: &Rect) -> komorebi_backend::Result<()>; /// Gives the window the focus, and, if `mouse_follows_focus`, puts the pointer in its middle. /// /// # Errors /// /// When the window does not exist or is no longer alive. - fn focus(&self, id: u32, mouse_follows_focus: bool) -> komorebi_backend::Result<()>; + fn focus(&self, id: WindowId, mouse_follows_focus: bool) -> komorebi_backend::Result<()>; /// Raises the window above the others. /// /// # Errors /// /// When the window does not exist or is no longer alive. - fn raise(&self, id: u32) -> komorebi_backend::Result<()>; + fn raise(&self, id: WindowId) -> komorebi_backend::Result<()>; /// Takes the window out of sight without closing or minimizing it, which is how the window /// manager keeps the back of a stack out of the way. On KWin it goes to a virtual desktop that @@ -351,7 +354,7 @@ pub trait Backend: Send + Sync + 'static { /// /// When the window does not exist or is no longer alive, or the compositor cannot make the /// place the window is hidden in. - fn hide(&self, id: u32) -> komorebi_backend::Result<()>; + fn hide(&self, id: WindowId) -> komorebi_backend::Result<()>; /// Brings a hidden window back, to the workspace it is on. A window that is not hidden is left /// as it is. @@ -359,28 +362,28 @@ pub trait Backend: Send + Sync + 'static { /// # Errors /// /// When the window does not exist or is no longer alive. - fn restore(&self, id: u32) -> komorebi_backend::Result<()>; + fn restore(&self, id: WindowId) -> komorebi_backend::Result<()>; /// Minimizes the window. /// /// # Errors /// /// When the window does not exist or is no longer alive. - fn minimize(&self, id: u32) -> komorebi_backend::Result<()>; + fn minimize(&self, id: WindowId) -> komorebi_backend::Result<()>; /// Brings a minimized window back. /// /// # Errors /// /// When the window does not exist or is no longer alive. - fn unminimize(&self, id: u32) -> komorebi_backend::Result<()>; + fn unminimize(&self, id: WindowId) -> komorebi_backend::Result<()>; /// Asks the window to close. /// /// # Errors /// /// When the window does not exist or is no longer alive. - fn close(&self, id: u32) -> komorebi_backend::Result<()>; + fn close(&self, id: WindowId) -> komorebi_backend::Result<()>; /// Puts the pointer in the middle of `rect`. /// @@ -416,21 +419,21 @@ pub trait Backend: Send + Sync + 'static { /// # Errors /// /// When there is no desktop for `idx` and one cannot be made. - fn switch_workspace(&self, monitor_id: u32, idx: usize) -> komorebi_backend::Result<()>; + fn switch_workspace(&self, monitor_id: MonitorId, idx: usize) -> komorebi_backend::Result<()>; /// Puts a window on workspace `idx`. It is visible at once to [`Backend::window_workspace`]. /// /// # Errors /// /// When the window does not exist, or there is no desktop for `idx` and one cannot be made. - fn set_window_workspace(&self, id: u32, idx: usize) -> komorebi_backend::Result<()>; + fn set_window_workspace(&self, id: WindowId, idx: usize) -> komorebi_backend::Result<()>; /// Returns the workspace a window is on, or `None` for a window the compositor does not know or /// that is on every workspace. - fn window_workspace(&self, id: u32) -> Option; + fn window_workspace(&self, id: WindowId) -> komorebi_backend::Result>; /// Returns the workspace each monitor shows, as `(monitor id, workspace index)`. - fn current_workspaces(&self) -> Vec<(u32, usize)>; + fn current_workspaces(&self) -> komorebi_backend::Result>; // ---- look, which a backend that draws nothing need not say anything about -------------------- @@ -523,11 +526,11 @@ pub trait Backend: Send + Sync + 'static { /// fake.open_window(7, "foot", "foot", "a terminal"); /// assert_eq!(fake.opacity_of(7), 255); /// - /// fake.set_opacity(7, 150)?; + /// fake.set_opacity(7.into(), 150)?; /// assert_eq!(fake.opacity_of(7), 150); /// # Ok::<(), color_eyre::eyre::Report>(()) /// ``` - fn set_opacity(&self, _id: u32, _alpha: u8) -> komorebi_backend::Result<()> { + fn set_opacity(&self, _id: WindowId, _alpha: u8) -> komorebi_backend::Result<()> { Ok(()) } @@ -576,7 +579,7 @@ pub trait Backend: Send + Sync + 'static { /// let fake = FakeBackend::with_one_monitor(); /// assert_eq!(fake.wallpaper_of(1), None); /// - /// fake.set_wallpaper(1, Path::new("/pictures/dunes.png"))?; + /// fake.set_wallpaper(1.into(), Path::new("/pictures/dunes.png"))?; /// assert_eq!(fake.wallpaper_of(1), Some("/pictures/dunes.png".into())); /// assert_eq!( /// fake.commands(), @@ -584,7 +587,7 @@ pub trait Backend: Send + Sync + 'static { /// ); /// # Ok::<(), color_eyre::eyre::Report>(()) /// ``` - fn set_wallpaper(&self, _monitor_id: u32, _path: &Path) -> eyre::Result<()> { + fn set_wallpaper(&self, _monitor_id: MonitorId, _path: &Path) -> eyre::Result<()> { Ok(()) } @@ -605,26 +608,26 @@ pub trait Backend: Send + Sync + 'static { /// # Errors /// /// When the window does not exist or is no longer alive. - fn maximize(&self, _id: u32, _maximize: bool) -> komorebi_backend::Result<()> { + fn maximize(&self, _id: WindowId, _maximize: bool) -> komorebi_backend::Result<()> { Ok(()) } /// Returns true if and only if the compositor has a live window with this id. - fn is_window(&self, id: u32) -> bool { + fn is_window(&self, id: WindowId) -> bool { self.window(id).is_some_and(|w| w.alive) } /// Returns the window's frame, if the compositor knows the window. - fn window_rect(&self, id: u32) -> Option { + fn window_rect(&self, id: WindowId) -> Option { self.window(id).map(|w| w.rect) } /// Returns the id of the monitor whose bounds contain the point. - fn monitor_from_point(&self, x: i32, y: i32) -> Option { + fn monitor_from_point(&self, x: i32, y: i32) -> Option { self.monitors().ok()?.into_iter().find_map(|m| { let (l, t) = (m.size.left, m.size.top); let (r, b) = (l + m.size.right, t + m.size.bottom); - (x >= l && x < r && y >= t && y < b).then_some(m.id) + (x >= l && x < r && y >= t && y < b).then_some(MonitorId::from_u32(m.id)) }) } } @@ -716,7 +719,7 @@ mod tests { fn a_thread_that_installs_nothing_gets_a_permissive_fake_in_unit_tests() { let id = 41; - assert!(backend().window(id).is_some()); + assert!(backend().window(id.into()).is_some()); } #[test] @@ -728,12 +731,12 @@ mod tests { with_backend(outer, || { with_backend(inner, || { - assert!(backend().is_window(2)); - assert!(!backend().is_window(1)); + assert!(backend().is_window(2.into())); + assert!(!backend().is_window(1.into())); }); - assert!(backend().is_window(1)); - assert!(!backend().is_window(2)); + assert!(backend().is_window(1.into())); + assert!(!backend().is_window(2.into())); }); } @@ -749,7 +752,7 @@ mod tests { })); assert!(result.is_err()); - assert!(backend().is_window(1)); + assert!(backend().is_window(1.into())); }); } @@ -758,10 +761,10 @@ mod tests { let fake = FakeBackend::with_one_monitor(); fake.open_window(5, "foot", "foot", "a terminal"); - assert!(fake.is_window(5)); - assert!(!fake.is_window(6)); - assert_eq!(fake.window_rect(5), fake.rect_of(5)); - assert_eq!(fake.monitor_from_point(10, 10), Some(1)); + assert!(fake.is_window(5.into())); + assert!(!fake.is_window(6.into())); + assert_eq!(fake.window_rect(5.into()), fake.rect_of(5)); + assert_eq!(fake.monitor_from_point(10, 10), Some(1.into())); assert_eq!(fake.monitor_from_point(5000, 10), None); } @@ -772,8 +775,8 @@ mod tests { fake.close_window_now(5); - assert!(!fake.is_window(5)); - assert!(fake.window(5).is_some_and(|w| !w.alive)); + assert!(!fake.is_window(5.into())); + assert!(fake.window(5.into()).is_some_and(|w| !w.alive)); assert!(fake.windows().is_empty()); } } diff --git a/komorebi-for-kde/komorebi/src/backend/shared.rs b/komorebi-for-kde/komorebi/src/backend/shared.rs index b38b52c6..6f1ad541 100644 --- a/komorebi-for-kde/komorebi/src/backend/shared.rs +++ b/komorebi-for-kde/komorebi/src/backend/shared.rs @@ -20,7 +20,6 @@ use super::Backend; use komorebi_backend as shared; use komorebi_backend::Capability; -use komorebi_backend::Error; use komorebi_backend::MonitorId; use komorebi_backend::Rect; use komorebi_backend::WindowId; @@ -34,18 +33,6 @@ impl Shared { pub fn kde(&self) -> &B { &self.0 } - - /// Runs a window command through KDE's trait; an id too wide for KDE is a window it never had. - fn window_command( - &self, - id: WindowId, - command: impl FnOnce(&B, u32) -> shared::Result<()>, - ) -> shared::Result<()> { - let Some(raw) = id.to_u32() else { - return Err(Error::WindowGone(id)); - }; - command(&self.0, raw) - } } fn window_info(info: super::WindowInfo) -> shared::WindowInfo { @@ -71,11 +58,11 @@ impl shared::Backend for Shared { } fn window(&self, id: WindowId) -> Option { - self.0.window(id.to_u32()?).map(window_info) + self.0.window(id).map(window_info) } fn foreground_window(&self) -> Option { - self.0.foreground_window().map(WindowId::from_u32) + self.0.foreground_window() } fn monitors(&self) -> shared::Result> { @@ -98,35 +85,35 @@ impl shared::Backend for Shared { } fn set_rect(&self, id: WindowId, rect: &Rect) -> shared::Result<()> { - self.window_command(id, |b, raw| b.set_rect(raw, rect)) + self.0.set_rect(id, rect) } fn focus(&self, id: WindowId, mouse_follows_focus: bool) -> shared::Result<()> { - self.window_command(id, |b, raw| b.focus(raw, mouse_follows_focus)) + self.0.focus(id, mouse_follows_focus) } fn raise(&self, id: WindowId) -> shared::Result<()> { - self.window_command(id, |b, raw| b.raise(raw)) + self.0.raise(id) } fn hide(&self, id: WindowId) -> shared::Result<()> { - self.window_command(id, |b, raw| b.hide(raw)) + self.0.hide(id) } fn restore(&self, id: WindowId) -> shared::Result<()> { - self.window_command(id, |b, raw| b.restore(raw)) + self.0.restore(id) } fn minimize(&self, id: WindowId) -> shared::Result<()> { - self.window_command(id, |b, raw| b.minimize(raw)) + self.0.minimize(id) } fn unminimize(&self, id: WindowId) -> shared::Result<()> { - self.window_command(id, |b, raw| b.unminimize(raw)) + self.0.unminimize(id) } fn close(&self, id: WindowId) -> shared::Result<()> { - self.window_command(id, |b, raw| b.close(raw)) + self.0.close(id) } fn center_cursor_in(&self, rect: &Rect) -> shared::Result<()> { @@ -138,11 +125,11 @@ impl shared::Backend for Shared { } fn maximize(&self, id: WindowId, maximize: bool) -> shared::Result<()> { - self.window_command(id, |b, raw| b.maximize(raw, maximize)) + self.0.maximize(id, maximize) } fn set_opacity(&self, id: WindowId, alpha: u8) -> shared::Result<()> { - self.window_command(id, |b, raw| b.set_opacity(raw, alpha)) + self.0.set_opacity(id, alpha) } fn set_focus_follows_mouse(&self, enable: bool) -> shared::Result<()> { @@ -154,25 +141,19 @@ impl shared::Backend for Shared { } fn switch_workspace(&self, monitor: MonitorId, idx: usize) -> shared::Result<()> { - let id = monitor.to_u32().unwrap_or(u32::MAX); - self.0.switch_workspace(id, idx) + self.0.switch_workspace(monitor, idx) } fn set_window_workspace(&self, id: WindowId, idx: usize) -> shared::Result<()> { - self.window_command(id, |b, raw| b.set_window_workspace(raw, idx)) + self.0.set_window_workspace(id, idx) } fn window_workspace(&self, id: WindowId) -> shared::Result> { - Ok(id.to_u32().and_then(|raw| self.0.window_workspace(raw))) + self.0.window_workspace(id) } fn current_workspaces(&self) -> shared::Result> { - Ok(self - .0 - .current_workspaces() - .into_iter() - .map(|(monitor, idx)| (MonitorId::from_u32(monitor), idx)) - .collect()) + self.0.current_workspaces() } // `is_window`, `window_rect` and `monitor_from_point` are the provided ones, over `window` and @@ -185,6 +166,7 @@ mod tests { use super::*; use crate::backend::fake::FakeBackend; use komorebi_backend::Backend as _; + use komorebi_backend::Error; use komorebi_backend::contract::Harness; use komorebi_backend::contract::check_all; diff --git a/komorebi-for-kde/komorebi/src/border_manager/mod.rs b/komorebi-for-kde/komorebi/src/border_manager/mod.rs index 427e24c3..233cf591 100644 --- a/komorebi-for-kde/komorebi/src/border_manager/mod.rs +++ b/komorebi-for-kde/komorebi/src/border_manager/mod.rs @@ -26,6 +26,7 @@ use crate::core::animation::AnimationStyle; use crate::core::animation::QtCurve; use crate::window_manager::WindowManager; use color_eyre::eyre; +use komorebi_backend::WindowId; use komorebi_themes::colour::Colour; use komorebi_themes::colour::Rgb; use lazy_static::lazy_static; @@ -113,7 +114,7 @@ fn kind_colour(kind: WindowKind) -> u32 { pub fn window_kinds(wm: &WindowManager) -> Vec<(u32, WindowKind)> { let mut out = vec![]; let focused_monitor_idx = wm.focused_monitor_idx(); - let foreground = backend().foreground_window(); + let foreground = backend().foreground_window().and_then(WindowId::to_u32); let floating = |workspace: &crate::workspace::Workspace, out: &mut Vec<(u32, WindowKind)>| { for window in workspace.floating_windows() { diff --git a/komorebi-for-kde/komorebi/src/desktop.rs b/komorebi-for-kde/komorebi/src/desktop.rs index a78c2256..2378e213 100644 --- a/komorebi-for-kde/komorebi/src/desktop.rs +++ b/komorebi-for-kde/komorebi/src/desktop.rs @@ -45,6 +45,8 @@ use crate::window::RuleDebug; use crate::window::Window; use crate::window_manager::WindowManager; use color_eyre::eyre; +use komorebi_backend::MonitorId; +use komorebi_backend::WindowId; use std::collections::HashMap; fn contains_point(area: &Rect, x: i32, y: i32) -> bool { @@ -339,8 +341,12 @@ pub fn load_workspace_information(wm: &mut WindowManager) -> eyre::Result<()> { let mut valid_window_count = 0; // each monitor starts out showing the workspace the compositor is showing on it - for (monitor_id, idx) in backend().current_workspaces() { - if let Some(monitor) = wm.monitors_mut().iter_mut().find(|m| m.id == monitor_id) { + for (monitor_id, idx) in backend().current_workspaces().unwrap_or_default() { + if let Some(monitor) = wm + .monitors_mut() + .iter_mut() + .find(|m| MonitorId::from_u32(m.id) == monitor_id) + { monitor.focus_workspace(idx)?; } } @@ -374,7 +380,9 @@ pub fn load_workspace_information(wm: &mut WindowManager) -> eyre::Result<()> { continue; }; let workspace_idx = backend() - .window_workspace(info.id) + .window_workspace(WindowId::from_u32(info.id)) + .ok() + .flatten() .unwrap_or_else(|| monitor.focused_workspace_idx()); monitor.ensure_workspace_count(workspace_idx + 1); diff --git a/komorebi-for-kde/komorebi/src/kwin/mod.rs b/komorebi-for-kde/komorebi/src/kwin/mod.rs index 949ecff1..bfc6d8bc 100644 --- a/komorebi-for-kde/komorebi/src/kwin/mod.rs +++ b/komorebi-for-kde/komorebi/src/kwin/mod.rs @@ -101,6 +101,8 @@ use crate::window_manager_event_listener; use color_eyre::eyre; use color_eyre::eyre::OptionExt; use futures_util::StreamExt; +use komorebi_backend::MonitorId; +use komorebi_backend::WindowId; use parking_lot::Condvar; use parking_lot::Mutex; use serde_json::Value; @@ -788,6 +790,11 @@ fn platform(report: eyre::Report) -> komorebi_backend::Error { komorebi_backend::Error::Platform(report.into()) } +/// The compositor's number for a window id, which is always one that was made from a `u32` +fn raw(id: komorebi_backend::WindowId) -> komorebi_backend::Result { + id.to_u32().ok_or(komorebi_backend::Error::WindowGone(id)) +} + fn command_rect(uuid: &str, rect: &Rect) -> Value { json!({ "op": "geo", "id": uuid, "x": rect.left, "y": rect.top, "w": rect.right, "h": rect.bottom }) } @@ -810,11 +817,7 @@ impl KWinBackend { )) } - fn command( - &self, - id: u32, - build: impl FnOnce(&str) -> Value, - ) -> komorebi_backend::Result<()> { + fn command(&self, id: u32, build: impl FnOnce(&str) -> Value) -> komorebi_backend::Result<()> { let uuid = self.uuid_of(id)?; self.shared.push(build(&uuid)); Ok(()) @@ -826,19 +829,26 @@ impl Backend for KWinBackend { self.shared.table.lock().windows() } - fn window(&self, id: u32) -> Option { + fn window(&self, id: WindowId) -> Option { + let id = id.to_u32()?; self.shared.table.lock().window(id) } - fn foreground_window(&self) -> Option { - self.shared.table.lock().foreground() + fn foreground_window(&self) -> Option { + self.shared + .table + .lock() + .foreground() + .map(WindowId::from_u32) } - fn drag_origin(&self, id: u32) -> Option { + fn drag_origin(&self, id: WindowId) -> Option { + let id = id.to_u32()?; self.shared.table.lock().drag_origin(id) } - fn drag_end(&self, id: u32) -> Option { + fn drag_end(&self, id: WindowId) -> Option { + let id = id.to_u32()?; self.shared.table.lock().drag_end(id) } @@ -864,14 +874,16 @@ impl Backend for KWinBackend { answer.or_else(|| self.shared.table.lock().cursor()) } - fn set_rect(&self, id: u32, rect: &Rect) -> komorebi_backend::Result<()> { + fn set_rect(&self, id: WindowId, rect: &Rect) -> komorebi_backend::Result<()> { + let id = raw(id)?; tracing::debug!("asking for window {id} to be at {rect:?}"); self.command(id, |uuid| command_rect(uuid, rect))?; self.shared.table.lock().note_requested_rect(id, *rect); Ok(()) } - fn focus(&self, id: u32, mouse_follows_focus: bool) -> komorebi_backend::Result<()> { + fn focus(&self, id: WindowId, mouse_follows_focus: bool) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.command(id, |uuid| json!({ "op": "activate", "id": uuid }))?; if mouse_follows_focus { @@ -894,11 +906,13 @@ impl Backend for KWinBackend { Ok(()) } - fn raise(&self, id: u32) -> komorebi_backend::Result<()> { + fn raise(&self, id: WindowId) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.command(id, |uuid| json!({ "op": "raise", "id": uuid })) } - fn hide(&self, id: u32) -> komorebi_backend::Result<()> { + fn hide(&self, id: WindowId) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.uuid_of(id)?; let commands = loop { @@ -923,7 +937,8 @@ impl Backend for KWinBackend { Ok(()) } - fn restore(&self, id: u32) -> komorebi_backend::Result<()> { + fn restore(&self, id: WindowId) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.uuid_of(id)?; let commands = self.shared.table.lock().restore_commands(id); @@ -942,9 +957,13 @@ impl Backend for KWinBackend { .map_err(platform) } - fn switch_workspace(&self, monitor_id: u32, idx: usize) -> komorebi_backend::Result<()> { + fn switch_workspace(&self, monitor_id: MonitorId, idx: usize) -> komorebi_backend::Result<()> { let commands = loop { - let attempt = self.shared.table.lock().switch_commands(monitor_id, idx); + let attempt = self + .shared + .table + .lock() + .switch_commands(monitor_id.to_u32().unwrap_or(u32::MAX), idx); match attempt { Ok(commands) => break commands, Err(NeedsDesktops(count)) => self.make_desktops(count)?, @@ -957,7 +976,8 @@ impl Backend for KWinBackend { Ok(()) } - fn set_window_workspace(&self, id: u32, idx: usize) -> komorebi_backend::Result<()> { + fn set_window_workspace(&self, id: WindowId, idx: usize) -> komorebi_backend::Result<()> { + let id = raw(id)?; let commands = loop { let attempt = self.shared.table.lock().window_workspace_commands(id, idx); match attempt { @@ -972,27 +992,41 @@ impl Backend for KWinBackend { Ok(()) } - fn window_workspace(&self, id: u32) -> Option { - self.shared.table.lock().window_workspace(id) + fn window_workspace(&self, id: WindowId) -> komorebi_backend::Result> { + let Some(id) = id.to_u32() else { + return Ok(None); + }; + Ok(self.shared.table.lock().window_workspace(id)) } - fn current_workspaces(&self) -> Vec<(u32, usize)> { - self.shared.table.lock().current_workspaces() + fn current_workspaces(&self) -> komorebi_backend::Result> { + Ok(self + .shared + .table + .lock() + .current_workspaces() + .into_iter() + .map(|(monitor, idx)| (MonitorId::from_u32(monitor), idx)) + .collect()) } - fn minimize(&self, id: u32) -> komorebi_backend::Result<()> { + fn minimize(&self, id: WindowId) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.command(id, |uuid| json!({ "op": "min", "id": uuid, "v": true })) } - fn unminimize(&self, id: u32) -> komorebi_backend::Result<()> { + fn unminimize(&self, id: WindowId) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.command(id, |uuid| json!({ "op": "min", "id": uuid, "v": false })) } - fn close(&self, id: u32) -> komorebi_backend::Result<()> { + fn close(&self, id: WindowId) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.command(id, |uuid| json!({ "op": "close", "id": uuid })) } - fn maximize(&self, id: u32, maximize: bool) -> komorebi_backend::Result<()> { + fn maximize(&self, id: WindowId, maximize: bool) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.command( id, |uuid| json!({ "op": "maximize", "id": uuid, "v": maximize }), @@ -1025,7 +1059,8 @@ impl Backend for KWinBackend { })? } - fn set_opacity(&self, id: u32, alpha: u8) -> komorebi_backend::Result<()> { + fn set_opacity(&self, id: WindowId, alpha: u8) -> komorebi_backend::Result<()> { + let id = raw(id)?; self.command( id, |uuid| json!({ "op": "opacity", "id": uuid, "v": f64::from(alpha) / 255.0 }), @@ -1037,31 +1072,31 @@ impl Backend for KWinBackend { self.shared .block_on(async move { - let Some(kwinrc) = &shared.kwinrc else { - eyre::bail!("there is no configuration directory to find kwinrc in"); - }; + let Some(kwinrc) = &shared.kwinrc else { + eyre::bail!("there is no configuration directory to find kwinrc in"); + }; - if enable { - kwinrc.set( - "Windows", - &[ - ("FocusPolicy", "1".to_string()), - ("DelayFocusInterval", "0".to_string()), - ], - )?; - } else { - kwinrc.restore_keys("Windows", &["FocusPolicy", "DelayFocusInterval"])?; - } + if enable { + kwinrc.set( + "Windows", + &[ + ("FocusPolicy", "1".to_string()), + ("DelayFocusInterval", "0".to_string()), + ], + )?; + } else { + kwinrc.restore_keys("Windows", &["FocusPolicy", "DelayFocusInterval"])?; + } - let connection = shared.connection().await?; - kwin_reconfigure(&connection).await; - Ok(()) - }) + let connection = shared.connection().await?; + kwin_reconfigure(&connection).await; + Ok(()) + }) .map_err(platform)? .map_err(platform) } - fn set_wallpaper(&self, monitor_id: u32, path: &std::path::Path) -> eyre::Result<()> { + fn set_wallpaper(&self, monitor_id: MonitorId, path: &std::path::Path) -> eyre::Result<()> { if !self.shared.alive.load(Ordering::SeqCst) { eyre::bail!("KWin is gone"); } @@ -1072,7 +1107,7 @@ impl Backend for KWinBackend { .lock() .monitors() .into_iter() - .find(|m| m.id == monitor_id) + .find(|m| MonitorId::from_u32(m.id) == monitor_id) .map(|m| m.name) .ok_or_eyre("there is no such monitor")?; @@ -1251,28 +1286,28 @@ mod tests { bottom: 1050, }; // the editor is 1, the terminal 2 and the dialog 3 - backend.set_rect(1, &left(0)).unwrap(); - backend.focus(1, false).unwrap(); - backend.raise(1).unwrap(); - backend.minimize(1).unwrap(); - backend.unminimize(1).unwrap(); - backend.maximize(1, true).unwrap(); - backend.maximize(1, false).unwrap(); - backend.close(3).unwrap(); + backend.set_rect(1.into(), &left(0)).unwrap(); + backend.focus(1.into(), false).unwrap(); + backend.raise(1.into()).unwrap(); + backend.minimize(1.into()).unwrap(); + backend.unminimize(1.into()).unwrap(); + backend.maximize(1.into(), true).unwrap(); + backend.maximize(1.into(), false).unwrap(); + backend.close(3.into()).unwrap(); // the terminal has closed, and the table still knows it: the bridge gives it back - backend.set_rect(2, &left(960)).unwrap(); + backend.set_rect(2.into(), &left(960)).unwrap(); }, |backend| { // the editor goes to the second workspace before the monitor is switched to it let monitor = backend.monitors().unwrap()[0].id; - backend.set_window_workspace(1, 1).unwrap(); - backend.switch_workspace(monitor, 1).unwrap(); - assert_eq!(backend.window_workspace(1), Some(1)); - assert_eq!(backend.current_workspaces(), [(monitor, 1)]); + backend.set_window_workspace(1.into(), 1).unwrap(); + backend.switch_workspace(monitor.into(), 1).unwrap(); + assert_eq!(backend.window_workspace(1.into()).unwrap(), Some(1)); + assert_eq!(backend.current_workspaces().unwrap(), [(monitor.into(), 1)]); }, |backend| { // 51 of 255 is a fifth - backend.set_opacity(1, 51).unwrap(); + backend.set_opacity(1.into(), 51).unwrap(); }, ]; assert_eq!(asks.len(), commands.len()); @@ -1362,7 +1397,7 @@ mod tests { } // the right tile, as the window manager put it - let tile = backend.window_rect(2).unwrap(); + let tile = backend.window_rect(2.into()).unwrap(); assert!(tile.left > 900, "{tile:?}"); let started = report(json!({ @@ -1382,7 +1417,7 @@ mod tests { process(&mut wm, waiting); assert_eq!( - backend.window_rect(2).unwrap().left, + backend.window_rect(2.into()).unwrap().left, tile.left - 200, "the tile took what the user asked for" ); @@ -1393,9 +1428,9 @@ mod tests { fn a_command_about_a_window_the_table_does_not_know_is_an_error_and_sends_nothing() { let (runtime, backend) = offline(); - assert!(backend.focus(7, false).is_err()); - assert!(backend.hide(7).is_err()); - assert!(backend.restore(7).is_err()); + assert!(backend.focus(7.into(), false).is_err()); + assert!(backend.hide(7.into()).is_err()); + assert!(backend.restore(7.into()).is_err()); assert_eq!(next_poll(&runtime, &backend), json!([])); } @@ -1429,20 +1464,20 @@ mod tests { table.set_park(String::from("p1")); } - backend.hide(1).unwrap(); + backend.hide(1.into()).unwrap(); assert_eq!( next_poll(&runtime, &backend), json!([{ "batch": 1, "cmds": [{ "op": "desktop", "id": "{a}", "v": "p1" }] }]) ); - backend.restore(1).unwrap(); + backend.restore(1.into()).unwrap(); assert_eq!( next_poll(&runtime, &backend), json!([{ "batch": 2, "cmds": [{ "op": "desktop", "id": "{a}", "v": "d1" }] }]) ); // a window that is not hidden is not sent anywhere - backend.restore(1).unwrap(); + backend.restore(1.into()).unwrap(); assert_eq!(next_poll(&runtime, &backend), json!([])); } @@ -1451,7 +1486,7 @@ mod tests { let (_runtime, backend) = offline(); // no snapshot yet: there is no monitor - let nowhere = backend.set_wallpaper(1, std::path::Path::new("/nonexistent/a.png")); + let nowhere = backend.set_wallpaper(1.into(), std::path::Path::new("/nonexistent/a.png")); assert!(nowhere.unwrap_err().to_string().contains("no such monitor")); let events: Vec = @@ -1463,7 +1498,8 @@ mod tests { .handle(&events[0], Instant::now()); let monitor = backend.monitors().unwrap()[0].id; - let missing = backend.set_wallpaper(monitor, std::path::Path::new("/nonexistent/a.png")); + let missing = + backend.set_wallpaper(monitor.into(), std::path::Path::new("/nonexistent/a.png")); assert!(missing.unwrap_err().to_string().contains("is not a file")); assert!(backend.shared.wallpapers.lock().is_empty()); } diff --git a/komorebi-for-kde/komorebi/src/monitor.rs b/komorebi-for-kde/komorebi/src/monitor.rs index 281ebc29..bd44a0d1 100644 --- a/komorebi-for-kde/komorebi/src/monitor.rs +++ b/komorebi-for-kde/komorebi/src/monitor.rs @@ -30,6 +30,8 @@ use crate::workspace::WorkspaceGlobals; use crate::workspace::WorkspaceLayer; use color_eyre::eyre; use color_eyre::eyre::OptionExt; +use komorebi_backend::MonitorId; +use komorebi_backend::WindowId; use serde::Deserialize; use serde::Serialize; use std::collections::VecDeque; @@ -254,7 +256,8 @@ impl Monitor { // was on self.assign_windows_to_workspaces(); - if let Err(error) = backend().switch_workspace(monitor_id, focused_idx) { + if let Err(error) = backend().switch_workspace(MonitorId::from_u32(monitor_id), focused_idx) + { tracing::warn!("could not show workspace {focused_idx}: {error}"); } @@ -284,8 +287,13 @@ impl Monitor { .chain(workspace.maximized_window.iter()); for window in windows { - if backend().window_workspace(window.id) != Some(idx) - && let Err(error) = backend().set_window_workspace(window.id, idx) + if backend() + .window_workspace(WindowId::from_u32(window.id)) + .ok() + .flatten() + != Some(idx) + && let Err(error) = + backend().set_window_workspace(WindowId::from_u32(window.id), idx) { tracing::debug!( "could not put window {} on workspace {idx}: {error}", @@ -323,6 +331,7 @@ impl Monitor { let foreground_hwnd = if !cfg!(test) { backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")? } else { 0 diff --git a/komorebi-for-kde/komorebi/src/process_event.rs b/komorebi-for-kde/komorebi/src/process_event.rs index b464d6db..2f654728 100644 --- a/komorebi-for-kde/komorebi/src/process_event.rs +++ b/komorebi-for-kde/komorebi/src/process_event.rs @@ -116,6 +116,7 @@ use crate::window_manager_event::WindowManagerEvent; use crate::workspace::WorkspaceLayer; use color_eyre::eyre; use color_eyre::eyre::OptionExt; +use komorebi_backend::WindowId; use parking_lot::Mutex; use std::sync::Arc; use tracing::instrument; @@ -457,7 +458,10 @@ impl WindowManager { } // an app that remembers it was maximized opens that way - if backend().window(window_id).is_some_and(|w| w.maximized) { + if backend() + .window(WindowId::from_u32(window_id)) + .is_some_and(|w| w.maximized) + { self.update_known_window_ids(); self.adopt_maximize_change(window_id, true)?; } @@ -518,7 +522,9 @@ impl WindowManager { } if focused { - let refocus = should_refocus_after_destroy(backend().foreground_window()); + let refocus = should_refocus_after_destroy( + backend().foreground_window().and_then(WindowId::to_u32), + ); self.update_focused_workspace(refocus, refocus)?; } } @@ -793,7 +799,9 @@ impl WindowManager { ); if !already_started { - let started_from = match crate::backend::backend().drag_origin(window_id) { + let started_from = match crate::backend::backend() + .drag_origin(WindowId::from_u32(window_id)) + { Some(origin) => origin, None => window.rect()?, }; @@ -861,10 +869,11 @@ impl WindowManager { // client is still drawing at the new size, and the frame events after the // drag can have changed that by now: the end of a resize does not wait for // them - let new_position = match crate::backend::backend().drag_end(window_id) { - Some(asked) => asked, - None => window.rect()?, - }; + let new_position = + match crate::backend::backend().drag_end(WindowId::from_u32(window_id)) { + Some(asked) => asked, + None => window.rect()?, + }; let resized = self.apply_mouse_resize(window, started_from, new_position)?; // put every window where the layout now says: the dragged one too when diff --git a/komorebi-for-kde/komorebi/src/transparency_manager.rs b/komorebi-for-kde/komorebi/src/transparency_manager.rs index a2d4ac87..40a20898 100644 --- a/komorebi-for-kde/komorebi/src/transparency_manager.rs +++ b/komorebi-for-kde/komorebi/src/transparency_manager.rs @@ -17,6 +17,7 @@ use crate::backend::backend; use crate::window::Window; use crate::window::should_act; use crate::window_manager::WindowManager; +use komorebi_backend::WindowId; use std::collections::HashSet; use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicU8; @@ -121,8 +122,8 @@ pub fn apply(wm: &mut WindowManager) { .copied() .collect(); for id in no_longer { - if backend().is_window(id) - && let Err(error) = backend().set_opacity(id, OPAQUE) + if backend().is_window(WindowId::from_u32(id)) + && let Err(error) = backend().set_opacity(WindowId::from_u32(id), OPAQUE) { tracing::warn!("could not make window {id} opaque: {error}"); } @@ -134,7 +135,7 @@ pub fn apply(wm: &mut WindowManager) { continue; } - match backend().set_opacity(id, alpha) { + match backend().set_opacity(WindowId::from_u32(id), alpha) { Ok(()) => { wm.opacity_applied.insert(id, alpha); } @@ -146,8 +147,8 @@ pub fn apply(wm: &mut WindowManager) { /// Makes every window komorebi made see-through opaque again, when komorebi exits. pub fn restore(wm: &mut WindowManager) { for (id, _) in wm.opacity_applied.drain() { - if backend().is_window(id) { - let _ = backend().set_opacity(id, OPAQUE); + if backend().is_window(WindowId::from_u32(id)) { + let _ = backend().set_opacity(WindowId::from_u32(id), OPAQUE); } } } diff --git a/komorebi-for-kde/komorebi/src/window.rs b/komorebi-for-kde/komorebi/src/window.rs index fca50ed3..a90902a1 100644 --- a/komorebi-for-kde/komorebi/src/window.rs +++ b/komorebi-for-kde/komorebi/src/window.rs @@ -27,14 +27,15 @@ use crate::REGEX_IDENTIFIERS; use crate::backend::backend; use crate::core::ApplicationIdentifier; use crate::core::Rect; -pub use komorebi_config::aspect_ratio::AspectRatio; -pub use komorebi_config::aspect_ratio::PredefinedAspectRatio; use crate::core::config_generation::IdWithIdentifier; use crate::core::config_generation::MatchingRule; use crate::core::config_generation::MatchingStrategy; use crate::window_manager_event::WindowManagerEvent; use color_eyre::eyre; use color_eyre::eyre::OptionExt; +use komorebi_backend::WindowId; +pub use komorebi_config::aspect_ratio::AspectRatio; +pub use komorebi_config::aspect_ratio::PredefinedAspectRatio; use regex::Regex; use serde::Deserialize; use serde::Serialize; @@ -91,6 +92,16 @@ impl From for Window { } } +impl From for Window { + /// An id too wide for a `u32` is not one this compositor ever gave: it becomes `u32::MAX`, which + /// no window has. + fn from(id: WindowId) -> Self { + Self { + id: id.to_u32().unwrap_or(u32::MAX), + } + } +} + #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct WindowDetails { @@ -174,18 +185,23 @@ impl schemars::JsonSchema for Window { } impl Window { + /// The id as the backend names it + pub fn window_id(self) -> WindowId { + WindowId::from_u32(self.id) + } + /// What the compositor knows about this window, including for a few moments after it closed pub fn info(self) -> Option { - backend().window(self.id) + backend().window(self.window_id()) } /// Whether the window still exists pub fn is_valid(self) -> bool { - backend().is_window(self.id) + backend().is_window(self.window_id()) } pub fn is_focused(self) -> bool { - backend().foreground_window() == Some(self.id) + backend().foreground_window() == Some(self.window_id()) } pub fn is_minimized(self) -> bool { @@ -216,7 +232,7 @@ impl Window { /// The window's current frame geometry, as last reported by the compositor pub fn rect(self) -> eyre::Result { backend() - .window_rect(self.id) + .window_rect(self.window_id()) .ok_or_eyre("the window does not exist") } @@ -240,21 +256,23 @@ impl Window { return Ok(()); } - backend().set_rect(self.id, rect) + backend().set_rect(self.window_id(), rect) } /// Returns true if and only if the window is fullscreen pub fn is_fullscreen(self) -> bool { - backend().window(self.id).is_some_and(|w| w.fullscreen) + backend() + .window(self.window_id()) + .is_some_and(|w| w.fullscreen) } /// Asks the compositor to draw the window with this opacity, 255 being not see-through at all pub fn set_opacity(self, alpha: u8) -> komorebi_backend::Result<()> { - backend().set_opacity(self.id, alpha) + backend().set_opacity(self.window_id(), alpha) } pub fn focus(self, mouse_follows_focus: bool) -> komorebi_backend::Result<()> { - backend().focus(self.id, mouse_follows_focus) + backend().focus(self.window_id(), mouse_follows_focus) } /// Have the compositor maximize the window (the work area, panels respected) @@ -263,7 +281,7 @@ impl Window { /// /// The backend does not know the window, or refuses to maximize it. pub fn maximize(self) -> komorebi_backend::Result<()> { - backend().maximize(self.id, true) + backend().maximize(self.window_id(), true) } /// Have the compositor give the window back the frame it had before it was maximized @@ -272,25 +290,25 @@ impl Window { /// /// The backend does not know the window, or refuses to restore it. pub fn unmaximize(self) -> komorebi_backend::Result<()> { - backend().maximize(self.id, false) + backend().maximize(self.window_id(), false) } pub fn raise(self) -> komorebi_backend::Result<()> { - backend().raise(self.id) + backend().raise(self.window_id()) } pub fn close(self) -> komorebi_backend::Result<()> { - backend().close(self.id) + backend().close(self.window_id()) } /// Minimizes the window, as the user asking for it would. [`Window::hide`] is what komorebi /// does to keep the back of a stack out of the way. pub fn minimize(self) -> komorebi_backend::Result<()> { - backend().minimize(self.id) + backend().minimize(self.window_id()) } pub fn unminimize(self) -> komorebi_backend::Result<()> { - backend().unminimize(self.id) + backend().unminimize(self.window_id()) } /// Takes the window out of sight ([`Backend::hide`](crate::backend::Backend::hide)): the back @@ -302,7 +320,7 @@ impl Window { /// stays where it is, and stays recorded as hidden until [`Window::restore`]. pub fn hide(self) { HIDDEN_WINDOWS.lock().insert(self.id); - if let Err(error) = backend().hide(self.id) { + if let Err(error) = backend().hide(self.window_id()) { tracing::warn!("failed to hide window {}: {error}", self.id); } } @@ -311,7 +329,7 @@ impl Window { /// [`struct@HIDDEN_WINDOWS`]. A failure is logged, as for [`Window::hide`]. pub fn restore(self) { HIDDEN_WINDOWS.lock().remove(&self.id); - if let Err(error) = backend().restore(self.id) { + if let Err(error) = backend().restore(self.window_id()) { tracing::warn!("failed to restore window {}: {error}", self.id); } } diff --git a/komorebi-for-kde/komorebi/src/window_manager.rs b/komorebi-for-kde/komorebi/src/window_manager.rs index 32a1beba..d4f0e253 100644 --- a/komorebi-for-kde/komorebi/src/window_manager.rs +++ b/komorebi-for-kde/komorebi/src/window_manager.rs @@ -91,6 +91,7 @@ use color_eyre::eyre::OptionExt; use color_eyre::eyre::bail; use crossbeam_channel::Receiver; use hotwatch::Hotwatch; +use komorebi_backend::WindowId; use parking_lot::Mutex; use std::collections::HashMap; use std::collections::HashSet; @@ -322,6 +323,7 @@ impl WindowManager { if len > 1 { let focused_window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")?; let focused_rect = Window::from(focused_window_id).rect()?; @@ -797,6 +799,7 @@ impl WindowManager { let focused_window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")?; for window in focused_workspace.floating_windows().iter() { if window.id == focused_window_id { @@ -1702,6 +1705,7 @@ impl WindowManager { pub fn toggle_float(&mut self, force_float: bool) -> eyre::Result<()> { let window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")?; let workspace = self.focused_workspace_mut()?; @@ -1811,6 +1815,7 @@ impl WindowManager { let workspace = self.focused_workspace()?; let focused_window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")?; let border_offset = 0; @@ -2359,7 +2364,7 @@ impl WindowManager { pub fn monitor_idx_from_current_pos(&mut self) -> Option { let (x, y) = backend().cursor_pos()?; - let monitor_id = backend().monitor_from_point(x, y)?; + let monitor_id = backend().monitor_from_point(x, y)?.to_u32()?; for (i, monitor) in self.monitors().iter().enumerate() { if monitor.id == monitor_id { @@ -2470,6 +2475,7 @@ impl WindowManager { let foreground_window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")?; let floating_window_index = workspace .floating_windows() @@ -2765,6 +2771,7 @@ impl WindowManager { if len > 1 { let focused_window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")?; for (idx, window) in focused_workspace.floating_windows().iter().enumerate() { if window.id == focused_window_id { @@ -3268,6 +3275,7 @@ impl WindowManager { let workspace = self.focused_workspace()?; let focused_hwnd = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("there is no foreground window")?; if !workspace.contains_managed_window(focused_hwnd) { bail!("ignoring commands while active window is not managed by komorebi"); @@ -3801,6 +3809,7 @@ impl WindowManager { pub fn manage_focused_window(&mut self) -> eyre::Result<()> { let window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("there is no foreground window")?; UNMANAGED_WINDOW_IDS.lock().retain(|id| *id != window_id); @@ -3823,6 +3832,7 @@ impl WindowManager { pub fn unmanage_focused_window(&mut self) -> eyre::Result<()> { let window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("there is no foreground window")?; window_manager_event_listener::send_notification(WindowManagerEvent::Unmanage( diff --git a/komorebi-for-kde/komorebi/src/workspace.rs b/komorebi-for-kde/komorebi/src/workspace.rs index ca86b6e5..c6d6552c 100644 --- a/komorebi-for-kde/komorebi/src/workspace.rs +++ b/komorebi-for-kde/komorebi/src/workspace.rs @@ -40,6 +40,8 @@ use crate::window::should_act; use crate::window::should_act_individual; use color_eyre::eyre; use color_eyre::eyre::OptionExt; +use komorebi_backend::MonitorId; +use komorebi_backend::WindowId; use komorebi_scrolling::ScrollingSpace; use komorebi_themes::KomorebiTheme; use komorebi_themes::KomorebiThemeCustom; @@ -905,6 +907,7 @@ impl Workspace { pub fn is_focused_window_monocle_or_maximized(&self) -> eyre::Result { let window_id = backend() .foreground_window() + .and_then(WindowId::to_u32) .ok_or_eyre("no foreground window")?; if let Some(window) = &self.maximized_window && window_id == window.id @@ -1663,7 +1666,7 @@ impl Workspace { } pub fn remove_focused_floating_window(&mut self) -> Option { - let window_id = backend().foreground_window()?; + let window_id = backend().foreground_window().and_then(WindowId::to_u32)?; self.remove_floating_window(window_id) } @@ -2137,7 +2140,9 @@ impl Workspace { monitor_wp: &Option, ) -> eyre::Result<()> { if let Some(wallpaper) = self.wallpaper.as_ref().or(monitor_wp.as_ref()) { - if let Err(error) = backend().set_wallpaper(monitor_id, &wallpaper.path) { + if let Err(error) = + backend().set_wallpaper(MonitorId::from_u32(monitor_id), &wallpaper.path) + { tracing::error!("failed to set wallpaper: {error}"); } diff --git a/komorebi-for-kde/komorebi/tests/maximize_commands.rs b/komorebi-for-kde/komorebi/tests/maximize_commands.rs index ab566f9d..ac052811 100644 --- a/komorebi-for-kde/komorebi/tests/maximize_commands.rs +++ b/komorebi-for-kde/komorebi/tests/maximize_commands.rs @@ -306,7 +306,10 @@ fn focusing_towards_a_monitor_with_a_maximized_window_gives_it_the_focus() { ); assert_eq!(wm.focused_monitor_idx(), 1); - assert_eq!(fake.foreground_window(), Some(36_064)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(36_064) + ); } #[test] @@ -352,7 +355,10 @@ fn eager_focus_finds_the_maximized_window_of_an_executable() { event(&fake, &mut wm, added(36_092)); send(&fake, &mut wm, SocketMessage::ToggleMaximize); event(&fake, &mut wm, activated(36_091)); - assert_eq!(fake.foreground_window(), Some(36_091)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(36_091) + ); send( &fake, @@ -360,5 +366,8 @@ fn eager_focus_finds_the_maximized_window_of_an_executable() { SocketMessage::EagerFocus(String::from("kate")), ); - assert_eq!(fake.foreground_window(), Some(36_092)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(36_092) + ); } diff --git a/komorebi-for-kde/komorebi/tests/monitors.rs b/komorebi-for-kde/komorebi/tests/monitors.rs index 1086ba37..2b21721c 100644 --- a/komorebi-for-kde/komorebi/tests/monitors.rs +++ b/komorebi-for-kde/komorebi/tests/monitors.rs @@ -145,7 +145,10 @@ fn the_focus_crosses_to_the_monitor_on_that_side() { .unwrap(); assert_eq!(wm.focused_monitor_idx(), 1); - assert_eq!(fake.foreground_window(), Some(32_011)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(32_011) + ); // and with no monitor further right, it is an error that changes nothing let result = send( @@ -258,7 +261,10 @@ fn a_monitor_is_focused_by_its_index_or_in_order() { send(&fake, &mut wm, SocketMessage::FocusMonitorNumber(0)).unwrap(); assert_eq!(wm.focused_monitor_idx(), 0); - assert_eq!(fake.foreground_window(), Some(32_051)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(32_051) + ); send( &fake, @@ -267,7 +273,10 @@ fn a_monitor_is_focused_by_its_index_or_in_order() { ) .unwrap(); assert_eq!(wm.focused_monitor_idx(), 1); - assert_eq!(fake.foreground_window(), Some(32_052)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(32_052) + ); assert!(send(&fake, &mut wm, SocketMessage::FocusMonitorNumber(5)).is_err()); assert_eq!(wm.focused_monitor_idx(), 1); @@ -396,7 +405,10 @@ fn eager_focus_finds_the_window_of_an_executable_on_any_monitor_and_workspace() assert_eq!(wm.focused_monitor_idx(), 1); assert_eq!(wm.focused_workspace_idx().unwrap(), 1); - assert_eq!(fake.foreground_window(), Some(32_102)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(32_102) + ); assert_eq!(fake.shown_workspace(RIGHT), 1); assert_eq!(fake.shown_workspace(LEFT), 0); } diff --git a/komorebi-for-kde/komorebi/tests/monocle.rs b/komorebi-for-kde/komorebi/tests/monocle.rs index 2fba8464..31082e28 100644 --- a/komorebi-for-kde/komorebi/tests/monocle.rs +++ b/komorebi-for-kde/komorebi/tests/monocle.rs @@ -508,7 +508,10 @@ fn focusing_towards_a_monitor_in_monocle_gives_the_focus_to_its_monocle_window() ); assert_eq!(wm.focused_monitor_idx(), 1); - assert_eq!(fake.foreground_window(), Some(35_113)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(35_113) + ); assert_eq!( wm.monitors()[1] .focused_workspace() @@ -592,5 +595,8 @@ fn eager_focus_finds_the_window_of_an_executable_in_the_monocle() { SocketMessage::EagerFocus(String::from("kate")), ); - assert_eq!(fake.foreground_window(), Some(35_142)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(35_142) + ); } diff --git a/komorebi-for-kde/komorebi/tests/stacks.rs b/komorebi-for-kde/komorebi/tests/stacks.rs index eaf1f11a..df6ab711 100644 --- a/komorebi-for-kde/komorebi/tests/stacks.rs +++ b/komorebi-for-kde/komorebi/tests/stacks.rs @@ -168,7 +168,10 @@ fn stacking_puts_two_windows_in_one_container_and_hides_the_one_behind() { // 33_023 is the bottom right tile and had the focus: it goes onto 33_022, above it assert_eq!(containers(&wm), [vec![33_021], vec![33_023, 33_022]]); assert_eq!(hidden(&fake, &ids), [33_022]); - assert_eq!(fake.foreground_window(), Some(33_023)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(33_023) + ); } #[test] @@ -258,7 +261,10 @@ fn closing_the_window_in_front_of_a_stack_brings_the_next_one_forward() { assert_eq!(containers(&wm), [vec![33_071]]); assert!(hidden(&fake, &ids).is_empty()); - assert_eq!(fake.foreground_window(), Some(33_071)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(33_071) + ); } #[test] @@ -504,7 +510,10 @@ fn cycling_the_stack_brings_the_next_window_to_the_front_and_hides_the_one_that_ assert_eq!(wm.focused_window().unwrap().id, 33_201); assert_eq!(hidden(&fake, &ids), [33_202, 33_203]); - assert_eq!(fake.foreground_window(), Some(33_201)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(33_201) + ); send( &fake, @@ -515,7 +524,10 @@ fn cycling_the_stack_brings_the_next_window_to_the_front_and_hides_the_one_that_ assert_eq!(wm.focused_window().unwrap().id, 33_203); assert_eq!(hidden(&fake, &ids), [33_201, 33_202]); - assert_eq!(fake.foreground_window(), Some(33_203)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(33_203) + ); } #[test] @@ -560,7 +572,10 @@ fn cycling_the_index_moves_the_front_window_along_the_stack_and_keeps_it_in_fron assert_eq!(order(&wm), [33_223, 33_222, 33_221]); assert_eq!(wm.focused_window().unwrap().id, 33_223); assert_eq!(hidden(&fake, &ids), [33_221, 33_222]); - assert_eq!(fake.foreground_window(), Some(33_223)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(33_223) + ); } #[test] @@ -572,7 +587,10 @@ fn focus_stack_window_brings_the_window_at_an_index_to_the_front() { assert_eq!(wm.focused_window().unwrap().id, 33_232); assert_eq!(hidden(&fake, &ids), [33_231, 33_233]); - assert_eq!(fake.foreground_window(), Some(33_232)); + assert_eq!( + fake.foreground_window().and_then(|id| id.to_u32()), + Some(33_232) + ); send(&fake, &mut wm, SocketMessage::FocusStackWindow(0)).unwrap(); assert_eq!(wm.focused_window().unwrap().id, 33_231); diff --git a/komorebi-for-kde/komorebi/tests/workspaces.rs b/komorebi-for-kde/komorebi/tests/workspaces.rs index e98b35ce..5e4d0c30 100644 --- a/komorebi-for-kde/komorebi/tests/workspaces.rs +++ b/komorebi-for-kde/komorebi/tests/workspaces.rs @@ -264,7 +264,7 @@ fn a_window_open_on_a_desktop_at_startup_starts_on_that_workspace() { fake.show_workspace_by_user(MONITOR, 0); { use komorebi::backend::Backend; - fake.set_window_workspace(10_112, 1).unwrap(); + fake.set_window_workspace(10_112.into(), 1).unwrap(); fake.clear_commands(); } let (_fake, wm) = desktop_on(fake);