improv(sctk): setup error handling

This commit is contained in:
Ashley Wulber 2025-06-12 10:42:59 -04:00
parent 9668aeba1f
commit e4f8120eed
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820

View file

@ -50,6 +50,7 @@ use std::{
}; };
use tracing::error; use tracing::error;
use wayland_backend::client::Backend; use wayland_backend::client::Backend;
use wayland_client::globals::GlobalError;
use winit::{dpi::LogicalSize, event_loop::OwnedDisplayHandle}; use winit::{dpi::LogicalSize, event_loop::OwnedDisplayHandle};
use self::state::SctkState; use self::state::SctkState;
@ -65,6 +66,14 @@ pub struct SctkEventLoop {
pub(crate) state: SctkState, pub(crate) state: SctkState,
} }
pub enum Error {
Connect(ConnectError),
Calloop(calloop::Error),
Global(GlobalError),
NoDisplayHandle,
NoWaylandDisplay,
}
impl SctkEventLoop { impl SctkEventLoop {
pub(crate) fn new( pub(crate) fn new(
winit_event_sender: mpsc::UnboundedSender<Control>, winit_event_sender: mpsc::UnboundedSender<Control>,
@ -76,12 +85,13 @@ impl SctkEventLoop {
> { > {
let Ok(dh) = display.display_handle() else { let Ok(dh) = display.display_handle() else {
log::error!("Failed to get display handle"); log::error!("Failed to get display handle");
return Err(Box::new(())); return Err(Box::new(Error::NoDisplayHandle));
}; };
let raw_window_handle::RawDisplayHandle::Wayland(wayland_dh) = let raw_window_handle::RawDisplayHandle::Wayland(wayland_dh) =
dh.as_raw() dh.as_raw()
else { else {
panic!("Invalid wayland display handle."); log::error!("Display handle is not Wayland");
return Err(Box::new(Error::NoWaylandDisplay));
}; };
let backend = unsafe { let backend = unsafe {
@ -90,12 +100,13 @@ impl SctkEventLoop {
let connection = Connection::from_backend(backend); let connection = Connection::from_backend(backend);
let (action_tx, action_rx) = calloop::channel::channel(); let (action_tx, action_rx) = calloop::channel::channel();
let res = std::thread::spawn(move || { let res: std::thread::JoinHandle<Result<(), Error>> =
std::thread::spawn(move || {
let _display = connection.display(); let _display = connection.display();
let (globals, event_queue) = let (globals, event_queue) =
registry_queue_init(&connection).unwrap(); registry_queue_init(&connection).map_err(Error::Global)?;
let event_loop = let event_loop = calloop::EventLoop::<SctkState>::try_new()
calloop::EventLoop::<SctkState>::try_new().unwrap(); .map_err(Error::Calloop)?;
let loop_handle = event_loop.handle(); let loop_handle = event_loop.handle();
let qh = event_queue.handle(); let qh = event_queue.handle();
@ -282,10 +293,14 @@ impl SctkEventLoop {
xdg_shell_state: XdgShell::bind(&globals, &qh) xdg_shell_state: XdgShell::bind(&globals, &qh)
.expect("xdg shell is not available"), .expect("xdg shell is not available"),
layer_shell: LayerShell::bind(&globals, &qh).ok(), layer_shell: LayerShell::bind(&globals, &qh).ok(),
activation_state: ActivationState::bind(&globals, &qh).ok(), activation_state: ActivationState::bind(&globals, &qh)
session_lock_state: SessionLockState::new(&globals, &qh), .ok(),
session_lock_state: SessionLockState::new(
&globals, &qh,
),
session_lock: None, session_lock: None,
overlap_notify: OverlapNotifyV1::bind(&globals, &qh).ok(), overlap_notify: OverlapNotifyV1::bind(&globals, &qh)
.ok(),
toplevel_info: ToplevelInfoState::try_new( toplevel_info: ToplevelInfoState::try_new(
&registry_state, &registry_state,
&qh, &qh,
@ -374,7 +389,8 @@ impl SctkEventLoop {
unmapped_subsurfaces: Vec::new(), unmapped_subsurfaces: Vec::new(),
new_iced_subsurfaces: Vec::new(), new_iced_subsurfaces: Vec::new(),
}; };
state.state.subsurface_state = Some(subsurface_state.clone()); state.state.subsurface_state =
Some(subsurface_state.clone());
state::send_event( state::send_event(
&state.state.events_sender, &state.state.events_sender,
&state.state.proxy, &state.state.proxy,
@ -410,20 +426,23 @@ impl SctkEventLoop {
let had_events = !state.state.sctk_events.is_empty(); let had_events = !state.state.sctk_events.is_empty();
let mut wake_up = had_events; let mut wake_up = had_events;
for s in state for s in
state
.state .state
.layer_surfaces .layer_surfaces
.iter() .iter()
.map(|s| s.surface.wl_surface()) .map(|s| s.surface.wl_surface())
.chain(
state.state.popups.iter().map(|s| s.popup.wl_surface()),
)
.chain( .chain(
state state
.state .state
.lock_surfaces .popups
.iter() .iter()
.map(|s| s.session_lock_surface.wl_surface()), .map(|s| s.popup.wl_surface()),
)
.chain(
state.state.lock_surfaces.iter().map(|s| {
s.session_lock_surface.wl_surface()
}),
) )
{ {
let id = s.id(); let id = s.id();
@ -458,11 +477,13 @@ impl SctkEventLoop {
.events_sender .events_sender
.unbounded_send(Control::Winit(id, e)); .unbounded_send(Control::Winit(id, e));
} else { } else {
_ = state.state.events_sender.unbounded_send( _ =
Control::PlatformSpecific( state
.state
.events_sender
.unbounded_send(Control::PlatformSpecific(
crate::platform_specific::Event::Wayland(e), crate::platform_specific::Event::Wayland(e),
), ));
);
} }
} }
if wake_up { if wake_up {
@ -473,7 +494,13 @@ impl SctkEventLoop {
if res.is_finished() { if res.is_finished() {
log::warn!("SCTK thread finished."); log::warn!("SCTK thread finished.");
res.join().map(|_: Result<(), ConnectError>| action_tx) match res.join() {
Ok(_) => Ok(action_tx),
Err(e) => {
log::error!("SCTK thread exited with error: {e:?}");
return Err(e);
}
}
} else { } else {
Ok(action_tx) Ok(action_tx)
} }