diff options
Diffstat (limited to 'crates/wayland/src/input.rs')
| -rw-r--r-- | crates/wayland/src/input.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/crates/wayland/src/input.rs b/crates/wayland/src/input.rs index 76607ee..6959c8f 100644 --- a/crates/wayland/src/input.rs +++ b/crates/wayland/src/input.rs @@ -20,6 +20,11 @@ use smithay::wayland::shell::wlr_layer::{KeyboardInteractivity, Layer}; use srdwm_core::{Event as CoreEvent, Modifiers, TitlebarHit, WindowId}; +/// Modifier that turns a drag anywhere in a window into move/resize. +/// Matches the `SUPER` the shipped and ported configs use for +/// `bindm ... movewindow` / `resizewindow`. +const DRAG_MODIFIER: Modifiers = Modifiers::SUPER; + use crate::state::CompState; pub(crate) fn last_pointer_pos(state: &CompState) -> Point<f64, Logical> { @@ -134,6 +139,7 @@ pub(crate) fn focus_window(state: &mut CompState, id: WindowId) { pub(crate) fn handle_pointer_button(state: &mut CompState, pos: Point<f64, Logical>, button: u32, pressed: bool, time: u32) { const BTN_LEFT: u32 = 0x110; + const BTN_RIGHT: u32 = 0x111; let serial = SERIAL_COUNTER.next_serial(); // Locked: forward the click to the lock surface (it may have a button or @@ -146,6 +152,33 @@ pub(crate) fn handle_pointer_button(state: &mut CompState, pos: Point<f64, Logic return; } + // Modifier+drag: with the modifier held, dragging *anywhere* in a window + // moves it (left button) or resizes it from the nearest corner (right + // button) - the `bindm SUPER, mouse:272/273` gesture. Without this a + // window can only be moved by its titlebar, which is useless for + // windows that have none (fullscreen, CSD apps, layer surfaces). + // + // Checked before the titlebar hit-test so the modifier wins over the + // decoration: holding the modifier and grabbing the titlebar should + // still move, not press a titlebar button. + if pressed && (button == BTN_LEFT || button == BTN_RIGHT) { + let mods = state.seat.get_keyboard().map(|k| core_modifiers_from_xkb(&k.modifier_state())); + if mods.is_some_and(|m| m.contains(DRAG_MODIFIER)) { + let target = state.wm.borrow().window_at(pos.x as i32, pos.y as i32); + if let Some(id) = target { + focus_window(state, id); + let mut wm = state.wm.borrow_mut(); + if button == BTN_LEFT { + wm.start_drag(id, pos.x as i32, pos.y as i32); + } else { + let edge = wm.nearest_corner(id, pos.x as i32, pos.y as i32); + wm.start_resize(id, edge, pos.x as i32, pos.y as i32); + } + return; + } + } + } + if pressed && button == BTN_LEFT { let layer_hit = layer_surface_under(state, pos); if let Some((surface, _)) = &layer_hit { @@ -275,3 +308,37 @@ pub(crate) fn core_modifiers_from_xkb(mods: &smithay::input::keyboard::Modifiers } m } + +/// Modifier+scroll cycles workspaces, consuming the event. +/// +/// Returns `true` if it handled the scroll, in which case the caller must +/// *not* also forward it to the client. Generic over the input backend for +/// the same reason the keyboard handler is: both backends deliver scroll +/// through smithay's `PointerAxisEvent` trait. +pub(crate) fn handle_workspace_scroll<B, E>(state: &mut CompState, event: &E) -> bool +where + B: smithay::backend::input::InputBackend, + E: smithay::backend::input::PointerAxisEvent<B>, +{ + use smithay::backend::input::Axis; + + if state.lock.locked { + return false; + } + let mods = state.seat.get_keyboard().map(|k| core_modifiers_from_xkb(&k.modifier_state())); + if !mods.is_some_and(|m| m.contains(DRAG_MODIFIER)) { + return false; + } + let Some(v) = event.amount(Axis::Vertical).filter(|v| *v != 0.0) else { return false }; + + let mut wm = state.wm.borrow_mut(); + let ids: Vec<_> = wm.workspaces().iter().map(|w| w.id).collect(); + if ids.is_empty() { + return false; + } + let current = ids.iter().position(|&id| id == wm.current_workspace()).unwrap_or(0); + // Scrolling down (positive) advances, matching `workspace, e+1`. + let next = if v > 0.0 { (current + 1) % ids.len() } else { (current + ids.len() - 1) % ids.len() }; + wm.switch_workspace(ids[next]); + true +} |