From d8679b38993ae66c9e6d60968da19124005d09b6 Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Tue, 2 Feb 2016 23:01:00 -0800 Subject: [PATCH 1/8] Allow openExternal to open URLs in the background #3224 --- .../atom_resource_dispatcher_host_delegate.cc | 2 +- atom/common/api/atom_api_shell.cc | 12 +++++++++++- atom/common/platform_util.h | 2 +- atom/common/platform_util_linux.cc | 2 +- atom/common/platform_util_mac.mm | 12 ++++++++++-- atom/common/platform_util_win.cc | 2 +- docs/api/shell.md | 10 ++++++++-- 7 files changed, 33 insertions(+), 9 deletions(-) diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc index aaba1f31045b..33e90671aba8 100644 --- a/atom/browser/atom_resource_dispatcher_host_delegate.cc +++ b/atom/browser/atom_resource_dispatcher_host_delegate.cc @@ -26,7 +26,7 @@ bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol( bool has_user_gesture) { GURL escaped_url(net::EscapeExternalHandlerValue(url.spec())); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(base::IgnoreResult(platform_util::OpenExternal), escaped_url)); + base::Bind(base::IgnoreResult(platform_util::OpenExternal), escaped_url, false)); return true; } diff --git a/atom/common/api/atom_api_shell.cc b/atom/common/api/atom_api_shell.cc index a4599ee0c359..d479911fbe32 100644 --- a/atom/common/api/atom_api_shell.cc +++ b/atom/common/api/atom_api_shell.cc @@ -12,12 +12,22 @@ namespace { +bool OpenExternal(const GURL& url, mate::Arguments* args) { + bool without_activation = false; + if (args->Length() == 2) { + mate::Dictionary options; + args->GetNext(&options); + options.Get("withoutActivation", &without_activation); + } + return platform_util::OpenExternal(url, without_activation); +} + void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { mate::Dictionary dict(context->GetIsolate(), exports); dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder); dict.SetMethod("openItem", &platform_util::OpenItem); - dict.SetMethod("openExternal", &platform_util::OpenExternal); + dict.SetMethod("openExternal", &OpenExternal); dict.SetMethod("moveItemToTrash", &platform_util::MoveItemToTrash); dict.SetMethod("beep", &platform_util::Beep); } diff --git a/atom/common/platform_util.h b/atom/common/platform_util.h index 312942c4f5dc..3550c243bb68 100644 --- a/atom/common/platform_util.h +++ b/atom/common/platform_util.h @@ -23,7 +23,7 @@ void OpenItem(const base::FilePath& full_path); // Open the given external protocol URL in the desktop's default manner. // (For example, mailto: URLs in the default mail user agent.) -bool OpenExternal(const GURL& url); +bool OpenExternal(const GURL& url, const bool without_activation); // Move a file to trash. bool MoveItemToTrash(const base::FilePath& full_path); diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index aa7439968daa..fd4dcba6973b 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -64,7 +64,7 @@ void OpenItem(const base::FilePath& full_path) { XDGOpen(full_path.value()); } -bool OpenExternal(const GURL& url) { +bool OpenExternal(const GURL& url, const bool without_activation) { if (url.SchemeIs("mailto")) return XDGEmail(url.spec()); else diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index 7184593ae190..e84b3fbec307 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -119,7 +119,7 @@ void OpenItem(const base::FilePath& full_path) { } } -bool OpenExternal(const GURL& url) { +bool OpenExternal(const GURL& url, const bool without_activation) { DCHECK([NSThread isMainThread]); NSURL* ns_url = net::NSURLWithGURL(url); if (!ns_url) { @@ -136,7 +136,15 @@ bool OpenExternal(const GURL& url) { } CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us - return [[NSWorkspace sharedWorkspace] openURL:ns_url]; + NSUInteger launchOptions = NSWorkspaceLaunchDefault; + if (without_activation) + launchOptions = launchOptions | NSWorkspaceLaunchWithoutActivation; + + return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url] + withAppBundleIdentifier: nil + options: launchOptions + additionalEventParamDescriptor: NULL + launchIdentifiers: NULL]; } bool MoveItemToTrash(const base::FilePath& full_path) { diff --git a/atom/common/platform_util_win.cc b/atom/common/platform_util_win.cc index 4de5224668b6..76b71cb7f702 100644 --- a/atom/common/platform_util_win.cc +++ b/atom/common/platform_util_win.cc @@ -301,7 +301,7 @@ void OpenItem(const base::FilePath& full_path) { ui::win::OpenFileViaShell(full_path); } -bool OpenExternal(const GURL& url) { +bool OpenExternal(const GURL& url, const bool without_activation) { // Quote the input scheme to be sure that the command does not have // parameters unexpected by the external program. This url should already // have been escaped. diff --git a/docs/api/shell.md b/docs/api/shell.md index e6678a955364..a7f03a52f9c7 100644 --- a/docs/api/shell.md +++ b/docs/api/shell.md @@ -26,12 +26,18 @@ Show the given file in a file manager. If possible, select the file. Open the given file in the desktop's default manner. -### `shell.openExternal(url)` +### `shell.openExternal(url[, options])` * `url` String Open the given external protocol URL in the desktop's default manner. (For -example, mailto: URLs in the user's default mail agent.) +example, mailto: URLs in the user's default mail agent.) Returns true if an +application was available to open the URL, false otherwise. + +On Mac OS X, you can pass additional options to openExternal: + +- withoutActivation: Pass true to open the URL without bringing the + application into the foreground. ### `shell.moveItemToTrash(fullPath)` From 52db43eee55975ab1cbd4926beedbd4b037c2a38 Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Wed, 3 Feb 2016 11:35:01 -0800 Subject: [PATCH 2/8] Fix linter error --- atom/browser/atom_resource_dispatcher_host_delegate.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc index 33e90671aba8..0ed59b71be98 100644 --- a/atom/browser/atom_resource_dispatcher_host_delegate.cc +++ b/atom/browser/atom_resource_dispatcher_host_delegate.cc @@ -26,7 +26,8 @@ bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol( bool has_user_gesture) { GURL escaped_url(net::EscapeExternalHandlerValue(url.spec())); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(base::IgnoreResult(platform_util::OpenExternal), escaped_url, false)); + base::Bind( + base::IgnoreResult(platform_util::OpenExternal), escaped_url, false)); return true; } From f5bed87199732cfac34b4dfe5ddcc6072fd5b549 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 16 Feb 2016 15:55:37 -0800 Subject: [PATCH 3/8] without_activation -> activate --- atom/common/api/atom_api_shell.cc | 12 +----------- atom/common/api/lib/shell.js | 18 +++++++++++++++++- atom/common/platform_util.h | 2 +- atom/common/platform_util_linux.cc | 2 +- atom/common/platform_util_mac.mm | 6 +++--- atom/common/platform_util_win.cc | 2 +- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/atom/common/api/atom_api_shell.cc b/atom/common/api/atom_api_shell.cc index d479911fbe32..d0e795e87455 100644 --- a/atom/common/api/atom_api_shell.cc +++ b/atom/common/api/atom_api_shell.cc @@ -12,22 +12,12 @@ namespace { -bool OpenExternal(const GURL& url, mate::Arguments* args) { - bool without_activation = false; - if (args->Length() == 2) { - mate::Dictionary options; - args->GetNext(&options); - options.Get("withoutActivation", &without_activation); - } - return platform_util::OpenExternal(url, without_activation); -} - void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { mate::Dictionary dict(context->GetIsolate(), exports); dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder); dict.SetMethod("openItem", &platform_util::OpenItem); - dict.SetMethod("openExternal", &OpenExternal); + dict.SetMethod("_openExternal", &platform_util::OpenExternal); dict.SetMethod("moveItemToTrash", &platform_util::MoveItemToTrash); dict.SetMethod("beep", &platform_util::Beep); } diff --git a/atom/common/api/lib/shell.js b/atom/common/api/lib/shell.js index 08cc4e8eb41c..e032a7370762 100644 --- a/atom/common/api/lib/shell.js +++ b/atom/common/api/lib/shell.js @@ -1 +1,17 @@ -module.exports = process.atomBinding('shell'); +'use strict'; + +const bindings = process.atomBinding('shell'); + +exports.beep = bindings.beep; +exports.moveItemToTrash = bindings.moveItemToTrash; +exports.openItem = bindings.openItem; +exports.showItemInFolder = bindings.showItemInFolder; + +exports.openExternal = (url, options) => { + var activate = true; + if (options != null && options.activate != null) { + activate = !!options.activate; + } + + bindings._openExternal(url, activate); +} diff --git a/atom/common/platform_util.h b/atom/common/platform_util.h index 3550c243bb68..4565221e9d84 100644 --- a/atom/common/platform_util.h +++ b/atom/common/platform_util.h @@ -23,7 +23,7 @@ void OpenItem(const base::FilePath& full_path); // Open the given external protocol URL in the desktop's default manner. // (For example, mailto: URLs in the default mail user agent.) -bool OpenExternal(const GURL& url, const bool without_activation); +bool OpenExternal(const GURL& url, bool activate); // Move a file to trash. bool MoveItemToTrash(const base::FilePath& full_path); diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index fd4dcba6973b..1e437b866cc0 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -64,7 +64,7 @@ void OpenItem(const base::FilePath& full_path) { XDGOpen(full_path.value()); } -bool OpenExternal(const GURL& url, const bool without_activation) { +bool OpenExternal(const GURL& url, bool activate) { if (url.SchemeIs("mailto")) return XDGEmail(url.spec()); else diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index e84b3fbec307..98bc4e537d89 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -119,7 +119,7 @@ void OpenItem(const base::FilePath& full_path) { } } -bool OpenExternal(const GURL& url, const bool without_activation) { +bool OpenExternal(const GURL& url, bool activate) { DCHECK([NSThread isMainThread]); NSURL* ns_url = net::NSURLWithGURL(url); if (!ns_url) { @@ -137,8 +137,8 @@ bool OpenExternal(const GURL& url, const bool without_activation) { CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us NSUInteger launchOptions = NSWorkspaceLaunchDefault; - if (without_activation) - launchOptions = launchOptions | NSWorkspaceLaunchWithoutActivation; + if (!activate) + launchOptions |= NSWorkspaceLaunchWithoutActivation; return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url] withAppBundleIdentifier: nil diff --git a/atom/common/platform_util_win.cc b/atom/common/platform_util_win.cc index 76b71cb7f702..12591a94d569 100644 --- a/atom/common/platform_util_win.cc +++ b/atom/common/platform_util_win.cc @@ -301,7 +301,7 @@ void OpenItem(const base::FilePath& full_path) { ui::win::OpenFileViaShell(full_path); } -bool OpenExternal(const GURL& url, const bool without_activation) { +bool OpenExternal(const GURL& url, bool activate) { // Quote the input scheme to be sure that the command does not have // parameters unexpected by the external program. This url should already // have been escaped. From 42041cd40273851d694bff1da6abd67489cb53e9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 16 Feb 2016 15:58:33 -0800 Subject: [PATCH 4/8] Use markdown list for new options param --- docs/api/shell.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/api/shell.md b/docs/api/shell.md index a7f03a52f9c7..823dc481bb07 100644 --- a/docs/api/shell.md +++ b/docs/api/shell.md @@ -29,16 +29,14 @@ Open the given file in the desktop's default manner. ### `shell.openExternal(url[, options])` * `url` String +* `options` Object (optional) _OS X_ + * `activate` Boolean - `true` to bring the opened application to the + foreground. The default is `true`. Open the given external protocol URL in the desktop's default manner. (For example, mailto: URLs in the user's default mail agent.) Returns true if an application was available to open the URL, false otherwise. -On Mac OS X, you can pass additional options to openExternal: - -- withoutActivation: Pass true to open the URL without bringing the - application into the foreground. - ### `shell.moveItemToTrash(fullPath)` * `fullPath` String From 5e5313d8b1659f9fbdee5ff3cf6198c696928005 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 16 Feb 2016 16:02:41 -0800 Subject: [PATCH 5/8] Return value from bindings method --- atom/common/api/lib/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/common/api/lib/shell.js b/atom/common/api/lib/shell.js index e032a7370762..7caf8518395d 100644 --- a/atom/common/api/lib/shell.js +++ b/atom/common/api/lib/shell.js @@ -13,5 +13,5 @@ exports.openExternal = (url, options) => { activate = !!options.activate; } - bindings._openExternal(url, activate); + return bindings._openExternal(url, activate); } From 04517caf36265055505c6dbec085c34aa0e14b33 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 16 Feb 2016 16:08:36 -0800 Subject: [PATCH 6/8] Add missing semicolon --- atom/common/api/lib/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/common/api/lib/shell.js b/atom/common/api/lib/shell.js index 7caf8518395d..d62280277c53 100644 --- a/atom/common/api/lib/shell.js +++ b/atom/common/api/lib/shell.js @@ -14,4 +14,4 @@ exports.openExternal = (url, options) => { } return bindings._openExternal(url, activate); -} +}; From 3f42909ecfe46fc786cb7e9eb662bb7f6e255154 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 16 Feb 2016 16:09:30 -0800 Subject: [PATCH 7/8] Call OpenExternal with new true default to activate arg --- atom/browser/atom_resource_dispatcher_host_delegate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc index 0ed59b71be98..4d969786c19a 100644 --- a/atom/browser/atom_resource_dispatcher_host_delegate.cc +++ b/atom/browser/atom_resource_dispatcher_host_delegate.cc @@ -27,7 +27,7 @@ bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol( GURL escaped_url(net::EscapeExternalHandlerValue(url.spec())); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( - base::IgnoreResult(platform_util::OpenExternal), escaped_url, false)); + base::IgnoreResult(platform_util::OpenExternal), escaped_url, true)); return true; } From b3ac48cf52f0b36831fb8366fc16ecf2be287cf8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 17 Feb 2016 09:05:21 -0800 Subject: [PATCH 8/8] Handle argument parsing in C++ --- atom/common/api/atom_api_shell.cc | 13 ++++++++++++- atom/common/api/lib/shell.js | 18 +----------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/atom/common/api/atom_api_shell.cc b/atom/common/api/atom_api_shell.cc index d0e795e87455..f99e2ba1854e 100644 --- a/atom/common/api/atom_api_shell.cc +++ b/atom/common/api/atom_api_shell.cc @@ -12,12 +12,23 @@ namespace { +bool OpenExternal(const GURL& url, mate::Arguments* args) { + bool activate = true; + if (args->Length() == 2) { + mate::Dictionary options; + if (args->GetNext(&options)) { + options.Get("activate", &activate); + } + } + return platform_util::OpenExternal(url, activate); +} + void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { mate::Dictionary dict(context->GetIsolate(), exports); dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder); dict.SetMethod("openItem", &platform_util::OpenItem); - dict.SetMethod("_openExternal", &platform_util::OpenExternal); + dict.SetMethod("openExternal", &OpenExternal); dict.SetMethod("moveItemToTrash", &platform_util::MoveItemToTrash); dict.SetMethod("beep", &platform_util::Beep); } diff --git a/atom/common/api/lib/shell.js b/atom/common/api/lib/shell.js index d62280277c53..08cc4e8eb41c 100644 --- a/atom/common/api/lib/shell.js +++ b/atom/common/api/lib/shell.js @@ -1,17 +1 @@ -'use strict'; - -const bindings = process.atomBinding('shell'); - -exports.beep = bindings.beep; -exports.moveItemToTrash = bindings.moveItemToTrash; -exports.openItem = bindings.openItem; -exports.showItemInFolder = bindings.showItemInFolder; - -exports.openExternal = (url, options) => { - var activate = true; - if (options != null && options.activate != null) { - activate = !!options.activate; - } - - return bindings._openExternal(url, activate); -}; +module.exports = process.atomBinding('shell');