Skip to content

Commit 1da51ee

Browse files
committed
seat/pointer: automatically use cursor-shape-v1
When using `ThemedPointer` automatically use the `cursor-shape-v1` protocol to set cursor icon. We still accept the `WlSurface` and `WlShm` when building the `ThemedPointer` to handle the pointer hiding and custom cursor setting.
1 parent b75b0b4 commit 1da51ee

File tree

7 files changed

+379
-14
lines changed

7 files changed

+379
-14
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
- `ThemedPointer` now automatically releases the associated `WlPointer`.
1010
- `CursorIcon` from `cursor-icon` crate is now used for `set_cursor` and `Frame`.
1111

12+
#### Additions
13+
14+
- `CursorShapeManager` providing handling for `cursor-shape-v1` protocol.
15+
- `SeatState::with_cursor_shape_state_manager` to automatically utilize `cursor-shape-v1` for `ThemedPointer`.
16+
1217
## 0.17.0 - 2023-03-28
1318

1419
#### Breaking Changes

cursor-shape-v1.xml

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<protocol name="cursor_shape_v1">
3+
<copyright>
4+
Copyright 2018 The Chromium Authors
5+
Copyright 2023 Simon Ser
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a
8+
copy of this software and associated documentation files (the "Software"),
9+
to deal in the Software without restriction, including without limitation
10+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
11+
and/or sell copies of the Software, and to permit persons to whom the
12+
Software is furnished to do so, subject to the following conditions:
13+
The above copyright notice and this permission notice (including the next
14+
paragraph) shall be included in all copies or substantial portions of the
15+
Software.
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22+
DEALINGS IN THE SOFTWARE.
23+
</copyright>
24+
25+
<interface name="wp_cursor_shape_manager_v1" version="1">
26+
<description summary="cursor shape manager">
27+
This global allows clients to set cursor images by name instead of
28+
creating and attaching buffers.
29+
30+
Warning! The protocol described in this file is currently in the testing
31+
phase. Backward compatible changes may be added together with the
32+
corresponding interface version bump. Backward incompatible changes can
33+
only be done by creating a new major version of the extension.
34+
</description>
35+
36+
<request name="destroy" type="destructor">
37+
<description summary="destroy the manager">
38+
Destroy the cursor shape manager.
39+
</description>
40+
</request>
41+
42+
<request name="get_pointer">
43+
<description summary="manage the cursor shape of a pointer device">
44+
Obtain a wp_cursor_shape_device_v1 for a wl_pointer object.
45+
</description>
46+
<arg name="cursor_shape_device" type="new_id" interface="wp_cursor_shape_device_v1"/>
47+
<arg name="pointer" type="object" interface="wl_pointer"/>
48+
</request>
49+
50+
<request name="get_tablet_tool_v2">
51+
<description summary="manage the cursor shape of a tablet tool device">
52+
Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object.
53+
</description>
54+
<arg name="cursor_shape_device" type="new_id" interface="wp_cursor_shape_device_v1"/>
55+
<arg name="tablet_tool" type="object" interface="zwp_tablet_tool_v2"/>
56+
</request>
57+
</interface>
58+
59+
<interface name="wp_cursor_shape_device_v1" version="1">
60+
<description summary="cursor shape for a device">
61+
This interface advertises the list of supported cursor shapes for a
62+
device, and allows clients to set the cursor shape.
63+
</description>
64+
65+
<enum name="shape">
66+
<description summary="cursor shapes">
67+
This enum describes cursor shapes.
68+
69+
The names are taken from the CSS W3C specification:
70+
https://w3c.github.io/csswg-drafts/css-ui/#cursor
71+
</description>
72+
<entry name="default" value="1" summary="default cursor"/>
73+
<entry name="context_menu" value="2" summary="a context menu is available for the object under the cursor"/>
74+
<entry name="help" value="3" summary="help is available for the object under the cursor"/>
75+
<entry name="pointer" value="4" summary="pointer that indicates a link or another interactive element"/>
76+
<entry name="progress" value="5" summary="progress indicator"/>
77+
<entry name="wait" value="6" summary="program is busy, user should wait"/>
78+
<entry name="cell" value="7" summary="a cell or set of cells may be selected"/>
79+
<entry name="crosshair" value="8" summary="simple crosshair"/>
80+
<entry name="text" value="9" summary="text may be selected"/>
81+
<entry name="vertical_text" value="10" summary="vertical text may be selected"/>
82+
<entry name="alias" value="11" summary="drag-and-drop: alias of/shortcut to something is to be created"/>
83+
<entry name="copy" value="12" summary="drag-and-drop: something is to be copied"/>
84+
<entry name="move" value="13" summary="drag-and-drop: something is to be moved"/>
85+
<entry name="no_drop" value="14" summary="drag-and-drop: the dragged item cannot be dropped at the current cursor location"/>
86+
<entry name="not_allowed" value="15" summary="drag-and-drop: the requested action will not be carried out"/>
87+
<entry name="grab" value="16" summary="drag-and-drop: something can be grabbed"/>
88+
<entry name="grabbing" value="17" summary="drag-and-drop: something is being grabbed"/>
89+
<entry name="e_resize" value="18" summary="resizing: the east border is to be moved"/>
90+
<entry name="n_resize" value="19" summary="resizing: the north border is to be moved"/>
91+
<entry name="ne_resize" value="20" summary="resizing: the north-east corner is to be moved"/>
92+
<entry name="nw_resize" value="21" summary="resizing: the north-west corner is to be moved"/>
93+
<entry name="s_resize" value="22" summary="resizing: the south border is to be moved"/>
94+
<entry name="se_resize" value="23" summary="resizing: the south-east corner is to be moved"/>
95+
<entry name="sw_resize" value="24" summary="resizing: the south-west corner is to be moved"/>
96+
<entry name="w_resize" value="25" summary="resizing: the west border is to be moved"/>
97+
<entry name="ew_resize" value="26" summary="resizing: the east and west borders are to be moved"/>
98+
<entry name="ns_resize" value="27" summary="resizing: the north and south borders are to be moved"/>
99+
<entry name="nesw_resize" value="28" summary="resizing: the north-east and south-west corners are to be moved"/>
100+
<entry name="nwse_resize" value="29" summary="resizing: the north-west and south-east corners are to be moved"/>
101+
<entry name="col_resize" value="30" summary="resizing: that the item/column can be resized horizontally"/>
102+
<entry name="row_resize" value="31" summary="resizing: that the item/row can be resized vertically"/>
103+
<entry name="all_scroll" value="32" summary="something can be scrolled in any direction"/>
104+
<entry name="zoom_in" value="33" summary="something can be zoomed in"/>
105+
<entry name="zoom_out" value="34" summary="something can be zoomed out"/>
106+
</enum>
107+
108+
<enum name="error">
109+
<entry name="invalid_shape" value="1"
110+
summary="the specified shape value is invalid"/>
111+
</enum>
112+
113+
<request name="destroy" type="destructor">
114+
<description summary="destroy the cursor shape device">
115+
Destroy the cursor shape device.
116+
117+
The device cursor shape remains unchanged.
118+
</description>
119+
</request>
120+
121+
<request name="set_shape">
122+
<description summary="set device cursor to the shape">
123+
Sets the device cursor to the specified shape. The compositor will
124+
change the cursor image based on the specified shape.
125+
126+
The cursor actually changes only if the input device focus is one of
127+
the requesting client's surfaces. If any, the previous cursor image
128+
(surface or shape) is replaced.
129+
130+
The "shape" argument must be a valid enum entry, otherwise the
131+
invalid_shape protocol error is raised.
132+
133+
This is similar to the wl_pointer.set_cursor and
134+
zwp_tablet_tool_v2.set_cursor requests, but this request accepts a
135+
shape instead of contents in the form of a surface. Clients can mix
136+
set_cursor and set_shape requests.
137+
138+
The serial parameter must match the latest wl_pointer.enter or
139+
zwp_tablet_tool_v2.enter serial number sent to the client. Otherwise
140+
the request will be ignored.
141+
</description>
142+
<arg name="serial" type="uint" summary="serial number of the enter event"/>
143+
<arg name="shape" type="uint" enum="shape"/>
144+
</request>
145+
</interface>
146+
</protocol>

examples/themed_window.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::sync::Arc;
22
use std::{convert::TryInto, num::NonZeroU32};
33

44
use smithay_client_toolkit::seat::keyboard::keysyms;
5+
use smithay_client_toolkit::wp_cursor_shape::CursorShapeManager;
56
use smithay_client_toolkit::{
67
compositor::{CompositorHandler, CompositorState},
78
delegate_compositor, delegate_keyboard, delegate_output, delegate_pointer, delegate_registry,
@@ -84,7 +85,8 @@ fn main() {
8485
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
8586
let qh = event_queue.handle();
8687
let registry_state = RegistryState::new(&globals);
87-
let seat_state = SeatState::new(&globals, &qh);
88+
let cursor_shape_manager = CursorShapeManager::bind(&globals, &qh).ok();
89+
let seat_state = SeatState::new(&globals, &qh).with_cursor_shape_manager(cursor_shape_manager);
8890
let output_state = OutputState::new(&globals, &qh);
8991
let compositor_state =
9092
CompositorState::bind(&globals, &qh).expect("wl_compositor not available");

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ pub mod seat;
2525
pub mod shell;
2626
pub mod shm;
2727
pub mod subcompositor;
28+
pub mod wp_cursor_shape;

src/seat/mod.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use wayland_client::{
2121

2222
use crate::{
2323
compositor::SurfaceDataExt,
24+
globals::GlobalData,
2425
registry::{ProvidesRegistryState, RegistryHandler},
26+
wp_cursor_shape::{CursorShapeManager, WpCursorShapeDeviceV1},
2527
};
2628

2729
use self::{
@@ -64,6 +66,9 @@ pub enum SeatError {
6466
pub struct SeatState {
6567
// (name, seat)
6668
seats: Vec<SeatInner>,
69+
70+
/// Shape manager for the cursor icons.
71+
cursor_shape_manager: Option<CursorShapeManager>,
6772
}
6873

6974
impl SeatState {
@@ -82,7 +87,7 @@ impl SeatState {
8287
.expect("failed to bind global")
8388
});
8489

85-
let mut state = SeatState { seats: vec![] };
90+
let mut state = SeatState { seats: vec![], cursor_shape_manager: None };
8691
for seat in seats {
8792
let data = seat.data::<SeatData>().unwrap().clone();
8893

@@ -91,6 +96,16 @@ impl SeatState {
9196
state
9297
}
9398

99+
/// Provide the [`CursorShapeManager`] to automatically handle server side cursor
100+
/// when using [`Self::get_pointer_with_theme`] and [`Self::get_pointer_with_theme_and_data`].
101+
pub fn with_cursor_shape_manager(
102+
mut self,
103+
cursor_shape_manager: Option<CursorShapeManager>,
104+
) -> Self {
105+
self.cursor_shape_manager = cursor_shape_manager;
106+
self
107+
}
108+
94109
/// Returns an iterator over all the seats.
95110
pub fn seats(&self) -> impl Iterator<Item = wl_seat::WlSeat> {
96111
self.seats.iter().map(|inner| inner.seat.clone()).collect::<Vec<_>>().into_iter()
@@ -112,6 +127,11 @@ impl SeatState {
112127
})
113128
}
114129

130+
/// Get the cursor shape manager passed in [`SeatState::with_cursor_shape_manager`].
131+
pub fn cursor_shape_manager(&self) -> Option<&CursorShapeManager> {
132+
self.cursor_shape_manager.as_ref()
133+
}
134+
115135
/// Creates a pointer from a seat.
116136
///
117137
/// ## Errors
@@ -144,6 +164,7 @@ impl SeatState {
144164
where
145165
D: Dispatch<wl_pointer::WlPointer, PointerData>
146166
+ Dispatch<wl_surface::WlSurface, S>
167+
+ Dispatch<WpCursorShapeDeviceV1, GlobalData>
147168
+ PointerHandler
148169
+ 'static,
149170
S: SurfaceDataExt + 'static,
@@ -200,6 +221,8 @@ impl SeatState {
200221
where
201222
D: Dispatch<wl_pointer::WlPointer, U>
202223
+ Dispatch<wl_surface::WlSurface, S>
224+
+ Dispatch<WpCursorShapeDeviceV1, GlobalData>
225+
+ Dispatch<WpCursorShapeDeviceV1, GlobalData>
203226
+ PointerHandler
204227
+ 'static,
205228
S: SurfaceDataExt + 'static,
@@ -213,11 +236,16 @@ impl SeatState {
213236
}
214237

215238
let wl_ptr = seat.get_pointer(qh, pointer_data);
239+
240+
// Use the cursor shape manager when available.
241+
let shape_device = self.cursor_shape_manager().map(|csm| csm.get_shape_device(&wl_ptr, qh));
242+
216243
Ok(ThemedPointer {
217244
themes: Arc::new(Mutex::new(Themes::new(theme))),
218245
pointer: wl_ptr,
219246
shm: shm.clone(),
220247
surface,
248+
shape_device,
221249
_marker: std::marker::PhantomData,
222250
_surface_data: std::marker::PhantomData,
223251
})

0 commit comments

Comments
 (0)