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