This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { join, resolve, sep } from 'node:path'
|
||||
import { readFileSync, statSync } from 'node:fs'
|
||||
import { spawn } from 'node:child_process'
|
||||
import { app, dialog, shell, BrowserWindow, ipcMain, Menu } from 'electron'
|
||||
import { watch, type FSWatcher } from 'chokidar'
|
||||
import { addRecentProject, getName, getRecentProjects, getRoot, openDialog, setRoot } from './project'
|
||||
@@ -27,6 +28,32 @@ function broadcast(channel: string): void {
|
||||
for (const w of BrowserWindow.getAllWindows()) w.webContents.send(channel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Each Helder window is one project, and one project owns global main-process
|
||||
* state (root + FS/git/config watchers + PTYs). To run several projects beside
|
||||
* each other we therefore spawn a *separate, detached* Helder process per window
|
||||
* rather than opening a second BrowserWindow in this process.
|
||||
*
|
||||
* Spawning `process.execPath` directly also sidesteps macOS LaunchServices, which
|
||||
* otherwise just re-activates the running instance when the bundle is launched
|
||||
* again from Finder/Dock. `HELDER_PROJECT` points the child at a project (the
|
||||
* child's `resolveInitialRoot` reads it); with no path it lands on the launcher.
|
||||
*/
|
||||
function spawnInstance(projectPath?: string): void {
|
||||
const env = { ...process.env }
|
||||
if (projectPath && safeIsDir(projectPath)) env.HELDER_PROJECT = resolve(projectPath)
|
||||
else delete env.HELDER_PROJECT
|
||||
// Packaged: execPath IS the app, no app path needed. Dev: replay our own argv
|
||||
// (the electron-vite main entry) so the child loads the same app.
|
||||
const args = app.isPackaged ? [] : process.argv.slice(1)
|
||||
const child = spawn(process.execPath, args, { detached: true, stdio: 'ignore', env })
|
||||
child.unref()
|
||||
}
|
||||
|
||||
function safeIsDir(p: string): boolean {
|
||||
try { return statSync(p).isDirectory() } catch { return false }
|
||||
}
|
||||
|
||||
function startConfigWatcher(): void {
|
||||
if (configWatcher) { configWatcher.close(); configWatcher = null }
|
||||
const root = getRoot()
|
||||
@@ -96,6 +123,11 @@ function buildAppMenu(): Menu {
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'New Window',
|
||||
accelerator: 'CmdOrCtrl+Shift+N',
|
||||
click: () => spawnInstance(),
|
||||
},
|
||||
{
|
||||
label: 'Open Folder…',
|
||||
accelerator: 'CmdOrCtrl+O',
|
||||
|
||||
Reference in New Issue
Block a user