diff --git a/build/tasks/convert-theme.coffee b/build/tasks/convert-theme.coffee deleted file mode 100644 index e94370e16..000000000 --- a/build/tasks/convert-theme.coffee +++ /dev/null @@ -1,102 +0,0 @@ -path = require 'path' - -_ = require 'underscore-plus' -fs = require 'fs-plus' -{ScopeSelector} = require 'first-mate' - -module.exports = (grunt) -> - grunt.registerTask 'convert-theme', 'Convert a TextMate theme to an Atom theme', -> - if textMateThemePath = grunt.option('path') - textMateThemePath = path.resolve(textMateThemePath) - if grunt.file.isFile(textMateThemePath) - textMateTheme = new TextMateTheme(textMateThemePath) - themeName = path.basename(textMateThemePath, path.extname(textMateThemePath)) - atomThemePath = path.join(path.dirname(textMateThemePath), "#{themeName.toLowerCase()}-syntax.css") - grunt.file.write(atomThemePath, textMateTheme.getStylesheet()) - grunt.log.ok("Atom theme written to: #{atomThemePath}") - else - grunt.log.error("No theme file found at: #{textMateThemePath}") - false - else - grunt.log.error('Must specify --path=') - false - -class TextMateTheme - constructor: (@path) -> - @rulesets = [] - @buildRulesets() - - buildRulesets: -> - {settings} = fs.readPlistSync(@path) - @buildGlobalSettingsRulesets(settings[0]) - @buildScopeSelectorRulesets(settings[1..]) - - getStylesheet: -> - lines = [] - for {selector, properties} in @getRulesets() - lines.push("#{selector} {") - lines.push " #{name}: #{value};" for name, value of properties - lines.push("}\n") - lines.join('\n') - - getRulesets: -> @rulesets - - buildGlobalSettingsRulesets: ({settings}) -> - { background, foreground, caret, selection, lineHighlight } = settings - - @rulesets.push - selector: '.editor, .editor .gutter' - properties: - 'background-color': @translateColor(background) - 'color': @translateColor(foreground) - - @rulesets.push - selector: '.editor.is-focused .cursor' - properties: - 'border-color': @translateColor(caret) - - @rulesets.push - selector: '.editor.is-focused .selection .region' - properties: - 'background-color': @translateColor(selection) - - @rulesets.push - selector: '.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line' - properties: - 'background-color': @translateColor(lineHighlight) - - buildScopeSelectorRulesets: (scopeSelectorSettings) -> - for { name, scope, settings } in scopeSelectorSettings - continue unless scope - @rulesets.push - comment: name - selector: @translateScopeSelector(scope) - properties: @translateScopeSelectorSettings(settings) - - translateScopeSelector: (textmateScopeSelector) -> - new ScopeSelector(textmateScopeSelector).toCssSelector() - - translateScopeSelectorSettings: ({ foreground, background, fontStyle }) -> - properties = {} - - if fontStyle - fontStyles = fontStyle.split(/\s+/) - properties['font-weight'] = 'bold' if _.contains(fontStyles, 'bold') - properties['font-style'] = 'italic' if _.contains(fontStyles, 'italic') - properties['text-decoration'] = 'underline' if _.contains(fontStyles, 'underline') - - properties['color'] = @translateColor(foreground) if foreground - properties['background-color'] = @translateColor(background) if background - properties - - translateColor: (textmateColor) -> - if textmateColor.length <= 7 - textmateColor - else - r = parseInt(textmateColor[1..2], 16) - g = parseInt(textmateColor[3..4], 16) - b = parseInt(textmateColor[5..6], 16) - a = parseInt(textmateColor[7..8], 16) - a = Math.round((a / 255.0) * 100) / 100 - - "rgba(#{r}, #{g}, #{b}, #{a})" diff --git a/resources/win/atom.ico b/resources/win/atom.ico index 2cf161e68..446140277 100644 Binary files a/resources/win/atom.ico and b/resources/win/atom.ico differ diff --git a/src/atom.coffee b/src/atom.coffee index fb9488452..606ba6b89 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -6,8 +6,6 @@ path = require 'path' remote = require 'remote' screen = require 'screen' shell = require 'shell' -dialog = remote.require 'dialog' -app = remote.require 'app' _ = require 'underscore-plus' {Model} = require 'theorist' @@ -96,7 +94,14 @@ class Atom extends Model # Private: Returns the load settings hash associated with the current window. @getLoadSettings: -> - _.deepClone(@loadSettings ?= _.deepClone(@getCurrentWindow().loadSettings)) + @loadSettings ?= JSON.parse(decodeURIComponent(location.search.substr(14))) + cloned = _.deepClone(@loadSettings) + # The loadSettings.windowState could be large, request it only when needed. + cloned.__defineGetter__ 'windowState', => + @getCurrentWindow().loadSettings.windowState + cloned.__defineSetter__ 'windowState', (value) => + @getCurrentWindow().loadSettings.windowState = value + cloned # Private: @getCurrentWindow: -> @@ -104,7 +109,7 @@ class Atom extends Model # Private: Get the version of the Atom application. @getVersion: -> - @version ?= app.getVersion() + @version ?= @getLoadSettings().appVersion # Private: Determine whether the current version is an official release. @isReleasedVersion: -> @@ -197,13 +202,12 @@ class Atom extends Model # + width: The new width. # + height: The new height. setWindowDimensions: ({x, y, width, height}) -> - browserWindow = @getCurrentWindow() if width? and height? - browserWindow.setSize(width, height) + @setSize(width, height) if x? and y? - browserWindow.setPosition(x, y) + @setPosition(x, y) else - browserWindow.center() + @center() # Private: restoreWindowDimensions: -> @@ -342,6 +346,7 @@ class Atom extends Model else buttonLabels = Object.keys(buttons) + dialog = remote.require('dialog') chosen = dialog.showMessageBox @getCurrentWindow(), type: 'info' message: message @@ -362,32 +367,45 @@ class Atom extends Model showSaveDialogSync: (defaultPath) -> defaultPath ?= @project?.getPath() currentWindow = @getCurrentWindow() + dialog = remote.require('dialog') dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath} # Public: Open the dev tools for the current window. openDevTools: -> - @getCurrentWindow().openDevTools() + ipc.sendChannel('call-window-method', 'openDevTools') # Public: Toggle the visibility of the dev tools for the current window. toggleDevTools: -> - @getCurrentWindow().toggleDevTools() + ipc.sendChannel('call-window-method', 'toggleDevTools') # Public: Reload the current window. reload: -> - @getCurrentWindow().restart() + ipc.sendChannel('call-window-method', 'restart') # Public: Focus the current window. focus: -> - @getCurrentWindow().focus() + ipc.sendChannel('call-window-method', 'focus') $(window).focus() # Public: Show the current window. show: -> - @getCurrentWindow().show() + ipc.sendChannel('call-window-method', 'show') # Public: Hide the current window. hide: -> - @getCurrentWindow().hide() + ipc.sendChannel('call-window-method', 'hide') + + # Public: Set the size of current window. + setSize: (width, height) -> + ipc.sendChannel('call-window-method', 'setSize', width, height) + + # Public: Set the position of current window. + setPosition: (x, y) -> + ipc.sendChannel('call-window-method', 'setPosition', x, y) + + # Public: Move current window to the center of the screen. + center: -> + ipc.sendChannel('call-window-method', 'center') # Private: Schedule the window to be shown and focused on the next tick. # @@ -404,7 +422,9 @@ class Atom extends Model @getCurrentWindow().close() # Private: - exit: (status) -> app.exit(status) + exit: (status) -> + app = remote.require('app') + app.exit(status) # Public: Is the current window in development mode? inDevMode: -> @@ -420,7 +440,7 @@ class Atom extends Model # Public: Set the full screen state of the current window. setFullScreen: (fullScreen=false) -> - @getCurrentWindow().setFullScreen(fullScreen) + ipc.sendChannel('call-window-method', 'setFullScreen', fullScreen) # Public: Is the current window in full screen mode? isFullScreen: -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index affabc0ae..881036b69 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -1,6 +1,7 @@ AtomWindow = require './atom-window' ApplicationMenu = require './application-menu' AtomProtocolHandler = require './atom-protocol-handler' +BrowserWindow = require 'browser-window' Menu = require 'menu' autoUpdater = require 'auto-updater' app = require 'app' @@ -195,6 +196,14 @@ class AtomApplication ipc.on 'command', (processId, routingId, command) => @emit(command) + ipc.on 'window-command', (processId, routingId, command, args...) -> + win = BrowserWindow.fromProcessIdAndRoutingId(processId, routingId) + win.emit(command, args...) + + ipc.on 'call-window-method', (processId, routingId, method, args...) -> + win = BrowserWindow.fromProcessIdAndRoutingId(processId, routingId) + win[method](args...) + # Public: Executes the given command. # # If it isn't handled globally, delegate to the currently focused window. diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 4ca0ab3ad..534154ddf 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -1,10 +1,12 @@ BrowserWindow = require 'browser-window' Menu = require 'menu' ContextMenu = require './context-menu' +app = require 'app' dialog = require 'dialog' ipc = require 'ipc' path = require 'path' fs = require 'fs' +url = require 'url' _ = require 'underscore-plus' # Private: @@ -31,6 +33,7 @@ class AtomWindow loadSettings = _.extend({}, settings) loadSettings.windowState ?= '{}' + loadSettings.appVersion = app.getVersion() # Only send to the first non-spec window created if @constructor.includeShellLoadTime and not @isSpec @@ -43,7 +46,7 @@ class AtomWindow @browserWindow.loadSettings = loadSettings @browserWindow.once 'window:loaded', => @loaded = true - @browserWindow.loadUrl "file://#{@resourcePath}/static/index.html" + @browserWindow.loadUrl @getUrl(loadSettings) @browserWindow.focusOnWebView() if @isSpec @openPath(pathToOpen, initialLine) @@ -51,6 +54,18 @@ class AtomWindow setupNodePath: (resourcePath) -> process.env['NODE_PATH'] = path.resolve(resourcePath, 'exports') + getUrl: (loadSettingsObj) -> + # Ignore the windowState when passing loadSettings via URL, since it could + # be quite large. + loadSettings = _.clone(loadSettingsObj) + delete loadSettings['windowState'] + + url.format + protocol: 'file' + pathname: "#{@resourcePath}/static/index.html" + slashes: true + query: {loadSettings: JSON.stringify(loadSettings)} + getInitialPath: -> @browserWindow.loadSettings.initialPath diff --git a/src/editor.coffee b/src/editor.coffee index 904c8dfa4..3e0ea7023 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -238,15 +238,15 @@ class Editor extends Model # Public: Given a position, this clips it to a real position. # - # For example, if `position`'s row exceeds the row count of the buffer, + # For example, if `bufferPosition`'s row exceeds the row count of the buffer, # or if its column goes beyond a line's length, this "sanitizes" the value # to a real position. # - # * position: + # * bufferPosition: # The {Point} to clip # # Returns the new, clipped {Point}. Note that this could be the same as - # `position` if no clipping was performed. + # `bufferPosition` if no clipping was performed. clipBufferPosition: (bufferPosition) -> @buffer.clipPosition(bufferPosition) # Public: Given a range, this clips it to a real range. diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index aaf55bf1e..00bcb86e6 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -11,6 +11,8 @@ fs = require 'fs-plus' # Should be accessed via `atom.menu`. module.exports = class MenuManager + pendingUpdateOperation: null + # Private: constructor: ({@resourcePath}) -> @template = [] @@ -49,11 +51,13 @@ class MenuManager # Public: Refreshes the currently visible menu. update: -> - keystrokesByCommand = {} - for binding in atom.keymap.getKeyBindings() when @includeSelector(binding.selector) - keystrokesByCommand[binding.command] ?= [] - keystrokesByCommand[binding.command].push binding.keystroke - @sendToBrowserProcess(@template, keystrokesByCommand) + clearImmediate(@pendingUpdateOperation) if @pendingUpdateOperation? + @pendingUpdateOperation = setImmediate => + keystrokesByCommand = {} + for binding in atom.keymap.getKeyBindings() when @includeSelector(binding.selector) + keystrokesByCommand[binding.command] ?= [] + keystrokesByCommand[binding.command].push binding.keystroke + @sendToBrowserProcess(@template, keystrokesByCommand) # Private: loadPlatformItems: -> diff --git a/src/window-bootstrap.coffee b/src/window-bootstrap.coffee index dc8c46c42..42ec7cd91 100644 --- a/src/window-bootstrap.coffee +++ b/src/window-bootstrap.coffee @@ -1,9 +1,6 @@ # Like sands through the hourglass, so are the days of our lives. startTime = Date.now() -# Start the crash reporter before anything else. -require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub') - require './window' Atom = require './atom' diff --git a/static/index.html b/static/index.html index ebc054082..990e08915 100644 --- a/static/index.html +++ b/static/index.html @@ -6,15 +6,28 @@