diff --git a/src/app/browser/preferences/index.tsx b/src/app/browser/preferences/index.tsx
index 70769d6..25c1c4b 100644
--- a/src/app/browser/preferences/index.tsx
+++ b/src/app/browser/preferences/index.tsx
@@ -22,11 +22,11 @@ export default function Preferences(props: PreferencesProps) {
const [login_item, ,, forceRefreshLoginItem] = useAsync(useCallback(() => ipc.getLoginItemSettings(), [ipc]));
const setOpenAtLogin = useCallback(async (open_at_login: boolean | 'mixed') => {
- await ipc.setLoginItemSettings({...login_item, openAtLogin: !!open_at_login});
+ await ipc.setLoginItemSettings({...login_item!, startup_enabled: !!open_at_login});
forceRefreshLoginItem();
}, [ipc, login_item]);
const setOpenAsHidden = useCallback(async (open_as_hidden: boolean | 'mixed') => {
- await ipc.setLoginItemSettings({...login_item, openAsHidden: !!open_as_hidden});
+ await ipc.setLoginItemSettings({...login_item!, startup_hidden: !!open_as_hidden});
forceRefreshLoginItem();
}, [ipc, login_item]);
@@ -114,7 +114,7 @@ export default function Preferences(props: PreferencesProps) {
{/* Preferences */}
- {ipc.platform === 'darwin' || ipc.platform === 'win32' ?
+ {login_item.supported || login_item.startup_enabled ?
Startup
@@ -124,32 +124,33 @@ export default function Preferences(props: PreferencesProps) {
- setOpenAtLogin(!login_item.openAtLogin)}>
+ setOpenAtLogin(!login_item.startup_enabled)}>
Open at login
- {ipc.platform === 'darwin' ?
- setOpenAsHidden(!login_item.openAsHidden)}
+ setOpenAsHidden(!login_item.startup_hidden)}
>
Open in background
- : null}
+
: null}
diff --git a/src/app/common/types.ts b/src/app/common/types.ts
index 630a4ec..8902bac 100644
--- a/src/app/common/types.ts
+++ b/src/app/common/types.ts
@@ -47,3 +47,10 @@ export interface DiscordPresenceSourceUrl {
export interface DiscordPresenceExternalMonitorsConfiguration {
enable_splatnet3_monitoring?: boolean;
}
+
+export interface LoginItem {
+ supported: boolean;
+ startup_enabled: boolean;
+ startup_hidden: boolean;
+}
+export type LoginItemOptions = Omit;
diff --git a/src/app/main/index.ts b/src/app/main/index.ts
index fb9aff6..aab909f 100644
--- a/src/app/main/index.ts
+++ b/src/app/main/index.ts
@@ -9,7 +9,7 @@ import MenuApp from './menu.js';
import { handleOpenWebServiceUri } from './webservices.js';
import { EmbeddedPresenceMonitor, PresenceMonitorManager } from './monitor.js';
import { createWindow } from './windows.js';
-import { DiscordPresenceConfiguration, WindowType } from '../common/types.js';
+import { DiscordPresenceConfiguration, LoginItem, LoginItemOptions, WindowType } from '../common/types.js';
import { initStorage, paths } from '../../util/storage.js';
import { checkUpdates, UpdateCacheData } from '../../common/update.js';
import Users, { CoralUser } from '../../common/users.js';
@@ -29,10 +29,28 @@ export const protocol_registration_options = dev && process.platform === 'win32'
path.join(dir, 'dist', 'app', 'app-entry.cjs'),
],
} : null;
-export const login_item_options: LoginItemSettingsOptions = {};
+export const login_item_options: LoginItemSettingsOptions = {
+ path: process.execPath,
+ args: dev ? [
+ path.join(dir, 'dist', 'app', 'app-entry.cjs'),
+ '--app-open-at-login=1',
+ ] : [
+ '--app-open-at-login=1',
+ ],
+};
+
+enum LoginItemType {
+ NATIVE,
+ NATIVE_PARTIAL,
+ NOT_SUPPORTED,
+}
+const login_item_type: LoginItemType =
+ process.platform === 'darwin' ? LoginItemType.NATIVE :
+ process.platform === 'win32' ? LoginItemType.NATIVE_PARTIAL :
+ LoginItemType.NOT_SUPPORTED;
debug('Protocol registration options', protocol_registration_options);
-debug('Login item registration options', login_item_options);
+debug('Login item registration options', LoginItemType[login_item_type], login_item_options);
export class App {
readonly store: Store;
@@ -184,7 +202,11 @@ export async function init() {
debug('App started');
- if (!app.getLoginItemSettings(login_item_options).wasOpenedAsHidden) {
+ const should_hide =
+ login_item_type === LoginItemType.NATIVE ? app.getLoginItemSettings(login_item_options).wasOpenedAsHidden :
+ process.argv.includes('--app-open-at-login=1') && (await appinstance.store.getLoginItem()).startup_hidden;
+
+ if (!should_hide) {
appinstance.showMainWindow();
}
}
@@ -254,6 +276,10 @@ class Updater {
}
}
+interface SavedStartupOptions {
+ hide: boolean;
+}
+
interface SavedMonitorState {
users: {
/** Nintendo Account ID */
@@ -277,6 +303,63 @@ export class Store extends EventEmitter {
this.users = Users.coral(this, process.env.ZNC_PROXY_URL, false);
}
+ async getLoginItem(): Promise {
+ const settings = app.getLoginItemSettings(login_item_options);
+
+ if (login_item_type === LoginItemType.NATIVE) {
+ // Fully supported
+ return {
+ supported: true,
+ startup_enabled: settings.openAtLogin,
+ startup_hidden: settings.openAsHidden,
+ };
+ }
+
+ const startup_options: SavedStartupOptions | undefined = await this.storage.getItem('StartupOptions');
+ const was_opened_at_login = process.argv.includes('--app-open-at-login=1');
+
+ if (login_item_type === LoginItemType.NATIVE_PARTIAL) {
+ // Partial native support
+ return {
+ supported: true,
+ startup_enabled: settings.openAtLogin,
+ startup_hidden: startup_options?.hide ?? false,
+ };
+ }
+
+ return {
+ supported: false,
+ startup_enabled: was_opened_at_login,
+ startup_hidden: startup_options?.hide ?? false,
+ };
+ }
+
+ async setLoginItem(settings: LoginItemOptions) {
+ if (login_item_type === LoginItemType.NATIVE) {
+ // Fully supported
+ app.setLoginItemSettings({
+ ...login_item_options,
+ openAtLogin: settings.startup_enabled,
+ openAsHidden: settings.startup_hidden,
+ });
+ return;
+ }
+
+ if (login_item_type === LoginItemType.NATIVE_PARTIAL) {
+ // Partial native support
+ app.setLoginItemSettings({
+ ...login_item_options,
+ openAtLogin: settings.startup_enabled,
+ });
+ }
+
+ const startup_options: SavedStartupOptions = {
+ hide: settings.startup_hidden,
+ };
+
+ await this.storage.setItem('StartupOptions', startup_options);
+ }
+
async saveMonitorState(monitors: PresenceMonitorManager) {
const users = new Set();
const state: SavedMonitorState = {
diff --git a/src/app/main/ipc.ts b/src/app/main/ipc.ts
index a5f2b76..8fd0dd9 100644
--- a/src/app/main/ipc.ts
+++ b/src/app/main/ipc.ts
@@ -1,10 +1,10 @@
-import { app, BrowserWindow, clipboard, dialog, IpcMain, KeyboardEvent, LoginItemSettings, Menu, MenuItem, Settings, ShareMenu, SharingItem, shell, systemPreferences } from './electron.js';
+import { app, BrowserWindow, clipboard, dialog, IpcMain, KeyboardEvent, Menu, MenuItem, Settings, ShareMenu, SharingItem, shell, systemPreferences } from './electron.js';
import * as util from 'node:util';
import createDebug from 'debug';
import { User } from 'discord-rpc';
import openWebService, { QrCodeReaderOptions, WebServiceIpc, WebServiceValidationError } from './webservices.js';
import { createWindow, getWindowConfiguration } from './windows.js';
-import { DiscordPresenceConfiguration, DiscordPresenceSource, WindowType } from '../common/types.js';
+import { DiscordPresenceConfiguration, DiscordPresenceSource, LoginItemOptions, WindowType } from '../common/types.js';
import { CurrentUser, Friend, Game, PresenceState, WebService } from '../../api/coral-types.js';
import { askAddNsoAccount, askAddPctlAccount } from './na-auth.js';
import { App, login_item_options } from './index.js';
@@ -40,8 +40,8 @@ export function setupIpc(appinstance: App, ipcMain: IpcMain) {
sendToAllWindows('nxapi:systemPreferences:accent-colour', accent_colour);
});
- ipcMain.handle('nxapi:systemPreferences:getloginitem', () => app.getLoginItemSettings(login_item_options));
- ipcMain.handle('nxapi:systemPreferences:setloginitem', (e, settings: Settings) => app.setLoginItemSettings({...login_item_options, ...settings}));
+ ipcMain.handle('nxapi:systemPreferences:getloginitem', () => appinstance.store.getLoginItem());
+ ipcMain.handle('nxapi:systemPreferences:setloginitem', (e, settings: LoginItemOptions) => appinstance.store.setLoginItem(settings));
ipcMain.handle('nxapi:update:get', () => appinstance.updater.cache ?? appinstance.updater.check());
ipcMain.handle('nxapi:update:check', () => appinstance.updater.check());
diff --git a/src/app/preload/index.ts b/src/app/preload/index.ts
index b475989..f304063 100644
--- a/src/app/preload/index.ts
+++ b/src/app/preload/index.ts
@@ -2,8 +2,8 @@ import { contextBridge, ipcRenderer } from 'electron';
import { EventEmitter } from 'events';
import createDebug from 'debug';
import type { User } from 'discord-rpc';
-import type { LoginItemSettings, Settings, SharingItem } from '../main/electron.js';
-import type { DiscordPresenceConfiguration, DiscordPresenceSource, WindowConfiguration } from '../common/types.js';
+import type { SharingItem } from '../main/electron.js';
+import type { DiscordPresenceConfiguration, DiscordPresenceSource, LoginItem, LoginItemOptions, WindowConfiguration } from '../common/types.js';
import type { SavedToken } from '../../common/auth/coral.js';
import type { SavedMoonToken } from '../../common/auth/moon.js';
import type { UpdateCacheData } from '../../common/update.js';
@@ -30,8 +30,8 @@ events.setMaxListeners(0);
const ipc = {
getWindowData: () => invSync('browser:getwindowdata'),
- getLoginItemSettings: () => inv('systemPreferences:getloginitem'),
- setLoginItemSettings: (settings: Settings) => inv('systemPreferences:setloginitem', settings),
+ getLoginItemSettings: () => inv('systemPreferences:getloginitem'),
+ setLoginItemSettings: (settings: LoginItemOptions) => inv('systemPreferences:setloginitem', settings),
getUpdateData: () => inv('update:get'),
checkUpdates: () => inv('update:check'),