X11: cache custom cursors (#3366)
This commit is contained in:
parent
6b29253797
commit
d1717b6a01
8 changed files with 100 additions and 38 deletions
|
|
@ -213,7 +213,10 @@ impl Eq for OnlyCursorImage {}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl OnlyCursorImage {
|
impl OnlyCursorImage {
|
||||||
fn build(builder: OnlyCursorImageBuilder, _: &platform_impl::EventLoopWindowTarget) -> Self {
|
pub(crate) fn build(
|
||||||
|
builder: OnlyCursorImageBuilder,
|
||||||
|
_: &platform_impl::EventLoopWindowTarget,
|
||||||
|
) -> Self {
|
||||||
Self(Arc::new(builder.0))
|
Self(Arc::new(builder.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use self::common::keymap::{physicalkey_to_scancode, scancode_to_physicalkey};
|
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::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder;
|
||||||
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
||||||
pub(crate) use crate::platform_impl::Fullscreen;
|
pub(crate) use crate::platform_impl::Fullscreen;
|
||||||
|
|
@ -639,6 +638,29 @@ pub struct KeyEventExtra {
|
||||||
pub key_without_modifiers: Key,
|
pub key_without_modifiers: Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
|
pub(crate) enum PlatformCustomCursor {
|
||||||
|
#[cfg(wayland_platform)]
|
||||||
|
Wayland(wayland::CustomCursor),
|
||||||
|
#[cfg(x11_platform)]
|
||||||
|
X(x11::CustomCursor),
|
||||||
|
}
|
||||||
|
impl PlatformCustomCursor {
|
||||||
|
pub(crate) fn build(
|
||||||
|
builder: PlatformCustomCursorBuilder,
|
||||||
|
p: &EventLoopWindowTarget,
|
||||||
|
) -> PlatformCustomCursor {
|
||||||
|
match p {
|
||||||
|
#[cfg(wayland_platform)]
|
||||||
|
EventLoopWindowTarget::Wayland(_) => {
|
||||||
|
Self::Wayland(wayland::CustomCursor::build(builder, p))
|
||||||
|
}
|
||||||
|
#[cfg(x11_platform)]
|
||||||
|
EventLoopWindowTarget::X(p) => Self::X(x11::CustomCursor::build(builder, p)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Hooks for X11 errors.
|
/// Hooks for X11 errors.
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
pub(crate) static mut XLIB_ERROR_HOOKS: Lazy<Mutex<Vec<XlibErrorHook>>> =
|
pub(crate) static mut XLIB_ERROR_HOOKS: Lazy<Mutex<Vec<XlibErrorHook>>> =
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use sctk::reexports::client::globals::{BindError, GlobalError};
|
||||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||||
use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy};
|
use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy};
|
||||||
|
|
||||||
|
pub(super) use crate::cursor::OnlyCursorImage as CustomCursor;
|
||||||
use crate::dpi::{LogicalSize, PhysicalSize};
|
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||||
pub use crate::platform_impl::platform::{OsError, WindowId};
|
pub use crate::platform_impl::platform::{OsError, WindowId};
|
||||||
pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ impl Window {
|
||||||
|
|
||||||
match attributes.cursor {
|
match attributes.cursor {
|
||||||
Cursor::Icon(icon) => window_state.set_cursor(icon),
|
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.
|
// Activate the window when the token is passed.
|
||||||
|
|
@ -514,7 +514,7 @@ impl Window {
|
||||||
|
|
||||||
match cursor {
|
match cursor {
|
||||||
Cursor::Icon(icon) => window_state.set_cursor(icon),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use sctk::shm::Shm;
|
||||||
use sctk::subcompositor::SubcompositorState;
|
use sctk::subcompositor::SubcompositorState;
|
||||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
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::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size};
|
||||||
use crate::error::{ExternalError, NotSupportedError};
|
use crate::error::{ExternalError, NotSupportedError};
|
||||||
use crate::event::WindowEvent;
|
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::cursor::{CustomCursor, SelectedCursor};
|
||||||
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
||||||
use crate::platform_impl::wayland::{logical_to_physical_rounded, make_wid};
|
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::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
|
||||||
|
|
||||||
use crate::platform_impl::wayland::seat::{
|
use crate::platform_impl::wayland::seat::{
|
||||||
|
|
@ -726,10 +726,23 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the custom cursor icon.
|
/// 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,
|
||||||
|
#[cfg(x11_platform)]
|
||||||
|
RootCustomCursor {
|
||||||
|
inner: PlatformCustomCursor::X(_),
|
||||||
|
} => {
|
||||||
|
log::error!("passed a X11 cursor to Wayland backend");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let cursor = {
|
let cursor = {
|
||||||
let mut pool = self.custom_cursor_pool.lock().unwrap();
|
let mut pool = self.custom_cursor_pool.lock().unwrap();
|
||||||
CustomCursor::new(&mut pool, cursor)
|
CustomCursor::new(&mut pool, &cursor)
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.cursor_visible {
|
if self.cursor_visible {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ use x11rb::{
|
||||||
xcb_ffi::ReplyOrIdError,
|
xcb_ffi::ReplyOrIdError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(super) use self::util::CustomCursor;
|
||||||
use self::{
|
use self::{
|
||||||
dnd::{Dnd, DndState},
|
dnd::{Dnd, DndState},
|
||||||
event_processor::EventProcessor,
|
event_processor::EventProcessor,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
use std::{ffi::CString, iter, slice, sync::Arc};
|
use std::{
|
||||||
|
ffi::CString,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
iter, slice,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use x11rb::connection::Connection;
|
use x11rb::connection::Connection;
|
||||||
|
|
||||||
use crate::{cursor::CursorImage, window::CursorIcon};
|
use crate::{platform_impl::PlatformCustomCursorBuilder, window::CursorIcon};
|
||||||
|
|
||||||
|
use super::super::EventLoopWindowTarget;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl XConnection {
|
impl XConnection {
|
||||||
|
|
@ -98,36 +104,55 @@ pub enum SelectedCursor {
|
||||||
Named(CursorIcon),
|
Named(CursorIcon),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CustomCursor {
|
pub struct CustomCursor {
|
||||||
inner: Arc<CustomCursorInner>,
|
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 {
|
impl CustomCursor {
|
||||||
pub(crate) unsafe fn new(xconn: &Arc<XConnection>, image: &CursorImage) -> Self {
|
pub(crate) fn build(
|
||||||
|
builder: PlatformCustomCursorBuilder,
|
||||||
|
p: &EventLoopWindowTarget,
|
||||||
|
) -> CustomCursor {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ximage =
|
let ximage = (p.xconn.xcursor.XcursorImageCreate)(
|
||||||
(xconn.xcursor.XcursorImageCreate)(image.width as i32, image.height as i32);
|
builder.0.width as i32,
|
||||||
|
builder.0.height as i32,
|
||||||
|
);
|
||||||
if ximage.is_null() {
|
if ximage.is_null() {
|
||||||
panic!("failed to allocate cursor image");
|
panic!("failed to allocate cursor image");
|
||||||
}
|
}
|
||||||
(*ximage).xhot = image.hotspot_x as u32;
|
(*ximage).xhot = builder.0.hotspot_x as u32;
|
||||||
(*ximage).yhot = image.hotspot_y as u32;
|
(*ximage).yhot = builder.0.hotspot_y as u32;
|
||||||
(*ximage).delay = 0;
|
(*ximage).delay = 0;
|
||||||
|
|
||||||
let dst = slice::from_raw_parts_mut((*ximage).pixels, image.rgba.len() / 4);
|
let dst = slice::from_raw_parts_mut((*ximage).pixels, builder.0.rgba.len() / 4);
|
||||||
for (dst, chunk) in dst.iter_mut().zip(image.rgba.chunks_exact(4)) {
|
for (dst, chunk) in dst.iter_mut().zip(builder.0.rgba.chunks_exact(4)) {
|
||||||
*dst = (chunk[0] as u32) << 16
|
*dst = (chunk[0] as u32) << 16
|
||||||
| (chunk[1] as u32) << 8
|
| (chunk[1] as u32) << 8
|
||||||
| (chunk[2] as u32)
|
| (chunk[2] as u32)
|
||||||
| (chunk[3] as u32) << 24;
|
| (chunk[3] as u32) << 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cursor = (xconn.xcursor.XcursorImageLoadCursor)(xconn.display, ximage);
|
let cursor = (p.xconn.xcursor.XcursorImageLoadCursor)(p.xconn.display, ximage);
|
||||||
(xconn.xcursor.XcursorImageDestroy)(ximage);
|
(p.xconn.xcursor.XcursorImageDestroy)(ximage);
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(CustomCursorInner {
|
inner: Arc::new(CustomCursorInner {
|
||||||
xconn: xconn.clone(),
|
xconn: p.xconn.clone(),
|
||||||
cursor,
|
cursor,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
@ -149,14 +174,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 {
|
impl Default for SelectedCursor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
SelectedCursor::Named(Default::default())
|
SelectedCursor::Named(Default::default())
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ use x11rb::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cursor::Cursor,
|
cursor::{Cursor, CustomCursor as RootCustomCursor},
|
||||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
event::{Event, InnerSizeWriter, WindowEvent},
|
event::{Event, InnerSizeWriter, WindowEvent},
|
||||||
|
|
@ -32,8 +32,9 @@ use crate::{
|
||||||
atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender,
|
atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender,
|
||||||
X11Error,
|
X11Error,
|
||||||
},
|
},
|
||||||
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformIcon,
|
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
|
||||||
PlatformSpecificWindowBuilderAttributes, VideoModeHandle as PlatformVideoModeHandle,
|
PlatformIcon, PlatformSpecificWindowBuilderAttributes,
|
||||||
|
VideoModeHandle as PlatformVideoModeHandle,
|
||||||
},
|
},
|
||||||
window::{
|
window::{
|
||||||
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
|
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
|
||||||
|
|
@ -43,7 +44,7 @@ use crate::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ffi,
|
ffi,
|
||||||
util::{self, CustomCursor, SelectedCursor},
|
util::{self, SelectedCursor},
|
||||||
CookieResultExt, EventLoopWindowTarget, ImeRequest, ImeSender, VoidCookie, WindowId,
|
CookieResultExt, EventLoopWindowTarget, ImeRequest, ImeSender, VoidCookie, WindowId,
|
||||||
XConnection,
|
XConnection,
|
||||||
};
|
};
|
||||||
|
|
@ -1552,16 +1553,20 @@ impl UnownedWindow {
|
||||||
self.xconn.set_cursor_icon(self.xwindow, Some(icon));
|
self.xconn.set_cursor_icon(self.xwindow, Some(icon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cursor::Custom(cursor) => {
|
Cursor::Custom(RootCustomCursor {
|
||||||
let new_cursor = unsafe { CustomCursor::new(&self.xconn, &cursor.inner.0) };
|
inner: PlatformCustomCursor::X(cursor),
|
||||||
|
}) => {
|
||||||
#[allow(clippy::mutex_atomic)]
|
#[allow(clippy::mutex_atomic)]
|
||||||
if *self.cursor_visible.lock().unwrap() {
|
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);
|
||||||
}
|
}
|
||||||
|
#[cfg(wayland_platform)]
|
||||||
|
Cursor::Custom(RootCustomCursor {
|
||||||
|
inner: PlatformCustomCursor::Wayland(_),
|
||||||
|
}) => log::error!("passed a Wayland cursor to X11 backend"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue