atagen

monolith

public
Star0
Watch0

Commit 7caafe71a560

tarball

atagen <boss@atagen.co>2026-10-19 10:59 UTC

1 file changed+58-31
drag: resize scratchpads around their centre and never move them

Shown scratchpads are placed at the centre of the output's usable area from their size alone, so a move drag was discarded on the next layout pass and a resize drag left the dragged edge trailing the pointer. A move now does not start, and a resize grows both sides, so the edge follows the pointer with twice the delta in size.
Modified file: crates/monolith/src/drag.rs+58 additions−31 deletions
@@ -3,7 +3,7 @@
33
44 use crate::state::{Input, State};
55 use crate::wm::Resizing;
6-use monolith_layout::{Dir, Layout, MIN_FLOAT_SIZE, Rect, WindowId, clamp_float};
6+use monolith_layout::{Dir, Layout, MIN_FLOAT_SIZE, OutputId, Rect, WindowId, clamp_float};
77 use smithay::input::pointer::CursorIcon;
88 use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
99 use smithay::utils::{Logical, Point};
@@ -159,6 +159,8 @@ pub struct Drag {
159159 bounds: Rect,
160160 /// A tiled window, whose splits follow the pointer instead of a rect.
161161 tiled: bool,
162+ /// A scratchpad, which is always centred so a resize grows both sides.
163+ centred: bool,
162164 /// None moves the window.
163165 edges: Option<Edges>,
164166 /// The button the drag started with, whose release ends it.
@@ -275,8 +277,24 @@ pub(crate) fn start_drag(state: &mut State, button: u32) -> bool {
275277 begin_drag(state, id, edges, button, false)
276278 }
277279
280+/// The output a window sits on, which for a scratchpad is wherever it is shown.
281+fn output_of(layout: &Layout, id: WindowId) -> Option<OutputId> {
282+ let win = layout.window(id)?;
283+ win.scratchpad
284+ .and_then(|s| layout.scratchpads().get(s)?.output)
285+ .or(win.output)
286+}
287+
278288 fn window_rect(layout: &Layout, id: WindowId) -> Option<Rect> {
279289 let win = layout.window(id)?;
290+ if win.scratchpad.is_some() {
291+ return layout
292+ .arrange(output_of(layout, id)?)
293+ .floating
294+ .iter()
295+ .find(|f| f.0 == id)
296+ .map(|f| f.1);
297+ }
280298 if win.floating {
281299 return win.float_rect;
282300 }
@@ -320,29 +338,27 @@ fn begin_drag(
320338 } else {
321339 edges
322340 };
323- if tiled && edges.is_none() {
341+ let centred = win.scratchpad.is_some();
342+ if (tiled || centred) && edges.is_none() {
324343 return false;
325344 }
326- let (Some(rect), Some(out)) = (
327- window_rect(layout, id),
328- win.output.and_then(|o| layout.output(o)),
329- ) else {
345+ let home = output_of(layout, id);
346+ let (Some(rect), Some(out)) = (window_rect(layout, id), home.and_then(|o| layout.output(o)))
347+ else {
330348 return false;
331349 };
332- state.wm.resizing = win
333- .output
334- .filter(|_| edges.is_some())
335- .map(|output| Resizing {
336- output,
337- window: id,
338- tiled,
339- });
350+ state.wm.resizing = home.filter(|_| edges.is_some()).map(|output| Resizing {
351+ output,
352+ window: id,
353+ tiled,
354+ });
340355 state.input.drag = Some(Drag {
341356 window: id,
342357 from: state.input.pointer_pos,
343358 rect,
344359 bounds: out.usable(),
345360 tiled,
361+ centred,
346362 edges,
347363 button,
348364 client,
@@ -413,23 +429,34 @@ pub(crate) fn drag_to(state: &mut State, pos: Point<f64, Logical>) -> bool {
413429 r.clamp_size(f64::INFINITY, f64::INFINITY)
414430 });
415431 let min = (min_w.max(MIN_FLOAT_SIZE), min_h.max(MIN_FLOAT_SIZE));
416- let (x, w) = resized(
417- r.x,
418- r.w,
419- dx,
420- (e.left, e.right),
421- (b.x, b.right()),
422- (min.0, max_w),
423- );
424- let (y, h) = resized(
425- r.y,
426- r.h,
427- dy,
428- (e.top, e.bottom),
429- (b.y, b.bottom()),
430- (min.1, max_h),
431- );
432- Rect::new(x, y, w, h)
432+ if d.centred {
433+ let both = (f64::NEG_INFINITY, f64::INFINITY);
434+ let grown = |start, len, delta, edges, limits: (f64, f64), room: f64| {
435+ let (_, len) = resized(start, len, 2.0 * delta, edges, both, limits);
436+ len.min(room).max(limits.0)
437+ };
438+ let w = grown(r.x, r.w, dx, (e.left, e.right), (min.0, max_w), b.w);
439+ let h = grown(r.y, r.h, dy, (e.top, e.bottom), (min.1, max_h), b.h);
440+ Rect::new(r.x + (r.w - w) / 2.0, r.y + (r.h - h) / 2.0, w, h)
441+ } else {
442+ let (x, w) = resized(
443+ r.x,
444+ r.w,
445+ dx,
446+ (e.left, e.right),
447+ (b.x, b.right()),
448+ (min.0, max_w),
449+ );
450+ let (y, h) = resized(
451+ r.y,
452+ r.h,
453+ dy,
454+ (e.top, e.bottom),
455+ (b.y, b.bottom()),
456+ (min.1, max_h),
457+ );
458+ Rect::new(x, y, w, h)
459+ }
433460 }
434461 None => clamp_float(Rect::new(r.x + dx, r.y + dy, r.w, r.h), d.bounds),
435462 };