Browse Source

fix(bundler): find icon for AppImage, define `.DirIcon`, closes #749 (#1594)

Lucas Fernandes Nogueira 4 years ago
parent
commit
fbf73f3ab5

+ 5 - 0
.changes/appimage-icon.md

@@ -0,0 +1,5 @@
+---
+"tauri-bundler": patch
+---
+
+Find best available icon for AppImage, follow `.DirIcon` spec.

+ 14 - 1
tooling/bundler/src/bundle/appimage_bundle.rs

@@ -47,7 +47,8 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
   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<deb_bundle::DebIcon> = 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<Vec<PathBuf>> {
   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)?;

+ 49 - 19
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<Vec<PathBuf>> {
@@ -63,7 +71,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
   }
   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<Vec<PathBuf>> {
 }
 
 /// Generate the debian data folders and files.
-pub fn generate_data(settings: &Settings, package_dir: &Path) -> crate::Result<PathBuf> {
+pub fn generate_data(
+  settings: &Settings,
+  package_dir: &Path,
+) -> crate::Result<(PathBuf, BTreeSet<DebIcon>)> {
   // 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<P
     .copy_binaries(&bin_dir)
     .with_context(|| "Failed to copy external binaries")?;
 
-  generate_icon_files(settings, &data_dir).with_context(|| "Failed to create icon files")?;
+  let icons =
+    generate_icon_files(settings, &data_dir).with_context(|| "Failed to create icon files")?;
   generate_desktop_file(settings, &data_dir).with_context(|| "Failed to create desktop file")?;
 
   let use_bootstrapper = settings.deb().use_bootstrapper.unwrap_or_default();
@@ -117,7 +129,7 @@ pub fn generate_data(settings: &Settings, package_dir: &Path) -> crate::Result<P
       .with_context(|| "Failed to generate bootstrap file")?;
   }
 
-  Ok(data_dir)
+  Ok((data_dir, icons))
 }
 
 /// Generates the bootstrap script file.
@@ -307,7 +319,7 @@ fn transfer_resource_files(settings: &Settings, data_dir: &Path) -> 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<BTreeSet<DebIcon>> {
   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

+ 4 - 4
tooling/bundler/src/bundle/templates/appimage

@@ -15,12 +15,12 @@ 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"
 
-cd ..
+ln -s "usr/share/applications/{{app_name}}.desktop" "{{app_name}}.desktop"
 
-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"
+cd ..
 
 mksquashfs "{{app_name}}.AppDir" "{{app_name}}.squashfs" -root-owned -noappend