authorgravatar for mwolson@member.fsf.orgMike Olson <mwolson@member.fsf.org> 2026-06-02 23:38:29-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-02 20:38:29-07:00
logf0116e44b6806a949fbd449b4548f3cfc6638510
treeac0431c451108133c00697ac301e49b310369a8f
parentbd851c0203f4318b8222566ef87009a189cdf1f5
signature Signed by PGP key B5690EEEBB952194

fix(desktop): Include standard Linux AppImage icons for Niri/Noctalia (#2915)


2 files changed, 70 insertions(+), 14 deletions(-)

.github/workflows/release.yml+26-11
...@@ -240,17 +240,32 @@ jobs:...@@ -240,17 +240,32 @@ jobs:
240 shell: pwsh240 shell: pwsh
241 run: |241 run: |
242 $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"242 $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
243 $installPath = & $vswhere -products * -latest -property installationPath243 $installPath = & $vswhere -products * -latest -property installationPath
244 $setupExe = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe"244 $setupExe = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe"
245 $proc = Start-Process -FilePath $setupExe `245 $proc = Start-Process -FilePath $setupExe `
246 -ArgumentList "modify", "--installPath", "`"$installPath`"", "--add", `246 -ArgumentList "modify", "--installPath", "`"$installPath`"", "--add", `
247 "Microsoft.VisualStudio.Component.VC.Tools.x86.x64.Spectre", "--quiet", "--norestart" `247 "Microsoft.VisualStudio.Component.VC.Tools.x86.x64.Spectre", "--quiet", "--norestart" `
248 -Wait -PassThru -NoNewWindow248 -Wait -PassThru -NoNewWindow
249 if ($null -eq $proc -or $proc.ExitCode -ne 0) {249 if ($null -eq $proc -or $proc.ExitCode -ne 0) {
250 $code = if ($null -ne $proc) { $proc.ExitCode } else { 1 }250 $code = if ($null -ne $proc) { $proc.ExitCode } else { 1 }
251 Write-Error "Visual Studio Installer failed with exit code $code"251 Write-Error "Visual Studio Installer failed with exit code $code"
252 exit $code252 exit $code
253 }253 }
254
255 - name: Install ImageMagick
256 if: matrix.platform == 'linux'
257 shell: bash
258 run: |
259 if ! command -v magick >/dev/null 2>&1 && ! command -v convert >/dev/null 2>&1; then
260 sudo apt-get update
261 sudo apt-get install -y imagemagick
262 fi
263
264 if command -v magick >/dev/null 2>&1; then
265 magick -version
266 else
267 convert -version
268 fi
254269
255 - name: Prepare Azure Trusted Signing270 - name: Prepare Azure Trusted Signing
256 if: matrix.platform == 'win'271 if: matrix.platform == 'win'
scripts/build-desktop-artifact.ts+44-3
...@@ -23,6 +23,8 @@ import * as Stream from "effect/Stream";...@@ -23,6 +23,8 @@ import * as Stream from "effect/Stream";
23import { Command, Flag } from "effect/unstable/cli";23import { Command, Flag } from "effect/unstable/cli";
24import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";24import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
2525
26const LINUX_ICON_SIZES = [16, 22, 24, 32, 48, 64, 128, 256, 512] as const;
27
26const BuildPlatform = Schema.Literals(["mac", "linux", "win"]);28const BuildPlatform = Schema.Literals(["mac", "linux", "win"]);
27const BuildArch = Schema.Literals(["arm64", "x64", "universal"]);29const BuildArch = Schema.Literals(["arm64", "x64", "universal"]);
2830
...@@ -417,7 +419,7 @@ function stageMacIcons(stageResourcesDir: string, sourcePng: string, verbose: bo...@@ -417,7 +419,7 @@ function stageMacIcons(stageResourcesDir: string, sourcePng: string, verbose: bo
417 });419 });
418}420}
419421
420function stageLinuxIcons(stageResourcesDir: string, sourcePng: string) {422function stageLinuxIcons(stageResourcesDir: string, sourcePng: string, verbose: boolean) {
421 return Effect.gen(function* () {423 return Effect.gen(function* () {
422 const fs = yield* FileSystem.FileSystem;424 const fs = yield* FileSystem.FileSystem;
423 const path = yield* Path.Path;425 const path = yield* Path.Path;
...@@ -429,9 +431,48 @@ function stageLinuxIcons(stageResourcesDir: string, sourcePng: string) {...@@ -429,9 +431,48 @@ function stageLinuxIcons(stageResourcesDir: string, sourcePng: string) {
429431
430 const iconPath = path.join(stageResourcesDir, "icon.png");432 const iconPath = path.join(stageResourcesDir, "icon.png");
431 yield* fs.copyFile(sourcePng, iconPath);433 yield* fs.copyFile(sourcePng, iconPath);
434
435 const iconsDir = path.join(stageResourcesDir, "icons");
436 yield* fs.makeDirectory(iconsDir, { recursive: true });
437 for (const iconSize of LINUX_ICON_SIZES) {
438 yield* stageLinuxIconSize(
439 sourcePng,
440 path.join(iconsDir, `${iconSize}x${iconSize}.png`),
441 iconSize,
442 verbose,
443 );
444 }
432 });445 });
433}446}
434447
448function stageLinuxIconSize(
449 sourcePng: string,
450 targetPng: string,
451 iconSize: number,
452 verbose: boolean,
453) {
454 const resize = (command: string) =>
455 runCommand(
456 ChildProcess.make(command, [sourcePng, "-resize", `${iconSize}x${iconSize}`, targetPng], {
457 ...commandOutputOptions(verbose),
458 }),
459 );
460
461 return resize("magick").pipe(
462 Effect.catch(() =>
463 resize("convert").pipe(
464 Effect.mapError(
465 () =>
466 new BuildScriptError({
467 message:
468 "ImageMagick is required to generate Linux desktop icon sizes. Install ImageMagick so either `magick` or `convert` is available.",
469 }),
470 ),
471 ),
472 ),
473 );
474}
475
435function stageWindowsIcons(stageResourcesDir: string, sourceIco: string) {476function stageWindowsIcons(stageResourcesDir: string, sourceIco: string) {
436 return Effect.gen(function* () {477 return Effect.gen(function* () {
437 const fs = yield* FileSystem.FileSystem;478 const fs = yield* FileSystem.FileSystem;
...@@ -600,7 +641,7 @@ const createBuildConfig = Effect.fn("createBuildConfig")(function* (...@@ -600,7 +641,7 @@ const createBuildConfig = Effect.fn("createBuildConfig")(function* (
600 buildConfig.linux = {641 buildConfig.linux = {
601 target: [target],642 target: [target],
602 executableName: "t3code",643 executableName: "t3code",
603 icon: "icon.png",644 icon: "icons",
604 category: "Development",645 category: "Development",
605 desktop: {646 desktop: {
606 entry: {647 entry: {
...@@ -639,7 +680,7 @@ const assertPlatformBuildResources = Effect.fn("assertPlatformBuildResources")(f...@@ -639,7 +680,7 @@ const assertPlatformBuildResources = Effect.fn("assertPlatformBuildResources")(f
639 }680 }
640681
641 if (platform === "linux") {682 if (platform === "linux") {
642 yield* stageLinuxIcons(stageResourcesDir, iconAssets.linuxIconPng);683 yield* stageLinuxIcons(stageResourcesDir, iconAssets.linuxIconPng, verbose);
643 return;684 return;
644 }685 }
645686