Propagate error from EventLoop creation
Inner panics could make it hard to trouble shoot the issues and for some users it's not desirable. The inner panics were left only when they are used to `assert!` during development. This reverts commit 9f91bc413fe20618bd7090829832bb074aab15c3 which reverted the original patch which was merged without a proper review. Fixes: #500.
This commit is contained in:
parent
778d70c001
commit
f9758528f6
59 changed files with 353 additions and 297 deletions
|
|
@ -1,7 +1,6 @@
|
|||
//! The event-loop routines.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::io::Result as IOResult;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
|
|
@ -13,11 +12,12 @@ use std::time::{Duration, Instant};
|
|||
use raw_window_handle::{RawDisplayHandle, WaylandDisplayHandle};
|
||||
|
||||
use sctk::reexports::calloop;
|
||||
use sctk::reexports::calloop::Error as CalloopError;
|
||||
use sctk::reexports::client::globals;
|
||||
use sctk::reexports::client::{Connection, Proxy, QueueHandle, WaylandSource};
|
||||
|
||||
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||
use crate::error::{OsError as RootOsError, RunLoopError};
|
||||
use crate::error::{EventLoopError, OsError as RootOsError};
|
||||
use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
|
||||
use crate::event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
|
|
@ -33,7 +33,7 @@ use sink::EventSink;
|
|||
|
||||
use super::state::{WindowCompositorUpdate, WinitState};
|
||||
use super::window::state::FrameCallbackState;
|
||||
use super::{DeviceId, WindowId};
|
||||
use super::{DeviceId, WaylandError, WindowId};
|
||||
|
||||
type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>;
|
||||
|
||||
|
|
@ -73,22 +73,38 @@ pub struct EventLoop<T: 'static> {
|
|||
}
|
||||
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub fn new() -> Result<EventLoop<T>, Box<dyn Error>> {
|
||||
let connection = Connection::connect_to_env()?;
|
||||
pub fn new() -> Result<EventLoop<T>, EventLoopError> {
|
||||
macro_rules! map_err {
|
||||
($e:expr, $err:expr) => {
|
||||
$e.map_err(|error| os_error!($err(error).into()))
|
||||
};
|
||||
}
|
||||
|
||||
let (globals, mut event_queue) = globals::registry_queue_init(&connection)?;
|
||||
let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?;
|
||||
|
||||
let (globals, mut event_queue) = map_err!(
|
||||
globals::registry_queue_init(&connection),
|
||||
WaylandError::Global
|
||||
)?;
|
||||
let queue_handle = event_queue.handle();
|
||||
|
||||
let event_loop = calloop::EventLoop::<WinitState>::try_new()?;
|
||||
let event_loop = map_err!(
|
||||
calloop::EventLoop::<WinitState>::try_new(),
|
||||
WaylandError::Calloop
|
||||
)?;
|
||||
|
||||
let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())?;
|
||||
let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())
|
||||
.map_err(|error| os_error!(error))?;
|
||||
|
||||
// NOTE: do a roundtrip after binding the globals to prevent potential
|
||||
// races with the server.
|
||||
event_queue.roundtrip(&mut winit_state)?;
|
||||
map_err!(
|
||||
event_queue.roundtrip(&mut winit_state),
|
||||
WaylandError::Dispatch
|
||||
)?;
|
||||
|
||||
// Register Wayland source.
|
||||
let wayland_source = WaylandSource::new(event_queue)?;
|
||||
let wayland_source = map_err!(WaylandSource::new(event_queue), WaylandError::Wire)?;
|
||||
let wayland_dispatcher =
|
||||
calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| {
|
||||
let result = queue.dispatch_pending(winit_state);
|
||||
|
|
@ -101,34 +117,50 @@ impl<T: 'static> EventLoop<T> {
|
|||
result
|
||||
});
|
||||
|
||||
event_loop
|
||||
.handle()
|
||||
.register_dispatcher(wayland_dispatcher.clone())?;
|
||||
map_err!(
|
||||
event_loop
|
||||
.handle()
|
||||
.register_dispatcher(wayland_dispatcher.clone()),
|
||||
WaylandError::Calloop
|
||||
)?;
|
||||
|
||||
// Setup the user proxy.
|
||||
let pending_user_events = Rc::new(RefCell::new(Vec::new()));
|
||||
let pending_user_events_clone = pending_user_events.clone();
|
||||
let (user_events_sender, user_events_channel) = calloop::channel::channel();
|
||||
event_loop.handle().insert_source(
|
||||
user_events_channel,
|
||||
move |event, _, winit_state: &mut WinitState| {
|
||||
if let calloop::channel::Event::Msg(msg) = event {
|
||||
winit_state.dispatched_events = true;
|
||||
pending_user_events_clone.borrow_mut().push(msg);
|
||||
}
|
||||
},
|
||||
)?;
|
||||
let result = event_loop
|
||||
.handle()
|
||||
.insert_source(
|
||||
user_events_channel,
|
||||
move |event, _, winit_state: &mut WinitState| {
|
||||
if let calloop::channel::Event::Msg(msg) = event {
|
||||
winit_state.dispatched_events = true;
|
||||
pending_user_events_clone.borrow_mut().push(msg);
|
||||
}
|
||||
},
|
||||
)
|
||||
.map_err(|error| error.error);
|
||||
map_err!(result, WaylandError::Calloop)?;
|
||||
|
||||
// An event's loop awakener to wake up for window events from winit's windows.
|
||||
let (event_loop_awakener, event_loop_awakener_source) = calloop::ping::make_ping()?;
|
||||
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;
|
||||
},
|
||||
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 result = 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)?;
|
||||
|
||||
let window_target = EventLoopWindowTarget {
|
||||
connection: connection.clone(),
|
||||
wayland_dispatcher: wayland_dispatcher.clone(),
|
||||
|
|
@ -158,12 +190,12 @@ impl<T: 'static> EventLoop<T> {
|
|||
Ok(event_loop)
|
||||
}
|
||||
|
||||
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), RunLoopError>
|
||||
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
|
||||
where
|
||||
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
|
||||
{
|
||||
if self.loop_running {
|
||||
return Err(RunLoopError::AlreadyRunning);
|
||||
return Err(EventLoopError::AlreadyRunning);
|
||||
}
|
||||
|
||||
let exit = loop {
|
||||
|
|
@ -172,7 +204,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
break Ok(());
|
||||
}
|
||||
PumpStatus::Exit(code) => {
|
||||
break Err(RunLoopError::ExitFailure(code));
|
||||
break Err(EventLoopError::ExitFailure(code));
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
|
|
@ -184,7 +216,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
// `run_ondemand` calls but if they have only just dropped their
|
||||
// windows we need to make sure those last requests are sent to the
|
||||
// compositor.
|
||||
let _ = self.roundtrip().map_err(RunLoopError::Os);
|
||||
let _ = self.roundtrip().map_err(EventLoopError::Os);
|
||||
|
||||
exit
|
||||
}
|
||||
|
|
@ -617,10 +649,10 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
let mut wayland_source = self.wayland_dispatcher.as_source_mut();
|
||||
let event_queue = wayland_source.queue();
|
||||
event_queue.roundtrip(state).map_err(|_| {
|
||||
os_error!(OsError::WaylandMisc(
|
||||
"failed to do a final roundtrip before exiting the loop."
|
||||
))
|
||||
event_queue.roundtrip(state).map_err(|error| {
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(
|
||||
error
|
||||
))))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
|
||||
//! Winit's Wayland backend.
|
||||
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Proxy;
|
||||
use std::fmt::Display;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use crate::platform_impl::platform::WindowId;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalError};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy};
|
||||
|
||||
pub use crate::platform_impl::platform::{OsError, WindowId};
|
||||
pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
||||
pub use output::{MonitorHandle, VideoMode};
|
||||
pub use window::Window;
|
||||
|
|
@ -17,6 +21,46 @@ 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;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
|
|
@ -24,6 +23,7 @@ use sctk::shm::{Shm, ShmHandler};
|
|||
use sctk::subcompositor::SubcompositorState;
|
||||
|
||||
use crate::dpi::LogicalSize;
|
||||
use crate::platform_impl::OsError;
|
||||
|
||||
use super::event_loop::sink::EventSink;
|
||||
use super::output::MonitorHandle;
|
||||
|
|
@ -35,7 +35,7 @@ use super::types::wp_fractional_scaling::FractionalScalingManager;
|
|||
use super::types::wp_viewporter::ViewporterState;
|
||||
use super::types::xdg_activation::XdgActivationState;
|
||||
use super::window::{WindowRequests, WindowState};
|
||||
use super::WindowId;
|
||||
use super::{WaylandError, WindowId};
|
||||
|
||||
/// Winit's Wayland state.
|
||||
pub struct WinitState {
|
||||
|
|
@ -116,14 +116,16 @@ impl WinitState {
|
|||
globals: &GlobalList,
|
||||
queue_handle: &QueueHandle<Self>,
|
||||
loop_handle: LoopHandle<'static, WinitState>,
|
||||
) -> Result<Self, Box<dyn Error>> {
|
||||
) -> Result<Self, OsError> {
|
||||
let registry_state = RegistryState::new(globals);
|
||||
let compositor_state = CompositorState::bind(globals, queue_handle)?;
|
||||
let compositor_state =
|
||||
CompositorState::bind(globals, queue_handle).map_err(WaylandError::Bind)?;
|
||||
let subcompositor_state = SubcompositorState::bind(
|
||||
compositor_state.wl_compositor().clone(),
|
||||
globals,
|
||||
queue_handle,
|
||||
)?;
|
||||
)
|
||||
.map_err(WaylandError::Bind)?;
|
||||
|
||||
let output_state = OutputState::new(globals, queue_handle);
|
||||
let monitors = output_state.outputs().map(MonitorHandle::new).collect();
|
||||
|
|
@ -148,9 +150,9 @@ impl WinitState {
|
|||
subcompositor_state: Arc::new(subcompositor_state),
|
||||
output_state,
|
||||
seat_state,
|
||||
shm: Shm::bind(globals, queue_handle)?,
|
||||
shm: Shm::bind(globals, queue_handle).map_err(WaylandError::Bind)?,
|
||||
|
||||
xdg_shell: XdgShell::bind(globals, queue_handle)?,
|
||||
xdg_shell: XdgShell::bind(globals, queue_handle).map_err(WaylandError::Bind)?,
|
||||
xdg_activation: XdgActivationState::bind(globals, queue_handle).ok(),
|
||||
|
||||
windows: Default::default(),
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ use super::event_loop::sink::EventSink;
|
|||
use super::output::MonitorHandle;
|
||||
use super::state::WinitState;
|
||||
use super::types::xdg_activation::XdgActivationTokenData;
|
||||
use super::{EventLoopWindowTarget, WindowId};
|
||||
use super::{EventLoopWindowTarget, WaylandError, WindowId};
|
||||
|
||||
pub(crate) mod state;
|
||||
|
||||
|
|
@ -205,18 +205,18 @@ impl Window {
|
|||
let event_queue = wayland_source.queue();
|
||||
|
||||
// Do a roundtrip.
|
||||
event_queue.roundtrip(&mut state).map_err(|_| {
|
||||
os_error!(OsError::WaylandMisc(
|
||||
"failed to do initial roundtrip for the window."
|
||||
))
|
||||
event_queue.roundtrip(&mut state).map_err(|error| {
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(
|
||||
error
|
||||
))))
|
||||
})?;
|
||||
|
||||
// XXX Wait for the initial configure to arrive.
|
||||
while !window_state.lock().unwrap().is_configured() {
|
||||
event_queue.blocking_dispatch(&mut state).map_err(|_| {
|
||||
os_error!(OsError::WaylandMisc(
|
||||
"failed to dispatch queue while waiting for initial configure."
|
||||
))
|
||||
event_queue.blocking_dispatch(&mut state).map_err(|error| {
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(
|
||||
error
|
||||
))))
|
||||
})?;
|
||||
}
|
||||
|
||||
|
|
@ -574,9 +574,7 @@ impl Window {
|
|||
Ok(())
|
||||
} else {
|
||||
let region = Region::new(&*self.compositor).map_err(|_| {
|
||||
ExternalError::Os(os_error!(OsError::WaylandMisc(
|
||||
"failed to set input region."
|
||||
)))
|
||||
ExternalError::Os(os_error!(OsError::Misc("failed to set input region.")))
|
||||
})?;
|
||||
region.add(0, 0, 0, 0);
|
||||
surface.set_input_region(Some(region.wl_region()));
|
||||
|
|
|
|||
|
|
@ -712,7 +712,7 @@ impl WindowState {
|
|||
// Positon 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::WaylandMisc(
|
||||
crate::platform_impl::OsError::Misc(
|
||||
"cursor position can be set only for locked cursor."
|
||||
)
|
||||
)));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue