cursor: refactor CustomCursor to be dyn
cursor: refactor `CustomCursor` to be `dyn` Same as for `MonitorHandle`, the source was changed to support all kinds of sources.
This commit is contained in:
parent
a0464ae83b
commit
ae28eea406
26 changed files with 329 additions and 333 deletions
|
|
@ -20,6 +20,7 @@ use crate::event_loop::{
|
|||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
};
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::window::{
|
||||
|
|
@ -29,11 +30,6 @@ use crate::window::{
|
|||
|
||||
mod keycodes;
|
||||
|
||||
pub(crate) use crate::cursor::{
|
||||
NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
|
||||
};
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
||||
static HAS_FOCUS: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
/// Returns the minimum `Option<Duration>`, taking into account that `None`
|
||||
|
|
|
|||
|
|
@ -10,21 +10,34 @@ use objc2_foundation::{
|
|||
ns_string, NSData, NSDictionary, NSNumber, NSObject, NSPoint, NSSize, NSString,
|
||||
};
|
||||
|
||||
use crate::cursor::{CursorImage, OnlyCursorImageSource};
|
||||
use crate::error::RequestError;
|
||||
use crate::cursor::{CursorImage, CustomCursorProvider, CustomCursorSource};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::window::CursorIcon;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct CustomCursor(pub(crate) Retained<NSCursor>);
|
||||
|
||||
impl CustomCursorProvider for CustomCursor {
|
||||
fn is_animated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: NSCursor is immutable and thread-safe
|
||||
// TODO(madsmtm): Put this logic in objc2-app-kit itself
|
||||
unsafe impl Send for CustomCursor {}
|
||||
unsafe impl Sync for CustomCursor {}
|
||||
|
||||
impl CustomCursor {
|
||||
pub(crate) fn new(cursor: OnlyCursorImageSource) -> Result<CustomCursor, RequestError> {
|
||||
cursor_from_image(&cursor.0).map(Self)
|
||||
pub(crate) fn new(cursor: CustomCursorSource) -> Result<CustomCursor, RequestError> {
|
||||
let cursor = match cursor {
|
||||
CustomCursorSource::Image(cursor_image) => cursor_image,
|
||||
CustomCursorSource::Animation { .. } | CustomCursorSource::Url { .. } => {
|
||||
return Err(NotSupportedError::new("unsupported cursor kind").into())
|
||||
},
|
||||
};
|
||||
|
||||
cursor_from_image(&cursor).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use crate::monitor::MonitorHandle as CoreMonitorHandle;
|
|||
use crate::platform::macos::ActivationPolicy;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::platform_impl::Window;
|
||||
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme};
|
||||
use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PanicInfo {
|
||||
|
|
@ -110,8 +110,8 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
|||
fn create_custom_cursor(
|
||||
&self,
|
||||
source: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, RequestError> {
|
||||
Ok(RootCustomCursor { inner: CustomCursor::new(source.inner)? })
|
||||
) -> Result<CoreCustomCursor, RequestError> {
|
||||
Ok(CoreCustomCursor(Arc::new(CustomCursor::new(source)?)))
|
||||
}
|
||||
|
||||
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ mod view;
|
|||
mod window;
|
||||
mod window_delegate;
|
||||
|
||||
pub(crate) use self::cursor::CustomCursor as PlatformCustomCursor;
|
||||
pub(crate) use self::event::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes,
|
||||
|
|
@ -22,5 +21,4 @@ pub(crate) use self::event_loop::{
|
|||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::Window;
|
||||
pub(crate) use self::window_delegate::PlatformSpecificWindowAttributes;
|
||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ use objc2_foundation::{
|
|||
use tracing::{trace, warn};
|
||||
|
||||
use super::app_state::AppState;
|
||||
use super::cursor::cursor_from_icon;
|
||||
use super::cursor::{cursor_from_icon, CustomCursor};
|
||||
use super::monitor::{self, flip_window_screen_coordinates, get_display_id};
|
||||
use super::observer::RunLoop;
|
||||
use super::util::cgerr;
|
||||
|
|
@ -1249,7 +1249,13 @@ impl WindowDelegate {
|
|||
|
||||
let cursor = match cursor {
|
||||
Cursor::Icon(icon) => cursor_from_icon(icon),
|
||||
Cursor::Custom(cursor) => cursor.inner.0,
|
||||
Cursor::Custom(cursor) => match cursor.cast_ref::<CustomCursor>() {
|
||||
Some(cursor) => cursor.0.clone(),
|
||||
None => {
|
||||
tracing::error!("unrecognized cursor passed to macOS backend");
|
||||
return;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if view.cursor_icon() == cursor {
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@ pub(crate) use self::event_loop::{
|
|||
};
|
||||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::{PlatformSpecificWindowAttributes, Window};
|
||||
pub(crate) use crate::cursor::{
|
||||
NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
|
||||
};
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use std::time::Duration;
|
|||
|
||||
pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
use crate::application::ApplicationHandler;
|
||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||
#[cfg(x11_platform)]
|
||||
use crate::dpi::Size;
|
||||
use crate::error::{EventLoopError, NotSupportedError};
|
||||
|
|
@ -120,14 +119,6 @@ macro_rules! x11_or_wayland {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub(crate) enum PlatformCustomCursor {
|
||||
#[cfg(wayland_platform)]
|
||||
Wayland(wayland::CustomCursor),
|
||||
#[cfg(x11_platform)]
|
||||
X(x11::CustomCursor),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EventLoop {
|
||||
#[cfg(wayland_platform)]
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ use sctk::reexports::calloop_wayland_source::WaylandSource;
|
|||
use sctk::reexports::client::{globals, Connection, QueueHandle};
|
||||
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::cursor::OnlyCursorImage;
|
||||
use crate::dpi::LogicalSize;
|
||||
use crate::error::{EventLoopError, OsError, RequestError};
|
||||
use crate::error::{EventLoopError, NotSupportedError, OsError, RequestError};
|
||||
use crate::event::{DeviceEvent, StartCause, SurfaceSizeWriter, WindowEvent};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
|
|
@ -23,8 +22,8 @@ use crate::event_loop::{
|
|||
use crate::monitor::MonitorHandle as CoreMonitorHandle;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::platform_impl::platform::min_timeout;
|
||||
use crate::platform_impl::PlatformCustomCursor;
|
||||
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme};
|
||||
use crate::platform_impl::wayland::types::cursor::WaylandCustomCursor;
|
||||
use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme};
|
||||
|
||||
mod proxy;
|
||||
pub mod sink;
|
||||
|
|
@ -604,10 +603,15 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
|||
fn create_custom_cursor(
|
||||
&self,
|
||||
cursor: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, RequestError> {
|
||||
Ok(RootCustomCursor {
|
||||
inner: PlatformCustomCursor::Wayland(OnlyCursorImage(Arc::from(cursor.inner.0))),
|
||||
})
|
||||
) -> Result<CoreCustomCursor, RequestError> {
|
||||
let cursor_image = match cursor {
|
||||
CustomCursorSource::Image(cursor_image) => cursor_image,
|
||||
CustomCursorSource::Animation { .. } | CustomCursorSource::Url { .. } => {
|
||||
return Err(NotSupportedError::new("unsupported cursor kind").into())
|
||||
},
|
||||
};
|
||||
|
||||
Ok(CoreCustomCursor(Arc::new(WaylandCustomCursor(cursor_image))))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Proxy;
|
||||
|
||||
pub(super) use crate::cursor::OnlyCursorImage as CustomCursor;
|
||||
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||
use crate::window::WindowId;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,16 @@ use cursor_icon::CursorIcon;
|
|||
use sctk::reexports::client::protocol::wl_shm::Format;
|
||||
use sctk::shm::slot::{Buffer, SlotPool};
|
||||
|
||||
use crate::cursor::CursorImage;
|
||||
use crate::cursor::{CursorImage, CustomCursorProvider};
|
||||
|
||||
// Wrap in our own type to not impl trait on global type.
|
||||
#[derive(Debug)]
|
||||
pub struct WaylandCustomCursor(pub(crate) CursorImage);
|
||||
impl CustomCursorProvider for WaylandCustomCursor {
|
||||
fn is_animated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SelectedCursor {
|
||||
|
|
@ -26,7 +35,8 @@ pub struct CustomCursor {
|
|||
}
|
||||
|
||||
impl CustomCursor {
|
||||
pub(crate) fn new(pool: &mut SlotPool, image: &CursorImage) -> Self {
|
||||
pub(crate) fn new(pool: &mut SlotPool, image: &WaylandCustomCursor) -> Self {
|
||||
let image = &image.0;
|
||||
let (buffer, canvas) = pool
|
||||
.create_buffer(
|
||||
image.width as i32,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use sctk::subcompositor::SubcompositorState;
|
|||
use tracing::{info, warn};
|
||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
||||
|
||||
use crate::cursor::CustomCursor as RootCustomCursor;
|
||||
use crate::cursor::CustomCursor as CoreCustomCursor;
|
||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::platform_impl::wayland::event_loop::OwnedDisplayHandle;
|
||||
|
|
@ -37,9 +37,10 @@ use crate::platform_impl::wayland::seat::{
|
|||
PointerConstraintsState, WinitPointerData, WinitPointerDataExt, ZwpTextInputV3Ext,
|
||||
};
|
||||
use crate::platform_impl::wayland::state::{WindowCompositorUpdate, WinitState};
|
||||
use crate::platform_impl::wayland::types::cursor::{CustomCursor, SelectedCursor};
|
||||
use crate::platform_impl::wayland::types::cursor::{
|
||||
CustomCursor, SelectedCursor, WaylandCustomCursor,
|
||||
};
|
||||
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
||||
use crate::platform_impl::PlatformCustomCursor;
|
||||
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, WindowId};
|
||||
|
||||
#[cfg(feature = "sctk-adwaita")]
|
||||
|
|
@ -702,19 +703,18 @@ impl WindowState {
|
|||
}
|
||||
|
||||
/// Set the custom cursor icon.
|
||||
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(_) } => {
|
||||
tracing::error!("passed a X11 cursor to Wayland backend");
|
||||
pub(crate) fn set_custom_cursor(&mut self, cursor: CoreCustomCursor) {
|
||||
let cursor = match cursor.cast_ref::<WaylandCustomCursor>() {
|
||||
Some(cursor) => cursor,
|
||||
None => {
|
||||
tracing::error!("unrecognized cursor passed 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 {
|
||||
|
|
|
|||
|
|
@ -36,10 +36,9 @@ use crate::platform::x11::XlibErrorHook;
|
|||
use crate::platform_impl::common::xkb::Context;
|
||||
use crate::platform_impl::platform::min_timeout;
|
||||
use crate::platform_impl::x11::window::Window;
|
||||
use crate::platform_impl::PlatformCustomCursor;
|
||||
use crate::utils::Lazy;
|
||||
use crate::window::{
|
||||
CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow,
|
||||
CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, Window as CoreWindow,
|
||||
WindowAttributes, WindowId,
|
||||
};
|
||||
|
||||
|
|
@ -731,10 +730,8 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
|||
fn create_custom_cursor(
|
||||
&self,
|
||||
custom_cursor: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, RequestError> {
|
||||
Ok(RootCustomCursor {
|
||||
inner: PlatformCustomCursor::X(CustomCursor::new(self, custom_cursor.inner)?),
|
||||
})
|
||||
) -> Result<CoreCustomCursor, RequestError> {
|
||||
Ok(CoreCustomCursor(Arc::new(CustomCursor::new(self, custom_cursor)?)))
|
||||
}
|
||||
|
||||
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use x11rb::protocol::xproto;
|
|||
|
||||
use super::super::ActiveEventLoop;
|
||||
use super::*;
|
||||
use crate::error::RequestError;
|
||||
use crate::platform_impl::PlatformCustomCursorSource;
|
||||
use crate::cursor::{CustomCursorProvider, CustomCursorSource};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::window::CursorIcon;
|
||||
|
||||
impl XConnection {
|
||||
|
|
@ -36,7 +36,7 @@ impl XConnection {
|
|||
window: xproto::Window,
|
||||
cursor: &CustomCursor,
|
||||
) -> Result<(), X11Error> {
|
||||
self.update_cursor(window, cursor.inner.cursor)
|
||||
self.update_cursor(window, cursor.cursor)
|
||||
}
|
||||
|
||||
/// Create a cursor from an image.
|
||||
|
|
@ -170,32 +170,45 @@ pub enum SelectedCursor {
|
|||
Named(CursorIcon),
|
||||
}
|
||||
|
||||
impl Default for SelectedCursor {
|
||||
fn default() -> Self {
|
||||
SelectedCursor::Named(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustomCursor {
|
||||
inner: Arc<CustomCursorInner>,
|
||||
xconn: Arc<XConnection>,
|
||||
cursor: xproto::Cursor,
|
||||
}
|
||||
|
||||
impl Hash for CustomCursor {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
Arc::as_ptr(&self.inner).hash(state);
|
||||
self.cursor.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for CustomCursor {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.inner, &other.inner)
|
||||
self.cursor == other.cursor
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for CustomCursor {}
|
||||
|
||||
impl CustomCursor {
|
||||
pub(crate) fn new(
|
||||
event_loop: &ActiveEventLoop,
|
||||
mut cursor: PlatformCustomCursorSource,
|
||||
cursor: CustomCursorSource,
|
||||
) -> Result<CustomCursor, RequestError> {
|
||||
let mut cursor = match cursor {
|
||||
CustomCursorSource::Image(cursor_image) => cursor_image,
|
||||
CustomCursorSource::Animation { .. } | CustomCursorSource::Url { .. } => {
|
||||
return Err(NotSupportedError::new("unsupported cursor kind").into())
|
||||
},
|
||||
};
|
||||
|
||||
// Reverse RGBA order to BGRA.
|
||||
cursor.0.rgba.chunks_mut(4).for_each(|chunk| {
|
||||
cursor.rgba.chunks_mut(4).for_each(|chunk| {
|
||||
let chunk: &mut [u8; 4] = chunk.try_into().unwrap();
|
||||
chunk[0..3].reverse();
|
||||
|
||||
|
|
@ -209,32 +222,26 @@ impl CustomCursor {
|
|||
let cursor = event_loop
|
||||
.xconn
|
||||
.create_cursor_from_image(
|
||||
cursor.0.width,
|
||||
cursor.0.height,
|
||||
cursor.0.hotspot_x,
|
||||
cursor.0.hotspot_y,
|
||||
&cursor.0.rgba,
|
||||
cursor.width,
|
||||
cursor.height,
|
||||
cursor.hotspot_x,
|
||||
cursor.hotspot_y,
|
||||
&cursor.rgba,
|
||||
)
|
||||
.map_err(|err| os_error!(err))?;
|
||||
|
||||
Ok(Self { inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }) })
|
||||
Ok(Self { xconn: event_loop.xconn.clone(), cursor })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CustomCursorInner {
|
||||
xconn: Arc<XConnection>,
|
||||
cursor: xproto::Cursor,
|
||||
}
|
||||
|
||||
impl Drop for CustomCursorInner {
|
||||
impl Drop for CustomCursor {
|
||||
fn drop(&mut self) {
|
||||
self.xconn.xcb_connection().free_cursor(self.cursor).map(|r| r.ignore_error()).ok();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SelectedCursor {
|
||||
fn default() -> Self {
|
||||
SelectedCursor::Named(Default::default())
|
||||
impl CustomCursorProvider for CustomCursor {
|
||||
fn is_animated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,11 @@ use x11rb::protocol::{randr, xinput};
|
|||
|
||||
use super::util::{self, SelectedCursor};
|
||||
use super::{
|
||||
ffi, ActiveEventLoop, CookieResultExt, ImeRequest, ImeSender, VoidCookie, XConnection,
|
||||
ffi, ActiveEventLoop, CookieResultExt, CustomCursor, ImeRequest, ImeSender, VoidCookie,
|
||||
XConnection,
|
||||
};
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::cursor::{Cursor, CustomCursor as RootCustomCursor};
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{SurfaceSizeWriter, WindowEvent};
|
||||
|
|
@ -35,7 +36,7 @@ use crate::platform_impl::x11::atoms::*;
|
|||
use crate::platform_impl::x11::{
|
||||
xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error,
|
||||
};
|
||||
use crate::platform_impl::{common, PlatformCustomCursor, PlatformIcon};
|
||||
use crate::platform_impl::{common, PlatformIcon};
|
||||
use crate::window::{
|
||||
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow,
|
||||
WindowAttributes, WindowButtons, WindowId, WindowLevel,
|
||||
|
|
@ -1808,19 +1809,23 @@ impl UnownedWindow {
|
|||
}
|
||||
}
|
||||
},
|
||||
Cursor::Custom(RootCustomCursor { inner: PlatformCustomCursor::X(cursor) }) => {
|
||||
Cursor::Custom(cursor) => {
|
||||
let cursor = match cursor.cast_ref::<CustomCursor>() {
|
||||
Some(cursor) => cursor,
|
||||
None => {
|
||||
tracing::error!("unrecognized cursor passed to X11 backend");
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::mutex_atomic)]
|
||||
if *self.cursor_visible.lock().unwrap() {
|
||||
if let Err(err) = self.xconn.set_custom_cursor(self.xwindow, &cursor) {
|
||||
if let Err(err) = self.xconn.set_custom_cursor(self.xwindow, cursor) {
|
||||
tracing::error!("failed to set window icon: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
*self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(cursor);
|
||||
},
|
||||
#[cfg(wayland_platform)]
|
||||
Cursor::Custom(RootCustomCursor { inner: PlatformCustomCursor::Wayland(_) }) => {
|
||||
tracing::error!("passed a Wayland cursor to X11 backend")
|
||||
*self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(cursor.clone());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,11 @@ use std::{fmt, str};
|
|||
|
||||
pub(crate) use self::event_loop::{ActiveEventLoop, EventLoop};
|
||||
pub use self::window::Window;
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
||||
mod event_loop;
|
||||
mod window;
|
||||
|
||||
pub(crate) use crate::cursor::{
|
||||
NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
|
||||
};
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RedoxSocket {
|
||||
fd: usize,
|
||||
|
|
|
|||
|
|
@ -24,50 +24,17 @@ use super::backend::Style;
|
|||
use super::main_thread::{MainThreadMarker, MainThreadSafe};
|
||||
use super::r#async::{AbortHandle, Abortable, DropAbortHandle, Notified, Notifier};
|
||||
use super::ActiveEventLoop;
|
||||
use crate::cursor::{BadImage, Cursor, CursorImage, CustomCursor as RootCustomCursor};
|
||||
use crate::cursor::{
|
||||
Cursor, CursorAnimation, CursorImage, CustomCursorProvider, CustomCursorSource,
|
||||
};
|
||||
use crate::platform::web::CustomCursorError;
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub(crate) enum CustomCursorSource {
|
||||
Image(CursorImage),
|
||||
Url { url: String, hotspot_x: u16, hotspot_y: u16 },
|
||||
Animation { duration: Duration, cursors: Vec<RootCustomCursor> },
|
||||
}
|
||||
|
||||
impl CustomCursorSource {
|
||||
pub fn from_rgba(
|
||||
rgba: Vec<u8>,
|
||||
width: u16,
|
||||
height: u16,
|
||||
hotspot_x: u16,
|
||||
hotspot_y: u16,
|
||||
) -> Result<CustomCursorSource, BadImage> {
|
||||
Ok(CustomCursorSource::Image(CursorImage::from_rgba(
|
||||
rgba, width, height, hotspot_x, hotspot_y,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CustomCursor {
|
||||
pub(crate) animation: bool,
|
||||
state: Arc<MainThreadSafe<RefCell<ImageState>>>,
|
||||
}
|
||||
|
||||
impl Hash for CustomCursor {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
Arc::as_ptr(&self.state).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for CustomCursor {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.state, &other.state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for CustomCursor {}
|
||||
|
||||
impl CustomCursor {
|
||||
pub(crate) fn new(event_loop: &ActiveEventLoop, source: CustomCursorSource) -> Self {
|
||||
match source {
|
||||
|
|
@ -81,15 +48,13 @@ impl CustomCursor {
|
|||
from_url(UrlType::Plain(url), hotspot_x, hotspot_y),
|
||||
false,
|
||||
),
|
||||
CustomCursorSource::Animation { duration, cursors } => Self::build_spawn(
|
||||
event_loop,
|
||||
from_animation(
|
||||
event_loop.runner.main_thread(),
|
||||
duration,
|
||||
cursors.into_iter().map(|cursor| cursor.inner),
|
||||
),
|
||||
true,
|
||||
),
|
||||
CustomCursorSource::Animation(CursorAnimation { duration, cursors }) => {
|
||||
Self::build_spawn(
|
||||
event_loop,
|
||||
from_animation(event_loop.runner.main_thread(), duration, cursors.into_iter()),
|
||||
true,
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +128,26 @@ impl CustomCursor {
|
|||
}
|
||||
}
|
||||
|
||||
impl CustomCursorProvider for CustomCursor {
|
||||
fn is_animated(&self) -> bool {
|
||||
self.animation
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for CustomCursor {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
Arc::as_ptr(&self.state).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for CustomCursor {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.state, &other.state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for CustomCursor {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CustomCursorFuture {
|
||||
notified: Notified<Result<(), CustomCursorError>>,
|
||||
|
|
@ -230,13 +215,16 @@ impl CursorHandler {
|
|||
this.set_style();
|
||||
},
|
||||
Cursor::Custom(cursor) => {
|
||||
let cursor = cursor.inner;
|
||||
let cursor = match cursor.cast_ref::<CustomCursor>() {
|
||||
Some(cursor) => cursor,
|
||||
None => todo!(),
|
||||
};
|
||||
|
||||
if let SelectedCursor::Loading { cursor: old_cursor, .. }
|
||||
| SelectedCursor::Image(old_cursor)
|
||||
| SelectedCursor::Animation { cursor: old_cursor, .. } = &this.cursor
|
||||
{
|
||||
if *old_cursor == cursor {
|
||||
if old_cursor == cursor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -263,7 +251,7 @@ impl CursorHandler {
|
|||
|
||||
drop(state);
|
||||
this.cursor = SelectedCursor::Loading {
|
||||
cursor,
|
||||
cursor: cursor.clone(),
|
||||
previous: mem::take(&mut this.cursor).into(),
|
||||
_handle: handle,
|
||||
};
|
||||
|
|
@ -275,7 +263,7 @@ impl CursorHandler {
|
|||
},
|
||||
ImageState::Image(_) => {
|
||||
drop(state);
|
||||
this.cursor = SelectedCursor::Image(cursor);
|
||||
this.cursor = SelectedCursor::Image(cursor.clone());
|
||||
this.set_style();
|
||||
},
|
||||
ImageState::Animation(animation) => {
|
||||
|
|
@ -292,7 +280,7 @@ impl CursorHandler {
|
|||
|
||||
this.cursor = SelectedCursor::Animation {
|
||||
animation: AnimationDropper(animation),
|
||||
cursor,
|
||||
cursor: cursor.clone(),
|
||||
};
|
||||
this.set_style();
|
||||
},
|
||||
|
|
@ -650,12 +638,13 @@ async fn from_url(
|
|||
async fn from_animation(
|
||||
main_thread: MainThreadMarker,
|
||||
duration: Duration,
|
||||
cursors: impl ExactSizeIterator<Item = CustomCursor>,
|
||||
cursors: impl ExactSizeIterator<Item = crate::cursor::CustomCursor>,
|
||||
) -> Result<Animation, CustomCursorError> {
|
||||
let keyframes = Array::new();
|
||||
let mut images = Vec::with_capacity(cursors.len());
|
||||
|
||||
for cursor in cursors {
|
||||
let cursor = cursor.cast_ref::<CustomCursor>().unwrap();
|
||||
let state = cursor.state.get(main_thread).borrow();
|
||||
|
||||
match state.deref() {
|
||||
|
|
@ -680,7 +669,7 @@ async fn from_animation(
|
|||
keyframes.push(&keyframe);
|
||||
drop(state);
|
||||
|
||||
images.push(cursor);
|
||||
images.push(cursor.clone());
|
||||
}
|
||||
|
||||
keyframes.push(&keyframes.get(0));
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use crate::platform::web::{CustomCursorFuture, PollStrategy, WaitUntilStrategy};
|
|||
use crate::platform_impl::platform::cursor::CustomCursor;
|
||||
use crate::platform_impl::web::event_loop::proxy::EventLoopProxy;
|
||||
use crate::platform_impl::Window;
|
||||
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId};
|
||||
use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, WindowId};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct ModifiersShared(Rc<Cell<ModifiersState>>);
|
||||
|
|
@ -65,7 +65,7 @@ impl ActiveEventLoop {
|
|||
}
|
||||
|
||||
pub fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture {
|
||||
CustomCursorFuture(CustomCursor::new_async(self, source.inner))
|
||||
CustomCursorFuture(CustomCursor::new_async(self, source))
|
||||
}
|
||||
|
||||
pub fn register(&self, canvas: &Rc<backend::Canvas>, window_id: WindowId) {
|
||||
|
|
@ -498,8 +498,8 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
|||
fn create_custom_cursor(
|
||||
&self,
|
||||
source: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, RequestError> {
|
||||
Ok(RootCustomCursor { inner: CustomCursor::new(self, source.inner) })
|
||||
) -> Result<CoreCustomCursor, RequestError> {
|
||||
Ok(CoreCustomCursor(Arc::new(CustomCursor::new(self, source))))
|
||||
}
|
||||
|
||||
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoremMonitorHandle>> {
|
||||
|
|
|
|||
|
|
@ -32,10 +32,7 @@ mod monitor;
|
|||
mod web_sys;
|
||||
mod window;
|
||||
|
||||
pub(crate) use cursor::{
|
||||
CustomCursor as PlatformCustomCursor, CustomCursorFuture,
|
||||
CustomCursorSource as PlatformCustomCursorSource,
|
||||
};
|
||||
pub(crate) use cursor::CustomCursorFuture;
|
||||
|
||||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes,
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ use super::window::set_skip_taskbar;
|
|||
use super::SelectedCursor;
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::error::{EventLoopError, RequestError};
|
||||
use crate::error::{EventLoopError, NotSupportedError, RequestError};
|
||||
use crate::event::{
|
||||
DeviceEvent, DeviceId, FingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, TouchPhase,
|
||||
WindowEvent,
|
||||
|
|
@ -93,7 +93,7 @@ use crate::platform_impl::platform::{raw_input, util, wrap_device_id};
|
|||
use crate::platform_impl::Window;
|
||||
use crate::utils::Lazy;
|
||||
use crate::window::{
|
||||
CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow,
|
||||
CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, Window as CoreWindow,
|
||||
WindowAttributes, WindowId,
|
||||
};
|
||||
|
||||
|
|
@ -421,8 +421,15 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
|||
fn create_custom_cursor(
|
||||
&self,
|
||||
source: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, RequestError> {
|
||||
Ok(RootCustomCursor { inner: WinCursor::new(&source.inner.0)? })
|
||||
) -> Result<CoreCustomCursor, RequestError> {
|
||||
let cursor = match source {
|
||||
CustomCursorSource::Image(cursor) => cursor,
|
||||
CustomCursorSource::Animation { .. } | CustomCursorSource::Url { .. } => {
|
||||
return Err(NotSupportedError::new("unsupported cursor kind").into())
|
||||
},
|
||||
};
|
||||
|
||||
Ok(CoreCustomCursor(Arc::new(WinCursor::new(&cursor)?)))
|
||||
}
|
||||
|
||||
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
|
|||
};
|
||||
|
||||
use super::util;
|
||||
use crate::cursor::CursorImage;
|
||||
use crate::cursor::{CursorImage, CustomCursorProvider};
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::error::RequestError;
|
||||
use crate::icon::*;
|
||||
|
|
@ -196,6 +196,12 @@ impl Default for SelectedCursor {
|
|||
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct WinCursor(pub(super) Arc<RaiiCursor>);
|
||||
|
||||
impl CustomCursorProvider for WinCursor {
|
||||
fn is_animated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl WinCursor {
|
||||
pub(crate) fn new(image: &CursorImage) -> Result<Self, RequestError> {
|
||||
let mut bgra = image.rgba.clone();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@ use windows_sys::Win32::Foundation::HWND;
|
|||
use windows_sys::Win32::UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX};
|
||||
|
||||
pub(crate) use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
|
||||
pub use self::icon::WinIcon as PlatformIcon;
|
||||
pub(crate) use self::icon::{SelectedCursor, WinCursor as PlatformCustomCursor, WinIcon};
|
||||
pub(crate) use self::icon::{SelectedCursor, WinIcon as PlatformIcon, WinIcon};
|
||||
pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::Window;
|
||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||
use crate::event::DeviceId;
|
||||
use crate::icon::Icon;
|
||||
use crate::platform::windows::{BackdropType, Color, CornerPreference};
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
|
|||
WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SYSCOMMAND, WNDCLASSEXW,
|
||||
};
|
||||
|
||||
use super::icon::WinCursor;
|
||||
use super::MonitorHandle;
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
|
|
@ -597,10 +598,15 @@ impl CoreWindow for Window {
|
|||
});
|
||||
},
|
||||
Cursor::Custom(cursor) => {
|
||||
let cursor = match cursor.cast_ref::<WinCursor>() {
|
||||
Some(cursor) => cursor,
|
||||
None => return,
|
||||
};
|
||||
self.window_state_lock().mouse.selected_cursor =
|
||||
SelectedCursor::Custom(cursor.inner.0.clone());
|
||||
SelectedCursor::Custom(cursor.0.clone());
|
||||
let handle = cursor.0.clone();
|
||||
self.thread_executor.execute_in_thread(move || unsafe {
|
||||
SetCursor(cursor.inner.0.as_raw_handle());
|
||||
SetCursor(handle.as_raw_handle());
|
||||
});
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue