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 shm: WlShm,
15 connection: Connection,
16}
17
18impl Drop for Cursor {
19 fn drop(&mut self) {
20 self.theme.take();
21 self.surface.destroy();
22 }
23}
24
25impl Cursor {
26 pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
27 Self {
28 theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
29 theme_name: None,
30 surface: globals.compositor.create_surface(&globals.qh, ()),
31 shm: globals.shm.clone(),
32 connection: connection.clone(),
33 size,
34 }
35 }
36
37 pub fn set_theme(&mut self, theme_name: &str, size: Option<u32>) {
38 if let Some(size) = size {
39 self.size = size;
40 }
41 if let Some(theme) =
42 CursorTheme::load_from_name(&self.connection, self.shm.clone(), theme_name, self.size)
43 .log_err()
44 {
45 self.theme = Some(theme);
46 self.theme_name = Some(theme_name.to_string());
47 } else if let Some(theme) =
48 CursorTheme::load(&self.connection, self.shm.clone(), self.size).log_err()
49 {
50 self.theme = Some(theme);
51 self.theme_name = None;
52 }
53 }
54
55 pub fn set_size(&mut self, size: u32) {
56 self.size = size;
57 self.theme = self
58 .theme_name
59 .as_ref()
60 .and_then(|name| {
61 CursorTheme::load_from_name(
62 &self.connection,
63 self.shm.clone(),
64 name.as_str(),
65 self.size,
66 )
67 .log_err()
68 })
69 .or_else(|| CursorTheme::load(&self.connection, self.shm.clone(), self.size).log_err());
70 }
71
72 pub fn set_icon(&mut self, wl_pointer: &WlPointer, serial_id: u32, mut cursor_icon_name: &str) {
73 if let Some(theme) = &mut self.theme {
74 let mut buffer: Option<&CursorImageBuffer>;
75
76 if let Some(cursor) = theme.get_cursor(&cursor_icon_name) {
77 buffer = Some(&cursor[0]);
78 } else if let Some(cursor) = theme.get_cursor("default") {
79 buffer = Some(&cursor[0]);
80 cursor_icon_name = "default";
81 log::warn!(
82 "Linux: Wayland: Unable to get cursor icon: {}. Using default cursor icon",
83 cursor_icon_name
84 );
85 } else {
86 buffer = None;
87 log::warn!("Linux: Wayland: Unable to get default cursor too!");
88 }
89
90 if let Some(buffer) = &mut buffer {
91 let (width, height) = buffer.dimensions();
92 let (hot_x, hot_y) = buffer.hotspot();
93
94 wl_pointer.set_cursor(serial_id, Some(&self.surface), hot_x as i32, hot_y as i32);
95 self.surface.attach(Some(&buffer), 0, 0);
96 self.surface.damage(0, 0, width as i32, height as i32);
97 self.surface.commit();
98 }
99 } else {
100 log::warn!("Linux: Wayland: Unable to load cursor themes");
101 }
102 }
103}