diff --git a/rust/limux-host-linux/dev.limux.linux.desktop b/rust/limux-host-linux/dev.limux.linux.desktop index 611eb643..a59a351f 100644 --- a/rust/limux-host-linux/dev.limux.linux.desktop +++ b/rust/limux-host-linux/dev.limux.linux.desktop @@ -4,7 +4,7 @@ Name=Limux Comment=GPU-accelerated terminal workspace manager Exec=limux TryExec=limux -Icon=limux +Icon=limux-os-dark Terminal=false Type=Application Categories=Utility;TerminalEmulator; diff --git a/rust/limux-host-linux/icons/app/128.png b/rust/limux-host-linux/icons/app/128.png index 34192bba..b16af325 100644 Binary files a/rust/limux-host-linux/icons/app/128.png and b/rust/limux-host-linux/icons/app/128.png differ diff --git a/rust/limux-host-linux/icons/app/16.png b/rust/limux-host-linux/icons/app/16.png index 20f65a4d..e129f22d 100644 Binary files a/rust/limux-host-linux/icons/app/16.png and b/rust/limux-host-linux/icons/app/16.png differ diff --git a/rust/limux-host-linux/icons/app/256.png b/rust/limux-host-linux/icons/app/256.png index 0bcb0745..1a7a3c9d 100644 Binary files a/rust/limux-host-linux/icons/app/256.png and b/rust/limux-host-linux/icons/app/256.png differ diff --git a/rust/limux-host-linux/icons/app/32.png b/rust/limux-host-linux/icons/app/32.png index 6f3c383f..70f4479e 100644 Binary files a/rust/limux-host-linux/icons/app/32.png and b/rust/limux-host-linux/icons/app/32.png differ diff --git a/rust/limux-host-linux/icons/app/512.png b/rust/limux-host-linux/icons/app/512.png index 4c1dd600..704f6e30 100644 Binary files a/rust/limux-host-linux/icons/app/512.png and b/rust/limux-host-linux/icons/app/512.png differ diff --git a/rust/limux-host-linux/icons/app/os-dark/1024.png b/rust/limux-host-linux/icons/app/os-dark/1024.png new file mode 100644 index 00000000..847feeb5 Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-dark/1024.png differ diff --git a/rust/limux-host-linux/icons/app/os-dark/128.png b/rust/limux-host-linux/icons/app/os-dark/128.png new file mode 100644 index 00000000..b16af325 Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-dark/128.png differ diff --git a/rust/limux-host-linux/icons/app/os-dark/16.png b/rust/limux-host-linux/icons/app/os-dark/16.png new file mode 100644 index 00000000..e129f22d Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-dark/16.png differ diff --git a/rust/limux-host-linux/icons/app/os-dark/256.png b/rust/limux-host-linux/icons/app/os-dark/256.png new file mode 100644 index 00000000..1a7a3c9d Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-dark/256.png differ diff --git a/rust/limux-host-linux/icons/app/os-dark/32.png b/rust/limux-host-linux/icons/app/os-dark/32.png new file mode 100644 index 00000000..70f4479e Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-dark/32.png differ diff --git a/rust/limux-host-linux/icons/app/os-dark/512.png b/rust/limux-host-linux/icons/app/os-dark/512.png new file mode 100644 index 00000000..704f6e30 Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-dark/512.png differ diff --git a/rust/limux-host-linux/icons/app/os-light/1024.png b/rust/limux-host-linux/icons/app/os-light/1024.png new file mode 100644 index 00000000..83b79438 Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-light/1024.png differ diff --git a/rust/limux-host-linux/icons/app/os-light/128.png b/rust/limux-host-linux/icons/app/os-light/128.png new file mode 100644 index 00000000..7ccc0dc8 Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-light/128.png differ diff --git a/rust/limux-host-linux/icons/app/os-light/16.png b/rust/limux-host-linux/icons/app/os-light/16.png new file mode 100644 index 00000000..622dad91 Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-light/16.png differ diff --git a/rust/limux-host-linux/icons/app/os-light/256.png b/rust/limux-host-linux/icons/app/os-light/256.png new file mode 100644 index 00000000..b0b03ed2 Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-light/256.png differ diff --git a/rust/limux-host-linux/icons/app/os-light/32.png b/rust/limux-host-linux/icons/app/os-light/32.png new file mode 100644 index 00000000..2d30056d Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-light/32.png differ diff --git a/rust/limux-host-linux/icons/app/os-light/512.png b/rust/limux-host-linux/icons/app/os-light/512.png new file mode 100644 index 00000000..70f3601f Binary files /dev/null and b/rust/limux-host-linux/icons/app/os-light/512.png differ diff --git a/rust/limux-host-linux/icons/hicolor/128x128/apps/limux-os-dark.png b/rust/limux-host-linux/icons/hicolor/128x128/apps/limux-os-dark.png new file mode 100644 index 00000000..b16af325 Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/128x128/apps/limux-os-dark.png differ diff --git a/rust/limux-host-linux/icons/hicolor/128x128/apps/limux-os-light.png b/rust/limux-host-linux/icons/hicolor/128x128/apps/limux-os-light.png new file mode 100644 index 00000000..7ccc0dc8 Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/128x128/apps/limux-os-light.png differ diff --git a/rust/limux-host-linux/icons/hicolor/16x16/apps/limux-os-dark.png b/rust/limux-host-linux/icons/hicolor/16x16/apps/limux-os-dark.png new file mode 100644 index 00000000..e129f22d Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/16x16/apps/limux-os-dark.png differ diff --git a/rust/limux-host-linux/icons/hicolor/16x16/apps/limux-os-light.png b/rust/limux-host-linux/icons/hicolor/16x16/apps/limux-os-light.png new file mode 100644 index 00000000..622dad91 Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/16x16/apps/limux-os-light.png differ diff --git a/rust/limux-host-linux/icons/hicolor/256x256/apps/limux-os-dark.png b/rust/limux-host-linux/icons/hicolor/256x256/apps/limux-os-dark.png new file mode 100644 index 00000000..1a7a3c9d Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/256x256/apps/limux-os-dark.png differ diff --git a/rust/limux-host-linux/icons/hicolor/256x256/apps/limux-os-light.png b/rust/limux-host-linux/icons/hicolor/256x256/apps/limux-os-light.png new file mode 100644 index 00000000..b0b03ed2 Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/256x256/apps/limux-os-light.png differ diff --git a/rust/limux-host-linux/icons/hicolor/32x32/apps/limux-os-dark.png b/rust/limux-host-linux/icons/hicolor/32x32/apps/limux-os-dark.png new file mode 100644 index 00000000..70f4479e Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/32x32/apps/limux-os-dark.png differ diff --git a/rust/limux-host-linux/icons/hicolor/32x32/apps/limux-os-light.png b/rust/limux-host-linux/icons/hicolor/32x32/apps/limux-os-light.png new file mode 100644 index 00000000..2d30056d Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/32x32/apps/limux-os-light.png differ diff --git a/rust/limux-host-linux/icons/hicolor/512x512/apps/limux-os-dark.png b/rust/limux-host-linux/icons/hicolor/512x512/apps/limux-os-dark.png new file mode 100644 index 00000000..704f6e30 Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/512x512/apps/limux-os-dark.png differ diff --git a/rust/limux-host-linux/icons/hicolor/512x512/apps/limux-os-light.png b/rust/limux-host-linux/icons/hicolor/512x512/apps/limux-os-light.png new file mode 100644 index 00000000..70f3601f Binary files /dev/null and b/rust/limux-host-linux/icons/hicolor/512x512/apps/limux-os-light.png differ diff --git a/rust/limux-host-linux/src/window.rs b/rust/limux-host-linux/src/window.rs index d089b3b5..02a16796 100644 --- a/rust/limux-host-linux/src/window.rs +++ b/rust/limux-host-linux/src/window.rs @@ -1,6 +1,8 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; +use std::fs; use std::path::{Path, PathBuf}; +use std::process::{Command as ProcessCommand, Stdio}; use std::rc::Rc; use adw::prelude::*; @@ -28,6 +30,10 @@ use crate::split_tree::{self, SplitTreeContainer}; const PANE_CREATE_COMMAND_READY_INTERVAL_MS: u64 = 50; const PANE_CREATE_COMMAND_READY_ATTEMPTS: u32 = 40; +const APP_ICON_FOR_DARK_OS: &str = "limux-os-dark"; +const APP_ICON_FOR_LIGHT_OS: &str = "limux-os-light"; +const APP_ICON_LAUNCHER_NAME: &str = "limux"; +const APP_ICON_SIZES: &[u16] = &[16, 32, 128, 256, 512]; // --------------------------------------------------------------------------- // State @@ -1400,10 +1406,21 @@ pub fn build_window(app: &adw::Application) { } } + let initial_app_icon_name = + app_icon_name_for_system_theme(system_prefers_dark.get(), style_manager.is_dark()); + gtk::Window::set_default_icon_name(initial_app_icon_name); + if let Err(err) = sync_launcher_icon_for_system_theme(initial_app_icon_name) { + eprintln!("limux: failed to sync launcher icon: {err}"); + } + if let Err(err) = sync_desktop_entry_icon_for_system_theme(initial_app_icon_name) { + eprintln!("limux: failed to sync desktop entry icon: {err}"); + } + let title = format!("Limux v{}", crate::VERSION); let window = adw::ApplicationWindow::builder() .application(app) .title(&title) + .icon_name(initial_app_icon_name) .default_width(1400) .default_height(900) .build(); @@ -1566,11 +1583,19 @@ pub fn build_window(app: &adw::Application) { let state = state.clone(); let system_prefers_dark = system_prefers_dark.clone(); style_manager.connect_dark_notify(move |style_manager| { + let state = state.borrow(); sync_ghostty_color_scheme_for_config( style_manager, system_prefers_dark.get(), - &state.borrow().config.borrow().appearance, + &state.config.borrow().appearance, ); + if system_prefers_dark.get().is_none() { + sync_app_icon_for_system_theme( + &state.window, + system_prefers_dark.get(), + style_manager.is_dark(), + ); + } }); } @@ -2361,11 +2386,13 @@ fn sync_system_prefers_dark_change( } system_prefers_dark.set(updated_preference); + let state = state.borrow(); sync_ghostty_color_scheme_for_config( style_manager, updated_preference, - &state.borrow().config.borrow().appearance, + &state.config.borrow().appearance, ); + sync_app_icon_for_system_theme(&state.window, updated_preference, style_manager.is_dark()); } fn sync_portal_color_scheme_preference_change( @@ -2768,6 +2795,196 @@ fn sync_ghostty_color_scheme_for_config( crate::terminal::sync_color_scheme(dark); } +fn app_icon_name_for_system_theme( + system_prefers_dark: Option, + fallback_dark: bool, +) -> &'static str { + if system_prefers_dark.unwrap_or(fallback_dark) { + APP_ICON_FOR_DARK_OS + } else { + APP_ICON_FOR_LIGHT_OS + } +} + +fn sync_app_icon_for_system_theme( + window: &adw::ApplicationWindow, + system_prefers_dark: Option, + fallback_dark: bool, +) { + let icon_name = app_icon_name_for_system_theme(system_prefers_dark, fallback_dark); + gtk::Window::set_default_icon_name(icon_name); + window.set_icon_name(Some(icon_name)); + if let Err(err) = sync_launcher_icon_for_system_theme(icon_name) { + eprintln!("limux: failed to sync launcher icon: {err}"); + } + if let Err(err) = sync_desktop_entry_icon_for_system_theme(icon_name) { + eprintln!("limux: failed to sync desktop entry icon: {err}"); + } +} + +fn sync_launcher_icon_for_system_theme(icon_name: &str) -> Result<(), String> { + let user_data_dir = + dirs::data_dir().ok_or_else(|| "could not resolve user data directory".to_string())?; + let source_roots = launcher_icon_source_roots(&user_data_dir); + let mut changed = false; + let mut copied = 0usize; + + for size in APP_ICON_SIZES { + let Some(source) = source_roots + .iter() + .map(|root| launcher_icon_path(root, *size, icon_name)) + .find(|path| path.is_file()) + else { + continue; + }; + let dest = launcher_icon_path(&user_data_dir, *size, APP_ICON_LAUNCHER_NAME); + if copy_icon_if_changed(&source, &dest)? { + changed = true; + } + copied += 1; + } + + if copied == 0 { + return Err(format!("no installed {icon_name} app icon variants found")); + } + + if changed { + refresh_user_icon_cache(&user_data_dir); + } + + Ok(()) +} + +fn launcher_icon_source_roots(user_data_dir: &Path) -> Vec { + let mut roots = vec![user_data_dir.to_path_buf()]; + + let xdg_data_dirs = std::env::var_os("XDG_DATA_DIRS") + .unwrap_or_else(|| std::ffi::OsString::from("/usr/local/share:/usr/share")); + roots.extend(std::env::split_paths(&xdg_data_dirs)); + roots.push(PathBuf::from(env!("CARGO_MANIFEST_DIR"))); + + roots.into_iter().fold(Vec::new(), |mut unique, root| { + if !unique.contains(&root) { + unique.push(root); + } + unique + }) +} + +fn launcher_icon_path(root: &Path, size: u16, icon_name: &str) -> PathBuf { + root.join("icons") + .join("hicolor") + .join(format!("{size}x{size}")) + .join("apps") + .join(format!("{icon_name}.png")) +} + +fn copy_icon_if_changed(source: &Path, dest: &Path) -> Result { + let source_bytes = + fs::read(source).map_err(|err| format!("failed to read {}: {err}", source.display()))?; + if fs::read(dest).is_ok_and(|dest_bytes| dest_bytes == source_bytes) { + return Ok(false); + } + + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent) + .map_err(|err| format!("failed to create {}: {err}", parent.display()))?; + } + fs::write(dest, source_bytes) + .map_err(|err| format!("failed to write {}: {err}", dest.display()))?; + Ok(true) +} + +fn refresh_user_icon_cache(user_data_dir: &Path) { + let hicolor_dir = user_data_dir.join("icons/hicolor"); + let _ = ProcessCommand::new("gtk-update-icon-cache") + .args(["-f", "-t"]) + .arg(hicolor_dir) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); +} + +fn sync_desktop_entry_icon_for_system_theme(icon_name: &str) -> Result<(), String> { + let user_data_dir = + dirs::data_dir().ok_or_else(|| "could not resolve user data directory".to_string())?; + let desktop_file_name = format!("{}.desktop", crate::APP_ID); + let dest = user_data_dir.join("applications").join(&desktop_file_name); + let source = desktop_entry_source_candidates(&user_data_dir, &desktop_file_name) + .into_iter() + .find(|path| path.is_file()) + .ok_or_else(|| format!("{desktop_file_name} was not found"))?; + let contents = fs::read_to_string(&source) + .map_err(|err| format!("failed to read {}: {err}", source.display()))?; + let updated = desktop_entry_with_icon(&contents, icon_name); + + if fs::read_to_string(&dest).is_ok_and(|existing| existing == updated) { + return Ok(()); + } + + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent) + .map_err(|err| format!("failed to create {}: {err}", parent.display()))?; + } + fs::write(&dest, updated) + .map_err(|err| format!("failed to write {}: {err}", dest.display()))?; + refresh_user_desktop_database(&user_data_dir); + Ok(()) +} + +fn desktop_entry_source_candidates(user_data_dir: &Path, desktop_file_name: &str) -> Vec { + let mut roots = vec![user_data_dir.to_path_buf()]; + + let xdg_data_dirs = std::env::var_os("XDG_DATA_DIRS") + .unwrap_or_else(|| std::ffi::OsString::from("/usr/local/share:/usr/share")); + roots.extend(std::env::split_paths(&xdg_data_dirs)); + + let mut candidates = roots + .into_iter() + .map(|root| root.join("applications").join(desktop_file_name)) + .collect::>(); + candidates.push(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(desktop_file_name)); + + candidates.into_iter().fold(Vec::new(), |mut unique, path| { + if !unique.contains(&path) { + unique.push(path); + } + unique + }) +} + +fn desktop_entry_with_icon(contents: &str, icon_name: &str) -> String { + let mut replaced = false; + let mut updated = contents + .lines() + .map(|line| { + if !replaced && line.starts_with("Icon=") { + replaced = true; + format!("Icon={icon_name}") + } else { + line.to_string() + } + }) + .collect::>(); + + if !replaced { + updated.push(format!("Icon={icon_name}")); + } + + let mut output = updated.join("\n"); + output.push('\n'); + output +} + +fn refresh_user_desktop_database(user_data_dir: &Path) { + let applications_dir = user_data_dir.join("applications"); + let _ = ProcessCommand::new("update-desktop-database") + .arg(applications_dir) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); +} + fn apply_appearance( style_manager: &adw::StyleManager, system_prefers_dark: Option, @@ -5872,14 +6089,15 @@ mod tests { use super::gtk::gdk; use super::ToVariant; use super::{ - build_window_css, clamp_workspace_insert_index_for_pinning, + app_icon_name_for_system_theme, build_window_css, clamp_workspace_insert_index_for_pinning, + copy_icon_if_changed, desktop_entry_source_candidates, desktop_entry_with_icon, desktop_notification_action_from_signal, desktop_notification_actions, desktop_notification_activation_token_from_signal, desktop_notification_closed_id_from_signal, desktop_notification_id_from_response, directional_neighbor_score, favorites_prefix_len, font_size_after_delta, - ghostty_prefers_dark, gtk_system_prefers_dark_from_raw, next_active_workspace_index, - pane_create_split_placement, queue_session_save_request, resolve_pane_create_source_id, - resolved_system_prefers_dark, sanitize_background_opacity, + ghostty_prefers_dark, gtk_system_prefers_dark_from_raw, launcher_icon_path, + next_active_workspace_index, pane_create_split_placement, queue_session_save_request, + resolve_pane_create_source_id, resolved_system_prefers_dark, sanitize_background_opacity, shortcut_allowed_while_browser_find_active, shortcut_blocked_by_editable, shortcut_command_from_key_event, shortcut_dispatch_propagation, should_emit_desktop_notification, tab_drag_workspace_seed, use_opaque_window_background, @@ -5887,7 +6105,8 @@ mod tests { workspace_folder_path_from_input, workspace_notification_message, Direction, EditableCaptureContext, NeighborScore, PaneBounds, PaneCreateDirection, PaneCreateTargetError, PortalColorSchemePreference, SessionSaveAccess, SessionSaveRequest, - WorkspaceSeedSource, BASE_CSS, HOST_ENTRY_CSS_CLASS, WORKSPACE_RENAME_ENTRY_CSS_CLASS, + WorkspaceSeedSource, APP_ICON_FOR_DARK_OS, APP_ICON_FOR_LIGHT_OS, APP_ICON_LAUNCHER_NAME, + BASE_CSS, HOST_ENTRY_CSS_CLASS, WORKSPACE_RENAME_ENTRY_CSS_CLASS, WORKSPACE_RENAME_ENTRY_CSS_CLASSES, }; use crate::layout_state::{LayoutNodeState, PaneState, SplitOrientation, SplitState}; @@ -6273,6 +6492,85 @@ mod tests { ); } + #[test] + fn app_icon_name_uses_os_theme_mapping() { + assert_eq!( + app_icon_name_for_system_theme(Some(true), false), + APP_ICON_FOR_DARK_OS + ); + assert_eq!( + app_icon_name_for_system_theme(Some(false), true), + APP_ICON_FOR_LIGHT_OS + ); + } + + #[test] + fn app_icon_name_uses_fallback_when_os_theme_is_unknown() { + assert_eq!( + app_icon_name_for_system_theme(None, true), + APP_ICON_FOR_DARK_OS + ); + assert_eq!( + app_icon_name_for_system_theme(None, false), + APP_ICON_FOR_LIGHT_OS + ); + } + + #[test] + fn launcher_icon_path_targets_hicolor_app_icon() { + assert_eq!( + launcher_icon_path( + std::path::Path::new("/home/tester/.local/share"), + 512, + APP_ICON_LAUNCHER_NAME + ), + std::path::PathBuf::from( + "/home/tester/.local/share/icons/hicolor/512x512/apps/limux.png" + ) + ); + } + + #[test] + fn copy_icon_if_changed_replaces_stale_launcher_icon() { + let dir = tempfile::tempdir().unwrap(); + let source = dir.path().join("source.png"); + let dest = dir.path().join("nested/dest.png"); + std::fs::write(&source, b"white-icon").unwrap(); + std::fs::write(&dest, b"black-icon").unwrap_err(); + + assert!(copy_icon_if_changed(&source, &dest).unwrap()); + assert_eq!(std::fs::read(&dest).unwrap(), b"white-icon"); + assert!(!copy_icon_if_changed(&source, &dest).unwrap()); + } + + #[test] + fn desktop_entry_with_icon_replaces_first_icon_line() { + let updated = desktop_entry_with_icon( + "[Desktop Entry]\nName=Limux\nIcon=limux\nType=Application\n", + APP_ICON_FOR_DARK_OS, + ); + + assert_eq!( + updated, + "[Desktop Entry]\nName=Limux\nIcon=limux-os-dark\nType=Application\n" + ); + } + + #[test] + fn desktop_entry_source_candidates_include_user_and_dev_paths() { + let candidates = desktop_entry_source_candidates( + std::path::Path::new("/home/tester/.local/share"), + "dev.limux.linux.desktop", + ); + + assert!(candidates.contains(&std::path::PathBuf::from( + "/home/tester/.local/share/applications/dev.limux.linux.desktop" + ))); + assert!(candidates.contains( + &std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("dev.limux.linux.desktop") + )); + } + #[test] fn ghostty_prefers_dark_uses_system_preference_when_requested() { assert!(ghostty_prefers_dark( diff --git a/scripts/package.sh b/scripts/package.sh index 8f389908..fd1c5d59 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -169,6 +169,34 @@ copy_ghostty_terminfo_entries() { fi } +install_app_icon_set() { + local src_dir="$1" + local hicolor_dir="$2" + local icon_name="$3" + local size + local src + + if [ ! -d "$src_dir" ]; then + return 0 + fi + + for size in 16 32 128 256 512; do + src="${src_dir}/${size}.png" + if [ -f "$src" ]; then + mkdir -p "$hicolor_dir/${size}x${size}/apps" + cp "$src" "$hicolor_dir/${size}x${size}/apps/${icon_name}.png" + fi + done +} + +install_app_icons() { + local hicolor_dir="$1" + + install_app_icon_set "$APP_ICONS_DIR" "$hicolor_dir" "limux" + install_app_icon_set "$APP_ICONS_DIR/os-dark" "$hicolor_dir" "limux-os-dark" + install_app_icon_set "$APP_ICONS_DIR/os-light" "$hicolor_dir" "limux-os-light" +} + . "${ROOT_DIR}/scripts/appimage-webkit.sh" configure_ghostty_build_args() { @@ -340,15 +368,7 @@ populate_tree() { done # App launcher icons - if [ -d "$APP_ICONS_DIR" ]; then - for size in 16 32 128 256 512; do - src="${APP_ICONS_DIR}/${size}.png" - if [ -f "$src" ]; then - mkdir -p "$icondir/${size}x${size}/apps" - cp "$src" "$icondir/${size}x${size}/apps/limux.png" - fi - done - fi + install_app_icons "$icondir" } build_rpm_source_tree() { @@ -427,15 +447,7 @@ fi for svg in "$ICONS_DIR"/*.svg; do [ -f "$svg" ] && cp "$svg" "$TARBALL_STAGE/share/icons/hicolor/scalable/actions/" done -if [ -d "$APP_ICONS_DIR" ]; then - for size in 16 32 128 256 512; do - src="${APP_ICONS_DIR}/${size}.png" - if [ -f "$src" ]; then - mkdir -p "$TARBALL_STAGE/share/icons/hicolor/${size}x${size}/apps" - cp "$src" "$TARBALL_STAGE/share/icons/hicolor/${size}x${size}/apps/limux.png" - fi - done -fi +install_app_icons "$TARBALL_STAGE/share/icons/hicolor" # Generate install.sh cat > "$TARBALL_STAGE/install.sh" << 'INSTALL_EOF' @@ -571,7 +583,9 @@ if $UNINSTALL; then rm -f "$PREFIX/share/applications/dev.limux.linux.desktop" rm -f "$PREFIX/share/metainfo/dev.limux.linux.metainfo.xml" for size in 16 32 128 256 512; do - rm -f "$PREFIX/share/icons/hicolor/${size}x${size}/apps/limux.png" + for icon_name in limux limux-os-dark limux-os-light; do + rm -f "$PREFIX/share/icons/hicolor/${size}x${size}/apps/${icon_name}.png" + done done rm -f "$PREFIX/share/icons/hicolor/scalable/actions/limux-globe-symbolic.svg" rm -f "$PREFIX/share/icons/hicolor/scalable/actions/limux-split-horizontal-symbolic.svg" @@ -748,15 +762,7 @@ fi for svg in "$ICONS_DIR"/*.svg; do [ -f "$svg" ] && cp "$svg" "$APPDIR/usr/share/icons/hicolor/scalable/actions/" done -if [ -d "$APP_ICONS_DIR" ]; then - for size in 16 32 128 256 512; do - src="${APP_ICONS_DIR}/${size}.png" - if [ -f "$src" ]; then - mkdir -p "$APPDIR/usr/share/icons/hicolor/${size}x${size}/apps" - cp "$src" "$APPDIR/usr/share/icons/hicolor/${size}x${size}/apps/limux.png" - fi - done -fi +install_app_icons "$APPDIR/usr/share/icons/hicolor" # AppImage icon (must be at root as .DirIcon and limux.png) if [ -f "$APP_ICONS_DIR/256.png" ]; then