Skip to content

Commit

Permalink
feat: load cursor from data (#680)
Browse files Browse the repository at this point in the history
* feat: load cursor from data

I want to add a function to load cursor from data

* chore: add documents and size parm input

* Update wayland-cursor/src/lib.rs

Co-authored-by: Elinor B. <3009227+elinorbgr@users.noreply.github.com>

* chore: make clippy happy

---------

Co-authored-by: Elinor B. <3009227+elinorbgr@users.noreply.github.com>
  • Loading branch information
Decodetalkers and elinorbgr authored Apr 29, 2024
1 parent 1fc7814 commit ff3b13d
Showing 1 changed file with 59 additions and 1 deletion.
60 changes: 59 additions & 1 deletion wayland-cursor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
//! # }
//! ```

use std::borrow::Cow;
use std::env;
use std::fmt::Debug;
use std::fs::File;
use std::io::{Error as IoError, Read, Result as IoResult, Seek, SeekFrom, Write};
use std::ops::{Deref, Index};
Expand Down Expand Up @@ -81,6 +83,26 @@ pub struct CursorTheme {
pool_size: i32,
file: File,
backend: WeakBackend,
fallback: Option<FallBack>,
}

type FallBackInner = Box<dyn Fn(&str, u32) -> Option<Cow<'static, [u8]>>>;

struct FallBack(FallBackInner);

impl FallBack {
fn new<F>(fallback: F) -> Self
where
F: Fn(&str, u32) -> Option<Cow<'static, [u8]>> + 'static,
{
Self(Box::new(fallback))
}
}

impl Debug for FallBack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("fallback function")
}
}

impl CursorTheme {
Expand Down Expand Up @@ -160,23 +182,59 @@ impl CursorTheme {
pool_size: INITIAL_POOL_SIZE,
cursors: Vec::new(),
backend: conn.backend().downgrade(),
fallback: None,
})
}

/// Retrieve a cursor from the theme.
///
/// This method returns [`None`] if this cursor is not provided either by the theme, or by one of its parents.
///
/// If a fallback is set, it will use the data from fallback
pub fn get_cursor(&mut self, name: &str) -> Option<&Cursor> {
match self.cursors.iter().position(|cursor| cursor.name == name) {
Some(i) => Some(&self.cursors[i]),
None => {
let cursor = self.load_cursor(name, self.size)?;
let cursor = match self.load_cursor(name, self.size) {
None => {
let fallback = self.fallback.as_ref()?;
let data = fallback.0(name, self.size)?;
let images = xparser::parse_xcursor(&data)?;
let conn = Connection::from_backend(self.backend.upgrade()?);
Cursor::new(&conn, name, self, &images, self.size)
}
Some(cursor) => cursor,
};
self.cursors.push(cursor);
self.cursors.iter().last()
}
}
}

/// Set a callback to load the cursor data, in case the system theme is missing a cursor that you need.
///
/// Your callback will be invoked with he name and size of the requested cursor and should return a byte
/// array with the contents of an `xcursor` file, or `None` if you don't provide a fallback for this cursor.
///
/// For example, this defines a generic fallback cursor image and uses it for all missing cursors:
/// ```ignore
/// # use wayland_cursor::CursorTheme;
/// # use wayland_client::{Connection, backend::InvalidId, protocol::wl_shm};
/// # fn example(conn: &Connection, shm: wl_shm::WlShm, size: u32) -> Result<CursorTheme, InvalidId> {
/// # let mut theme = CursorTheme::load_or(conn, shm, "default", size)?;
/// # theme.set_callback(|name, size| {
/// # include_bytes!("./icons/default")
/// # });
/// # Ok(theme)
/// # }
/// ```
pub fn set_callback<F>(&mut self, fallback: F)
where
F: Fn(&str, u32) -> Option<Cow<'static, [u8]>> + 'static,
{
self.fallback = Some(FallBack::new(fallback))
}

/// 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 ff3b13d

Please sign in to comment.