Shell openExternal can take optional callback (macOS)
authorGabriel Handford <gabrielh@gmail.com>
Thu, 13 Oct 2016 20:28:11 +0000 (13:28 -0700)
committerCheng Zhao <zcbenz@gmail.com>
Thu, 17 Nov 2016 01:33:23 +0000 (10:33 +0900)
atom/common/api/atom_api_shell.cc
atom/common/platform_util.h
atom/common/platform_util_linux.cc
atom/common/platform_util_mac.mm
atom/common/platform_util_win.cc
docs/api/shell.md

index 03e8ed3..0521453 100644 (file)
@@ -4,6 +4,7 @@
 
 #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/gurl_converter.h"
 #include "atom/common/native_mate_converters/string16_converter.h"
@@ -49,12 +50,22 @@ bool OpenExternal(
 #endif
     mate::Arguments* args) {
   bool activate = true;
-  if (args->Length() == 2) {
+  if (args->Length() >= 2) {
     mate::Dictionary options;
     if (args->GetNext(&options)) {
       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);
 }
 
index 520faa4..8f2c5b6 100644 (file)
@@ -6,6 +6,7 @@
 #define ATOM_COMMON_PLATFORM_UTIL_H_
 
 #include "build/build_config.h"
+#include "base/callback_forward.h"
 
 #if defined(OS_WIN)
 #include "base/strings/string16.h"
@@ -27,6 +28,8 @@ bool ShowItemInFolder(const base::FilePath& full_path);
 // Must be called from the UI thread.
 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.
 // (For example, mailto: URLs in the default mail user agent.)
 bool OpenExternal(
@@ -37,6 +40,15 @@ bool OpenExternal(
 #endif
     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.
 bool MoveItemToTrash(const base::FilePath& full_path);
 
index 8226590..8cfa516 100644 (file)
@@ -79,7 +79,7 @@ bool OpenItem(const base::FilePath& full_path) {
   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
   // client window to close before returning
   if (url.SchemeIs("mailto"))
@@ -88,6 +88,17 @@ bool OpenExternal(const GURL& url, bool activate) {
     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) {
   std::string trash;
   if (getenv(ELECTRON_TRASH) != NULL) {
index 6d253c9..3f6c347 100644 (file)
@@ -7,6 +7,7 @@
 #include <Carbon/Carbon.h>
 #import <Cocoa/Cocoa.h>
 
+#include "base/cancelable_callback.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -128,7 +129,17 @@ bool OpenItem(const base::FilePath& full_path) {
   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]);
   NSURL* ns_url = net::NSURLWithGURL(url);
   if (!ns_url) {
@@ -149,11 +160,26 @@ bool OpenExternal(const GURL& url, bool activate) {
   if (!activate)
     launchOptions |= NSWorkspaceLaunchWithoutActivation;
 
-  return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url]
-                                        withAppBundleIdentifier: nil
-                                        options: launchOptions
-                                        additionalEventParamDescriptor: NULL
-                                        launchIdentifiers: NULL];
+  return open(ns_url, launchOptions);
+}
+
+bool OpenExternal(const GURL& url, bool activate) {
+  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) {
index 2c98115..5483c78 100644 (file)
@@ -299,7 +299,7 @@ bool OpenItem(const base::FilePath& 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
   // parameters unexpected by the external program. This url should already
   // have been escaped.
@@ -316,6 +316,17 @@ bool OpenExternal(const base::string16& url, bool activate) {
   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) {
   base::win::ScopedCOMInitializer com_initializer;
   if (!com_initializer.succeeded())
index 89ae954..d96df89 100644 (file)
@@ -34,18 +34,22 @@ Returns `Boolean` - Whether the item was successfully opened.
 
 Open the given file in the desktop's default manner.
 
-### `shell.openExternal(url[, options])`
+### `shell.openExternal(url[, options, callback])`
 
 * `url` String
 * `options` Object (optional) _macOS_
   * `activate` Boolean - `true` to bring the opened application to the
     foreground. The default is `true`.
+* `callback` Function (optional) _macOS_
 
 Returns `Boolean` - Whether an application was available to open the URL.
 
 Open the given external protocol URL in the desktop's default manner. (For
 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)`
 
 * `fullPath` String