Commit b01f4e7ab7e6
tarball3 files changed+80-25
@@ -91,6 +91,19 @@ pub struct Output {
9191
pub floating: Vec<WindowId>,9292
}9393
94
+impl Output {95
+ /// The area left once bars and panels have taken their edges.96
+ pub fn usable(&self) -> Rect {97
+ let (a, r) = (self.area, self.reserved);98
+ Rect::new(99
+ a.x + r.left,100
+ a.y + r.top,101
+ (a.w - r.left - r.right).max(0.0),102
+ (a.h - r.top - r.bottom).max(0.0),103
+ )104
+ }105
+}106
+94107
#[derive(Clone, Debug)]95108
pub struct Scratchpad {96109
pub name: String,@@ -725,14 +738,7 @@ impl Layout {
725738
let Some(out) = self.outputs.get(o) else {726739
return Arrangement::default();727740
};728
- let r = out.reserved;729
- let usable = Rect::new(730
- out.area.x + r.left,731
- out.area.y + r.top,732
- (out.area.w - r.left - r.right).max(0.0),733
- (out.area.h - r.top - r.bottom).max(0.0),734
- );735
- let area = inset(usable, self.gaps.outer);741
+ let area = inset(out.usable(), self.gaps.outer);736742
let shown = self.vis_on(o);737743
let vis = &|w: WindowId| shown(w) && !hide.contains(&w);738744
let tiled = out@@ -918,6 +924,30 @@ fn centred(area: Rect, frac: f64) -> Rect {
918924
)919925
}920926
927
+/// The smallest a floating window gets when dragged or rescaled.928
+pub const MIN_FLOAT_SIZE: f64 = 32.0;929
+930
+/// How much of a floating window stays reachable when it is larger than931
+/// the area it lives in.932
+const STRIP: f64 = 64.0;933
+934
+/// Moves a floating rect to keep it reachable inside bounds. A window that935
+/// fits stays whole inside, a larger one keeps its top edge and a strip.936
+pub fn clamp_float(r: Rect, bounds: Rect) -> Rect {937
+ let x = if r.w <= bounds.w {938
+ r.x.clamp(bounds.x, bounds.right() - r.w)939
+ } else {940
+ let strip = STRIP.min(bounds.w);941
+ r.x.clamp(bounds.x + strip - r.w, bounds.right() - strip)942
+ };943
+ let y = if r.h <= bounds.h {944
+ r.y.clamp(bounds.y, bounds.bottom() - r.h)945
+ } else {946
+ r.y.clamp(bounds.y, bounds.bottom() - STRIP.min(bounds.h))947
+ };948
+ Rect::new(x, y, r.w, r.h)949
+}950
+921951
/// Keeps a rect at the same relative spot when it changes output.922952
fn translate(r: Rect, from: Rect, to: Rect) -> Rect {923953
let sx = if from.w > 0.0 { to.w / from.w } else { 1.0 };@@ -629,3 +629,15 @@ fn urgency_skips_the_focused_window_and_ends_with_focus() {
629629
l.focus(b);630630
assert!(!l.window(b).unwrap().urgent);631631
}632
+633
+#[test]634
+fn oversized_floats_keep_their_top_edge_and_a_strip() {635
+ let bounds = Rect::new(0.0, 0.0, 1000.0, 600.0);636
+ let huge = Rect::new(-5000.0, -300.0, 3000.0, 2000.0);637
+ let r = clamp_float(huge, bounds);638
+ assert_eq!((r.x, r.y), (-2936.0, 0.0));639
+ let r = clamp_float(Rect::new(5000.0, 5000.0, 3000.0, 2000.0), bounds);640
+ assert_eq!((r.x, r.y), (936.0, 536.0));641
+ let fits = clamp_float(Rect::new(900.0, 500.0, 300.0, 200.0), bounds);642
+ assert_eq!((fits.x, fits.y), (700.0, 400.0));643
+}@@ -2,7 +2,7 @@
22
//! into these calls, with pointer positions in global logical coordinates.33
44
use crate::state::State;5
-use monolith_layout::{Rect, WindowId};5
+use monolith_layout::{MIN_FLOAT_SIZE, Rect, WindowId, clamp_float};66
use smithay::backend::input::{ButtonState, InputTime, KeyState};77
use smithay::backend::session::Session;88
use smithay::input::keyboard::{FilterResult, Keycode, xkb};@@ -244,7 +244,6 @@ impl State {
244244
245245
const BTN_LEFT: u32 = 0x110;246246
const BTN_RIGHT: u32 = 0x111;247
-const MIN_SIZE: f64 = 32.0;248247
249248
/// The sides of a window a resize moves.250249
#[derive(Clone, Copy, Default)]@@ -310,6 +309,7 @@ pub struct Drag {
310309
window: WindowId,311310
from: Point<f64, Logical>,312311
rect: Rect,312
+ bounds: Rect,313313
/// None moves the window.314314
edges: Option<Edges>,315315
/// The client's button, whose release is still the client's to see.@@ -345,12 +345,11 @@ impl State {
345345
}346346
347347
fn begin_drag(state: &mut State, id: WindowId, edges: Option<Edges>, button: Option<u32>) -> bool {348
- let Some(rect) = state349
- .wm350
- .layout348
+ let layout = &state.wm.layout;349
+ let Some((rect, bounds)) = layout351350
.window(id)352351
.filter(|w| w.floating && !w.fullscreen)353
- .and_then(|w| w.float_rect)352
+ .and_then(|w| Some((w.float_rect?, layout.output(w.output?)?.usable())))354353
else {355354
return false;356355
};@@ -358,20 +357,33 @@ fn begin_drag(state: &mut State, id: WindowId, edges: Option<Edges>, button: Opt
358357
window: id,359358
from: state.input.pointer_pos,360359
rect,360
+ bounds,361361
edges,362362
button,363363
});364364
true365365
}366366
367
-fn resized(start: f64, len: f64, delta: f64, low: bool, high: bool) -> (f64, f64) {368
- if low {369
- let len_now = (len - delta).max(MIN_SIZE);370
- (start + len - len_now, len_now)371
- } else if high {372
- (start, (len + delta).max(MIN_SIZE))373
- } else {374
- (start, len)367
+/// Moves the dragged edges of an axis, keeping them between lo and hi unless368
+/// the window started beyond them, and the size above the minimum.369
+fn resized(370
+ start: f64,371
+ len: f64,372
+ delta: f64,373
+ edges: (bool, bool),374
+ (lo, hi): (f64, f64),375
+) -> (f64, f64) {376
+ let end = start + len;377
+ match edges {378
+ (true, _) => {379
+ let edge = (start + delta).max(lo.min(start)).min(end - MIN_FLOAT_SIZE);380
+ (edge, end - edge)381
+ }382
+ (_, true) => {383
+ let edge = (end + delta).min(hi.max(end)).max(start + MIN_FLOAT_SIZE);384
+ (start, edge - start)385
+ }386
+ _ => (start, len),375387
}376388
}377389
@@ -383,11 +395,12 @@ fn drag_to(state: &mut State, pos: Point<f64, Logical>) -> bool {
383395
let r = d.rect;384396
let rect = match d.edges {385397
Some(e) => {386
- let (x, w) = resized(r.x, r.w, dx, e.left, e.right);387
- let (y, h) = resized(r.y, r.h, dy, e.top, e.bottom);398
+ let b = d.bounds;399
+ let (x, w) = resized(r.x, r.w, dx, (e.left, e.right), (b.x, b.right()));400
+ let (y, h) = resized(r.y, r.h, dy, (e.top, e.bottom), (b.y, b.bottom()));388401
Rect::new(x, y, w, h)389402
}390
- None => Rect::new(r.x + dx, r.y + dy, r.w, r.h),403
+ None => clamp_float(Rect::new(r.x + dx, r.y + dy, r.w, r.h), d.bounds),391404
};392405
let id = d.window;393406
state.wm.layout.set_float_rect(id, rect);