Skip to content

Commit 8cecd26

Browse files
committed
seat/pointer: simplify ThemedPointer handling
This should simplify the handling of custom cursors in the user applications by incapsulating all the necessary state in the ThemedPointer. In the future we can automatically handle the `wp_cursor_shape` under the hood.
1 parent c0eabf6 commit 8cecd26

File tree

4 files changed

+107
-52
lines changed

4 files changed

+107
-52
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## Unreleased
44

5+
#### Breaking Changes
6+
7+
- `ThemedPointer::set_cursor` now takes only `Connection` and `&str`.
8+
- `SeatState:get_pointer_with_them*` now takes `Shm` and `WlSurface` for the themed cursor.
9+
- `ThemedPointer` now automatically releases the associated `WlPointer`.
10+
511
## 0.17.0 - 2023-03-28
612

713
#### Breaking Changes

examples/themed_window.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ fn main() {
6060
.expect("Failed to create pool");
6161

6262
let window_surface = compositor_state.create_surface(&qh);
63-
let pointer_surface = compositor_state.create_surface(&qh);
6463

6564
let window =
6665
xdg_shell_state.create_window(window_surface, WindowDecorations::ServerDefault, &qh);
@@ -80,7 +79,7 @@ fn main() {
8079
registry_state,
8180
seat_state,
8281
output_state,
83-
_compositor_state: compositor_state,
82+
compositor_state,
8483
subcompositor_state: Arc::new(subcompositor_state),
8584
shm_state,
8685
_xdg_shell_state: xdg_shell_state,
@@ -94,7 +93,6 @@ fn main() {
9493
buffer: None,
9594
window,
9695
window_frame: None,
97-
pointer_surface,
9896
keyboard: None,
9997
keyboard_focus: false,
10098
themed_pointer: None,
@@ -118,7 +116,7 @@ struct SimpleWindow {
118116
registry_state: RegistryState,
119117
seat_state: SeatState,
120118
output_state: OutputState,
121-
_compositor_state: CompositorState,
119+
compositor_state: CompositorState,
122120
subcompositor_state: Arc<SubcompositorState>,
123121
shm_state: Shm,
124122
_xdg_shell_state: XdgShell,
@@ -132,7 +130,6 @@ struct SimpleWindow {
132130
buffer: Option<Buffer>,
133131
window: Window,
134132
window_frame: Option<FallbackFrame<Self>>,
135-
pointer_surface: wl_surface::WlSurface,
136133
keyboard: Option<wl_keyboard::WlKeyboard>,
137134
keyboard_focus: bool,
138135
themed_pointer: Option<ThemedPointer>,
@@ -312,9 +309,16 @@ impl SeatHandler for SimpleWindow {
312309
if capability == Capability::Pointer && self.themed_pointer.is_none() {
313310
println!("Set pointer capability");
314311
println!("Creating pointer theme");
312+
let surface = self.compositor_state.create_surface(qh);
315313
let themed_pointer = self
316314
.seat_state
317-
.get_pointer_with_theme(qh, &seat, ThemeSpec::default())
315+
.get_pointer_with_theme(
316+
qh,
317+
&seat,
318+
self.shm_state.wl_shm(),
319+
surface,
320+
ThemeSpec::default(),
321+
)
318322
.expect("Failed to create pointer");
319323
self.themed_pointer.replace(themed_pointer);
320324
}
@@ -504,13 +508,7 @@ impl ShmHandler for SimpleWindow {
504508
impl SimpleWindow {
505509
pub fn draw(&mut self, conn: &Connection, qh: &QueueHandle<Self>) {
506510
if self.set_cursor {
507-
let _ = self.themed_pointer.as_mut().unwrap().set_cursor(
508-
conn,
509-
&self.cursor_icon,
510-
self.shm_state.wl_shm(),
511-
&self.pointer_surface,
512-
1,
513-
);
511+
let _ = self.themed_pointer.as_mut().unwrap().set_cursor(conn, &self.cursor_icon);
514512
self.set_cursor = false;
515513
}
516514

src/seat/mod.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ use std::{
1515

1616
use wayland_client::{
1717
globals::GlobalList,
18-
protocol::{wl_pointer, wl_seat, wl_touch},
18+
protocol::{wl_pointer, wl_seat, wl_shm, wl_surface, wl_touch},
1919
Connection, Dispatch, Proxy, QueueHandle,
2020
};
2121

22-
use crate::registry::{ProvidesRegistryState, RegistryHandler};
22+
use crate::{
23+
compositor::SurfaceDataExt,
24+
registry::{ProvidesRegistryState, RegistryHandler},
25+
};
2326

2427
use self::{
2528
pointer::{PointerData, PointerDataExt, PointerHandler, ThemeSpec, ThemedPointer, Themes},
@@ -130,16 +133,29 @@ impl SeatState {
130133
/// ## Errors
131134
///
132135
/// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a pointer.
133-
pub fn get_pointer_with_theme<D>(
136+
pub fn get_pointer_with_theme<D, S>(
134137
&mut self,
135138
qh: &QueueHandle<D>,
136139
seat: &wl_seat::WlSeat,
140+
shm: &wl_shm::WlShm,
141+
surface: wl_surface::WlSurface,
137142
theme: ThemeSpec,
138143
) -> Result<ThemedPointer<PointerData>, SeatError>
139144
where
140-
D: Dispatch<wl_pointer::WlPointer, PointerData> + PointerHandler + 'static,
145+
D: Dispatch<wl_pointer::WlPointer, PointerData>
146+
+ Dispatch<wl_surface::WlSurface, S>
147+
+ PointerHandler
148+
+ 'static,
149+
S: SurfaceDataExt + 'static,
141150
{
142-
self.get_pointer_with_theme_and_data(qh, seat, theme, PointerData::new(seat.clone()))
151+
self.get_pointer_with_theme_and_data(
152+
qh,
153+
seat,
154+
shm,
155+
surface,
156+
theme,
157+
PointerData::new(seat.clone()),
158+
)
143159
}
144160

145161
/// Creates a pointer from a seat.
@@ -172,15 +188,21 @@ impl SeatState {
172188
/// ## Errors
173189
///
174190
/// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a pointer.
175-
pub fn get_pointer_with_theme_and_data<D, U>(
191+
pub fn get_pointer_with_theme_and_data<D, S, U>(
176192
&mut self,
177193
qh: &QueueHandle<D>,
178194
seat: &wl_seat::WlSeat,
195+
shm: &wl_shm::WlShm,
196+
surface: wl_surface::WlSurface,
179197
theme: ThemeSpec,
180198
pointer_data: U,
181199
) -> Result<ThemedPointer<U>, SeatError>
182200
where
183-
D: Dispatch<wl_pointer::WlPointer, U> + PointerHandler + 'static,
201+
D: Dispatch<wl_pointer::WlPointer, U>
202+
+ Dispatch<wl_surface::WlSurface, S>
203+
+ PointerHandler
204+
+ 'static,
205+
S: SurfaceDataExt + 'static,
184206
U: PointerDataExt + 'static,
185207
{
186208
let inner =
@@ -194,7 +216,10 @@ impl SeatState {
194216
Ok(ThemedPointer {
195217
themes: Arc::new(Mutex::new(Themes::new(theme))),
196218
pointer: wl_ptr,
219+
shm: shm.clone(),
220+
surface,
197221
_marker: std::marker::PhantomData,
222+
_surface_data: std::marker::PhantomData,
198223
})
199224
}
200225

src/seat/pointer/mod.rs

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,23 @@ use std::{
33
env, mem,
44
sync::{Arc, Mutex},
55
};
6-
use wayland_backend::{client::InvalidId, smallvec::SmallVec};
76

7+
use wayland_backend::{client::InvalidId, smallvec::SmallVec};
88
use wayland_client::{
9-
protocol::{wl_pointer, wl_seat::WlSeat, wl_shm, wl_surface},
9+
protocol::{
10+
wl_pointer::{self, WlPointer},
11+
wl_seat::WlSeat,
12+
wl_shm::WlShm,
13+
wl_surface::WlSurface,
14+
},
1015
Connection, Dispatch, Proxy, QueueHandle, WEnum,
1116
};
1217
use wayland_cursor::{Cursor, CursorTheme};
1318

14-
use crate::error::GlobalError;
19+
use crate::{
20+
compositor::{SurfaceData, SurfaceDataExt},
21+
error::GlobalError,
22+
};
1523

1624
use super::SeatState;
1725

@@ -64,7 +72,7 @@ impl AxisScroll {
6472
/// A single pointer event.
6573
#[derive(Debug, Clone)]
6674
pub struct PointerEvent {
67-
pub surface: wl_surface::WlSurface,
75+
pub surface: WlSurface,
6876
pub position: (f64, f64),
6977
pub kind: PointerEventKind,
7078
}
@@ -109,7 +117,7 @@ pub trait PointerHandler: Sized {
109117
&mut self,
110118
conn: &Connection,
111119
qh: &QueueHandle<Self>,
112-
pointer: &wl_pointer::WlPointer,
120+
pointer: &WlPointer,
113121
events: &[PointerEvent],
114122
);
115123
}
@@ -169,7 +177,7 @@ macro_rules! delegate_pointer {
169177
#[derive(Debug, Default)]
170178
pub(crate) struct PointerDataInner {
171179
/// Surface the pointer most recently entered
172-
pub(crate) surface: Option<wl_surface::WlSurface>,
180+
pub(crate) surface: Option<WlSurface>,
173181
/// Position relative to the surface
174182
pub(crate) position: (f64, f64),
175183

@@ -180,14 +188,14 @@ pub(crate) struct PointerDataInner {
180188
pub(crate) latest_enter: Option<u32>,
181189
}
182190

183-
impl<D, U> Dispatch<wl_pointer::WlPointer, U, D> for SeatState
191+
impl<D, U> Dispatch<WlPointer, U, D> for SeatState
184192
where
185-
D: Dispatch<wl_pointer::WlPointer, U> + PointerHandler,
193+
D: Dispatch<WlPointer, U> + PointerHandler,
186194
U: PointerDataExt,
187195
{
188196
fn event(
189197
data: &mut D,
190-
pointer: &wl_pointer::WlPointer,
198+
pointer: &WlPointer,
191199
event: wl_pointer::Event,
192200
udata: &U,
193201
conn: &Connection,
@@ -372,59 +380,77 @@ where
372380

373381
/// Pointer themeing
374382
#[derive(Debug)]
375-
pub struct ThemedPointer<U = PointerData> {
383+
pub struct ThemedPointer<U = PointerData, S = SurfaceData> {
376384
pub(super) themes: Arc<Mutex<Themes>>,
377-
pub(super) pointer: wl_pointer::WlPointer,
385+
/// The underlying wl_pointer.
386+
pub(super) pointer: WlPointer,
387+
pub(super) shm: WlShm,
388+
/// The surface owned by the cursor to present the icon.
389+
pub(super) surface: WlSurface,
378390
pub(super) _marker: std::marker::PhantomData<U>,
391+
pub(super) _surface_data: std::marker::PhantomData<S>,
379392
}
380393

381-
impl<U: PointerDataExt + 'static> ThemedPointer<U> {
382-
pub fn set_cursor(
383-
&self,
384-
conn: &Connection,
385-
name: &str,
386-
shm: &wl_shm::WlShm,
387-
surface: &wl_surface::WlSurface,
388-
scale: i32,
389-
) -> Result<(), PointerThemeError> {
394+
impl<U: PointerDataExt + 'static, S: SurfaceDataExt + 'static> ThemedPointer<U, S> {
395+
pub fn set_cursor(&self, conn: &Connection, name: &str) -> Result<(), PointerThemeError> {
390396
let mut themes = self.themes.lock().unwrap();
391397

398+
let scale = self.surface.data::<S>().unwrap().surface_data().scale_factor();
392399
let cursor = themes
393-
.get_cursor(conn, name, scale as u32, shm)
400+
.get_cursor(conn, name, scale as u32, &self.shm)
394401
.map_err(PointerThemeError::InvalidId)?
395402
.ok_or(PointerThemeError::CursorNotFound)?;
396403

397404
let image = &cursor[0];
398405
let (w, h) = image.dimensions();
399406
let (hx, hy) = image.hotspot();
400407

401-
surface.set_buffer_scale(scale);
402-
surface.attach(Some(image), 0, 0);
408+
self.surface.set_buffer_scale(scale);
409+
self.surface.attach(Some(image), 0, 0);
403410

404-
if surface.version() >= 4 {
405-
surface.damage_buffer(0, 0, w as i32, h as i32);
411+
if self.surface.version() >= 4 {
412+
self.surface.damage_buffer(0, 0, w as i32, h as i32);
406413
} else {
407-
// surface is old and does not support damage_buffer, so we damage
408-
// in surface coordinates and hope it is not rescaled
409-
surface.damage(0, 0, w as i32 / scale, h as i32 / scale);
414+
// Fallback for the old old surface.
415+
self.surface.damage(0, 0, w as i32 / scale, h as i32 / scale);
410416
}
411417

412418
// Commit the surface to place the cursor image in the compositor's memory.
413-
surface.commit();
419+
self.surface.commit();
414420

415421
// Set the pointer surface to change the pointer.
416422
let data = self.pointer.data::<U>();
417423
if let Some(serial) = data.and_then(|data| data.pointer_data().latest_enter_serial()) {
418-
self.pointer.set_cursor(serial, Some(surface), hx as i32 / scale, hy as i32 / scale);
424+
self.pointer.set_cursor(
425+
serial,
426+
Some(&self.surface),
427+
hx as i32 / scale,
428+
hy as i32 / scale,
429+
);
419430
Ok(())
420431
} else {
421432
Err(PointerThemeError::MissingEnterSerial)
422433
}
423434
}
424435

425-
pub fn pointer(&self) -> &wl_pointer::WlPointer {
436+
/// The [`WlPointer`] associated with this [`ThemedPointer`].
437+
pub fn pointer(&self) -> &WlPointer {
426438
&self.pointer
427439
}
440+
441+
/// The associated [`WlSurface`] with this [`ThemedPointer`].
442+
pub fn surface(&self) -> &WlSurface {
443+
&self.surface
444+
}
445+
}
446+
447+
impl<U, S> Drop for ThemedPointer<U, S> {
448+
fn drop(&mut self) {
449+
if self.pointer.version() >= 3 {
450+
self.pointer.release();
451+
}
452+
self.surface.destroy();
453+
}
428454
}
429455

430456
/// Specifies which cursor theme should be used by the theme manager.
@@ -509,7 +535,7 @@ impl Themes {
509535
conn: &Connection,
510536
name: &str,
511537
scale: u32,
512-
shm: &wl_shm::WlShm,
538+
shm: &WlShm,
513539
) -> Result<Option<&Cursor>, InvalidId> {
514540
// Check if the theme has been initialized at the specified scale.
515541
if let Entry::Vacant(e) = self.themes.entry(scale) {

0 commit comments

Comments
 (0)