aboutsummaryrefslogtreecommitdiff
path: root/src/utils/mod.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-12-15 09:07:44 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-12-30 20:12:37 +0300
commitc008e1c5bcab360425780997f70818fa4252c938 (patch)
treefe8b7138ddc3b7bc9a3616cbf42cf8d8defb807e /src/utils/mod.rs
parent1aa60f0da3e7f1a0bf50d6b88d59db6ba094d4f0 (diff)
downloadniri-c008e1c5bcab360425780997f70818fa4252c938.tar.gz
niri-c008e1c5bcab360425780997f70818fa4252c938.tar.bz2
niri-c008e1c5bcab360425780997f70818fa4252c938.zip
floating: Implement smarter clamping for window location
A small part of the window always remains on-screen regardless of the working area changes. Interactive move lets the user position the window anywhere; automatic actions like toggle-window-floating and dialog opening try to put the window fully on-screen. The size-fraction canonical floating window position remains unclamped, and clamping happens when recomputing the logical position.
Diffstat (limited to 'src/utils/mod.rs')
-rw-r--r--src/utils/mod.rs49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index b4ba1002..e7dff735 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -272,6 +272,18 @@ pub fn ensure_min_max_size(mut x: i32, min_size: i32, max_size: i32) -> i32 {
x
}
+pub fn clamp_preferring_top_left_in_area(
+ area: Rectangle<f64, Logical>,
+ rect: &mut Rectangle<f64, Logical>,
+) {
+ rect.loc.x = f64::min(rect.loc.x, area.loc.x + area.size.w - rect.size.w);
+ rect.loc.y = f64::min(rect.loc.y, area.loc.y + area.size.h - rect.size.h);
+
+ // Clamp by top and left last so it takes precedence.
+ rect.loc.x = f64::max(rect.loc.x, area.loc.x);
+ rect.loc.y = f64::max(rect.loc.y, area.loc.y);
+}
+
#[cfg(feature = "dbus")]
pub fn show_screenshot_notification(image_path: Option<PathBuf>) {
let mut notification = notify_rust::Notification::new();
@@ -309,3 +321,40 @@ pub fn cause_panic() {
let b = Duration::from_secs(2);
let _ = a - b;
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_clamp_preferring_top_left() {
+ fn check(
+ (ax, ay, aw, ah): (i32, i32, i32, i32),
+ (rx, ry, rw, rh): (i32, i32, i32, i32),
+ (ex, ey): (i32, i32),
+ ) {
+ let area = Rectangle::from_loc_and_size((ax, ay), (aw, ah)).to_f64();
+ let mut rect = Rectangle::from_loc_and_size((rx, ry), (rw, rh)).to_f64();
+ clamp_preferring_top_left_in_area(area, &mut rect);
+ assert_eq!(rect.loc, Point::from((ex, ey)).to_f64());
+ }
+
+ check((0, 0, 10, 20), (2, 3, 4, 5), (2, 3));
+ check((0, 0, 10, 20), (-2, 3, 4, 5), (0, 3));
+ check((0, 0, 10, 20), (2, -3, 4, 5), (2, 0));
+ check((0, 0, 10, 20), (-2, -3, 4, 5), (0, 0));
+
+ check((1, 1, 10, 20), (2, 3, 4, 5), (2, 3));
+ check((1, 1, 10, 20), (-2, 3, 4, 5), (1, 3));
+ check((1, 1, 10, 20), (2, -3, 4, 5), (2, 1));
+ check((1, 1, 10, 20), (-2, -3, 4, 5), (1, 1));
+
+ check((0, 0, 10, 20), (20, 3, 4, 5), (6, 3));
+ check((0, 0, 10, 20), (2, 30, 4, 5), (2, 15));
+ check((0, 0, 10, 20), (20, 30, 4, 5), (6, 15));
+
+ check((0, 0, 10, 20), (20, 30, 40, 5), (0, 15));
+ check((0, 0, 10, 20), (20, 30, 4, 50), (6, 0));
+ check((0, 0, 10, 20), (20, 30, 40, 50), (0, 0));
+ }
+}