atagen

monolith

public
Star0
Watch0
8e6f96f0a32d329d75ee602576de162d212a6169
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/monolith/src/input.rsRust209 lines6.1 KB
1
//! Input handling shared by every backend. Backends translate their events
2
//! into these calls, with pointer positions in global logical coordinates.
3
4
use crate::state::State;
5
use monolith_config::Modifier;
6
use monolith_layout::{Rect, WindowId};
7
use smithay::backend::input::{ButtonState, InputTime, KeyState};
8
use smithay::backend::session::Session;
9
use smithay::input::keyboard::{FilterResult, Keycode, xkb};
10
use smithay::input::pointer::{AxisFrame, ButtonEvent, MotionEvent};
11
use smithay::utils::{Logical, Point, SERIAL_COUNTER};
12
13
impl State {
14
    pub fn pointer_to(&mut self, pos: Point<f64, Logical>, time: InputTime) {
15
        self.pointer_pos = pos;
16
        if drag_to(self, pos) {
17
            return;
18
        }
19
        let Some(pointer) = self.seat.get_pointer() else {
20
            return;
21
        };
22
        let under = self.surface_under(pos);
23
        pointer.motion(
24
            self,
25
            under,
26
            &MotionEvent {
27
                location: pos,
28
                serial: SERIAL_COUNTER.next_serial(),
29
                time,
30
            },
31
        );
32
    }
33
34
    pub fn pointer_button(&mut self, button: u32, pressed: ButtonState, time: InputTime) {
35
        if pressed == ButtonState::Released && self.drag.take().is_some() {
36
            return;
37
        }
38
        if pressed == ButtonState::Pressed {
39
            focus_under_pointer(self);
40
            if start_drag(self, button) {
41
                return;
42
            }
43
        }
44
        let Some(pointer) = self.seat.get_pointer() else {
45
            return;
46
        };
47
        pointer.button(
48
            self,
49
            &ButtonEvent {
50
                button,
51
                state: pressed,
52
                serial: SERIAL_COUNTER.next_serial(),
53
                time,
54
            },
55
        );
56
    }
57
58
    pub fn pointer_axis(&mut self, frame: AxisFrame) {
59
        if let Some(pointer) = self.seat.get_pointer() {
60
            pointer.axis(self, frame);
61
        }
62
    }
63
64
    pub fn pointer_frame(&mut self) {
65
        if let Some(pointer) = self.seat.get_pointer() {
66
            pointer.frame(self);
67
        }
68
    }
69
70
    pub fn key(&mut self, code: Keycode, pressed: KeyState, time: InputTime) {
71
        let Some(keyboard) = self.seat.get_keyboard() else {
72
            return;
73
        };
74
        let action = keyboard.input(
75
            self,
76
            code,
77
            pressed,
78
            SERIAL_COUNTER.next_serial(),
79
            time,
80
            |state, mods, handle| {
81
                if pressed == KeyState::Released {
82
                    let before = state.suppressed.len();
83
                    state.suppressed.retain(|k| *k != code);
84
                    return if state.suppressed.len() < before {
85
                        FilterResult::Intercept(None)
86
                    } else {
87
                        FilterResult::Forward
88
                    };
89
                }
90
                let sym = handle.modified_sym().raw();
91
                if (xkb::keysyms::KEY_XF86Switch_VT_1..=xkb::keysyms::KEY_XF86Switch_VT_12)
92
                    .contains(&sym)
93
                {
94
                    state.suppressed.push(code);
95
                    let vt = (sym - xkb::keysyms::KEY_XF86Switch_VT_1 + 1) as i32;
96
                    return FilterResult::Intercept(Some(Action::Vt(vt)));
97
                }
98
                match state.binds.find(mods, &handle.raw_syms()) {
99
                    Some(cmd) => {
100
                        tracing::debug!(?cmd, "bind");
101
                        state.suppressed.push(code);
102
                        FilterResult::Intercept(Some(Action::Run(cmd)))
103
                    }
104
                    None => FilterResult::Forward,
105
                }
106
            },
107
        );
108
        match action {
109
            Some(Some(Action::Run(cmd))) => {
110
                if let Err(e) = self.run(cmd) {
111
                    tracing::warn!("bind failed: {e}");
112
                }
113
            }
114
            Some(Some(Action::Vt(vt))) => {
115
                if let Some(drm) = self.drm.as_mut()
116
                    && let Err(e) = drm.session.change_vt(vt)
117
                {
118
                    tracing::warn!("switching to VT {vt} failed: {e}");
119
                }
120
            }
121
            _ => {}
122
        }
123
    }
124
}
125
126
enum Action {
127
    Run(monolith_ipc::Command),
128
    Vt(i32),
129
}
130
131
fn focus_under_pointer(state: &mut State) {
132
    let pos = state.pointer_pos;
133
    let id = state
134
        .space
135
        .element_under(pos)
136
        .and_then(|(w, _)| w.toplevel())
137
        .and_then(|t| state.window_id(t.wl_surface()));
138
    if let Some(id) = id
139
        && state.layout.focused() != Some(id)
140
    {
141
        state.layout.focus(id);
142
        state.apply_layout();
143
    }
144
}
145
146
const BTN_LEFT: u32 = 0x110;
147
const BTN_RIGHT: u32 = 0x111;
148
149
/// A floating window being moved or resized with Mod and a mouse button.
150
pub struct Drag {
151
    window: WindowId,
152
    from: Point<f64, Logical>,
153
    rect: Rect,
154
    resize: bool,
155
}
156
157
fn start_drag(state: &mut State, button: u32) -> bool {
158
    if button != BTN_LEFT && button != BTN_RIGHT {
159
        return false;
160
    }
161
    let held = state
162
        .seat
163
        .get_keyboard()
164
        .map(|k| k.modifier_state())
165
        .is_some_and(|m| match state.config.general.mod_key {
166
            Modifier::Super => m.logo,
167
            Modifier::Alt => m.alt,
168
            Modifier::Ctrl => m.ctrl,
169
            Modifier::Shift => m.shift,
170
        });
171
    let Some(id) = state.layout.focused() else {
172
        return false;
173
    };
174
    let Some(rect) = state
175
        .layout
176
        .window(id)
177
        .filter(|w| w.floating && !w.fullscreen)
178
        .and_then(|w| w.float_rect)
179
    else {
180
        return false;
181
    };
182
    if !held {
183
        return false;
184
    }
185
    state.drag = Some(Drag {
186
        window: id,
187
        from: state.pointer_pos,
188
        rect,
189
        resize: button == BTN_RIGHT,
190
    });
191
    true
192
}
193
194
fn drag_to(state: &mut State, pos: Point<f64, Logical>) -> bool {
195
    let Some(d) = &state.drag else {
196
        return false;
197
    };
198
    let (dx, dy) = (pos.x - d.from.x, pos.y - d.from.y);
199
    let r = d.rect;
200
    let rect = if d.resize {
201
        Rect::new(r.x, r.y, (r.w + dx).max(32.0), (r.h + dy).max(32.0))
202
    } else {
203
        Rect::new(r.x + dx, r.y + dy, r.w, r.h)
204
    };
205
    let id = d.window;
206
    state.layout.set_float_rect(id, rect);
207
    state.apply_layout();
208
    true
209
}