diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index ce48a7431..3fe624cf2 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -65,6 +65,7 @@ const APP_DISPLAY_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; const APP_USER_MODEL_ID = "com.t3tools.t3code"; const USER_DATA_DIR_NAME = isDevelopment ? "t3code-dev" : "t3code"; const LEGACY_USER_DATA_DIR_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; +const APPIMAGE_ICON_BASENAME = "t3-code-desktop.png"; const COMMIT_HASH_PATTERN = /^[0-9a-f]{7,40}$/i; const COMMIT_HASH_DISPLAY_LENGTH = 12; const LOG_DIR = Path.join(STATE_DIR, "logs"); @@ -618,8 +619,108 @@ function resolveResourcePath(fileName: string): string | null { return null; } +let cachedAppImageIconPath: string | null | undefined; + +function resolveAppImageIconPath(): string | null { + if (cachedAppImageIconPath !== undefined) { + return cachedAppImageIconPath; + } + + const executablePath = Path.resolve(process.execPath); + const executableDir = Path.dirname(executablePath); + const executableBase = Path.basename(executablePath, Path.extname(executablePath)); + const iconBaseNames = [ + APPIMAGE_ICON_BASENAME.replace(/\.png$/, ""), + executableBase, + "t3-code-desktop", + ]; + const iconSizes = ["1024x1024", "512x512", "256x256", "128x128", "64x64", "48x48", "32x32"]; + + const appImageRoots: string[] = []; + const seenRoots = new Set(); + const pushRoot = (root: string) => { + if (!seenRoots.has(root)) { + seenRoots.add(root); + appImageRoots.push(root); + } + }; + + pushRoot(Path.resolve(process.resourcesPath, "..")); + pushRoot(Path.resolve(process.resourcesPath)); + pushRoot(executableDir); + + if (process.env.APPDIR) { + pushRoot(Path.resolve(process.env.APPDIR)); + } + + if (process.env.APPIMAGE) { + pushRoot(Path.resolve(process.env.APPIMAGE, "..")); + } + + const triedCandidates = new Set(); + const tryCandidate = (candidate: string): string | null => { + if (triedCandidates.has(candidate)) { + return null; + } + triedCandidates.add(candidate); + if (FS.existsSync(candidate)) { + cachedAppImageIconPath = candidate; + return candidate; + } + return null; + }; + + for (const root of appImageRoots) { + const candidate = tryCandidate(Path.join(root, ".DirIcon")); + if (candidate) { + return candidate; + } + } + + for (const iconBaseName of iconBaseNames) { + for (const root of appImageRoots) { + const candidate = tryCandidate(Path.join(root, `${iconBaseName}.png`)); + if (candidate) { + return candidate; + } + } + + for (const iconSize of iconSizes) { + for (const root of appImageRoots) { + const candidate = tryCandidate( + Path.join( + root, + "usr", + "share", + "icons", + "hicolor", + iconSize, + "apps", + `${iconBaseName}.png`, + ), + ); + if (candidate) { + return candidate; + } + } + } + } + + cachedAppImageIconPath = null; + return null; +} + function resolveIconPath(ext: "ico" | "icns" | "png"): string | null { - return resolveResourcePath(`icon.${ext}`); + const iconPath = resolveResourcePath(`icon.${ext}`); + if (iconPath) { + return iconPath; + } + + if (process.platform === "linux") { + return resolveAppImageIconPath(); + } + + return null; } /**