fix(wayland): graceful exit on compositor disconnect
Some checks failed
Continuous Integration / formatting (push) Has been cancelled
Continuous Integration / linting (push) Has been cancelled

Replace 3 panicking unwrap() in cosmic-app-list/wayland_handler.rs
(event loop dispatch + 2 conn.flush in screencopy) with logged
errors that break/return None instead.

Wrap cosmic-applets/main.rs entry point in panic::catch_unwind to
catch panics propagating from libcosmic/iced/winit (which we cannot
patch locally without forking) when the COSMIC compositor closes
the Wayland connection at logout. This eliminates the cascade of
~12 SIGABRT coredumps observed at session shutdown.

Panic strategy is unwind (default), catch_unwind is sound here.

Leyoda 2026 – GPLv3
This commit is contained in:
Votre Nom 2026-04-26 11:10:19 +02:00
parent 28010fd260
commit 22d6f353f1
2 changed files with 48 additions and 21 deletions

View file

@ -388,7 +388,10 @@ impl CaptureData {
},
)
.unwrap();
self.conn.flush().unwrap();
if let Err(err) = self.conn.flush() {
tracing::error!("Wayland flush failed during screencopy session create: {err}");
return None;
}
let formats = session
.wait_while(|data| data.formats.is_none())
@ -437,7 +440,10 @@ impl CaptureData {
session: capture_session.clone(),
},
);
self.conn.flush().unwrap();
if let Err(err) = self.conn.flush() {
tracing::error!("Wayland flush failed during screencopy capture: {err}");
return None;
}
// TODO: wait for server to release buffer?
let res = session
@ -709,7 +715,10 @@ pub(crate) fn wayland_handler(
if app_data.exit {
break;
}
event_loop.dispatch(None, &mut app_data).unwrap();
if let Err(err) = event_loop.dispatch(None, &mut app_data) {
tracing::error!("Wayland event loop terminated: {err}");
break;
}
}
}

View file

@ -12,26 +12,44 @@ fn main() -> cosmic::iced::Result {
};
let start = applet.rfind('/').map_or(0, |v| v + 1);
let cmd = &applet.as_str()[start..];
let cmd = applet.as_str()[start..].to_string();
tracing::info!("Starting `{cmd}` with version {VERSION}");
match cmd {
"cosmic-app-list" => cosmic_app_list::run(),
"cosmic-applet-a11y" => cosmic_applet_a11y::run(),
"cosmic-applet-audio" => cosmic_applet_audio::run(),
"cosmic-applet-battery" => cosmic_applet_battery::run(),
"cosmic-applet-bluetooth" => cosmic_applet_bluetooth::run(),
"cosmic-applet-minimize" => cosmic_applet_minimize::run(),
"cosmic-applet-network" => cosmic_applet_network::run(),
"cosmic-applet-notifications" => cosmic_applet_notifications::run(),
"cosmic-applet-power" => cosmic_applet_power::run(),
"cosmic-applet-status-area" => cosmic_applet_status_area::run(),
"cosmic-applet-tiling" => cosmic_applet_tiling::run(),
"cosmic-applet-time" => cosmic_applet_time::run(),
"cosmic-applet-workspaces" => cosmic_applet_workspaces::run(),
"cosmic-applet-input-sources" => cosmic_applet_input_sources::run(),
"cosmic-panel-button" => cosmic_panel_button::run(),
_ => Ok(()),
let cmd_for_run = cmd.clone();
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || {
match cmd_for_run.as_str() {
"cosmic-app-list" => cosmic_app_list::run(),
"cosmic-applet-a11y" => cosmic_applet_a11y::run(),
"cosmic-applet-audio" => cosmic_applet_audio::run(),
"cosmic-applet-battery" => cosmic_applet_battery::run(),
"cosmic-applet-bluetooth" => cosmic_applet_bluetooth::run(),
"cosmic-applet-minimize" => cosmic_applet_minimize::run(),
"cosmic-applet-network" => cosmic_applet_network::run(),
"cosmic-applet-notifications" => cosmic_applet_notifications::run(),
"cosmic-applet-power" => cosmic_applet_power::run(),
"cosmic-applet-status-area" => cosmic_applet_status_area::run(),
"cosmic-applet-tiling" => cosmic_applet_tiling::run(),
"cosmic-applet-time" => cosmic_applet_time::run(),
"cosmic-applet-workspaces" => cosmic_applet_workspaces::run(),
"cosmic-applet-input-sources" => cosmic_applet_input_sources::run(),
"cosmic-panel-button" => cosmic_panel_button::run(),
_ => Ok(()),
}
}));
match result {
Ok(r) => r,
Err(payload) => {
let msg = payload
.downcast_ref::<&str>()
.map(|s| s.to_string())
.or_else(|| payload.downcast_ref::<String>().cloned())
.unwrap_or_else(|| "<non-string panic>".to_string());
tracing::error!(
"`{cmd}` panicked (likely compositor disconnect), exiting cleanly: {msg}"
);
Ok(())
}
}
}