Merge branch 'gabriel-master'

This commit is contained in:
Cheng Zhao 2016-11-17 12:15:38 +09:00
commit eb63bea87c
6 changed files with 156 additions and 23 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"
@ -41,6 +42,16 @@ struct Converter<base::win::ShortcutOperation> {
namespace { namespace {
void OnOpenExternalFinished(
v8::Isolate* isolate,
const base::Callback<void(v8::Local<v8::Value>)>& callback,
const std::string& error) {
if (error.empty())
callback.Run(v8::Null(isolate));
else
callback.Run(v8::String::NewFromUtf8(isolate, error.c_str()));
}
bool OpenExternal( bool OpenExternal(
#if defined(OS_WIN) #if defined(OS_WIN)
const base::string16& url, const base::string16& url,
@ -49,12 +60,23 @@ 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) {
base::Callback<void(v8::Local<v8::Value>)> callback;
if (args->GetNext(&callback)) {
platform_util::OpenExternal(
url, activate,
base::Bind(&OnOpenExternalFinished, args->isolate(), callback));
return true;
}
}
return platform_util::OpenExternal(url, activate); return platform_util::OpenExternal(url, activate);
} }

View file

@ -5,6 +5,9 @@
#ifndef ATOM_COMMON_PLATFORM_UTIL_H_ #ifndef ATOM_COMMON_PLATFORM_UTIL_H_
#define ATOM_COMMON_PLATFORM_UTIL_H_ #define ATOM_COMMON_PLATFORM_UTIL_H_
#include <string>
#include "base/callback_forward.h"
#include "build/build_config.h" #include "build/build_config.h"
#if defined(OS_WIN) #if defined(OS_WIN)
@ -19,6 +22,8 @@ class FilePath;
namespace platform_util { namespace platform_util {
typedef base::Callback<void(const std::string&)> OpenExternalCallback;
// Show the given file in a file manager. If possible, select the file. // Show the given file in a file manager. If possible, select the file.
// Must be called from the UI thread. // Must be called from the UI thread.
bool ShowItemInFolder(const base::FilePath& full_path); bool ShowItemInFolder(const base::FilePath& full_path);
@ -37,6 +42,16 @@ bool OpenExternal(
#endif #endif
bool activate); bool activate);
// The asynchronous version of OpenExternal.
void 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

@ -6,6 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include "base/cancelable_callback.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/process/kill.h" #include "base/process/kill.h"
#include "base/process/launch.h" #include "base/process/launch.h"
@ -88,6 +89,12 @@ bool OpenExternal(const GURL& url, bool activate) {
return XDGOpen(url.spec(), false); return XDGOpen(url.spec(), false);
} }
void OpenExternal(const GURL& url, bool activate,
const OpenExternalCallback& callback) {
// TODO(gabriel): Implement async open if callback is specified
callback.Run(OpenExternal(url, activate) ? "" : "Failed to open");
}
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

@ -4,18 +4,101 @@
#include "atom/common/platform_util.h" #include "atom/common/platform_util.h"
#include <Carbon/Carbon.h> #import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "base/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"
#include "base/mac/mac_logging.h" #include "base/mac/mac_logging.h"
#include "base/mac/scoped_aedesc.h" #include "base/mac/scoped_aedesc.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "net/base/mac/url_conversions.h" #include "net/base/mac/url_conversions.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace {
std::string MessageForOSStatus(OSStatus status, const char* default_message) {
switch (status) {
case kLSAppInTrashErr:
return "The application cannot be run because it is inside a Trash "
"folder.";
case kLSUnknownErr:
return "An unknown error has occurred.";
case kLSNotAnApplicationErr:
return "The item to be registered is not an application.";
case kLSNotInitializedErr:
return "Formerly returned by LSInit on initialization failure; "
"no longer used.";
case kLSDataUnavailableErr:
return "Data of the desired type is not available (for example, there is "
"no kind string).";
case kLSApplicationNotFoundErr:
return "No application in the Launch Services database matches the input "
"criteria.";
case kLSDataErr:
return "Data is structured improperly (for example, an items "
"information property list is malformed). Not used in macOS 10.4.";
case kLSLaunchInProgressErr:
return "A launch of the application is already in progress.";
case kLSServerCommunicationErr:
return "There is a problem communicating with the server process that "
"maintains the Launch Services database.";
case kLSCannotSetInfoErr:
return "The filename extension to be hidden cannot be hidden.";
case kLSIncompatibleSystemVersionErr:
return "The application to be launched cannot run on the current Mac OS "
"version.";
case kLSNoLaunchPermissionErr:
return "The user does not have permission to launch the application (on a"
"managed network).";
case kLSNoExecutableErr:
return "The executable file is missing or has an unusable format.";
case kLSNoClassicEnvironmentErr:
return "The Classic emulation environment was required but is not "
"available.";
case kLSMultipleSessionsNotSupportedErr:
return "The application to be launched cannot run simultaneously in two "
"different user sessions.";
default:
return base::StringPrintf("%s (%d)", default_message, status);
}
}
// This may be called from a global dispatch queue, the methods used here are
// thread safe, including LSGetApplicationForURL (> 10.2) and
// NSWorkspace#openURLs.
std::string OpenURL(NSURL* ns_url, bool activate) {
CFURLRef openingApp = NULL;
OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url,
kLSRolesAll,
NULL,
&openingApp);
if (status != noErr)
return MessageForOSStatus(status, "Failed to open");
CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us
NSUInteger launchOptions = NSWorkspaceLaunchDefault;
if (!activate)
launchOptions |= NSWorkspaceLaunchWithoutActivation;
bool opened = [[NSWorkspace sharedWorkspace]
openURLs:@[ns_url]
withAppBundleIdentifier:nil
options:launchOptions
additionalEventParamDescriptor:nil
launchIdentifiers:nil];
if (!opened)
return "Failed to open URL";
return "";
}
} // namespace
namespace platform_util { namespace platform_util {
bool ShowItemInFolder(const base::FilePath& path) { bool ShowItemInFolder(const base::FilePath& path) {
@ -131,29 +214,26 @@ bool OpenItem(const base::FilePath& full_path) {
bool OpenExternal(const GURL& url, bool activate) { bool OpenExternal(const GURL& url, bool activate) {
DCHECK([NSThread isMainThread]); DCHECK([NSThread isMainThread]);
NSURL* ns_url = net::NSURLWithGURL(url); NSURL* ns_url = net::NSURLWithGURL(url);
if (ns_url)
return OpenURL(ns_url, activate).empty();
return false;
}
void OpenExternal(const GURL& url, bool activate,
const OpenExternalCallback& callback) {
NSURL* ns_url = net::NSURLWithGURL(url);
if (!ns_url) { if (!ns_url) {
return false; callback.Run("Invalid URL");
return;
} }
CFURLRef openingApp = NULL; __block OpenExternalCallback c = callback;
OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
kLSRolesAll, __block std::string error = OpenURL(ns_url, activate);
NULL, dispatch_async(dispatch_get_main_queue(), ^{
&openingApp); c.Run(error);
if (status != noErr) { });
return false; });
}
CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us
NSUInteger launchOptions = NSWorkspaceLaunchDefault;
if (!activate)
launchOptions |= NSWorkspaceLaunchWithoutActivation;
return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url]
withAppBundleIdentifier: nil
options: launchOptions
additionalEventParamDescriptor: NULL
launchIdentifiers: NULL];
} }
bool MoveItemToTrash(const base::FilePath& full_path) { bool MoveItemToTrash(const base::FilePath& full_path) {

View file

@ -316,6 +316,12 @@ bool OpenExternal(const base::string16& url, bool activate) {
return true; return true;
} }
void OpenExternal(const base::string16& url, bool activate,
const OpenExternalCallback& callback) {
// TODO(gabriel): Implement async open if callback is specified
callback.Run(OpenExternal(url, activate) ? "" : "Failed to open");
}
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,14 +34,17 @@ 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) - If specified will perform the open asynchronously. _macOS_
* `error` Error
Returns `Boolean` - Whether an application was available to open the URL. Returns `Boolean` - Whether an application was available to open the URL.
If callback is specified, always returns true.
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).