From 9e73b1f9a45cef115a12772f0e0bad624ea9efb2 Mon Sep 17 00:00:00 2001 From: Cody Bloemhard Date: Mon, 12 Aug 2024 20:31:41 +0200 Subject: [PATCH 1/6] feat: toggle_floating_state and is_floating (#306) --- src/builtin/actions/floating.rs | 20 +++++++++++++++++++- src/pure/stack_set.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/builtin/actions/floating.rs b/src/builtin/actions/floating.rs index caa0b530..dc76a9da 100644 --- a/src/builtin/actions/floating.rs +++ b/src/builtin/actions/floating.rs @@ -52,7 +52,7 @@ pub fn reposition(dx: i32, dy: i32) -> Box> { }) } -/// Move the currently focused windo to the floating layer in its current on screen position +/// Move the currently focused window to the floating layer in its current on screen position pub fn float_focused() -> Box> { key_handler(|state, x: &X| { let id = match state.client_set.current_client() { @@ -82,6 +82,24 @@ pub fn sink_focused() -> Box> { }) } +/// Sink the current window if it was floating, float it if it was tiled. +pub fn toggle_floating_focused() -> Box> { + key_handler(|state, x: &X| { + let id = match state.client_set.current_client() { + Some(&id) => id, + None => return Ok(()), + }; + + let mut r = x.client_geometry(id)?; + + x.modify_and_refresh(state, |cs| { + if let Err(err) = cs.toggle_floating_state(id, r) { + error!(%err, %id, "unable to float requested client window"); + } + }) + }) +} + /// Float all windows in their current tiled position pub fn float_all() -> Box> { key_handler(|state, x: &X| { diff --git a/src/pure/stack_set.rs b/src/pure/stack_set.rs index 6f9c2a75..cc4a644e 100644 --- a/src/pure/stack_set.rs +++ b/src/pure/stack_set.rs @@ -270,6 +270,11 @@ where .map(|rr| rr.applied_to(&self.screens.focus.r)) } + /// Check whether a given client is currently floating. + pub fn is_floating(&mut self, client: &C) -> bool { + self.floating.contains_key(client) + } + /// Check whether a given tag currently has any floating windows present. /// /// Returns false if the tag given is unknown to this StackSet. @@ -799,6 +804,27 @@ impl StackSet { Ok(()) } + /// If a known client is floating, sink it. + /// Otherwise, record it as floating with its preferred screen position. + /// + /// # Errors + /// This method with return [Error::UnknownClient] if the given client is + /// not already managed in this stack_set. + /// + /// This method with return [Error::ClientIsNotVisible] if the given client is + /// not currently mapped to a screen. This is required to determine the correct + /// relative positioning for the floating client as is it is moved between + /// screens. + pub fn toggle_floating_state(&mut self, client: Xid, r: Rect) -> Result> { + Ok(if self.is_floating(&client) { + self.sink(&client) + + } else { + self.float(client, r)?; + None + }) + } + pub(crate) fn update_screens(&mut self, rects: Vec) -> Result<()> { let n_old = self.screens.len(); let n_new = rects.len(); From a4c430eb5ca52a2376eea20deb07d0f8cce3de83 Mon Sep 17 00:00:00 2001 From: Cody Bloemhard Date: Mon, 12 Aug 2024 20:37:56 +0200 Subject: [PATCH 2/6] fix: remove unnecessary mut; --- src/builtin/actions/floating.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtin/actions/floating.rs b/src/builtin/actions/floating.rs index dc76a9da..7190f8e1 100644 --- a/src/builtin/actions/floating.rs +++ b/src/builtin/actions/floating.rs @@ -90,7 +90,7 @@ pub fn toggle_floating_focused() -> Box> { None => return Ok(()), }; - let mut r = x.client_geometry(id)?; + let r = x.client_geometry(id)?; x.modify_and_refresh(state, |cs| { if let Err(err) = cs.toggle_floating_state(id, r) { From fb854f2a72708de21ea53fedc46146119455ee3f Mon Sep 17 00:00:00 2001 From: Cody Bloemhard Date: Mon, 12 Aug 2024 20:40:26 +0200 Subject: [PATCH 3/6] fix: apply cargo fmt; --- src/pure/stack_set.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pure/stack_set.rs b/src/pure/stack_set.rs index cc4a644e..f4723696 100644 --- a/src/pure/stack_set.rs +++ b/src/pure/stack_set.rs @@ -818,7 +818,6 @@ impl StackSet { pub fn toggle_floating_state(&mut self, client: Xid, r: Rect) -> Result> { Ok(if self.is_floating(&client) { self.sink(&client) - } else { self.float(client, r)?; None From 20d433a943d392928d3bed59eb9cf16950816553 Mon Sep 17 00:00:00 2001 From: Cody Bloemhard Date: Tue, 13 Aug 2024 22:31:35 +0200 Subject: [PATCH 4/6] fix: remove mutable borrow from is_floating; refactor: toggle_floating_state; testcase: floating_client_status tests is_floating; --- src/pure/stack_set.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/pure/stack_set.rs b/src/pure/stack_set.rs index f4723696..c0f72f6a 100644 --- a/src/pure/stack_set.rs +++ b/src/pure/stack_set.rs @@ -271,7 +271,7 @@ where } /// Check whether a given client is currently floating. - pub fn is_floating(&mut self, client: &C) -> bool { + pub fn is_floating(&self, client: &C) -> bool { self.floating.contains_key(client) } @@ -804,7 +804,7 @@ impl StackSet { Ok(()) } - /// If a known client is floating, sink it. + /// If a known client is floating, sink it and return its previous preferred screen position. /// Otherwise, record it as floating with its preferred screen position. /// /// # Errors @@ -816,12 +816,13 @@ impl StackSet { /// relative positioning for the floating client as is it is moved between /// screens. pub fn toggle_floating_state(&mut self, client: Xid, r: Rect) -> Result> { - Ok(if self.is_floating(&client) { + let rect = if self.is_floating(&client) { self.sink(&client) } else { self.float(client, r)?; None - }) + }; + Ok(rect) } pub(crate) fn update_screens(&mut self, rects: Vec) -> Result<()> { @@ -1305,6 +1306,27 @@ pub mod tests { assert_eq!(s.current_client(), Some(&4)); } + #[test_case(&[]; "none")] + #[test_case(&[1]; "one")] + #[test_case(&[1, 2, 4]; "multiple")] + #[test] + fn floating_client_status(to_float: &[u8]) { + let mut s = test_stack_set(5, 3); + for n in 1..5 { + s.insert(n); + } + + for c in to_float { + s.float_unchecked(*c, Rect::default()); + } + for c in to_float { + assert!(s.is_floating(c)); + } + for client in s.clients().copied() { + assert_eq!(to_float.contains(&client), s.is_floating(&client)); + } + } + #[test_case(1, "1"; "current focus to current tag")] #[test_case(2, "1"; "from current tag to current tag")] #[test_case(6, "1"; "from other tag to current tag")] From cad4e38d1efa6b3e998811ed46c50f64c0070352 Mon Sep 17 00:00:00 2001 From: Cody Bloemhard Date: Wed, 14 Aug 2024 05:20:42 +0200 Subject: [PATCH 5/6] test: toggle_floating_state --- src/pure/stack_set.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/pure/stack_set.rs b/src/pure/stack_set.rs index c0f72f6a..19b21395 100644 --- a/src/pure/stack_set.rs +++ b/src/pure/stack_set.rs @@ -1327,6 +1327,42 @@ pub mod tests { } } + #[test] + fn toggle_floating_state() { + let mut ss: StackSet = StackSet::try_new( + LayoutStack::default(), + ["1", "2", "3"], + vec![Rect::default(); 2], + ) + .expect("enough workspaces to cover the number of initial screens"); + + ss.insert(Xid(0)); + ss.insert(Xid(1)); + + for i in 0..10 { + assert_eq!(ss.is_floating(&Xid(0)), i % 2 != 0); + let res = ss.toggle_floating_state(Xid(0), Rect::default()); + assert!(res.is_ok()); + } + + assert!( + matches!( + ss.toggle_floating_state(Xid(3), Rect::default()), + Err(Error::UnknownClient(_)) + ) + ); + + ss.insert(Xid(3)); + ss.move_client_to_tag(&Xid(3), "3"); + + assert!( + matches!( + ss.toggle_floating_state(Xid(3), Rect::default()), + Err(Error::ClientIsNotVisible(_)) + ) + ); + } + #[test_case(1, "1"; "current focus to current tag")] #[test_case(2, "1"; "from current tag to current tag")] #[test_case(6, "1"; "from other tag to current tag")] From 00b8d05f12a7fa7535c25077593caf7b34618847 Mon Sep 17 00:00:00 2001 From: Cody Bloemhard Date: Wed, 14 Aug 2024 17:36:24 +0200 Subject: [PATCH 6/6] fix: apply cargo fmt; --- src/pure/stack_set.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/pure/stack_set.rs b/src/pure/stack_set.rs index 19b21395..52dda1e2 100644 --- a/src/pure/stack_set.rs +++ b/src/pure/stack_set.rs @@ -1345,22 +1345,18 @@ pub mod tests { assert!(res.is_ok()); } - assert!( - matches!( - ss.toggle_floating_state(Xid(3), Rect::default()), - Err(Error::UnknownClient(_)) - ) - ); + assert!(matches!( + ss.toggle_floating_state(Xid(3), Rect::default()), + Err(Error::UnknownClient(_)) + )); ss.insert(Xid(3)); ss.move_client_to_tag(&Xid(3), "3"); - assert!( - matches!( - ss.toggle_floating_state(Xid(3), Rect::default()), - Err(Error::ClientIsNotVisible(_)) - ) - ); + assert!(matches!( + ss.toggle_floating_state(Xid(3), Rect::default()), + Err(Error::ClientIsNotVisible(_)) + )); } #[test_case(1, "1"; "current focus to current tag")]