cursor.rs

  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}