Shell openExternal can take optional callback (macOS)

This commit is contained in:
Gabriel Handford 2016-10-13 13:28:11 -07:00 committed by Cheng Zhao
parent 1b5b29901c
commit b266533dfc
6 changed files with 85 additions and 10 deletions

View file

@ -4,6 +4,7 @@
#include <string> #include <string>
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
@ -49,12 +50,22 @@ bool OpenExternal(
#endif #endif
mate::Arguments* args) { mate::Arguments* args) {
bool activate = true; bool activate = true;
if (args->Length() == 2) { if (args->Length() >= 2) {
mate::Dictionary options; mate::Dictionary options;
if (args->GetNext(&options)) { if (args->GetNext(&options)) {
options.Get("activate", &activate); options.Get("activate", &activate);
} }
} }
if (args->Length() >= 3) {
v8::Local<v8::Value> peek = args->PeekNext();
platform_util::OpenExternalCallback callback;
if (mate::Converter<platform_util::OpenExternalCallback>::FromV8(args->isolate(), peek, &callback)) {
return platform_util::OpenExternal(url, activate, callback);
}
return false;
}
return platform_util::OpenExternal(url, activate); return platform_util::OpenExternal(url, activate);
} }

View file

@ -6,6 +6,7 @@
#define ATOM_COMMON_PLATFORM_UTIL_H_ #define ATOM_COMMON_PLATFORM_UTIL_H_
#include "build/build_config.h" #include "build/build_config.h"
#include "base/callback_forward.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/strings/string16.h" #include "base/strings/string16.h"
@ -27,6 +28,8 @@ bool ShowItemInFolder(const base::FilePath& full_path);
// Must be called from the UI thread. // Must be called from the UI thread.
bool OpenItem(const base::FilePath& full_path); bool OpenItem(const base::FilePath& full_path);
typedef base::Callback<void(bool opened)> OpenExternalCallback;
// Open the given external protocol URL in the desktop's default manner. // Open the given external protocol URL in the desktop's default manner.
// (For example, mailto: URLs in the default mail user agent.) // (For example, mailto: URLs in the default mail user agent.)
bool OpenExternal( bool OpenExternal(
@ -37,6 +40,15 @@ bool OpenExternal(
#endif #endif
bool activate); bool activate);
bool OpenExternal(
#if defined(OS_WIN)
const base::string16& url,
#else
const GURL& url,
#endif
bool activate,
const OpenExternalCallback& callback);
// Move a file to trash. // Move a file to trash.
bool MoveItemToTrash(const base::FilePath& full_path); bool MoveItemToTrash(const base::FilePath& full_path);

View file

@ -79,7 +79,7 @@ bool OpenItem(const base::FilePath& full_path) {
return XDGOpen(full_path.value(), true); return XDGOpen(full_path.value(), true);
} }
bool OpenExternal(const GURL& url, bool activate) { bool openExternal(const GURL& url, bool activate) {
// Don't wait for exit, since we don't want to wait for the browser/email // Don't wait for exit, since we don't want to wait for the browser/email
// client window to close before returning // client window to close before returning
if (url.SchemeIs("mailto")) if (url.SchemeIs("mailto"))
@ -88,6 +88,17 @@ bool OpenExternal(const GURL& url, bool activate) {
return XDGOpen(url.spec(), false); return XDGOpen(url.spec(), false);
} }
bool OpenExternal(const GURL& url, bool activate) {
return openExternal(url, activate);
}
bool OpenExternal(const GURL& url, bool activate, const OpenExternalCallback& callback) {
// TODO: Implement async open if callback is specified
bool opened = openExternal(url, activate);
callback(opened);
return opened;
}
bool MoveItemToTrash(const base::FilePath& full_path) { bool MoveItemToTrash(const base::FilePath& full_path) {
std::string trash; std::string trash;
if (getenv(ELECTRON_TRASH) != NULL) { if (getenv(ELECTRON_TRASH) != NULL) {

View file

@ -7,6 +7,7 @@
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "base/cancelable_callback.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/logging.h" #include "base/logging.h"
@ -128,7 +129,17 @@ bool OpenItem(const base::FilePath& full_path) {
return status == noErr; return status == noErr;
} }
bool OpenExternal(const GURL& url, bool activate) { bool openURLInWorkspace(NSURL* ns_url, NSUInteger launchOptions) {
return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url]
withAppBundleIdentifier: nil
options: launchOptions
additionalEventParamDescriptor: NULL
launchIdentifiers: NULL];
}
typedef bool(^OpenExternalBlock)(NSURL* ns_url, NSUInteger launchOptions);
bool openExternal(const GURL& url, bool activate, OpenExternalBlock open) {
DCHECK([NSThread isMainThread]); DCHECK([NSThread isMainThread]);
NSURL* ns_url = net::NSURLWithGURL(url); NSURL* ns_url = net::NSURLWithGURL(url);
if (!ns_url) { if (!ns_url) {
@ -149,11 +160,26 @@ bool OpenExternal(const GURL& url, bool activate) {
if (!activate) if (!activate)
launchOptions |= NSWorkspaceLaunchWithoutActivation; launchOptions |= NSWorkspaceLaunchWithoutActivation;
return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url] return open(ns_url, launchOptions);
withAppBundleIdentifier: nil }
options: launchOptions
additionalEventParamDescriptor: NULL bool OpenExternal(const GURL& url, bool activate) {
launchIdentifiers: NULL]; return openExternal(url, activate, ^bool(NSURL* ns_url, NSUInteger launchOptions) {
return openURLInWorkspace(ns_url, launchOptions);
});
}
bool OpenExternal(const GURL& url, bool activate, const OpenExternalCallback& c) {
__block OpenExternalCallback callback = c;
return openExternal(url, activate, ^bool(NSURL* ns_url, NSUInteger launchOptions) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
bool opened = openURLInWorkspace(ns_url, launchOptions);
dispatch_async(dispatch_get_main_queue(), ^{
callback.Run(opened);
});
});
return YES;
});
} }
bool MoveItemToTrash(const base::FilePath& full_path) { bool MoveItemToTrash(const base::FilePath& full_path) {

View file

@ -299,7 +299,7 @@ bool OpenItem(const base::FilePath& full_path) {
return ui::win::OpenFileViaShell(full_path); return ui::win::OpenFileViaShell(full_path);
} }
bool OpenExternal(const base::string16& url, bool activate) { bool openExternal(const base::string16& url, bool activate) {
// Quote the input scheme to be sure that the command does not have // Quote the input scheme to be sure that the command does not have
// parameters unexpected by the external program. This url should already // parameters unexpected by the external program. This url should already
// have been escaped. // have been escaped.
@ -316,6 +316,17 @@ bool OpenExternal(const base::string16& url, bool activate) {
return true; return true;
} }
bool OpenExternal(const base::string16& url, bool activate) {
return openExternal(url, activate);
}
bool OpenExternal(const base::string16& url, bool activate, const OpenExternalCallback& callback) {
// TODO: Implement async open if callback is specified
bool opened = openExternal(url, activate)
callback(opened);
return opened;
}
bool MoveItemToTrash(const base::FilePath& path) { bool MoveItemToTrash(const base::FilePath& path) {
base::win::ScopedCOMInitializer com_initializer; base::win::ScopedCOMInitializer com_initializer;
if (!com_initializer.succeeded()) if (!com_initializer.succeeded())

View file

@ -34,18 +34,22 @@ Returns `Boolean` - Whether the item was successfully opened.
Open the given file in the desktop's default manner. Open the given file in the desktop's default manner.
### `shell.openExternal(url[, options])` ### `shell.openExternal(url[, options, callback])`
* `url` String * `url` String
* `options` Object (optional) _macOS_ * `options` Object (optional) _macOS_
* `activate` Boolean - `true` to bring the opened application to the * `activate` Boolean - `true` to bring the opened application to the
foreground. The default is `true`. foreground. The default is `true`.
* `callback` Function (optional) _macOS_
Returns `Boolean` - Whether an application was available to open the URL. Returns `Boolean` - Whether an application was available to open the URL.
Open the given external protocol URL in the desktop's default manner. (For 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).
If a `callback` is passed, the API call will be asynchronous and the result
will be passed via `callback(opened)`.
### `shell.moveItemToTrash(fullPath)` ### `shell.moveItemToTrash(fullPath)`
* `fullPath` String * `fullPath` String