Skip to content

Commit

Permalink
feat: load cursor from data
Browse files Browse the repository at this point in the history
I want to add a function to load cursor from data
  • Loading branch information
Decodetalkers committed Dec 9, 2023
1 parent fdd88c4 commit bf1e0b9
Showing 1 changed file with 74 additions and 0 deletions.
74 changes: 74 additions & 0 deletions wayland-cursor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
//! # }
//! ```

use std::borrow::Cow;
use std::env;
use std::fs::File;
use std::io::{Error as IoError, Read, Result as IoResult, Seek, SeekFrom, Write};
Expand Down Expand Up @@ -83,6 +84,22 @@ pub struct CursorTheme {
backend: WeakBackend,
}

/// An error that occurs when a binding a global fails.
#[derive(Debug)]
pub enum CursorLoadError {
/// When give a icon name, but XCursorTheme cannot find a path
IconPathNotFound(String),

/// When the path finded before, but it cannot be opened
IconFileCannotOpen(std::io::Error),

/// When the file is opened, but cannot get the data
IconFileNotReadable(std::io::Error),

/// When the data of icon is get, but xparser cannot parse it
IconFileNotParsable,
}

impl CursorTheme {
/// Load a cursor theme from system defaults.
///
Expand Down Expand Up @@ -177,6 +194,63 @@ impl CursorTheme {
}
}

/// try to load data from theme, else, it will try to load from fallback data
///
/// This method returns [`None`] if this cursor is not provided either by the theme, or by one of its parents,
/// and the data by fallback function cannot parse it
/// fallback function will receive a enum which discribe the error, you can print some messages
/// or do some other things before return the finally fallback data
pub fn get_cursor_with_default_data<F>(&mut self, name: &str, fallback: F) -> Option<&Cursor>
where
F: Fn(CursorLoadError) -> Cow<'static, [u8]>,
{
match self.cursors.iter().position(|cursor| cursor.name == name) {
Some(i) => Some(&self.cursors[i]),
None => {
let cursor = self.load_cursor_with_default_data(name, self.size, fallback)?;
self.cursors.push(cursor);
self.cursors.iter().last()
}
}
}

fn load_cursor_with_default_data<F>(
&mut self,
name: &str,
size: u32,
fallback: F,
) -> Option<Cursor>
where
F: Fn(CursorLoadError) -> Cow<'static, [u8]>,
{
let conn = Connection::from_backend(self.backend.upgrade()?);
let err_reason = 'fallback: {
let Some(icon_path) = XCursorTheme::load(&self.name).load_icon(name) else {
break 'fallback CursorLoadError::IconPathNotFound(name.to_owned());
};
let mut icon_file = match File::open(&icon_path) {
Ok(icon_file) => icon_file,
Err(e) => {
break 'fallback CursorLoadError::IconFileCannotOpen(e);
}
};
let mut buf = Vec::new();
let Some(images) = ({
if let Err(e) = icon_file.read_to_end(&mut buf) {
break 'fallback CursorLoadError::IconFileNotReadable(e);
}
xparser::parse_xcursor(&buf)
}) else {
break 'fallback CursorLoadError::IconFileNotParsable;
};

return Some(Cursor::new(&conn, name, self, &images, size));
};
let data = fallback(err_reason);
let images = xparser::parse_xcursor(data.as_ref())?;
Some(Cursor::new(&conn, name, self, &images, size))
}

/// This function loads a cursor, parses it and pushes the images onto the shm pool.
///
/// Keep in mind that if the cursor is already loaded, the function will make a duplicate.
Expand Down

0 comments on commit bf1e0b9

Please sign in to comment.