srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/core/src/manager/hittest.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-07-11 14:17:00 +0200
committersrdusr <[email protected]>2024-07-11 14:17:00 +0200
commit86b557a6c0baa4146b30712d8b7633f1b9b46d43 (patch)
tree96ab749c728ac11c2851ea361c6fda63990e588f /crates/core/src/manager/hittest.rs
parent68b645b43e19330474ff106ce5c88dab520d7417 (diff)
downloadsrdwm-86b557a6c0baa4146b30712d8b7633f1b9b46d43.tar.gz
srdwm-86b557a6c0baa4146b30712d8b7633f1b9b46d43.zip
Split crates/core/src/manager.rs (2048 lines) into manager/
Pure reorganization, no behavior change - verified by diffing the function-name set before/after (identical 130 functions) plus a full cargo test pass. WindowManager's struct/field definitions, Default, new(), and the three trivial constructors (add_rule/register_layout/ available_layouts) stay in mod.rs; the rest of the single ~950-line impl block is split into one file per the section comments the file already had (monitors, windows, focus, winops, hittest, dragresize, workspaces, layout). Three methods called across section boundaries (monitor_for, windows_on_workspace, cycle_focus) went from private to pub(super) - Rust's privacy model doesn't let sibling submodules see each other's private items, only a defining module's own descendants. The ~1000-line test module moves to manager/tests.rs unsplit: its helpers (wm_with_monitor, two_monitors, monitor_with_dock) are shared across tests for every section, so splitting further would mean duplicating them or adding another shared-support file for little benefit.
Diffstat (limited to 'crates/core/src/manager/hittest.rs')
-rw-r--r--crates/core/src/manager/hittest.rs51
1 files changed, 51 insertions, 0 deletions
diff --git a/crates/core/src/manager/hittest.rs b/crates/core/src/manager/hittest.rs
new file mode 100644
index 0000000..918acb5
--- /dev/null
+++ b/crates/core/src/manager/hittest.rs
@@ -0,0 +1,51 @@
+//! Pointer hit-testing against a window's titlebar/border/content.
+//! Split out of the original single `manager.rs` - see `super` (`mod.rs`) for
+//! `WindowManager`'s field definitions; everything here is plain `impl WindowManager`
+//! methods, unchanged from before the split.
+
+use super::*;
+
+impl WindowManager {
+ // ---- Hit testing ------------------------------------------------------
+
+ /// Topmost window whose frame contains `(x, y)`, along with what part of
+ /// its titlebar/border was hit (button, drag area, resize edge).
+ pub fn hit_test(&self, x: i32, y: i32) -> Option<(WindowId, TitlebarHit)> {
+ for w in self.order.iter().rev().filter_map(|id| self.windows.get(id)) {
+ if w.minimized {
+ continue;
+ }
+ if let Some(hit) = ResizeEdge::hit_test(w.geometry, x, y, w.decorated, w.border_width, self.resize_margin) {
+ return Some((w.id, hit));
+ }
+ }
+ None
+ }
+
+ /// Topmost non-minimised window containing a point, ignoring
+ /// decorations. Used for modifier+drag, where the grab applies anywhere
+ /// in the window rather than only on the titlebar (`hit_test`).
+ pub fn window_at(&self, x: i32, y: i32) -> Option<WindowId> {
+ self.order
+ .iter()
+ .rev()
+ .filter_map(|id| self.windows.get(id))
+ .find(|w| !w.minimized && w.geometry.contains_point(x, y))
+ .map(|w| w.id)
+ }
+
+ /// The corner of `id` nearest a point, for modifier+right-drag resize:
+ /// grabbing the closest corner is what makes the gesture feel like it
+ /// pulls the edge you aimed at (matching Hyprland's `resizewindow`).
+ pub fn nearest_corner(&self, id: WindowId, x: i32, y: i32) -> ResizeEdge {
+ let Some(w) = self.windows.get(&id) else { return ResizeEdge::BottomRight };
+ let (cx, cy) = w.geometry.center();
+ match (x < cx, y < cy) {
+ (true, true) => ResizeEdge::TopLeft,
+ (false, true) => ResizeEdge::TopRight,
+ (true, false) => ResizeEdge::BottomLeft,
+ (false, false) => ResizeEdge::BottomRight,
+ }
+ }
+
+}