This commit is contained in:
eaton11 2015-06-10 19:28:14 -06:00
commit d367af3fa4
40 changed files with 283 additions and 171 deletions

View file

@ -41,8 +41,9 @@ void PowerMonitor::OnResume() {
// static // static
v8::Local<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) { v8::Local<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
if (!Browser::Get()->is_ready()) { if (!Browser::Get()->is_ready()) {
node::ThrowError("Cannot initialize \"power-monitor\" module" node::ThrowError(
"before app is ready"); isolate,
"Cannot initialize \"power-monitor\" module before app is ready");
return v8::Null(isolate); return v8::Null(isolate);
} }

View file

@ -192,28 +192,19 @@ Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder( mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
v8::Isolate* isolate) { v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate) return mate::ObjectTemplateBuilder(isolate)
.SetMethod("registerProtocol", .SetMethod("registerProtocol", &Protocol::RegisterProtocol)
base::Bind(&Protocol::RegisterProtocol, .SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
base::Unretained(this))) .SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol)
.SetMethod("unregisterProtocol", .SetMethod("interceptProtocol", &Protocol::InterceptProtocol)
base::Bind(&Protocol::UnregisterProtocol, .SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
base::Unretained(this)))
.SetMethod("isHandledProtocol",
base::Bind(&Protocol::IsHandledProtocol,
base::Unretained(this)))
.SetMethod("interceptProtocol",
base::Bind(&Protocol::InterceptProtocol,
base::Unretained(this)))
.SetMethod("uninterceptProtocol",
base::Bind(&Protocol::UninterceptProtocol,
base::Unretained(this)));
} }
void Protocol::RegisterProtocol(const std::string& scheme, void Protocol::RegisterProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback) { const JsProtocolHandler& callback) {
if (ContainsKey(protocol_handlers_, scheme) || if (ContainsKey(protocol_handlers_, scheme) ||
job_factory_->IsHandledProtocol(scheme)) job_factory_->IsHandledProtocol(scheme))
return node::ThrowError("The scheme is already registered"); return node::ThrowError(isolate, "The scheme is already registered");
protocol_handlers_[scheme] = callback; protocol_handlers_[scheme] = callback;
BrowserThread::PostTask(BrowserThread::IO, BrowserThread::PostTask(BrowserThread::IO,
@ -222,10 +213,11 @@ void Protocol::RegisterProtocol(const std::string& scheme,
base::Unretained(this), scheme)); base::Unretained(this), scheme));
} }
void Protocol::UnregisterProtocol(const std::string& scheme) { void Protocol::UnregisterProtocol(v8::Isolate* isolate,
const std::string& scheme) {
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme)); ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
if (it == protocol_handlers_.end()) if (it == protocol_handlers_.end())
return node::ThrowError("The scheme has not been registered"); return node::ThrowError(isolate, "The scheme has not been registered");
protocol_handlers_.erase(it); protocol_handlers_.erase(it);
BrowserThread::PostTask(BrowserThread::IO, BrowserThread::PostTask(BrowserThread::IO,
@ -238,13 +230,14 @@ bool Protocol::IsHandledProtocol(const std::string& scheme) {
return job_factory_->IsHandledProtocol(scheme); return job_factory_->IsHandledProtocol(scheme);
} }
void Protocol::InterceptProtocol(const std::string& scheme, void Protocol::InterceptProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback) { const JsProtocolHandler& callback) {
if (!job_factory_->HasProtocolHandler(scheme)) if (!job_factory_->HasProtocolHandler(scheme))
return node::ThrowError("Scheme does not exist."); return node::ThrowError(isolate, "Scheme does not exist.");
if (ContainsKey(protocol_handlers_, scheme)) if (ContainsKey(protocol_handlers_, scheme))
return node::ThrowError("Cannot intercept custom procotols"); return node::ThrowError(isolate, "Cannot intercept custom procotols");
protocol_handlers_[scheme] = callback; protocol_handlers_[scheme] = callback;
BrowserThread::PostTask(BrowserThread::IO, BrowserThread::PostTask(BrowserThread::IO,
@ -253,10 +246,11 @@ void Protocol::InterceptProtocol(const std::string& scheme,
base::Unretained(this), scheme)); base::Unretained(this), scheme));
} }
void Protocol::UninterceptProtocol(const std::string& scheme) { void Protocol::UninterceptProtocol(v8::Isolate* isolate,
const std::string& scheme) {
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme)); ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
if (it == protocol_handlers_.end()) if (it == protocol_handlers_.end())
return node::ThrowError("The scheme has not been registered"); return node::ThrowError(isolate, "The scheme has not been registered");
protocol_handlers_.erase(it); protocol_handlers_.erase(it);
BrowserThread::PostTask(BrowserThread::IO, BrowserThread::PostTask(BrowserThread::IO,

View file

@ -43,9 +43,10 @@ class Protocol : public mate::EventEmitter {
// Register/unregister an networking |scheme| which would be handled by // Register/unregister an networking |scheme| which would be handled by
// |callback|. // |callback|.
void RegisterProtocol(const std::string& scheme, void RegisterProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback); const JsProtocolHandler& callback);
void UnregisterProtocol(const std::string& scheme); void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme);
// Returns whether a scheme has been registered. // Returns whether a scheme has been registered.
// FIXME Should accept a callback and be asynchronous so we do not have to use // FIXME Should accept a callback and be asynchronous so we do not have to use
@ -53,9 +54,10 @@ class Protocol : public mate::EventEmitter {
bool IsHandledProtocol(const std::string& scheme); bool IsHandledProtocol(const std::string& scheme);
// Intercept/unintercept an existing protocol handler. // Intercept/unintercept an existing protocol handler.
void InterceptProtocol(const std::string& scheme, void InterceptProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback); const JsProtocolHandler& callback);
void UninterceptProtocol(const std::string& scheme); void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme);
// The networking related operations have to be done in IO thread. // The networking related operations have to be done in IO thread.
void RegisterProtocolInIO(const std::string& scheme); void RegisterProtocolInIO(const std::string& scheme);

View file

@ -113,13 +113,14 @@ mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
// static // static
v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) { v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) {
if (!Browser::Get()->is_ready()) { if (!Browser::Get()->is_ready()) {
node::ThrowError("Cannot initialize \"screen\" module before app is ready"); node::ThrowError(isolate,
"Cannot initialize \"screen\" module before app is ready");
return v8::Null(isolate); return v8::Null(isolate);
} }
gfx::Screen* screen = gfx::Screen::GetNativeScreen(); gfx::Screen* screen = gfx::Screen::GetNativeScreen();
if (!screen) { if (!screen) {
node::ThrowError("Failed to get screen information"); node::ThrowError(isolate, "Failed to get screen information");
return v8::Null(isolate); return v8::Null(isolate);
} }

View file

@ -32,9 +32,9 @@ Tray::~Tray() {
} }
// static // static
mate::Wrappable* Tray::New(const gfx::Image& image) { mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
if (!Browser::Get()->is_ready()) { if (!Browser::Get()->is_ready()) {
node::ThrowError("Cannot create Tray before app is ready"); node::ThrowError(isolate, "Cannot create Tray before app is ready");
return nullptr; return nullptr;
} }
return new Tray(image); return new Tray(image);

View file

@ -31,7 +31,7 @@ class Menu;
class Tray : public mate::EventEmitter, class Tray : public mate::EventEmitter,
public TrayIconObserver { public TrayIconObserver {
public: public:
static mate::Wrappable* New(const gfx::Image& image); static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image);
static void BuildPrototype(v8::Isolate* isolate, static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype); v8::Local<v8::ObjectTemplate> prototype);

View file

@ -189,7 +189,8 @@ void Window::OnDevToolsClosed() {
mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Wrappable* Window::New(v8::Isolate* isolate,
const mate::Dictionary& options) { const mate::Dictionary& options) {
if (!Browser::Get()->is_ready()) { if (!Browser::Get()->is_ready()) {
node::ThrowError("Cannot create BrowserWindow before app is ready"); node::ThrowError(isolate,
"Cannot create BrowserWindow before app is ready");
return nullptr; return nullptr;
} }
return new Window(options); return new Window(options);

View file

@ -14,16 +14,20 @@
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "atom/common/options_switches.h" #include "atom/common/options_switches.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "chrome/browser/printing/printing_message_filter.h" #include "chrome/browser/printing/printing_message_filter.h"
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
#include "chrome/browser/speech/tts_message_filter.h" #include "chrome/browser/speech/tts_message_filter.h"
#include "content/public/browser/browser_ppapi_host.h" #include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h" #include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h" #include "content/public/common/web_preferences.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "ppapi/host/ppapi_host.h" #include "ppapi/host/ppapi_host.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
@ -67,6 +71,23 @@ ProcessOwner GetProcessOwner(int process_id,
return OWNER_NONE; return OWNER_NONE;
} }
scoped_refptr<net::X509Certificate> ImportCertFromFile(
const base::FilePath& path) {
std::string cert_data;
if (!base::ReadFileToString(path, &cert_data))
return nullptr;
net::CertificateList certs =
net::X509Certificate::CreateCertificateListFromBytes(
cert_data.data(), cert_data.size(),
net::X509Certificate::FORMAT_AUTO);
if (certs.empty())
return nullptr;
return certs[0];
}
} // namespace } // namespace
// static // static
@ -189,6 +210,29 @@ content::QuotaPermissionContext*
return new AtomQuotaPermissionContext; return new AtomQuotaPermissionContext;
} }
void AtomBrowserClient::SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {
auto command_line = base::CommandLine::ForCurrentProcess();
auto cert_path = command_line->GetSwitchValueNative(
switches::kClientCertificate);
// TODO(zcbenz): allow users to select certificate from
// client_cert list. Right now defaults to first certificate
// in the list.
scoped_refptr<net::X509Certificate> certificate;
if (cert_path.empty()) {
if (!cert_request_info->client_certs.empty())
certificate = cert_request_info->client_certs[0];
} else {
certificate = ImportCertFromFile(base::FilePath(cert_path));
}
if (certificate.get())
delegate->ContinueWithCertificate(certificate.get());
}
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts( brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) { const content::MainFunctionParams&) {
v8::V8::Initialize(); // Init V8 before creating main parts. v8::V8::Initialize(); // Init V8 before creating main parts.

View file

@ -11,6 +11,11 @@
namespace content { namespace content {
class QuotaPermissionContext; class QuotaPermissionContext;
class ClientCertificateDelegate;
}
namespace net {
class SSLCertRequestInfo;
} }
namespace atom { namespace atom {
@ -41,6 +46,10 @@ class AtomBrowserClient : public brightray::BrowserClient {
int child_process_id) override; int child_process_id) override;
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override; void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
content::QuotaPermissionContext* CreateQuotaPermissionContext() override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
void SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
private: private:
brightray::BrowserMainParts* OverrideCreateBrowserMainParts( brightray::BrowserMainParts* OverrideCreateBrowserMainParts(

View file

@ -7,6 +7,7 @@ v8Util = process.atomBinding 'v8_util'
valueToMeta = (sender, value) -> valueToMeta = (sender, value) ->
meta = type: typeof value meta = type: typeof value
meta.type = 'buffer' if Buffer.isBuffer value
meta.type = 'value' if value is null meta.type = 'value' if value is null
meta.type = 'array' if Array.isArray value meta.type = 'array' if Array.isArray value
@ -26,6 +27,8 @@ valueToMeta = (sender, value) ->
meta.members = [] meta.members = []
meta.members.push {name: prop, type: typeof field} for prop, field of value meta.members.push {name: prop, type: typeof field} for prop, field of value
else if meta.type is 'buffer'
meta.value = Array::slice.call value, 0
else else
meta.type = 'value' meta.type = 'value'
meta.value = value meta.value = value
@ -43,6 +46,7 @@ unwrapArgs = (sender, args) ->
when 'value' then meta.value when 'value' then meta.value
when 'remote-object' then objectsRegistry.get meta.id when 'remote-object' then objectsRegistry.get meta.id
when 'array' then unwrapArgs sender, meta.value when 'array' then unwrapArgs sender, meta.value
when 'buffer' then new Buffer(meta.value)
when 'object' when 'object'
ret = v8Util.createObjectWithName meta.name ret = v8Util.createObjectWithName meta.name
for member in meta.members for member in meta.members

View file

@ -7,6 +7,7 @@
#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/arguments.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard.h"
@ -15,44 +16,32 @@
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
namespace mate {
template<>
struct Converter<ui::ClipboardType> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
ui::ClipboardType* out) {
std::string type;
if (!Converter<std::string>::FromV8(isolate, val, &type))
return false;
if (type == "selection")
*out = ui::CLIPBOARD_TYPE_SELECTION;
else
*out = ui::CLIPBOARD_TYPE_COPY_PASTE;
return true;
}
};
} // namespace mate
namespace { namespace {
std::vector<base::string16> AvailableFormats(ui::ClipboardType type) { ui::ClipboardType GetClipboardType(mate::Arguments* args) {
std::string type;
if (args->GetNext(&type) && type == "selection")
return ui::CLIPBOARD_TYPE_SELECTION;
else
return ui::CLIPBOARD_TYPE_COPY_PASTE;
}
std::vector<base::string16> AvailableFormats(mate::Arguments* args) {
std::vector<base::string16> format_types; std::vector<base::string16> format_types;
bool ignore; bool ignore;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
clipboard->ReadAvailableTypes(type, &format_types, &ignore); clipboard->ReadAvailableTypes(GetClipboardType(args), &format_types, &ignore);
return format_types; return format_types;
} }
bool Has(const std::string& format_string, ui::ClipboardType type) { bool Has(const std::string& format_string, mate::Arguments* args) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string)); ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string));
return clipboard->IsFormatAvailable(format, type); return clipboard->IsFormatAvailable(format, GetClipboardType(args));
} }
std::string Read(const std::string& format_string, std::string Read(const std::string& format_string,
ui::ClipboardType type) { mate::Arguments* args) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string)); ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string));
@ -61,62 +50,62 @@ std::string Read(const std::string& format_string,
return data; return data;
} }
base::string16 ReadText(ui::ClipboardType type) { base::string16 ReadText(mate::Arguments* args) {
base::string16 data; base::string16 data;
ui::Clipboard::GetForCurrentThread()->ReadText(type, &data); ui::Clipboard::GetForCurrentThread()->ReadText(GetClipboardType(args), &data);
return data; return data;
} }
void WriteText(const base::string16& text, ui::ClipboardType type) { void WriteText(const base::string16& text, mate::Arguments* args) {
ui::ScopedClipboardWriter writer(type); ui::ScopedClipboardWriter writer(GetClipboardType(args));
writer.WriteText(text); writer.WriteText(text);
} }
base::string16 ReadHtml(ui::ClipboardType type) { base::string16 ReadHtml(mate::Arguments* args) {
base::string16 data; base::string16 data;
base::string16 html; base::string16 html;
std::string url; std::string url;
uint32 start; uint32 start;
uint32 end; uint32 end;
ui::Clipboard::GetForCurrentThread()->ReadHTML(type, &html, &url, ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
&start, &end); clipboard->ReadHTML(GetClipboardType(args), &html, &url, &start, &end);
data = html.substr(start, end - start); data = html.substr(start, end - start);
return data; return data;
} }
void WriteHtml(const base::string16& html, void WriteHtml(const base::string16& html, mate::Arguments* args) {
ui::ClipboardType type) { ui::ScopedClipboardWriter writer(GetClipboardType(args));
ui::ScopedClipboardWriter writer(type);
writer.WriteHTML(html, std::string()); writer.WriteHTML(html, std::string());
} }
gfx::Image ReadImage(ui::ClipboardType type) { gfx::Image ReadImage(mate::Arguments* args) {
SkBitmap bitmap = ui::Clipboard::GetForCurrentThread()->ReadImage(type); ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
SkBitmap bitmap = clipboard->ReadImage(GetClipboardType(args));
return gfx::Image::CreateFrom1xBitmap(bitmap); return gfx::Image::CreateFrom1xBitmap(bitmap);
} }
void WriteImage(const gfx::Image& image, ui::ClipboardType type) { void WriteImage(const gfx::Image& image, mate::Arguments* args) {
ui::ScopedClipboardWriter writer(type); ui::ScopedClipboardWriter writer(GetClipboardType(args));
writer.WriteImage(image.AsBitmap()); writer.WriteImage(image.AsBitmap());
} }
void Clear(ui::ClipboardType type) { void Clear(mate::Arguments* args) {
ui::Clipboard::GetForCurrentThread()->Clear(type); ui::Clipboard::GetForCurrentThread()->Clear(GetClipboardType(args));
} }
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused, void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) { v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports); mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("_availableFormats", &AvailableFormats); dict.SetMethod("availableFormats", &AvailableFormats);
dict.SetMethod("_has", &Has); dict.SetMethod("has", &Has);
dict.SetMethod("_read", &Read); dict.SetMethod("read", &Read);
dict.SetMethod("_readText", &ReadText); dict.SetMethod("readText", &ReadText);
dict.SetMethod("_writeText", &WriteText); dict.SetMethod("writeText", &WriteText);
dict.SetMethod("_readHtml", &ReadHtml); dict.SetMethod("readHtml", &ReadHtml);
dict.SetMethod("_writeHtml", &WriteHtml); dict.SetMethod("writeHtml", &WriteHtml);
dict.SetMethod("_readImage", &ReadImage); dict.SetMethod("readImage", &ReadImage);
dict.SetMethod("_writeImage", &WriteImage); dict.SetMethod("writeImage", &WriteImage);
dict.SetMethod("_clear", &Clear); dict.SetMethod("clear", &Clear);
} }
} // namespace } // namespace

View file

@ -35,7 +35,7 @@ int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local<v8::Object> object) {
v8::Local<v8::Value> IDWeakMap::Get(v8::Isolate* isolate, int32_t key) { v8::Local<v8::Value> IDWeakMap::Get(v8::Isolate* isolate, int32_t key) {
if (!Has(key)) { if (!Has(key)) {
node::ThrowError("Invalid key"); node::ThrowError(isolate, "Invalid key");
return v8::Undefined(isolate); return v8::Undefined(isolate);
} }

View file

@ -1,12 +1,5 @@
binding = process.atomBinding 'clipboard' if process.platform is 'linux' and process.type is 'renderer'
module.exports = # On Linux we could not access clipboard in renderer process.
availableFormats: (type='standard') -> binding._availableFormats type module.exports = require('remote').require 'clipboard'
has: (format, type='standard') -> binding._has format, type else
read: (format, type='standard') -> binding._read format, type module.exports = process.atomBinding 'clipboard'
readText: (type='standard') -> binding._readText type
writeText: (text, type='standard') -> binding._writeText text, type
readHtml: (type='standard') -> binding._readHtml type
writeHtml: (markup, type='standard') -> binding._writeHtml markup, type
readImage: (type='standard') -> binding._readImage type
writeImage: (image, type='standard') -> binding._writeImage image, type
clear: (type='standard') -> binding._clear type

View file

@ -46,7 +46,8 @@ std::vector<CrashReporter::UploadReportResult>
CrashReporter::GetUploadedReports(const std::string& path) { CrashReporter::GetUploadedReports(const std::string& path) {
std::string file_content; std::string file_content;
std::vector<CrashReporter::UploadReportResult> result; std::vector<CrashReporter::UploadReportResult> result;
if (base::ReadFileToString(base::FilePath(path), &file_content)) { if (base::ReadFileToString(base::FilePath::FromUTF8Unsafe(path),
&file_content)) {
std::vector<std::string> reports; std::vector<std::string> reports;
base::SplitString(file_content, '\n', &reports); base::SplitString(file_content, '\n', &reports);
for (const std::string& report : reports) { for (const std::string& report : reports) {

View file

@ -310,6 +310,38 @@ exports.wrapFsWithAsar = (fs) ->
files files
internalModuleReadFile = process.binding('fs').internalModuleReadFile
process.binding('fs').internalModuleReadFile = (p) ->
[isAsar, asarPath, filePath] = splitPath p
return internalModuleReadFile p unless isAsar
archive = getOrCreateArchive asarPath
return undefined unless archive
info = archive.getFileInfo filePath
return undefined unless info
return '' if info.size is 0
buffer = new Buffer(info.size)
fd = archive.getFd()
retrun undefined unless fd >= 0
fs.readSync fd, buffer, 0, info.size, info.offset
buffer.toString 'utf8'
internalModuleStat = process.binding('fs').internalModuleStat
process.binding('fs').internalModuleStat = (p) ->
[isAsar, asarPath, filePath] = splitPath p
return internalModuleStat p unless isAsar
archive = getOrCreateArchive asarPath
return -34 unless archive # -ENOENT
stats = archive.stat filePath
return -34 unless stats # -ENOENT
if stats.isDirectory then return 1 else return 0
overrideAPI fs, 'open' overrideAPI fs, 'open'
overrideAPI child_process, 'execFile' overrideAPI child_process, 'execFile'
overrideAPISync process, 'dlopen', 1 overrideAPISync process, 'dlopen', 1

View file

@ -87,6 +87,9 @@ const char kDisableAutoHideCursor[] = "disable-auto-hide-cursor";
// Use the OS X's standard window instead of the textured window. // Use the OS X's standard window instead of the textured window.
const char kStandardWindow[] = "standard-window"; const char kStandardWindow[] = "standard-window";
// Path to client certificate.
const char kClientCertificate[] = "client-certificate";
// Web runtime features. // Web runtime features.
const char kExperimentalFeatures[] = "experimental-features"; const char kExperimentalFeatures[] = "experimental-features";
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features"; const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";

View file

@ -45,6 +45,7 @@ extern const char kTransparent[];
extern const char kType[]; extern const char kType[];
extern const char kDisableAutoHideCursor[]; extern const char kDisableAutoHideCursor[];
extern const char kStandardWindow[]; extern const char kStandardWindow[];
extern const char kClientCertificate[];
extern const char kExperimentalFeatures[]; extern const char kExperimentalFeatures[];
extern const char kExperimentalCanvasFeatures[]; extern const char kExperimentalCanvasFeatures[];

View file

@ -30,7 +30,9 @@ RenderView* GetCurrentRenderView() {
return RenderView::FromWebView(view); return RenderView::FromWebView(view);
} }
void Send(const base::string16& channel, const base::ListValue& arguments) { void Send(v8::Isolate* isolate,
const base::string16& channel,
const base::ListValue& arguments) {
RenderView* render_view = GetCurrentRenderView(); RenderView* render_view = GetCurrentRenderView();
if (render_view == NULL) if (render_view == NULL)
return; return;
@ -39,10 +41,11 @@ void Send(const base::string16& channel, const base::ListValue& arguments) {
render_view->GetRoutingID(), channel, arguments)); render_view->GetRoutingID(), channel, arguments));
if (!success) if (!success)
node::ThrowError("Unable to send AtomViewHostMsg_Message"); node::ThrowError(isolate, "Unable to send AtomViewHostMsg_Message");
} }
base::string16 SendSync(const base::string16& channel, base::string16 SendSync(v8::Isolate* isolate,
const base::string16& channel,
const base::ListValue& arguments) { const base::ListValue& arguments) {
base::string16 json; base::string16 json;
@ -57,7 +60,7 @@ base::string16 SendSync(const base::string16& channel,
bool success = render_view->Send(message); bool success = render_view->Send(message);
if (!success) if (!success)
node::ThrowError("Unable to send AtomViewHostMsg_Message_Sync"); node::ThrowError(isolate, "Unable to send AtomViewHostMsg_Message_Sync");
return json; return json;
} }

View file

@ -10,6 +10,8 @@ wrapArgs = (args) ->
valueToMeta = (value) -> valueToMeta = (value) ->
if Array.isArray value if Array.isArray value
type: 'array', value: wrapArgs(value) type: 'array', value: wrapArgs(value)
else if Buffer.isBuffer value
type: 'buffer', value: Array::slice.call(value, 0)
else if value? and typeof value is 'object' and v8Util.getHiddenValue value, 'atomId' else if value? and typeof value is 'object' and v8Util.getHiddenValue value, 'atomId'
type: 'remote-object', id: v8Util.getHiddenValue value, 'atomId' type: 'remote-object', id: v8Util.getHiddenValue value, 'atomId'
else if value? and typeof value is 'object' else if value? and typeof value is 'object'
@ -30,6 +32,7 @@ metaToValue = (meta) ->
switch meta.type switch meta.type
when 'value' then meta.value when 'value' then meta.value
when 'array' then (metaToValue(el) for el in meta.members) when 'array' then (metaToValue(el) for el in meta.members)
when 'buffer' then new Buffer(meta.value)
when 'error' when 'error'
throw new Error("#{meta.message}\n#{meta.stack}") throw new Error("#{meta.message}\n#{meta.stack}")
else else

View file

@ -173,7 +173,7 @@ class WebViewImpl
params = params =
instanceId: @viewInstanceId instanceId: @viewInstanceId
userAgentOverride: @userAgentOverride userAgentOverride: @userAgentOverride
for attributeName, attribute of @attributes for own attributeName, attribute of @attributes
params[attributeName] = attribute.getValue() params[attributeName] = attribute.getValue()
# When the WebView is not participating in layout (display:none) # When the WebView is not participating in layout (display:none)
# then getBoundingClientRect() would report a width and height of 0. # then getBoundingClientRect() would report a width and height of 0.

View file

@ -9,6 +9,7 @@
'component%': 'static_library', 'component%': 'static_library',
'python': 'python', 'python': 'python',
'openssl_no_asm': 1, 'openssl_no_asm': 1,
'node_target_type': 'shared_library',
'node_install_npm': 'false', 'node_install_npm': 'false',
'node_prefix': '', 'node_prefix': '',
'node_shared_cares': 'false', 'node_shared_cares': 'false',
@ -26,6 +27,7 @@
'uv_library': 'static_library', 'uv_library': 'static_library',
'uv_parent_path': 'vendor/node/deps/uv', 'uv_parent_path': 'vendor/node/deps/uv',
'uv_use_dtrace': 'false', 'uv_use_dtrace': 'false',
'V8_BASE': '',
'v8_postmortem_support': 'false', 'v8_postmortem_support': 'false',
'v8_enable_i18n_support': 'false', 'v8_enable_i18n_support': 'false',
# Required by Linux (empty for now, should support it in future). # Required by Linux (empty for now, should support it in future).
@ -99,7 +101,10 @@
], ],
}], }],
['_target_name=="node"', { ['_target_name=="node"', {
'include_dirs': [ '<(libchromiumcontent_src_dir)/v8/include' ], 'include_dirs': [
'<(libchromiumcontent_src_dir)/v8',
'<(libchromiumcontent_src_dir)/v8/include',
],
'conditions': [ 'conditions': [
['OS=="mac" and libchromiumcontent_component==0', { ['OS=="mac" and libchromiumcontent_component==0', {
# -all_load is the "whole-archive" on OS X. # -all_load is the "whole-archive" on OS X.

View file

@ -43,7 +43,7 @@ You can also create a window without chrome by using
other windows other windows
* `fullscreen` Boolean - Whether the window should show in fullscreen, when * `fullscreen` Boolean - Whether the window should show in fullscreen, when
set to `false` the fullscreen button would also be hidden on OS X set to `false` the fullscreen button would also be hidden on OS X
* `skip-taskbar` Boolean - Do not show window in Taskbar * `skip-taskbar` Boolean - Do not show window in taskbar
* `zoom-factor` Number - The default zoom factor of the page, zoom factor is * `zoom-factor` Number - The default zoom factor of the page, zoom factor is
zoom percent / 100, so `3.0` represents `300%` zoom percent / 100, so `3.0` represents `300%`
* `kiosk` Boolean - The kiosk mode * `kiosk` Boolean - The kiosk mode
@ -131,9 +131,9 @@ window.onbeforeunload = function(e) {
console.log('I do not want to be closed'); console.log('I do not want to be closed');
// Unlike usual browsers, in which a string should be returned and the user is // Unlike usual browsers, in which a string should be returned and the user is
// prompted to confirm the page unload. Electron gives the power completely // prompted to confirm the page unload, Electron gives developers more options.
// to the developers, return empty string or false would prevent the unloading // Returning empty string or false would prevent the unloading now.
// now. You can also use the dialog API to let user confirm it. // You can also use the dialog API to let the user confirm closing the application.
return false; return false;
}; };
``` ```
@ -464,7 +464,7 @@ Starts or stops flashing the window to attract user's attention.
* `skip` Boolean * `skip` Boolean
Makes the window do not show in Taskbar. Makes the window not show in the taskbar.
### BrowserWindow.setKiosk(flag) ### BrowserWindow.setKiosk(flag)
@ -483,13 +483,13 @@ Returns whether the window is in kiosk mode.
Sets the pathname of the file the window represents, and the icon of the file Sets the pathname of the file the window represents, and the icon of the file
will show in window's title bar. will show in window's title bar.
__Note__: This API is available only on OS X. __Note__: This API is only available on OS X.
### BrowserWindow.getRepresentedFilename() ### BrowserWindow.getRepresentedFilename()
Returns the pathname of the file the window represents. Returns the pathname of the file the window represents.
__Note__: This API is available only on OS X. __Note__: This API is only available on OS X.
### BrowserWindow.setDocumentEdited(edited) ### BrowserWindow.setDocumentEdited(edited)
@ -498,13 +498,13 @@ __Note__: This API is available only on OS X.
Specifies whether the windows document has been edited, and the icon in title Specifies whether the windows document has been edited, and the icon in title
bar will become grey when set to `true`. bar will become grey when set to `true`.
__Note__: This API is available only on OS X. __Note__: This API is only available on OS X.
### BrowserWindow.IsDocumentEdited() ### BrowserWindow.IsDocumentEdited()
Whether the window's document has been edited. Whether the window's document has been edited.
__Note__: This API is available only on OS X. __Note__: This API is only available on OS X.
### BrowserWindow.openDevTools([options]) ### BrowserWindow.openDevTools([options])
@ -604,20 +604,20 @@ it will assume `app.getName().desktop`.
### BrowserWindow.setOverlayIcon(overlay, description) ### BrowserWindow.setOverlayIcon(overlay, description)
* `overlay` [NativeImage](native-image.md) - the icon to display on the bottom * `overlay` [NativeImage](native-image.md) - the icon to display on the bottom
right corner of the Taskbar icon. If this parameter is `null`, the overlay is right corner of the taskbar icon. If this parameter is `null`, the overlay is
cleared cleared
* `description` String - a description that will be provided to Accessibility * `description` String - a description that will be provided to Accessibility
screen readers screen readers
Sets a 16px overlay onto the current Taskbar icon, usually used to convey some sort of application status or to passively notify the user. Sets a 16px overlay onto the current taskbar icon, usually used to convey some sort of application status or to passively notify the user.
__Note:__ This API is only available on Windows, Win7 or above __Note:__ This API is only available on Windows (Windows 7 and above)
### BrowserWindow.showDefinitionForSelection() ### BrowserWindow.showDefinitionForSelection()
Shows pop-up dictionary that searches the selected word on the page. Shows pop-up dictionary that searches the selected word on the page.
__Note__: This API is available only on OS X. __Note__: This API is only available on OS X.
### BrowserWindow.setAutoHideMenuBar(hide) ### BrowserWindow.setAutoHideMenuBar(hide)
@ -753,7 +753,7 @@ Calling `event.preventDefault()` can prevent creating new windows.
Emitted when user or the page wants to start an navigation, it can happen when Emitted when user or the page wants to start an navigation, it can happen when
`window.location` object is changed or user clicks a link in the page. `window.location` object is changed or user clicks a link in the page.
This event will not emit when the navigation is started programmely with APIs This event will not emit when the navigation is started programmatically with APIs
like `WebContents.loadUrl` and `WebContents.back`. like `WebContents.loadUrl` and `WebContents.back`.
Calling `event.preventDefault()` can prevent the navigation. Calling `event.preventDefault()` can prevent the navigation.

View file

@ -1,6 +1,6 @@
# Supported Chrome command line switches # Supported Chrome command line switches
Following command lines switches in Chrome browser are also Supported in The following command lines switches in Chrome browser are also supported in
Electron, you can use [app.commandLine.appendSwitch][append-switch] to append Electron, you can use [app.commandLine.appendSwitch][append-switch] to append
them in your app's main script before the [ready][ready] event of [app][app] them in your app's main script before the [ready][ready] event of [app][app]
module is emitted: module is emitted:
@ -11,9 +11,14 @@ app.commandLine.appendSwitch('remote-debugging-port', '8315');
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1');
app.on('ready', function() { app.on('ready', function() {
// Your code here
}); });
``` ```
## --client-certificate=`path`
Sets `path` of client certificate file.
## --disable-http-cache ## --disable-http-cache
Disables the disk cache for HTTP requests. Disables the disk cache for HTTP requests.

View file

@ -36,8 +36,8 @@ selected, an example is:
filters: [ filters: [
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }, { name: 'Images', extensions: ['jpg', 'png', 'gif'] },
{ name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] }, { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] },
{ name: 'Custom File Type', extensions: ['as'] }, { name: 'Custom File Type', extensions: ['as'] }
], ]
} }
``` ```

View file

@ -28,7 +28,7 @@ var win = new BrowserWindow({ transparent: true, frame: false });
API to set window shape to solve this, but currently blocked at an API to set window shape to solve this, but currently blocked at an
[upstream bug](https://code.google.com/p/chromium/issues/detail?id=387234). [upstream bug](https://code.google.com/p/chromium/issues/detail?id=387234).
* Transparent window is not resizable, setting `resizable` to `true` may make * Transparent window is not resizable, setting `resizable` to `true` may make
transprent window stop working on some platforms. transparent window stop working on some platforms.
* The `blur` filter only applies to the web page, so there is no way to apply * The `blur` filter only applies to the web page, so there is no way to apply
blur effect to the content below the window. blur effect to the content below the window.
* On Windows transparent window will not work when DWM is disabled. * On Windows transparent window will not work when DWM is disabled.

View file

@ -9,8 +9,10 @@ var globalShortcut = require('global-shortcut');
// Register a 'ctrl+x' shortcut listener. // Register a 'ctrl+x' shortcut listener.
var ret = globalShortcut.register('ctrl+x', function() { console.log('ctrl+x is pressed'); }) var ret = globalShortcut.register('ctrl+x', function() { console.log('ctrl+x is pressed'); })
if (!ret)
console.log('registerion fails'); if (!ret) {
console.log('registration failed');
}
// Check whether a shortcut is registered. // Check whether a shortcut is registered.
console.log(globalShortcut.isRegistered('ctrl+x')); console.log(globalShortcut.isRegistered('ctrl+x'));

View file

@ -29,8 +29,11 @@ window.addEventListener('contextmenu', function (e) {
Another example of creating the application menu with the simple template API: Another example of creating the application menu with the simple template API:
```javascript ```html
// main.js <!-- index.html -->
<script>
var remote = require('remote');
var Menu = remote.require('menu');
var template = [ var template = [
{ {
label: 'Electron', label: 'Electron',
@ -69,7 +72,7 @@ var template = [
{ {
label: 'Quit', label: 'Quit',
accelerator: 'Command+Q', accelerator: 'Command+Q',
click: function() { app.quit(); } selector: 'terminate:'
}, },
] ]
}, },
@ -108,7 +111,7 @@ var template = [
label: 'Select All', label: 'Select All',
accelerator: 'Command+A', accelerator: 'Command+A',
selector: 'selectAll:' selector: 'selectAll:'
}, }
] ]
}, },
{ {
@ -117,12 +120,12 @@ var template = [
{ {
label: 'Reload', label: 'Reload',
accelerator: 'Command+R', accelerator: 'Command+R',
click: function() { BrowserWindow.getFocusedWindow().reloadIgnoringCache(); } click: function() { remote.getCurrentWindow().reload(); }
}, },
{ {
label: 'Toggle DevTools', label: 'Toggle DevTools',
accelerator: 'Alt+Command+I', accelerator: 'Alt+Command+I',
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); } click: function() { remote.getCurrentWindow().toggleDevTools(); }
}, },
] ]
}, },
@ -145,18 +148,19 @@ var template = [
{ {
label: 'Bring All to Front', label: 'Bring All to Front',
selector: 'arrangeInFront:' selector: 'arrangeInFront:'
}, }
] ]
}, },
{ {
label: 'Help', label: 'Help',
submenu: [] submenu: []
}, }
]; ];
menu = Menu.buildFromTemplate(template); menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu); // Must be called within app.on('ready', function(){ ... }); Menu.setApplicationMenu(menu);
</script>
``` ```
## Class: Menu ## Class: Menu
@ -281,10 +285,10 @@ Template:
```javascript ```javascript
[ [
{label: '4', id: '4'} {label: '4', id: '4'},
{label: '5', id: '5'} {label: '5', id: '5'},
{label: '1', id: '1', position: 'before=4'} {label: '1', id: '1', position: 'before=4'},
{label: '2', id: '2'} {label: '2', id: '2'},
{label: '3', id: '3'} {label: '3', id: '3'}
] ]
``` ```
@ -303,11 +307,11 @@ Template:
```javascript ```javascript
[ [
{label: 'a', position: 'endof=letters'} {label: 'a', position: 'endof=letters'},
{label: '1', position: 'endof=numbers'} {label: '1', position: 'endof=numbers'},
{label: 'b', position: 'endof=letters'} {label: 'b', position: 'endof=letters'},
{label: '2', position: 'endof=numbers'} {label: '2', position: 'endof=numbers'},
{label: 'c', position: 'endof=letters'} {label: 'c', position: 'endof=letters'},
{label: '3', position: 'endof=numbers'} {label: '3', position: 'endof=numbers'}
] ]
``` ```

View file

@ -7,8 +7,8 @@ An example of implementing a protocol that has the same effect with the
`file://` protocol: `file://` protocol:
```javascript ```javascript
var app = require('app'), var app = require('app');
path = require('path'); var path = require('path');
app.on('ready', function() { app.on('ready', function() {
var protocol = require('protocol'); var protocol = require('protocol');

View file

@ -15,7 +15,7 @@ app.on('ready', function(){
{ label: 'Item1', type: 'radio' }, { label: 'Item1', type: 'radio' },
{ label: 'Item2', type: 'radio' }, { label: 'Item2', type: 'radio' },
{ label: 'Item3', type: 'radio', checked: true }, { label: 'Item3', type: 'radio', checked: true },
{ label: 'Item4', type: 'radio' }, { label: 'Item4', type: 'radio' }
]); ]);
appIcon.setToolTip('This is my application.'); appIcon.setToolTip('This is my application.');
appIcon.setContextMenu(contextMenu); appIcon.setContextMenu(contextMenu);

View file

@ -18,7 +18,7 @@ form, the `webview` tag includes the `src` of the web page and css styles that
control the appearance of the `webview` container: control the appearance of the `webview` container:
```html ```html
<webview id="foo" src="https://www.github.com/" style="width:640px; height:480px"></webview> <webview id="foo" src="https://www.github.com/" style="display:inline-block; width:640px; height:480px"></webview>
``` ```
If you want to control the guest content in any way, you can write JavaScript If you want to control the guest content in any way, you can write JavaScript
@ -398,7 +398,7 @@ without regard for log level or other properties.
```javascript ```javascript
webview.addEventListener('console-message', function(e) { webview.addEventListener('console-message', function(e) {
console.log('Guest page logged a message: ', e.message); console.log('Guest page logged a message:', e.message);
}); });
``` ```
@ -456,7 +456,7 @@ webview.send('ping');
var ipc = require('ipc'); var ipc = require('ipc');
ipc.on('ping', function() { ipc.on('ping', function() {
ipc.sendToHost('pong'); ipc.sendToHost('pong');
}) });
``` ```
### crashed ### crashed

View file

@ -35,7 +35,7 @@ exposing your app's source code to users.
To use an `asar` archive to replace the `app` folder, you need to rename the To use an `asar` archive to replace the `app` folder, you need to rename the
archive to `app.asar`, and put it under Electron's resources directory like archive to `app.asar`, and put it under Electron's resources directory like
bellow, and Electron will then try read the archive and start from it. below, and Electron will then try read the archive and start from it.
On OS X: On OS X:

View file

@ -70,9 +70,9 @@ var dockMenu = Menu.buildFromTemplate([
{ label: 'New Window', click: function() { console.log('New Window'); } }, { label: 'New Window', click: function() { console.log('New Window'); } },
{ label: 'New Window with Settings', submenu: [ { label: 'New Window with Settings', submenu: [
{ label: 'Basic' }, { label: 'Basic' },
{ label: 'Pro'}, { label: 'Pro'}
]}, ]},
{ label: 'New Command...'}, { label: 'New Command...'}
]); ]);
app.dock.setMenu(dockMenu); app.dock.setMenu(dockMenu);
``` ```
@ -119,7 +119,7 @@ app.setUserTasks([
iconPath: process.execPath, iconPath: process.execPath,
iconIndex: 0, iconIndex: 0,
title: 'New Window', title: 'New Window',
description: 'Create a new window', description: 'Create a new window'
} }
]); ]);
``` ```
@ -149,8 +149,8 @@ On Windows, a taskbar button can be used to display a progress bar. This enables
a window to provide progress information to the user without that user having to a window to provide progress information to the user without that user having to
switch to the window itself. switch to the window itself.
The Unity DE also has a simililar feature that allows you to specify progress The Unity DE also has a similar feature that allows you to specify the progress
bar in the lancher. bar in the launcher.
__Progress bar in taskbar button:__ __Progress bar in taskbar button:__

View file

@ -20,14 +20,14 @@ Then you can load the extension in Electron by opening devtools in any window,
and then running the following code in the devtools console: and then running the following code in the devtools console:
```javascript ```javascript
require('remote').require('browser-window').addDevToolsExtension('/some-directory/react-devtools') require('remote').require('browser-window').addDevToolsExtension('/some-directory/react-devtools');
``` ```
To unload the extension, you can call `BrowserWindow.removeDevToolsExtension` To unload the extension, you can call `BrowserWindow.removeDevToolsExtension`
API with its name and it will not load the next time you open the devtools: API with its name and it will not load the next time you open the devtools:
```javascript ```javascript
require('remote').require('browser-window').removeDevToolsExtension('React Developer Tools') require('remote').require('browser-window').removeDevToolsExtension('React Developer Tools');
``` ```
## Format of devtools extension ## Format of devtools extension

View file

@ -82,8 +82,9 @@ var mainWindow = null;
// Quit when all windows are closed. // Quit when all windows are closed.
app.on('window-all-closed', function() { app.on('window-all-closed', function() {
if (process.platform != 'darwin') if (process.platform != 'darwin') {
app.quit(); app.quit();
}
}); });
// This method will be called when Electron has done everything // This method will be called when Electron has done everything

View file

@ -23,8 +23,9 @@ var mainWindow = null;
// Quit when all windows are closed. // Quit when all windows are closed.
app.on('window-all-closed', function() { app.on('window-all-closed', function() {
if (process.platform != 'darwin') if (process.platform != 'darwin') {
app.quit(); app.quit();
}
}); });
// Specify flash path. // Specify flash path.

View file

@ -49,14 +49,14 @@ and where to find Electron's binary:
```javascript ```javascript
var webdriver = require('selenium-webdriver'); var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder(). var driver = new webdriver.Builder()
// The "9515" is the port opened by chrome driver. // The "9515" is the port opened by chrome driver.
usingServer('http://localhost:9515'). .usingServer('http://localhost:9515')
withCapabilities({chromeOptions: { .withCapabilities({chromeOptions: {
// Here is the path to your Electron binary. // Here is the path to your Electron binary.
binary: '/Path-to-Your-App.app/Contents/MacOS/Atom'}}). binary: '/Path-to-Your-App.app/Contents/MacOS/Atom'}})
forBrowser('electron'). .forBrowser('electron')
build(); .build();
driver.get('http://www.google.com'); driver.get('http://www.google.com');
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
import os import os
import platform
import subprocess import subprocess
import sys import sys
@ -43,10 +44,19 @@ def run_gyp(target_arch, component):
defines = [ defines = [
'-Dlibchromiumcontent_component={0}'.format(component), '-Dlibchromiumcontent_component={0}'.format(component),
'-Dtarget_arch={0}'.format(target_arch), '-Dtarget_arch={0}'.format(target_arch),
'-Dhost_arch={0}'.format(target_arch),
'-Dlibrary=static_library', '-Dlibrary=static_library',
] ]
return subprocess.call([python, gyp, '-f', 'ninja', '--depth', '.', return subprocess.call([python, gyp, '-f', 'ninja', '--depth', '.',
'atom.gyp', '-Icommon.gypi'] + defines) 'atom.gyp', '-Icommon.gypi'] + defines)
def get_host_arch():
if platform.architecture()[0] == '32bit':
return 'ia32'
else:
return 'x64'
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View file

@ -188,6 +188,7 @@ describe 'browser-window module', ->
w.loadUrl 'file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html') w.loadUrl 'file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html')
describe 'new-window event', -> describe 'new-window event', ->
return if isCI and process.platform is 'darwin'
it 'emits when window.open is called', (done) -> it 'emits when window.open is called', (done) ->
w.webContents.once 'new-window', (e, url, frameName) -> w.webContents.once 'new-window', (e, url, frameName) ->
e.preventDefault() e.preventDefault()
@ -230,6 +231,7 @@ describe 'browser-window module', ->
w.minimize() w.minimize()
describe 'will-navigate event', -> describe 'will-navigate event', ->
return if isCI and process.platform is 'darwin'
it 'emits when user starts a navigation', (done) -> it 'emits when user starts a navigation', (done) ->
@timeout 10000 @timeout 10000
w.webContents.on 'will-navigate', (event, url) -> w.webContents.on 'will-navigate', (event, url) ->
@ -239,6 +241,7 @@ describe 'browser-window module', ->
w.loadUrl "file://#{fixtures}/pages/will-navigate.html" w.loadUrl "file://#{fixtures}/pages/will-navigate.html"
describe 'dom-ready event', -> describe 'dom-ready event', ->
return if isCI and process.platform is 'darwin'
it 'emits when document is loaded', (done) -> it 'emits when document is loaded', (done) ->
ipc = remote.require 'ipc' ipc = remote.require 'ipc'
server = http.createServer (req, res) -> server = http.createServer (req, res) ->

2
vendor/brightray vendored

@ -1 +1 @@
Subproject commit 1cba3a459e9629916655c98716b32ccd1869ef56 Subproject commit 7c6c530608e17ee569edea3dc2607736f3cdb376

2
vendor/node vendored

@ -1 +1 @@
Subproject commit b772c19a8f9db65673184822fb294235eff9c364 Subproject commit ab1b3ba0b0076d7aa72e80caf8045fb6f7a68be0