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<WindowId> 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.
This commit is contained in:
LGUG2Z committed 2026-10-31 10:29:23 -07:00
1 parent 06ce5adfe8
commit c08ee2cfae
17 files changed
+459 -306

No files matched your search

+116 -90
View File
@@ -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<WindowInfo> {
self.inner.window(wid(id)).map(window_info)
fn window(&self, id: WindowId) -> Option<WindowInfo> {
self.inner.window(id).map(window_info)
}
fn foreground_window(&self) -> Option<u32> {
self.inner.foreground_window().map(raw)
fn foreground_window(&self) -> Option<WindowId> {
self.inner.foreground_window()
}
fn monitors(&self) -> shared::Result<Vec<MonitorInfo>> {
@@ -433,41 +433,40 @@ impl Backend for FakeBackend {
self.inner.cursor_pos()
}
fn drag_end(&self, id: u32) -> Option<Rect> {
self.kde.lock().drag_ends.get(&id).copied()
fn drag_end(&self, id: WindowId) -> Option<Rect> {
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<usize> {
self.inner.window_workspace(wid(id)).ok().flatten()
fn window_workspace(&self, id: WindowId) -> komorebi_backend::Result<Option<usize>> {
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<Vec<(MonitorId, usize)>> {
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<bool> {
@@ -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<bool> {
@@ -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);
+57 -54
View File
@@ -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<u8>);
///
/// # impl Backend for NotShareable {
/// # fn windows(&self) -> Vec<WindowInfo> { vec![] }
/// # fn window(&self, _: u32) -> Option<WindowInfo> { None }
/// # fn foreground_window(&self) -> Option<u32> { None }
/// # fn window(&self, _: WindowId) -> Option<WindowInfo> { None }
/// # fn foreground_window(&self) -> Option<WindowId> { None }
/// # fn monitors(&self) -> komorebi_backend::Result<Vec<MonitorInfo>> { 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<usize> { 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<Option<usize>> { Ok(None) }
/// # fn current_workspaces(&self) -> komorebi_backend::Result<Vec<(MonitorId, usize)>> { Ok(vec![]) }
/// # }
/// ```
pub trait Backend: Send + Sync + 'static {
@@ -243,10 +246,10 @@ pub trait Backend: Send + Sync + 'static {
fn windows(&self) -> Vec<WindowInfo>;
/// Returns what is known about the window, or `None` if the compositor has never heard of it.
fn window(&self, id: u32) -> Option<WindowInfo>;
fn window(&self, id: WindowId) -> Option<WindowInfo>;
/// Returns the id of the window that has the focus, if any window does.
fn foreground_window(&self) -> Option<u32>;
fn foreground_window(&self) -> Option<WindowId>;
/// 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<Rect> {
fn drag_origin(&self, _id: WindowId) -> Option<Rect> {
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<Rect> {
fn drag_end(&self, _id: WindowId) -> Option<Rect> {
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<usize>;
fn window_workspace(&self, id: WindowId) -> komorebi_backend::Result<Option<usize>>;
/// 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<Vec<(MonitorId, usize)>>;
// ---- 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<Rect> {
fn window_rect(&self, id: WindowId) -> Option<Rect> {
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<u32> {
fn monitor_from_point(&self, x: i32, y: i32) -> Option<MonitorId> {
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());
}
}
+17 -35
View File
@@ -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<B: Backend + ?Sized> Shared<B> {
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<B: Backend + ?Sized> shared::Backend for Shared<B> {
}
fn window(&self, id: WindowId) -> Option<shared::WindowInfo> {
self.0.window(id.to_u32()?).map(window_info)
self.0.window(id).map(window_info)
}
fn foreground_window(&self) -> Option<WindowId> {
self.0.foreground_window().map(WindowId::from_u32)
self.0.foreground_window()
}
fn monitors(&self) -> shared::Result<Vec<shared::MonitorInfo>> {
@@ -98,35 +85,35 @@ impl<B: Backend + ?Sized> shared::Backend for Shared<B> {
}
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<B: Backend + ?Sized> shared::Backend for Shared<B> {
}
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<B: Backend + ?Sized> shared::Backend for Shared<B> {
}
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<Option<usize>> {
Ok(id.to_u32().and_then(|raw| self.0.window_workspace(raw)))
self.0.window_workspace(id)
}
fn current_workspaces(&self) -> shared::Result<Vec<(MonitorId, usize)>> {
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;
@@ -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() {
+11 -3
View File
@@ -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);
+107 -71
View File
@@ -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<u32> {
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<WindowInfo> {
fn window(&self, id: WindowId) -> Option<WindowInfo> {
let id = id.to_u32()?;
self.shared.table.lock().window(id)
}
fn foreground_window(&self) -> Option<u32> {
self.shared.table.lock().foreground()
fn foreground_window(&self) -> Option<WindowId> {
self.shared
.table
.lock()
.foreground()
.map(WindowId::from_u32)
}
fn drag_origin(&self, id: u32) -> Option<Rect> {
fn drag_origin(&self, id: WindowId) -> Option<Rect> {
let id = id.to_u32()?;
self.shared.table.lock().drag_origin(id)
}
fn drag_end(&self, id: u32) -> Option<Rect> {
fn drag_end(&self, id: WindowId) -> Option<Rect> {
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<usize> {
self.shared.table.lock().window_workspace(id)
fn window_workspace(&self, id: WindowId) -> komorebi_backend::Result<Option<usize>> {
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<Vec<(MonitorId, usize)>> {
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<Value> =
@@ -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());
}
+12 -3
View File
@@ -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
+16 -7
View File
@@ -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
@@ -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);
}
}
}
+36 -18
View File
@@ -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<u32> for Window {
}
}
impl From<WindowId> 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<crate::backend::WindowInfo> {
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<Rect> {
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);
}
}
@@ -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<usize> {
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(
+7 -2
View File
@@ -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<bool> {
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<Window> {
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<Wallpaper>,
) -> 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}");
}
@@ -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)
);
}
+16 -4
View File
@@ -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);
}
+8 -2
View File
@@ -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)
);
}
+24 -6
View File
@@ -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);
@@ -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);