1use crate::Globals;
2use util::ResultExt;
3
4use wayland_client::protocol::wl_surface::WlSurface;
5use wayland_client::protocol::{wl_pointer::WlPointer, wl_shm::WlShm};
6use wayland_client::Connection;
7use wayland_cursor::{CursorImageBuffer, CursorTheme};
8
9pub(crate) struct Cursor {
10 theme: Option<CursorTheme>,
11 theme_name: Option<String>,
12 surface: WlSurface,
13 size: u32,
14 scale: u32,
15 shm: WlShm,
16 connection: Connection,
17}
18
19impl Drop for Cursor {
20 fn drop(&mut self) {
21 self.theme.take();
22 self.surface.destroy();
23 }
24}
25
26impl Cursor {
27 pub fn new(connection: &Connection, globals: &Globals, size: u32, scale: u32) -> Self {
28 Self {
29 theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
30 theme_name: None,
31 surface: globals.compositor.create_surface(&globals.qh, ()),
32 shm: globals.shm.clone(),
33 connection: connection.clone(),
34 size,
35 scale,
36 }
37 }
38
39 pub fn set_theme(&mut self, theme_name: &str, size: Option<u32>) {
40 if let Some(size) = size {
41 self.size = size;
42 }
43 if let Some(theme) = CursorTheme::load_from_name(
44 &self.connection,
45 self.shm.clone(),
46 theme_name,
47 self.size * self.scale,
48 )
49 .log_err()
50 {
51 self.theme = Some(theme);
52 self.theme_name = Some(theme_name.to_string());
53 } else if let Some(theme) =
54 CursorTheme::load(&self.connection, self.shm.clone(), self.size * self.scale).log_err()
55 {
56 self.theme = Some(theme);
57 self.theme_name = None;
58 }
59 }
60
61 pub fn set_size(&mut self, size: u32) {
62 self.size = size;
63 self.theme = self
64 .theme_name
65 .as_ref()
66 .and_then(|name| {
67 CursorTheme::load_from_name(
68 &self.connection,
69 self.shm.clone(),
70 name.as_str(),
71 self.size,
72 )
73 .log_err()
74 })
75 .or_else(|| CursorTheme::load(&self.connection, self.shm.clone(), self.size).log_err());
76 }
77
78 pub fn set_icon(&mut self, wl_pointer: &WlPointer, serial_id: u32, mut cursor_icon_name: &str) {
79 if let Some(theme) = &mut self.theme {
80 let mut buffer: Option<&CursorImageBuffer>;
81
82 if let Some(cursor) = theme.get_cursor(&cursor_icon_name) {
83 buffer = Some(&cursor[0]);
84 } else if let Some(cursor) = theme.get_cursor("default") {
85 buffer = Some(&cursor[0]);
86 cursor_icon_name = "default";
87 log::warn!(
88 "Linux: Wayland: Unable to get cursor icon: {}. Using default cursor icon",
89 cursor_icon_name
90 );
91 } else {
92 buffer = None;
93 log::warn!("Linux: Wayland: Unable to get default cursor too!");
94 }
95
96 if let Some(buffer) = &mut buffer {
97 let (width, height) = buffer.dimensions();
98 let (hot_x, hot_y) = buffer.hotspot();
99
100 let scaled_width = width / self.scale;
101 let scaled_height = height / self.scale;
102 let scaled_hot_x = hot_x / self.scale;
103 let scaled_hot_y = hot_y / self.scale;
104
105 self.surface.set_buffer_scale(self.scale as i32);
106
107 wl_pointer.set_cursor(
108 serial_id,
109 Some(&self.surface),
110 scaled_hot_x as i32,
111 scaled_hot_y as i32,
112 );
113 self.surface.attach(Some(&buffer), 0, 0);
114 self.surface
115 .damage(0, 0, scaled_width as i32, scaled_height as i32);
116 self.surface.commit();
117 }
118 } else {
119 log::warn!("Linux: Wayland: Unable to load cursor themes");
120 }
121 }
122}