Files
atom/src/atom-application.coffee
2013-05-24 11:53:49 -07:00

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