Merge remote-tracking branch 'atom/master'
This commit is contained in:
commit
8b6f3dc0aa
59 changed files with 2623 additions and 1483 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -17,3 +17,4 @@ node_modules/
|
|||
*.pyc
|
||||
debug.log
|
||||
npm-debug.log
|
||||
atom/common/chrome_version.h
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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...);
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
209
atom/browser/node_debugger.cc
Normal file
209
atom/browser/node_debugger.cc
Normal 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
|
65
atom/browser/node_debugger.h
Normal file
65
atom/browser/node_debugger.h
Normal 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_
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
|
@ -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_
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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_
|
118
chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc
Normal file
118
chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc
Normal 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
|
|
@ -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_
|
|
@ -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):
|
||||
|
|
219
docs/api/app.md
219
docs/api/app.md
|
@ -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 dock’s 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
|
||||
|
|
|
@ -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
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
172
docs/api/session.md
Normal 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 session’s 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
477
docs/api/web-contents.md
Normal 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.
|
|
@ -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
|
||||
|
|
|
@ -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
78
docs/styleguide.md
Normal 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)
|
||||
})
|
||||
```
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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',
|
||||
],
|
||||
|
|
|
@ -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": "*",
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 5b2a73c68a986780e67eb2e738327d35c7c1c21e
|
||||
Subproject commit 0bf81275795b15eb361a1fd213ae9c7c1f60bdea
|
2
vendor/native_mate
vendored
2
vendor/native_mate
vendored
|
@ -1 +1 @@
|
|||
Subproject commit b41635e80921bddbf1a36f030490e063cd593477
|
||||
Subproject commit 8ca005eb41591f583ebab804945311903f866ad6
|
2
vendor/node
vendored
2
vendor/node
vendored
|
@ -1 +1 @@
|
|||
Subproject commit b9b6dd9f3fc095e66a3b89d3efd50f7c576da2c8
|
||||
Subproject commit 8253eb68252639db471090edb059eaa4fea4ce46
|
Loading…
Reference in a new issue