mirror of
https://github.com/atom/atom.git
synced 2026-02-12 23:55:10 -05:00
217 lines
6.8 KiB
CoffeeScript
217 lines
6.8 KiB
CoffeeScript
BrowserWindow = require 'browser_window'
|
|
Menu = require 'menu'
|
|
app = require 'app'
|
|
ipc = require 'ipc'
|
|
dialog = require 'dialog'
|
|
fs = require 'fs'
|
|
path = require 'path'
|
|
net = require 'net'
|
|
|
|
atomApplication = null
|
|
|
|
module.exports =
|
|
class AtomApplication
|
|
windows: null
|
|
menu: null
|
|
resourcePath: null
|
|
executedFrom: null
|
|
pathsToOpen: null
|
|
testMode: null
|
|
version: null
|
|
socketPath: '/tmp/atom.sock'
|
|
|
|
constructor: ({@resourcePath, @executedFrom, @pathsToOpen, @testMode, @version}) ->
|
|
atomApplication = this
|
|
@windows = []
|
|
|
|
@sendArgumentsToExistingProcess (success) =>
|
|
process.exit(1) if success # An Atom already exists, kill this process
|
|
@listenForArgumentsFromNewProcess()
|
|
@setupNodePath()
|
|
@setupJavaScriptArguments()
|
|
@buildApplicationMenu()
|
|
@handleEvents()
|
|
|
|
if @testMode
|
|
@runSpecs(true)
|
|
else
|
|
@open(@pathsToOpen)
|
|
|
|
getHomeDir: ->
|
|
process.env[if process.platform is 'win32' then 'USERPROFILE' else 'HOME']
|
|
|
|
setupNodePath: ->
|
|
resourcePaths = [
|
|
'src/stdlib',
|
|
'src/app',
|
|
'src/packages',
|
|
'src',
|
|
'vendor',
|
|
'static',
|
|
'node_modules',
|
|
'spec',
|
|
'',
|
|
]
|
|
|
|
resourcePaths.push path.join(@getHomeDir(), '.atom', 'packages')
|
|
|
|
resourcePaths = resourcePaths.map (relativeOrAbsolutePath) =>
|
|
path.resolve @resourcePath, relativeOrAbsolutePath
|
|
|
|
process.env['NODE_PATH'] = resourcePaths.join path.delimiter
|
|
|
|
sendArgumentsToExistingProcess: (callback) ->
|
|
client = net.connect {path: @socketPath}, (args...) =>
|
|
output = JSON.stringify({@pathsToOpen})
|
|
client.write(output)
|
|
callback(true)
|
|
|
|
client.on 'error', (args...) -> callback(false)
|
|
|
|
listenForArgumentsFromNewProcess: ->
|
|
fs.unlinkSync @socketPath if fs.existsSync(@socketPath)
|
|
server = net.createServer (connection) =>
|
|
connection.on 'data', (data) =>
|
|
{pathsToOpen} = JSON.parse(data)
|
|
@open(pathsToOpen)
|
|
|
|
server.listen @socketPath
|
|
server.on 'error', (error) -> console.error 'Application server failed', error
|
|
|
|
setupJavaScriptArguments: ->
|
|
app.commandLine.appendSwitch 'js-flags', '--harmony_collections'
|
|
|
|
buildApplicationMenu: ->
|
|
atomMenu =
|
|
label: 'Atom'
|
|
submenu: [
|
|
{ label: 'About Atom', selector: 'orderFrontStandardAboutPanel:' }
|
|
{ label: "Version #{@version}", enabled: false }
|
|
{ type: 'separator' }
|
|
{ label: 'Preferences...', accelerator: 'Command+,', click: => @openConfig() }
|
|
{ type: 'separator' }
|
|
{ label: 'Hide Atom Shell', accelerator: 'Command+H', selector: 'hide:' }
|
|
{ label: 'Hide Others', accelerator: 'Command+Shift+H', selector: 'hideOtherApplications:' }
|
|
{ label: 'Show All', selector: 'unhideAllApplications:' }
|
|
{ type: 'separator' }
|
|
{ label: 'Run Specs', accelerator: 'Command+MacCtrl+Alt+S', click: => @runSpecs() }
|
|
{ type: 'separator' }
|
|
{ label: 'Quit', accelerator: 'Command+Q', click: -> app.quit() }
|
|
]
|
|
|
|
editMenu =
|
|
label: 'Edit'
|
|
submenu:[
|
|
{ label: 'Undo', accelerator: 'Command+Z', selector: 'undo:' }
|
|
{ label: 'Redo', accelerator: 'Command+Shift+Z', selector: 'redo:' }
|
|
{ type: 'separator' }
|
|
{ label: 'Cut', accelerator: 'Command+X', selector: 'cut:' }
|
|
{ label: 'Copy', accelerator: 'Command+C', selector: 'copy:' }
|
|
{ label: 'Paste', accelerator: 'Command+V', selector: 'paste:' }
|
|
{ label: 'Select All', accelerator: 'Command+A', selector: 'selectAll:' }
|
|
]
|
|
|
|
viewMenu =
|
|
label: 'View'
|
|
submenu:[
|
|
{ label: 'Reload', accelerator: 'Command+R', click: => BrowserWindow.getFocusedWindow()?.reloadIgnoringCache() }
|
|
{ label: 'Toggle DevTools', accelerator: 'Alt+Command+I', click: => BrowserWindow.getFocusedWindow()?.toggleDevTools() }
|
|
]
|
|
|
|
windowMenu =
|
|
label: 'Window'
|
|
submenu: [
|
|
{ label: 'Minimize', accelerator: 'Command+M', selector: 'performMiniaturize:' }
|
|
{ label: 'Close', accelerator: 'Command+W', selector: 'performClose:' }
|
|
{ type: 'separator' }
|
|
{ label: 'Bring All to Front', selector: 'arrangeInFront:' }
|
|
]
|
|
|
|
@menu = Menu.buildFromTemplate [atomMenu, viewMenu, editMenu, windowMenu]
|
|
Menu.setApplicationMenu @menu
|
|
|
|
handleEvents: ->
|
|
# Quit when all windows are closed.
|
|
app.on 'window-all-closed', ->
|
|
app.quit()
|
|
|
|
ipc.on 'close-without-confirm', (processId, routingId) ->
|
|
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
|
|
window.removeAllListeners 'close'
|
|
window.close()
|
|
|
|
ipc.on 'open-config', =>
|
|
@openConfig()
|
|
|
|
ipc.on 'open-folder', =>
|
|
currentWindow = BrowserWindow.getFocusedWindow()
|
|
pathsToOpen = dialog.showOpenDialog title: 'Open', properties: ['openFile', 'openDirectory', 'multiSelections', 'createDirectory']
|
|
@open(pathToOpen) for pathToOpen in @pathsToOpen if @pathsToOpen?
|
|
|
|
ipc.on 'new-window', =>
|
|
@open()
|
|
|
|
ipc.on 'get-version', (event) ->
|
|
event.result = @version
|
|
|
|
sendCommand: (command) ->
|
|
atomWindow.sendCommand command for atomWindow in @windows when atomWindow.browserWindow.isFocused()
|
|
|
|
open: (pathsToOpen = []) ->
|
|
pathsToOpen = [null] if pathsToOpen.length == 0
|
|
for pathToOpen in pathsToOpen
|
|
pathToOpen = path.resolve(@executedFrom, pathToOpen) if @executedFrom and pathToOpen
|
|
|
|
atomWindow = new AtomWindow
|
|
pathToOpen: pathToOpen
|
|
bootstrapScript: 'window-bootstrap',
|
|
resourcePath: @resourcePath
|
|
|
|
@windows.push atomWindow
|
|
|
|
openConfig: ->
|
|
atomWindow = new AtomWindow
|
|
bootstrapScript: 'config-bootstrap',
|
|
resourcePath: @resourcePath
|
|
|
|
@windows.push atomWindow
|
|
|
|
runSpecs: (exitWhenDone) ->
|
|
specWindow = new AtomWindow
|
|
bootstrapScript: 'spec-bootstrap',
|
|
resourcePath: @resourcePath
|
|
exitWhenDone: exitWhenDone
|
|
isSpec: true
|
|
|
|
specWindow.browserWindow.show()
|
|
@windows.push specWindow
|
|
|
|
class AtomWindow
|
|
browserWindow: null
|
|
|
|
constructor: ({bootstrapScript, resourcePath, pathToOpen, exitWhenDone, @isSpec}) ->
|
|
@browserWindow = new BrowserWindow show: false, title: 'Atom'
|
|
@handleEvents()
|
|
|
|
url = "file://#{resourcePath}/static/index.html?bootstrapScript=#{bootstrapScript}&resourcePath=#{resourcePath}"
|
|
url += "&pathToOpen=#{pathToOpen}" if pathToOpen
|
|
url += '&exitWhenDone=1' if exitWhenDone
|
|
|
|
@browserWindow.loadUrl url
|
|
|
|
handleEvents: ->
|
|
@browserWindow.on 'destroyed', =>
|
|
atomApplication.windows.splice atomApplication.windows.indexOf(this), 1
|
|
|
|
if @isSpec
|
|
# Spec window's web view should always have focus
|
|
@browserWindow.on 'blur', =>
|
|
@browserWindow.focusOnWebView()
|
|
else
|
|
@browserWindow.on 'close', (event) =>
|
|
event.preventDefault()
|
|
@sendCommand 'window:close'
|
|
|
|
sendCommand: (command) ->
|
|
ipc.sendChannel @browserWindow.getProcessId(), @browserWindow.getRoutingId(), 'command', command
|