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