Skip to content

Commit

Permalink
X11: cache custom cursors
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Jan 5, 2024
1 parent 787b2d7 commit 2c8142d
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl Eq for OnlyCursorImage {}

#[allow(dead_code)]
impl OnlyCursorImage {
fn build<T>(
pub(crate) fn build<T>(
builder: OnlyCursorImageBuilder,
_: &platform_impl::EventLoopWindowTarget<T>,
) -> Self {
Expand Down
19 changes: 18 additions & 1 deletion src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<T>(
builder: PlatformCustomCursorBuilder,
p: &EventLoopWindowTarget<T>,
) -> 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<Mutex<Vec<XlibErrorHook>>> =
Expand Down
1 change: 1 addition & 0 deletions src/platform_impl/linux/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
4 changes: 2 additions & 2 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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),
}
}

Expand Down
22 changes: 17 additions & 5 deletions src/platform_impl/linux/wayland/window/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,15 +28,15 @@ 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;
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::{
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/platform_impl/linux/x11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ use x11rb::{
xcb_ffi::ReplyOrIdError,
};

pub(super) use self::util::CustomCursor;
use self::{
dnd::{Dnd, DndState},
event_processor::EventProcessor,
Expand Down
47 changes: 35 additions & 12 deletions src/platform_impl/linux/x11/util/cursor.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down Expand Up @@ -98,13 +106,36 @@ pub enum SelectedCursor {
Named(CursorIcon),
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone)]
pub struct CustomCursor {
inner: Arc<CustomCursorInner>,
}

impl Hash for CustomCursor {
fn hash<H: Hasher>(&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<XConnection>, image: &CursorImage) -> Self {
pub(crate) fn build<T>(
builder: PlatformCustomCursorBuilder,
p: &EventLoopWindowTarget<T>,
) -> 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);
Expand Down Expand Up @@ -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())
Expand Down
24 changes: 14 additions & 10 deletions src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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},
Expand All @@ -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,
Expand All @@ -43,7 +44,7 @@ use crate::{

use super::{
ffi,
util::{self, CustomCursor, SelectedCursor},
util::{self, SelectedCursor},
CookieResultExt, EventLoopWindowTarget, ImeRequest, ImeSender, VoidCookie, WindowId,
XConnection,
};
Expand Down Expand Up @@ -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"),
}
}

Expand Down

0 comments on commit 2c8142d

Please sign in to comment.