diff options
| author | srdusr <[email protected]> | 2024-05-29 14:40:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2024-05-29 14:40:00 +0200 |
| commit | 3d3057ae384ef7389284af8988410889e99c6bb9 (patch) | |
| tree | 57b05e9660afd8ed51b26e5db1ab541a811ccc16 /crates/wayland/src/cursor.rs | |
| parent | dd31bf5ac2a692617d478478d36c733586b93cf8 (diff) | |
| download | srdwm-3d3057ae384ef7389284af8988410889e99c6bb9.tar.gz srdwm-3d3057ae384ef7389284af8988410889e99c6bb9.zip | |
Config at ~/.config/srd; cursor shapes, key repeat, pin, mouse defaults
Config path drops a level: ~/.config/srd, not ~/.config/srdwm/srd, which
said the same thing twice. No other user-facing path had the same problem --
srdwm reads the config dir and writes nothing else.
Cursor shapes. A client's own cursor surface is now rendered with the
hotspot it declared, so an I-beam over text or a hand over a link shows the
app's image instead of srdwm's arrow. The built-in arrow stays as the
fallback when no client has set one, over decorations and the desktop.
Named shapes still fall back to the arrow; most toolkits set a surface.
Decorations and cursors now share one OverlayElement type, since
render_output takes a single custom-element slice.
Key repeat (srd.bind_repeat, Hyprland's binde). Held volume, brightness and
switcher keys repeat at the seat's own rate rather than firing once. Driven
from the poll loop, not a timer source: the winit backend has no calloop
loop of its own, and poll_events already runs continuously in both backends.
Repeat stops when *that* key is released, not when any key is.
Always-on-top / pin, for the picture-in-picture and HUD rules that used it.
Window::always_on_top was another declared-but-never-read field. Enforced in
WindowManager's stacking order rather than at render time, so every consumer
of stacking_order gets it and none can forget to honour it.
Mouse-only window management, checked end to end: drag the titlebar to move,
drag any edge or corner to resize, titlebar buttons to close/maximise/
minimise, click to focus, drag to a screen edge to snap, and now
double-click the titlebar to maximise. The resize grab band went from 6px to
10px - a hairline is genuinely hard to hit with a mouse, which is why
Hyprland ships extend_border_grab_area.
Also removed the emoji status markers from docs/IMPLEMENTATION_STATUS.md.
Diffstat (limited to 'crates/wayland/src/cursor.rs')
| -rw-r--r-- | crates/wayland/src/cursor.rs | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/crates/wayland/src/cursor.rs b/crates/wayland/src/cursor.rs index 121e8e1..b489c03 100644 --- a/crates/wayland/src/cursor.rs +++ b/crates/wayland/src/cursor.rs @@ -7,13 +7,19 @@ //! can move it, click with it, and drag windows with it, but you cannot see //! where it is. That makes the udev backend unusable as a real session. //! -//! **Scope, stated plainly:** this draws one built-in arrow, always. It -//! honours `CursorImageStatus::Hidden` (so a client that hides the pointer -//! still gets its way), but it does *not* yet render a client's own cursor -//! surface or a named shape - an app asking for an I-beam or a resize arrow -//! still sees this arrow. That is a real limitation, and a visible one over -//! text fields; it is also strictly better than the previous behaviour of -//! drawing nothing at all. +//! Two sources, in priority order: +//! +//! 1. **The client's own cursor surface** (`CursorImageStatus::Surface`) -- +//! a terminal's I-beam, a browser's hand, an app's resize arrows. Drawn +//! from its surface tree, offset by the hotspot the client declared. +//! 2. **A built-in arrow**, for when no client has set an image (over +//! srdwm's own decorations and the desktop) or asked for a named shape +//! we have no art for. +//! +//! `CursorImageStatus::Hidden` is honoured, so a client that hides the +//! pointer still gets its way. Named shapes (`CursorIcon::Text` etc.) fall +//! back to the arrow rather than being drawn as the requested shape - most +//! toolkits set a surface rather than a name, so this is rarely visible. //! //! The built-in arrow is deliberate rather than loading an XCursor theme: //! theme loading pulls in a dependency, needs a theme to actually be @@ -21,8 +27,11 @@ //! is always present beats a prettier one that sometimes isn't there - the //! same reasoning as `decoration.rs`'s font fallback. +use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement; use smithay::utils::{Logical, Point}; +use crate::elements::OverlayElement; + /// Side length of the built-in cursor bitmap, in pixels. pub(crate) const CURSOR_SIZE: i32 = 24; @@ -85,6 +94,10 @@ pub(crate) fn arrow_bitmap() -> Vec<u8> { } +/// One cursor render element, whatever the source. +/// +/// Client cursor surfaces and the built-in bitmap are different element +/// types, so they're unified here rather than forcing both through one. /// Render elements for the pointer, to be drawn above everything else. /// /// `pos` is in the global space and `origin` is the output's origin, since @@ -99,14 +112,17 @@ pub(crate) fn render_elements<R>( pos: Point<f64, Logical>, origin: Point<i32, Logical>, size: (i32, i32), -) -> Vec<smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement<R>> +) -> Vec<OverlayElement<R>> where - R: smithay::backend::renderer::Renderer + smithay::backend::renderer::ImportMem, + R: smithay::backend::renderer::Renderer + + smithay::backend::renderer::ImportAll + + smithay::backend::renderer::ImportMem, R::TextureId: Clone + Send + 'static, { - use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement; + use smithay::backend::renderer::element::surface::render_elements_from_surface_tree; use smithay::backend::renderer::element::Kind; - use smithay::input::pointer::CursorImageStatus; + use smithay::input::pointer::{CursorImageStatus, CursorImageSurfaceData}; + use smithay::wayland::compositor::with_states; if matches!(status, CursorImageStatus::Hidden) { return Vec::new(); @@ -117,10 +133,26 @@ where return Vec::new(); } - // Built-in arrow: hotspot is the tip, so no offset. + if let CursorImageStatus::Surface(surface) = status { + // The client picked an image. Its hotspot is the point *inside* that + // image which tracks the pointer, so the surface is drawn offset by + // it - without this the image sits down-right of where clicks land. + let hotspot = with_states(surface, |states| { + states + .data_map + .get::<CursorImageSurfaceData>() + .map(|d| d.lock().unwrap().hotspot) + .unwrap_or_default() + }); + let at = (local.0 - hotspot.x, local.1 - hotspot.y); + return render_elements_from_surface_tree(renderer, surface, at, 1.0, 1.0, Kind::Cursor); + } + + // No client image (or a named shape we don't have art for): the + // built-in arrow, whose hotspot is its tip, so no offset. let at = (local.0 as f64, local.1 as f64); match MemoryRenderBufferRenderElement::from_buffer(renderer, at, buffer, None, None, None, Kind::Cursor) { - Ok(e) => vec![e], + Ok(e) => vec![OverlayElement::Memory(e)], Err(e) => { log::warn!("cursor: failed to import bitmap: {e}"); Vec::new() @@ -128,6 +160,7 @@ where } } + /// The built-in arrow as an uploadable buffer. Built once at startup rather /// than per frame - the bitmap never changes. pub(crate) fn make_buffer() -> smithay::backend::renderer::element::memory::MemoryRenderBuffer { |