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:
240240 shell: pwsh
241241 run: |
242242 $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
243 $installPath = & $vswhere -products * -latest -property installationPath
244 $setupExe = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe"
245 $proc = Start-Process -FilePath $setupExe `
246 -ArgumentList "modify", "--installPath", "`"$installPath`"", "--add", `
247 "Microsoft.VisualStudio.Component.VC.Tools.x86.x64.Spectre", "--quiet", "--norestart" `
248 -Wait -PassThru -NoNewWindow
249 if ($null -eq $proc -or $proc.ExitCode -ne 0) {
250 $code = if ($null -ne $proc) { $proc.ExitCode } else { 1 }
251 Write-Error "Visual Studio Installer failed with exit code $code"
252 exit $code
253 }
243 $installPath = & $vswhere -products * -latest -property installationPath
244 $setupExe = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe"
245 $proc = Start-Process -FilePath $setupExe `
246 -ArgumentList "modify", "--installPath", "`"$installPath`"", "--add", `
247 "Microsoft.VisualStudio.Component.VC.Tools.x86.x64.Spectre", "--quiet", "--norestart" `
248 -Wait -PassThru -NoNewWindow
249 if ($null -eq $proc -or $proc.ExitCode -ne 0) {
250 $code = if ($null -ne $proc) { $proc.ExitCode } else { 1 }
251 Write-Error "Visual Studio Installer failed with exit code $code"
252 exit $code
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
255270 - name: Prepare Azure Trusted Signing
256271 if: matrix.platform == 'win'
scripts/build-desktop-artifact.ts+44-3
......@@ -23,6 +23,8 @@ import * as Stream from "effect/Stream";
2323import { Command, Flag } from "effect/unstable/cli";
2424import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
2525
26const LINUX_ICON_SIZES = [16, 22, 24, 32, 48, 64, 128, 256, 512] as const;
27
2628const BuildPlatform = Schema.Literals(["mac", "linux", "win"]);
2729const BuildArch = Schema.Literals(["arm64", "x64", "universal"]);
2830
......@@ -417,7 +419,7 @@ function stageMacIcons(stageResourcesDir: string, sourcePng: string, verbose: bo
417419 });
418420}
419421
420function stageLinuxIcons(stageResourcesDir: string, sourcePng: string) {
422function stageLinuxIcons(stageResourcesDir: string, sourcePng: string, verbose: boolean) {
421423 return Effect.gen(function* () {
422424 const fs = yield* FileSystem.FileSystem;
423425 const path = yield* Path.Path;
......@@ -429,9 +431,48 @@ function stageLinuxIcons(stageResourcesDir: string, sourcePng: string) {
429431
430432 const iconPath = path.join(stageResourcesDir, "icon.png");
431433 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 }
432445 });
433446}
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
435476function stageWindowsIcons(stageResourcesDir: string, sourceIco: string) {
436477 return Effect.gen(function* () {
437478 const fs = yield* FileSystem.FileSystem;
......@@ -600,7 +641,7 @@ const createBuildConfig = Effect.fn("createBuildConfig")(function* (
600641 buildConfig.linux = {
601642 target: [target],
602643 executableName: "t3code",
603 icon: "icon.png",
644 icon: "icons",
604645 category: "Development",
605646 desktop: {
606647 entry: {
......@@ -639,7 +680,7 @@ const assertPlatformBuildResources = Effect.fn("assertPlatformBuildResources")(f
639680 }
640681
641682 if (platform === "linux") {
642 yield* stageLinuxIcons(stageResourcesDir, iconAssets.linuxIconPng);
683 yield* stageLinuxIcons(stageResourcesDir, iconAssets.linuxIconPng, verbose);
643684 return;
644685 }
645686