Files
atom/src/application-delegate.coffee
Nathan Sobo dfc0910023 Stringify/parse temporary window state to avoid nulling out references
If the object passed via IPC contains any keys of the same reference,
all but one of these keys will be nulled out. Converting to/from a
string avoids this problem.
2016-08-09 14:43:38 -06:00

284 lines
9.0 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")
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)
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)