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'; import { DESKTOP_APP_DISPLAY_NAME, patchLinuxAutostartDesktopEntryNameField } from './desktop-branding.rules'; import { resolveLaunchPath } from './launch-path'; let autoLauncher: AutoLaunch | null = null; let autoLaunchPath = ''; const LINUX_AUTO_START_ARGUMENTS = ['--no-sandbox', '%U']; 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 { return [ '[Desktop Entry]', 'Type=Application', 'Version=1.0', `Name=${DESKTOP_APP_DISPLAY_NAME}`, `Comment=${DESKTOP_APP_DISPLAY_NAME} 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 = patchLinuxAutostartDesktopEntryNameField( 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: DESKTOP_APP_DISPLAY_NAME, 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. } }