Change create_custom_cursor() to return Result (#3844)

This commit is contained in:
daxpedda 2024-08-06 18:57:03 +02:00 committed by GitHub
parent 29e1041987
commit f5304815a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 141 additions and 87 deletions

View file

@ -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> {

View file

@ -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> {

View file

@ -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]

View file

@ -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> {

View file

@ -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))
}

View file

@ -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")]

View file

@ -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) {

View file

@ -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 }),
})
}
}
}

View file

@ -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> {

View file

@ -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 {

View file

@ -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

View file

@ -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 })))
}
}
}

View file

@ -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());
});
},
}