diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index c6551a94d13..18effb7c6d9 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -1,4 +1,6 @@ -use crate::window::CursorIcon; +use std::slice; + +use crate::window::{CursorIcon, CursorRgba}; use super::*; @@ -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 { diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index c41dd2be6a4..e9bea2dfeb2 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -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> { diff --git a/src/platform_impl/linux/x11/xdisplay.rs b/src/platform_impl/linux/x11/xdisplay.rs index 25065f045df..ec2ec4c94d5 100644 --- a/src/platform_impl/linux/x11/xdisplay.rs +++ b/src/platform_impl/linux/x11/xdisplay.rs @@ -22,6 +22,7 @@ pub struct XConnection { pub x11_fd: c_int, pub latest_error: Mutex>, pub cursor_cache: Mutex, ffi::Cursor>>, + pub cursor_rgba: Mutex>, } unsafe impl Send for XConnection {} @@ -68,6 +69,7 @@ impl XConnection { x11_fd: fd, latest_error: Mutex::new(None), cursor_cache: Default::default(), + cursor_rgba: Mutex::new(None), }) } @@ -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) }; } }