Skip to main content

leftwm_core/handlers/
mouse_combo_handler.rs

1use crate::display_action::DisplayAction;
2use crate::models::Handle;
3use crate::models::Mode;
4use crate::models::ResizeCorner;
5use crate::models::WindowHandle;
6use crate::state::State;
7use crate::utils;
8use crate::utils::modmask_lookup::Button;
9use crate::utils::modmask_lookup::ModMask;
10
11impl<H: Handle> State<H> {
12    /// `mouse_combo_handler` is called when the display server sends
13    /// `DisplayEvent::MouseCombo(modmask, button, handle, x, y)`
14    ///
15    /// Returns `true` if changes need to be rendered.
16    pub fn mouse_combo_handler(
17        &mut self,
18        modmask: &ModMask,
19        button: Button,
20        handle: WindowHandle<H>,
21        x: i32,
22        y: i32,
23    ) -> bool {
24        if let Some(window) = self.windows.iter().find(|w| w.handle == handle) {
25            if !self.disable_tile_drag || window.floating() {
26                let modifier = utils::modmask_lookup::into_modmask(&self.mousekey);
27                // A resize is anchored to the corner the pointer is closest
28                // to, so grabbing near the top left edge grows the window up
29                // and to the left instead of always dragging the bottom right
30                // corner around.
31                let corner = ResizeCorner::nearest(
32                    x,
33                    y,
34                    window.x(),
35                    window.y(),
36                    window.width(),
37                    window.height(),
38                );
39                let anchor = corner.point(window.x(), window.y(), window.width(), window.height());
40                // Build the display to say whether we are ready to move/resize.
41                let act = self.build_action(modmask, button, handle, modifier);
42                if let Some(act) = act {
43                    if let DisplayAction::ReadyToResizeWindow(_) = act {
44                        self.resize_corner = corner;
45                        if self.reposition_cursor_on_resize {
46                            let move_act = DisplayAction::MoveMouseOverPoint(anchor);
47                            self.actions.push_back(move_act);
48                        }
49                    }
50                    self.actions.push_back(act);
51                    return false;
52                }
53            }
54        } else if self.focus_manager.behaviour.is_clickto()
55            && (button == Button::Main || button == Button::Secondary)
56            && self.screens.iter().any(|s| s.root == handle)
57        {
58            self.focus_workspace_with_point(x, y);
59            return false;
60        }
61        true
62    }
63
64    // private helper function
65    fn build_action(
66        &mut self,
67        mod_mask: &ModMask,
68        button: Button,
69        window: WindowHandle<H>,
70        modifier: ModMask,
71    ) -> Option<DisplayAction<H>> {
72        let is_mouse_key = *mod_mask == modifier || *mod_mask == (modifier | ModMask::Shift);
73        match button {
74            Button::Main if is_mouse_key => {
75                _ = self
76                    .windows
77                    .iter()
78                    .find(|w| w.handle == window && w.can_move())?;
79                self.mode = Mode::ReadyToMove(window);
80                Some(DisplayAction::ReadyToMoveWindow(window))
81            }
82            Button::Secondary if is_mouse_key => {
83                _ = self
84                    .windows
85                    .iter()
86                    .find(|w| w.handle == window && w.can_resize())?;
87                self.mode = Mode::ReadyToResize(window);
88                Some(DisplayAction::ReadyToResizeWindow(window))
89            }
90            Button::Main | Button::Secondary if self.focus_manager.behaviour.is_clickto() => {
91                self.focus_window(&window);
92                Some(DisplayAction::ReplayClick(window, button))
93            }
94            _ => None,
95        }
96    }
97}