cursor.rs

 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}