Files
orca/src/main/startup/main-process-ready.ts
T
OrcaWinandm4air 029b5ba1cb fix(startup): hold desktop activations until the startup window exists (#22495)
* fix(startup): hold desktop activations until the startup window exists

A second-instance, open-url, or open-file activation that landed after app
ready but before the startup window was created opened its own main window.
The startup open then built a second window, threw on the duplicate
'window:isMaximized' handler, and aborted runtime launch: no runtime RPC,
no orca-runtime.json, an orphan hidden window holding the trusted-renderer
id, and the visible window refused trusted IPC.

The desktop activation gate now starts 'initializing' for every launch mode.
The startup window opener releases it once that window exists, so queued
activations focus it, and a desktop launch that fails first releases it so
later activations can still open a window. Serve mode keeps settling the
gate after its RPC is ready.

* fix(startup): release desktop activation after failed ready prerequisites

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
2026-09-25 23:02:23 -07:00

54 lines
2.0 KiB
TypeScript

import { initializeMainProcessI18nAndMenu } from './main-process-i18n-menu'
import { mainProcessState as state } from './main-process-state'
import { initializeReadyFoundation } from './main-process-ready-foundation'
import { initializeReadyRuntimeServices } from './main-process-ready-runtime'
import { releaseDesktopActivationAfter } from './serve-desktop-activation'
import {
initializeMainProcessRuntimeLaunch,
type MainProcessRuntimeLaunchOptions
} from './main-process-runtime-launch'
/** Runs the ready-phase composition in the same dependency order as the legacy entry point. */
export async function initializeMainProcessReady(
launchOptions: MainProcessRuntimeLaunchOptions
): Promise<void> {
const options: MainProcessRuntimeLaunchOptions = {
...launchOptions,
openMainWindow: releaseDesktopActivationAfter(
state.desktopActivationGate,
launchOptions.openMainWindow
)
}
try {
await initializeReadyFoundation()
await initializeReadyRuntimeServices()
// Window creation can proceed while translations and the native menu initialize.
const i18nAndMenuReady = initializeMainProcessI18nAndMenu()
state.mainProcessI18nReady = i18nAndMenuReady.catch(() => {})
// Join both branches before cleanup can close the profile writer.
const results = await Promise.allSettled([
i18nAndMenuReady,
initializeMainProcessRuntimeLaunch(options)
])
for (const result of results) {
if (result.status === 'rejected') {
throw result.reason
}
}
} catch (error) {
// Startup now exits after failure; reopening would use a closing profile writer.
state.desktopActivationGate = null
try {
await state.store?.freezeWritesAsync()
state.profileStateAdmission?.release()
state.profileStateAdmission = undefined
} catch (closeError) {
console.error(
'[persistence] Failed to close profile persistence after startup failure:',
closeError
)
}
throw error
}
}