From 32f51491962cd0d5c95982b0abd6bdf015148571 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 27 Jan 2016 12:38:28 -0800 Subject: [PATCH] Wait for browser process to acknowledge window manipulation IPC requests We need to avoid using the module for synchronous IPC on startup, but in some cases, we need to know when our asynchronous IPC messages have taken effect. Now, methods like and return Promises that indicate when the message has been processed. --- spec/text-editor-component-spec.js | 6 +--- src/application-delegate.coffee | 13 ++++---- src/atom-environment.coffee | 28 +++++++++-------- src/browser/atom-application.coffee | 19 +++++++++++ src/initialize-application-window.coffee | 14 ++++----- src/ipc-helpers.js | 40 ++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 31 deletions(-) create mode 100644 src/ipc-helpers.js diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 15ad223fe..08da07dd8 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -2151,15 +2151,11 @@ describe('TextEditorComponent', function () { item.style.height = itemHeight + 'px' wrapperNode.style.width = windowWidth + 'px' wrapperNode.style.height = windowHeight + 'px' - atom.setWindowDimensions({ + await atom.setWindowDimensions({ width: windowWidth, height: windowHeight }) - await conditionPromise(function () { - return window.innerWidth === windowWidth - }) - component.measureDimensions() component.measureWindowSize() await nextViewUpdatePromise() diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index f7b04e10d..f87827886 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -1,5 +1,6 @@ _ = require 'underscore-plus' {ipcRenderer, remote, shell, webFrame} = require 'electron' +ipcHelpers = require './ipc-helpers' {Disposable} = require 'event-kit' {getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers' @@ -26,26 +27,26 @@ class ApplicationDelegate {width, height} setWindowSize: (width, height) -> - remote.getCurrentWindow().setSize(width, height) + ipcHelpers.call('set-window-size', width, height) getWindowPosition: -> [x, y] = remote.getCurrentWindow().getPosition() {x, y} setWindowPosition: (x, y) -> - ipcRenderer.send("call-window-method", "setPosition", x, y) + ipcHelpers.call('set-window-position', x, y) centerWindow: -> - ipcRenderer.send("call-window-method", "center") + ipcHelpers.call('center-window') focusWindow: -> - ipcRenderer.send("call-window-method", "focus") + ipcHelpers.call('focus-window') showWindow: -> - ipcRenderer.send("call-window-method", "show") + ipcHelpers.call('show-window') hideWindow: -> - ipcRenderer.send("call-window-method", "hide") + ipcHelpers.call('hide-window') reloadWindow: -> ipcRenderer.send("call-window-method", "reload") diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index cd6834da4..be05ef4cf 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -519,16 +519,17 @@ class AtomEnvironment extends Model # Restore the window to its previous dimensions and show it. # - # Also restores the full screen and maximized state on the next tick to + # Restores the full screen and maximized state after the window has resized to # prevent resize glitches. displayWindow: -> - dimensions = @restoreWindowDimensions() - @show() - @focus() - - setImmediate => - @setFullScreen(true) if @workspace?.fullScreen - @maximize() if dimensions?.maximized and process.platform isnt 'darwin' + @restoreWindowDimensions().then (dimensions) => + steps = [ + @show(), + @focus() + ] + steps.push(@setFullScreen(true)) if @workspace.fullScreen + steps.push(@maximize()) if dimensions?.maximized and process.platform isnt 'darwin' + Promise.all(steps) # Get the dimensions of this window. # @@ -556,12 +557,14 @@ class AtomEnvironment extends Model # * `width` The new width. # * `height` The new height. setWindowDimensions: ({x, y, width, height}) -> + steps = [] if width? and height? - @setSize(width, height) + steps.push(@setSize(width, height)) if x? and y? - @setPosition(x, y) + steps.push(@setPosition(x, y)) else - @center() + steps.push(@center()) + Promise.all(steps) # Returns true if the dimensions are useable, false if they should be ignored. # Work around for https://github.com/atom/atom-shell/issues/473 @@ -594,8 +597,7 @@ class AtomEnvironment extends Model dimensions = @state.windowDimensions unless @isValidDimensions(dimensions) dimensions = @getDefaultWindowDimensions() - @setWindowDimensions(dimensions) - dimensions + @setWindowDimensions(dimensions).then -> dimensions storeWindowDimensions: -> dimensions = @getWindowDimensions() diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 49bf310dc..ff98c9edc 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -3,6 +3,7 @@ ApplicationMenu = require './application-menu' AtomProtocolHandler = require './atom-protocol-handler' AutoUpdateManager = require './auto-update-manager' StorageFolder = require '../storage-folder' +ipcHelpers = require '../ipc-helpers' {BrowserWindow, Menu, app, dialog, ipcMain, shell} = require 'electron' fs = require 'fs-plus' path = require 'path' @@ -261,6 +262,24 @@ class AtomApplication @promptForPath "folder", (selectedPaths) -> event.sender.send(responseChannel, selectedPaths) + ipcHelpers.respondTo 'set-window-size', (win, width, height) -> + win.setSize(width, height) + + ipcHelpers.respondTo 'set-window-position', (win, x, y) -> + win.setPosition(x, y) + + ipcHelpers.respondTo 'center-window', (win) -> + win.center() + + ipcHelpers.respondTo 'focus-window', (win) -> + win.focus() + + ipcHelpers.respondTo 'show-window', (win) -> + win.show() + + ipcHelpers.respondTo 'hide-window', (win) -> + win.hide() + ipcMain.on 'did-cancel-window-unload', => @quitting = false diff --git a/src/initialize-application-window.coffee b/src/initialize-application-window.coffee index 57aa33ce0..35c48ee0a 100644 --- a/src/initialize-application-window.coffee +++ b/src/initialize-application-window.coffee @@ -23,11 +23,11 @@ module.exports = ({blobStore}) -> enablePersistence: true }) - atom.displayWindow() - atom.startEditorWindow() + atom.displayWindow().then -> + atom.startEditorWindow() - # Workaround for focus getting cleared upon window creation - windowFocused = -> - window.removeEventListener('focus', windowFocused) - setTimeout (-> document.querySelector('atom-workspace').focus()), 0 - window.addEventListener('focus', windowFocused) + # Workaround for focus getting cleared upon window creation + windowFocused = -> + window.removeEventListener('focus', windowFocused) + setTimeout (-> document.querySelector('atom-workspace').focus()), 0 + window.addEventListener('focus', windowFocused) diff --git a/src/ipc-helpers.js b/src/ipc-helpers.js new file mode 100644 index 000000000..c0b38c50e --- /dev/null +++ b/src/ipc-helpers.js @@ -0,0 +1,40 @@ +var ipcRenderer = null +var ipcMain = null +var BrowserWindow = null + +exports.call = function (methodName, ...args) { + if (!ipcRenderer) { + ipcRenderer = require('electron').ipcRenderer + } + + var responseChannel = getResponseChannel(methodName) + + return new Promise(function (resolve) { + ipcRenderer.on(responseChannel, function (event, result) { + ipcRenderer.removeAllListeners(responseChannel) + resolve(result) + }) + + ipcRenderer.send(methodName, ...args) + }) +} + +exports.respondTo = function (methodName, callback) { + if (!ipcMain) { + var electron = require('electron') + ipcMain = electron.ipcMain + BrowserWindow = electron.BrowserWindow + } + + var responseChannel = getResponseChannel(methodName) + + ipcMain.on(methodName, function (event, ...args) { + var browserWindow = BrowserWindow.fromWebContents(event.sender) + var result = callback(browserWindow, ...args) + event.sender.send(responseChannel, result) + }) +} + +function getResponseChannel (methodName) { + return 'ipc-helpers-' + methodName + '-response' +}