mirror of
https://github.com/atom/atom.git
synced 2026-02-15 00:55:14 -05:00
260 lines
8.5 KiB
CoffeeScript
260 lines
8.5 KiB
CoffeeScript
{BrowserWindow, app, dialog, ipcMain} = require 'electron'
|
|
path = require 'path'
|
|
fs = require 'fs'
|
|
url = require 'url'
|
|
{EventEmitter} = require 'events'
|
|
|
|
module.exports =
|
|
class AtomWindow
|
|
Object.assign @prototype, EventEmitter.prototype
|
|
|
|
@iconPath: path.resolve(__dirname, '..', '..', 'resources', 'atom.png')
|
|
@includeShellLoadTime: true
|
|
|
|
browserWindow: null
|
|
loaded: null
|
|
isSpec: null
|
|
|
|
constructor: (@atomApplication, @fileRecoveryService, settings={}) ->
|
|
{@resourcePath, initialPaths, pathToOpen, locationsToOpen, @isSpec, @headless, @safeMode, @devMode} = settings
|
|
locationsToOpen ?= [{pathToOpen}] if pathToOpen
|
|
locationsToOpen ?= []
|
|
|
|
@loadedPromise = new Promise((@resolveLoadedPromise) =>)
|
|
@closedPromise = new Promise((@resolveClosedPromise) =>)
|
|
|
|
options =
|
|
show: false
|
|
title: 'Atom'
|
|
# Add an opaque backgroundColor (instead of keeping the default
|
|
# transparent one) to prevent subpixel anti-aliasing from being disabled.
|
|
# We believe this is a regression introduced with Electron 0.37.3, and
|
|
# thus we should remove this as soon as a fix gets released.
|
|
backgroundColor: "#fff"
|
|
webPreferences:
|
|
# Prevent specs from throttling when the window is in the background:
|
|
# this should result in faster CI builds, and an improvement in the
|
|
# local development experience when running specs through the UI (which
|
|
# now won't pause when e.g. minimizing the window).
|
|
backgroundThrottling: not @isSpec
|
|
|
|
# Don't set icon on Windows so the exe's ico will be used as window and
|
|
# taskbar's icon. See https://github.com/atom/atom/issues/4811 for more.
|
|
if process.platform is 'linux'
|
|
options.icon = @constructor.iconPath
|
|
|
|
if @shouldHideTitleBar()
|
|
options.titleBarStyle = 'hidden'
|
|
|
|
@browserWindow = new BrowserWindow options
|
|
@atomApplication.addWindow(this)
|
|
|
|
@handleEvents()
|
|
|
|
loadSettings = Object.assign({}, settings)
|
|
loadSettings.appVersion = app.getVersion()
|
|
loadSettings.resourcePath = @resourcePath
|
|
loadSettings.devMode ?= false
|
|
loadSettings.safeMode ?= false
|
|
loadSettings.atomHome = process.env.ATOM_HOME
|
|
loadSettings.clearWindowState ?= false
|
|
loadSettings.initialPaths ?=
|
|
for {pathToOpen} in locationsToOpen when pathToOpen
|
|
if fs.statSyncNoException(pathToOpen).isFile?()
|
|
path.dirname(pathToOpen)
|
|
else
|
|
pathToOpen
|
|
|
|
loadSettings.initialPaths.sort()
|
|
|
|
# Only send to the first non-spec window created
|
|
if @constructor.includeShellLoadTime and not @isSpec
|
|
@constructor.includeShellLoadTime = false
|
|
loadSettings.shellLoadTime ?= Date.now() - global.shellStartTime
|
|
|
|
@browserWindow.loadSettings = loadSettings
|
|
|
|
@browserWindow.on 'window:loaded', =>
|
|
@emit 'window:loaded'
|
|
@resolveLoadedPromise()
|
|
|
|
@setLoadSettings(loadSettings)
|
|
@env = loadSettings.env if loadSettings.env?
|
|
@browserWindow.focusOnWebView() if @isSpec
|
|
@browserWindow.temporaryState = {windowDimensions} if windowDimensions?
|
|
|
|
hasPathToOpen = not (locationsToOpen.length is 1 and not locationsToOpen[0].pathToOpen?)
|
|
@openLocations(locationsToOpen) if hasPathToOpen and not @isSpecWindow()
|
|
|
|
setLoadSettings: (loadSettings) ->
|
|
@browserWindow.loadURL url.format
|
|
protocol: 'file'
|
|
pathname: "#{@resourcePath}/static/index.html"
|
|
slashes: true
|
|
hash: encodeURIComponent(JSON.stringify(loadSettings))
|
|
|
|
getLoadSettings: ->
|
|
if @browserWindow.webContents? and not @browserWindow.webContents.isLoading()
|
|
hash = url.parse(@browserWindow.webContents.getURL()).hash.substr(1)
|
|
JSON.parse(decodeURIComponent(hash))
|
|
|
|
hasProjectPath: -> @getLoadSettings().initialPaths?.length > 0
|
|
|
|
setupContextMenu: ->
|
|
ContextMenu = require './context-menu'
|
|
|
|
@browserWindow.on 'context-menu', (menuTemplate) =>
|
|
new ContextMenu(menuTemplate, this)
|
|
|
|
containsPaths: (paths) ->
|
|
for pathToCheck in paths
|
|
return false unless @containsPath(pathToCheck)
|
|
true
|
|
|
|
containsPath: (pathToCheck) ->
|
|
@getLoadSettings()?.initialPaths?.some (projectPath) ->
|
|
if not projectPath
|
|
false
|
|
else if not pathToCheck
|
|
false
|
|
else if pathToCheck is projectPath
|
|
true
|
|
else if fs.statSyncNoException(pathToCheck).isDirectory?()
|
|
false
|
|
else if pathToCheck.indexOf(path.join(projectPath, path.sep)) is 0
|
|
true
|
|
else
|
|
false
|
|
|
|
handleEvents: ->
|
|
@browserWindow.on 'close', (event) =>
|
|
unless @atomApplication.quitting or @unloading
|
|
event.preventDefault()
|
|
@unloading = true
|
|
@atomApplication.saveState(false)
|
|
@saveState().then(=> @close())
|
|
|
|
@browserWindow.on 'closed', =>
|
|
@fileRecoveryService.didCloseWindow(this)
|
|
@atomApplication.removeWindow(this)
|
|
@resolveClosedPromise()
|
|
|
|
@browserWindow.on 'unresponsive', =>
|
|
return if @isSpec
|
|
|
|
chosen = dialog.showMessageBox @browserWindow,
|
|
type: 'warning'
|
|
buttons: ['Close', 'Keep Waiting']
|
|
message: 'Editor is not responding'
|
|
detail: 'The editor is not responding. Would you like to force close it or just keep waiting?'
|
|
@browserWindow.destroy() if chosen is 0
|
|
|
|
@browserWindow.webContents.on 'crashed', =>
|
|
@atomApplication.exit(100) if @headless
|
|
|
|
@fileRecoveryService.didCrashWindow(this)
|
|
chosen = dialog.showMessageBox @browserWindow,
|
|
type: 'warning'
|
|
buttons: ['Close Window', 'Reload', 'Keep It Open']
|
|
message: 'The editor has crashed'
|
|
detail: 'Please report this issue to https://github.com/atom/atom'
|
|
switch chosen
|
|
when 0 then @browserWindow.destroy()
|
|
when 1 then @browserWindow.reload()
|
|
|
|
@browserWindow.webContents.on 'will-navigate', (event, url) =>
|
|
unless url is @browserWindow.webContents.getURL()
|
|
event.preventDefault()
|
|
|
|
@setupContextMenu()
|
|
|
|
if @isSpec
|
|
# Spec window's web view should always have focus
|
|
@browserWindow.on 'blur', =>
|
|
@browserWindow.focusOnWebView()
|
|
|
|
didCancelWindowUnload: ->
|
|
@unloading = false
|
|
|
|
saveState: ->
|
|
if @isSpecWindow()
|
|
return Promise.resolve()
|
|
|
|
@lastSaveStatePromise = new Promise (resolve) =>
|
|
callback = (event) =>
|
|
if BrowserWindow.fromWebContents(event.sender) is @browserWindow
|
|
ipcMain.removeListener('did-save-window-state', callback)
|
|
resolve()
|
|
ipcMain.on('did-save-window-state', callback)
|
|
@browserWindow.webContents.send('save-window-state')
|
|
@lastSaveStatePromise
|
|
|
|
openPath: (pathToOpen, initialLine, initialColumn) ->
|
|
@openLocations([{pathToOpen, initialLine, initialColumn}])
|
|
|
|
openLocations: (locationsToOpen) ->
|
|
@loadedPromise.then => @sendMessage 'open-locations', locationsToOpen
|
|
|
|
replaceEnvironment: (env) ->
|
|
@browserWindow.webContents.send 'environment', env
|
|
|
|
sendMessage: (message, detail) ->
|
|
@browserWindow.webContents.send 'message', message, detail
|
|
|
|
sendCommand: (command, args...) ->
|
|
if @isSpecWindow()
|
|
unless @atomApplication.sendCommandToFirstResponder(command)
|
|
switch command
|
|
when 'window:reload' then @reload()
|
|
when 'window:toggle-dev-tools' then @toggleDevTools()
|
|
when 'window:close' then @close()
|
|
else if @isWebViewFocused()
|
|
@sendCommandToBrowserWindow(command, args...)
|
|
else
|
|
unless @atomApplication.sendCommandToFirstResponder(command)
|
|
@sendCommandToBrowserWindow(command, args...)
|
|
|
|
sendCommandToBrowserWindow: (command, args...) ->
|
|
action = if args[0]?.contextCommand then 'context-command' else 'command'
|
|
@browserWindow.webContents.send action, command, args...
|
|
|
|
getDimensions: ->
|
|
[x, y] = @browserWindow.getPosition()
|
|
[width, height] = @browserWindow.getSize()
|
|
{x, y, width, height}
|
|
|
|
shouldHideTitleBar: ->
|
|
not @isSpec and
|
|
process.platform is 'darwin' and
|
|
@atomApplication.config.get('core.useCustomTitleBar')
|
|
|
|
close: -> @browserWindow.close()
|
|
|
|
focus: -> @browserWindow.focus()
|
|
|
|
minimize: -> @browserWindow.minimize()
|
|
|
|
maximize: -> @browserWindow.maximize()
|
|
|
|
restore: -> @browserWindow.restore()
|
|
|
|
handlesAtomCommands: ->
|
|
not @isSpecWindow() and @isWebViewFocused()
|
|
|
|
isFocused: -> @browserWindow.isFocused()
|
|
|
|
isMaximized: -> @browserWindow.isMaximized()
|
|
|
|
isMinimized: -> @browserWindow.isMinimized()
|
|
|
|
isWebViewFocused: -> @browserWindow.isWebViewFocused()
|
|
|
|
isSpecWindow: -> @isSpec
|
|
|
|
reload: ->
|
|
@loadedPromise = new Promise((@resolveLoadedPromise) =>)
|
|
@saveState().then => @browserWindow.reload()
|
|
@loadedPromise
|
|
|
|
toggleDevTools: -> @browserWindow.toggleDevTools()
|