wayland: Implement cursor-shape-v1 (#11106)
Fixes wrong cursor icons and sizes on KDE 6 (and possibly other compositors) Gnome still doesn't support this protocol, so to fix cursor settings there we'll need to read `gsettings`. Before:  After:  Release Notes: - N/A
This commit is contained in:
parent
089ea7852d
commit
a765535557
4 changed files with 136 additions and 98 deletions
|
@ -715,7 +715,7 @@ pub enum PromptLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The style of the cursor (pointer)
|
/// The style of the cursor (pointer)
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum CursorStyle {
|
pub enum CursorStyle {
|
||||||
/// The default cursor
|
/// The default cursor
|
||||||
Arrow,
|
Arrow,
|
||||||
|
|
|
@ -28,6 +28,7 @@ use futures::channel::oneshot;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
use wayland_client::Connection;
|
use wayland_client::Connection;
|
||||||
|
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
|
||||||
use xkbcommon::xkb::{self, Keycode, Keysym, State};
|
use xkbcommon::xkb::{self, Keycode, Keysym, State};
|
||||||
|
|
||||||
use crate::platform::linux::wayland::WaylandClient;
|
use crate::platform::linux::wayland::WaylandClient;
|
||||||
|
@ -501,6 +502,58 @@ pub(super) unsafe fn read_fd(mut fd: FileDescriptor) -> Result<String> {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CursorStyle {
|
||||||
|
pub(super) fn to_shape(&self) -> Shape {
|
||||||
|
match self {
|
||||||
|
CursorStyle::Arrow => Shape::Default,
|
||||||
|
CursorStyle::IBeam => Shape::Text,
|
||||||
|
CursorStyle::Crosshair => Shape::Crosshair,
|
||||||
|
CursorStyle::ClosedHand => Shape::Grabbing,
|
||||||
|
CursorStyle::OpenHand => Shape::Grab,
|
||||||
|
CursorStyle::PointingHand => Shape::Pointer,
|
||||||
|
CursorStyle::ResizeLeft => Shape::WResize,
|
||||||
|
CursorStyle::ResizeRight => Shape::EResize,
|
||||||
|
CursorStyle::ResizeLeftRight => Shape::EwResize,
|
||||||
|
CursorStyle::ResizeUp => Shape::NResize,
|
||||||
|
CursorStyle::ResizeDown => Shape::SResize,
|
||||||
|
CursorStyle::ResizeUpDown => Shape::NsResize,
|
||||||
|
CursorStyle::DisappearingItem => Shape::Grabbing, // todo(linux) - couldn't find equivalent icon in linux
|
||||||
|
CursorStyle::IBeamCursorForVerticalLayout => Shape::VerticalText,
|
||||||
|
CursorStyle::OperationNotAllowed => Shape::NotAllowed,
|
||||||
|
CursorStyle::DragLink => Shape::Alias,
|
||||||
|
CursorStyle::DragCopy => Shape::Copy,
|
||||||
|
CursorStyle::ContextualMenu => Shape::ContextMenu,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn to_icon_name(&self) -> String {
|
||||||
|
// Based on cursor names from https://gitlab.gnome.org/GNOME/adwaita-icon-theme (GNOME)
|
||||||
|
// and https://github.com/KDE/breeze (KDE). Both of them seem to be also derived from
|
||||||
|
// Web CSS cursor names: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#values
|
||||||
|
match self {
|
||||||
|
CursorStyle::Arrow => "arrow",
|
||||||
|
CursorStyle::IBeam => "text",
|
||||||
|
CursorStyle::Crosshair => "crosshair",
|
||||||
|
CursorStyle::ClosedHand => "grabbing",
|
||||||
|
CursorStyle::OpenHand => "grab",
|
||||||
|
CursorStyle::PointingHand => "pointer",
|
||||||
|
CursorStyle::ResizeLeft => "w-resize",
|
||||||
|
CursorStyle::ResizeRight => "e-resize",
|
||||||
|
CursorStyle::ResizeLeftRight => "ew-resize",
|
||||||
|
CursorStyle::ResizeUp => "n-resize",
|
||||||
|
CursorStyle::ResizeDown => "s-resize",
|
||||||
|
CursorStyle::ResizeUpDown => "ns-resize",
|
||||||
|
CursorStyle::DisappearingItem => "grabbing", // todo(linux) - couldn't find equivalent icon in linux
|
||||||
|
CursorStyle::IBeamCursorForVerticalLayout => "vertical-text",
|
||||||
|
CursorStyle::OperationNotAllowed => "not-allowed",
|
||||||
|
CursorStyle::DragLink => "alias",
|
||||||
|
CursorStyle::DragCopy => "copy",
|
||||||
|
CursorStyle::ContextualMenu => "context-menu",
|
||||||
|
}
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Keystroke {
|
impl Keystroke {
|
||||||
pub(super) fn from_xkb(state: &State, modifiers: Modifiers, keycode: Keycode) -> Self {
|
pub(super) fn from_xkb(state: &State, modifiers: Modifiers, keycode: Keycode) -> Self {
|
||||||
let mut modifiers = modifiers;
|
let mut modifiers = modifiers;
|
||||||
|
|
|
@ -34,6 +34,10 @@ use wayland_client::{
|
||||||
},
|
},
|
||||||
Connection, Dispatch, Proxy, QueueHandle,
|
Connection, Dispatch, Proxy, QueueHandle,
|
||||||
};
|
};
|
||||||
|
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
|
||||||
|
use wayland_protocols::wp::cursor_shape::v1::client::{
|
||||||
|
wp_cursor_shape_device_v1, wp_cursor_shape_manager_v1,
|
||||||
|
};
|
||||||
use wayland_protocols::wp::fractional_scale::v1::client::{
|
use wayland_protocols::wp::fractional_scale::v1::client::{
|
||||||
wp_fractional_scale_manager_v1, wp_fractional_scale_v1,
|
wp_fractional_scale_manager_v1, wp_fractional_scale_v1,
|
||||||
};
|
};
|
||||||
|
@ -68,6 +72,7 @@ const MIN_KEYCODE: u32 = 8;
|
||||||
pub struct Globals {
|
pub struct Globals {
|
||||||
pub qh: QueueHandle<WaylandClientStatePtr>,
|
pub qh: QueueHandle<WaylandClientStatePtr>,
|
||||||
pub compositor: wl_compositor::WlCompositor,
|
pub compositor: wl_compositor::WlCompositor,
|
||||||
|
pub cursor_shape_manager: Option<wp_cursor_shape_manager_v1::WpCursorShapeManagerV1>,
|
||||||
pub data_device_manager: Option<wl_data_device_manager::WlDataDeviceManager>,
|
pub data_device_manager: Option<wl_data_device_manager::WlDataDeviceManager>,
|
||||||
pub wm_base: xdg_wm_base::XdgWmBase,
|
pub wm_base: xdg_wm_base::XdgWmBase,
|
||||||
pub shm: wl_shm::WlShm,
|
pub shm: wl_shm::WlShm,
|
||||||
|
@ -93,6 +98,7 @@ impl Globals {
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
cursor_shape_manager: globals.bind(&qh, 1..=1, ()).ok(),
|
||||||
data_device_manager: globals
|
data_device_manager: globals
|
||||||
.bind(
|
.bind(
|
||||||
&qh,
|
&qh,
|
||||||
|
@ -112,9 +118,11 @@ impl Globals {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct WaylandClientState {
|
pub(crate) struct WaylandClientState {
|
||||||
serial: u32,
|
serial: u32, // todo(linux): storing a general serial is wrong
|
||||||
|
pointer_serial: u32,
|
||||||
globals: Globals,
|
globals: Globals,
|
||||||
wl_pointer: Option<wl_pointer::WlPointer>,
|
wl_pointer: Option<wl_pointer::WlPointer>,
|
||||||
|
cursor_shape_device: Option<wp_cursor_shape_device_v1::WpCursorShapeDeviceV1>,
|
||||||
data_device: Option<wl_data_device::WlDataDevice>,
|
data_device: Option<wl_data_device::WlDataDevice>,
|
||||||
// Surface to Window mapping
|
// Surface to Window mapping
|
||||||
windows: HashMap<ObjectId, WaylandWindowStatePtr>,
|
windows: HashMap<ObjectId, WaylandWindowStatePtr>,
|
||||||
|
@ -137,7 +145,7 @@ pub(crate) struct WaylandClientState {
|
||||||
mouse_focused_window: Option<WaylandWindowStatePtr>,
|
mouse_focused_window: Option<WaylandWindowStatePtr>,
|
||||||
keyboard_focused_window: Option<WaylandWindowStatePtr>,
|
keyboard_focused_window: Option<WaylandWindowStatePtr>,
|
||||||
loop_handle: LoopHandle<'static, WaylandClientStatePtr>,
|
loop_handle: LoopHandle<'static, WaylandClientStatePtr>,
|
||||||
cursor_icon_name: String,
|
cursor_style: Option<CursorStyle>,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
clipboard: Option<Clipboard>,
|
clipboard: Option<Clipboard>,
|
||||||
primary: Option<Primary>,
|
primary: Option<Primary>,
|
||||||
|
@ -197,6 +205,9 @@ impl WaylandClientStatePtr {
|
||||||
if let Some(wl_pointer) = &state.wl_pointer {
|
if let Some(wl_pointer) = &state.wl_pointer {
|
||||||
wl_pointer.release();
|
wl_pointer.release();
|
||||||
}
|
}
|
||||||
|
if let Some(cursor_shape_device) = &state.cursor_shape_device {
|
||||||
|
cursor_shape_device.destroy();
|
||||||
|
}
|
||||||
if let Some(data_device) = &state.data_device {
|
if let Some(data_device) = &state.data_device {
|
||||||
data_device.release();
|
data_device.release();
|
||||||
}
|
}
|
||||||
|
@ -289,8 +300,10 @@ impl WaylandClient {
|
||||||
|
|
||||||
let mut state = Rc::new(RefCell::new(WaylandClientState {
|
let mut state = Rc::new(RefCell::new(WaylandClientState {
|
||||||
serial: 0,
|
serial: 0,
|
||||||
|
pointer_serial: 0,
|
||||||
globals,
|
globals,
|
||||||
wl_pointer: None,
|
wl_pointer: None,
|
||||||
|
cursor_shape_device: None,
|
||||||
data_device,
|
data_device,
|
||||||
output_scales: outputs,
|
output_scales: outputs,
|
||||||
windows: HashMap::default(),
|
windows: HashMap::default(),
|
||||||
|
@ -330,8 +343,8 @@ impl WaylandClient {
|
||||||
mouse_focused_window: None,
|
mouse_focused_window: None,
|
||||||
keyboard_focused_window: None,
|
keyboard_focused_window: None,
|
||||||
loop_handle: handle.clone(),
|
loop_handle: handle.clone(),
|
||||||
cursor_icon_name: "arrow".to_string(),
|
|
||||||
enter_token: None,
|
enter_token: None,
|
||||||
|
cursor_style: None,
|
||||||
cursor,
|
cursor,
|
||||||
clipboard: Some(clipboard),
|
clipboard: Some(clipboard),
|
||||||
primary: Some(primary),
|
primary: Some(primary),
|
||||||
|
@ -375,39 +388,28 @@ impl LinuxClient for WaylandClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cursor_style(&self, style: CursorStyle) {
|
fn set_cursor_style(&self, style: CursorStyle) {
|
||||||
// Based on cursor names from https://gitlab.gnome.org/GNOME/adwaita-icon-theme (GNOME)
|
|
||||||
// and https://github.com/KDE/breeze (KDE). Both of them seem to be also derived from
|
|
||||||
// Web CSS cursor names: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#values
|
|
||||||
let cursor_icon_name = match style {
|
|
||||||
CursorStyle::Arrow => "arrow",
|
|
||||||
CursorStyle::IBeam => "text",
|
|
||||||
CursorStyle::Crosshair => "crosshair",
|
|
||||||
CursorStyle::ClosedHand => "grabbing",
|
|
||||||
CursorStyle::OpenHand => "grab",
|
|
||||||
CursorStyle::PointingHand => "pointer",
|
|
||||||
CursorStyle::ResizeLeft => "w-resize",
|
|
||||||
CursorStyle::ResizeRight => "e-resize",
|
|
||||||
CursorStyle::ResizeLeftRight => "ew-resize",
|
|
||||||
CursorStyle::ResizeUp => "n-resize",
|
|
||||||
CursorStyle::ResizeDown => "s-resize",
|
|
||||||
CursorStyle::ResizeUpDown => "ns-resize",
|
|
||||||
CursorStyle::DisappearingItem => "grabbing", // todo(linux) - couldn't find equivalent icon in linux
|
|
||||||
CursorStyle::IBeamCursorForVerticalLayout => "vertical-text",
|
|
||||||
CursorStyle::OperationNotAllowed => "not-allowed",
|
|
||||||
CursorStyle::DragLink => "alias",
|
|
||||||
CursorStyle::DragCopy => "copy",
|
|
||||||
CursorStyle::ContextualMenu => "context-menu",
|
|
||||||
}
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let mut state = self.0.borrow_mut();
|
let mut state = self.0.borrow_mut();
|
||||||
state.cursor_icon_name = cursor_icon_name.clone();
|
|
||||||
if state.mouse_focused_window.is_some() {
|
let need_update = state
|
||||||
let wl_pointer = state
|
.cursor_style
|
||||||
.wl_pointer
|
.map_or(true, |current_style| current_style != style);
|
||||||
.clone()
|
|
||||||
.expect("window is focused by pointer");
|
if need_update {
|
||||||
state.cursor.set_icon(&wl_pointer, &cursor_icon_name);
|
let serial = state.pointer_serial;
|
||||||
|
state.cursor_style = Some(style);
|
||||||
|
|
||||||
|
if let Some(cursor_shape_device) = &state.cursor_shape_device {
|
||||||
|
cursor_shape_device.set_shape(serial, style.to_shape());
|
||||||
|
} else if state.mouse_focused_window.is_some() {
|
||||||
|
// cursor-shape-v1 isn't supported, set the cursor using a surface.
|
||||||
|
let wl_pointer = state
|
||||||
|
.wl_pointer
|
||||||
|
.clone()
|
||||||
|
.expect("window is focused by pointer");
|
||||||
|
state
|
||||||
|
.cursor
|
||||||
|
.set_icon(&wl_pointer, serial, &style.to_icon_name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,6 +518,8 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStat
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate_noop!(WaylandClientStatePtr: ignore wl_compositor::WlCompositor);
|
delegate_noop!(WaylandClientStatePtr: ignore wl_compositor::WlCompositor);
|
||||||
|
delegate_noop!(WaylandClientStatePtr: ignore wp_cursor_shape_device_v1::WpCursorShapeDeviceV1);
|
||||||
|
delegate_noop!(WaylandClientStatePtr: ignore wp_cursor_shape_manager_v1::WpCursorShapeManagerV1);
|
||||||
delegate_noop!(WaylandClientStatePtr: ignore wl_data_device_manager::WlDataDeviceManager);
|
delegate_noop!(WaylandClientStatePtr: ignore wl_data_device_manager::WlDataDeviceManager);
|
||||||
delegate_noop!(WaylandClientStatePtr: ignore wl_shm::WlShm);
|
delegate_noop!(WaylandClientStatePtr: ignore wl_shm::WlShm);
|
||||||
delegate_noop!(WaylandClientStatePtr: ignore wl_shm_pool::WlShmPool);
|
delegate_noop!(WaylandClientStatePtr: ignore wl_shm_pool::WlShmPool);
|
||||||
|
@ -684,7 +688,13 @@ impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
|
||||||
if capabilities.contains(wl_seat::Capability::Pointer) {
|
if capabilities.contains(wl_seat::Capability::Pointer) {
|
||||||
let client = state.get_client();
|
let client = state.get_client();
|
||||||
let mut state = client.borrow_mut();
|
let mut state = client.borrow_mut();
|
||||||
state.wl_pointer = Some(seat.get_pointer(qh, ()));
|
let pointer = seat.get_pointer(qh, ());
|
||||||
|
state.cursor_shape_device = state
|
||||||
|
.globals
|
||||||
|
.cursor_shape_manager
|
||||||
|
.as_ref()
|
||||||
|
.map(|cursor_shape_manager| cursor_shape_manager.get_pointer(&pointer, qh, ()));
|
||||||
|
state.wl_pointer = Some(pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -889,7 +899,6 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
|
||||||
) {
|
) {
|
||||||
let mut client = this.get_client();
|
let mut client = this.get_client();
|
||||||
let mut state = client.borrow_mut();
|
let mut state = client.borrow_mut();
|
||||||
let cursor_icon_name = state.cursor_icon_name.clone();
|
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
wl_pointer::Event::Enter {
|
wl_pointer::Event::Enter {
|
||||||
|
@ -899,17 +908,21 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
|
||||||
surface_y,
|
surface_y,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
state.serial = serial;
|
state.pointer_serial = serial;
|
||||||
state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
|
state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
|
||||||
|
|
||||||
if let Some(window) = get_window(&mut state, &surface.id()) {
|
if let Some(window) = get_window(&mut state, &surface.id()) {
|
||||||
state.enter_token = Some(());
|
state.enter_token = Some(());
|
||||||
state.mouse_focused_window = Some(window.clone());
|
state.mouse_focused_window = Some(window.clone());
|
||||||
state.cursor.mark_dirty();
|
if let Some(style) = state.cursor_style {
|
||||||
state.cursor.set_serial_id(serial);
|
if let Some(cursor_shape_device) = &state.cursor_shape_device {
|
||||||
state
|
cursor_shape_device.set_shape(serial, style.to_shape());
|
||||||
.cursor
|
} else {
|
||||||
.set_icon(&wl_pointer, cursor_icon_name.as_str());
|
state
|
||||||
|
.cursor
|
||||||
|
.set_icon(&wl_pointer, serial, &style.to_icon_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
drop(state);
|
drop(state);
|
||||||
window.set_focused(true);
|
window.set_focused(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,7 @@ use wayland_cursor::{CursorImageBuffer, CursorTheme};
|
||||||
|
|
||||||
pub(crate) struct Cursor {
|
pub(crate) struct Cursor {
|
||||||
theme: Option<CursorTheme>,
|
theme: Option<CursorTheme>,
|
||||||
current_icon_name: Option<String>,
|
|
||||||
surface: WlSurface,
|
surface: WlSurface,
|
||||||
serial_id: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Cursor {
|
impl Drop for Cursor {
|
||||||
|
@ -24,65 +22,39 @@ impl Cursor {
|
||||||
pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
|
pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
|
theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
|
||||||
current_icon_name: None,
|
|
||||||
surface: globals.compositor.create_surface(&globals.qh, ()),
|
surface: globals.compositor.create_surface(&globals.qh, ()),
|
||||||
serial_id: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_dirty(&mut self) {
|
pub fn set_icon(&mut self, wl_pointer: &WlPointer, serial_id: u32, mut cursor_icon_name: &str) {
|
||||||
self.current_icon_name = None;
|
if let Some(theme) = &mut self.theme {
|
||||||
}
|
let mut buffer: Option<&CursorImageBuffer>;
|
||||||
|
|
||||||
pub fn set_serial_id(&mut self, serial_id: u32) {
|
if let Some(cursor) = theme.get_cursor(&cursor_icon_name) {
|
||||||
self.serial_id = serial_id;
|
buffer = Some(&cursor[0]);
|
||||||
}
|
} else if let Some(cursor) = theme.get_cursor("default") {
|
||||||
|
buffer = Some(&cursor[0]);
|
||||||
pub fn set_icon(&mut self, wl_pointer: &WlPointer, mut cursor_icon_name: &str) {
|
cursor_icon_name = "default";
|
||||||
let need_update = self
|
log::warn!(
|
||||||
.current_icon_name
|
"Linux: Wayland: Unable to get cursor icon: {}. Using default cursor icon",
|
||||||
.as_ref()
|
cursor_icon_name
|
||||||
.map_or(true, |current_icon_name| {
|
);
|
||||||
current_icon_name != cursor_icon_name
|
|
||||||
});
|
|
||||||
|
|
||||||
if need_update {
|
|
||||||
if let Some(theme) = &mut self.theme {
|
|
||||||
let mut buffer: Option<&CursorImageBuffer>;
|
|
||||||
|
|
||||||
if let Some(cursor) = theme.get_cursor(&cursor_icon_name) {
|
|
||||||
buffer = Some(&cursor[0]);
|
|
||||||
} else if let Some(cursor) = theme.get_cursor("default") {
|
|
||||||
buffer = Some(&cursor[0]);
|
|
||||||
cursor_icon_name = "default";
|
|
||||||
log::warn!(
|
|
||||||
"Linux: Wayland: Unable to get cursor icon: {}. Using default cursor icon",
|
|
||||||
cursor_icon_name
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
buffer = None;
|
|
||||||
log::warn!("Linux: Wayland: Unable to get default cursor too!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(buffer) = &mut buffer {
|
|
||||||
let (width, height) = buffer.dimensions();
|
|
||||||
let (hot_x, hot_y) = buffer.hotspot();
|
|
||||||
|
|
||||||
wl_pointer.set_cursor(
|
|
||||||
self.serial_id,
|
|
||||||
Some(&self.surface),
|
|
||||||
hot_x as i32,
|
|
||||||
hot_y as i32,
|
|
||||||
);
|
|
||||||
self.surface.attach(Some(&buffer), 0, 0);
|
|
||||||
self.surface.damage(0, 0, width as i32, height as i32);
|
|
||||||
self.surface.commit();
|
|
||||||
|
|
||||||
self.current_icon_name = Some(cursor_icon_name.to_string());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Linux: Wayland: Unable to load cursor themes");
|
buffer = None;
|
||||||
|
log::warn!("Linux: Wayland: Unable to get default cursor too!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(buffer) = &mut buffer {
|
||||||
|
let (width, height) = buffer.dimensions();
|
||||||
|
let (hot_x, hot_y) = buffer.hotspot();
|
||||||
|
|
||||||
|
wl_pointer.set_cursor(serial_id, Some(&self.surface), hot_x as i32, hot_y as i32);
|
||||||
|
self.surface.attach(Some(&buffer), 0, 0);
|
||||||
|
self.surface.damage(0, 0, width as i32, height as i32);
|
||||||
|
self.surface.commit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Linux: Wayland: Unable to load cursor themes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue