leftwm_core/handlers/
window_move_handler.rs

1use super::{Manager, Window, WindowHandle, Workspace};
2use crate::config::Config;
3use crate::display_servers::DisplayServer;
4use crate::models::{Handle, Xyhw};
5
6impl<H: Handle, C: Config, SERVER: DisplayServer<H>> Manager<H, C, SERVER> {
7    /// `window_move_handler` is called when the display server
8    /// sends the `DisplayEvent::MoveWindow(handle, offset_x, offset_y)` event.
9    ///
10    /// Returns true if changes need to be rendered.
11    pub fn window_move_handler(
12        &mut self,
13        handle: &WindowHandle<H>,
14        offset_x: i32,
15        offset_y: i32,
16    ) -> bool {
17        let disable_snap = &self.config.disable_window_snap();
18        match self.state.windows.iter_mut().find(|w| w.handle == *handle) {
19            Some(w) => {
20                process_window(w, offset_x, offset_y);
21                if !disable_snap && snap_to_workspace(w, &self.state.workspaces) {
22                    self.state.sort_windows();
23                }
24                true
25            }
26            None => false,
27        }
28    }
29}
30
31// private helper function
32fn process_window<H: Handle>(window: &mut Window<H>, offset_x: i32, offset_y: i32) {
33    let mut offset = window.get_floating_offsets().unwrap_or_default();
34    let start = window.start_loc.unwrap_or_default();
35    offset.set_x(start.x() + offset_x);
36    offset.set_y(start.y() + offset_y);
37    window.set_floating_offsets(Some(offset));
38}
39
40// Update the window for the workspace it is currently on.
41fn snap_to_workspace<H: Handle>(window: &mut Window<H>, workspaces: &[Workspace]) -> bool {
42    // Check that the workspace contains the window.
43    let loc = window.calculated_xyhw();
44    let (x, y) = loc.center();
45
46    if let Some(workspace) = workspaces.iter().find(|ws| ws.contains_point(x, y)) {
47        return should_snap(window, workspace, loc);
48    }
49    false
50}
51
52// To be snapable, the window must be inside the workspace AND the a side must be close to
53// the workspaces edge.
54fn should_snap<H: Handle>(window: &mut Window<H>, workspace: &Workspace, loc: Xyhw) -> bool {
55    if window.must_float() {
56        return false;
57    }
58    // Get window sides.
59    let win_left = loc.x();
60    let win_right = win_left + window.width();
61    let win_top = loc.y();
62    let win_bottom = win_top + window.height();
63    // Check for close edge.
64    let dist = 10;
65    let ws_left = workspace.x();
66    let ws_right = workspace.x() + workspace.width();
67    let ws_top = workspace.y();
68    let ws_bottom = workspace.y() + workspace.height();
69    if [
70        win_top - ws_top,
71        win_bottom - ws_bottom,
72        win_left - ws_left,
73        win_right - ws_right,
74    ]
75    .iter()
76    .any(|x| x.abs() < dist)
77    {
78        return window.snap_to_workspace(workspace);
79    }
80    false
81}