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