import { app } from 'electron'; import AutoLaunch from 'auto-launch'; import * as fsp from 'fs/promises'; import * as path from 'path'; import { readDesktopSettings } from '../desktop-settings'; let autoLauncher: AutoLaunch | null = null; let autoLaunchPath = ''; const LINUX_AUTO_START_ARGUMENTS = ['--no-sandbox', '%U']; function resolveLaunchPath(): string { // AppImage runs from a temporary mount; APPIMAGE points to the real file path. const appImagePath = process.platform === 'linux' ? String(process.env['APPIMAGE'] || '').trim() : ''; return appImagePath || process.execPath; } function escapeDesktopEntryExecArgument(argument: string): string { const escapedArgument = argument.replace(/(["\\$`])/g, '\\$1'); return /[\s"]/u.test(argument) ? `"${escapedArgument}"` : escapedArgument; } function getLinuxAutoStartDesktopEntryPath(launchPath: string): string { return path.join(app.getPath('home'), '.config', 'autostart', `${path.basename(launchPath)}.desktop`); } function buildLinuxAutoStartExecLine(launchPath: string): string { return `Exec=${[escapeDesktopEntryExecArgument(launchPath), ...LINUX_AUTO_START_ARGUMENTS].join(' ')}`; } function buildLinuxAutoStartDesktopEntry(launchPath: string): string { const appName = path.basename(launchPath); return [ '[Desktop Entry]', 'Type=Application', 'Version=1.0', `Name=${appName}`, `Comment=${appName}startup script`, buildLinuxAutoStartExecLine(launchPath), 'StartupNotify=false', 'Terminal=false' ].join('\n'); } async function synchronizeLinuxAutoStartDesktopEntry(launchPath: string): Promise { if (process.platform !== 'linux') { return; } const desktopEntryPath = getLinuxAutoStartDesktopEntryPath(launchPath); const execLine = buildLinuxAutoStartExecLine(launchPath); let currentDesktopEntry = ''; try { currentDesktopEntry = await fsp.readFile(desktopEntryPath, 'utf8'); } catch { // Create the desktop entry if auto-launch did not leave one behind. } const nextDesktopEntry = currentDesktopEntry ? /^Exec=.*$/m.test(currentDesktopEntry) ? currentDesktopEntry.replace(/^Exec=.*$/m, execLine) : `${currentDesktopEntry.trimEnd()}\n${execLine}\n` : buildLinuxAutoStartDesktopEntry(launchPath); if (nextDesktopEntry === currentDesktopEntry) { return; } await fsp.mkdir(path.dirname(desktopEntryPath), { recursive: true }); await fsp.writeFile(desktopEntryPath, nextDesktopEntry, 'utf8'); } function getAutoLauncher(): AutoLaunch | null { if (!app.isPackaged) { return null; } if (!autoLauncher) { autoLaunchPath = resolveLaunchPath(); autoLauncher = new AutoLaunch({ name: app.getName(), path: autoLaunchPath }); } return autoLauncher; } async function setAutoStartEnabled(enabled: boolean): Promise { const launcher = getAutoLauncher(); if (!launcher) { return; } const currentlyEnabled = await launcher.isEnabled(); if (!enabled && currentlyEnabled === enabled) { return; } if (enabled) { if (!currentlyEnabled) { await launcher.enable(); } await synchronizeLinuxAutoStartDesktopEntry(autoLaunchPath); return; } await launcher.disable(); } export async function synchronizeAutoStartSetting(enabled = readDesktopSettings().autoStart): Promise { try { await setAutoStartEnabled(enabled); } catch { // Auto-launch integration should never block app startup or settings saves. } }