1use crate::Globals;
2use util::ResultExt;
3
4use wayland_client::protocol::wl_pointer::WlPointer;
5use wayland_client::protocol::wl_surface::WlSurface;
6use wayland_client::Connection;
7use wayland_cursor::{CursorImageBuffer, CursorTheme};
8
9pub(crate) struct Cursor {
10 theme: Option<CursorTheme>,
11 current_icon_name: Option<String>,
12 surface: WlSurface,
13 serial_id: u32,
14}
15
16impl Drop for Cursor {
17 fn drop(&mut self) {
18 self.theme.take();
19 self.surface.destroy();
20 }
21}
22
23impl Cursor {
24 pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
25 Self {
26 theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
27 current_icon_name: None,
28 surface: globals.compositor.create_surface(&globals.qh, ()),
29 serial_id: 0,
30 }
31 }
32
33 pub fn mark_dirty(&mut self) {
34 self.current_icon_name = None;
35 }
36
37 pub fn set_serial_id(&mut self, serial_id: u32) {
38 self.serial_id = serial_id;
39 }
40
41 pub fn set_icon(&mut self, wl_pointer: &WlPointer, mut cursor_icon_name: &str) {
42 let need_update = self
43 .current_icon_name
44 .as_ref()
45 .map_or(true, |current_icon_name| {
46 current_icon_name != cursor_icon_name
47 });
48
49 if need_update {
50 if let Some(theme) = &mut self.theme {
51 let mut buffer: Option<&CursorImageBuffer>;
52
53 if let Some(cursor) = theme.get_cursor(&cursor_icon_name) {
54 buffer = Some(&cursor[0]);
55 } else if let Some(cursor) = theme.get_cursor("default") {
56 buffer = Some(&cursor[0]);
57 cursor_icon_name = "default";
58 log::warn!(
59 "Linux: Wayland: Unable to get cursor icon: {}. Using default cursor icon",
60 cursor_icon_name
61 );
62 } else {
63 buffer = None;
64 log::warn!("Linux: Wayland: Unable to get default cursor too!");
65 }
66
67 if let Some(buffer) = &mut buffer {
68 let (width, height) = buffer.dimensions();
69 let (hot_x, hot_y) = buffer.hotspot();
70
71 wl_pointer.set_cursor(
72 self.serial_id,
73 Some(&self.surface),
74 hot_x as i32,
75 hot_y as i32,
76 );
77 self.surface.attach(Some(&buffer), 0, 0);
78 self.surface.damage(0, 0, width as i32, height as i32);
79 self.surface.commit();
80
81 self.current_icon_name = Some(cursor_icon_name.to_string());
82 }
83 } else {
84 log::warn!("Linux: Wayland: Unable to load cursor themes");
85 }
86 }
87 }
88}