seat: support for curstom cursor images
This commit is contained in:
parent
60bb5e8d5a
commit
f3a68fb1af
|
@ -9,6 +9,7 @@ use rand;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent},
|
compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent},
|
||||||
|
seat::CursorImageRole,
|
||||||
shell::{
|
shell::{
|
||||||
legacy::{
|
legacy::{
|
||||||
wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole,
|
wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole,
|
||||||
|
@ -27,7 +28,11 @@ use smithay::{
|
||||||
|
|
||||||
use window_map::{Kind as SurfaceKind, WindowMap};
|
use window_map::{Kind as SurfaceKind, WindowMap};
|
||||||
|
|
||||||
define_roles!(Roles => [ XdgSurface, XdgSurfaceRole ] [ ShellSurface, ShellSurfaceRole<()>] );
|
define_roles!(Roles =>
|
||||||
|
[ XdgSurface, XdgSurfaceRole ]
|
||||||
|
[ ShellSurface, ShellSurfaceRole<()>]
|
||||||
|
[ CursorImage, CursorImageRole ]
|
||||||
|
);
|
||||||
|
|
||||||
pub type MyWindowMap =
|
pub type MyWindowMap =
|
||||||
WindowMap<SurfaceData, Roles, (), (), fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>>;
|
WindowMap<SurfaceData, Roles, (), (), fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>>;
|
||||||
|
|
|
@ -146,9 +146,14 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
|
||||||
/*
|
/*
|
||||||
* Initialize wayland input object
|
* Initialize wayland input object
|
||||||
*/
|
*/
|
||||||
let (mut w_seat, _) = Seat::new(&mut display.borrow_mut(), session.seat(), log.clone());
|
let (mut w_seat, _) = Seat::new(
|
||||||
|
&mut display.borrow_mut(),
|
||||||
|
session.seat(),
|
||||||
|
compositor_token.clone(),
|
||||||
|
log.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let pointer = w_seat.add_pointer();
|
let pointer = w_seat.add_pointer(compositor_token.clone(), |_| {});
|
||||||
let keyboard = w_seat
|
let keyboard = w_seat
|
||||||
.add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| {
|
.add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| {
|
||||||
set_data_device_focus(seat, focus.and_then(|s| s.client()))
|
set_data_device_focus(seat, focus.and_then(|s| s.client()))
|
||||||
|
|
|
@ -52,9 +52,9 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
|
||||||
|
|
||||||
init_data_device(display, |_| {}, default_action_chooser, log.clone());
|
init_data_device(display, |_| {}, default_action_chooser, log.clone());
|
||||||
|
|
||||||
let (mut seat, _) = Seat::new(display, "winit".into(), log.clone());
|
let (mut seat, _) = Seat::new(display, "winit".into(), compositor_token.clone(), log.clone());
|
||||||
|
|
||||||
let pointer = seat.add_pointer();
|
let pointer = seat.add_pointer(compositor_token.clone(), |_| {});
|
||||||
|
|
||||||
let keyboard = seat
|
let keyboard = seat
|
||||||
.add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| {
|
.add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| {
|
||||||
|
|
|
@ -10,15 +10,22 @@
|
||||||
//! ```
|
//! ```
|
||||||
//! # extern crate wayland_server;
|
//! # extern crate wayland_server;
|
||||||
//! # #[macro_use] extern crate smithay;
|
//! # #[macro_use] extern crate smithay;
|
||||||
//! use smithay::wayland::seat::Seat;
|
//! use smithay::wayland::seat::{Seat, CursorImageRole};
|
||||||
|
//! # use smithay::wayland::compositor::compositor_init;
|
||||||
|
//!
|
||||||
|
//! // You need to insert the `CursorImageRole` into your roles, to handle requests from clients
|
||||||
|
//! // to set a surface as a cursor image
|
||||||
|
//! define_roles!(Roles => [CursorImage, CursorImageRole]);
|
||||||
//!
|
//!
|
||||||
//! # fn main(){
|
//! # fn main(){
|
||||||
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
|
//! # let (compositor_token, _, _) = compositor_init::<(), Roles, _, _>(&mut display, |_, _, _| {}, None);
|
||||||
//! // insert the seat:
|
//! // insert the seat:
|
||||||
//! let (seat, seat_global) = Seat::new(
|
//! let (seat, seat_global) = Seat::new(
|
||||||
//! &mut display, // the display
|
//! &mut display, // the display
|
||||||
//! "seat-0".into(), // the name of the seat, will be advertized to clients
|
//! "seat-0".into(), // the name of the seat, will be advertized to clients
|
||||||
|
//! compositor_token.clone(), // the compositor token
|
||||||
//! None // insert a logger here
|
//! None // insert a logger here
|
||||||
//! );
|
//! );
|
||||||
//! # }
|
//! # }
|
||||||
|
@ -31,27 +38,8 @@
|
||||||
//! Currently, only pointer and keyboard capabilities are supported by
|
//! Currently, only pointer and keyboard capabilities are supported by
|
||||||
//! smithay.
|
//! smithay.
|
||||||
//!
|
//!
|
||||||
//! You can add these capabilities via methods of the `Seat` struct:
|
//! You can add these capabilities via methods of the `Seat` struct: `add_keyboard`, `add_pointer`.
|
||||||
//!
|
//! These methods return handles that can be cloned and sent across thread, so you can keep one around
|
||||||
//! ```
|
|
||||||
//! # extern crate wayland_server;
|
|
||||||
//! # #[macro_use] extern crate smithay;
|
|
||||||
//! #
|
|
||||||
//! # use smithay::wayland::seat::Seat;
|
|
||||||
//! #
|
|
||||||
//! # fn main(){
|
|
||||||
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
|
||||||
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
|
||||||
//! # let (mut seat, seat_global) = Seat::new(
|
|
||||||
//! # &mut display,
|
|
||||||
//! # "seat-0".into(),
|
|
||||||
//! # None
|
|
||||||
//! # );
|
|
||||||
//! let pointer_handle = seat.add_pointer();
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! These handles can be cloned and sent across thread, so you can keep one around
|
|
||||||
//! in your event-handling code to forward inputs to your clients.
|
//! in your event-handling code to forward inputs to your clients.
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -61,9 +49,13 @@ mod pointer;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig},
|
keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig},
|
||||||
pointer::{AxisFrame, PointerGrab, PointerHandle, PointerInnerHandle},
|
pointer::{
|
||||||
|
AxisFrame, CursorImageRole, CursorImageStatus, PointerGrab, PointerHandle, PointerInnerHandle,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use wayland::compositor::{roles::Role, CompositorToken};
|
||||||
|
|
||||||
use wayland_commons::utils::UserDataMap;
|
use wayland_commons::utils::UserDataMap;
|
||||||
|
|
||||||
use wayland_server::{
|
use wayland_server::{
|
||||||
|
@ -129,8 +121,15 @@ impl Seat {
|
||||||
/// You are provided with the state token to retrieve it (allowing
|
/// You are provided with the state token to retrieve it (allowing
|
||||||
/// you to add or remove capabilities from it), and the global handle,
|
/// you to add or remove capabilities from it), and the global handle,
|
||||||
/// in case you want to remove it.
|
/// in case you want to remove it.
|
||||||
pub fn new<L>(display: &mut Display, name: String, logger: L) -> (Seat, Global<wl_seat::WlSeat>)
|
pub fn new<U, R, L>(
|
||||||
|
display: &mut Display,
|
||||||
|
name: String,
|
||||||
|
token: CompositorToken<U, R>,
|
||||||
|
logger: L,
|
||||||
|
) -> (Seat, Global<wl_seat::WlSeat>)
|
||||||
where
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<CursorImageRole> + 'static,
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
let log = ::slog_or_stdlog(logger);
|
let log = ::slog_or_stdlog(logger);
|
||||||
|
@ -146,7 +145,7 @@ impl Seat {
|
||||||
});
|
});
|
||||||
let seat = Seat { arc: arc.clone() };
|
let seat = Seat { arc: arc.clone() };
|
||||||
let global = display.create_global(5, move |new_seat, _version| {
|
let global = display.create_global(5, move |new_seat, _version| {
|
||||||
let seat = implement_seat(new_seat, arc.clone());
|
let seat = implement_seat(new_seat, arc.clone(), token.clone());
|
||||||
let mut inner = arc.inner.lock().unwrap();
|
let mut inner = arc.inner.lock().unwrap();
|
||||||
if seat.version() >= 2 {
|
if seat.version() >= 2 {
|
||||||
seat.send(wl_seat::Event::Name {
|
seat.send(wl_seat::Event::Name {
|
||||||
|
@ -179,9 +178,44 @@ impl Seat {
|
||||||
/// Calling this method on a seat that already has a pointer capability
|
/// Calling this method on a seat that already has a pointer capability
|
||||||
/// will overwrite it, and will be seen by the clients as if the
|
/// will overwrite it, and will be seen by the clients as if the
|
||||||
/// mouse was unplugged and a new one was plugged.
|
/// mouse was unplugged and a new one was plugged.
|
||||||
pub fn add_pointer(&mut self) -> PointerHandle {
|
///
|
||||||
|
/// You need to provide a compositor token, as well as a callback that will be notified
|
||||||
|
/// whenever a client requests to set a custom cursor image.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # extern crate wayland_server;
|
||||||
|
/// # #[macro_use] extern crate smithay;
|
||||||
|
/// #
|
||||||
|
/// # use smithay::wayland::{seat::{Seat, CursorImageRole}, compositor::compositor_init};
|
||||||
|
/// #
|
||||||
|
/// # define_roles!(Roles => [CursorImage, CursorImageRole]);
|
||||||
|
/// #
|
||||||
|
/// # fn main(){
|
||||||
|
/// # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
/// # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
|
/// # let (compositor_token, _, _) = compositor_init::<(), Roles, _, _>(&mut display, |_, _, _| {}, None);
|
||||||
|
/// # let (mut seat, seat_global) = Seat::new(
|
||||||
|
/// # &mut display,
|
||||||
|
/// # "seat-0".into(),
|
||||||
|
/// # compositor_token.clone(),
|
||||||
|
/// # None
|
||||||
|
/// # );
|
||||||
|
/// let pointer_handle = seat.add_pointer(
|
||||||
|
/// compositor_token.clone(),
|
||||||
|
/// |new_status| { /* a closure handling requests from clients tot change the cursor icon */ }
|
||||||
|
/// );
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn add_pointer<U, R, F>(&mut self, token: CompositorToken<U, R>, cb: F) -> PointerHandle
|
||||||
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<CursorImageRole> + 'static,
|
||||||
|
F: FnMut(CursorImageStatus) + Send + 'static,
|
||||||
|
{
|
||||||
let mut inner = self.arc.inner.lock().unwrap();
|
let mut inner = self.arc.inner.lock().unwrap();
|
||||||
let pointer = self::pointer::create_pointer_handler();
|
let pointer = self::pointer::create_pointer_handler(token, cb);
|
||||||
if inner.pointer.is_some() {
|
if inner.pointer.is_some() {
|
||||||
// there is already a pointer, remove it and notify the clients
|
// there is already a pointer, remove it and notify the clients
|
||||||
// of the change
|
// of the change
|
||||||
|
@ -303,7 +337,15 @@ impl ::std::cmp::PartialEq for Seat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_seat(new_seat: NewResource<wl_seat::WlSeat>, arc: Arc<SeatArc>) -> Resource<wl_seat::WlSeat> {
|
fn implement_seat<U, R>(
|
||||||
|
new_seat: NewResource<wl_seat::WlSeat>,
|
||||||
|
arc: Arc<SeatArc>,
|
||||||
|
token: CompositorToken<U, R>,
|
||||||
|
) -> Resource<wl_seat::WlSeat>
|
||||||
|
where
|
||||||
|
R: Role<CursorImageRole> + 'static,
|
||||||
|
U: 'static,
|
||||||
|
{
|
||||||
let dest_arc = arc.clone();
|
let dest_arc = arc.clone();
|
||||||
new_seat.implement(
|
new_seat.implement(
|
||||||
move |request, seat| {
|
move |request, seat| {
|
||||||
|
@ -311,7 +353,7 @@ fn implement_seat(new_seat: NewResource<wl_seat::WlSeat>, arc: Arc<SeatArc>) ->
|
||||||
let inner = arc.inner.lock().unwrap();
|
let inner = arc.inner.lock().unwrap();
|
||||||
match request {
|
match request {
|
||||||
wl_seat::Request::GetPointer { id } => {
|
wl_seat::Request::GetPointer { id } => {
|
||||||
let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref());
|
let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref(), token.clone());
|
||||||
if let Some(ref ptr_handle) = inner.pointer {
|
if let Some(ref ptr_handle) = inner.pointer {
|
||||||
ptr_handle.new_pointer(pointer);
|
ptr_handle.new_pointer(pointer);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,13 +1,31 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use wayland_server::{
|
use wayland_server::{
|
||||||
protocol::{
|
protocol::{
|
||||||
wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer},
|
wl_pointer::{self, Axis, AxisSource, ButtonState, Event, Request, WlPointer},
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
NewResource, Resource,
|
NewResource, Resource,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: handle pointer surface role
|
use wayland::compositor::{roles::Role, CompositorToken};
|
||||||
|
|
||||||
|
/// The role representing a surface set as the pointer cursor
|
||||||
|
#[derive(Default, Copy, Clone)]
|
||||||
|
pub struct CursorImageRole {
|
||||||
|
/// Location of the hotspot of the pointer in the surface
|
||||||
|
pub hotspot: (i32, i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Possible status of a cursor as requested by clients
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum CursorImageStatus {
|
||||||
|
/// The cursor should be hidden
|
||||||
|
Hidden,
|
||||||
|
/// The compositor should draw its cursor
|
||||||
|
Default,
|
||||||
|
/// The cursor should be drawn using this surface as an image
|
||||||
|
Image(Resource<WlSurface>),
|
||||||
|
}
|
||||||
|
|
||||||
enum GrabStatus {
|
enum GrabStatus {
|
||||||
None,
|
None,
|
||||||
|
@ -22,10 +40,35 @@ struct PointerInternal {
|
||||||
location: (f64, f64),
|
location: (f64, f64),
|
||||||
grab: GrabStatus,
|
grab: GrabStatus,
|
||||||
pressed_buttons: Vec<u32>,
|
pressed_buttons: Vec<u32>,
|
||||||
|
image_callback: Box<FnMut(CursorImageStatus) + Send>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerInternal {
|
impl PointerInternal {
|
||||||
fn new() -> PointerInternal {
|
fn new<F, U, R>(token: CompositorToken<U, R>, mut cb: F) -> PointerInternal
|
||||||
|
where
|
||||||
|
U: 'static,
|
||||||
|
R: Role<CursorImageRole> + 'static,
|
||||||
|
F: FnMut(CursorImageStatus) + Send + 'static,
|
||||||
|
{
|
||||||
|
let mut old_status = CursorImageStatus::Default;
|
||||||
|
let wrapper = move |new_status: CursorImageStatus| {
|
||||||
|
if let CursorImageStatus::Image(surface) =
|
||||||
|
::std::mem::replace(&mut old_status, new_status.clone())
|
||||||
|
{
|
||||||
|
match new_status {
|
||||||
|
CursorImageStatus::Image(ref new_surface) if new_surface == &surface => {
|
||||||
|
// don't remove the role, we are just re-binding the same surface
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if surface.is_alive() {
|
||||||
|
token.remove_role::<CursorImageRole>(&surface).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb(new_status)
|
||||||
|
};
|
||||||
|
|
||||||
PointerInternal {
|
PointerInternal {
|
||||||
known_pointers: Vec::new(),
|
known_pointers: Vec::new(),
|
||||||
focus: None,
|
focus: None,
|
||||||
|
@ -33,6 +76,7 @@ impl PointerInternal {
|
||||||
location: (0.0, 0.0),
|
location: (0.0, 0.0),
|
||||||
grab: GrabStatus::None,
|
grab: GrabStatus::None,
|
||||||
pressed_buttons: Vec::new(),
|
pressed_buttons: Vec::new(),
|
||||||
|
image_callback: Box::new(wrapper) as Box<_>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +341,7 @@ impl<'a> PointerInnerHandle<'a> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.inner.focus = None;
|
self.inner.focus = None;
|
||||||
|
(self.inner.image_callback)(CursorImageStatus::Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we enter one ?
|
// do we enter one ?
|
||||||
|
@ -431,6 +476,7 @@ pub struct AxisFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AxisFrame {
|
impl AxisFrame {
|
||||||
|
/// Create a new frame of axis events
|
||||||
pub fn new(time: u32) -> Self {
|
pub fn new(time: u32) -> Self {
|
||||||
AxisFrame {
|
AxisFrame {
|
||||||
source: None,
|
source: None,
|
||||||
|
@ -501,34 +547,83 @@ impl AxisFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_pointer_handler() -> PointerHandle {
|
pub(crate) fn create_pointer_handler<F, U, R>(token: CompositorToken<U, R>, cb: F) -> PointerHandle
|
||||||
|
where
|
||||||
|
R: Role<CursorImageRole> + 'static,
|
||||||
|
U: 'static,
|
||||||
|
F: FnMut(CursorImageStatus) + Send + 'static,
|
||||||
|
{
|
||||||
PointerHandle {
|
PointerHandle {
|
||||||
inner: Arc::new(Mutex::new(PointerInternal::new())),
|
inner: Arc::new(Mutex::new(PointerInternal::new(token, cb))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn implement_pointer(
|
pub(crate) fn implement_pointer<U, R>(
|
||||||
new_pointer: NewResource<WlPointer>,
|
new_pointer: NewResource<WlPointer>,
|
||||||
handle: Option<&PointerHandle>,
|
handle: Option<&PointerHandle>,
|
||||||
) -> Resource<WlPointer> {
|
token: CompositorToken<U, R>,
|
||||||
let destructor = match handle {
|
) -> Resource<WlPointer>
|
||||||
Some(h) => {
|
where
|
||||||
let inner = h.inner.clone();
|
R: Role<CursorImageRole> + 'static,
|
||||||
Some(move |pointer: Resource<_>| {
|
U: 'static,
|
||||||
|
{
|
||||||
|
let inner = handle.map(|h| h.inner.clone());
|
||||||
|
let destructor = match inner.clone() {
|
||||||
|
Some(inner) => Some(move |pointer: Resource<_>| {
|
||||||
inner
|
inner
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.known_pointers
|
.known_pointers
|
||||||
.retain(|p| !p.equals(&pointer))
|
.retain(|p| !p.equals(&pointer))
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
new_pointer.implement(
|
new_pointer.implement(
|
||||||
|request, _pointer| {
|
move |request, pointer| {
|
||||||
match request {
|
match request {
|
||||||
Request::SetCursor { .. } => {
|
Request::SetCursor {
|
||||||
// TODO
|
serial: _,
|
||||||
|
surface,
|
||||||
|
hotspot_x,
|
||||||
|
hotspot_y,
|
||||||
|
} => {
|
||||||
|
if let Some(ref inner) = inner {
|
||||||
|
let mut guard = inner.lock().unwrap();
|
||||||
|
// only allow setting the cursor icon if the current pointer focus
|
||||||
|
// is of the same client
|
||||||
|
let PointerInternal {
|
||||||
|
ref mut image_callback,
|
||||||
|
ref focus,
|
||||||
|
..
|
||||||
|
} = *guard;
|
||||||
|
if let Some((ref focus, _)) = *focus {
|
||||||
|
if focus.same_client_as(&pointer) {
|
||||||
|
match surface {
|
||||||
|
Some(surface) => {
|
||||||
|
let role_data = CursorImageRole {
|
||||||
|
hotspot: (hotspot_x, hotspot_y),
|
||||||
|
};
|
||||||
|
// we gracefully tolerate the client to provide a surface that
|
||||||
|
// already had the "CursorImage" role, as most clients will
|
||||||
|
// always reuse the same surface (and they are right to do so!)
|
||||||
|
if token.with_role_data(&surface, |data| *data = role_data).is_err()
|
||||||
|
&& token.give_role_with(&surface, role_data).is_err()
|
||||||
|
{
|
||||||
|
pointer.post_error(
|
||||||
|
wl_pointer::Error::Role as u32,
|
||||||
|
"Given wl_surface has another role.".into(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
image_callback(CursorImageStatus::Image(surface));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
image_callback(CursorImageStatus::Hidden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Request::Release => {
|
Request::Release => {
|
||||||
// Our destructors already handle it
|
// Our destructors already handle it
|
||||||
|
|
Loading…
Reference in New Issue