diff --git a/src/cursor.rs b/src/cursor.rs index b11104ee3e7..1a417f4dde7 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -213,7 +213,7 @@ impl Eq for OnlyCursorImage {} #[allow(dead_code)] impl OnlyCursorImage { - fn build( + pub(crate) fn build( builder: OnlyCursorImageBuilder, _: &platform_impl::EventLoopWindowTarget, ) -> Self { diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 4555751acbe..4d9595bb7d8 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -35,7 +35,6 @@ use crate::{ }; pub(crate) use self::common::keymap::{physicalkey_to_scancode, scancode_to_physicalkey}; -pub(crate) use crate::cursor::OnlyCursorImage as PlatformCustomCursor; pub(crate) use crate::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder; pub(crate) use crate::icon::RgbaIcon as PlatformIcon; pub(crate) use crate::platform_impl::Fullscreen; @@ -639,6 +638,24 @@ pub struct KeyEventExtra { pub key_without_modifiers: Key, } +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(crate) enum PlatformCustomCursor { + Wayland(wayland::CustomCursor), + X11(x11::CustomCursor), +} +impl PlatformCustomCursor { + pub(crate) fn build( + builder: PlatformCustomCursorBuilder, + p: &EventLoopWindowTarget, + ) -> PlatformCustomCursor { + if p.is_wayland() { + Self::Wayland(wayland::CustomCursor::build(builder, p)) + } else { + Self::X11(x11::CustomCursor::build(builder, p)) + } + } +} + /// Hooks for X11 errors. #[cfg(x11_platform)] pub(crate) static mut XLIB_ERROR_HOOKS: Lazy>> = diff --git a/src/platform_impl/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs index 4a86aff5f33..2c0d6b5d3dd 100644 --- a/src/platform_impl/linux/wayland/mod.rs +++ b/src/platform_impl/linux/wayland/mod.rs @@ -9,6 +9,7 @@ use sctk::reexports::client::globals::{BindError, GlobalError}; use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy}; +pub(super) use crate::cursor::OnlyCursorImage as CustomCursor; use crate::dpi::{LogicalSize, PhysicalSize}; pub use crate::platform_impl::platform::{OsError, WindowId}; pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 8074920259e..0bd66c17e17 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -171,7 +171,7 @@ impl Window { match attributes.cursor { Cursor::Icon(icon) => window_state.set_cursor(icon), - Cursor::Custom(cursor) => window_state.set_custom_cursor(&cursor.inner.0), + Cursor::Custom(cursor) => window_state.set_custom_cursor(cursor), } // Activate the window when the token is passed. @@ -514,7 +514,7 @@ impl Window { match cursor { Cursor::Icon(icon) => window_state.set_cursor(icon), - Cursor::Custom(cursor) => window_state.set_custom_cursor(&cursor.inner.0), + Cursor::Custom(cursor) => window_state.set_custom_cursor(cursor), } } diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index b540a8d2e06..01194b79067 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -4,7 +4,7 @@ use std::num::NonZeroU32; use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; -use log::{info, warn}; +use log::{error, info, warn}; use sctk::reexports::client::protocol::wl_seat::WlSeat; use sctk::reexports::client::protocol::wl_shm::WlShm; @@ -28,7 +28,7 @@ use sctk::shm::Shm; use sctk::subcompositor::SubcompositorState; use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur; -use crate::cursor::CursorImage; +use crate::cursor::CustomCursor as RootCustomCursor; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size}; use crate::error::{ExternalError, NotSupportedError}; use crate::event::WindowEvent; @@ -36,7 +36,7 @@ use crate::platform_impl::wayland::event_loop::sink::EventSink; use crate::platform_impl::wayland::types::cursor::{CustomCursor, SelectedCursor}; use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager; use crate::platform_impl::wayland::{logical_to_physical_rounded, make_wid}; -use crate::platform_impl::WindowId; +use crate::platform_impl::{PlatformCustomCursor, WindowId}; use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme}; use crate::platform_impl::wayland::seat::{ @@ -726,10 +726,22 @@ impl WindowState { } /// Set the custom cursor icon. - pub(crate) fn set_custom_cursor(&mut self, cursor: &CursorImage) { + pub(crate) fn set_custom_cursor(&mut self, cursor: RootCustomCursor) { + let cursor = match cursor { + RootCustomCursor { + inner: PlatformCustomCursor::Wayland(cursor), + } => cursor.0, + RootCustomCursor { + inner: PlatformCustomCursor::X11(_), + } => { + error!("passed a X11 cursor to Wayland backend"); + return; + } + }; + let cursor = { let mut pool = self.custom_cursor_pool.lock().unwrap(); - CustomCursor::new(&mut pool, cursor) + CustomCursor::new(&mut pool, &cursor) }; if self.cursor_visible { diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 395668c37a8..8bc31351621 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -59,6 +59,7 @@ use x11rb::{ xcb_ffi::ReplyOrIdError, }; +pub(super) use self::util::CustomCursor; use self::{ dnd::{Dnd, DndState}, event_processor::EventProcessor, diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index 5650aadcf30..82badccab0c 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -1,8 +1,16 @@ -use std::{ffi::CString, iter, slice, sync::Arc}; +use std::{ + ffi::CString, + hash::{Hash, Hasher}, + iter, slice, + sync::Arc, +}; use x11rb::connection::Connection; -use crate::{cursor::CursorImage, window::CursorIcon}; +use crate::{ + platform_impl::{EventLoopWindowTarget, PlatformCustomCursorBuilder}, + window::CursorIcon, +}; use super::*; @@ -98,13 +106,36 @@ pub enum SelectedCursor { Named(CursorIcon), } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct CustomCursor { inner: Arc, } +impl Hash for CustomCursor { + fn hash(&self, state: &mut H) { + Arc::as_ptr(&self.inner).hash(state); + } +} + +impl PartialEq for CustomCursor { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.inner, &other.inner) + } +} + +impl Eq for CustomCursor {} + impl CustomCursor { - pub(crate) unsafe fn new(xconn: &Arc, image: &CursorImage) -> Self { + pub(crate) fn build( + builder: PlatformCustomCursorBuilder, + p: &EventLoopWindowTarget, + ) -> CustomCursor { + let image = builder.0; + let EventLoopWindowTarget::X(elwt) = p else { + unreachable!("called from Wayland backend"); + }; + let xconn = &elwt.xconn; + unsafe { let ximage = (xconn.xcursor.XcursorImageCreate)(image.width as i32, image.height as i32); @@ -149,14 +180,6 @@ impl Drop for CustomCursorInner { } } -impl PartialEq for CustomCursorInner { - fn eq(&self, other: &Self) -> bool { - self.cursor == other.cursor - } -} - -impl Eq for CustomCursorInner {} - impl Default for SelectedCursor { fn default() -> Self { SelectedCursor::Named(Default::default()) diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index ddf96542b2a..a568d113349 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -7,7 +7,7 @@ use std::{ sync::{Arc, Mutex, MutexGuard}, }; -use log::{debug, info, warn}; +use log::{debug, error, info, warn}; use x11rb::{ connection::Connection, properties::{WmHints, WmSizeHints, WmSizeHintsSpecification}, @@ -21,7 +21,7 @@ use x11rb::{ }; use crate::{ - cursor::Cursor, + cursor::{Cursor, CustomCursor as RootCustomCursor}, dpi::{PhysicalPosition, PhysicalSize, Position, Size}, error::{ExternalError, NotSupportedError, OsError as RootOsError}, event::{Event, InnerSizeWriter, WindowEvent}, @@ -32,8 +32,9 @@ use crate::{ atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error, }, - Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformIcon, - PlatformSpecificWindowBuilderAttributes, VideoModeHandle as PlatformVideoModeHandle, + Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor, + PlatformIcon, PlatformSpecificWindowBuilderAttributes, + VideoModeHandle as PlatformVideoModeHandle, }, window::{ CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, @@ -43,7 +44,7 @@ use crate::{ use super::{ ffi, - util::{self, CustomCursor, SelectedCursor}, + util::{self, SelectedCursor}, CookieResultExt, EventLoopWindowTarget, ImeRequest, ImeSender, VoidCookie, WindowId, XConnection, }; @@ -1552,16 +1553,19 @@ impl UnownedWindow { self.xconn.set_cursor_icon(self.xwindow, Some(icon)); } } - Cursor::Custom(cursor) => { - let new_cursor = unsafe { CustomCursor::new(&self.xconn, &cursor.inner.0) }; - + Cursor::Custom(RootCustomCursor { + inner: PlatformCustomCursor::X11(cursor), + }) => { #[allow(clippy::mutex_atomic)] if *self.cursor_visible.lock().unwrap() { - self.xconn.set_custom_cursor(self.xwindow, &new_cursor); + self.xconn.set_custom_cursor(self.xwindow, &cursor); } - *self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(new_cursor); + *self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(cursor); } + Cursor::Custom(RootCustomCursor { + inner: PlatformCustomCursor::Wayland(_), + }) => error!("passed a Wayland cursor to X11 backend"), } }