Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 64 additions & 23 deletions shared/desktop/app/app-events.desktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as R from '@/constants/remote'
import * as RemoteGen from '@/constants/remote-actions'
import logger from '@/logger'
import os from 'os'
import {isWindows, cacheRoot} from '@/constants/platform.desktop'
import {isLinux, isWindows, cacheRoot} from '@/constants/platform.desktop'
import {ctlQuit} from './ctl.desktop'
import {allowMultipleInstances} from '@/local-debug.desktop'
import KB2 from '@/util/electron.desktop'
Expand Down Expand Up @@ -77,7 +77,7 @@ export const fixWindowsNotifications = () => {
Electron.app.setAppUserModelId('Keybase.Keybase.GUI')
}

export const handleCrashes = () => {
export const registerCrashHandling = () => {
process.on('uncaughtException', e => {
console.log('Uncaught exception on main thread:', e)
})
Expand All @@ -100,7 +100,7 @@ export const handleCrashes = () => {
})
}

export const stopNav = () => {
export const registerNavigationGuards = () => {
Electron.app.on('web-contents-created', (_, contents) => {
contents.on('will-navigate', event => {
event.preventDefault()
Expand All @@ -111,7 +111,7 @@ export const stopNav = () => {
})
}

export const focusSelfOnAnotherInstanceLaunching = (
const focusSelfOnAnotherInstanceLaunching = (
getMainWindow: () => Electron.BrowserWindow | null,
commandLine: Array<string>
) => {
Expand Down Expand Up @@ -143,6 +143,14 @@ export const focusSelfOnAnotherInstanceLaunching = (
}
}

export const registerSecondInstanceHandler = (deps: {
getMainWindow: () => Electron.BrowserWindow | null
}) => {
Electron.app.on('second-instance', (_, commandLine) =>
focusSelfOnAnotherInstanceLaunching(deps.getMainWindow, commandLine)
)
}

// On Windows and Linux startup, open-file and open-url arguments will be
// passed via process.argv instead of via Electron event arguments.
export const getStartupProcessArgs = () => {
Expand Down Expand Up @@ -177,7 +185,7 @@ export const getStartupProcessArgs = () => {
}
}

export const handleActivate = (getMainWindow: () => Electron.BrowserWindow | null) => {
const handleActivate = (getMainWindow: () => Electron.BrowserWindow | null) => {
getMainWindow()?.show()
const dock = Electron.app.dock
dock
Expand All @@ -186,32 +194,65 @@ export const handleActivate = (getMainWindow: () => Electron.BrowserWindow | nul
.catch(() => {})
}

export const handleQuitting = (event: Electron.Event) => {
const handleQuitting = (event: Electron.Event) => {
console.log('Quit through before-quit')
event.preventDefault()
ctlQuit()
}

export const willFinishLaunching = (deps: {
export const registerLifecycleHandlers = (deps: {
getMainWindow: () => Electron.BrowserWindow | null
}) => {
Electron.app.on('activate', () => handleActivate(deps.getMainWindow))
Electron.app.once('before-quit', handleQuitting)
}

export const registerOpenHandlers = (deps: {
getAppStartedUp: () => boolean
setSaltpackFilePath: (path: string) => void
setStartupURL: (url: string) => void
queueSaltpackFilePath: (path: string) => void
queueStartupURL: (url: string) => void
openSaltpackFile: (path: string) => void
openURL: (url: string) => void
}) => {
Electron.app.on('open-file', (event, path) => {
event.preventDefault()
if (!deps.getAppStartedUp()) {
deps.setSaltpackFilePath(path)
} else {
R.remoteDispatch(RemoteGen.createSaltpackFileOpen({path}))
}
Electron.app.once('will-finish-launching', () => {
Electron.app.on('open-file', (event, path) => {
event.preventDefault()
if (!deps.getAppStartedUp()) {
deps.queueSaltpackFilePath(path)
} else {
deps.openSaltpackFile(path)
}
})

Electron.app.on('open-url', (event, link) => {
event.preventDefault()
if (!deps.getAppStartedUp()) {
deps.queueStartupURL(link)
} else {
deps.openURL(link)
}
})
})
}

Electron.app.on('open-url', (event, link) => {
event.preventDefault()
if (!deps.getAppStartedUp()) {
deps.setStartupURL(link)
} else {
R.remoteDispatch(RemoteGen.createLink({link}))
}
export const registerPowerMonitorEvents = () => {
if (isLinux) {
return
}

Electron.powerMonitor.on('suspend', () => {
R.remoteDispatch(RemoteGen.createPowerMonitorEvent({event: 'suspend'}))
})
Electron.powerMonitor.on('resume', () => {
R.remoteDispatch(RemoteGen.createPowerMonitorEvent({event: 'resume'}))
})
Electron.powerMonitor.on('shutdown', () => {
R.remoteDispatch(RemoteGen.createPowerMonitorEvent({event: 'shutdown'}))
})
Electron.powerMonitor.on('lock-screen', () => {
R.remoteDispatch(RemoteGen.createPowerMonitorEvent({event: 'lock-screen'}))
})
Electron.powerMonitor.on('unlock-screen', () => {
R.remoteDispatch(RemoteGen.createPowerMonitorEvent({event: 'unlock-screen'}))
})
}
4 changes: 2 additions & 2 deletions shared/desktop/app/ipc-handlers.desktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ const timeoutPromise = async (timeMs: number) =>

export const setupIPCHandlers = (deps: {
getMainWindow: () => Electron.BrowserWindow | null
markAppStartedUp: () => void
nodeEngine: Engine
onAppStartedUp: () => void
}) => {
Electron.ipcMain.handle('KBdispatchAction', (_: unknown, action: unknown) => {
deps.getMainWindow()?.webContents.send('KBdispatchAction', action)
Expand Down Expand Up @@ -507,7 +507,7 @@ export const setupIPCHandlers = (deps: {
}
break
case 'appStartedUp':
deps.onAppStartedUp()
deps.markAppStartedUp()
break
case 'requestWindowsStartService':
if (isWindows) {
Expand Down
12 changes: 5 additions & 7 deletions shared/desktop/app/menu-bar.desktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,6 @@ const MenuBar = () => {
showOnAllWorkspaces: true,
})

Electron.app.on('ready', () => {
mb.window
?.loadURL(htmlFile)
.then(() => {})
.catch(() => {})
})

const updateIcon = () => {
try {
mb.tray.setImage(getIcon())
Expand Down Expand Up @@ -135,6 +128,11 @@ const MenuBar = () => {
})

mb.on('ready', () => {
mb.window
?.loadURL(htmlFile)
.then(() => {})
.catch(() => {})

// ask for an update in case we missed one
R.remoteDispatch(
RemoteGen.createRemoteWindowWantsProps({
Expand Down
143 changes: 137 additions & 6 deletions shared/desktop/app/node.desktop.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,142 @@
// Entry point for the node part of the electron app
// order of modules is important here
// Entry point for the node part of the electron app.
import '../renderer/preload.desktop'
import * as Electron from 'electron'
import * as R from '@/constants/remote'
import * as RemoteGen from '@/constants/remote-actions'
import {isDarwin} from '@/constants/platform.desktop'
import KB2 from '@/util/electron.desktop'
import {configOverload} from './dynamic-config'
import MainWindow from './main-window.desktop'
import devTools from './dev-tools.desktop'
import installer from './installer.desktop'
import menuBar from './menu-bar.desktop'
import {makeEngine} from '@/engine'
import {
installCrashReporter,
appShouldDieOnStartup,
changeCommandLineSwitches,
fixWindowsNotifications,
getStartupProcessArgs,
registerCrashHandling,
registerLifecycleHandlers,
registerNavigationGuards,
registerOpenHandlers,
registerPowerMonitorEvents,
registerSecondInstanceHandler,
} from './app-events.desktop'
import {setupIPCHandlers} from './ipc-handlers.desktop'

type DeferredLaunch = {
saltpackFilePath?: string
startupURL?: string
}

type AppRuntime = {
appStartedUp: boolean
deferredLaunch: DeferredLaunch
mainWindow: Electron.BrowserWindow | null
}

const dispatchStartupURL = (link: string) => {
R.remoteDispatch(RemoteGen.createLink({link}))
}

const dispatchSaltpackFile = (path: string) => {
R.remoteDispatch(RemoteGen.createSaltpackFileOpen({path}))
}

const flushDeferredLaunch = (
runtime: AppRuntime,
getStartupProcessArgs: () => void
) => {
const {startupURL, saltpackFilePath} = runtime.deferredLaunch
runtime.deferredLaunch = {}

if (startupURL) {
dispatchStartupURL(startupURL)
} else if (saltpackFilePath) {
dispatchSaltpackFile(saltpackFilePath)
} else if (!isDarwin) {
getStartupProcessArgs()
}
}

const startApp = () => {
const runtime: AppRuntime = {
appStartedUp: false,
deferredLaunch: {},
mainWindow: null,
}
const getMainWindow = () => runtime.mainWindow

registerCrashHandling()
registerNavigationGuards()
installCrashReporter()

if (appShouldDieOnStartup()) {
Electron.app.quit()
return
}

console.log('Version:', Electron.app.getVersion())

registerSecondInstanceHandler({getMainWindow})
fixWindowsNotifications()
changeCommandLineSwitches()
devTools()
registerPowerMonitorEvents()

const nodeEngine = makeEngine(
() => {},
(connected: boolean) => {
R.remoteDispatch(RemoteGen.createEngineConnection({connected}))
}
)

setupIPCHandlers({
getMainWindow,
markAppStartedUp: () => {
if (runtime.appStartedUp) {
return
}

runtime.appStartedUp = true
nodeEngine.listenersAreReady()
flushDeferredLaunch(runtime, getStartupProcessArgs)

installer(err => {
err && console.log('Error: ', err)
R.remoteDispatch(RemoteGen.createInstallerRan())
})
},
nodeEngine,
})

registerOpenHandlers({
getAppStartedUp: () => runtime.appStartedUp,
openSaltpackFile: dispatchSaltpackFile,
openURL: dispatchStartupURL,
queueSaltpackFilePath: (path: string) => {
runtime.deferredLaunch.saltpackFilePath = path
},
queueStartupURL: (url: string) => {
runtime.deferredLaunch.startupURL = url
},
})
registerLifecycleHandlers({getMainWindow})

Electron.app
.whenReady()
.then(() => {
menuBar()
runtime.mainWindow = MainWindow()
})
.catch((err: unknown) => {
console.log('Electron app failed to initialize:', err)
Electron.app.quit()
})
}

// This isn't ideal. In order to load the config overload from the disk we need paths
// which are loaded from the KB2. Maybe we split this up later but for now we just inject it
// back inside before we load the rest of the app
KB2.constants.configOverload = configOverload
require('./node2.desktop')
Electron.app.commandLine.appendSwitch('disk-cache-size', '1')
startApp()
Loading