api: unify error handling

Make error infrastructure more backend agnostic and let backends
just forward the os errors opaquely.
This commit is contained in:
Kirill Chibisov 2024-09-06 17:20:11 +03:00 committed by GitHub
parent 8db3e0e043
commit b674d20edf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 507 additions and 630 deletions

View file

@ -3,25 +3,24 @@
#[cfg(all(not(x11_platform), not(wayland_platform)))]
compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
use std::env;
use std::num::{NonZeroU16, NonZeroU32};
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
use std::sync::Arc;
use std::time::Duration;
use std::{env, fmt};
#[cfg(x11_platform)]
use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex};
use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Arc, sync::Mutex};
use smol_str::SmolStr;
pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
#[cfg(x11_platform)]
use self::x11::{X11Error, XConnection, XError, XNotSupported};
use self::x11::{XConnection, XError, XNotSupported};
use crate::application::ApplicationHandler;
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
#[cfg(x11_platform)]
use crate::dpi::Size;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::error::EventLoopError;
use crate::error::{EventLoopError, NotSupportedError};
use crate::event_loop::ActiveEventLoop;
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
use crate::keyboard::Key;
@ -108,31 +107,6 @@ impl Default for PlatformSpecificWindowAttributes {
pub(crate) static X11_BACKEND: Lazy<Mutex<Result<Arc<XConnection>, XNotSupported>>> =
Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));
#[derive(Debug, Clone)]
pub enum OsError {
Misc(&'static str),
#[cfg(x11_platform)]
XNotSupported(XNotSupported),
#[cfg(x11_platform)]
XError(Arc<X11Error>),
#[cfg(wayland_platform)]
WaylandError(Arc<wayland::WaylandError>),
}
impl fmt::Display for OsError {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match *self {
OsError::Misc(e) => _f.pad(e),
#[cfg(x11_platform)]
OsError::XNotSupported(ref e) => fmt::Display::fmt(e, _f),
#[cfg(x11_platform)]
OsError::XError(ref e) => fmt::Display::fmt(e, _f),
#[cfg(wayland_platform)]
OsError::WaylandError(ref e) => fmt::Display::fmt(e, _f),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(u64);
@ -411,7 +385,7 @@ impl EventLoop {
} else {
"neither WAYLAND_DISPLAY nor WAYLAND_SOCKET nor DISPLAY is set."
};
return Err(EventLoopError::Os(os_error!(OsError::Misc(msg))));
return Err(NotSupportedError::new(msg).into());
},
};
@ -433,9 +407,7 @@ impl EventLoop {
fn new_x11_any_thread() -> Result<EventLoop, EventLoopError> {
let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() {
Ok(xconn) => xconn.clone(),
Err(err) => {
return Err(EventLoopError::Os(os_error!(OsError::XNotSupported(err.clone()))))
},
Err(err) => return Err(os_error!(err.clone()).into()),
};
Ok(EventLoop::X(x11::EventLoop::new(xconn)))

View file

@ -8,19 +8,18 @@ use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use sctk::reexports::calloop::Error as CalloopError;
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, ExternalError, OsError as RootOsError};
use crate::error::{EventLoopError, OsError, RequestError};
use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent};
use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
use crate::platform::pump_events::PumpStatus;
use crate::platform_impl::platform::min_timeout;
use crate::platform_impl::{OsError, PlatformCustomCursor};
use crate::platform_impl::PlatformCustomCursor;
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme};
mod proxy;
@ -31,7 +30,7 @@ use sink::EventSink;
use super::state::{WindowCompositorUpdate, WinitState};
use super::window::state::FrameCallbackState;
use super::{logical_to_physical_rounded, DeviceId, WaylandError, WindowId};
use super::{logical_to_physical_rounded, DeviceId, WindowId};
type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>;
@ -61,27 +60,20 @@ pub struct EventLoop {
impl EventLoop {
pub fn new() -> Result<EventLoop, EventLoopError> {
macro_rules! map_err {
($e:expr, $err:expr) => {
$e.map_err(|error| os_error!($err(error).into()))
};
}
let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?;
let connection = Connection::connect_to_env().map_err(|err| os_error!(err))?;
let (globals, mut event_queue) =
map_err!(globals::registry_queue_init(&connection), WaylandError::Global)?;
globals::registry_queue_init(&connection).map_err(|err| os_error!(err))?;
let queue_handle = event_queue.handle();
let event_loop =
map_err!(calloop::EventLoop::<WinitState>::try_new(), WaylandError::Calloop)?;
calloop::EventLoop::<WinitState>::try_new().map_err(|err| os_error!(err))?;
let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())
.map_err(|error| os_error!(error))?;
let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())?;
// NOTE: do a roundtrip after binding the globals to prevent potential
// races with the server.
map_err!(event_queue.roundtrip(&mut winit_state), WaylandError::Dispatch)?;
event_queue.roundtrip(&mut winit_state).map_err(|err| os_error!(err))?;
// Register Wayland source.
let wayland_source = WaylandSource::new(connection.clone(), event_queue);
@ -97,37 +89,32 @@ impl EventLoop {
result
});
map_err!(
event_loop.handle().register_dispatcher(wayland_dispatcher.clone()),
WaylandError::Calloop
)?;
event_loop
.handle()
.register_dispatcher(wayland_dispatcher.clone())
.map_err(|err| os_error!(err))?;
// Setup the user proxy.
let (ping, ping_source) = calloop::ping::make_ping().unwrap();
let result = event_loop
event_loop
.handle()
.insert_source(ping_source, move |_, _, winit_state: &mut WinitState| {
winit_state.dispatched_events = true;
winit_state.proxy_wake_up = true;
})
.map_err(|error| error.error);
map_err!(result, WaylandError::Calloop)?;
.map_err(|err| os_error!(err))?;
// An event's loop awakener to wake up for window events from winit's windows.
let (event_loop_awakener, event_loop_awakener_source) = map_err!(
calloop::ping::make_ping()
.map_err(|error| CalloopError::OtherError(Box::new(error).into())),
WaylandError::Calloop
)?;
let (event_loop_awakener, event_loop_awakener_source) =
calloop::ping::make_ping().map_err(|err| os_error!(err))?;
let result = event_loop
event_loop
.handle()
.insert_source(event_loop_awakener_source, move |_, _, winit_state: &mut WinitState| {
// Mark that we have something to dispatch.
winit_state.dispatched_events = true;
})
.map_err(|error| error.error);
map_err!(result, WaylandError::Calloop)?;
.map_err(|err| os_error!(err))?;
let active_event_loop = ActiveEventLoop {
connection: connection.clone(),
@ -517,14 +504,12 @@ impl EventLoop {
})
}
fn roundtrip(&mut self) -> Result<usize, RootOsError> {
fn roundtrip(&mut self) -> Result<usize, OsError> {
let state = &mut self.active_event_loop.state.get_mut();
let mut wayland_source = self.wayland_dispatcher.as_source_mut();
let event_queue = wayland_source.queue();
event_queue.roundtrip(state).map_err(|error| {
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
})
event_queue.roundtrip(state).map_err(|err| os_error!(err))
}
fn control_flow(&self) -> ControlFlow {
@ -614,7 +599,7 @@ impl RootActiveEventLoop for ActiveEventLoop {
fn create_custom_cursor(
&self,
cursor: CustomCursorSource,
) -> Result<RootCustomCursor, ExternalError> {
) -> Result<RootCustomCursor, RequestError> {
Ok(RootCustomCursor {
inner: PlatformCustomCursor::Wayland(OnlyCursorImage(Arc::from(cursor.inner.0))),
})
@ -628,7 +613,7 @@ impl RootActiveEventLoop for ActiveEventLoop {
fn create_window(
&self,
window_attributes: crate::window::WindowAttributes,
) -> Result<Box<dyn crate::window::Window>, RootOsError> {
) -> Result<Box<dyn crate::window::Window>, RequestError> {
let window = crate::platform_impl::wayland::Window::new(self, window_attributes)?;
Ok(Box::new(window))
}

View file

@ -1,18 +1,14 @@
//! Winit's Wayland backend.
use std::fmt::Display;
use std::sync::Arc;
pub use event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy};
pub use output::{MonitorHandle, VideoModeHandle};
use sctk::reexports::client::globals::{BindError, GlobalError};
use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy};
use sctk::reexports::client::Proxy;
pub use window::Window;
pub(super) use crate::cursor::OnlyCursorImage as CustomCursor;
use crate::dpi::{LogicalSize, PhysicalSize};
pub use crate::platform_impl::platform::{OsError, WindowId};
pub use crate::platform_impl::platform::WindowId;
mod event_loop;
mod output;
@ -21,46 +17,6 @@ mod state;
mod types;
mod window;
#[derive(Debug)]
pub enum WaylandError {
/// Error connecting to the socket.
Connection(ConnectError),
/// Error binding the global.
Global(GlobalError),
// Bind error.
Bind(BindError),
/// Error during the dispatching the event queue.
Dispatch(DispatchError),
/// Calloop error.
Calloop(calloop::Error),
/// Wayland
Wire(client::backend::WaylandError),
}
impl Display for WaylandError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WaylandError::Connection(error) => error.fmt(f),
WaylandError::Global(error) => error.fmt(f),
WaylandError::Bind(error) => error.fmt(f),
WaylandError::Dispatch(error) => error.fmt(f),
WaylandError::Calloop(error) => error.fmt(f),
WaylandError::Wire(error) => error.fmt(f),
}
}
}
impl From<WaylandError> for OsError {
fn from(value: WaylandError) -> Self {
Self::WaylandError(Arc::new(value))
}
}
/// Dummy device id, since Wayland doesn't have device events.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;

View file

@ -21,6 +21,7 @@ use sctk::shm::slot::SlotPool;
use sctk::shm::{Shm, ShmHandler};
use sctk::subcompositor::SubcompositorState;
use crate::error::OsError;
use crate::platform_impl::wayland::event_loop::sink::EventSink;
use crate::platform_impl::wayland::output::MonitorHandle;
use crate::platform_impl::wayland::seat::{
@ -32,8 +33,7 @@ use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScali
use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState;
use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState;
use crate::platform_impl::wayland::window::{WindowRequests, WindowState};
use crate::platform_impl::wayland::{WaylandError, WindowId};
use crate::platform_impl::OsError;
use crate::platform_impl::wayland::WindowId;
/// Winit's Wayland state.
pub struct WinitState {
@ -126,7 +126,7 @@ impl WinitState {
) -> Result<Self, OsError> {
let registry_state = RegistryState::new(globals);
let compositor_state =
CompositorState::bind(globals, queue_handle).map_err(WaylandError::Bind)?;
CompositorState::bind(globals, queue_handle).map_err(|err| os_error!(err))?;
let subcompositor_state = match SubcompositorState::bind(
compositor_state.wl_compositor().clone(),
globals,
@ -156,7 +156,7 @@ impl WinitState {
(None, None)
};
let shm = Shm::bind(globals, queue_handle).map_err(WaylandError::Bind)?;
let shm = Shm::bind(globals, queue_handle).map_err(|err| os_error!(err))?;
let custom_cursor_pool = Arc::new(Mutex::new(SlotPool::new(2, &shm).unwrap()));
Ok(Self {
@ -168,7 +168,7 @@ impl WinitState {
shm,
custom_cursor_pool,
xdg_shell: XdgShell::bind(globals, queue_handle).map_err(WaylandError::Bind)?,
xdg_shell: XdgShell::bind(globals, queue_handle).map_err(|err| os_error!(err))?,
xdg_activation: XdgActivationState::bind(globals, queue_handle).ok(),
windows: Default::default(),

View file

@ -16,13 +16,13 @@ use super::event_loop::sink::EventSink;
use super::output::MonitorHandle;
use super::state::WinitState;
use super::types::xdg_activation::XdgActivationTokenData;
use super::{ActiveEventLoop, WaylandError, WindowId};
use super::{ActiveEventLoop, WindowId};
use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
use crate::error::{NotSupportedError, RequestError};
use crate::event::{Ime, WindowEvent};
use crate::event_loop::AsyncRequestSerial;
use crate::monitor::MonitorHandle as CoreMonitorHandle;
use crate::platform_impl::{Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError};
use crate::platform_impl::{Fullscreen, MonitorHandle as PlatformMonitorHandle};
use crate::window::{
Cursor, CursorGrabMode, Fullscreen as CoreFullscreen, ImePurpose, ResizeDirection, Theme,
UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons,
@ -77,7 +77,7 @@ impl Window {
pub(crate) fn new(
event_loop_window_target: &ActiveEventLoop,
attributes: WindowAttributes,
) -> Result<Self, RootOsError> {
) -> Result<Self, RequestError> {
let queue_handle = event_loop_window_target.queue_handle.clone();
let mut state = event_loop_window_target.state.borrow_mut();
@ -190,15 +190,11 @@ impl Window {
let event_queue = wayland_source.queue();
// Do a roundtrip.
event_queue.roundtrip(&mut state).map_err(|error| {
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
})?;
event_queue.roundtrip(&mut state).map_err(|err| os_error!(err))?;
// XXX Wait for the initial configure to arrive.
while !window_state.lock().unwrap().is_configured() {
event_queue.blocking_dispatch(&mut state).map_err(|error| {
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
})?;
event_queue.blocking_dispatch(&mut state).map_err(|err| os_error!(err))?;
}
// Wake-up event loop, so it'll send initial redraw requested.
@ -223,10 +219,10 @@ impl Window {
}
impl Window {
pub fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> {
pub fn request_activation_token(&self) -> Result<AsyncRequestSerial, RequestError> {
let xdg_activation = match self.xdg_activation.as_ref() {
Some(xdg_activation) => xdg_activation,
None => return Err(NotSupportedError::new()),
None => return Err(NotSupportedError::new("xdg_activation_v1 is not available").into()),
};
let serial = AsyncRequestSerial::get();
@ -309,12 +305,14 @@ impl CoreWindow for Window {
crate::platform_impl::common::xkb::reset_dead_keys()
}
fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
Err(NotSupportedError::new())
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
Err(NotSupportedError::new("window position information is not available on Wayland")
.into())
}
fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
Err(NotSupportedError::new())
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
Err(NotSupportedError::new("window position information is not available on Wayland")
.into())
}
fn set_outer_position(&self, _position: Position) {
@ -576,7 +574,7 @@ impl CoreWindow for Window {
}
}
fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> {
let scale_factor = self.scale_factor();
let position = position.to_logical(scale_factor);
self.window_state
@ -587,7 +585,7 @@ impl CoreWindow for Window {
.map(|_| self.request_redraw())
}
fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> {
self.window_state.lock().unwrap().set_cursor_grab(mode)
}
@ -595,11 +593,11 @@ impl CoreWindow for Window {
self.window_state.lock().unwrap().set_cursor_visible(visible);
}
fn drag_window(&self) -> Result<(), ExternalError> {
fn drag_window(&self) -> Result<(), RequestError> {
self.window_state.lock().unwrap().drag_window()
}
fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> {
self.window_state.lock().unwrap().drag_resize_window(direction)
}
@ -609,16 +607,14 @@ impl CoreWindow for Window {
self.window_state.lock().unwrap().show_window_menu(position);
}
fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> {
let surface = self.window.wl_surface();
if hittest {
surface.set_input_region(None);
Ok(())
} else {
let region = Region::new(&*self.compositor).map_err(|_| {
ExternalError::Os(os_error!(OsError::Misc("failed to set input region.")))
})?;
let region = Region::new(&*self.compositor).map_err(|err| os_error!(err))?;
region.add(0, 0, 0, 0);
surface.set_input_region(Some(region.wl_region()));
Ok(())

View file

@ -30,7 +30,7 @@ use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
use crate::cursor::CustomCursor as RootCustomCursor;
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size};
use crate::error::{ExternalError, NotSupportedError};
use crate::error::{NotSupportedError, RequestError};
use crate::platform_impl::wayland::logical_to_physical_rounded;
use crate::platform_impl::wayland::seat::{
PointerConstraintsState, WinitPointerData, WinitPointerDataExt, ZwpTextInputV3Ext,
@ -388,7 +388,7 @@ impl WindowState {
}
/// Start interacting drag resize.
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> {
let xdg_toplevel = self.window.xdg_toplevel();
// TODO(kchibisov) handle touch serials.
@ -402,7 +402,7 @@ impl WindowState {
}
/// Start the window drag.
pub fn drag_window(&self) -> Result<(), ExternalError> {
pub fn drag_window(&self) -> Result<(), RequestError> {
let xdg_toplevel = self.window.xdg_toplevel();
// TODO(kchibisov) handle touch serials.
self.apply_on_pointer(|_, data| {
@ -799,7 +799,7 @@ impl WindowState {
}
/// Set the cursor grabbing state on the top-level.
pub fn set_cursor_grab(&mut self, mode: CursorGrabMode) -> Result<(), ExternalError> {
pub fn set_cursor_grab(&mut self, mode: CursorGrabMode) -> Result<(), RequestError> {
if self.cursor_grab_mode.user_grab_mode == mode {
return Ok(());
}
@ -817,11 +817,15 @@ impl WindowState {
}
/// Set the grabbing state on the surface.
fn set_cursor_grab_inner(&mut self, mode: CursorGrabMode) -> Result<(), ExternalError> {
fn set_cursor_grab_inner(&mut self, mode: CursorGrabMode) -> Result<(), RequestError> {
let pointer_constraints = match self.pointer_constraints.as_ref() {
Some(pointer_constraints) => pointer_constraints,
None if mode == CursorGrabMode::None => return Ok(()),
None => return Err(ExternalError::NotSupported(NotSupportedError::new())),
None => {
return Err(
NotSupportedError::new("zwp_pointer_constraints is not available").into()
)
},
};
// Replace the current mode.
@ -865,16 +869,17 @@ impl WindowState {
}
/// Set the position of the cursor.
pub fn set_cursor_position(&self, position: LogicalPosition<f64>) -> Result<(), ExternalError> {
pub fn set_cursor_position(&self, position: LogicalPosition<f64>) -> Result<(), RequestError> {
if self.pointer_constraints.is_none() {
return Err(ExternalError::NotSupported(NotSupportedError::new()));
return Err(NotSupportedError::new("zwp_pointer_constraints is not available").into());
}
// Position can be set only for locked cursor.
if self.cursor_grab_mode.current_grab_mode != CursorGrabMode::Locked {
return Err(ExternalError::Os(os_error!(crate::platform_impl::OsError::Misc(
"cursor position can be set only for locked cursor."
))));
return Err(NotSupportedError::new(
"cursor position could only be changed for locked pointer",
)
.into());
}
self.apply_on_pointer(|_, data| {

View file

@ -1,7 +1,8 @@
use std::error::Error;
use std::ffi::CStr;
use std::os::raw::c_short;
use std::sync::Arc;
use std::{mem, ptr};
use std::{fmt, mem, ptr};
use x11_dl::xlib::{XIMCallback, XIMPreeditCaretCallbackStruct, XIMPreeditDrawCallbackStruct};
@ -19,6 +20,19 @@ pub enum ImeContextCreationError {
Null,
}
impl fmt::Display for ImeContextCreationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ImeContextCreationError::XError(err) => err.fmt(f),
ImeContextCreationError::Null => {
write!(f, "got null pointer from Xlib without exact reason")
},
}
}
}
impl Error for ImeContextCreationError {}
/// The callback used by XIM preedit functions.
type XIMProcNonnull = unsafe extern "C" fn(ffi::XIM, ffi::XPointer, ffi::XPointer);

View file

@ -23,7 +23,7 @@ use x11rb::x11_utils::X11Error as LogicalError;
use x11rb::xcb_ffi::ReplyOrIdError;
use crate::application::ApplicationHandler;
use crate::error::{EventLoopError, ExternalError, OsError as RootOsError};
use crate::error::{EventLoopError, RequestError};
use crate::event::{Event, StartCause, WindowEvent};
use crate::event_loop::{
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
@ -33,7 +33,7 @@ use crate::platform::pump_events::PumpStatus;
use crate::platform_impl::common::xkb::Context;
use crate::platform_impl::platform::{min_timeout, WindowId};
use crate::platform_impl::x11::window::Window;
use crate::platform_impl::{OsError, OwnedDisplayHandle, PlatformCustomCursor};
use crate::platform_impl::{OwnedDisplayHandle, PlatformCustomCursor};
use crate::window::{
CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow,
WindowAttributes,
@ -399,9 +399,11 @@ impl EventLoop {
// `run_on_demand` calls but if they have only just dropped their
// windows we need to make sure those last requests are sent to the
// X Server.
self.event_processor.target.x_connection().sync_with_server().map_err(|x_err| {
EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err)))))
})?;
self.event_processor
.target
.x_connection()
.sync_with_server()
.map_err(|x_err| EventLoopError::Os(os_error!(X11Error::Xlib(x_err))))?;
exit
}
@ -688,14 +690,14 @@ impl RootActiveEventLoop for ActiveEventLoop {
fn create_window(
&self,
window_attributes: WindowAttributes,
) -> Result<Box<dyn CoreWindow>, RootOsError> {
) -> Result<Box<dyn CoreWindow>, RequestError> {
Ok(Box::new(Window::new(self, window_attributes)?))
}
fn create_custom_cursor(
&self,
custom_cursor: CustomCursorSource,
) -> Result<RootCustomCursor, ExternalError> {
) -> Result<RootCustomCursor, RequestError> {
Ok(RootCustomCursor {
inner: PlatformCustomCursor::X(CustomCursor::new(self, custom_cursor.inner)?),
})

View file

@ -9,8 +9,8 @@ use x11rb::protocol::xproto;
use super::super::ActiveEventLoop;
use super::*;
use crate::error::ExternalError;
use crate::platform_impl::{OsError, PlatformCustomCursorSource};
use crate::error::RequestError;
use crate::platform_impl::PlatformCustomCursorSource;
use crate::window::CursorIcon;
impl XConnection {
@ -193,7 +193,7 @@ impl CustomCursor {
pub(crate) fn new(
event_loop: &ActiveEventLoop,
mut cursor: PlatformCustomCursorSource,
) -> Result<CustomCursor, ExternalError> {
) -> Result<CustomCursor, RequestError> {
// Reverse RGBA order to BGRA.
cursor.0.rgba.chunks_mut(4).for_each(|chunk| {
let chunk: &mut [u8; 4] = chunk.try_into().unwrap();
@ -215,7 +215,7 @@ impl CustomCursor {
cursor.0.hotspot_y,
&cursor.0.rgba,
)
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err.into()))))?;
.map_err(|err| os_error!(err))?;
Ok(Self { inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }) })
}

View file

@ -22,7 +22,7 @@ use super::{
};
use crate::cursor::{Cursor, CustomCursor as RootCustomCursor};
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
use crate::error::{NotSupportedError, RequestError};
use crate::event::{Event, SurfaceSizeWriter, WindowEvent};
use crate::event_loop::AsyncRequestSerial;
use crate::platform::x11::WindowType;
@ -31,8 +31,8 @@ use crate::platform_impl::x11::{
xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error,
};
use crate::platform_impl::{
common, Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
PlatformIcon, VideoModeHandle as PlatformVideoModeHandle,
common, Fullscreen, MonitorHandle as PlatformMonitorHandle, PlatformCustomCursor, PlatformIcon,
VideoModeHandle as PlatformVideoModeHandle,
};
use crate::window::{
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow,
@ -54,7 +54,7 @@ impl Window {
pub(crate) fn new(
event_loop: &ActiveEventLoop,
attribs: WindowAttributes,
) -> Result<Self, RootOsError> {
) -> Result<Self, RequestError> {
let window = Arc::new(UnownedWindow::new(event_loop, attribs)?);
event_loop.windows.borrow_mut().insert(window.id(), Arc::downgrade(&window));
Ok(Window(window))
@ -82,11 +82,11 @@ impl CoreWindow for Window {
common::xkb::reset_dead_keys();
}
fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
self.0.inner_position()
}
fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
self.0.outer_position()
}
@ -242,11 +242,11 @@ impl CoreWindow for Window {
self.0.set_cursor(cursor);
}
fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> {
self.0.set_cursor_position(position)
}
fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> {
self.0.set_cursor_grab(mode)
}
@ -254,11 +254,11 @@ impl CoreWindow for Window {
self.0.set_cursor_visible(visible);
}
fn drag_window(&self) -> Result<(), ExternalError> {
fn drag_window(&self) -> Result<(), RequestError> {
self.0.drag_window()
}
fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> {
self.0.drag_resize_window(direction)
}
@ -266,7 +266,7 @@ impl CoreWindow for Window {
self.0.show_window_menu(position);
}
fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> {
self.0.set_cursor_hittest(hittest)
}
@ -427,13 +427,9 @@ pub struct UnownedWindow {
redraw_sender: WakeSender<WindowId>,
activation_sender: WakeSender<super::ActivationToken>,
}
macro_rules! leap {
($e:expr) => {
match $e {
Ok(x) => x,
Err(err) => return Err(os_error!(OsError::XError(X11Error::from(err).into()))),
}
$e.map_err(|err| os_error!(err))?
};
}
@ -442,7 +438,7 @@ impl UnownedWindow {
pub(crate) fn new(
event_loop: &ActiveEventLoop,
window_attrs: WindowAttributes,
) -> Result<UnownedWindow, RootOsError> {
) -> Result<UnownedWindow, RequestError> {
let xconn = &event_loop.xconn;
let atoms = xconn.atoms();
#[cfg(feature = "rwh_06")]
@ -527,10 +523,9 @@ impl UnownedWindow {
match window_attrs.platform_specific.x11.visual_id {
Some(vi) => {
// Find this specific visual.
let (visualtype, depth) =
all_visuals.find(|(visual, _)| visual.visual_id == vi).ok_or_else(
|| os_error!(OsError::XError(X11Error::NoSuchVisual(vi).into())),
)?;
let (visualtype, depth) = all_visuals
.find(|(visual, _)| visual.visual_id == vi)
.ok_or_else(|| os_error!(X11Error::NoSuchVisual(vi)))?;
(Some(visualtype), depth, true)
},
@ -828,7 +823,7 @@ impl UnownedWindow {
&mut supported_ptr,
);
if supported_ptr == ffi::False {
return Err(os_error!(OsError::Misc("`XkbSetDetectableAutoRepeat` failed")));
return Err(os_error!("`XkbSetDetectableAutoRepeat` failed").into());
}
}
@ -848,14 +843,16 @@ impl UnownedWindow {
// Try to create input context for the window.
if let Some(ime) = event_loop.ime.as_ref() {
let result = ime.borrow_mut().create_context(window.xwindow as ffi::Window, false);
leap!(result);
ime.borrow_mut()
.create_context(window.xwindow as ffi::Window, false)
.map_err(|err| os_error!(err))?;
}
// These properties must be set after mapping
if window_attrs.maximized {
leap!(window.set_maximized_inner(window_attrs.maximized)).ignore_error();
}
if window_attrs.fullscreen.is_some() {
if let Some(flusher) =
leap!(window
@ -888,7 +885,7 @@ impl UnownedWindow {
}
/// Embed this window into a parent window.
pub(super) fn embed_window(&self) -> Result<(), RootOsError> {
pub(super) fn embed_window(&self) -> Result<(), RequestError> {
let atoms = self.xconn.atoms();
leap!(leap!(self.xconn.change_property(
self.xwindow,
@ -1500,7 +1497,7 @@ impl UnownedWindow {
}
#[inline]
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
let extents = self.shared_state_lock().frame_extents.clone();
if let Some(extents) = extents {
let (x, y) = self.inner_position_physical();
@ -1521,7 +1518,7 @@ impl UnownedWindow {
}
#[inline]
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
Ok(self.inner_position_physical().into())
}
@ -1815,7 +1812,7 @@ impl UnownedWindow {
}
#[inline]
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> {
let mut grabbed_lock = self.cursor_grabbed_mode.lock().unwrap();
if mode == *grabbed_lock {
return Ok(());
@ -1829,9 +1826,10 @@ impl UnownedWindow {
.expect_then_ignore_error("Failed to call `xcb_ungrab_pointer`");
let result = match mode {
CursorGrabMode::None => self.xconn.flush_requests().map_err(|err| {
ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(err).into())))
}),
CursorGrabMode::None => self
.xconn
.flush_requests()
.map_err(|err| RequestError::Os(os_error!(X11Error::Xlib(err)))),
CursorGrabMode::Confined => {
let result = {
self.xconn
@ -1878,10 +1876,12 @@ impl UnownedWindow {
},
_ => unreachable!(),
}
.map_err(|err| ExternalError::Os(os_error!(OsError::Misc(err))))
.map_err(|err| RequestError::Os(os_error!(err)))
},
CursorGrabMode::Locked => {
return Err(ExternalError::NotSupported(NotSupportedError::new()));
return Err(
NotSupportedError::new("locked cursor is not implemented on X11").into()
);
},
};
@ -1923,28 +1923,23 @@ impl UnownedWindow {
self.shared_state_lock().last_monitor.scale_factor
}
pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), ExternalError> {
{
self.xconn
.xcb_connection()
.warp_pointer(x11rb::NONE, self.xwindow, 0, 0, 0, 0, x as _, y as _)
.map_err(|e| {
ExternalError::Os(os_error!(OsError::XError(X11Error::from(e).into())))
})?;
self.xconn.flush_requests().map_err(|e| {
ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(e).into())))
})
}
pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), RequestError> {
self.xconn
.xcb_connection()
.warp_pointer(x11rb::NONE, self.xwindow, 0, 0, 0, 0, x as _, y as _)
.map_err(|err| os_error!(X11Error::from(err)))?;
self.xconn.flush_requests().map_err(|err| os_error!(X11Error::Xlib(err)))?;
Ok(())
}
#[inline]
pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
pub fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> {
let (x, y) = position.to_physical::<i32>(self.scale_factor()).into();
self.set_cursor_position_physical(x, y)
}
#[inline]
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> {
let mut rectangles: Vec<Rectangle> = Vec::new();
if hittest {
let size = self.surface_size();
@ -1956,17 +1951,17 @@ impl UnownedWindow {
})
}
let region = RegionWrapper::create_region(self.xconn.xcb_connection(), &rectangles)
.map_err(|_e| ExternalError::Ignored)?;
.map_err(|_e| RequestError::Ignored)?;
self.xconn
.xcb_connection()
.xfixes_set_window_shape_region(self.xwindow, SK::INPUT, 0, 0, region.region())
.map_err(|_e| ExternalError::Ignored)?;
.map_err(|_e| RequestError::Ignored)?;
self.shared_state_lock().cursor_hittest = Some(hittest);
Ok(())
}
/// Moves the window while it is being dragged.
pub fn drag_window(&self) -> Result<(), ExternalError> {
pub fn drag_window(&self) -> Result<(), RequestError> {
self.drag_initiate(util::MOVERESIZE_MOVE)
}
@ -1974,7 +1969,7 @@ impl UnownedWindow {
pub fn show_window_menu(&self, _position: Position) {}
/// Resizes the window while it is being dragged.
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> {
self.drag_initiate(match direction {
ResizeDirection::East => util::MOVERESIZE_RIGHT,
ResizeDirection::North => util::MOVERESIZE_TOP,
@ -1988,13 +1983,13 @@ impl UnownedWindow {
}
/// Initiates a drag operation while the left mouse button is pressed.
fn drag_initiate(&self, action: isize) -> Result<(), ExternalError> {
fn drag_initiate(&self, action: isize) -> Result<(), RequestError> {
let pointer = self
.xconn
.query_pointer(self.xwindow, util::VIRTUAL_CORE_POINTER)
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err.into()))))?;
.map_err(|err| os_error!(err))?;
let window = self.inner_position().map_err(ExternalError::NotSupported)?;
let window_position = self.inner_position()?;
let atoms = self.xconn.atoms();
let message = atoms[_NET_WM_MOVERESIZE];
@ -2005,13 +2000,9 @@ impl UnownedWindow {
self.xconn
.xcb_connection()
.ungrab_pointer(x11rb::CURRENT_TIME)
.map_err(|err| {
ExternalError::Os(os_error!(OsError::XError(X11Error::from(err).into())))
})?
.map_err(|err| os_error!(X11Error::from(err)))?
.ignore_error();
self.xconn.flush_requests().map_err(|err| {
ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(err).into())))
})?;
self.xconn.flush_requests().map_err(|err| os_error!(X11Error::Xlib(err)))?;
*grabbed_lock = CursorGrabMode::None;
// we keep the lock until we are done
@ -2025,18 +2016,18 @@ impl UnownedWindow {
| xproto::EventMask::SUBSTRUCTURE_NOTIFY,
),
[
(window.x + xinput_fp1616_to_float(pointer.win_x) as i32) as u32,
(window.y + xinput_fp1616_to_float(pointer.win_y) as i32) as u32,
(window_position.x + xinput_fp1616_to_float(pointer.win_x) as i32) as u32,
(window_position.y + xinput_fp1616_to_float(pointer.win_y) as i32) as u32,
action.try_into().unwrap(),
1, // Button 1
1,
],
)
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err.into()))))?;
.map_err(|err| os_error!(err))?;
self.xconn.flush_requests().map_err(|err| {
ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(err).into())))
})
self.xconn.flush_requests().map_err(|err| os_error!(X11Error::Xlib(err)))?;
Ok(())
}
#[inline]
@ -2135,7 +2126,7 @@ impl UnownedWindow {
}
#[inline]
pub fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> {
pub fn request_activation_token(&self) -> Result<AsyncRequestSerial, RequestError> {
let serial = AsyncRequestSerial::get();
self.activation_sender.send((self.id(), serial));
Ok(serial)