Files
atom/src/application-delegate.coffee
Nathan Sobo fe9a7d1db3 Preserve command line flags when restarting
This performs restarts in the main process and uses ipc to request restarts from application windows. We preserve the following settings:

* dev mode
* custom resource path
* safe mode
* portable mode
* socket path
* log file path
* user data dir
2016-09-20 15:13:46 -06:00

298 lines
9.4 KiB
CoffeeScript

_ = require 'underscore-plus'
{screen, ipcRenderer, remote, shell, systemPreferences, webFrame} = require 'electron'
ipcHelpers = require './ipc-helpers'
{Disposable} = require 'event-kit'
{getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers'
module.exports =
class ApplicationDelegate
open: (params) ->
ipcRenderer.send('open', params)
pickFolder: (callback) ->
responseChannel = "atom-pick-folder-response"
ipcRenderer.on responseChannel, (event, path) ->
ipcRenderer.removeAllListeners(responseChannel)
callback(path)
ipcRenderer.send("pick-folder", responseChannel)
getCurrentWindow: ->
remote.getCurrentWindow()
closeWindow: ->
ipcRenderer.send("call-window-method", "close")
getTemporaryWindowState: ->
ipcHelpers.call('get-temporary-window-state').then (stateJSON) -> JSON.parse(stateJSON)
setTemporaryWindowState: (state) ->
ipcHelpers.call('set-temporary-window-state', JSON.stringify(state))
getWindowSize: ->
[width, height] = remote.getCurrentWindow().getSize()
{width, height}
setWindowSize: (width, height) ->
ipcHelpers.call('set-window-size', width, height)
getWindowPosition: ->
[x, y] = remote.getCurrentWindow().getPosition()
{x, y}
setWindowPosition: (x, y) ->
ipcHelpers.call('set-window-position', x, y)
centerWindow: ->
ipcHelpers.call('center-window')
focusWindow: ->
ipcHelpers.call('focus-window')
showWindow: ->
ipcHelpers.call('show-window')
hideWindow: ->
ipcHelpers.call('hide-window')
reloadWindow: ->
ipcRenderer.send("call-window-method", "reload")
restartApplication: ->
ipcRenderer.send("restart-application")
minimizeWindow: ->
ipcRenderer.send("call-window-method", "minimize")
isWindowMaximized: ->
remote.getCurrentWindow().isMaximized()
maximizeWindow: ->
ipcRenderer.send("call-window-method", "maximize")
unmaximizeWindow: ->
ipcRenderer.send("call-window-method", "unmaximize")
isWindowFullScreen: ->
remote.getCurrentWindow().isFullScreen()
setWindowFullScreen: (fullScreen=false) ->
ipcRenderer.send("call-window-method", "setFullScreen", fullScreen)
openWindowDevTools: ->
new Promise (resolve) ->
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
# `TextEditorComponent` (Ref.: https://github.com/atom/atom/issues/9697).
process.nextTick ->
if remote.getCurrentWindow().isDevToolsOpened()
resolve()
else
remote.getCurrentWindow().once("devtools-opened", -> resolve())
ipcRenderer.send("call-window-method", "openDevTools")
closeWindowDevTools: ->
new Promise (resolve) ->
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
# `TextEditorComponent` (Ref.: https://github.com/atom/atom/issues/9697).
process.nextTick ->
unless remote.getCurrentWindow().isDevToolsOpened()
resolve()
else
remote.getCurrentWindow().once("devtools-closed", -> resolve())
ipcRenderer.send("call-window-method", "closeDevTools")
toggleWindowDevTools: ->
new Promise (resolve) =>
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
# `TextEditorComponent` (Ref.: https://github.com/atom/atom/issues/9697).
process.nextTick =>
if remote.getCurrentWindow().isDevToolsOpened()
@closeWindowDevTools().then(resolve)
else
@openWindowDevTools().then(resolve)
executeJavaScriptInWindowDevTools: (code) ->
ipcRenderer.send("execute-javascript-in-dev-tools", code)
setWindowDocumentEdited: (edited) ->
ipcRenderer.send("call-window-method", "setDocumentEdited", edited)
setRepresentedFilename: (filename) ->
ipcRenderer.send("call-window-method", "setRepresentedFilename", filename)
addRecentDocument: (filename) ->
ipcRenderer.send("add-recent-document", filename)
setRepresentedDirectoryPaths: (paths) ->
loadSettings = getWindowLoadSettings()
loadSettings['initialPaths'] = paths
setWindowLoadSettings(loadSettings)
setAutoHideWindowMenuBar: (autoHide) ->
ipcRenderer.send("call-window-method", "setAutoHideMenuBar", autoHide)
setWindowMenuBarVisibility: (visible) ->
remote.getCurrentWindow().setMenuBarVisibility(visible)
getPrimaryDisplayWorkAreaSize: ->
remote.screen.getPrimaryDisplay().workAreaSize
getUserDefault: (key, type) ->
remote.systemPreferences.getUserDefault(key, type)
confirm: ({message, detailedMessage, buttons}) ->
buttons ?= {}
if _.isArray(buttons)
buttonLabels = buttons
else
buttonLabels = Object.keys(buttons)
chosen = remote.dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'info'
message: message
detail: detailedMessage
buttons: buttonLabels
})
if _.isArray(buttons)
chosen
else
callback = buttons[buttonLabels[chosen]]
callback?()
showMessageDialog: (params) ->
showSaveDialog: (params) ->
if _.isString(params)
params = defaultPath: params
else
params = _.clone(params)
params.title ?= 'Save File'
params.defaultPath ?= getWindowLoadSettings().initialPaths[0]
remote.dialog.showSaveDialog remote.getCurrentWindow(), params
playBeepSound: ->
shell.beep()
onDidOpenLocations: (callback) ->
outerCallback = (event, message, detail) ->
callback(detail) if message is 'open-locations'
ipcRenderer.on('message', outerCallback)
new Disposable ->
ipcRenderer.removeListener('message', outerCallback)
onUpdateAvailable: (callback) ->
outerCallback = (event, message, detail) ->
# TODO: Yes, this is strange that `onUpdateAvailable` is listening for
# `did-begin-downloading-update`. We currently have no mechanism to know
# if there is an update, so begin of downloading is a good proxy.
callback(detail) if message is 'did-begin-downloading-update'
ipcRenderer.on('message', outerCallback)
new Disposable ->
ipcRenderer.removeListener('message', outerCallback)
onDidBeginDownloadingUpdate: (callback) ->
@onUpdateAvailable(callback)
onDidBeginCheckingForUpdate: (callback) ->
outerCallback = (event, message, detail) ->
callback(detail) if message is 'checking-for-update'
ipcRenderer.on('message', outerCallback)
new Disposable ->
ipcRenderer.removeListener('message', outerCallback)
onDidCompleteDownloadingUpdate: (callback) ->
outerCallback = (event, message, detail) ->
# TODO: We could rename this event to `did-complete-downloading-update`
callback(detail) if message is 'update-available'
ipcRenderer.on('message', outerCallback)
new Disposable ->
ipcRenderer.removeListener('message', outerCallback)
onUpdateNotAvailable: (callback) ->
outerCallback = (event, message, detail) ->
callback(detail) if message is 'update-not-available'
ipcRenderer.on('message', outerCallback)
new Disposable ->
ipcRenderer.removeListener('message', outerCallback)
onUpdateError: (callback) ->
outerCallback = (event, message, detail) ->
callback(detail) if message is 'update-error'
ipcRenderer.on('message', outerCallback)
new Disposable ->
ipcRenderer.removeListener('message', outerCallback)
onApplicationMenuCommand: (callback) ->
outerCallback = (event, args...) ->
callback(args...)
ipcRenderer.on('command', outerCallback)
new Disposable ->
ipcRenderer.removeListener('command', outerCallback)
onContextMenuCommand: (callback) ->
outerCallback = (event, args...) ->
callback(args...)
ipcRenderer.on('context-command', outerCallback)
new Disposable ->
ipcRenderer.removeListener('context-command', outerCallback)
onSaveWindowStateRequest: (callback) ->
outerCallback = (event, message) ->
callback(event)
ipcRenderer.on('save-window-state', outerCallback)
new Disposable ->
ipcRenderer.removeListener('save-window-state', outerCallback)
didSaveWindowState: ->
ipcRenderer.send('did-save-window-state')
didCancelWindowUnload: ->
ipcRenderer.send('did-cancel-window-unload')
openExternal: (url) ->
shell.openExternal(url)
disableZoom: ->
outerCallback = ->
webFrame.setZoomLevelLimits(1, 1)
outerCallback()
# Set the limits every time a display is added or removed, otherwise the
# configuration gets reset to the default, which allows zooming the
# webframe.
screen.on('display-added', outerCallback)
screen.on('display-removed', outerCallback)
new Disposable ->
screen.removeListener('display-added', outerCallback)
screen.removeListener('display-removed', outerCallback)
checkForUpdate: ->
ipcRenderer.send('command', 'application:check-for-update')
restartAndInstallUpdate: ->
ipcRenderer.send('command', 'application:install-update')
getAutoUpdateManagerState: ->
ipcRenderer.sendSync('get-auto-update-manager-state')
getAutoUpdateManagerErrorMessage: ->
ipcRenderer.sendSync('get-auto-update-manager-error')
emitWillSavePath: (path) ->
ipcRenderer.sendSync('will-save-path', path)
emitDidSavePath: (path) ->
ipcRenderer.sendSync('did-save-path', path)