Skip to content

Commit ff3b13d

Browse files
feat: load cursor from data (#680)
* 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>
1 parent 1fc7814 commit ff3b13d

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

wayland-cursor/src/lib.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@
4545
//! # }
4646
//! ```
4747
48+
use std::borrow::Cow;
4849
use std::env;
50+
use std::fmt::Debug;
4951
use std::fs::File;
5052
use std::io::{Error as IoError, Read, Result as IoResult, Seek, SeekFrom, Write};
5153
use std::ops::{Deref, Index};
@@ -81,6 +83,26 @@ pub struct CursorTheme {
8183
pool_size: i32,
8284
file: File,
8385
backend: WeakBackend,
86+
fallback: Option<FallBack>,
87+
}
88+
89+
type FallBackInner = Box<dyn Fn(&str, u32) -> Option<Cow<'static, [u8]>>>;
90+
91+
struct FallBack(FallBackInner);
92+
93+
impl FallBack {
94+
fn new<F>(fallback: F) -> Self
95+
where
96+
F: Fn(&str, u32) -> Option<Cow<'static, [u8]>> + 'static,
97+
{
98+
Self(Box::new(fallback))
99+
}
100+
}
101+
102+
impl Debug for FallBack {
103+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104+
f.write_str("fallback function")
105+
}
84106
}
85107

86108
impl CursorTheme {
@@ -160,23 +182,59 @@ impl CursorTheme {
160182
pool_size: INITIAL_POOL_SIZE,
161183
cursors: Vec::new(),
162184
backend: conn.backend().downgrade(),
185+
fallback: None,
163186
})
164187
}
165188

166189
/// Retrieve a cursor from the theme.
167190
///
168191
/// This method returns [`None`] if this cursor is not provided either by the theme, or by one of its parents.
192+
///
193+
/// If a fallback is set, it will use the data from fallback
169194
pub fn get_cursor(&mut self, name: &str) -> Option<&Cursor> {
170195
match self.cursors.iter().position(|cursor| cursor.name == name) {
171196
Some(i) => Some(&self.cursors[i]),
172197
None => {
173-
let cursor = self.load_cursor(name, self.size)?;
198+
let cursor = match self.load_cursor(name, self.size) {
199+
None => {
200+
let fallback = self.fallback.as_ref()?;
201+
let data = fallback.0(name, self.size)?;
202+
let images = xparser::parse_xcursor(&data)?;
203+
let conn = Connection::from_backend(self.backend.upgrade()?);
204+
Cursor::new(&conn, name, self, &images, self.size)
205+
}
206+
Some(cursor) => cursor,
207+
};
174208
self.cursors.push(cursor);
175209
self.cursors.iter().last()
176210
}
177211
}
178212
}
179213

214+
/// Set a callback to load the cursor data, in case the system theme is missing a cursor that you need.
215+
///
216+
/// Your callback will be invoked with he name and size of the requested cursor and should return a byte
217+
/// array with the contents of an `xcursor` file, or `None` if you don't provide a fallback for this cursor.
218+
///
219+
/// For example, this defines a generic fallback cursor image and uses it for all missing cursors:
220+
/// ```ignore
221+
/// # use wayland_cursor::CursorTheme;
222+
/// # use wayland_client::{Connection, backend::InvalidId, protocol::wl_shm};
223+
/// # fn example(conn: &Connection, shm: wl_shm::WlShm, size: u32) -> Result<CursorTheme, InvalidId> {
224+
/// # let mut theme = CursorTheme::load_or(conn, shm, "default", size)?;
225+
/// # theme.set_callback(|name, size| {
226+
/// # include_bytes!("./icons/default")
227+
/// # });
228+
/// # Ok(theme)
229+
/// # }
230+
/// ```
231+
pub fn set_callback<F>(&mut self, fallback: F)
232+
where
233+
F: Fn(&str, u32) -> Option<Cow<'static, [u8]>> + 'static,
234+
{
235+
self.fallback = Some(FallBack::new(fallback))
236+
}
237+
180238
/// This function loads a cursor, parses it and pushes the images onto the shm pool.
181239
///
182240
/// Keep in mind that if the cursor is already loaded, the function will make a duplicate.

0 commit comments

Comments
 (0)