From d0cb8e2c558fe01c094a624fe751cb957b4f6570 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 17 Nov 2015 21:00:13 -0800 Subject: [PATCH] Store project directory paths as state on AtomWindow in browser process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #9574 Previously, we were storing the project directory paths as the `initialPaths` key in load settings, which were accessed in the browser process by reading the URL hash. However, this URL hash was not always available, subjecting us to timing issues when opening multiple files in the same folder in rapid succession. We now store the project directory paths directly on AtomWindow instances on creation, then RPC changes from the render process to the browser process with a custom code path. Shout out to :airplane::finnadie:’d @as-cii on this for pairing with me. --- spec/atom-environment-spec.coffee | 8 ++++---- src/application-delegate.coffee | 10 ++++------ src/atom-environment.coffee | 8 ++++---- src/browser/atom-application.coffee | 7 +++---- src/browser/atom-window.coffee | 16 ++++++++-------- ...rs.coffee => get-window-load-settings.coffee} | 6 +----- src/initialize-application-window.coffee | 2 +- src/initialize-test-window.coffee | 2 +- 8 files changed, 26 insertions(+), 33 deletions(-) rename src/{window-load-settings-helpers.coffee => get-window-load-settings.coffee} (74%) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 3e6536681..127659cf7 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -151,7 +151,7 @@ describe "AtomEnvironment", -> [dir1, dir2] = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")] loadSettings = _.extend atom.getLoadSettings(), - initialPaths: [dir1] + projectDirectoryPaths: [dir1] windowState: null spyOn(atom, 'getLoadSettings').andCallFake -> loadSettings @@ -165,7 +165,7 @@ describe "AtomEnvironment", -> atom.loadStateSync() expect(atom.state.stuff).toBeUndefined() - loadSettings.initialPaths = [dir2, dir1] + loadSettings.projectDirectoryPaths = [dir2, dir1] atom.state = {} atom.loadStateSync() expect(atom.state.stuff).toBe("cool") @@ -173,7 +173,7 @@ describe "AtomEnvironment", -> describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> beforeEach -> - spyOn(atom, 'getLoadSettings').andReturn(initialPaths: []) + spyOn(atom, 'getLoadSettings').andReturn(projectDirectoryPaths: []) it "opens an empty buffer", -> spyOn(atom.workspace, 'open') @@ -191,7 +191,7 @@ describe "AtomEnvironment", -> describe "when the project has a path", -> beforeEach -> - spyOn(atom, 'getLoadSettings').andReturn(initialPaths: ['something']) + spyOn(atom, 'getLoadSettings').andReturn(projectDirectoryPaths: ['something']) spyOn(atom.workspace, 'open') it "does not open an empty buffer", -> diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index 1e05b3dbb..0ea0bdafd 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -4,7 +4,7 @@ remote = require 'remote' shell = require 'shell' webFrame = require 'web-frame' {Disposable} = require 'event-kit' -{getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers' +getWindowLoadSettings = require './get-window-load-settings' module.exports = class ApplicationDelegate @@ -80,10 +80,8 @@ class ApplicationDelegate setRepresentedFilename: (filename) -> ipc.send("call-window-method", "setRepresentedFilename", filename) - setRepresentedDirectoryPaths: (paths) -> - loadSettings = getWindowLoadSettings() - loadSettings['initialPaths'] = paths - setWindowLoadSettings(loadSettings) + setProjectDirectoryPaths: (paths) -> + ipc.send("window-command", "set-project-directory-paths", paths) setAutoHideWindowMenuBar: (autoHide) -> ipc.send("call-window-method", "setAutoHideMenuBar", autoHide) @@ -124,7 +122,7 @@ class ApplicationDelegate else params = _.clone(params) params.title ?= 'Save File' - params.defaultPath ?= getWindowLoadSettings().initialPaths[0] + params.defaultPath ?= getWindowLoadSettings().projectDirectoryPaths[0] dialog = remote.require('dialog') dialog.showSaveDialog remote.getCurrentWindow(), params diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index ac76daf04..c1b25abf1 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -11,7 +11,7 @@ Model = require './model' WindowEventHandler = require './window-event-handler' StylesElement = require './styles-element' StorageFolder = require './storage-folder' -{getWindowLoadSettings} = require './window-load-settings-helpers' +getWindowLoadSettings = require './get-window-load-settings' registerDefaultCommands = require './register-default-commands' DeserializerManager = require './deserializer-manager' @@ -651,7 +651,7 @@ class AtomEnvironment extends Model openInitialEmptyEditorIfNecessary: -> return unless @config.get('core.openEmptyEditorOnStart') - if @getLoadSettings().initialPaths?.length is 0 and @workspace.getPaneItems().length is 0 + if @getLoadSettings().projectDirectoryPaths?.length is 0 and @workspace.getPaneItems().length is 0 @workspace.open(null) installUncaughtErrorHandler: -> @@ -753,7 +753,7 @@ class AtomEnvironment extends Model # Notify the browser project of the window's current project path watchProjectPath: -> @disposables.add @project.onDidChangePaths => - @applicationDelegate.setRepresentedDirectoryPaths(@project.getPaths()) + @applicationDelegate.setProjectDirectoryPaths(@project.getPaths()) setDocumentEdited: (edited) -> @applicationDelegate.setWindowDocumentEdited?(edited) @@ -789,7 +789,7 @@ class AtomEnvironment extends Model startTime = Date.now() - if stateKey = @getStateKey(@getLoadSettings().initialPaths) + if stateKey = @getStateKey(@getLoadSettings().projectDirectoryPaths) if state = @getStorageFolder().load(stateKey) @state = state diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 8bb44349e..7e1f71390 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -437,9 +437,8 @@ class AtomApplication return if @quitting states = [] for window in @windows - unless window.isSpec - if loadSettings = window.getLoadSettings() - states.push(initialPaths: loadSettings.initialPaths) + if not window.isSpec and window.projectDirectoryPaths? + states.push(projectDirectoryPaths: window.projectDirectoryPaths) if states.length > 0 or allowEmpty @storageFolder.store('application.json', states) @@ -447,7 +446,7 @@ class AtomApplication if (states = @storageFolder.load('application.json'))?.length > 0 for state in states @openWithOptions(_.extend(options, { - pathsToOpen: state.initialPaths + pathsToOpen: state.projectDirectoryPaths urlsToOpen: [] devMode: @devMode safeMode: @safeMode diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index c507b634c..e519d9157 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -55,14 +55,15 @@ class AtomWindow @constructor.includeShellLoadTime = false loadSettings.shellLoadTime ?= Date.now() - global.shellStartTime - loadSettings.initialPaths = + loadSettings.projectDirectoryPaths = for {pathToOpen} in locationsToOpen when pathToOpen if fs.statSyncNoException(pathToOpen).isFile?() path.dirname(pathToOpen) else pathToOpen - loadSettings.initialPaths.sort() + loadSettings.projectDirectoryPaths.sort() + @setProjectDirectoryPaths(loadSettings.projectDirectoryPaths) @browserWindow.loadSettings = loadSettings @browserWindow.once 'window:loaded', => @@ -87,12 +88,9 @@ class AtomWindow 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)) + setProjectDirectoryPaths: (@projectDirectoryPaths) -> - hasProjectPath: -> @getLoadSettings().initialPaths?.length > 0 + hasProjectPath: -> @projectDirectoryPaths?.length > 0 setupContextMenu: -> ContextMenu = require './context-menu' @@ -106,7 +104,7 @@ class AtomWindow true containsPath: (pathToCheck) -> - @getLoadSettings()?.initialPaths?.some (projectPath) -> + @projectDirectoryPaths?.some (projectPath) -> if not projectPath false else if not pathToCheck @@ -121,6 +119,8 @@ class AtomWindow false handleEvents: -> + @browserWindow.on 'set-project-directory-paths', @setProjectDirectoryPaths.bind(this) + @browserWindow.on 'closed', => global.atomApplication.removeWindow(this) diff --git a/src/window-load-settings-helpers.coffee b/src/get-window-load-settings.coffee similarity index 74% rename from src/window-load-settings-helpers.coffee rename to src/get-window-load-settings.coffee index 59ee2f382..85e087645 100644 --- a/src/window-load-settings-helpers.coffee +++ b/src/get-window-load-settings.coffee @@ -3,7 +3,7 @@ _ = require 'underscore-plus' windowLoadSettings = null -exports.getWindowLoadSettings = -> +module.exports = -> windowLoadSettings ?= JSON.parse(window.decodeURIComponent(window.location.hash.substr(1))) clone = _.deepClone(windowLoadSettings) @@ -14,7 +14,3 @@ exports.getWindowLoadSettings = -> remote.getCurrentWindow().loadSettings.windowState = value clone - -exports.setWindowLoadSettings = (settings) -> - windowLoadSettings = settings - location.hash = encodeURIComponent(JSON.stringify(settings)) diff --git a/src/initialize-application-window.coffee b/src/initialize-application-window.coffee index 57aa33ce0..4bc50144c 100644 --- a/src/initialize-application-window.coffee +++ b/src/initialize-application-window.coffee @@ -2,7 +2,7 @@ module.exports = ({blobStore}) -> path = require 'path' require './window' - {getWindowLoadSettings} = require './window-load-settings-helpers' + getWindowLoadSettings = require './get-window-load-settings' {resourcePath, isSpec, devMode} = getWindowLoadSettings() diff --git a/src/initialize-test-window.coffee b/src/initialize-test-window.coffee index 375581a96..97caae276 100644 --- a/src/initialize-test-window.coffee +++ b/src/initialize-test-window.coffee @@ -15,7 +15,7 @@ module.exports = ({blobStore}) -> try path = require 'path' ipc = require 'ipc' - {getWindowLoadSettings} = require './window-load-settings-helpers' + getWindowLoadSettings = require './get-window-load-settings' AtomEnvironment = require '../src/atom-environment' ApplicationDelegate = require '../src/application-delegate'