diff --git a/apps/desktop/electron/main/icon-path.test.ts b/apps/desktop/electron/main/icon-path.test.ts index f6423aa..22cbd92 100644 --- a/apps/desktop/electron/main/icon-path.test.ts +++ b/apps/desktop/electron/main/icon-path.test.ts @@ -1,4 +1,4 @@ -import { readFileSync } from 'node:fs' +import { readdirSync, readFileSync } from 'node:fs' import { join } from 'node:path' import { describe, expect, it } from 'vitest' import { resolveIconPath, WM_CLASS } from './icon-path.js' @@ -39,6 +39,49 @@ describe('StartupWMClass', () => { it('is what electron-builder writes into the packaged entry', () => { const manifest = JSON.parse(readFileSync(join(root, 'apps', 'desktop', 'package.json'), 'utf8')) - expect(manifest.build.linux.desktop.entry.StartupWMClass).toBe(WM_CLASS) + expect(manifest.build.linux.desktop.StartupWMClass).toBe(WM_CLASS) + }) + + it('is a flat map, which is the only shape electron-builder 25 reads', () => { + // `desktop: { entry: {...} }` is electron-builder 26 syntax. 25 stringifies + // the nested object, so the deb shipped `entry=[object Object]` and lost + // its Keywords without a warning. + const manifest = JSON.parse(readFileSync(join(root, 'apps', 'desktop', 'package.json'), 'utf8')) + for (const value of Object.values(manifest.build.linux.desktop)) { + expect(typeof value).toBe('string') + } + }) +}) + +describe('Linux icon set', () => { + /** + * An icon theme is searched only in the directories its index.theme lists. + * Given one PNG, electron-builder files it under its pixel size, and the + * 1254px source landed in hicolor/1254x1254/, which no desktop looks in, so + * Plasma drew a generic icon. The set has to be standard sizes, each file + * really that size. + */ + const root = join(import.meta.dirname, '..', '..', '..', '..') + const desktop = join(root, 'apps', 'desktop') + const HICOLOR = [16, 22, 24, 32, 48, 64, 96, 128, 192, 256, 512] + + it('is the directory both electron-builder and the tarball use', () => { + const manifest = JSON.parse(readFileSync(join(desktop, 'package.json'), 'utf8')) + expect(manifest.build.linux.icon).toBe('resources/icons') + expect(manifest.build.extraResources).toContainEqual({ from: 'resources/icons', to: 'icons' }) + }) + + it('holds only hicolor sizes, each file the size its name says', () => { + const files = readdirSync(join(desktop, 'resources', 'icons')) + expect(files).toContain('512x512.png') + for (const file of files) { + const match = /^(\d+)x(\d+)\.png$/.exec(file) + expect(match, file).not.toBeNull() + const size = Number(match![1]) + expect(HICOLOR, file).toContain(size) + // A PNG's IHDR puts width and height at bytes 16 and 20. + const png = readFileSync(join(desktop, 'resources', 'icons', file)) + expect([png.readUInt32BE(16), png.readUInt32BE(20)], file).toEqual([size, size]) + } }) }) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 5877f38..9ccfd78 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -67,6 +67,10 @@ "from": "resources/icon.png", "to": "icon.png" }, + { + "from": "resources/icons", + "to": "icons" + }, { "from": "resources/launch.sh", "to": "launch.sh" @@ -81,12 +85,10 @@ "deb", "tar.gz" ], - "icon": "resources/icon.png", + "icon": "resources/icons", "desktop": { - "entry": { - "Keywords": "rsync;sftp;ssh;sync;transfer;backup;", - "StartupWMClass": "DiskPush" - } + "Keywords": "rsync;sftp;ssh;sync;transfer;backup;", + "StartupWMClass": "DiskPush" }, "artifactName": "${productName}-${version}-linux-${arch}.${ext}" }, diff --git a/apps/desktop/resources/icons/128x128.png b/apps/desktop/resources/icons/128x128.png new file mode 100644 index 0000000..3e44435 Binary files /dev/null and b/apps/desktop/resources/icons/128x128.png differ diff --git a/apps/desktop/resources/icons/16x16.png b/apps/desktop/resources/icons/16x16.png new file mode 100644 index 0000000..37ab320 Binary files /dev/null and b/apps/desktop/resources/icons/16x16.png differ diff --git a/apps/desktop/resources/icons/24x24.png b/apps/desktop/resources/icons/24x24.png new file mode 100644 index 0000000..2564b59 Binary files /dev/null and b/apps/desktop/resources/icons/24x24.png differ diff --git a/apps/desktop/resources/icons/256x256.png b/apps/desktop/resources/icons/256x256.png new file mode 100644 index 0000000..ce9d5b1 Binary files /dev/null and b/apps/desktop/resources/icons/256x256.png differ diff --git a/apps/desktop/resources/icons/32x32.png b/apps/desktop/resources/icons/32x32.png new file mode 100644 index 0000000..f7113a3 Binary files /dev/null and b/apps/desktop/resources/icons/32x32.png differ diff --git a/apps/desktop/resources/icons/48x48.png b/apps/desktop/resources/icons/48x48.png new file mode 100644 index 0000000..5c144cf Binary files /dev/null and b/apps/desktop/resources/icons/48x48.png differ diff --git a/apps/desktop/resources/icons/512x512.png b/apps/desktop/resources/icons/512x512.png new file mode 100644 index 0000000..9b390ba Binary files /dev/null and b/apps/desktop/resources/icons/512x512.png differ diff --git a/apps/desktop/resources/icons/64x64.png b/apps/desktop/resources/icons/64x64.png new file mode 100644 index 0000000..05cbe1a Binary files /dev/null and b/apps/desktop/resources/icons/64x64.png differ diff --git a/scripts/install.sh b/scripts/install.sh index 49a8a77..a4fc6a8 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -151,9 +151,29 @@ FALLBACK # A launcher, an icon, and a menu entry. This is what a .deb would give # you; done by hand because doing it by hand needs no root. - mkdir -p "$PREFIX/share/applications" "$PREFIX/share/icons/hicolor/512x512/apps" - [ -f "$SHARE/app/resources/icon.png" ] && - cp "$SHARE/app/resources/icon.png" "$PREFIX/share/icons/hicolor/512x512/apps/diskpush.png" + # + # Icons go in one file per hicolor size. An icon theme is only searched in + # the directories its index.theme lists, so the size directory has to be a + # real one: the source PNG is 1254px, and a 1254x1254/ directory (what the + # deb used to get) is simply never looked in. Bundles before 0.12.6 carry + # only that one PNG; it still goes under 512x512, which Plasma scales. + mkdir -p "$PREFIX/share/applications" + ICONS="$PREFIX/share/icons/hicolor" + if [ -d "$SHARE/app/resources/icons" ]; then + for png in "$SHARE/app/resources/icons"/*x*.png; do + [ -f "$png" ] || continue + size="$(basename "$png" .png)" + mkdir -p "$ICONS/$size/apps" + cp "$png" "$ICONS/$size/apps/diskpush.png" + PATHS="$PATHS +$ICONS/$size/apps/diskpush.png" + done + elif [ -f "$SHARE/app/resources/icon.png" ]; then + mkdir -p "$ICONS/512x512/apps" + cp "$SHARE/app/resources/icon.png" "$ICONS/512x512/apps/diskpush.png" + PATHS="$PATHS +$ICONS/512x512/apps/diskpush.png" + fi cat > "$PREFIX/share/applications/diskpush.desktop" </dev/null 2>&1 || true PATHS="$PATHS -$PREFIX/share/applications/diskpush.desktop -$PREFIX/share/icons/hicolor/512x512/apps/diskpush.png" +$PREFIX/share/applications/diskpush.desktop" else ASSET="DiskPush-$VERSION-mac-$ARCH.zip"