From 97c72506663d120744a6f6df607ceb5df79ae33d Mon Sep 17 00:00:00 2001 From: lashman Date: Sat, 28 Feb 2026 00:02:44 +0200 Subject: [PATCH] Extract and apply StartupWMClass for proper taskbar icons Parse StartupWMClass from embedded .desktop entries during analysis, store in DB, include in generated .desktop files. Detail view shows an editable WM class field with apply button for manual override. --- src/core/analysis.rs | 5 +++++ src/core/database.rs | 8 ++++++++ src/core/inspector.rs | 4 ++++ src/ui/detail_view.rs | 22 ++++++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/src/core/analysis.rs b/src/core/analysis.rs index 7ea8168..8c2e877 100644 --- a/src/core/analysis.rs +++ b/src/core/analysis.rs @@ -133,6 +133,11 @@ pub fn run_background_analysis(id: i64, path: PathBuf, appimage_type: AppImageTy Some(meta.screenshot_urls.join("\n")) }; + // Store StartupWMClass + if let Some(ref wm_class) = meta.startup_wm_class { + db.set_startup_wm_class(id, Some(wm_class)).ok(); + } + if let Err(e) = db.update_appstream_metadata( id, meta.appstream_id.as_deref(), diff --git a/src/core/database.rs b/src/core/database.rs index c9c3ddf..16ffac2 100644 --- a/src/core/database.rs +++ b/src/core/database.rs @@ -1754,6 +1754,14 @@ impl Database { Ok(()) } + pub fn set_startup_wm_class(&self, id: i64, wm_class: Option<&str>) -> SqlResult<()> { + self.conn.execute( + "UPDATE appimages SET startup_wm_class = ?2 WHERE id = ?1", + params![id, wm_class], + )?; + Ok(()) + } + // --- Launch statistics --- pub fn get_top_launched(&self, limit: i32) -> SqlResult> { diff --git a/src/core/inspector.rs b/src/core/inspector.rs index 5d8eece..6b03175 100644 --- a/src/core/inspector.rs +++ b/src/core/inspector.rs @@ -61,6 +61,7 @@ pub struct AppImageMetadata { pub desktop_actions: Vec, pub has_signature: bool, pub screenshot_urls: Vec, + pub startup_wm_class: Option, } #[derive(Debug, Default)] @@ -76,6 +77,7 @@ struct DesktopEntryFields { mime_types: Vec, terminal: bool, x_appimage_name: Option, + startup_wm_class: Option, actions: Vec, } @@ -367,6 +369,7 @@ fn parse_desktop_entry(content: &str) -> DesktopEntryFields { } "Terminal" => fields.terminal = value == "true", "X-AppImage-Name" => fields.x_appimage_name = Some(value.to_string()), + "StartupWMClass" => fields.startup_wm_class = Some(value.to_string()), "Actions" => { fields.actions = value .split(';') @@ -814,6 +817,7 @@ pub fn inspect_appimage( .as_ref() .map(|a| a.screenshot_urls.clone()) .unwrap_or_default(), + startup_wm_class: fields.startup_wm_class, }) } diff --git a/src/ui/detail_view.rs b/src/ui/detail_view.rs index 3186c0f..e8644f5 100644 --- a/src/ui/detail_view.rs +++ b/src/ui/detail_view.rs @@ -1033,6 +1033,28 @@ fn build_system_tab(record: &AppImageRecord, db: &Rc, toast_overlay: & }); integration_group.add(&autostart_row); + // StartupWMClass row with editable override + let wm_class_row = adw::EntryRow::builder() + .title("StartupWMClass") + .text(record.startup_wm_class.as_deref().unwrap_or("")) + .show_apply_button(true) + .build(); + let db_wm = db.clone(); + let record_id_wm = record.id; + let toast_wm = toast_overlay.clone(); + wm_class_row.connect_apply(move |row| { + let text = row.text().to_string(); + let value = if text.is_empty() { None } else { Some(text.as_str()) }; + match db_wm.set_startup_wm_class(record_id_wm, value) { + Ok(()) => toast_wm.add_toast(adw::Toast::new("WM class updated")), + Err(e) => { + log::error!("Failed to set WM class: {}", e); + toast_wm.add_toast(adw::Toast::new("Failed to update WM class")); + } + } + }); + integration_group.add(&wm_class_row); + inner.append(&integration_group); // Version Rollback group