Skip to content

Commit

Permalink
Add custom cursor icon support on Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
rofferom committed Apr 19, 2022
1 parent b281123 commit 11a7e4f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 2 deletions.
42 changes: 41 additions & 1 deletion src/platform_impl/linux/x11/util/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::window::CursorIcon;
use std::slice;

use crate::window::{CursorIcon, CursorRgba};

use super::*;

Expand All @@ -13,6 +15,44 @@ impl XConnection {
self.update_cursor(window, cursor);
}

pub fn set_cursor_rgba(&self, window: ffi::Window, cursor: CursorRgba) {
// Create new cursor
let new_cursor = unsafe {
let image = (self.xcursor.XcursorImageCreate)(
cursor.width.into(),
cursor.height.into());
if image == ptr::null_mut() {
panic!("failed to allocate image for cursor");
}

(*image).xhot = cursor.xhot.into();
(*image).yhot = cursor.yhot.into();
(*image).delay = 0;

let dst = slice::from_raw_parts_mut(
(*image).pixels,
(cursor.width * cursor.height).into());

dst.copy_from_slice(cursor.data.as_slice());

let cursor = (self.xcursor.XcursorImageLoadCursor)(self.display, image);
(self.xcursor.XcursorImageDestroy)(image);

cursor
};

// Drop old cursor if required, and store the new one
let mut cursor_rgba = self.cursor_rgba.lock();
if let Some(old_cursor) = cursor_rgba.take() {
unsafe { (self.xlib.XFreeCursor)(self.display, old_cursor); }
}

*cursor_rgba = Some(new_cursor);

// Display
self.update_cursor(window, new_cursor);
}

fn create_empty_cursor(&self) -> ffi::Cursor {
let data = 0;
let pixmap = unsafe {
Expand Down
6 changes: 5 additions & 1 deletion src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,11 @@ impl UnownedWindow {
}

#[inline]
pub fn set_cursor_rgba(&self, _cursor: CursorRgba) {}
pub fn set_cursor_rgba(&self, cursor: CursorRgba) {
if *self.cursor_visible.lock() {
self.xconn.set_cursor_rgba(self.xwindow, cursor);
}
}

#[inline]
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/linux/x11/xdisplay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct XConnection {
pub x11_fd: c_int,
pub latest_error: Mutex<Option<XError>>,
pub cursor_cache: Mutex<HashMap<Option<CursorIcon>, ffi::Cursor>>,
pub cursor_rgba: Mutex<Option<ffi::Cursor>>,
}

unsafe impl Send for XConnection {}
Expand Down Expand Up @@ -68,6 +69,7 @@ impl XConnection {
x11_fd: fd,
latest_error: Mutex::new(None),
cursor_cache: Default::default(),
cursor_rgba: Mutex::new(None),
})
}

Expand Down Expand Up @@ -98,6 +100,10 @@ impl fmt::Debug for XConnection {
impl Drop for XConnection {
#[inline]
fn drop(&mut self) {
if let Some(cursor_rgba) = self.cursor_rgba.lock().take() {
unsafe { (self.xlib.XFreeCursor)(self.display, cursor_rgba); }
}

unsafe { (self.xlib.XCloseDisplay)(self.display) };
}
}
Expand Down

0 comments on commit 11a7e4f

Please sign in to comment.