X11: cache custom cursors (#3366)
This commit is contained in:
parent
6b29253797
commit
d1717b6a01
8 changed files with 100 additions and 38 deletions
|
|
@ -60,6 +60,7 @@ use x11rb::{
|
|||
xcb_ffi::ReplyOrIdError,
|
||||
};
|
||||
|
||||
pub(super) use self::util::CustomCursor;
|
||||
use self::{
|
||||
dnd::{Dnd, DndState},
|
||||
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 crate::{cursor::CursorImage, window::CursorIcon};
|
||||
use crate::{platform_impl::PlatformCustomCursorBuilder, window::CursorIcon};
|
||||
|
||||
use super::super::EventLoopWindowTarget;
|
||||
use super::*;
|
||||
|
||||
impl XConnection {
|
||||
|
|
@ -98,36 +104,55 @@ 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(
|
||||
builder: PlatformCustomCursorBuilder,
|
||||
p: &EventLoopWindowTarget,
|
||||
) -> CustomCursor {
|
||||
unsafe {
|
||||
let ximage =
|
||||
(xconn.xcursor.XcursorImageCreate)(image.width as i32, image.height as i32);
|
||||
let ximage = (p.xconn.xcursor.XcursorImageCreate)(
|
||||
builder.0.width as i32,
|
||||
builder.0.height as i32,
|
||||
);
|
||||
if ximage.is_null() {
|
||||
panic!("failed to allocate cursor image");
|
||||
}
|
||||
(*ximage).xhot = image.hotspot_x as u32;
|
||||
(*ximage).yhot = image.hotspot_y as u32;
|
||||
(*ximage).xhot = builder.0.hotspot_x as u32;
|
||||
(*ximage).yhot = builder.0.hotspot_y as u32;
|
||||
(*ximage).delay = 0;
|
||||
|
||||
let dst = slice::from_raw_parts_mut((*ximage).pixels, image.rgba.len() / 4);
|
||||
for (dst, chunk) in dst.iter_mut().zip(image.rgba.chunks_exact(4)) {
|
||||
let dst = slice::from_raw_parts_mut((*ximage).pixels, builder.0.rgba.len() / 4);
|
||||
for (dst, chunk) in dst.iter_mut().zip(builder.0.rgba.chunks_exact(4)) {
|
||||
*dst = (chunk[0] as u32) << 16
|
||||
| (chunk[1] as u32) << 8
|
||||
| (chunk[2] as u32)
|
||||
| (chunk[3] as u32) << 24;
|
||||
}
|
||||
|
||||
let cursor = (xconn.xcursor.XcursorImageLoadCursor)(xconn.display, ximage);
|
||||
(xconn.xcursor.XcursorImageDestroy)(ximage);
|
||||
let cursor = (p.xconn.xcursor.XcursorImageLoadCursor)(p.xconn.display, ximage);
|
||||
(p.xconn.xcursor.XcursorImageDestroy)(ximage);
|
||||
Self {
|
||||
inner: Arc::new(CustomCursorInner {
|
||||
xconn: xconn.clone(),
|
||||
xconn: p.xconn.clone(),
|
||||
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 {
|
||||
fn default() -> Self {
|
||||
SelectedCursor::Named(Default::default())
|
||||
|
|
|
|||
|
|
@ -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,20 @@ 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::X(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);
|
||||
}
|
||||
#[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