heynote/electron/main/index.ts

225 lines
7.1 KiB
TypeScript
Raw Normal View History

import { app, BrowserWindow, shell, ipcMain, Menu, nativeTheme, globalShortcut } from 'electron'
2023-01-12 18:55:55 +01:00
import { release } from 'node:os'
import { join } from 'node:path'
2023-01-19 00:20:50 +01:00
import * as jetpack from "fs-jetpack";
2023-03-06 01:30:37 +01:00
import menu from './menu'
2023-01-19 00:20:50 +01:00
import { initialContent, initialDevContent } from '../initial-content'
import { WINDOW_CLOSE_EVENT, SETTINGS_CHANGE_EVENT } from '../constants';
import CONFIG from "../config"
import { onBeforeInputEvent } from "../keymap"
import { isMac } from '../detect-platform';
2023-12-06 13:31:47 +01:00
import { initializeAutoUpdate, checkForUpdates } from './auto-update';
import { fixElectronCors } from './cors';
2023-03-06 01:30:37 +01:00
2023-01-12 18:55:55 +01:00
// The built directory structure
//
// ├─┬ dist-electron
// │ ├─┬ main
// │ │ └── index.js > Electron-Main
// │ └─┬ preload
// │ └── index.js > Preload-Scripts
// ├─┬ dist
// │ └── index.html > Electron-Renderer
//
process.env.DIST_ELECTRON = join(__dirname, '..')
process.env.DIST = join(process.env.DIST_ELECTRON, '../dist')
process.env.PUBLIC = process.env.VITE_DEV_SERVER_URL
2023-01-15 10:53:09 +01:00
? join(process.env.DIST_ELECTRON, '../public')
: process.env.DIST
2023-01-12 18:55:55 +01:00
// Disable GPU Acceleration for Windows 7
if (release().startsWith('6.1')) app.disableHardwareAcceleration()
// Set application name for Windows 10+ notifications
if (process.platform === 'win32') app.setAppUserModelId(app.getName())
if (!process.env.VITE_DEV_SERVER_URL && !app.requestSingleInstanceLock()) {
2023-01-15 10:53:09 +01:00
app.quit()
process.exit(0)
2023-01-12 18:55:55 +01:00
}
// Set custom application menu
Menu.setApplicationMenu(menu)
2023-01-12 18:55:55 +01:00
// Remove electron security warnings
// This warning only shows in development mode
// Read more on https://www.electronjs.org/docs/latest/tutorial/security
// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
export let win: BrowserWindow | null = null
2023-01-12 18:55:55 +01:00
// Here, you can also use other preload
const preload = join(__dirname, '../preload/index.js')
const url = process.env.VITE_DEV_SERVER_URL
const indexHtml = join(process.env.DIST, 'index.html')
2023-01-19 00:20:50 +01:00
const isDev = !!process.env.VITE_DEV_SERVER_URL
2023-01-29 12:49:54 +01:00
let currentKeymap = CONFIG.get("settings.keymap")
2023-01-19 00:20:50 +01:00
let contentSaved = false
2023-12-06 13:31:47 +01:00
// if this version is a beta version, set the release channel to beta
const isBetaVersion = app.getVersion().includes("beta")
if (isBetaVersion) {
CONFIG.set("settings.releaseChannel", "beta")
}
2023-01-12 18:55:55 +01:00
async function createWindow() {
// read any stored window settings from config, or use defaults
let windowConfig = {
width: CONFIG.get("windowConfig.width", 900) as number,
height: CONFIG.get("windowConfig.height", 680) as number,
isMaximized: CONFIG.get("windowConfig.isMaximized", false) as boolean,
isFullScreen: CONFIG.get("windowConfig.isFullScreen", false) as boolean,
}
win = new BrowserWindow(Object.assign({
title: 'heynote',
icon: join(process.env.PUBLIC, 'favicon.ico'),
backgroundColor: nativeTheme.shouldUseDarkColors ? '#262B37' : '#FFFFFF',
2023-01-15 10:53:09 +01:00
//titleBarStyle: 'customButtonsOnHover',
autoHideMenuBar: true,
2023-01-15 10:53:09 +01:00
webPreferences: {
preload,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
nodeIntegration: true,
contextIsolation: true,
2023-01-15 10:53:09 +01:00
},
}, windowConfig))
2023-01-19 02:47:57 +01:00
// maximize window if it was maximized last time
if (windowConfig.isMaximized) {
win.maximize()
}
if (windowConfig.isFullScreen) {
win.setFullScreen(true)
}
2023-01-15 10:53:09 +01:00
2023-01-19 00:20:50 +01:00
win.on("close", (event) => {
// Prevent the window from closing, and send a message to the renderer which will in turn
// send a message to the main process to save the current buffer and close the window.
if (!contentSaved) {
event.preventDefault()
win?.webContents.send(WINDOW_CLOSE_EVENT)
} else {
// save window config
Object.assign(windowConfig, {
isMaximized: win.isMaximized(),
isFullScreen: win.isFullScreen(),
}, win.getNormalBounds())
CONFIG.set("windowConfig", windowConfig)
2023-01-19 00:20:50 +01:00
}
})
2023-03-09 09:46:21 +01:00
nativeTheme.themeSource = CONFIG.get("theme")
2023-01-15 10:53:09 +01:00
if (process.env.VITE_DEV_SERVER_URL) { // electron-vite-vue#298
win.loadURL(url + '?dev=1')
2023-01-15 10:53:09 +01:00
// Open devTool if the app is not packaged
//win.webContents.openDevTools()
} else {
win.loadFile(indexHtml)
//win.webContents.openDevTools()
}
// custom keyboard shortcuts for Emacs keybindings
win.webContents.on("before-input-event", function (event, input) {
onBeforeInputEvent({event, input, win, currentKeymap})
})
2023-01-15 10:53:09 +01:00
// Test actively push message to the Electron-Renderer
win.webContents.on('did-finish-load', () => {
win?.webContents.send('main-process-message', new Date().toLocaleString())
})
// Make all links open with the browser, not with the application
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https:') || url.startsWith('http:')) {
shell.openExternal(url)
}
2023-01-15 10:53:09 +01:00
return { action: 'deny' }
})
fixElectronCors(win)
2023-01-12 18:55:55 +01:00
}
2023-03-06 01:30:37 +01:00
app.whenReady().then(createWindow).then(async () => {
initializeAutoUpdate(win)
2023-03-06 01:30:37 +01:00
})
2023-01-12 18:55:55 +01:00
app.on('window-all-closed', () => {
2023-01-15 10:53:09 +01:00
win = null
if (process.platform !== 'darwin') app.quit()
2023-01-12 18:55:55 +01:00
})
app.on('second-instance', () => {
2023-01-15 10:53:09 +01:00
if (win) {
// Focus on the main window if the user tried to open another
if (win.isMinimized()) win.restore()
win.focus()
}
2023-01-12 18:55:55 +01:00
})
app.on('activate', () => {
2023-01-15 10:53:09 +01:00
const allWindows = BrowserWindow.getAllWindows()
if (allWindows.length) {
allWindows[0].focus()
} else {
createWindow()
}
2023-01-12 18:55:55 +01:00
})
ipcMain.handle('dark-mode:set', (event, mode) => {
2023-03-09 09:46:21 +01:00
CONFIG.set("theme", mode)
nativeTheme.themeSource = mode
2023-01-12 18:55:55 +01:00
})
ipcMain.handle('dark-mode:get', () => nativeTheme.themeSource)
2023-01-19 00:20:50 +01:00
const bufferPath = isDev ? join(app.getPath("userData"), "buffer-dev.txt") : join(app.getPath("userData"), "buffer.txt")
ipcMain.handle('buffer-content:load', async () =>  {
if (jetpack.exists(bufferPath) === "file") {
return await jetpack.read(bufferPath, 'utf8')
} else {
return isDev? initialDevContent : initialContent
}
});
async function save(content) {
return await jetpack.write(bufferPath, content, {
atomic: true,
mode: '600',
})
}
ipcMain.handle('buffer-content:save', async (event, content) =>  {
return await save(content)
});
ipcMain.handle('buffer-content:saveAndQuit', async (event, content) => {
await save(content)
contentSaved = true
app.quit()
})
ipcMain.handle('settings:set', (event, settings) => {
2023-12-06 11:56:10 +01:00
if (settings.keymap !== CONFIG.get("settings.keymap")) {
currentKeymap = settings.keymap
}
2023-12-06 13:31:47 +01:00
const releaseChannelChanged = settings.releaseChannel !== CONFIG.get("settings.releaseChannel")
CONFIG.set("settings", settings)
2023-12-06 13:31:47 +01:00
if (releaseChannelChanged) {
// release channel changed, check for updates
checkForUpdates()
}
win?.webContents.send(SETTINGS_CHANGE_EVENT, settings)
})