Change create_custom_cursor() to return Result (#3844)
This commit is contained in:
parent
29e1041987
commit
f5304815a1
17 changed files with 141 additions and 87 deletions
|
|
@ -17,6 +17,7 @@ use rwh_06::{DisplayHandle, HasDisplayHandle};
|
|||
use softbuffer::{Context, Surface};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
||||
use winit::error::ExternalError;
|
||||
use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::keyboard::{Key, ModifiersState};
|
||||
|
|
@ -75,7 +76,7 @@ struct Application {
|
|||
receiver: Receiver<Action>,
|
||||
sender: Sender<Action>,
|
||||
/// Custom cursors assets.
|
||||
custom_cursors: Vec<CustomCursor>,
|
||||
custom_cursors: Result<Vec<CustomCursor>, ExternalError>,
|
||||
/// Application icon.
|
||||
icon: Icon,
|
||||
windows: HashMap<WindowId, WindowState>,
|
||||
|
|
@ -107,11 +108,13 @@ impl Application {
|
|||
let icon = load_icon(include_bytes!("data/icon.png"));
|
||||
|
||||
info!("Loading cursor assets");
|
||||
let custom_cursors = vec![
|
||||
let custom_cursors = [
|
||||
event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross.png"))),
|
||||
event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross2.png"))),
|
||||
event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/gradient.png"))),
|
||||
];
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
receiver,
|
||||
|
|
@ -217,12 +220,27 @@ impl Application {
|
|||
Action::ToggleImeInput => window.toggle_ime(),
|
||||
Action::Minimize => window.minimize(),
|
||||
Action::NextCursor => window.next_cursor(),
|
||||
Action::NextCustomCursor => window.next_custom_cursor(&self.custom_cursors),
|
||||
Action::NextCustomCursor => {
|
||||
if let Err(err) = self.custom_cursors.as_ref().map(|c| window.next_custom_cursor(c))
|
||||
{
|
||||
error!("Error creating custom cursor: {err}");
|
||||
}
|
||||
},
|
||||
#[cfg(web_platform)]
|
||||
Action::UrlCustomCursor => window.url_custom_cursor(event_loop),
|
||||
Action::UrlCustomCursor => {
|
||||
if let Err(err) = window.url_custom_cursor(event_loop) {
|
||||
error!("Error creating custom cursor from URL: {err}");
|
||||
}
|
||||
},
|
||||
#[cfg(web_platform)]
|
||||
Action::AnimationCustomCursor => {
|
||||
window.animation_custom_cursor(event_loop, &self.custom_cursors)
|
||||
if let Err(err) = self
|
||||
.custom_cursors
|
||||
.as_ref()
|
||||
.map(|c| window.animation_custom_cursor(event_loop, c))
|
||||
{
|
||||
error!("Error creating animated custom cursor: {err}");
|
||||
}
|
||||
},
|
||||
Action::CycleCursorGrab => window.cycle_cursor_grab(),
|
||||
Action::DragWindow => window.drag_window(),
|
||||
|
|
@ -588,7 +606,7 @@ impl WindowState {
|
|||
let mut state = Self {
|
||||
#[cfg(macos_platform)]
|
||||
option_as_alt: window.option_as_alt(),
|
||||
custom_idx: app.custom_cursors.len() - 1,
|
||||
custom_idx: app.custom_cursors.as_ref().map(Vec::len).unwrap_or(1) - 1,
|
||||
cursor_grab: CursorGrabMode::None,
|
||||
named_idx,
|
||||
#[cfg(not(any(android_platform, ios_platform)))]
|
||||
|
|
@ -737,10 +755,12 @@ impl WindowState {
|
|||
|
||||
/// Custom cursor from an URL.
|
||||
#[cfg(web_platform)]
|
||||
fn url_custom_cursor(&mut self, event_loop: &ActiveEventLoop) {
|
||||
let cursor = event_loop.create_custom_cursor(url_custom_cursor());
|
||||
fn url_custom_cursor(&mut self, event_loop: &ActiveEventLoop) -> Result<(), Box<dyn Error>> {
|
||||
let cursor = event_loop.create_custom_cursor(url_custom_cursor())?;
|
||||
|
||||
self.window.set_cursor(cursor);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Custom cursor from a URL.
|
||||
|
|
@ -749,18 +769,20 @@ impl WindowState {
|
|||
&mut self,
|
||||
event_loop: &ActiveEventLoop,
|
||||
custom_cursors: &[CustomCursor],
|
||||
) {
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
use std::time::Duration;
|
||||
|
||||
let cursors = vec![
|
||||
custom_cursors[0].clone(),
|
||||
custom_cursors[1].clone(),
|
||||
event_loop.create_custom_cursor(url_custom_cursor()),
|
||||
event_loop.create_custom_cursor(url_custom_cursor())?,
|
||||
];
|
||||
let cursor = CustomCursor::from_animation(Duration::from_secs(3), cursors).unwrap();
|
||||
let cursor = event_loop.create_custom_cursor(cursor);
|
||||
let cursor = event_loop.create_custom_cursor(cursor)?;
|
||||
|
||||
self.window.set_cursor(cursor);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resize the window to the new size.
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ changelog entry.
|
|||
- On Web, `Window::canvas()` now returns a reference.
|
||||
- On Web, `CursorGrabMode::Locked` now lets `DeviceEvent::MouseMotion` return raw data, not OS
|
||||
accelerated, if the browser supports it.
|
||||
- `(Active)EventLoop::create_custom_cursor()` now returns a `Result<CustomCursor, ExternalError>`.
|
||||
|
||||
### Removed
|
||||
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ impl From<CustomCursor> for Cursor {
|
|||
/// CustomCursor::from_url(String::from("http://localhost:3000/cursor.png"), 0, 0)
|
||||
/// };
|
||||
///
|
||||
/// let custom_cursor = event_loop.create_custom_cursor(source);
|
||||
///
|
||||
/// window.set_cursor(custom_cursor.clone());
|
||||
/// if let Ok(custom_cursor) = event_loop.create_custom_cursor(source) {
|
||||
/// window.set_cursor(custom_cursor.clone());
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
|
|
@ -109,6 +109,8 @@ impl CustomCursor {
|
|||
/// See [`CustomCursor`] for more details.
|
||||
#[derive(Debug)]
|
||||
pub struct CustomCursorSource {
|
||||
// Some platforms don't support custom cursors.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) inner: PlatformCustomCursorSource,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use std::time::{Duration, Instant};
|
|||
use web_time::{Duration, Instant};
|
||||
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::error::{EventLoopError, OsError};
|
||||
use crate::error::{EventLoopError, ExternalError, OsError};
|
||||
use crate::monitor::MonitorHandle;
|
||||
use crate::platform_impl;
|
||||
use crate::window::{CustomCursor, CustomCursorSource, Theme, Window, WindowAttributes};
|
||||
|
|
@ -270,7 +270,14 @@ impl EventLoop {
|
|||
}
|
||||
|
||||
/// Create custom cursor.
|
||||
pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// **iOS / Android / Orbital:** Unsupported.
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
custom_cursor: CustomCursorSource,
|
||||
) -> Result<CustomCursor, ExternalError> {
|
||||
self.event_loop.window_target().p.create_custom_cursor(custom_cursor)
|
||||
}
|
||||
}
|
||||
|
|
@ -338,7 +345,14 @@ impl ActiveEventLoop {
|
|||
}
|
||||
|
||||
/// Create custom cursor.
|
||||
pub fn create_custom_cursor(&self, custom_cursor: CustomCursorSource) -> CustomCursor {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// **iOS / Android / Orbital:** Unsupported.
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
custom_cursor: CustomCursorSource,
|
||||
) -> Result<CustomCursor, ExternalError> {
|
||||
let _span = tracing::debug_span!("winit::ActiveEventLoop::create_custom_cursor",).entered();
|
||||
|
||||
self.p.create_custom_cursor(custom_cursor)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ use tracing::{debug, trace, warn};
|
|||
use crate::application::ApplicationHandler;
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error;
|
||||
use crate::error::EventLoopError;
|
||||
use crate::error::{self, EventLoopError, ExternalError, NotSupportedError};
|
||||
use crate::event::{self, Force, InnerSizeWriter, StartCause};
|
||||
use crate::event_loop::{self, ControlFlow, DeviceEvents};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
|
|
@ -591,9 +590,11 @@ impl ActiveEventLoop {
|
|||
Some(MonitorHandle::new(self.app.clone()))
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor {
|
||||
let _ = source.inner;
|
||||
CustomCursor { inner: PlatformCustomCursor }
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
_source: CustomCursorSource,
|
||||
) -> Result<CustomCursor, ExternalError> {
|
||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||
}
|
||||
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ use objc2_foundation::{
|
|||
NSString,
|
||||
};
|
||||
|
||||
use super::OsError;
|
||||
use crate::cursor::{CursorImage, OnlyCursorImageSource};
|
||||
use crate::error::ExternalError;
|
||||
use crate::window::CursorIcon;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
@ -23,12 +25,12 @@ unsafe impl Send for CustomCursor {}
|
|||
unsafe impl Sync for CustomCursor {}
|
||||
|
||||
impl CustomCursor {
|
||||
pub(crate) fn new(cursor: OnlyCursorImageSource) -> CustomCursor {
|
||||
Self(cursor_from_image(&cursor.0))
|
||||
pub(crate) fn new(cursor: OnlyCursorImageSource) -> Result<CustomCursor, ExternalError> {
|
||||
cursor_from_image(&cursor.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Retained<NSCursor> {
|
||||
pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result<Retained<NSCursor>, ExternalError> {
|
||||
let width = cursor.width;
|
||||
let height = cursor.height;
|
||||
|
||||
|
|
@ -45,8 +47,8 @@ pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Retained<NSCursor> {
|
|||
NSDeviceRGBColorSpace,
|
||||
width as isize * 4,
|
||||
32,
|
||||
).unwrap()
|
||||
};
|
||||
)
|
||||
}.ok_or_else(|| ExternalError::Os(os_error!(OsError::CreationError("parent view should be installed in a window"))))?;
|
||||
let bitmap_data = unsafe { slice::from_raw_parts_mut(bitmap.bitmapData(), cursor.rgba.len()) };
|
||||
bitmap_data.copy_from_slice(&cursor.rgba);
|
||||
|
||||
|
|
@ -57,7 +59,7 @@ pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Retained<NSCursor> {
|
|||
|
||||
let hotspot = NSPoint::new(cursor.hotspot_x as f64, cursor.hotspot_y as f64);
|
||||
|
||||
NSCursor::initWithImage_hotSpot(NSCursor::alloc(), &image, hotspot)
|
||||
Ok(NSCursor::initWithImage_hotSpot(NSCursor::alloc(), &image, hotspot))
|
||||
}
|
||||
|
||||
pub(crate) fn default_cursor() -> Retained<NSCursor> {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use super::event::dummy_event;
|
|||
use super::monitor::{self, MonitorHandle};
|
||||
use super::observer::setup_control_flow_observers;
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::error::EventLoopError;
|
||||
use crate::error::{EventLoopError, ExternalError};
|
||||
use crate::event_loop::{ActiveEventLoop as RootWindowTarget, ControlFlow, DeviceEvents};
|
||||
use crate::platform::macos::ActivationPolicy;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
|
|
@ -85,8 +85,11 @@ impl ActiveEventLoop {
|
|||
&self.delegate
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
|
||||
RootCustomCursor { inner: CustomCursor::new(source.inner) }
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
source: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, ExternalError> {
|
||||
Ok(RootCustomCursor { inner: CustomCursor::new(source.inner)? })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use super::app_delegate::AppDelegate;
|
|||
use super::app_state::{AppState, EventLoopHandler};
|
||||
use super::{app_state, monitor, MonitorHandle};
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::error::EventLoopError;
|
||||
use crate::error::{EventLoopError, ExternalError, NotSupportedError};
|
||||
use crate::event::Event;
|
||||
use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
|
||||
use crate::window::{CustomCursor, CustomCursorSource, Theme};
|
||||
|
|
@ -36,9 +36,11 @@ impl ActiveEventLoop {
|
|||
EventLoopProxy::new(AppState::get_mut(self.mtm).proxy_wake_up())
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> CustomCursor {
|
||||
let _ = source.inner;
|
||||
CustomCursor { inner: super::PlatformCustomCursor }
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
_source: CustomCursorSource,
|
||||
) -> Result<CustomCursor, ExternalError> {
|
||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||
}
|
||||
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
|
|
|
|||
|
|
@ -834,7 +834,10 @@ impl ActiveEventLoop {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor(&self, cursor: CustomCursorSource) -> CustomCursor {
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
cursor: CustomCursorSource,
|
||||
) -> Result<CustomCursor, ExternalError> {
|
||||
x11_or_wayland!(match self; ActiveEventLoop(evlp) => evlp.create_custom_cursor(cursor))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use sctk::reexports::client::{globals, Connection, QueueHandle};
|
|||
use crate::application::ApplicationHandler;
|
||||
use crate::cursor::OnlyCursorImage;
|
||||
use crate::dpi::LogicalSize;
|
||||
use crate::error::{EventLoopError, OsError as RootOsError};
|
||||
use crate::error::{EventLoopError, ExternalError, OsError as RootOsError};
|
||||
use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
|
||||
use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
|
|
@ -644,10 +644,13 @@ impl ActiveEventLoop {
|
|||
#[inline]
|
||||
pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
||||
|
||||
pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor {
|
||||
RootCustomCursor {
|
||||
pub(crate) fn create_custom_cursor(
|
||||
&self,
|
||||
cursor: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, ExternalError> {
|
||||
Ok(RootCustomCursor {
|
||||
inner: PlatformCustomCursor::Wayland(OnlyCursorImage(Arc::from(cursor.inner.0))),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use x11rb::x11_utils::X11Error as LogicalError;
|
|||
use x11rb::xcb_ffi::ReplyOrIdError;
|
||||
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::error::{EventLoopError, OsError as RootOsError};
|
||||
use crate::error::{EventLoopError, ExternalError, OsError as RootOsError};
|
||||
use crate::event::{Event, StartCause, WindowEvent};
|
||||
use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
|
|
@ -643,8 +643,13 @@ impl ActiveEventLoop {
|
|||
self.xconn.primary_monitor().ok()
|
||||
}
|
||||
|
||||
pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor {
|
||||
RootCustomCursor { inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)) }
|
||||
pub(crate) fn create_custom_cursor(
|
||||
&self,
|
||||
cursor: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, ExternalError> {
|
||||
Ok(RootCustomCursor {
|
||||
inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)?),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use x11rb::connection::Connection;
|
|||
|
||||
use super::super::ActiveEventLoop;
|
||||
use super::*;
|
||||
use crate::platform_impl::PlatformCustomCursorSource;
|
||||
use crate::error::ExternalError;
|
||||
use crate::platform_impl::{OsError, PlatformCustomCursorSource};
|
||||
use crate::window::CursorIcon;
|
||||
|
||||
impl XConnection {
|
||||
|
|
@ -123,14 +124,16 @@ impl CustomCursor {
|
|||
pub(crate) fn new(
|
||||
event_loop: &ActiveEventLoop,
|
||||
cursor: PlatformCustomCursorSource,
|
||||
) -> CustomCursor {
|
||||
) -> Result<CustomCursor, ExternalError> {
|
||||
unsafe {
|
||||
let ximage = (event_loop.xconn.xcursor.XcursorImageCreate)(
|
||||
cursor.0.width as i32,
|
||||
cursor.0.height as i32,
|
||||
);
|
||||
if ximage.is_null() {
|
||||
panic!("failed to allocate cursor image");
|
||||
return Err(ExternalError::Os(os_error!(OsError::Misc(
|
||||
"`XcursorImageCreate` failed"
|
||||
))));
|
||||
}
|
||||
(*ximage).xhot = cursor.0.hotspot_x as u32;
|
||||
(*ximage).yhot = cursor.0.hotspot_y as u32;
|
||||
|
|
@ -147,7 +150,9 @@ impl CustomCursor {
|
|||
let cursor =
|
||||
(event_loop.xconn.xcursor.XcursorImageLoadCursor)(event_loop.xconn.display, ximage);
|
||||
(event_loop.xconn.xcursor.XcursorImageDestroy)(ximage);
|
||||
Self { inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }) }
|
||||
Ok(Self {
|
||||
inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use super::{
|
|||
RedoxSocket, TimeSocket, WindowId, WindowProperties,
|
||||
};
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::error::EventLoopError;
|
||||
use crate::error::{EventLoopError, ExternalError, NotSupportedError};
|
||||
use crate::event::{self, Ime, Modifiers, StartCause};
|
||||
use crate::event_loop::{self, ControlFlow, DeviceEvents};
|
||||
use crate::keyboard::{
|
||||
|
|
@ -729,9 +729,11 @@ impl ActiveEventLoop {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
|
||||
let _ = source.inner;
|
||||
RootCustomCursor { inner: super::PlatformCustomCursor }
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
_source: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, ExternalError> {
|
||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||
}
|
||||
|
||||
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use super::device::DeviceId;
|
|||
use super::runner::{EventWrapper, WeakShared};
|
||||
use super::window::WindowId;
|
||||
use super::{backend, runner, EventLoopProxy};
|
||||
use crate::error::NotSupportedError;
|
||||
use crate::error::{ExternalError, NotSupportedError};
|
||||
use crate::event::{
|
||||
DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent,
|
||||
};
|
||||
|
|
@ -71,8 +71,11 @@ impl ActiveEventLoop {
|
|||
EventLoopProxy::new(self.waker())
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
|
||||
RootCustomCursor { inner: CustomCursor::new(self, source.inner) }
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
source: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, ExternalError> {
|
||||
Ok(RootCustomCursor { inner: CustomCursor::new(self, source.inner) })
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ use super::window::set_skip_taskbar;
|
|||
use super::SelectedCursor;
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::error::EventLoopError;
|
||||
use crate::error::{EventLoopError, ExternalError};
|
||||
use crate::event::{
|
||||
Event, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, WindowEvent,
|
||||
};
|
||||
|
|
@ -483,16 +483,11 @@ impl ActiveEventLoop {
|
|||
EventLoopThreadExecutor { thread_id: self.thread_id, target_window: self.thread_msg_target }
|
||||
}
|
||||
|
||||
pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
|
||||
let inner = match WinCursor::new(&source.inner.0) {
|
||||
Ok(cursor) => cursor,
|
||||
Err(err) => {
|
||||
tracing::warn!("Failed to create custom cursor: {err}");
|
||||
WinCursor::Failed
|
||||
},
|
||||
};
|
||||
|
||||
RootCustomCursor { inner }
|
||||
pub fn create_custom_cursor(
|
||||
&self,
|
||||
source: CustomCursorSource,
|
||||
) -> Result<RootCustomCursor, ExternalError> {
|
||||
Ok(RootCustomCursor { inner: WinCursor::new(&source.inner.0)? })
|
||||
}
|
||||
|
||||
// TODO: Investigate opportunities for caching
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
|
|||
use super::util;
|
||||
use crate::cursor::CursorImage;
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::error::ExternalError;
|
||||
use crate::icon::*;
|
||||
|
||||
impl Pixel {
|
||||
|
|
@ -175,13 +176,10 @@ impl Default for SelectedCursor {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum WinCursor {
|
||||
Cursor(Arc<RaiiCursor>),
|
||||
Failed,
|
||||
}
|
||||
pub struct WinCursor(pub(super) Arc<RaiiCursor>);
|
||||
|
||||
impl WinCursor {
|
||||
pub(crate) fn new(image: &CursorImage) -> Result<Self, io::Error> {
|
||||
pub(crate) fn new(image: &CursorImage) -> Result<Self, ExternalError> {
|
||||
let mut bgra = image.rgba.clone();
|
||||
bgra.chunks_exact_mut(4).for_each(|chunk| chunk.swap(0, 2));
|
||||
|
||||
|
|
@ -191,16 +189,16 @@ impl WinCursor {
|
|||
unsafe {
|
||||
let hdc_screen = GetDC(0);
|
||||
if hdc_screen == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
|
||||
}
|
||||
let hbm_color = CreateCompatibleBitmap(hdc_screen, w, h);
|
||||
ReleaseDC(0, hdc_screen);
|
||||
if hbm_color == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
|
||||
}
|
||||
if SetBitmapBits(hbm_color, bgra.len() as u32, bgra.as_ptr() as *const c_void) == 0 {
|
||||
DeleteObject(hbm_color);
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
|
||||
};
|
||||
|
||||
// Mask created according to https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createbitmap#parameters
|
||||
|
|
@ -208,7 +206,7 @@ impl WinCursor {
|
|||
let hbm_mask = CreateBitmap(w, h, 1, 1, mask_bits.as_ptr() as *const _);
|
||||
if hbm_mask == 0 {
|
||||
DeleteObject(hbm_color);
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
|
||||
}
|
||||
|
||||
let icon_info = ICONINFO {
|
||||
|
|
@ -223,10 +221,10 @@ impl WinCursor {
|
|||
DeleteObject(hbm_color);
|
||||
DeleteObject(hbm_mask);
|
||||
if handle == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
|
||||
}
|
||||
|
||||
Ok(Self::Cursor(Arc::new(RaiiCursor { handle })))
|
||||
Ok(Self(Arc::new(RaiiCursor { handle })))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ use crate::platform_impl::platform::dpi::{
|
|||
};
|
||||
use crate::platform_impl::platform::drop_handler::FileDropHandler;
|
||||
use crate::platform_impl::platform::event_loop::{self, ActiveEventLoop, DESTROY_MSG_ID};
|
||||
use crate::platform_impl::platform::icon::{self, IconType, WinCursor};
|
||||
use crate::platform_impl::platform::icon::{self, IconType};
|
||||
use crate::platform_impl::platform::ime::ImeContext;
|
||||
use crate::platform_impl::platform::keyboard::KeyEventBuilder;
|
||||
use crate::platform_impl::platform::monitor::{self, MonitorHandle};
|
||||
|
|
@ -383,17 +383,10 @@ impl Window {
|
|||
});
|
||||
},
|
||||
Cursor::Custom(cursor) => {
|
||||
let new_cursor = match cursor.inner {
|
||||
WinCursor::Cursor(cursor) => cursor,
|
||||
WinCursor::Failed => {
|
||||
warn!("Requested to apply failed cursor");
|
||||
return;
|
||||
},
|
||||
};
|
||||
self.window_state_lock().mouse.selected_cursor =
|
||||
SelectedCursor::Custom(new_cursor.clone());
|
||||
SelectedCursor::Custom(cursor.inner.0.clone());
|
||||
self.thread_executor.execute_in_thread(move || unsafe {
|
||||
SetCursor(new_cursor.as_raw_handle());
|
||||
SetCursor(cursor.inner.0.as_raw_handle());
|
||||
});
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue