Add launch crash detection with detailed error dialog, fix all warnings

This commit is contained in:
2026-02-27 20:23:10 +02:00
parent e20759d1cb
commit 11c754a8c1
16 changed files with 324 additions and 70 deletions

View File

@@ -79,59 +79,67 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
]);
let record_id = record.id;
let path = record.path.clone();
let app_name_launch = record.app_name.clone().unwrap_or_else(|| record.filename.clone());
let db_launch = db.clone();
launch_button.connect_clicked(move |_| {
let appimage_path = std::path::Path::new(&path);
let result = launcher::launch_appimage(
&db_launch,
record_id,
appimage_path,
"gui_detail",
&[],
&[],
);
match result {
launcher::LaunchResult::Started { child, method } => {
let pid = child.id();
log::info!("Launched AppImage: {} (PID: {}, method: {})", path, pid, method.as_str());
let toast_launch = toast_overlay.clone();
launch_button.connect_clicked(move |btn| {
btn.set_sensitive(false);
let btn_ref = btn.clone();
let path = path.clone();
let app_name = app_name_launch.clone();
let db_launch = db_launch.clone();
let toast_ref = toast_launch.clone();
glib::spawn_future_local(async move {
let path_bg = path.clone();
let result = gio::spawn_blocking(move || {
let appimage_path = std::path::Path::new(&path_bg);
launcher::launch_appimage(
&Database::open().expect("DB open"),
record_id,
appimage_path,
"gui_detail",
&[],
&[],
)
}).await;
let db_wayland = db_launch.clone();
let path_clone = path.clone();
glib::spawn_future_local(async move {
glib::timeout_future(std::time::Duration::from_secs(3)).await;
btn_ref.set_sensitive(true);
match result {
Ok(launcher::LaunchResult::Started { child, method }) => {
let pid = child.id();
log::info!("Launched: {} (PID: {}, method: {})", path, pid, method.as_str());
let analysis_result = gio::spawn_blocking(move || {
wayland::analyze_running_process(pid)
}).await;
match analysis_result {
Ok(Ok(analysis)) => {
let status_label = analysis.status_label();
let db_wayland = db_launch.clone();
let path_clone = path.clone();
glib::spawn_future_local(async move {
glib::timeout_future(std::time::Duration::from_secs(3)).await;
let analysis_result = gio::spawn_blocking(move || {
wayland::analyze_running_process(pid)
}).await;
if let Ok(Ok(analysis)) = analysis_result {
let status_str = analysis.as_status_str();
log::info!(
"Runtime Wayland analysis for {} (PID {}): {} (wayland_socket={}, x11={}, env_vars={})",
path_clone, analysis.pid, status_label,
analysis.has_wayland_socket,
analysis.has_x11_connection,
analysis.env_vars.len(),
);
db_wayland.update_runtime_wayland_status(
record_id, status_str,
).ok();
log::info!("Runtime Wayland: {} -> {}", path_clone, analysis.status_label());
db_wayland.update_runtime_wayland_status(record_id, status_str).ok();
}
Ok(Err(e)) => {
log::debug!("Runtime analysis failed for PID {}: {}", pid, e);
}
Err(_) => {
log::debug!("Runtime analysis task failed for PID {}", pid);
}
}
});
});
}
Ok(launcher::LaunchResult::Crashed { exit_code, stderr, .. }) => {
log::error!("App crashed on launch (exit {}): {}", exit_code.unwrap_or(-1), stderr);
widgets::show_crash_dialog(&btn_ref, &app_name, exit_code, &stderr);
}
Ok(launcher::LaunchResult::Failed(msg)) => {
log::error!("Failed to launch: {}", msg);
let toast = adw::Toast::builder()
.title(&format!("Could not launch: {}", msg))
.timeout(5)
.build();
toast_ref.add_toast(toast);
}
Err(_) => {
log::error!("Launch task panicked");
}
}
launcher::LaunchResult::Failed(msg) => {
log::error!("Failed to launch: {}", msg);
}
}
});
});
header.pack_end(&launch_button);
@@ -1025,7 +1033,7 @@ fn build_system_tab(record: &AppImageRecord, db: &Rc<Database>, toast_overlay: &
match result {
Ok(analysis) => {
let toolkit_label = analysis.toolkit.label();
let lib_count = analysis.libraries_found.len();
let _lib_count = analysis.libraries_found.len();
row_clone.set_subtitle(&format!(
"Built with: {}",
toolkit_label,
@@ -1062,13 +1070,10 @@ fn build_system_tab(record: &AppImageRecord, db: &Rc<Database>, toast_overlay: &
compat_group.add(&runtime_row);
}
// FUSE status
// FUSE status - always use live system detection (the stored fuse_status
// is per-app AppImageFuseStatus, not the system-level FuseStatus)
let fuse_system = fuse::detect_system_fuse();
let fuse_status = record
.fuse_status
.as_deref()
.map(FuseStatus::from_str)
.unwrap_or(fuse_system.status.clone());
let fuse_status = fuse_system.status.clone();
let fuse_row = adw::ActionRow::builder()
.title("App mounting")
@@ -1824,3 +1829,4 @@ fn fetch_favicon_async(url: &str, image: &gtk::Image) {
}
});
}