cursor.rs

  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}