Merge remote-tracking branch 'atom/master'

This commit is contained in:
Plusb Preco 2015-08-31 09:55:35 +09:00
commit 8b6f3dc0aa
59 changed files with 2623 additions and 1483 deletions

1
.gitignore vendored
View file

@ -17,3 +17,4 @@ node_modules/
*.pyc
debug.log
npm-debug.log
atom/common/chrome_version.h

View file

@ -5,15 +5,18 @@
#include "atom/app/node_main.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/node_includes.h"
#include "base/command_line.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "gin/v8_initializer.h"
#include "atom/common/node_includes.h"
namespace atom {
int NodeMain(int argc, char *argv[]) {
base::CommandLine::Init(argc, argv);
argv = uv_setup_args(argc, argv);
int exec_argc;
const char** exec_argv;
@ -31,17 +34,13 @@ int NodeMain(int argc, char *argv[]) {
gin_env.isolate(), uv_default_loop(), gin_env.context(), argc, argv,
exec_argc, exec_argv);
// Start debugger.
node::node_isolate = gin_env.isolate();
if (node::use_debug_agent)
node::StartDebug(env, node::debug_wait_connect);
// Start our custom debugger implementation.
NodeDebugger node_debugger(gin_env.isolate());
if (node_debugger.IsRunning())
env->AssignToContext(v8::Debug::GetDebugContext());
node::LoadEnvironment(env);
// Enable debugger.
if (node::use_debug_agent)
node::EnableDebug(env);
bool more;
do {
more = uv_run(env->event_loop(), UV_RUN_ONCE);

View file

@ -45,6 +45,8 @@ class EventEmitter : public Wrappable {
content::WebContents* sender,
IPC::Message* message,
const Args&... args) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
return EmitWithEvent(name, event, args...);
}

View file

@ -9,6 +9,7 @@
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/google_api_key.h"
#include "content/public/browser/geolocation_provider.h"
namespace atom {
@ -24,6 +25,7 @@ const char* kGeolocationProviderUrl =
} // namespace
AtomAccessTokenStore::AtomAccessTokenStore() {
content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices();
}
AtomAccessTokenStore::~AtomAccessTokenStore() {

View file

@ -9,6 +9,7 @@
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/browser.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h"
#include "base/command_line.h"
@ -69,9 +70,16 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
node_bindings_->Initialize();
// Support the "--debug" switch.
node_debugger_.reset(new NodeDebugger(js_env_->isolate()));
// Create the global environment.
global_env = node_bindings_->CreateEnvironment(js_env_->context());
// Make sure node can get correct environment when debugging.
if (node_debugger_->IsRunning())
global_env->AssignToContext(v8::Debug::GetDebugContext());
// Add atom-shell extended APIs.
atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object());

View file

@ -19,6 +19,7 @@ class AtomBindings;
class Browser;
class JavascriptEnvironment;
class NodeBindings;
class NodeDebugger;
class AtomBrowserMainParts : public brightray::BrowserMainParts {
public:
@ -57,6 +58,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
scoped_ptr<JavascriptEnvironment> js_env_;
scoped_ptr<NodeBindings> node_bindings_;
scoped_ptr<AtomBindings> atom_bindings_;
scoped_ptr<NodeDebugger> node_debugger_;
base::Timer gc_timer_;

View file

@ -45,7 +45,8 @@ void Browser::Shutdown() {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
is_quiting_ = true;
base::MessageLoop::current()->Quit();
base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
}
std::string Browser::GetVersion() const {

View file

@ -92,5 +92,8 @@ app.setAppPath packagePath
# Load the chrome extension support.
require './chrome-extension'
# Set main startup script of the app.
mainStartupScript = packageJson.main or 'index.js'
# Finally load app's main.js and transfer control to C++.
Module._load path.join(packagePath, packageJson.main), Module, true
Module._load path.join(packagePath, mainStartupScript), Module, true

View file

@ -1,82 +1,65 @@
EventEmitter = require('events').EventEmitter
IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap
v8Util = process.atomBinding 'v8_util'
# Class to reference all objects.
class ObjectsStore
@stores = {}
constructor: ->
@nextId = 0
@objects = []
getNextId: ->
++@nextId
add: (obj) ->
id = @getNextId()
@objects[id] = obj
id
has: (id) ->
@objects[id]?
remove: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
delete @objects[id]
get: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
@objects[id]
@forRenderView: (key) ->
@stores[key] = new ObjectsStore unless @stores[key]?
@stores[key]
@releaseForRenderView: (key) ->
delete @stores[key]
class ObjectsRegistry extends EventEmitter
constructor: ->
@setMaxListeners Number.MAX_VALUE
@nextId = 0
# Objects in weak map will be not referenced (so we won't leak memory), and
# every object created in browser will have a unique id in weak map.
@objectsWeakMap = new IDWeakMap
@objectsWeakMap.add = (obj) ->
id = IDWeakMap::add.call this, obj
v8Util.setHiddenValue obj, 'atomId', id
id
# Stores all objects by ref-counting.
# (id) => {object, count}
@storage = {}
# Stores the IDs of objects referenced by WebContents.
# (webContentsId) => {(id) => (count)}
@owners = {}
# Register a new object, the object would be kept referenced until you release
# it explicitly.
add: (key, obj) ->
# Some native objects may already been added to objectsWeakMap, be care not
# to add it twice.
@objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
id = v8Util.getHiddenValue obj, 'atomId'
add: (webContentsId, obj) ->
id = @saveToStorage obj
# Remember the owner.
@owners[webContentsId] ?= {}
@owners[webContentsId][id] ?= 0
@owners[webContentsId][id]++
# Returns object's id
id
# Store and reference the object, then return the storeId which points to
# where the object is stored. The caller can later dereference the object
# with the storeId.
# We use a difference key because the same object can be referenced for
# multiple times by the same renderer view.
store = ObjectsStore.forRenderView key
storeId = store.add obj
[id, storeId]
# Get an object according to its id.
# Get an object according to its ID.
get: (id) ->
@objectsWeakMap.get id
@storage[id]?.object
# Remove an object according to its storeId.
remove: (key, storeId) ->
ObjectsStore.forRenderView(key).remove storeId
# Dereference an object according to its ID.
remove: (webContentsId, id) ->
@dereference id, 1
# Also reduce the count in owner.
pointer = @owners[webContentsId]
--pointer[id]
delete pointer[id] if pointer[id] is 0
# Clear all references to objects from renderer view.
clear: (key) ->
@emit "clear-#{key}"
ObjectsStore.releaseForRenderView key
# Clear all references to objects refrenced by the WebContents.
clear: (webContentsId) ->
@emit "clear-#{webContentsId}"
return unless @owners[webContentsId]?
@dereference id, count for id, count of @owners[webContentsId]
delete @owners[webContentsId]
# Private: Saves the object into storage and assigns an ID for it.
saveToStorage: (object) ->
id = v8Util.getHiddenValue object, 'atomId'
unless id
id = ++@nextId
@storage[id] = {count: 0, object}
v8Util.setHiddenValue object, 'atomId', id
++@storage[id].count
id
# Private: Dereference the object from store.
dereference: (id, count) ->
pointer = @storage[id]
pointer.count -= count
if pointer.count is 0
v8Util.deleteHiddenValue pointer.object, 'atomId'
delete @storage[id]
module.exports = new ObjectsRegistry

View file

@ -4,7 +4,7 @@ objectsRegistry = require './objects-registry.js'
v8Util = process.atomBinding 'v8_util'
# Convert a real value into meta data.
valueToMeta = (sender, value) ->
valueToMeta = (sender, value, optimizeSimpleObject=false) ->
meta = type: typeof value
meta.type = 'buffer' if Buffer.isBuffer value
@ -12,6 +12,10 @@ valueToMeta = (sender, value) ->
meta.type = 'array' if Array.isArray value
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
# Treat simple objects as value.
if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple'
meta.type = 'value'
# Treat the arguments object as array.
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
@ -24,7 +28,7 @@ valueToMeta = (sender, value) ->
# Reference the original value if it's an object, because when it's
# passed to renderer we would assume the renderer keeps a reference of
# it.
[meta.id, meta.storeId] = objectsRegistry.add sender.getId(), value
meta.id = objectsRegistry.add sender.getId(), value
meta.members = []
meta.members.push {name: prop, type: typeof field} for prop, field of value
@ -80,11 +84,11 @@ unwrapArgs = (sender, args) ->
callFunction = (event, func, caller, args) ->
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
args.push (ret) ->
event.returnValue = valueToMeta event.sender, ret
event.returnValue = valueToMeta event.sender, ret, true
func.apply caller, args
else
ret = func.apply caller, args
event.returnValue = valueToMeta event.sender, ret
event.returnValue = valueToMeta event.sender, ret, true
# Send by BrowserWindow when its render view is deleted.
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) ->
@ -170,8 +174,8 @@ ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, storeId) ->
objectsRegistry.remove event.sender.getId(), storeId
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) ->
objectsRegistry.remove event.sender.getId(), id
ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) ->
try

View file

@ -82,9 +82,6 @@ class NativeWindowMac : public NativeWindow {
// Called to handle a mouse event.
void HandleMouseEvent(NSEvent* event);
// Clip web view to rounded corner.
void ClipWebView();
protected:
// NativeWindow:
void HandleKeyboardEvent(

View file

@ -22,9 +22,6 @@
namespace {
// The radius of rounded corner.
const CGFloat kAtomWindowCornerRadius = 4.0;
// Prevents window from resizing during the scope.
class ScopedDisableResize {
public:
@ -41,10 +38,6 @@ bool ScopedDisableResize::disable_resize_ = false;
} // namespace
@interface NSView (PrivateMethods)
- (CGFloat)roundedCornerRadius;
@end
// This view always takes the size of its superview. It is intended to be used
// as a NSWindow's contentView. It is needed because NSWindow's implementation
// explicitly resizes the contentView at inopportune times.
@ -153,9 +146,6 @@ bool ScopedDisableResize::disable_resize_ = false;
}
- (void)windowDidResize:(NSNotification*)notification {
if (!shell_->has_frame())
shell_->ClipWebView();
shell_->NotifyWindowResize();
}
@ -613,8 +603,8 @@ void NativeWindowMac::Center() {
}
void NativeWindowMac::SetTitle(const std::string& title) {
// We don't want the title to show in transparent window.
if (transparent())
// We don't want the title to show in transparent or frameless window.
if (transparent() || !has_frame())
return;
[window_ setTitle:base::SysUTF8ToNSString(title)];
@ -804,35 +794,27 @@ void NativeWindowMac::HandleKeyboardEvent(
}
void NativeWindowMac::InstallView() {
// Make sure the bottom corner is rounded: http://crbug.com/396264.
[[window_ contentView] setWantsLayer:YES];
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
if (has_frame()) {
// Add layer with white background for the contents view.
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
[view setLayer:layer];
[view setFrame:[[window_ contentView] bounds]];
[[window_ contentView] addSubview:view];
} else {
if (base::mac::IsOSYosemiteOrLater()) {
// In OSX 10.10, adding subviews to the root view for the NSView hierarchy
// produces warnings. To eliminate the warnings, we resize the contentView
// to fill the window, and add subviews to that.
// http://crbug.com/380412
content_view_.reset([[FullSizeContentView alloc] init]);
[content_view_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[content_view_ setFrame:[[[window_ contentView] superview] bounds]];
[window_ setContentView:content_view_];
// In OSX 10.10, adding subviews to the root view for the NSView hierarchy
// produces warnings. To eliminate the warnings, we resize the contentView
// to fill the window, and add subviews to that.
// http://crbug.com/380412
content_view_.reset([[FullSizeContentView alloc] init]);
[content_view_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[content_view_ setFrame:[[[window_ contentView] superview] bounds]];
[window_ setContentView:content_view_];
[view setFrame:[content_view_ bounds]];
[content_view_ addSubview:view];
} else {
NSView* frameView = [[window_ contentView] superview];
[view setFrame:[frameView bounds]];
[frameView addSubview:view];
}
[view setFrame:[content_view_ bounds]];
[content_view_ addSubview:view];
ClipWebView();
InstallDraggableRegionView();
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
@ -851,14 +833,6 @@ void NativeWindowMac::UninstallView() {
[view removeFromSuperview];
}
void NativeWindowMac::ClipWebView() {
if (!web_contents())
return;
NSView* webView = web_contents()->GetNativeView();
webView.layer.masksToBounds = YES;
webView.layer.cornerRadius = kAtomWindowCornerRadius;
}
void NativeWindowMac::InstallDraggableRegionView() {
NSView* webView = web_contents()->GetNativeView();
base::scoped_nsobject<NSView> controlRegion(

View file

@ -0,0 +1,209 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/node_debugger.h"
#include <string>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "net/test/embedded_test_server/tcp_listen_socket.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace {
// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been
// taken by gin, blink and node, using 2 is a safe option for now.
const int kIsolateSlot = 2;
const char* kContentLength = "Content-Length";
} // namespace
NodeDebugger::NodeDebugger(v8::Isolate* isolate)
: isolate_(isolate),
thread_("NodeDebugger"),
content_length_(-1),
weak_factory_(this) {
bool use_debug_agent = false;
int port = 5858;
bool wait_for_connection = false;
std::string port_str;
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch("debug")) {
use_debug_agent = true;
port_str = cmd->GetSwitchValueASCII("debug");
}
if (cmd->HasSwitch("debug-brk")) {
use_debug_agent = true;
wait_for_connection = true;
port_str = cmd->GetSwitchValueASCII("debug-brk");
}
if (use_debug_agent) {
if (!port_str.empty())
base::StringToInt(port_str, &port);
isolate_->SetData(kIsolateSlot, this);
v8::Debug::SetMessageHandler(DebugMessageHandler);
if (wait_for_connection)
v8::Debug::DebugBreak(isolate_);
uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI);
// Start a new IO thread.
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
if (!thread_.StartWithOptions(options)) {
LOG(ERROR) << "Unable to start debugger thread";
return;
}
// Start the server in new IO thread.
thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(),
port));
}
}
NodeDebugger::~NodeDebugger() {
thread_.Stop();
}
bool NodeDebugger::IsRunning() const {
return thread_.IsRunning();
}
void NodeDebugger::StartServer(int port) {
server_ = net::test_server::TCPListenSocket::CreateAndListen(
"127.0.0.1", port, this);
if (!server_) {
LOG(ERROR) << "Cannot start debugger server";
return;
}
}
void NodeDebugger::CloseSession() {
accepted_socket_.reset();
}
void NodeDebugger::OnMessage(const std::string& message) {
if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") !=
std::string::npos)
CloseSession();
base::string16 message16 = base::UTF8ToUTF16(message);
v8::Debug::SendCommand(
isolate_,
reinterpret_cast<const uint16_t*>(message16.data()), message16.size());
uv_async_send(&weak_up_ui_handle_);
}
void NodeDebugger::SendMessage(const std::string& message) {
if (accepted_socket_) {
std::string header = base::StringPrintf(
"%s: %d\r\n\r\n", kContentLength, static_cast<int>(message.size()));
accepted_socket_->Send(header);
accepted_socket_->Send(message);
}
}
void NodeDebugger::SendConnectMessage() {
accepted_socket_->Send(base::StringPrintf(
"Type: connect\r\n"
"V8-Version: %s\r\n"
"Protocol-Version: 1\r\n"
"Embedding-Host: %s\r\n"
"%s: 0\r\n",
v8::V8::GetVersion(), ATOM_PRODUCT_NAME, kContentLength), true);
}
// static
void NodeDebugger::ProcessMessageInUI(uv_async_t* handle) {
v8::Debug::ProcessDebugMessages();
}
// static
void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) {
NodeDebugger* self = static_cast<NodeDebugger*>(
message.GetIsolate()->GetData(kIsolateSlot));
if (self) {
std::string message8(*v8::String::Utf8Value(message.GetJSON()));
self->thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(),
message8));
}
}
void NodeDebugger::DidAccept(
net::test_server::StreamListenSocket* server,
scoped_ptr<net::test_server::StreamListenSocket> socket) {
// Only accept one session.
if (accepted_socket_) {
socket->Send(std::string("Remote debugging session already active"), true);
return;
}
accepted_socket_ = socket.Pass();
SendConnectMessage();
}
void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket,
const char* data,
int len) {
buffer_.append(data, len);
do {
if (buffer_.size() == 0)
return;
// Read the "Content-Length" header.
if (content_length_ < 0) {
size_t pos = buffer_.find("\r\n\r\n");
if (pos == std::string::npos)
return;
// We can be sure that the header is "Content-Length: xxx\r\n".
std::string content_length = buffer_.substr(16, pos - 16);
if (!base::StringToInt(content_length, &content_length_)) {
DidClose(accepted_socket_.get());
return;
}
// Strip header from buffer.
buffer_ = buffer_.substr(pos + 4);
}
// Read the message.
if (buffer_.size() >= static_cast<size_t>(content_length_)) {
std::string message = buffer_.substr(0, content_length_);
buffer_ = buffer_.substr(content_length_);
OnMessage(message);
// Get ready for next message.
content_length_ = -1;
}
} while (true);
}
void NodeDebugger::DidClose(net::test_server::StreamListenSocket* socket) {
// If we lost the connection, then simulate a disconnect msg:
OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}");
}
} // namespace atom

View file

@ -0,0 +1,65 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NODE_DEBUGGER_H_
#define ATOM_BROWSER_NODE_DEBUGGER_H_
#include <string>
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "net/test/embedded_test_server/stream_listen_socket.h"
#include "v8/include/v8-debug.h"
#include "vendor/node/deps/uv/include/uv.h"
namespace atom {
// Add support for node's "--debug" switch.
class NodeDebugger : public net::test_server::StreamListenSocket::Delegate {
public:
explicit NodeDebugger(v8::Isolate* isolate);
virtual ~NodeDebugger();
bool IsRunning() const;
private:
void StartServer(int port);
void CloseSession();
void OnMessage(const std::string& message);
void SendMessage(const std::string& message);
void SendConnectMessage();
static void ProcessMessageInUI(uv_async_t* handle);
static void DebugMessageHandler(const v8::Debug::Message& message);
// net::test_server::StreamListenSocket::Delegate:
void DidAccept(
net::test_server::StreamListenSocket* server,
scoped_ptr<net::test_server::StreamListenSocket> socket) override;
void DidRead(net::test_server::StreamListenSocket* socket,
const char* data,
int len) override;
void DidClose(net::test_server::StreamListenSocket* socket) override;
v8::Isolate* isolate_;
uv_async_t weak_up_ui_handle_;
base::Thread thread_;
scoped_ptr<net::test_server::StreamListenSocket> server_;
scoped_ptr<net::test_server::StreamListenSocket> accepted_socket_;
std::string buffer_;
int content_length_;
base::WeakPtrFactory<NodeDebugger> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NodeDebugger);
};
} // namespace atom
#endif // ATOM_BROWSER_NODE_DEBUGGER_H_

View file

@ -1,6 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<dependency>
<dependentAssembly>
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>

View file

@ -207,8 +207,14 @@ const CGFloat kVerticalTitleMargin = 2;
}
inMouseEventSequence_ = NO;
// Show menu when single clicked on the icon.
if (event.clickCount == 1 && menuController_)
// Show menu when there is a context menu.
// NB(hokein): Make tray's behavior more like official one's.
// When the tray icon gets clicked quickly multiple times, the
// event.clickCount doesn't always return 1. Instead, it returns a value that
// counts the clicked times.
// So we don't check the clickCount here, just pop up the menu for each click
// event.
if (menuController_)
[statusItem_ popUpStatusItemMenu:[menuController_ menu]];
// Don't emit click events when menu is showing.

View file

@ -1,80 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/common/api/atom_api_id_weak_map.h"
#include "native_mate/constructor.h"
#include "native_mate/object_template_builder.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
IDWeakMap::IDWeakMap() {
}
IDWeakMap::~IDWeakMap() {
}
int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local<v8::Object> object) {
return map_.Add(isolate, object);
}
v8::Local<v8::Value> IDWeakMap::Get(v8::Isolate* isolate, int32_t key) {
v8::MaybeLocal<v8::Object> result = map_.Get(isolate, key);
if (result.IsEmpty()) {
isolate->ThrowException(v8::Exception::Error(
mate::StringToV8(isolate, "Invalid key")));
return v8::Undefined(isolate);
} else {
return result.ToLocalChecked();
}
}
bool IDWeakMap::Has(int32_t key) const {
return map_.Has(key);
}
std::vector<int32_t> IDWeakMap::Keys() const {
return map_.Keys();
}
void IDWeakMap::Remove(int32_t key) {
map_.Remove(key);
}
// static
void IDWeakMap::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("add", &IDWeakMap::Add)
.SetMethod("get", &IDWeakMap::Get)
.SetMethod("has", &IDWeakMap::Has)
.SetMethod("keys", &IDWeakMap::Keys)
.SetMethod("remove", &IDWeakMap::Remove);
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
using atom::api::IDWeakMap;
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<IDWeakMap>(
isolate,
"IDWeakMap",
base::Bind(&mate::NewOperatorFactory<IDWeakMap>));
exports->Set(mate::StringToSymbol(isolate, "IDWeakMap"), constructor);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_id_weak_map, Initialize)

View file

@ -1,44 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Copyright (c) 2012 Intel Corp. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_
#define ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_
#include <vector>
#include "atom/common/id_weak_map.h"
#include "native_mate/wrappable.h"
namespace atom {
namespace api {
// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer.
class IDWeakMap : public mate::Wrappable {
public:
IDWeakMap();
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
private:
virtual ~IDWeakMap();
int32_t Add(v8::Isolate* isolate, v8::Local<v8::Object> object);
v8::Local<v8::Value> Get(v8::Isolate* isolate, int32_t key);
bool Has(int32_t key) const;
std::vector<int32_t> Keys() const;
void Remove(int32_t key);
atom::IDWeakMap map_;
DISALLOW_COPY_AND_ASSIGN(IDWeakMap);
};
} // namespace api
} // namespace atom
#endif // ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_

View file

@ -28,6 +28,11 @@ void SetHiddenValue(v8::Local<v8::Object> object,
object->SetHiddenValue(key, value);
}
void DeleteHiddenValue(v8::Local<v8::Object> object,
v8::Local<v8::String> key) {
object->DeleteHiddenValue(key);
}
int32_t GetObjectHash(v8::Local<v8::Object> object) {
return object->GetIdentityHash();
}
@ -48,6 +53,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
dict.SetMethod("createObjectWithName", &CreateObjectWithName);
dict.SetMethod("getHiddenValue", &GetHiddenValue);
dict.SetMethod("setHiddenValue", &SetHiddenValue);
dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue);
dict.SetMethod("getObjectHash", &GetObjectHash);
dict.SetMethod("setDestructor", &SetDestructor);
dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot);

View file

@ -5,32 +5,52 @@
#include "atom/common/api/object_life_monitor.h"
#include "native_mate/compat.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
namespace atom {
// static
void ObjectLifeMonitor::BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> target,
v8::Local<v8::Value> destructor) {
target->SetHiddenValue(MATE_STRING_NEW(isolate, "destructor"), destructor);
ObjectLifeMonitor* olm = new ObjectLifeMonitor();
olm->handle_.reset(isolate, target);
olm->handle_.SetWeak(olm, WeakCallback);
v8::Local<v8::Function> destructor) {
new ObjectLifeMonitor(isolate, target, destructor);
}
ObjectLifeMonitor::ObjectLifeMonitor() {
ObjectLifeMonitor::ObjectLifeMonitor(v8::Isolate* isolate,
v8::Local<v8::Object> target,
v8::Local<v8::Function> destructor)
: isolate_(isolate),
context_(isolate, isolate->GetCurrentContext()),
target_(isolate, target),
destructor_(isolate, destructor),
weak_ptr_factory_(this) {
target_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter);
}
// static
void ObjectLifeMonitor::WeakCallback(
const v8::WeakCallbackData<v8::Object, ObjectLifeMonitor>& data) {
// destructor.call(object, object);
v8::Local<v8::Object> obj = data.GetValue();
v8::Local<v8::Function>::Cast(obj->GetHiddenValue(
MATE_STRING_NEW(data.GetIsolate(), "destructor")))->Call(obj, 0, NULL);
delete data.GetParameter();
void ObjectLifeMonitor::OnObjectGC(
const v8::WeakCallbackInfo<ObjectLifeMonitor>& data) {
// Usually FirstWeakCallback should do nothing other than reset |object_|
// and then set a second weak callback to run later. We can sidestep that,
// because posting a task to the current message loop is all but free - but
// DO NOT add any more work to this method. The only acceptable place to add
// code is RunCallback.
ObjectLifeMonitor* self = data.GetParameter();
self->target_.Reset();
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&ObjectLifeMonitor::RunCallback,
self->weak_ptr_factory_.GetWeakPtr()));
}
void ObjectLifeMonitor::RunCallback() {
v8::HandleScope handle_scope(isolate_);
v8::Local<v8::Context> context = v8::Local<v8::Context>::New(
isolate_, context_);
v8::Context::Scope context_scope(context);
v8::Local<v8::Function>::New(isolate_, destructor_)->Call(
context->Global(), 0, nullptr);
delete this;
}
} // namespace atom

View file

@ -6,7 +6,8 @@
#define ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_
#include "base/basictypes.h"
#include "native_mate/scoped_persistent.h"
#include "base/memory/weak_ptr.h"
#include "v8/include/v8.h"
namespace atom {
@ -14,15 +15,23 @@ class ObjectLifeMonitor {
public:
static void BindTo(v8::Isolate* isolate,
v8::Local<v8::Object> target,
v8::Local<v8::Value> destructor);
v8::Local<v8::Function> destructor);
private:
ObjectLifeMonitor();
ObjectLifeMonitor(v8::Isolate* isolate,
v8::Local<v8::Object> target,
v8::Local<v8::Function> destructor);
static void WeakCallback(
const v8::WeakCallbackData<v8::Object, ObjectLifeMonitor>& data);
static void OnObjectGC(const v8::WeakCallbackInfo<ObjectLifeMonitor>& data);
mate::ScopedPersistent<v8::Object> handle_;
void RunCallback();
v8::Isolate* isolate_;
v8::Global<v8::Context> context_;
v8::Global<v8::Object> target_;
v8::Global<v8::Function> destructor_;
base::WeakPtrFactory<ObjectLifeMonitor> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ObjectLifeMonitor);
};

View file

@ -10,6 +10,22 @@
namespace atom {
namespace {
struct ObjectKey {
ObjectKey(int id, IDWeakMap* map) : id(id), map(map) {}
int id;
IDWeakMap* map;
};
void OnObjectGC(const v8::WeakCallbackInfo<ObjectKey>& data) {
ObjectKey* key = data.GetParameter();
key->map->Remove(key->id);
delete key;
}
} // namespace
IDWeakMap::IDWeakMap() : next_id_(0) {
}
@ -18,11 +34,9 @@ IDWeakMap::~IDWeakMap() {
int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local<v8::Object> object) {
int32_t id = GetNextID();
object->SetHiddenValue(mate::StringToSymbol(isolate, "IDWeakMapKey"),
mate::Converter<int32_t>::ToV8(isolate, id));
auto global = make_linked_ptr(new v8::Global<v8::Object>(isolate, object));
global->SetWeak(this, &WeakCallback);
ObjectKey* key = new ObjectKey(id, this);
global->SetWeak(key, OnObjectGC, v8::WeakCallbackType::kParameter);
map_[id] = global;
return id;
}
@ -71,12 +85,4 @@ int32_t IDWeakMap::GetNextID() {
return ++next_id_;
}
// static
void IDWeakMap::WeakCallback(
const v8::WeakCallbackData<v8::Object, IDWeakMap>& data) {
int32_t id = data.GetValue()->GetHiddenValue(
mate::StringToV8(data.GetIsolate(), "IDWeakMapKey"))->Int32Value();
data.GetParameter()->Remove(id);
}
} // namespace atom

View file

@ -44,9 +44,6 @@ class IDWeakMap {
// Returns next available ID.
int32_t GetNextID();
static void WeakCallback(
const v8::WeakCallbackData<v8::Object, IDWeakMap>& data);
// ID of next stored object.
int32_t next_id_;

View file

@ -14,7 +14,8 @@ namespace mate {
v8::Local<v8::Value> Converter<gfx::Point>::ToV8(v8::Isolate* isolate,
const gfx::Point& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("x", val.x());
dict.Set("y", val.y());
return dict.GetHandle();
@ -35,7 +36,8 @@ bool Converter<gfx::Point>::FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> Converter<gfx::Size>::ToV8(v8::Isolate* isolate,
const gfx::Size& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("width", val.width());
dict.Set("height", val.height());
return dict.GetHandle();
@ -56,7 +58,8 @@ bool Converter<gfx::Size>::FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> Converter<gfx::Rect>::ToV8(v8::Isolate* isolate,
const gfx::Rect& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("x", val.x());
dict.Set("y", val.y());
dict.Set("width", val.width());
@ -95,7 +98,8 @@ struct Converter<gfx::Display::TouchSupport> {
v8::Local<v8::Value> Converter<gfx::Display>::ToV8(v8::Isolate* isolate,
const gfx::Display& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.SetHidden("simple", true);
dict.Set("id", val.id());
dict.Set("bounds", val.bounds());
dict.Set("workArea", val.work_area());

View file

@ -11,13 +11,14 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "native_mate/dictionary.h"
#include "vendor/node/src/node_buffer.h"
namespace atom {
namespace {
const int kMaxRecursionDepth = 20;
const int kMaxRecursionDepth = 100;
} // namespace
@ -179,7 +180,8 @@ v8::Local<v8::Value> V8ValueConverter::ToV8Array(
v8::Local<v8::Value> V8ValueConverter::ToV8Object(
v8::Isolate* isolate, const base::DictionaryValue* val) const {
v8::Local<v8::Object> result(v8::Object::New(isolate));
mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate);
result.SetHidden("simple", true);
for (base::DictionaryValue::Iterator iter(*val);
!iter.IsAtEnd(); iter.Advance()) {
@ -188,17 +190,14 @@ v8::Local<v8::Value> V8ValueConverter::ToV8Object(
CHECK(!child_v8.IsEmpty());
v8::TryCatch try_catch;
result->Set(
v8::String::NewFromUtf8(isolate, key.c_str(), v8::String::kNormalString,
key.length()),
child_v8);
result.Set(key, child_v8);
if (try_catch.HasCaught()) {
LOG(ERROR) << "Setter for property " << key.c_str() << " threw an "
<< "exception.";
}
}
return result;
return result.GetHandle();
}
base::Value* V8ValueConverter::FromV8ValueImpl(

View file

@ -47,7 +47,6 @@ REFERENCE_MODULE(atom_browser_window);
REFERENCE_MODULE(atom_common_asar);
REFERENCE_MODULE(atom_common_clipboard);
REFERENCE_MODULE(atom_common_crash_reporter);
REFERENCE_MODULE(atom_common_id_weak_map);
REFERENCE_MODULE(atom_common_native_image);
REFERENCE_MODULE(atom_common_screen);
REFERENCE_MODULE(atom_common_shell);
@ -137,11 +136,6 @@ void NodeBindings::Initialize() {
AtomCommandLine::InitializeFromCommandLine();
#endif
// Parse the debug args.
auto args = AtomCommandLine::argv();
for (const std::string& arg : args)
node::ParseDebugOpt(arg.c_str());
// Init node.
// (we assume node::Init would not modify the parameters under embedded mode).
node::Init(nullptr, nullptr, nullptr, nullptr);
@ -179,15 +173,7 @@ node::Environment* NodeBindings::CreateEnvironment(
}
void NodeBindings::LoadEnvironment(node::Environment* env) {
node::node_isolate = env->isolate();
if (node::use_debug_agent)
node::StartDebug(env, node::debug_wait_connect);
node::LoadEnvironment(env);
if (node::use_debug_agent)
node::EnableDebug(env);
mate::EmitEvent(env->isolate(), env->process_object(), "loaded");
}

View file

@ -50,6 +50,10 @@ double WebFrame::GetZoomFactor() const {
return blink::WebView::zoomLevelToZoomFactor(GetZoomLevel());
}
void WebFrame::SetZoomLevelLimits(double min_level, double max_level) {
web_frame_->view()->setDefaultPageScaleLimits(min_level, max_level);
}
v8::Local<v8::Value> WebFrame::RegisterEmbedderCustomElement(
const base::string16& name, v8::Local<v8::Object> options) {
blink::WebExceptionCode c = 0;
@ -102,6 +106,7 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
.SetMethod("getZoomLevel", &WebFrame::GetZoomLevel)
.SetMethod("setZoomFactor", &WebFrame::SetZoomFactor)
.SetMethod("getZoomFactor", &WebFrame::GetZoomFactor)
.SetMethod("setZoomLevelLimits", &WebFrame::SetZoomLevelLimits)
.SetMethod("registerEmbedderCustomElement",
&WebFrame::RegisterEmbedderCustomElement)
.SetMethod("registerElementResizeCallback",

View file

@ -41,6 +41,8 @@ class WebFrame : public mate::Wrappable {
double SetZoomFactor(double factor);
double GetZoomFactor() const;
void SetZoomLevelLimits(double min_level, double max_level);
v8::Local<v8::Value> RegisterEmbedderCustomElement(
const base::string16& name, v8::Local<v8::Object> options);
void RegisterElementResizeCallback(

View file

@ -102,7 +102,7 @@ metaToValue = (meta) ->
# Track delegate object's life time, and tell the browser to clean up
# when the object is GCed.
v8Util.setDestructor ret, ->
ipc.send 'ATOM_BROWSER_DEREFERENCE', meta.storeId
ipc.send 'ATOM_BROWSER_DEREFERENCE', meta.id
# Remember object's id.
v8Util.setHiddenValue ret, 'atomId', meta.id

View file

@ -0,0 +1,330 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/test/embedded_test_server/stream_listen_socket.h"
#if defined(OS_WIN)
// winsock2.h must be included first in order to ensure it is included before
// windows.h.
#include <winsock2.h>
#elif defined(OS_POSIX)
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "net/base/net_errors.h"
#endif
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/sys_byteorder.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/socket/socket_descriptor.h"
using std::string;
#if defined(OS_WIN)
typedef int socklen_t;
#endif // defined(OS_WIN)
namespace net {
namespace test_server {
namespace {
const int kReadBufSize = 4096;
} // namespace
#if defined(OS_WIN)
const int StreamListenSocket::kSocketError = SOCKET_ERROR;
#elif defined(OS_POSIX)
const int StreamListenSocket::kSocketError = -1;
#endif
StreamListenSocket::StreamListenSocket(SocketDescriptor s,
StreamListenSocket::Delegate* del)
: socket_delegate_(del),
socket_(s),
reads_paused_(false),
has_pending_reads_(false) {
#if defined(OS_WIN)
socket_event_ = WSACreateEvent();
// TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT.
WatchSocket(NOT_WAITING);
#elif defined(OS_POSIX)
wait_state_ = NOT_WAITING;
#endif
}
StreamListenSocket::~StreamListenSocket() {
CloseSocket();
#if defined(OS_WIN)
if (socket_event_) {
WSACloseEvent(socket_event_);
socket_event_ = WSA_INVALID_EVENT;
}
#endif
}
void StreamListenSocket::Send(const char* bytes,
int len,
bool append_linefeed) {
SendInternal(bytes, len);
if (append_linefeed)
SendInternal("\r\n", 2);
}
void StreamListenSocket::Send(const string& str, bool append_linefeed) {
Send(str.data(), static_cast<int>(str.length()), append_linefeed);
}
int StreamListenSocket::GetLocalAddress(IPEndPoint* address) const {
SockaddrStorage storage;
if (getsockname(socket_, storage.addr, &storage.addr_len)) {
#if defined(OS_WIN)
int err = WSAGetLastError();
#else
int err = errno;
#endif
return MapSystemError(err);
}
if (!address->FromSockAddr(storage.addr, storage.addr_len))
return ERR_ADDRESS_INVALID;
return OK;
}
int StreamListenSocket::GetPeerAddress(IPEndPoint* address) const {
SockaddrStorage storage;
if (getpeername(socket_, storage.addr, &storage.addr_len)) {
#if defined(OS_WIN)
int err = WSAGetLastError();
#else
int err = errno;
#endif
return MapSystemError(err);
}
if (!address->FromSockAddr(storage.addr, storage.addr_len))
return ERR_ADDRESS_INVALID;
return OK;
}
SocketDescriptor StreamListenSocket::AcceptSocket() {
SocketDescriptor conn = HANDLE_EINTR(accept(socket_, NULL, NULL));
if (conn == kInvalidSocket)
LOG(ERROR) << "Error accepting connection.";
else
SetNonBlocking(conn);
return conn;
}
void StreamListenSocket::SendInternal(const char* bytes, int len) {
char* send_buf = const_cast<char*>(bytes);
int len_left = len;
while (true) {
int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0));
if (sent == len_left) { // A shortcut to avoid extraneous checks.
break;
}
if (sent == kSocketError) {
#if defined(OS_WIN)
if (WSAGetLastError() != WSAEWOULDBLOCK) {
LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError();
#elif defined(OS_POSIX)
if (errno != EWOULDBLOCK && errno != EAGAIN) {
LOG(ERROR) << "send failed: errno==" << errno;
#endif
break;
}
// Otherwise we would block, and now we have to wait for a retry.
// Fall through to PlatformThread::YieldCurrentThread()
} else {
// sent != len_left according to the shortcut above.
// Shift the buffer start and send the remainder after a short while.
send_buf += sent;
len_left -= sent;
}
base::PlatformThread::YieldCurrentThread();
}
}
void StreamListenSocket::Listen() {
int backlog = 10; // TODO(erikkay): maybe don't allow any backlog?
if (listen(socket_, backlog) == -1) {
// TODO(erikkay): error handling.
LOG(ERROR) << "Could not listen on socket.";
return;
}
#if defined(OS_POSIX)
WatchSocket(WAITING_ACCEPT);
#endif
}
void StreamListenSocket::Read() {
char buf[kReadBufSize + 1]; // +1 for null termination.
int len;
do {
len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0));
if (len == kSocketError) {
#if defined(OS_WIN)
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK) {
#elif defined(OS_POSIX)
if (errno == EWOULDBLOCK || errno == EAGAIN) {
#endif
break;
} else {
// TODO(ibrar): some error handling required here.
break;
}
} else if (len == 0) {
#if defined(OS_POSIX)
// In Windows, Close() is called by OnObjectSignaled. In POSIX, we need
// to call it here.
Close();
#endif
} else {
// TODO(ibrar): maybe change DidRead to take a length instead.
DCHECK_GT(len, 0);
DCHECK_LE(len, kReadBufSize);
buf[len] = 0; // Already create a buffer with +1 length.
socket_delegate_->DidRead(this, buf, len);
}
} while (len == kReadBufSize);
}
void StreamListenSocket::Close() {
#if defined(OS_POSIX)
if (wait_state_ == NOT_WAITING)
return;
wait_state_ = NOT_WAITING;
#endif
UnwatchSocket();
socket_delegate_->DidClose(this);
}
void StreamListenSocket::CloseSocket() {
if (socket_ != kInvalidSocket) {
UnwatchSocket();
#if defined(OS_WIN)
closesocket(socket_);
#elif defined(OS_POSIX)
close(socket_);
#endif
}
}
void StreamListenSocket::WatchSocket(WaitState state) {
#if defined(OS_WIN)
WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ);
watcher_.StartWatching(socket_event_, this);
#elif defined(OS_POSIX)
// Implicitly calls StartWatchingFileDescriptor().
base::MessageLoopForIO::current()->WatchFileDescriptor(
socket_, true, base::MessageLoopForIO::WATCH_READ, &watcher_, this);
wait_state_ = state;
#endif
}
void StreamListenSocket::UnwatchSocket() {
#if defined(OS_WIN)
watcher_.StopWatching();
#elif defined(OS_POSIX)
watcher_.StopWatchingFileDescriptor();
#endif
}
// TODO(ibrar): We can add these functions into OS dependent files.
#if defined(OS_WIN)
// MessageLoop watcher callback.
void StreamListenSocket::OnObjectSignaled(HANDLE object) {
WSANETWORKEVENTS ev;
if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) {
// TODO
return;
}
// If both FD_CLOSE and FD_READ are set we only call Read().
// This will cause OnObjectSignaled to be called immediately again
// unless this socket is destroyed in Read().
if ((ev.lNetworkEvents & (FD_CLOSE | FD_READ)) == FD_CLOSE) {
Close();
// Close might have deleted this object. We should return immediately.
return;
}
// The object was reset by WSAEnumNetworkEvents. Watch for the next signal.
watcher_.StartWatching(object, this);
if (ev.lNetworkEvents == 0) {
// Occasionally the event is set even though there is no new data.
// The net seems to think that this is ignorable.
return;
}
if (ev.lNetworkEvents & FD_ACCEPT) {
Accept();
}
if (ev.lNetworkEvents & FD_READ) {
if (reads_paused_) {
has_pending_reads_ = true;
} else {
Read();
// Read might have deleted this object. We should return immediately.
}
}
}
#elif defined(OS_POSIX)
void StreamListenSocket::OnFileCanReadWithoutBlocking(int fd) {
switch (wait_state_) {
case WAITING_ACCEPT:
Accept();
break;
case WAITING_READ:
if (reads_paused_) {
has_pending_reads_ = true;
} else {
Read();
}
break;
default:
// Close() is called by Read() in the Linux case.
NOTREACHED();
break;
}
}
void StreamListenSocket::OnFileCanWriteWithoutBlocking(int fd) {
// MessagePumpLibevent callback, we don't listen for write events
// so we shouldn't ever reach here.
NOTREACHED();
}
#endif
void StreamListenSocket::PauseReads() {
DCHECK(!reads_paused_);
reads_paused_ = true;
}
void StreamListenSocket::ResumeReads() {
DCHECK(reads_paused_);
reads_paused_ = false;
if (has_pending_reads_) {
has_pending_reads_ = false;
Read();
}
}
} // namespace test_server
} // namespace net

View file

@ -0,0 +1,151 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Stream-based listen socket implementation that handles reading and writing
// to the socket, but does not handle creating the socket nor connecting
// sockets, which are handled by subclasses on creation and in Accept,
// respectively.
// StreamListenSocket handles IO asynchronously in the specified MessageLoop.
// This class is NOT thread safe. It uses WSAEVENT handles to monitor activity
// in a given MessageLoop. This means that callbacks will happen in that loop's
// thread always and that all other methods (including constructor and
// destructor) should also be called from the same thread.
#ifndef NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_
#define NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_
#include "build/build_config.h"
#if defined(OS_WIN)
#include <winsock2.h>
#endif
#include <string>
#if defined(OS_WIN)
#include "base/win/object_watcher.h"
#elif defined(OS_POSIX)
#include "base/message_loop/message_loop.h"
#endif
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/net_export.h"
#include "net/socket/socket_descriptor.h"
namespace net {
class IPEndPoint;
namespace test_server {
class StreamListenSocket :
#if defined(OS_WIN)
public base::win::ObjectWatcher::Delegate {
#elif defined(OS_POSIX)
public base::MessageLoopForIO::Watcher {
#endif
public:
~StreamListenSocket() override;
// TODO(erikkay): this delegate should really be split into two parts
// to split up the listener from the connected socket. Perhaps this class
// should be split up similarly.
class Delegate {
public:
// |server| is the original listening Socket, connection is the new
// Socket that was created.
virtual void DidAccept(StreamListenSocket* server,
scoped_ptr<StreamListenSocket> connection) = 0;
virtual void DidRead(StreamListenSocket* connection,
const char* data,
int len) = 0;
virtual void DidClose(StreamListenSocket* sock) = 0;
protected:
virtual ~Delegate() {}
};
// Send data to the socket.
void Send(const char* bytes, int len, bool append_linefeed = false);
void Send(const std::string& str, bool append_linefeed = false);
// Copies the local address to |address|. Returns a network error code.
// This method is virtual to support unit testing.
virtual int GetLocalAddress(IPEndPoint* address) const;
// Copies the peer address to |address|. Returns a network error code.
// This method is virtual to support unit testing.
virtual int GetPeerAddress(IPEndPoint* address) const;
static const int kSocketError;
protected:
enum WaitState { NOT_WAITING = 0, WAITING_ACCEPT = 1, WAITING_READ = 2 };
StreamListenSocket(SocketDescriptor s, Delegate* del);
SocketDescriptor AcceptSocket();
virtual void Accept() = 0;
void Listen();
void Read();
void Close();
void CloseSocket();
// Pass any value in case of Windows, because in Windows
// we are not using state.
void WatchSocket(WaitState state);
void UnwatchSocket();
Delegate* const socket_delegate_;
private:
friend class TransportClientSocketTest;
void SendInternal(const char* bytes, int len);
#if defined(OS_WIN)
// ObjectWatcher delegate.
void OnObjectSignaled(HANDLE object) override;
base::win::ObjectWatcher watcher_;
HANDLE socket_event_;
#elif defined(OS_POSIX)
// Called by MessagePumpLibevent when the socket is ready to do I/O.
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
WaitState wait_state_;
// The socket's libevent wrapper.
base::MessageLoopForIO::FileDescriptorWatcher watcher_;
#endif
// NOTE: This is for unit test use only!
// Pause/Resume calling Read(). Note that ResumeReads() will also call
// Read() if there is anything to read.
void PauseReads();
void ResumeReads();
const SocketDescriptor socket_;
bool reads_paused_;
bool has_pending_reads_;
DISALLOW_COPY_AND_ASSIGN(StreamListenSocket);
};
// Abstract factory that must be subclassed for each subclass of
// StreamListenSocket.
class StreamListenSocketFactory {
public:
virtual ~StreamListenSocketFactory() {}
// Returns a new instance of StreamListenSocket or NULL if an error occurred.
virtual scoped_ptr<StreamListenSocket> CreateAndListen(
StreamListenSocket::Delegate* delegate) const = 0;
};
} // namespace test_server
} // namespace net
#endif // NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_

View file

@ -0,0 +1,118 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/test/embedded_test_server/tcp_listen_socket.h"
#if defined(OS_WIN)
// winsock2.h must be included first in order to ensure it is included before
// windows.h.
#include <winsock2.h>
#elif defined(OS_POSIX)
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "net/base/net_errors.h"
#endif
#include "base/logging.h"
#include "base/sys_byteorder.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "net/base/net_util.h"
#include "net/base/winsock_init.h"
#include "net/socket/socket_descriptor.h"
using std::string;
namespace net {
namespace test_server {
// static
scoped_ptr<TCPListenSocket> TCPListenSocket::CreateAndListen(
const string& ip,
uint16 port,
StreamListenSocket::Delegate* del) {
SocketDescriptor s = CreateAndBind(ip, port);
if (s == kInvalidSocket)
return scoped_ptr<TCPListenSocket>();
scoped_ptr<TCPListenSocket> sock(new TCPListenSocket(s, del));
sock->Listen();
return sock.Pass();
}
TCPListenSocket::TCPListenSocket(SocketDescriptor s,
StreamListenSocket::Delegate* del)
: StreamListenSocket(s, del) {
}
TCPListenSocket::~TCPListenSocket() {
}
SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, uint16 port) {
SocketDescriptor s = CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s != kInvalidSocket) {
#if defined(OS_POSIX)
// Allow rapid reuse.
static const int kOn = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
#endif
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip.c_str());
addr.sin_port = base::HostToNet16(port);
if (bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
#if defined(OS_WIN)
closesocket(s);
#elif defined(OS_POSIX)
close(s);
#endif
LOG(ERROR) << "Could not bind socket to " << ip << ":" << port;
s = kInvalidSocket;
}
}
return s;
}
SocketDescriptor TCPListenSocket::CreateAndBindAnyPort(const string& ip,
uint16* port) {
SocketDescriptor s = CreateAndBind(ip, 0);
if (s == kInvalidSocket)
return kInvalidSocket;
sockaddr_in addr;
socklen_t addr_size = sizeof(addr);
bool failed = getsockname(s, reinterpret_cast<struct sockaddr*>(&addr),
&addr_size) != 0;
if (addr_size != sizeof(addr))
failed = true;
if (failed) {
LOG(ERROR) << "Could not determine bound port, getsockname() failed";
#if defined(OS_WIN)
closesocket(s);
#elif defined(OS_POSIX)
close(s);
#endif
return kInvalidSocket;
}
*port = base::NetToHost16(addr.sin_port);
return s;
}
void TCPListenSocket::Accept() {
SocketDescriptor conn = AcceptSocket();
if (conn == kInvalidSocket)
return;
scoped_ptr<TCPListenSocket> sock(new TCPListenSocket(conn, socket_delegate_));
#if defined(OS_POSIX)
sock->WatchSocket(WAITING_READ);
#endif
socket_delegate_->DidAccept(this, sock.Pass());
}
} // namespace test_server
} // namespace net

View file

@ -0,0 +1,55 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_
#define NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_
#include <string>
#include "base/basictypes.h"
#include "net/base/net_export.h"
#include "net/socket/socket_descriptor.h"
#include "net/test/embedded_test_server/stream_listen_socket.h"
namespace net {
namespace test_server {
// Implements a TCP socket.
class TCPListenSocket : public StreamListenSocket {
public:
~TCPListenSocket() override;
// Listen on port for the specified IP address. Use 127.0.0.1 to only
// accept local connections.
static scoped_ptr<TCPListenSocket> CreateAndListen(
const std::string& ip,
uint16 port,
StreamListenSocket::Delegate* del);
protected:
TCPListenSocket(SocketDescriptor s, StreamListenSocket::Delegate* del);
// Implements StreamListenSocket::Accept.
void Accept() override;
private:
friend class EmbeddedTestServer;
friend class TCPListenSocketTester;
// Get raw TCP socket descriptor bound to ip:port.
static SocketDescriptor CreateAndBind(const std::string& ip, uint16 port);
// Get raw TCP socket descriptor bound to ip and return port it is bound to.
static SocketDescriptor CreateAndBindAnyPort(const std::string& ip,
uint16* port);
DISALLOW_COPY_AND_ASSIGN(TCPListenSocket);
};
} // namespace test_server
} // namespace net
#endif // NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_

View file

@ -40,6 +40,8 @@ Modules for the main process:
* [power-monitor](api/power-monitor.md)
* [power-save-blocker](api/power-save-blocker.md)
* [protocol](api/protocol.md)
* [session](api/session.md)
* [webContents](api/web-contents.md)
* [tray](api/tray.md)
Modules for the renderer process (web page):

View file

@ -2,7 +2,8 @@
The `app` module is responsible for controlling the application's lifecycle.
The following example shows how to quit the application when the last window is closed:
The following example shows how to quit the application when the last window is
closed:
```javascript
var app = require('app');
@ -11,30 +12,36 @@ app.on('window-all-closed', function() {
});
```
## Event: will-finish-launching
## Events
The `app` object emits the following events:
### Event: 'will-finish-launching'
Emitted when the application has finished basic startup. On Windows and Linux,
the `will-finish-launching` event is the same as the `ready` event; on OS X,
this event represents the `applicationWillFinishLaunching` notification of `NSApplication`.
You would usually set up listeners for the `open-file` and `open-url` events here,
and start the crash reporter and auto updater.
this event represents the `applicationWillFinishLaunching` notification of
`NSApplication`. You would usually set up listeners for the `open-file` and
`open-url` events here, and start the crash reporter and auto updater.
In most cases, you should just do everything in the `ready` event handler.
## Event: ready
### Event: 'ready'
Emitted when Electron has finished initialization.
## Event: window-all-closed
### Event: 'window-all-closed'
Emitted when all windows have been closed.
This event is only emitted when the application is not going to quit. If the
user pressed `Cmd + Q`, or the developer called `app.quit()`, Electron would
user pressed `Cmd + Q`, or the developer called `app.quit()`, Electron will
first try to close all the windows and then emit the `will-quit` event, and in
this case the `window-all-closed` event would not be emitted.
## Event: before-quit
### Event: 'before-quit'
Returns:
* `event` Event
@ -42,7 +49,9 @@ Emitted before the application starts closing its windows.
Calling `event.preventDefault()` will prevent the default behaviour, which is
terminating the application.
## Event: will-quit
### Event: 'will-quit'
Returns:
* `event` Event
@ -50,28 +59,32 @@ Emitted when all windows have been closed and the application will quit.
Calling `event.preventDefault()` will prevent the default behaviour, which is
terminating the application.
See the description of the `window-all-closed` event for the differences between the `will-quit`
and `window-all-closed` events.
See the description of the `window-all-closed` event for the differences between
the `will-quit` and `window-all-closed` events.
## Event: quit
### Event: 'quit'
Emitted when the application is quitting.
## Event: open-file
### Event: 'open-file'
Returns:
* `event` Event
* `path` String
Emitted when the user wants to open a file with the application. The `open-file` event
is usually emitted when the application is already open and the OS wants to reuse the
application to open the file. `open-file` is also emitted when a file is dropped onto the
dock and the application is not yet running. Make sure to listen for the `open-file`
event very early in your application startup to handle this case (even before the
`ready` event is emitted).
Emitted when the user wants to open a file with the application. The `open-file`
event is usually emitted when the application is already open and the OS wants
to reuse the application to open the file. `open-file` is also emitted when a
file is dropped onto the dock and the application is not yet running. Make sure
to listen for the `open-file` event very early in your application startup to
handle this case (even before the `ready` event is emitted).
You should call `event.preventDefault()` if you want to handle this event.
## Event: open-url
### Event: 'open-url'
Returns:
* `event` Event
* `url` String
@ -81,20 +94,24 @@ must be registered to be opened by your application.
You should call `event.preventDefault()` if you want to handle this event.
## Event: activate-with-no-open-windows
### Event: 'activate-with-no-open-windows'
Emitted when the application is activated while there are no open windows, which
usually happens when the user has closed all of the application's windows and then
clicks on the application's dock icon.
usually happens when the user has closed all of the application's windows and
then clicks on the application's dock icon.
## Event: browser-window-blur
### Event: 'browser-window-blur'
Returns:
* `event` Event
* `window` BrowserWindow
Emitted when a [browserWindow](browser-window.md) gets blurred.
## Event: browser-window-focus
### Event: 'browser-window-focus'
Returns:
* `event` Event
* `window` BrowserWindow
@ -105,6 +122,8 @@ Emitted when a [browserWindow](browser-window.md) gets focused.
Emitted when a client certificate is requested.
Returns:
* `event` Event
* `webContents` [WebContents](browser-window.md#class-webcontents)
* `url` String
@ -113,37 +132,43 @@ Emitted when a client certificate is requested.
* `issuerName` Issuer's Common Name
* `callback` Function
```
```javascript
app.on('select-certificate', function(event, host, url, list, callback) {
event.preventDefault();
callback(list[0]);
})
```
`url` corresponds to the navigation entry requesting the client certificate.
`callback` needs to be called with an entry filtered from the list.
`event.preventDefault()` prevents the application from using the first certificate
from the store.
The `url` corresponds to the navigation entry requesting the client certificate
and `callback` needs to be called with an entry filtered from the list. Using
`event.preventDefault()` prevents the application from using the first
certificate from the store.
### Event: 'gpu-process-crashed'
Emitted when the gpu process crashes.
## app.quit()
## Methods
Try to close all windows. The `before-quit` event will first be emitted. If all
The `app` object has the following methods:
**Note** Some methods are only available on specific operating systems and are labeled as such.
### `app.quit()`
Try to close all windows. The `before-quit` event will emitted first. If all
windows are successfully closed, the `will-quit` event will be emitted and by
default the application will terminate.
This method guarantees that all `beforeunload` and `unload` event handlers are correctly
executed. It is possible that a window cancels the quitting by returning
`false` in the `beforeunload` event handler.
This method guarantees that all `beforeunload` and `unload` event handlers are
correctly executed. It is possible that a window cancels the quitting by
returning `false` in the `beforeunload` event handler.
## app.getAppPath()
### `app.getAppPath()`
Returns the current application directory.
## app.getPath(name)
### `app.getPath(name)`
* `name` String
@ -152,25 +177,25 @@ failure an `Error` is thrown.
You can request the following paths by the name:
* `home`: User's home directory
* `appData`: Per-user application data directory, which by default points to:
* `home` User's home directory.
* `appData` Per-user application data directory, which by default points to:
* `%APPDATA%` on Windows
* `$XDG_CONFIG_HOME` or `~/.config` on Linux
* `~/Library/Application Support` on OS X
* `userData`: The directory for storing your app's configuration files, which by
default it is the `appData` directory appended with your app's name
* `cache`: Per-user application cache directory, which by default points to:
* `userData` The directory for storing your app's configuration files, which by
default it is the `appData` directory appended with your app's name.
* `cache` Per-user application cache directory, which by default points to:
* `%APPDATA%` on Windows (which doesn't have a universal cache location)
* `$XDG_CACHE_HOME` or `~/.cache` on Linux
* `~/Library/Caches` on OS X
* `userCache`: The directory for placing your app's caches, by default it is the
`cache` directory appended with your app's name
* `temp`: Temporary directory
* `userDesktop`: The current user's Desktop directory
* `exe`: The current executable file
* `module`: The `libchromiumcontent` library
* `userCache` The directory for placing your app's caches, by default it is the
`cache` directory appended with your app's name.
* `temp` Temporary directory.
* `userDesktop` The current user's Desktop directory.
* `exe` The current executable file.
* `module` The `libchromiumcontent` library.
## app.setPath(name, path)
### `app.setPath(name, path)`
* `name` String
* `path` String
@ -179,19 +204,19 @@ Overrides the `path` to a special directory or file associated with `name`. If
the path specifies a directory that does not exist, the directory will be
created by this method. On failure an `Error` is thrown.
You can only override paths of `name`s defined in `app.getPath`.
You can only override paths of a `name` defined in `app.getPath`.
By default, web pages' cookies and caches will be stored under the `userData`
By default, web pages's cookies and caches will be stored under the `userData`
directory. If you want to change this location, you have to override the
`userData` path before the `ready` event of the `app` module is emitted.
## app.getVersion()
### `app.getVersion()`
Returns the version of the loaded application. If no version is found in the
application's `package.json` file, the version of the current bundle or executable is
returned.
application's `package.json` file, the version of the current bundle or
executable is returned.
## app.getName()
### `app.getName()`
Returns the current application's name, which is the name in the application's
`package.json` file.
@ -201,7 +226,7 @@ to the npm modules spec. You should usually also specify a `productName`
field, which is your application's full capitalized name, and which will be
preferred over `name` by Electron.
## app.resolveProxy(url, callback)
### `app.resolveProxy(url, callback)`
* `url` URL
* `callback` Function
@ -209,7 +234,7 @@ preferred over `name` by Electron.
Resolves the proxy information for `url`. The `callback` will be called with
`callback(proxy)` when the request is performed.
## app.addRecentDocument(path)
### `app.addRecentDocument(path)`
* `path` String
@ -218,11 +243,11 @@ Adds `path` to the recent documents list.
This list is managed by the OS. On Windows you can visit the list from the task
bar, and on OS X you can visit it from dock menu.
## app.clearRecentDocuments()
### `app.clearRecentDocuments()`
Clears the recent documents list.
## app.setUserTasks(tasks)
### `app.setUserTasks(tasks)` _Windows_
* `tasks` Array - Array of `Task` objects
@ -230,92 +255,78 @@ Adds `tasks` to the [Tasks][tasks] category of the JumpList on Windows.
`tasks` is an array of `Task` objects in following format:
* `Task` Object
* `program` String - Path of the program to execute, usually you should
specify `process.execPath` which opens the current program
* `arguments` String - The command line arguments when `program` is
executed
* `title` String - The string to be displayed in a JumpList
* `description` String - Description of this task
* `iconPath` String - The absolute path to an icon to be displayed in a
JumpList, which can be an arbitrary resource file that contains an icon. You can
usually specify `process.execPath` to show the icon of the program
* `iconIndex` Integer - The icon index in the icon file. If an icon file
consists of two or more icons, set this value to identify the icon. If an
icon file consists of one icon, this value is 0
`Task` Object
* `program` String - Path of the program to execute, usually you should
specify `process.execPath` which opens the current program.
* `arguments` String - The command line arguments when `program` is
executed.
* `title` String - The string to be displayed in a JumpList.
* `description` String - Description of this task.
* `iconPath` String - The absolute path to an icon to be displayed in a
JumpList, which can be an arbitrary resource file that contains an icon. You
can usually specify `process.execPath` to show the icon of the program.
* `iconIndex` Integer - The icon index in the icon file. If an icon file
consists of two or more icons, set this value to identify the icon. If an
icon file consists of one icon, this value is 0.
**Note:** This API is only available on Windows.
## app.commandLine.appendSwitch(switch, [value])
### `app.commandLine.appendSwitch(switch[, value])`
Append a switch [with optional value] to Chromium's command line.
Append a switch (with optional `value`) to Chromium's command line.
**Note:** This will not affect `process.argv`, and is mainly used by developers
to control some low-level Chromium behaviors.
## app.commandLine.appendArgument(value)
### `app.commandLine.appendArgument(value)`
Append an argument to Chromium's command line. The argument will be quoted correctly.
Append an argument to Chromium's command line. The argument will be quoted
correctly.
**Note:** This will not affect `process.argv`.
## app.dock.bounce([type])
### `app.dock.bounce([type])` _OS X_
* `type` String - Can be `critical` or `informational`. The default is
* `type` String (optional) - Can be `critical` or `informational`. The default is
`informational`
When `critical` is passed, the dock icon will bounce until either the
application becomes active or the request is canceled.
When `informational` is passed, the dock icon will bounce for one second. However,
the request remains active until either the application becomes active or
the request is canceled.
When `informational` is passed, the dock icon will bounce for one second.
However, the request remains active until either the application becomes active
or the request is canceled.
An ID representing the request is returned.
Returns an ID representing the request.
**Note:** This API is only available on OS X.
## app.dock.cancelBounce(id)
### `app.dock.cancelBounce(id)` _OS X_
* `id` Integer
Cancel the bounce of `id`.
**Note:** This API is only available on OS X.
## app.dock.setBadge(text)
### `app.dock.setBadge(text)` _OS X_
* `text` String
Sets the string to be displayed in the docks badging area.
**Note:** This API is only available on OS X.
## app.dock.getBadge()
### `app.dock.getBadge()` _OS X_
Returns the badge string of the dock.
**Note:** This API is only available on OS X.
## app.dock.hide()
### `app.dock.hide()` _OS X_
Hides the dock icon.
**Note:** This API is only available on OS X.
## app.dock.show()
### `app.dock.show()` _OS X_
Shows the dock icon.
**Note:** This API is only available on OS X.
## app.dock.setMenu(menu)
### `app.dock.setMenu(menu)` _OS X_
* `menu` Menu
Sets the application's [dock menu][dock-menu].
**Note:** This API is only available on OS X.
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks

View file

@ -1,4 +1,4 @@
# auto-updater
# autoUpdater
**This module has only been implemented for OS X.**
@ -98,27 +98,35 @@ appropriate format.
`pub_date` (if present) must be formatted according to ISO 8601.
## Event: error
## Events
The `autoUpdater` object emits the following events:
### Event: 'error'
Returns:
* `event` Event
* `message` String
Emitted when there is an error while updating.
## Event: checking-for-update
### Event: 'checking-for-update'
Emitted when checking if an update has started.
## Event: update-available
### Event: 'update-available'
Emitted when there is an available update. The update is downloaded
automatically.
## Event: update-not-available
### Event: 'update-not-available'
Emitted when there is no available update.
## Event: update-downloaded
### Event: 'update-downloaded'
Returns:
* `event` Event
* `releaseNotes` String
@ -127,17 +135,21 @@ Emitted when there is no available update.
* `updateUrl` String
* `quitAndUpdate` Function
Emitted when an update has been downloaded. Calling `quitAndUpdate()` will restart
the application and install the update.
Emitted when an update has been downloaded. Calling `quitAndUpdate()` will
restart the application and install the update.
## autoUpdater.setFeedUrl(url)
## Methods
The `autoUpdater` object has the following methods:
### `autoUpdater.setFeedUrl(url)`
* `url` String
Set the `url` and initialize the auto updater. The `url` cannot be changed
once it is set.
## autoUpdater.checkForUpdates()
### `autoUpdater.checkForUpdates()`
Ask the server whether there is an update. You must call `setFeedUrl` before
using this API.

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
# clipboard
The `clipboard` provides methods to perform copy and paste operations. The following example
shows how to write a string to the clipboard:
The `clipboard` module provides methods to perform copy and paste operations.
The following example shows how to write a string to the clipboard:
```javascript
var clipboard = require('clipboard');
@ -17,59 +17,67 @@ clipboard.writeText('Example String', 'selection');
console.log(clipboard.readText('selection'));
```
## clipboard.readText([type])
## Methods
* `type` String
The `clipboard` module has the following methods:
**Note:** Experimental APIs are marked as such and could be removed in future.
### `clipboard.readText([type])`
* `type` String (optional)
Returns the content in the clipboard as plain text.
## clipboard.writeText(text[, type])
### `clipboard.writeText(text[, type])`
* `text` String
* `type` String
* `type` String (optional)
Writes the `text` into the clipboard as plain text.
## clipboard.readHtml([type])
### `clipboard.readHtml([type])`
* `type` String
* `type` String (optional)
Returns the content in the clipboard as markup.
## clipboard.writeHtml(markup[, type])
### `clipboard.writeHtml(markup[, type])`
* `markup` String
* `type` String
* `type` String (optional)
Writes `markup` into the clipboard.
Writes `markup` to the clipboard.
## clipboard.readImage([type])
### `clipboard.readImage([type])`
* `type` String
* `type` String (optional)
Returns the content in the clipboard as a [NativeImage](native-image.md).
## clipboard.writeImage(image[, type])
### `clipboard.writeImage(image[, type])`
* `image` [NativeImage](native-image.md)
* `type` String
* `type` String (optional)
Writes `image` into the clipboard.
Writes `image` to the clipboard.
## clipboard.clear([type])
### `clipboard.clear([type])`
* `type` String
* `type` String (optional)
Clears the clipboard.
Clears the clipboard content.
## clipboard.availableFormats([type])
### `clipboard.availableFormats([type])`
Returns an array of supported `format` for the clipboard `type`.
* `type` String (optional)
## clipboard.has(data[, type])
Returns an array of supported formats for the clipboard `type`.
### `clipboard.has(data[, type])` _Experimental_
* `data` String
* `type` String
* `type` String (optional)
Returns whether the clipboard supports the format of specified `data`.
@ -78,27 +86,23 @@ var clipboard = require('clipboard');
console.log(clipboard.has('<p>selection</p>'));
```
**Note:** This API is experimental and could be removed in future.
## clipboard.read(data[, type])
### `clipboard.read(data[, type])` _Experimental_
* `data` String
* `type` String
* `type` String (optional)
Reads `data` from the clipboard.
**Note:** This API is experimental and could be removed in future.
## clipboard.write(data[, type])
### `clipboard.write(data[, type])`
* `data` Object
* `text` String
* `html` String
* `image` [NativeImage](native-image.md)
* `type` String
* `type` String (optional)
```javascript
var clipboard = require('clipboard');
clipboard.write({text: 'test', html: "<b>test</b>"});
```
Writes `data` into clipboard.
Writes `data` to the clipboard.

View file

@ -1,12 +1,13 @@
# content-tracing
# contentTracing
The `content-trace` module is used to collect tracing data generated by the
The `content-tracing` module is used to collect tracing data generated by the
underlying Chromium content module. This module does not include a web interface
so you need to open `chrome://tracing/` in a Chrome browser and load the generated
file to view the result.
so you need to open `chrome://tracing/` in a Chrome browser and load the
generated file to view the result.
```javascript
var tracing = require('content-tracing');
var contentTracing = require('content-tracing');
tracing.startRecording('*', tracing.DEFAULT_OPTIONS, function() {
console.log('Tracing started');
@ -18,17 +19,21 @@ tracing.startRecording('*', tracing.DEFAULT_OPTIONS, function() {
});
```
## tracing.getCategories(callback)
## Methods
The `content-tracing` module has the following methods:
### `contentTracing.getCategories(callback)`
* `callback` Function
Get a set of category groups. The category groups can change as new code paths
are reached.
Once all child processes have acked to the `getCategories` request, `callback`
is invoked with an array of category groups.
Once all child processes have acknowledged the `getCategories` request the
`callback` is invoked with an array of category groups.
## tracing.startRecording(categoryFilter, traceOptions, callback)
### `contentTracing.startRecording(categoryFilter, traceOptions, callback)`
* `categoryFilter` String
* `traceOptions` String
@ -36,9 +41,9 @@ is invoked with an array of category groups.
Start recording on all processes.
Recording begins immediately locally, and asynchronously on child processes
as soon as they receive the EnableRecording request. Once all child processes
have acked to the `startRecording` request, `callback` will be called back.
Recording begins immediately locally and asynchronously on child processes
as soon as they receive the EnableRecording request. The `callback` will be
called once all child processes have acknowledged the `startRecording` request.
`categoryFilter` is a filter to control what category groups should be
traced. A filter can have an optional `-` prefix to exclude category groups
@ -51,8 +56,8 @@ Examples:
* `test_MyTest*,test_OtherStuff`,
* `"-excluded_category1,-excluded_category2`
`traceOptions` controls what kind of tracing is enabled, it is a comma-delimited list.
Possible options are:
`traceOptions` controls what kind of tracing is enabled, it is a comma-delimited
list. Possible options are:
* `record-until-full`
* `record-continuously`
@ -62,34 +67,34 @@ Possible options are:
The first 3 options are trace recoding modes and hence mutually exclusive.
If more than one trace recording modes appear in the `traceOptions` string,
the last one takes precedence. If none of the trace recording mode is specified,
recording mode is `record-until-full`.
the last one takes precedence. If none of the trace recording modes are
specified, recording mode is `record-until-full`.
The trace option will first be reset to the default option (record_mode set to
`record-until-full`, enable_sampling and enable_systrace set to false)
The trace option will first be reset to the default option (`record_mode` set to
`record-until-full`, `enable_sampling` and `enable_systrace` set to `false`)
before options parsed from `traceOptions` are applied on it.
## tracing.stopRecording(resultFilePath, callback)
### `contentTracing.stopRecording(resultFilePath, callback)`
* `resultFilePath` String
* `callback` Function
Stop recording on all processes.
Child processes typically are caching trace data and only rarely flush and send
trace data back to the main process. That is because it may be an expensive
operation to send the trace data over IPC, and we would like to avoid much
runtime overhead of tracing. So, to end tracing, we must asynchronously ask all
child processes to flush any pending trace data.
Child processes typically cache trace data and only rarely flush and send
trace data back to the main process. This helps to minimize the runtime overhead
of tracing since sending trace data over IPC can be an expensive operation. So,
to end tracing, we must asynchronously ask all child processes to flush any
pending trace data.
Once all child processes have acked to the `stopRecording` request, `callback`
will be called back with a file that contains the traced data.
Once all child processes have acknowledged the `stopRecording` request,
`callback` will be called with a file that contains the traced data.
Trace data will be written into `resultFilePath` if it is not empty, or into a
Trace data will be written into `resultFilePath` if it is not empty or into a
temporary file. The actual file path will be passed to `callback` if it's not
null.
`null`.
## tracing.startMonitoring(categoryFilter, traceOptions, callback)
### `contentTracing.startMonitoring(categoryFilter, traceOptions, callback)`
* `categoryFilter` String
* `traceOptions` String
@ -97,46 +102,47 @@ null.
Start monitoring on all processes.
Monitoring begins immediately locally, and asynchronously on child processes as
Monitoring begins immediately locally and asynchronously on child processes as
soon as they receive the `startMonitoring` request.
Once all child processes have acked to the `startMonitoring` request,
`callback` will be called back.
Once all child processes have acknowledged the `startMonitoring` request the
`callback` will be called.
## tracing.stopMonitoring(callback);
### `contentTracing.stopMonitoring(callback)`
* `callback` Function
Stop monitoring on all processes.
Once all child processes have acked to the `stopMonitoring` request, `callback`
is called back.
Once all child processes have acknowledged the `stopMonitoring` request the
`callback` is called.
## tracing.captureMonitoringSnapshot(resultFilePath, callback)
### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)`
* `resultFilePath` String
* `callback` Function
Get the current monitoring traced data.
Child processes typically are caching trace data and only rarely flush and send
trace data back to the main process. That is because it may be an expensive
operation to send the trace data over IPC, and we would like to avoid unneeded
runtime overhead of tracing. So, to end tracing, we must asynchronously ask all
child processes to flush any pending trace data.
Child processes typically cache trace data and only rarely flush and send
trace data back to the main process. This is because it may be an expensive
operation to send the trace data over IPC and we would like to avoid unneeded
runtime overhead from tracing. So, to end tracing, we must asynchronously ask
all child processes to flush any pending trace data.
Once all child processes have acked to the `captureMonitoringSnapshot` request,
the `callback` will be invoked with a file that contains the traced data.
Once all child processes have acknowledged the `captureMonitoringSnapshot`
request the `callback` will be called with a file that contains the traced data.
## tracing.getTraceBufferUsage(callback)
### `contentTracing.getTraceBufferUsage(callback)`
* `callback` Function
Get the maximum across processes of trace buffer percent full state. When the
TraceBufferUsage value is determined, the `callback` is called.
Get the maximum usage across processes of trace buffer as a percentage of the
full state. When the TraceBufferUsage value is determined the `callback` is
called.
## tracing.setWatchEvent(categoryName, eventName, callback)
### `contentTracing.setWatchEvent(categoryName, eventName, callback)`
* `categoryName` String
* `eventName` String
@ -145,7 +151,7 @@ TraceBufferUsage value is determined, the `callback` is called.
`callback` will will be called every time the given event occurs on any
process.
## tracing.cancelWatchEvent()
### `contentTracing.cancelWatchEvent()`
Cancel the watch event. If tracing is enabled, this may race with the watch
event callback.
Cancel the watch event. This may lead to a race condition with the watch event
callback if tracing is enabled.

View file

@ -1,9 +1,13 @@
# crash-reporter
# crashReporter
The following is an example of automatically submitting a crash report to a remote server:
The `crash-reporter` module enables sending your app's crash reports.
The following is an example of automatically submitting a crash report to a
remote server:
```javascript
crashReporter = require('crash-reporter');
var crashReporter = require('crash-reporter');
crashReporter.start({
productName: 'YourName',
companyName: 'YourCompany',
@ -12,49 +16,60 @@ crashReporter.start({
});
```
## crashReporter.start(options)
## Methods
* `options` Object
* `productName` String, default: Electron
* `companyName` String, default: GitHub, Inc
* `submitUrl` String, default: http://54.249.141.255:1127/post
* URL that crash reports will be sent to as POST
* `autoSubmit` Boolean, default: true
* Send the crash report without user interaction
* `ignoreSystemCrashHandler` Boolean, default: false
* `extra` Object
* An object you can define that will be sent along with the report.
* Only string properties are sent correctly.
* Nested objects are not supported.
The `crash-reporter` module has the following methods:
Developers are required to call this method before using other `crashReporter` APIs.
### `crashReporter.start(options)`
`options` Object, properties:
* `productName` String, default: Electron.
* `companyName` String, default: GitHub, Inc.
* `submitUrl` String, default: http://54.249.141.255:1127/post.
* URL that crash reports will be sent to as POST.
* `autoSubmit` Boolean, default: `true`.
* Send the crash report without user interaction.
* `ignoreSystemCrashHandler` Boolean, default: `false`.
* `extra` Object
* An object you can define that will be sent along with the report.
* Only string properties are sent correctly.
* Nested objects are not supported.
You are required to call this method before using other `crashReporter`
APIs.
**Note:** On OS X, Electron uses a new `crashpad` client, which is different
from `breakpad` on Windows and Linux. To enable the crash collection feature,
you are required to call `crashReporter.start` API to initialize `crashpad` in the
main process and in each renderer process from which you wish to collect crash reports.
you are required to call the `crashReporter.start` API to initialize `crashpad`
in the main process and in each renderer process from which you wish to collect
crash reports.
## crashReporter.getLastCrashReport()
### `crashReporter.getLastCrashReport()`
Returns the date and ID of the last crash report. If no crash reports have been
sent or the crash reporter has not been started, `null` is returned.
## crashReporter.getUploadedReports()
### `crashReporter.getUploadedReports()`
Returns all uploaded crash reports. Each report contains the date and uploaded ID.
Returns all uploaded crash reports. Each report contains the date and uploaded
ID.
# crash-reporter payload
## crash-reporter Payload
The crash reporter will send the following data to the `submitUrl` as `POST`:
* `rept` String - e.g. 'electron-crash-service'
* `ver` String - The version of Electron
* `platform` String - e.g. 'win32'
* `process_type` String - e.g. 'renderer'
* `rept` String - e.g. 'electron-crash-service'.
* `ver` String - The version of Electron.
* `platform` String - e.g. 'win32'.
* `process_type` String - e.g. 'renderer'.
* `ptime` Number
* `_version` String - The version in `package.json`
* `_productName` String - The product name in the `crashReporter` `options` object
* `prod` String - Name of the underlying product. In this case Electron
* `_companyName` String - The company name in the `crashReporter` `options` object
* `upload_file_minidump` File - The crashreport as file
* All level one properties of the `extra` object in the `crashReporter` `options` object
* `_version` String - The version in `package.json`.
* `_productName` String - The product name in the `crashReporter` `options`
object.
* `prod` String - Name of the underlying product. In this case Electron.
* `_companyName` String - The company name in the `crashReporter` `options`
object.
* `upload_file_minidump` File - The crash report as file.
* All level one properties of the `extra` object in the `crashReporter`.
`options` object

View file

@ -1,12 +1,13 @@
# dialog
The `dialog` module provides APIs to show native system dialogs, so web
applications can deliver the same user experience as native applications.
The `dialog` module provides APIs to show native system dialogs, such as opening
files or alerting, so web applications can deliver the same user experience as
native applications.
An example of showing a dialog to select multiple files and directories:
```javascript
var win = ...; // window in which to show the dialog
var win = ...; // BrowserWindow in which to show the dialog
var dialog = require('dialog');
console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', 'multiSelections' ]}));
```
@ -15,23 +16,27 @@ console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', '
have to do is provide a `BrowserWindow` reference in the `browserWindow`
parameter.
## dialog.showOpenDialog([browserWindow], [options], [callback])
## Methods
* `browserWindow` BrowserWindow
* `options` Object
The `dialog` module has the following methods:
### `dialog.showOpenDialog([browserWindow][, options][, callback])`
* `browserWindow` BrowserWindow (optional)
* `options` Object (optional)
* `title` String
* `defaultPath` String
* `filters` Array
* `properties` Array - Contains which features the dialog should use, can
contain `openFile`, `openDirectory`, `multiSelections` and
`createDirectory`
* `callback` Function
* `callback` Function (optional)
On success, returns an array of file paths chosen by the user, otherwise
returns `undefined`.
On success this method returns an array of file paths chosen by the user,
otherwise it returns `undefined`.
The `filters` specifies an array of file types that can be displayed or
selected, an example is:
selected when you want to limit the user to a specific type. For example:
```javascript
{
@ -44,28 +49,28 @@ selected, an example is:
}
```
The `extensions` array should contain extensions without wildcards or dots (e.g.
`'png'` is good, `'.png'` and `'*.png'` are bad). To show all files, use the
`'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the
`'*'` wildcard (no other wildcard is supported).
If a `callback` is passed, the API call would be asynchronous and the result
would be passed via `callback(filenames)`
If a `callback` is passed, the API call will be asynchronous and the result
wil be passed via `callback(filenames)`
**Note:** On Windows and Linux, an open dialog can not be both a file selector
**Note:** On Windows and Linux an open dialog can not be both a file selector
and a directory selector, so if you set `properties` to
`['openFile', 'openDirectory']` on these platforms, a directory selector will be
shown.
## dialog.showSaveDialog([browserWindow], [options], [callback])
### `dialog.showSaveDialog([browserWindow][, options][, callback])`
* `browserWindow` BrowserWindow
* `options` Object
* `browserWindow` BrowserWindow (optional)
* `options` Object (optional)
* `title` String
* `defaultPath` String
* `filters` Array
* `callback` Function
* `callback` Function (optional)
On success, returns the path of the file chosen by the user, otherwise returns
`undefined`.
On success this method returns the path of the file chosen by the user,
otherwise it returns `undefined`.
The `filters` specifies an array of file types that can be displayed, see
`dialog.showOpenDialog` for an example.
@ -73,39 +78,39 @@ The `filters` specifies an array of file types that can be displayed, see
If a `callback` is passed, the API call will be asynchronous and the result
will be passed via `callback(filename)`
## dialog.showMessageBox([browserWindow], options, [callback])
### `dialog.showMessageBox([browserWindow][, options][, callback])`
* `browserWindow` BrowserWindow
* `options` Object
* `browserWindow` BrowserWindow (optional)
* `options` Object (optional)
* `type` String - Can be `"none"`, `"info"`, `"error"`, `"question"` or
`"warning"`. On Windows, "question" displays the same icon as "info", unless
if you set an icon using the "icon" option
* `buttons` Array - Array of texts for buttons
* `title` String - Title of the message box, some platforms will not show it
* `message` String - Content of the message box
* `detail` String - Extra information of the message
you set an icon using the "icon" option.
* `buttons` Array - Array of texts for buttons.
* `title` String - Title of the message box, some platforms will not show it.
* `message` String - Content of the message box.
* `detail` String - Extra information of the message.
* `icon` [NativeImage](native-image.md)
* `cancelId` Integer - The value will be returned when user cancels the dialog
instead of clicking the buttons of the dialog. By default it is the index
of the buttons that have "cancel" or "no" as label, or 0 if there is no such
buttons. On OS X and Windows the index of "Cancel" button will always be
used as `cancelId`, not matter whether it is already specified
* `noLink` Boolean - On Windows Electron would try to figure out which ones of
used as `cancelId`, not matter whether it is already specified.
* `noLink` Boolean - On Windows Electron will try to figure out which one of
the `buttons` are common buttons (like "Cancel" or "Yes"), and show the
others as command links in the dialog, this can make the dialog appear in
others as command links in the dialog. This can make the dialog appear in
the style of modern Windows apps. If you don't like this behavior, you can
specify `noLink` to `true`
set `noLink` to `true`.
* `callback` Function
Shows a message box, it will block until the message box is closed. It returns
the index of the clicked button.
Shows a message box, it will block the process until the message box is closed.
It returns the index of the clicked button.
If a `callback` is passed, the API call will be asynchronous and the result
will be passed via `callback(response)`
will be passed via `callback(response)`.
## dialog.showErrorBox(title, content)
### `dialog.showErrorBox(title, content)`
Runs a modal dialog that shows an error message.
Displays a modal dialog that shows an error message.
This API can be called safely before the `ready` event of `app` module emits, it
is usually used to report errors in early stage of startup.
This API can be called safely before the `ready` event the `app` module emits,
it is usually used to report errors in early stage of startup.

View file

@ -1,11 +1,11 @@
# `File` object
The DOM's File interface provides abstraction around native files, in order to
let users work on native files directly with HTML5 file API, Electron has
added a `path` attribute to `File` interface which exposes the file's real path
on filesystem.
The DOM's File interface provides abstraction around native files in order to
let users work on native files directly with the HTML5 file API. Electron has
added a `path` attribute to the `File` interface which exposes the file's real
path on filesystem.
Example on getting real path of a dragged file:
Example on getting a real path from a dragged-onto-the-app file:
```html
<div id="holder">

View file

@ -1,10 +1,10 @@
# Frameless window
# Frameless Window
A frameless window is a window that has no chrome.
A frameless window is a window that has no [chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of the window, like toolbars, that are not a part of the webp page. These are options on the [`BrowserWindow`](browser-window.md) class.
## Create a frameless window
To create a frameless window, you only need to specify `frame` to `false` in
To create a frameless window, you need to set `frame` to `false` in
[BrowserWindow](browser-window.md)'s `options`:
@ -24,19 +24,22 @@ var win = new BrowserWindow({ transparent: true, frame: false });
### Limitations
* You can not click through the transparent area, we are going to introduce an
* You can not click through the transparent area. We are going to introduce 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).
* Transparent window is not resizable, setting `resizable` to `true` may make
transparent window stop working on some platforms.
* Transparent windows are not resizable. Setting `resizable` to `true` may make
a transparent window stop working on some platforms.
* The `blur` filter only applies to the web page, so there is no way to apply
blur effect to the content below the window.
* On Windows transparent window will not work when DWM is disabled.
blur effect to the content below the window (i.e. other applications open on
the user's system).
* On Windows operation shystems, transparent windows will not work when DWM is
disabled.
* On Linux users have to put `--enable-transparent-visuals --disable-gpu` in
command line to disable GPU and allow ARGB to make transparent window, this is
caused by an upstream bug that [alpha channel doesn't work on some NVidia
drivers](https://code.google.com/p/chromium/issues/detail?id=369209) on Linux.
* On Mac the native window shadow will not show for transparent window.
the command line to disable GPU and allow ARGB to make transparent window,
this is caused by an upstream bug that [alpha channel doesn't work on some
NVidia drivers](https://code.google.com/p/chromium/issues/detail?id=369209) on
Linux.
* On Mac the native window shadow will not be shown on a transparent window.
## Draggable region
@ -44,7 +47,7 @@ By default, the frameless window is non-draggable. Apps need to specify
`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
(like the OS's standard titlebar), and apps can also use
`-webkit-app-region: no-drag` to exclude the non-draggable area from the
draggable region. Note that only rectangular shape is currently supported.
draggable region. Note that only rectangular shapes are currently supported.
To make the whole window draggable, you can add `-webkit-app-region: drag` as
`body`'s style:
@ -64,15 +67,15 @@ button {
}
```
If you're only using a custom titlebar, you also need to make buttons in
titlebar non-draggable.
If you're setting just a custom titlebar as draggable, you also need to make all
buttons in titlebar non-draggable.
## Text selection
One thing on frameless window is that the dragging behaviour may conflict with
selecting text, for example, when you drag the titlebar, you may accidentally
select the text on titlebar. To prevent this, you need to disable text
selection on dragging area like this:
In a frameless window the dragging behaviour may conflict with selecting text.
For example, when you drag the titlebar you may accidentally select the text on
the titlebar. To prevent this, you need to disable text selection within a
draggable area like this:
```css
.titlebar {
@ -83,7 +86,7 @@ selection on dragging area like this:
## Context menu
On some platforms, the draggable area would be treated as non-client frame, so
when you right click on it a system menu would be popuped. To make context menu
behave correctly on all platforms, you should never custom context menu on
On some platforms, the draggable area will be treated as a non-client frame, so
when you right click on it a system menu will pop up. To make the context menu
behave correctly on all platforms you should never use a custom context menu on
draggable areas.

View file

@ -52,16 +52,43 @@ Primary value types like strings and numbers, however, are sent by copy.
## Passing callbacks to the main process
Some APIs in the main process accept callbacks, and it would be tempting to
pass callbacks when calling a remote function. The `remote` module does support
doing this, but you should also be extremely careful with this.
Code in the main process can accept callbacks from the renderer - for instance the `remote` module -
but you should be extremely careful when using this feature.
First, in order to avoid deadlocks, the callbacks passed to the main process
are called asynchronously, so you should not expect the main process to
are called asynchronously. You should not expect the main process to
get the return value of the passed callbacks.
Second, the callbacks passed to the main process will not get released
automatically after they are called. Instead, they will persistent until the
For instance you can't use a function from the renderer process in a `Array.map` called in the main process:
```javascript
// main process mapNumbers.js
exports.withRendererCallback = function(mapper) {
return [1,2,3].map(mapper);
}
exports.withLocalCallback = function() {
return exports.mapNumbers(function(x) {
return x + 1;
});
}
// renderer process
var mapNumbers = require("remote").require("mapNumbers");
var withRendererCb = mapNumbers.withRendererCallback(function(x) {
return x + 1;
})
var withLocalCb = mapNumbers.withLocalCallback()
console.log(withRendererCb, withLocalCb) // [true, true, true], [2, 3, 4]
```
As you can see, the renderer callback's synchronous return value was not as expected,
and didn't match the return value of an indentical callback that lives in the main process.
Second, the callbacks passed to the main process will persist until the
main process garbage-collects them.
For example, the following code seems innocent at first glance. It installs a
@ -74,14 +101,16 @@ remote.getCurrentWindow().on('close', function() {
});
```
The problem is that the callback would be stored in the main process until you
explicitly uninstall it! So each time you reload your window, the callback would
be installed again and previous callbacks would just leak. To make things
worse, since the context of previously installed callbacks have been released,
when the `close` event was emitted, exceptions would be raised in the main process.
But remember the callback is referenced by the main process until you
explicitly uninstall it! If you do not, each time you reload your window the callback will
be installed again, leaking one callback each restart.
Generally, unless you are clear what you are doing, you should always avoid
passing callbacks to the main process.
To make things worse, since the context of previously installed callbacks have been released,
when the `close` event was emitted exceptions would be raised in the main process.
To avoid this problem, ensure you clean up any references to renderer callbacks passed to the main
process. This involves cleaning up event handlers, or ensuring the main process is explicitly told to deference
callbacks that came from a renderer process that is exiting.
## remote.require(module)

172
docs/api/session.md Normal file
View file

@ -0,0 +1,172 @@
# session
The `session` object is a property of [`webContents`](web-contents.md) which is
a property of [`BrowserWindow`](browser-window.md). You can access it through an
instance of `BrowserWindow`. For example:
```javascript
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600 });
win.loadUrl("http://github.com");
var session = win.webContents.session
```
## Methods
The `session` object has the following methods:
### `session.cookies`
The `cookies` gives you ability to query and modify cookies. For example:
```javascript
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600 });
win.loadUrl('https://github.com');
win.webContents.on('did-finish-load', function() {
// Query all cookies.
win.webContents.session.cookies.get({}, function(error, cookies) {
if (error) throw error;
console.log(cookies);
});
// Query all cookies associated with a specific url.
win.webContents.session.cookies.get({ url : "http://www.github.com" },
function(error, cookies) {
if (error) throw error;
console.log(cookies);
});
// Set a cookie with the given cookie data;
// may overwrite equivalent cookies if they exist.
win.webContents.session.cookies.set(
{ url : "http://www.github.com", name : "dummy_name", value : "dummy"},
function(error, cookies) {
if (error) throw error;
console.log(cookies);
});
});
```
### `session.cookies.get(details, callback)`
`details` Object, properties:
* `url` String - Retrieves cookies which are associated with `url`.
Empty implies retrieving cookies of all urls.
* `name` String - Filters cookies by name
* `domain` String - Retrieves cookies whose domains match or are subdomains of
`domains`
* `path` String - Retrieves cookies whose path matches `path`
* `secure` Boolean - Filters cookies by their Secure property
* `session` Boolean - Filters out session or persistent cookies.
* `callback` Function - function(error, cookies)
* `error` Error
* `cookies` Array - array of `cookie` objects, properties:
* `name` String - The name of the cookie.
* `value` String - The value of the cookie.
* `domain` String - The domain of the cookie.
* `host_only` String - Whether the cookie is a host-only cookie.
* `path` String - The path of the cookie.
* `secure` Boolean - Whether the cookie is marked as Secure (typically HTTPS).
* `http_only` Boolean - Whether the cookie is marked as HttpOnly.
* `session` Boolean - Whether the cookie is a session cookie or a persistent
cookie with an expiration date.
* `expirationDate` Double - (Option) The expiration date of the cookie as
the number of seconds since the UNIX epoch. Not provided for session
cookies.
### `session.cookies.set(details, callback)`
`details` Object, properties:
* `url` String - Retrieves cookies which are associated with `url`
* `name` String - The name of the cookie. Empty by default if omitted.
* `value` String - The value of the cookie. Empty by default if omitted.
* `domain` String - The domain of the cookie. Empty by default if omitted.
* `path` String - The path of the cookie. Empty by default if omitted.
* `secure` Boolean - Whether the cookie should be marked as Secure. Defaults to
false.
* `session` Boolean - Whether the cookie should be marked as HttpOnly. Defaults
to false.
* `expirationDate` Double - The expiration date of the cookie as the number of
seconds since the UNIX epoch. If omitted, the cookie becomes a session cookie.
* `callback` Function - function(error)
* `error` Error
### `session.cookies.remove(details, callback)`
* `details` Object, proprties:
* `url` String - The URL associated with the cookie
* `name` String - The name of cookie to remove
* `callback` Function - function(error)
* `error` Error
### `session.clearCache(callback)`
* `callback` Function - Called when operation is done
Clears the sessions HTTP cache.
### `session.clearStorageData([options, ]callback)`
* `options` Object (optional), proprties:
* `origin` String - Should follow `window.location.origin`s representation
`scheme://host:port`.
* `storages` Array - The types of storages to clear, can contain:
`appcache`, `cookies`, `filesystem`, `indexdb`, `local storage`,
`shadercache`, `websql`, `serviceworkers`
* `quotas` Array - The types of quotas to clear, can contain:
`temporary`, `persistent`, `syncable`.
* `callback` Function - Called when operation is done.
Clears the data of web storages.
### `session.setProxy(config, callback)`
* `config` String
* `callback` Function - Called when operation is done.
Parses the `config` indicating which proxies to use for the session.
```
config = scheme-proxies[";"<scheme-proxies>]
scheme-proxies = [<url-scheme>"="]<proxy-uri-list>
url-scheme = "http" | "https" | "ftp" | "socks"
proxy-uri-list = <proxy-uri>[","<proxy-uri-list>]
proxy-uri = [<proxy-scheme>"://"]<proxy-host>[":"<proxy-port>]
For example:
"http=foopy:80;ftp=foopy2" -- use HTTP proxy "foopy:80" for http://
URLs, and HTTP proxy "foopy2:80" for
ftp:// URLs.
"foopy:80" -- use HTTP proxy "foopy:80" for all URLs.
"foopy:80,bar,direct://" -- use HTTP proxy "foopy:80" for all URLs,
failing over to "bar" if "foopy:80" is
unavailable, and after that using no
proxy.
"socks4://foopy" -- use SOCKS v4 proxy "foopy:1080" for all
URLs.
"http=foopy,socks5://bar.com -- use HTTP proxy "foopy" for http URLs,
and fail over to the SOCKS5 proxy
"bar.com" if "foopy" is unavailable.
"http=foopy,direct:// -- use HTTP proxy "foopy" for http URLs,
and use no proxy if "foopy" is
unavailable.
"http=foopy;socks=foopy2 -- use HTTP proxy "foopy" for http URLs,
and use socks4://foopy2 for all other
URLs.
```
### `session.setDownloadPath(path)`
* `path` String - The download location
Sets download saving directory. By default, the download directory will be the
`Downloads` under the respective app folder.

477
docs/api/web-contents.md Normal file
View file

@ -0,0 +1,477 @@
# webContents
`webContents` is an
[EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter).
It is responsible for rendering and controlling a web page and is a property of
the [`BrowserWindow`](browser-window.md) object. An example of accessing the
`webContents` object:
```javascript
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({width: 800, height: 1500});
win.loadUrl("http://github.com");
var webContents = win.webContents;
```
## Events
The `webContents` object emits the following events:
### Event: 'did-finish-load'
Emitted when the navigation is done, i.e. the spinner of the tab has stopped
spinning, and the `onload` event was dispatched.
### Event: 'did-fail-load'
Returns:
* `event` Event
* `errorCode` Integer
* `errorDescription` String
This event is like `did-finish-load` but emitted when the load failed or was
cancelled, e.g. `window.stop()` is invoked.
### Event: 'did-frame-finish-load'
Returns:
* `event` Event
* `isMainFrame` Boolean
Emitted when a frame has done navigation.
### Event: 'did-start-loading'
Corresponds to the points in time when the spinner of the tab started spinning.
### Event: 'did-stop-loading'
Corresponds to the points in time when the spinner of the tab stopped spinning.
### Event: 'did-get-response-details'
Returns:
* `event` Event
* `status` Boolean
* `newUrl` String
* `originalUrl` String
* `httpResponseCode` Integer
* `requestMethod` String
* `referrer` String
* `headers` Object
Emitted when details regarding a requested resource are available.
`status` indicates the socket connection to download the resource.
### Event: 'did-get-redirect-request'
Returns:
* `event` Event
* `oldUrl` String
* `newUrl` String
* `isMainFrame` Boolean
Emitted when a redirect is received while requesting a resource.
### Event: 'dom-ready'
Returns:
* `event` Event
Emitted when the document in the given frame is loaded.
### Event: 'page-favicon-updated'
Returns:
* `event` Event
* `favicons` Array - Array of Urls
Emitted when page receives favicon urls.
### Event: 'new-window'
Returns:
* `event` Event
* `url` String
* `frameName` String
* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`,
`new-window` and `other`.
Emitted when the page requests to open a new window for a `url`. It could be
requested by `window.open` or an external link like `<a target='_blank'>`.
By default a new `BrowserWindow` will be created for the `url`.
Calling `event.preventDefault()` will prevent creating new windows.
### Event: 'will-navigate'
Returns:
* `event` Event
* `url` String
Emitted when a user or the page wants to start navigation. It can happen when the
`window.location` object is changed or a user clicks a link in the page.
This event will not emit when the navigation is started programmatically with
APIs like `webContents.loadUrl` and `webContents.back`.
Calling `event.preventDefault()` will prevent the navigation.
### Event: 'crashed'
Emitted when the renderer process has crashed.
### Event: 'plugin-crashed'
Returns:
* `event` Event
* `name` String
* `version` String
Emitted when a plugin process has crashed.
### Event: 'destroyed'
Emitted when `webContents` is destroyed.
## Instance Methods
The `webContents` object has the following instance methods:
### `webContents.session`
Returns the `session` object used by this webContents.
See [session documentation](session.md) for this object's methods.
### `webContents.loadUrl(url[, options])`
* `url` URL
* `options` Object (optional), properties:
* `httpReferrer` String - A HTTP Referrer url.
* `userAgent` String - A user agent originating the request.
Loads the `url` in the window, the `url` must contain the protocol prefix,
e.g. the `http://` or `file://`.
### `webContents.getUrl()`
```javascript
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({width: 800, height: 600});
win.loadUrl("http://github.com");
var currentUrl = win.webContents.getUrl();
```
Returns URL of the current web page.
### `webContents.getTitle()`
Returns the title of the current web page.
### `webContents.isLoading()`
Returns whether web page is still loading resources.
### `webContents.isWaitingForResponse()`
Returns whether the web page is waiting for a first-response from the main
resource of the page.
### `webContents.stop()`
Stops any pending navigation.
### `webContents.reload()`
Reloads the current web page.
### `webContents.reloadIgnoringCache()`
Reloads current page and ignores cache.
### `webContents.canGoBack()`
Returns whether the browser can go back to previous web page.
### `webContents.canGoForward()`
Returns whether the browser can go forward to next web page.
### `webContents.canGoToOffset(offset)`
* `offset` Integer
Returns whether the web page can go to `offset`.
### `webContents.clearHistory()`
Clears the navigation history.
### `webContents.goBack()`
Makes the browser go back a web page.
### `webContents.goForward()`
Makes the browser go forward a web page.
### `webContents.goToIndex(index)`
* `index` Integer
Navigates browser to the specified absolute web page index.
### `webContents.goToOffset(offset)`
* `offset` Integer
Navigates to the specified offset from the "current entry".
### `webContents.isCrashed()`
Whether the renderer process has crashed.
### `webContents.setUserAgent(userAgent)`
* `userAgent` String
Overrides the user agent for this web page.
### `webContents.getUserAgent()`
Returns a `String` representing the user agent for this web page.
### `webContents.insertCSS(css)`
* `css` String
Injects CSS into the current web page.
### `webContents.executeJavaScript(code[, userGesture])`
* `code` String
* `userGesture` Boolean (optional)
Evaluates `code` in page.
In the browser window some HTML APIs like `requestFullScreen` can only be
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
this limitation.
### `webContents.setAudioMuted(muted)`
+ `muted` Boolean
Mute the audio on the current web page.
### `webContents.isAudioMuted()`
Returns whether this page has been muted.
### `webContents.undo()`
Executes the editing command `undo` in web page.
### `webContents.redo()`
Executes the editing command `redo` in web page.
### `webContents.cut()`
Executes the editing command `cut` in web page.
### `webContents.copy()`
Executes the editing command `copy` in web page.
### `webContents.paste()`
Executes the editing command `paste` in web page.
### `webContents.pasteAndMatchStyle()`
Executes the editing command `pasteAndMatchStyle` in web page.
### `webContents.delete()`
Executes the editing command `delete` in web page.
### `webContents.selectAll()`
Executes the editing command `selectAll` in web page.
### `webContents.unselect()`
Executes the editing command `unselect` in web page.
### `webContents.replace(text)`
* `text` String
Executes the editing command `replace` in web page.
### `webContents.replaceMisspelling(text)`
* `text` String
Executes the editing command `replaceMisspelling` in web page.
### `webContents.hasServiceWorker(callback)`
* `callback` Function
Checks if any ServiceWorker is registered and returns a boolean as
response to `callback`.
### `webContents.unregisterServiceWorker(callback)`
* `callback` Function
Unregisters any ServiceWorker if present and returns a boolean as
response to `callback` when the JS promise is fulfilled or false
when the JS promise is rejected.
### `webContents.print([options])`
`options` Object (optional), properties:
* `silent` Boolean - Don't ask user for print settings, defaults to `false`
* `printBackground` Boolean - Also prints the background color and image of
the web page, defaults to `false`.
Prints window's web page. When `silent` is set to `false`, Electron will pick
up system's default printer and default settings for printing.
Calling `window.print()` in web page is equivalent to calling
`webContents.print({silent: false, printBackground: false})`.
**Note:** On Windows, the print API relies on `pdf.dll`. If your application
doesn't need the print feature, you can safely remove `pdf.dll` to reduce binary
size.
### `webContents.printToPDF(options, callback)`
`options` Object, properties:
* `marginsType` Integer - Specify the type of margins to use
* 0 - default
* 1 - none
* 2 - minimum
* `pageSize` String - Specify page size of the generated PDF.
* `A4`
* `A3`
* `Legal`
* `Letter`
* `Tabloid`
* `printBackground` Boolean - Whether to print CSS backgrounds.
* `printSelectionOnly` Boolean - Whether to print selection only.
* `landscape` Boolean - `true` for landscape, `false` for portrait.
`callback` Function - `function(error, data) {}`
* `error` Error
* `data` Buffer - PDF file content.
Prints window's web page as PDF with Chromium's preview printing custom
settings.
By default, an empty `options` will be regarded as:
```javascript
{
marginsType: 0,
printBackground: false,
printSelectionOnly: false,
landscape: false
}
```
```javascript
var BrowserWindow = require('browser-window');
var fs = require('fs');
var win = new BrowserWindow({width: 800, height: 600});
win.loadUrl("http://github.com");
win.webContents.on("did-finish-load", function() {
// Use default printing options
win.webContents.printToPDF({}, function(error, data) {
if (error) throw error;
fs.writeFile("/tmp/print.pdf", data, function(error) {
if (err)
throw error;
console.log("Write PDF successfully.");
})
})
});
```
### `webContents.addWorkSpace(path)`
* `path` String
Adds the specified path to devtools workspace.
### `webContents.removeWorkSpace(path)`
* `path` String
Removes the specified path from devtools workspace.
### `webContents.send(channel[, args...])`
* `channel` String
* `args...` (optional)
Send `args...` to the web page via `channel` in an asynchronous message, the web
page can handle it by listening to the `channel` event of the `ipc` module.
An example of sending messages from the main process to the renderer process:
```javascript
// On the main process.
var window = null;
app.on('ready', function() {
window = new BrowserWindow({width: 800, height: 600});
window.loadUrl('file://' + __dirname + '/index.html');
window.webContents.on('did-finish-load', function() {
window.webContents.send('ping', 'whoooooooh!');
});
});
```
```html
<!-- index.html -->
<html>
<body>
<script>
require('ipc').on('ping', function(message) {
console.log(message); // Prints "whoooooooh!"
});
</script>
</body>
</html>
```
**Note:**
1. The IPC message handler in web pages does not have an `event` parameter,
which is different from the handlers on the main process.
2. There is no way to send synchronous messages from the main process to a
renderer process, because it would be very easy to cause dead locks.

View file

@ -32,6 +32,13 @@ limits of 300% and 50% of original size, respectively.
Returns the current zoom level.
## webFrame.setZoomLevelLimits(minimumLevel, maximumLevel)
* `minimumLevel` Number
* `maximumLevel` Number
Sets the maximum and minimum zoom level.
## webFrame.setSpellCheckProvider(language, autoCorrectWord, provider)
* `language` String

View file

@ -54,7 +54,8 @@ You can also only build the Debug target:
python script\build.py -c D
```
After building is done, you can find `atom.exe` under `out\D`.
After building is done, you can find `electron.exe` under `out\D` (debug
target) or under `out\R` (release target).
## 64bit build
@ -81,6 +82,15 @@ Test functionality using:
python script\test.py
```
Tests that include native modules (e.g. `runas`) can't be executed with the
debug build (see #2558 for details), but they will work with the release build.
To run the tests with the release build use:
```powershell
python script\test.py -R
```
## Troubleshooting
### Command xxxx not found

78
docs/styleguide.md Normal file
View file

@ -0,0 +1,78 @@
# Electron Documentation Styleguide
Find the appropriate section for your task: [reading Electron documentation](#)
or [writing Electron documentation](#).
## Writing Electron Documentation
These are the ways that we construct the Electron documentation.
- Maximum one `h1` title per page.
- Use `bash` instead of `cmd` in code blocks (because of syntax highlighter).
- Doc `h1` titles should match object name (i.e. `browser-window`
`BrowserWindow`).
- Hyphen separated filenames, however, are fine.
- No headers following headers, add at least a one-sentence description.
- Methods headers are wrapped in `code` ticks.
- Event headers are wrapped in single 'quotation' marks.
- No nesting lists more than 2 levels (unfortunately because of markdown
renderer).
- Add section titles: Events, Class Methods and Instance Methods.
- Use 'will' over 'would' when describing outcomes.
- Events and methods are `h3` headers.
- Optional arguments written as `function (required[, optional])`.
- Optional arguments are denoted when called out in list.
- Line length is 80-column wrapped.
- Platform specific methods are noted in italics following method header.
- ```### `method(foo, bar)` _OS X_```
## Reading Electron Documentation
Here are some tips for understanding Electron documentation syntax.
### Methods
An example of [method](https://developer.mozilla.org/en-US/docs/Glossary/Method)
documentation:
---
`methodName(required[, optional]))`
* `require` String, **required**
* `optional` Integer
---
The method name is followed by the arguments it takes. Optional arguments are
notated by brackets surrounding the optional argument as well as the comma
required if this optional argument follows another argument.
Below the method is more detailed information on each of the arguments. The type
of argument is notated by either the common types: [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
or a custom type like Electron's [`webContent`](api/web-content.md).
### Events
An example of [event](https://developer.mozilla.org/en-US/docs/Web/API/Event)
documentation:
---
Event: 'wake-up'
Returns:
* `time` String
---
The event is a string that is used after a `.on` listener method. If it returns
a value it and its type is noted below. If you were to listen and respond to
this event it might look something like this:
```javascript
Alarm.on('wake-up', function(time) {
console.log(time)
})
```

View file

@ -67,6 +67,9 @@ like this:
}
```
__Note__: If the `main` field is not present in `package.json`, Electron will
attempt to load an `index.js`.
The `main.js` should create windows and handle system events, a typical
example being:

View file

@ -7,14 +7,14 @@ the location of Electron's headers when building native modules.
## Native Node module compatibility
Since Node v0.11.x there were vital changes in the V8 API. So generally all
native modules written for Node v0.10.x wouldn't work for Node v0.11.x. And
because Electron internally uses Node v0.11.13, it carries with the same
native modules written for Node v0.10.x wouldn't work for newer Node or io.js versions. And
because Electron internally uses __io.js v3.1.0__, it carries with the same
problem.
To solve this, you should use modules that support Node v0.11.x,
To solve this, you should use modules that support Node v0.11.x or later,
[many modules](https://www.npmjs.org/browse/depended/nan) do support both now.
For old modules that only support Node v0.10.x, you should use the
[nan](https://github.com/rvagg/nan) module to port it to v0.11.x.
[nan](https://github.com/rvagg/nan) module to port it to v0.11.x or later versions of Node or io.js.
## How to install native modules

View file

@ -164,6 +164,8 @@
'atom/browser/net/url_request_buffer_job.h',
'atom/browser/net/url_request_fetch_job.cc',
'atom/browser/net/url_request_fetch_job.h',
'atom/browser/node_debugger.cc',
'atom/browser/node_debugger.h',
'atom/browser/ui/accelerator_util.cc',
'atom/browser/ui/accelerator_util.h',
'atom/browser/ui/accelerator_util_mac.mm',
@ -233,8 +235,6 @@
'atom/common/api/atom_api_asar.cc',
'atom/common/api/atom_api_clipboard.cc',
'atom/common/api/atom_api_crash_reporter.cc',
'atom/common/api/atom_api_id_weak_map.cc',
'atom/common/api/atom_api_id_weak_map.h',
'atom/common/api/atom_api_native_image.cc',
'atom/common/api/atom_api_native_image.h',
'atom/common/api/atom_api_native_image_mac.mm',
@ -410,6 +410,10 @@
'chromium_src/chrome/utility/utility_message_handler.h',
'chromium_src/library_loaders/libspeechd_loader.cc',
'chromium_src/library_loaders/libspeechd.h',
'chromium_src/net/test/embedded_test_server/stream_listen_socket.cc',
'chromium_src/net/test/embedded_test_server/stream_listen_socket.h',
'chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc',
'chromium_src/net/test/embedded_test_server/tcp_listen_socket.h',
'<@(native_mate_files)',
'<(SHARED_INTERMEDIATE_DIR)/atom_natives.h',
],

View file

@ -1,7 +1,7 @@
{
"name": "electron",
"devDependencies": {
"asar": "0.7.x",
"asar": "0.8.x",
"coffee-script": "^1.9.2",
"coffeelint": "^1.9.4",
"request": "*",

View file

@ -8,7 +8,7 @@ remote = require 'remote'
describe 'chromium feature', ->
fixtures = path.resolve __dirname, 'fixtures'
describe 'heap snapshot', ->
xdescribe 'heap snapshot', ->
it 'does not crash', ->
process.atomBinding('v8_util').takeHeapSnapshot()

View file

@ -7,16 +7,20 @@ describe 'third-party module', ->
fixtures = path.join __dirname, 'fixtures'
temp.track()
describe 'runas', ->
it 'can be required in renderer', ->
require 'runas'
# If the test is executed with the debug build on Windows, we will skip it
# because native modules don't work with the debug build (see issue #2558).
if process.platform isnt 'win32' or
process.execPath.toLowerCase().indexOf('\\out\\d\\') is -1
describe 'runas', ->
it 'can be required in renderer', ->
require 'runas'
it 'can be required in node binary', (done) ->
runas = path.join fixtures, 'module', 'runas.js'
child = require('child_process').fork runas
child.on 'message', (msg) ->
assert.equal msg, 'ok'
done()
it 'can be required in node binary', (done) ->
runas = path.join fixtures, 'module', 'runas.js'
child = require('child_process').fork runas
child.on 'message', (msg) ->
assert.equal msg, 'ok'
done()
describe 'q', ->
Q = require 'q'

View file

@ -48,18 +48,22 @@ describe '<webview> tag', ->
webview.src = "file://#{fixtures}/pages/d.html"
document.body.appendChild webview
it 'loads native modules when navigation happens', (done) ->
listener = (e) ->
webview.removeEventListener 'did-finish-load', listener
listener2 = (e) ->
assert.equal e.message, 'function'
done()
webview.addEventListener 'console-message', listener2
webview.reload()
webview.addEventListener 'did-finish-load', listener
webview.setAttribute 'nodeintegration', 'on'
webview.src = "file://#{fixtures}/pages/native-module.html"
document.body.appendChild webview
# If the test is executed with the debug build on Windows, we will skip it
# because native modules don't work with the debug build (see issue #2558).
if process.platform isnt 'win32' or
process.execPath.toLowerCase().indexOf('\\out\\d\\') is -1
it 'loads native modules when navigation happens', (done) ->
listener = (e) ->
webview.removeEventListener 'did-finish-load', listener
listener2 = (e) ->
assert.equal e.message, 'function'
done()
webview.addEventListener 'console-message', listener2
webview.reload()
webview.addEventListener 'did-finish-load', listener
webview.setAttribute 'nodeintegration', 'on'
webview.src = "file://#{fixtures}/pages/native-module.html"
document.body.appendChild webview
describe 'preload attribute', ->
it 'loads the script before other scripts in window', (done) ->

2
vendor/brightray vendored

@ -1 +1 @@
Subproject commit 5b2a73c68a986780e67eb2e738327d35c7c1c21e
Subproject commit 0bf81275795b15eb361a1fd213ae9c7c1f60bdea

2
vendor/native_mate vendored

@ -1 +1 @@
Subproject commit b41635e80921bddbf1a36f030490e063cd593477
Subproject commit 8ca005eb41591f583ebab804945311903f866ad6

2
vendor/node vendored

@ -1 +1 @@
Subproject commit b9b6dd9f3fc095e66a3b89d3efd50f7c576da2c8
Subproject commit 8253eb68252639db471090edb059eaa4fea4ce46