From fbf73f3ab53387e68c8cbf9e788820bea0f2f111 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Fri, 23 Apr 2021 00:25:50 -0300 Subject: [PATCH] fix(bundler): find icon for AppImage, define `.DirIcon`, closes #749 (#1594) --- .changes/appimage-icon.md | 5 ++ tooling/bundler/src/bundle/appimage_bundle.rs | 15 +++- tooling/bundler/src/bundle/deb_bundle.rs | 68 +++++++++++++------ tooling/bundler/src/bundle/templates/appimage | 8 +-- 4 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 .changes/appimage-icon.md diff --git a/.changes/appimage-icon.md b/.changes/appimage-icon.md new file mode 100644 index 000000000..5974165f1 --- /dev/null +++ b/.changes/appimage-icon.md @@ -0,0 +1,5 @@ +--- +"tauri-bundler": patch +--- + +Find best available icon for AppImage, follow `.DirIcon` spec. diff --git a/tooling/bundler/src/bundle/appimage_bundle.rs b/tooling/bundler/src/bundle/appimage_bundle.rs index 51d1b6dd3..9b317eb58 100644 --- a/tooling/bundler/src/bundle/appimage_bundle.rs +++ b/tooling/bundler/src/bundle/appimage_bundle.rs @@ -47,7 +47,8 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { let package_dir = settings.project_out_directory().join("bundle/appimage_deb"); // generate deb_folder structure - deb_bundle::generate_data(settings, &package_dir)?; + let (_, icons) = deb_bundle::generate_data(settings, &package_dir)?; + let icons: Vec = icons.into_iter().collect(); let output_path = settings.project_out_directory().join("bundle/appimage"); if output_path.exists() { @@ -71,6 +72,18 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { sh_map.insert("app_name", settings.main_binary_name()); sh_map.insert("app_name_uppercase", &upcase_app_name); sh_map.insert("appimage_filename", &appimage_filename); + let larger_icon = icons + .iter() + .filter(|i| i.width == i.height) + .max_by_key(|i| i.width) + .expect("couldn't find a square icon to use as AppImage icon"); + let larger_icon_path = larger_icon + .path + .strip_prefix(package_dir.join("data")) + .unwrap() + .to_string_lossy() + .to_string(); + sh_map.insert("icon_path", &larger_icon_path); // initialize shell script template. let temp = HANDLEBARS.render("appimage", &sh_map)?; diff --git a/tooling/bundler/src/bundle/deb_bundle.rs b/tooling/bundler/src/bundle/deb_bundle.rs index 89636bb8b..05cc52c91 100644 --- a/tooling/bundler/src/bundle/deb_bundle.rs +++ b/tooling/bundler/src/bundle/deb_bundle.rs @@ -39,6 +39,14 @@ use std::{ path::{Path, PathBuf}, }; +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub struct DebIcon { + pub width: u32, + pub height: u32, + pub is_high_density: bool, + pub path: PathBuf, +} + /// Bundles the project. /// Returns a vector of PathBuf that shows where the DEB was created. pub fn bundle_project(settings: &Settings) -> crate::Result> { @@ -63,7 +71,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { } let package_path = base_dir.join(package_name); - let data_dir = generate_data(settings, &package_dir) + let (data_dir, _) = generate_data(settings, &package_dir) .with_context(|| "Failed to build data folders and files")?; // Generate control files. let control_dir = package_dir.join("control"); @@ -91,7 +99,10 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { } /// Generate the debian data folders and files. -pub fn generate_data(settings: &Settings, package_dir: &Path) -> crate::Result { +pub fn generate_data( + settings: &Settings, + package_dir: &Path, +) -> crate::Result<(PathBuf, BTreeSet)> { // Generate data files. let data_dir = package_dir.join("data"); let bin_dir = data_dir.join("usr/bin"); @@ -108,7 +119,8 @@ pub fn generate_data(settings: &Settings, package_dir: &Path) -> crate::Result

crate::Result

crate::Resul } /// Generate the icon files and store them under the `data_dir`. -fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<()> { +fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result> { let base_dir = data_dir.join("usr/share/icons/hicolor"); let get_dest_path = |width: u32, height: u32, is_high_density: bool| { base_dir.join(format!( @@ -318,7 +330,7 @@ fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<() settings.main_binary_name() )) }; - let mut sizes = BTreeSet::new(); + let mut icons = BTreeSet::new(); // Prefer PNG files. for icon_path in settings.icon_files() { let icon_path = icon_path?; @@ -329,10 +341,16 @@ fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<() let width = decoder.dimensions().0; let height = decoder.dimensions().1; let is_high_density = common::is_retina(&icon_path); - if !sizes.contains(&(width, height, is_high_density)) { - sizes.insert((width, height, is_high_density)); - let dest_path = get_dest_path(width, height, is_high_density); - common::copy_file(&icon_path, &dest_path)?; + let dest_path = get_dest_path(width, height, is_high_density); + let deb_icon = DebIcon { + width, + height, + is_high_density, + path: dest_path, + }; + if !icons.contains(&deb_icon) { + common::copy_file(&icon_path, &deb_icon.path)?; + icons.insert(deb_icon); } } // Fall back to non-PNG files for any missing sizes. @@ -346,28 +364,40 @@ fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<() let width = icon_type.screen_width(); let height = icon_type.screen_height(); let is_high_density = icon_type.pixel_density() > 1; - if !sizes.contains(&(width, height, is_high_density)) { - sizes.insert((width, height, is_high_density)); - let dest_path = get_dest_path(width, height, is_high_density); + let dest_path = get_dest_path(width, height, is_high_density); + let deb_icon = DebIcon { + width, + height, + is_high_density, + path: dest_path, + }; + if !icons.contains(&deb_icon) { let icon = icon_family.get_icon_with_type(icon_type)?; - icon.write_png(common::create_file(&dest_path)?)?; + icon.write_png(common::create_file(&deb_icon.path)?)?; + icons.insert(deb_icon); } } } else { let icon = image::open(&icon_path)?; let (width, height) = icon.dimensions(); let is_high_density = common::is_retina(&icon_path); - if !sizes.contains(&(width, height, is_high_density)) { - sizes.insert((width, height, is_high_density)); - let dest_path = get_dest_path(width, height, is_high_density); + let dest_path = get_dest_path(width, height, is_high_density); + let deb_icon = DebIcon { + width, + height, + is_high_density, + path: dest_path, + }; + if !icons.contains(&deb_icon) { icon.write_to( - &mut common::create_file(&dest_path)?, + &mut common::create_file(&deb_icon.path)?, image::ImageOutputFormat::Png, )?; + icons.insert(deb_icon); } } } - Ok(()) + Ok(icons) } /// Create an empty file at the given path, creating any parent directories as diff --git a/tooling/bundler/src/bundle/templates/appimage b/tooling/bundler/src/bundle/templates/appimage index 297d2ffd4..138e40188 100644 --- a/tooling/bundler/src/bundle/templates/appimage +++ b/tooling/bundler/src/bundle/templates/appimage @@ -15,13 +15,13 @@ cd "{{app_name}}.AppDir" wget -q -4 -O AppRun https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-x86_64 || wget -q -4 -O AppRun https://github.com/AppImage/AppImageKit/releases/download/12/AppRun-aarch64 chmod +x AppRun -cp "usr/share/icons/hicolor/256x256/apps/{{app_name}}.png" "{{app_name}}.png" +cp "{{icon_path}}" .DirIcon +ln -s "{{icon_path}}" "{{app_name}}.png" + +ln -s "usr/share/applications/{{app_name}}.desktop" "{{app_name}}.desktop" cd .. -cp "../appimage_deb/data/usr/share/applications/{{app_name}}.desktop" "{{app_name}}.AppDir/usr/share/applications/{{app_name}}.desktop" -cp "../appimage_deb/data/usr/share/applications/{{app_name}}.desktop" "{{app_name}}.AppDir/{{app_name}}.desktop" - mksquashfs "{{app_name}}.AppDir" "{{app_name}}.squashfs" -root-owned -noappend wget -q -4 -O appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage || wget -q -4 -O appimagetool https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage