From e39b12b165690ac1a1f8d85e3441f0489269820c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 10 Apr 2019 16:08:59 -0400 Subject: [PATCH 1/4] Prefer a {window} explicitly provided to openPaths() --- src/main-process/atom-application.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index dc5671ddc..f5fc411a7 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -968,11 +968,21 @@ class AtomApplication extends EventEmitter { const normalizedPathsToOpen = locationsToOpen.map(location => location.pathToOpen).filter(Boolean) let existingWindow - if (!newWindow && normalizedPathsToOpen.length > 0) { + + // Explicitly provided AtomWindow has precedence unless a new window is forced. + if (!newWindow) { + existingWindow = window + } + + // If no window is specified, a new window is not forced, and at least one path is provided, locate + // an existing window that contains all paths. + if (!existingWindow && !newWindow && normalizedPathsToOpen.length > 0) { existingWindow = this.windowForPaths(normalizedPathsToOpen, devMode) } - if (addToLastWindow && !existingWindow) { + // No window specified, new window not forced, no existing window found, and addition to the last window + // requested. Find the last focused window. + if (!existingWindow && !newWindow && addToLastWindow) { let lastWindow = window || this.getLastFocusedWindow() if (lastWindow && lastWindow.devMode === devMode) { existingWindow = lastWindow From 03908ddfab113bfe633c1a8c29b8a15c42154a6e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 10 Apr 2019 16:09:32 -0400 Subject: [PATCH 2/4] Pass along the source window of an `open-command` IPC event --- src/main-process/atom-application.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index f5fc411a7..ed1c2dc91 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -639,13 +639,15 @@ class AtomApplication extends EventEmitter { })) this.disposable.add(ipcHelpers.on(ipcMain, 'open-command', (event, command, defaultPath) => { + const options = getLoadSettings() + options.window = this.atomWindowForEvent(event) switch (command) { case 'application:open': - return this.promptForPathToOpen('all', getLoadSettings(), defaultPath) + return this.promptForPathToOpen('all', options, defaultPath) case 'application:open-file': - return this.promptForPathToOpen('file', getLoadSettings(), defaultPath) + return this.promptForPathToOpen('file', options, defaultPath) case 'application:open-folder': - return this.promptForPathToOpen('folder', getLoadSettings(), defaultPath) + return this.promptForPathToOpen('folder', options, defaultPath) default: return console.log(`Invalid open-command received: ${command}`) } From 866447934e397e5a0fd4359be6fafb2de0bd3c3c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 10 Apr 2019 16:15:39 -0400 Subject: [PATCH 3/4] promptForPathToOpen() uses an existing window when only files are chosen --- src/main-process/atom-application.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index ed1c2dc91..481ece658 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -1424,14 +1424,32 @@ class AtomApplication extends EventEmitter { // should be in dev mode or not. // :safeMode - A Boolean which controls whether any newly opened windows // should be in safe mode or not. - // :window - An {AtomWindow} to use for opening a selected file path. + // :window - An {AtomWindow} to use for opening selected file paths as long as + // all are files. // :path - An optional String which controls the default path to which the // file dialog opens. promptForPathToOpen (type, {devMode, safeMode, window}, path = null) { return this.promptForPath( type, - pathsToOpen => { - return this.openPaths({pathsToOpen, devMode, safeMode, window}) + async pathsToOpen => { + let targetWindow + + // Open in :window as long as no chosen paths are folders. If any chosen path is a folder, open in a + // new window instead. + if (type === 'folder') { + targetWindow = null + } else if (type === 'file') { + targetWindow = window + } else if (type === 'all') { + const areDirectories = await Promise.all( + pathsToOpen.map(pathToOpen => new Promise(resolve => fs.isDirectory(pathToOpen, resolve))) + ) + if (!areDirectories.some(Boolean)) { + targetWindow = window + } + } + + return this.openPaths({pathsToOpen, devMode, safeMode, window: targetWindow}) }, path ) From ffb295d5d642e5507a3318e31e9d9753c5e6b805 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 10 Apr 2019 16:50:21 -0400 Subject: [PATCH 4/4] Conditionally include {window} in getLoadSettings() --- src/main-process/atom-application.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 481ece658..11680f3f1 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -452,13 +452,17 @@ class AtomApplication extends EventEmitter { // Registers basic application commands, non-idempotent. handleEvents () { - const getLoadSettings = () => { + const getLoadSettings = includeWindow => { const window = this.focusedWindow() - return {devMode: window && window.devMode, safeMode: window && window.safeMode} + return { + devMode: window && window.devMode, + safeMode: window && window.safeMode, + window: includeWindow && window + } } this.on('application:quit', () => app.quit()) - this.on('application:new-window', () => this.openPath(getLoadSettings())) + this.on('application:new-window', () => this.openPath(getLoadSettings(false))) this.on('application:new-file', () => (this.focusedWindow() || this).openPath()) this.on('application:open-dev', () => this.promptForPathToOpen('all', {devMode: true})) this.on('application:open-safe', () => this.promptForPathToOpen('all', {safeMode: true})) @@ -487,9 +491,9 @@ class AtomApplication extends EventEmitter { this.openPaths({ pathsToOpen: paths }) }) - this.on('application:open', () => this.promptForPathToOpen('all', getLoadSettings(), getDefaultPath())) - this.on('application:open-file', () => this.promptForPathToOpen('file', getLoadSettings(), getDefaultPath())) - this.on('application:open-folder', () => this.promptForPathToOpen('folder', getLoadSettings(), getDefaultPath())) + this.on('application:open', () => this.promptForPathToOpen('all', getLoadSettings(true), getDefaultPath())) + this.on('application:open-file', () => this.promptForPathToOpen('file', getLoadSettings(true), getDefaultPath())) + this.on('application:open-folder', () => this.promptForPathToOpen('folder', getLoadSettings(true), getDefaultPath())) this.on('application:bring-all-windows-to-front', () => Menu.sendActionToFirstResponder('arrangeInFront:')) this.on('application:hide', () => Menu.sendActionToFirstResponder('hide:')) this.on('application:hide-other-applications', () => Menu.sendActionToFirstResponder('hideOtherApplications:')) @@ -639,15 +643,13 @@ class AtomApplication extends EventEmitter { })) this.disposable.add(ipcHelpers.on(ipcMain, 'open-command', (event, command, defaultPath) => { - const options = getLoadSettings() - options.window = this.atomWindowForEvent(event) switch (command) { case 'application:open': - return this.promptForPathToOpen('all', options, defaultPath) + return this.promptForPathToOpen('all', getLoadSettings(true), defaultPath) case 'application:open-file': - return this.promptForPathToOpen('file', options, defaultPath) + return this.promptForPathToOpen('file', getLoadSettings(true), defaultPath) case 'application:open-folder': - return this.promptForPathToOpen('folder', options, defaultPath) + return this.promptForPathToOpen('folder', getLoadSettings(true), defaultPath) default: return console.log(`Invalid open-command received: ${command}`) }