diff options
| author | srdusr <[email protected]> | 2024-05-14 00:42:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2024-05-14 00:42:00 +0200 |
| commit | dd31bf5ac2a692617d478478d36c733586b93cf8 (patch) | |
| tree | 2adb42ad8b24172cbbea3bf362a0d284acd54439 /crates/wayland/src/udev.rs | |
| parent | a9dd8a6d4947cb537f7919c5a66ba4624af61800 (diff) | |
| download | srdwm-dd31bf5ac2a692617d478478d36c733586b93cf8.tar.gz srdwm-dd31bf5ac2a692617d478478d36c733586b93cf8.zip | |
Draw a cursor, handle the lid, and everything a real config needs
Groundwork for actually daily-driving this: porting the user's Hyprland
config exposed what srdwm couldn't yet express, and testing on a bare TTY
exposed something worse.
A visible mouse cursor. Nothing drew a pointer at all - on a bare TTY the
mouse was simply invisible. It hid because the nested backend runs inside
another compositor, which draws a cursor over srdwm's window; only the DRM
backend, i.e. the actual session path, was affected. A built-in arrow is now
composited above everything on the output the pointer is on. It's a
reviewable ASCII bitmap rather than an XCursor theme: a cursor that is always
present beats a prettier one that sometimes isn't, the same reasoning as
decoration.rs's font fallback. Client-set cursor surfaces and named shapes
are still not rendered, so an app asking for an I-beam gets the arrow.
Lid switch. libinput switch events are handled and surfaced to config as
srd.on("lid_closed"/"lid_open", fn), so closing the lid can lock and suspend
instead of doing nothing.
Config-driven additions, each needed by a binding in the ported config and
none of which existed: fullscreen (Window.fullscreen was a dead field --
declared, never read or written), directional window move that swaps with
the neighbour and reorders the stack so tiling follows, focus cycling,
modifier+drag to move/resize anywhere in a window rather than only by the
titlebar, modifier+scroll to change workspace, and 8 XF86 media/power
keysyms taken from the system's own XF86keysym.h. The keysym tables are
hand-maintained in both directions and a key missing from either fails
silently, so a round-trip test now covers every one the configs bind.
Verified in the QEMU VM: a bare-TTY screendump shows a recognisable arrow at
the pointer position (113 white fill + 58 black outline pixels at screen
centre, where the pointer starts).
Diffstat (limited to 'crates/wayland/src/udev.rs')
| -rw-r--r-- | crates/wayland/src/udev.rs | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/crates/wayland/src/udev.rs b/crates/wayland/src/udev.rs index aca4865..30517f8 100644 --- a/crates/wayland/src/udev.rs +++ b/crates/wayland/src/udev.rs @@ -159,6 +159,9 @@ impl CompState { // Drained before the `&mut self.udev` borrow below, so screencopy can // be serviced with the renderer that borrow owns. let mut captures = std::mem::take(&mut self.screencopy_pending); + // Same reason: the cursor needs the renderer that borrow owns. + let cursor_status = self.cursor_status.clone(); + let cursor_buffer = self.cursor_buffer.clone(); // Which heads are eligible, and what each needs, gathered before the // mutable borrow of `self.udev`. @@ -196,6 +199,19 @@ impl CompState { let mut custom_elements: Vec<MemoryRenderBufferRenderElement<PixmanRenderer>> = Vec::new(); if !locked { + // Cursor first: `render_output` draws custom elements + // front-to-back, so the earliest element is topmost. On a + // bare TTY nothing else draws a pointer - see `cursor.rs`. + let pointer_pos = udev.pointer_pos; + let hsize = udev.heads[index].size; + custom_elements.extend(crate::cursor::render_elements( + &cursor_status, + &cursor_buffer, + &mut udev.renderer, + pointer_pos, + origin, + hsize, + )); for (geom, deco) in &decorations { let pos = ((geom.x - origin.x) as f64, (geom.y - origin.y) as f64); match MemoryRenderBufferRenderElement::from_buffer(&mut udev.renderer, pos, deco, None, None, None, Kind::Unspecified) { @@ -538,6 +554,8 @@ impl UdevPlatform { _screencopy_state: crate::screencopy::ScreencopyState::new::<CompState>(&display_handle), screencopy_pending: Vec::new(), lock: Default::default(), + cursor_status: smithay::input::pointer::CursorImageStatus::default_named(), + cursor_buffer: crate::cursor::make_buffer(), wm: wm.clone(), surface_to_id: HashMap::new(), id_to_window: HashMap::new(), @@ -832,10 +850,30 @@ fn handle_libinput_event(state: &mut CompState, event: InputEvent<LibinputInputB let pressed = event.state() == BackendButtonState::Pressed; handle_pointer_button(state, pos, button, pressed, event.time_msec()); } + // Laptop lid. libinput reports this as a switch toggle; without + // handling it, closing the lid does nothing at all - no lock, no + // suspend - which is a genuine problem on a laptop rather than a + // missing nicety. + InputEvent::SwitchToggle { event } => { + // Fully qualified: libinput's own `Switch` is also in scope here. + use smithay::backend::input::{SwitchState, SwitchToggleEvent}; + if matches!(event.switch(), Some(smithay::reexports::input::event::switch::Switch::Lid)) { + let closed = event.state() == SwitchState::On; + log::info!("lid {}", if closed { "closed" } else { "opened" }); + state.pending.borrow_mut().push(CoreEvent::LidSwitch { closed }); + } + } InputEvent::PointerAxis { event } => { - // Scroll: forwarded to the focused client via the pointer axis - // frame, no WM-level handling (matches the winit backend, which - // doesn't handle scroll either). + // Modifier+scroll switches workspace instead of reaching the + // client - the `bind = SUPER, mouse_down/up, workspace, e+1/e-1` + // gesture. Checked first so the client never sees these events; + // forwarding them too would scroll the window under the cursor + // as a side effect of changing workspace. + if crate::input::handle_workspace_scroll(state, &event) { + return; + } + // Otherwise: forwarded to the focused client via the pointer axis + // frame, no WM-level handling. let Some(pointer) = state.seat.get_pointer() else { return }; let source = event.source(); let mut frame = AxisFrame::new(event.time_msec()).source(source); |