From 7a40437bddfaedeb4d0300afbc1bb2cbf9081290 Mon Sep 17 00:00:00 2001 From: toonn Date: Mon, 21 Mar 2022 12:35:42 +0100 Subject: [PATCH 1/5] write-darwin-bundle: Invert squircle logic Older macOS cannot interpret the `CFBundleIconFiles` key so we cannot rewrite the `CFBundleIconFile` entry without special consideration. I opted to fix this by inverting the squircle logic. We always add both the `CFBundleIconFile` and `CFBundleIconFiles` keys. The former is necessary for at least macOS 10.13 and probably 10.12. The latter seems to be ignored on those versions and overrides the former on newer versions of macOS. Inverting the logic also allows us to rely on the `toPlist` generator to generate the XML syntax, which is a nice bonus. --- .../make-darwin-bundle/write-darwin-bundle.nix | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix b/pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix index d21e0475e2d..fde977c3636 100644 --- a/pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix +++ b/pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix @@ -5,6 +5,7 @@ let CFBundleDevelopmentRegion = "English"; CFBundleExecutable = "$name"; CFBundleIconFile = "$icon"; + CFBundleIconFiles = [ "$icon" ]; CFBundleIdentifier = "org.nixos.$name"; CFBundleInfoDictionaryVersion = "6.0"; CFBundleName = "$name"; @@ -25,11 +26,8 @@ in writeScriptBin "write-darwin-bundle" '' ${pListText} EOF - if [[ $squircle != 0 && $squircle != "false" ]]; then - sed " - s|CFBundleIconFile|CFBundleIconFiles|; - s|$icon|$icon| - " -i "$plist" + if [[ $squircle == 0 || $squircle == "false" ]]; then + sed '/CFBundleIconFiles/,\||d' -i "$plist" fi cat > "$prefix/Applications/$name.app/Contents/MacOS/$name" < Date: Mon, 21 Mar 2022 12:41:52 +0100 Subject: [PATCH 2/5] desktopToDarwinBundle: Drop 48x48 size On macOS 10.13 the 48x48 icon size is not supported. It results in a corrupted image being displayed. I suspect the image data is being truncated to what it expects for 32x32 or maybe data is read for 128x128, which would be a buffer overflow. --- .../setup-hooks/desktop-to-darwin-bundle.sh | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh index b2e2738cb6e..235cb0323b3 100644 --- a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh +++ b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh @@ -18,7 +18,9 @@ convertIconTheme() { local -r iconName=$3 local -r theme=${4:-hicolor} - local -ra iconSizes=(16 32 48 128 256 512) + # Sizes based on archived Apple documentation: + # https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/app-icon#app-icon-sizes + local -ra iconSizes=(16 32 128 256 512) local -ra scales=([1]="" [2]="@2") # Based loosely on the algorithm at: @@ -31,13 +33,6 @@ convertIconTheme() { local scaleSuffix=${scales[$scale]} local exactSize=${iconSize}x${iconSize}${scaleSuffix} - if [[ $exactSize = '48x48@2' ]]; then - # macOS does not support a 2x scale variant of 48x48 icons - # See: https://en.wikipedia.org/wiki/Apple_Icon_Image_format#Icon_types - echo "unsupported" - return 0 - fi - local -a validSizes=( ${exactSize} $((iconSize + 1))x$((iconSize + 1))${scaleSuffix} From c3d974e44181603e73ec541568c0e8b102cecd0e Mon Sep 17 00:00:00 2001 From: toonn Date: Mon, 21 Mar 2022 12:44:51 +0100 Subject: [PATCH 3/5] desktopToDarwinBundle: Simplify double negation --- pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh index 235cb0323b3..5b67378aa78 100644 --- a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh +++ b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh @@ -132,8 +132,8 @@ convertIconTheme() { } iconsdir=$(getIcons "$sharePath" "apps/${iconName}" "$theme") - if [[ ! -z "$(ls -1 "$iconsdir/"*)" ]]; then icnsutil compose "$out/${iconName}.icns" "$iconsdir/"* + if [[ -n "$(ls -1 "$iconsdir/"*)" ]]; then else echo "Warning: no icons were found. Creating an empty icon for ${iconName}.icns." touch "$out/${iconName}.icns" From 08a2b83c9630fb191022dda93d62cc1c0f9e5aa4 Mon Sep 17 00:00:00 2001 From: toonn Date: Mon, 21 Mar 2022 12:45:26 +0100 Subject: [PATCH 4/5] desktopToDarwinBundle: Include TOC in generated ICNS file In order to compose a `.icns` file containing multiple icon sizes I had to pass `--toc` to `icnsutil`. This did not seem to have a negative effect on `.icns` containing only a single icon size. --- pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh index 5b67378aa78..0519d183ba9 100644 --- a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh +++ b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh @@ -132,8 +132,8 @@ convertIconTheme() { } iconsdir=$(getIcons "$sharePath" "apps/${iconName}" "$theme") - icnsutil compose "$out/${iconName}.icns" "$iconsdir/"* if [[ -n "$(ls -1 "$iconsdir/"*)" ]]; then + icnsutil compose --toc "$out/${iconName}.icns" "$iconsdir/"* else echo "Warning: no icons were found. Creating an empty icon for ${iconName}.icns." touch "$out/${iconName}.icns" From 6aa5c537483e9cc9cbd66ac28fef8800ba306f97 Mon Sep 17 00:00:00 2001 From: toonn Date: Mon, 21 Mar 2022 13:26:19 +0100 Subject: [PATCH 5/5] desktopToDarwinBundle: Fall back to scaling available Sometimes scalable icons or icons within the thresholds from the desired resolutions aren't available. In this case it's still nicer to end up with a blocky scaled icon rather than the generic default. --- .../setup-hooks/desktop-to-darwin-bundle.sh | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh index 0519d183ba9..d54af90b688 100644 --- a/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh +++ b/pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh @@ -50,8 +50,10 @@ convertIconTheme() { else echo "threshold $icon" fi - return 0 + elif [[ -a $icon ]]; then + echo "fallback $icon" fi + return 0 done done echo "scalable" @@ -101,6 +103,17 @@ convertIconTheme() { scalableIcon=('-') fi + # Tri-state variable, NONE means no icons have been found, an empty + # icns file will be generated, not sure that's necessary because macOS + # will default to a generic icon if no icon can be found. + # + # OTHER means an appropriate icon was found. + # + # Any other value is a path to an icon file that isn't scalable or + # within the threshold. This is used as a fallback in case no better + # icon can be found and will be scaled as much as + # necessary to result in appropriate icon sizes. + local foundIcon=NONE for iconSize in "${iconSizes[@]}"; do for scale in "${!scales[@]}"; do local iconResult=$(findIcon $iconSize $scale) @@ -112,6 +125,7 @@ convertIconTheme() { fixed) local density=$((72 * scale))x$((72 * scale)) magick convert -density "$density" -units PixelsPerInch "$icon" "$result" + foundIcon=OTHER ;; threshold) # Synthesize an icon of the exact size if a scalable icon is available @@ -119,15 +133,32 @@ convertIconTheme() { if ! synthesizeIcon "${scalableIcon[0]}" "$result" "$iconSize" "$scale"; then resizeIcon "$icon" "$result" "$iconSize" "$scale" fi + foundIcon=OTHER ;; scalable) synthesizeIcon "${scalableIcon[0]}" "$result" "$iconSize" "$scale" || true + foundIcon=OTHER + ;; + fallback) + # Use the largest size available to scale to + # appropriate sizes. + if [[ $foundIcon != OTHER ]]; then + foundIcon=$icon + fi ;; *) ;; esac done done + if [[ $foundIcon != NONE && $foundIcon != OTHER ]]; then + # Ideally we'd only resize to whatever the closest sizes are, + # starting from whatever icon sizes are available. + for iconSize in 16 32 128 256 512; do + local result=${resultdir}/${iconSize}x${iconSize}.png + resizeIcon "$foundIcon" "$result" "$iconSize" 1 + done + fi echo "$resultdir" }