/* * Copyright (C) 2021-2022 Kristóf Marussy * * This file is part of Sophie. * * Sophie is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * SPDX-License-Identifier: AGPL-3.0-only */ import { app, BrowserView, BrowserWindow } from 'electron'; import { autorun } from 'mobx'; import { getSnapshot, onPatch } from 'mobx-state-tree'; import { join } from 'path'; import { browserViewBounds, MainToRendererIpcMessage, paletteMode, RendererToMainIpcMessage, } from '@sophie/shared'; import { URL } from 'url'; import { installDevToolsExtensions, openDevToolsWhenReady, } from './devTools'; import { createRootStore } from './stores/RootStore'; const isSingleInstance = app.requestSingleInstanceLock(); const isDevelopment = import.meta.env.MODE === 'development'; if (!isSingleInstance) { app.quit(); process.exit(0); } app.enableSandbox(); if (isDevelopment) { installDevToolsExtensions(app); } let mainWindow: BrowserWindow | null = null; const store = createRootStore(); async function createWindow(): Promise { mainWindow = new BrowserWindow({ show: false, autoHideMenuBar: true, webPreferences: { sandbox: true, preload: join(__dirname, '../../preload/dist/index.cjs'), }, }); if (isDevelopment) { openDevToolsWhenReady(mainWindow); } mainWindow.on('ready-to-show', () => { mainWindow?.show(); }); const { webContents } = mainWindow; webContents.on('ipc-message', (_event, channel, ...args) => { try { switch (channel) { case RendererToMainIpcMessage.SharedStoreSnapshotRequest: webContents.send(MainToRendererIpcMessage.SharedStoreSnapshot, getSnapshot(store.shared)); break; case RendererToMainIpcMessage.SetBrowserViewBounds: store.setBrowserViewBounds(browserViewBounds.parse(args[0])); break; case RendererToMainIpcMessage.SetPaletteMode: store.setPaletteMode(paletteMode.parse(args[0])) break; default: console.warn('Unknown IPC message:', channel, args); break; } } catch (err) { console.error('Error while processing IPC message:', channel, args, err); } }); onPatch(store.shared, (patch) => { webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); }); const pageUrl = (isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined) ? import.meta.env.VITE_DEV_SERVER_URL : new URL('../renderer/dist/index.html', `file://${__dirname}`).toString(); const browserView = new BrowserView({ webPreferences: { sandbox: true, partition: 'service', }, }); browserView.setBackgroundColor('#fff'); autorun(() => { browserView.setBounds(store.shared.browserViewBounds); }); await mainWindow.loadURL(pageUrl); mainWindow.addBrowserView(browserView); return browserView.webContents.loadURL('https://git.marussy.com/sophie/about'); } app.on('second-instance', () => { if (mainWindow !== null) { if (!mainWindow.isVisible()) { mainWindow.show(); } if (mainWindow.isMinimized()) { mainWindow.restore(); } mainWindow.focus(); } }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.whenReady().then(createWindow).catch((err) => { console.error('Failed to create window', err); process.exit(1); });