leftwm_core/handlers/
display_event_handler.rs

1use super::{Config, DisplayEvent, Manager, Mode};
2use crate::display_action::DisplayAction;
3use crate::display_servers::DisplayServer;
4use crate::models::{Handle, WindowHandle, WindowState};
5use crate::State;
6
7impl<H: Handle, C: Config, SERVER: DisplayServer<H>> Manager<H, C, SERVER> {
8    /// Process a collection of events, and apply changes to a manager.
9    /// Returns true if changes need to be rendered.
10    pub fn display_event_handler(&mut self, event: DisplayEvent<H>) -> bool {
11        let state = &mut self.state;
12        match event {
13            DisplayEvent::ScreenCreate(s) => self.screen_create_handler(s),
14            DisplayEvent::WindowCreate(w, x, y) => self.window_created_handler(w, x, y),
15            DisplayEvent::WindowChange(w) => self.window_changed_handler(w),
16            DisplayEvent::WindowDestroy(handle) => self.window_destroyed_handler(&handle),
17            DisplayEvent::SendCommand(command) => self.command_handler(&command),
18            DisplayEvent::MouseCombo(mod_mask, button, handle, x, y) => self
19                .state
20                .mouse_combo_handler(&mod_mask, button, handle, x, y),
21
22            DisplayEvent::WindowTakeFocus(handle) => from_window_take_focus(state, handle),
23            DisplayEvent::HandleWindowFocus(handle) => from_handle_window_focus(state, handle),
24            DisplayEvent::MoveFocusTo(x, y) => from_move_focus_to(state, x, y),
25            DisplayEvent::VerifyFocusedAt(handle) => from_verify_focus_at(state, handle),
26            DisplayEvent::ChangeToNormalMode => from_change_to_normal_mode(state),
27            DisplayEvent::Movement(handle, x, y) => from_movement(state, handle, x, y),
28            DisplayEvent::MoveWindow(handle, x, y) => from_move_window(self, handle, x, y),
29            DisplayEvent::ResizeWindow(handle, x, y) => from_resize_window(self, handle, x, y),
30            DisplayEvent::ConfigureXlibWindow(handle) => from_configure_xlib_window(state, handle),
31        }
32    }
33}
34
35fn from_window_take_focus<H: Handle>(state: &mut State<H>, handle: WindowHandle<H>) -> bool {
36    state.focus_window(&handle);
37    false
38}
39
40fn from_handle_window_focus<H: Handle>(state: &mut State<H>, handle: WindowHandle<H>) -> bool {
41    state.handle_window_focus(&handle);
42    false
43}
44
45fn from_move_focus_to<H: Handle>(state: &mut State<H>, x: i32, y: i32) -> bool {
46    state.focus_window_with_point(x, y);
47    false
48}
49
50fn from_verify_focus_at<H: Handle>(state: &mut State<H>, handle: WindowHandle<H>) -> bool {
51    if state.focus_manager.behaviour.is_sloppy() {
52        state.validate_focus_at(&handle);
53    }
54    false
55}
56
57fn from_change_to_normal_mode<H: Handle>(state: &mut State<H>) -> bool {
58    match state.mode {
59        Mode::MovingWindow(h) | Mode::ResizingWindow(h) => {
60            // We want to update the windows tag once it is done moving. This means
61            // when the window is re-tiled it is on the correct workspace. This also
62            // prevents the focus switching between the floating window and the
63            // workspace behind. We will also apply the margin_multiplier here so that
64            // it is only called once the window has stopped moving.
65            if let Some(window) = state.windows.iter_mut().find(|w| w.handle == h) {
66                let loc = window.calculated_xyhw();
67                let (center_x, center_y) = loc.center();
68                let (margin_multiplier, tag, normal) = if let Some(ws) = state
69                    .workspaces
70                    .iter()
71                    .find(|ws| ws.contains_point(center_x, center_y))
72                {
73                    (ws.margin_multiplier(), ws.tag, ws.xyhw)
74                } else if let Some(ws) = state.workspaces.iter().find(|ws| {
75                    let dx =
76                        ws.xyhw.x() <= loc.x() + loc.w() && ws.xyhw.x() + ws.xyhw.w() >= loc.x();
77                    let dy =
78                        ws.xyhw.y() <= loc.y() + loc.h() && ws.xyhw.y() + ws.xyhw.h() >= loc.y();
79                    dx && dy
80                }) {
81                    (ws.margin_multiplier(), ws.tag, ws.xyhw)
82                } else {
83                    tracing::debug!("No matching workspace found for {:?}", window.handle);
84                    (1.0, Some(1), window.normal)
85                };
86                let mut offset = window.get_floating_offsets().unwrap_or_default();
87                // Re-adjust the floating offsets to the new workspace.
88                let exact = window.normal + offset;
89                offset = exact - normal;
90                window.set_floating_offsets(Some(offset));
91                window.tag = tag;
92                window.apply_margin_multiplier(margin_multiplier);
93                let act = DisplayAction::SetWindowTag(window.handle, tag);
94                state.actions.push_back(act);
95            }
96            state.focus_window(&h);
97        }
98        _ => {}
99    }
100    state.mode = Mode::Normal;
101    true
102}
103
104fn from_movement<H: Handle>(state: &mut State<H>, handle: WindowHandle<H>, x: i32, y: i32) -> bool {
105    if state.screens.iter().any(|s| s.root == handle) {
106        state.focus_workspace_with_point(x, y);
107    }
108    false
109}
110
111// private helper function wrapping `window_move_handler`
112// TODO: maybe move to window_move_handler.rs
113fn from_move_window<H: Handle, C: Config, SERVER: DisplayServer<H>>(
114    manager: &mut Manager<H, C, SERVER>,
115    handle: WindowHandle<H>,
116    x: i32,
117    y: i32,
118) -> bool {
119    // Setup for when window first moves.
120    if let Mode::ReadyToMove(h) = manager.state.mode {
121        manager.state.mode = Mode::MovingWindow(h);
122        prepare_window(&mut manager.state, h);
123    }
124    manager.window_move_handler(&handle, x, y)
125}
126
127// private helper function wrapping `window_resize_handler`
128// TODO: maybe move to window_resize_handler.rs
129fn from_resize_window<H: Handle, C: Config, SERVER: DisplayServer<H>>(
130    manager: &mut Manager<H, C, SERVER>,
131    handle: WindowHandle<H>,
132    x: i32,
133    y: i32,
134) -> bool {
135    // Setup for when window first resizes.
136    if let Mode::ReadyToResize(h) = manager.state.mode {
137        manager.state.mode = Mode::ResizingWindow(h);
138        prepare_window(&mut manager.state, h);
139    }
140    manager.window_resize_handler(&handle, x, y)
141}
142
143// called when manager receives `DisplayAction::ConfigureXlibWindow(handle)`
144// then sends back a copy of the event if the state already knows about it.
145fn from_configure_xlib_window<H: Handle>(state: &mut State<H>, handle: WindowHandle<H>) -> bool {
146    if let Some(window) = state.windows.iter().find(|w| w.handle == handle) {
147        let act = DisplayAction::ConfigureXlibWindow(window.clone());
148        state.actions.push_back(act);
149    }
150    false
151}
152
153// Save off the info about position of the window when we start to move/resize.
154fn prepare_window<H: Handle>(state: &mut State<H>, handle: WindowHandle<H>) {
155    if let Some(w) = state.windows.iter_mut().find(|w| w.handle == handle) {
156        // Un-pin window if maximized or in fullscreen
157        if w.is_fullscreen() {
158            w.reset_float_offset();
159            state.actions.push_back(DisplayAction::SetState(
160                handle,
161                false,
162                WindowState::Fullscreen,
163            ));
164            w.states.retain(|s| s != &WindowState::Fullscreen);
165            // Force update for all windows
166            state.mode = Mode::ReadyToResize(handle);
167        }
168        if w.is_maximized() {
169            w.reset_float_offset();
170            state.actions.push_back(DisplayAction::SetState(
171                handle,
172                false,
173                WindowState::Maximized,
174            ));
175            w.states.retain(|s| s != &WindowState::Maximized);
176            w.states.retain(|s| s != &WindowState::MaximizedHorz);
177            w.states.retain(|s| s != &WindowState::MaximizedVert);
178            // Force update for all windows
179            state.mode = Mode::ReadyToResize(handle);
180        }
181        if w.floating() {
182            let offset = w.get_floating_offsets().unwrap_or_default();
183            w.start_loc = Some(offset);
184        } else {
185            let container = w.container_size.unwrap_or_default();
186            let normal = w.normal;
187            let floating = normal - container;
188            w.set_floating_offsets(Some(floating));
189            w.start_loc = Some(floating);
190            w.set_floating(true);
191            // Force update for all windows
192            state.mode = Mode::ReadyToResize(handle);
193        }
194    }
195    state.move_to_top(&handle);
196}