Merge pull request #234 from atom/api-web-contents

Separate out WebContents API to a new class
This commit is contained in:
Cheng Zhao 2014-04-25 09:41:58 +00:00
commit 3584d48dbe
30 changed files with 603 additions and 835 deletions

View file

@ -24,6 +24,7 @@
'atom/browser/api/lib/menu-item.coffee', 'atom/browser/api/lib/menu-item.coffee',
'atom/browser/api/lib/power-monitor.coffee', 'atom/browser/api/lib/power-monitor.coffee',
'atom/browser/api/lib/protocol.coffee', 'atom/browser/api/lib/protocol.coffee',
'atom/browser/api/lib/web-contents.coffee',
'atom/browser/lib/init.coffee', 'atom/browser/lib/init.coffee',
'atom/browser/lib/objects-registry.coffee', 'atom/browser/lib/objects-registry.coffee',
'atom/browser/lib/rpc-server.coffee', 'atom/browser/lib/rpc-server.coffee',
@ -48,7 +49,6 @@
'atom/browser/api/atom_api_app.h', 'atom/browser/api/atom_api_app.h',
'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.cc',
'atom/browser/api/atom_api_auto_updater.h', 'atom/browser/api/atom_api_auto_updater.h',
'atom/browser/api/atom_api_browser_ipc.cc',
'atom/browser/api/atom_api_dialog.cc', 'atom/browser/api/atom_api_dialog.cc',
'atom/browser/api/atom_api_menu.cc', 'atom/browser/api/atom_api_menu.cc',
'atom/browser/api/atom_api_menu.h', 'atom/browser/api/atom_api_menu.h',
@ -62,10 +62,10 @@
'atom/browser/api/atom_api_power_monitor.h', 'atom/browser/api/atom_api_power_monitor.h',
'atom/browser/api/atom_api_protocol.cc', 'atom/browser/api/atom_api_protocol.cc',
'atom/browser/api/atom_api_protocol.h', 'atom/browser/api/atom_api_protocol.h',
'atom/browser/api/atom_api_web_contents.cc',
'atom/browser/api/atom_api_web_contents.h',
'atom/browser/api/atom_api_window.cc', 'atom/browser/api/atom_api_window.cc',
'atom/browser/api/atom_api_window.h', 'atom/browser/api/atom_api_window.h',
'atom/browser/api/atom_browser_bindings.cc',
'atom/browser/api/atom_browser_bindings.h',
'atom/browser/api/event.cc', 'atom/browser/api/event.cc',
'atom/browser/api/event.h', 'atom/browser/api/event.h',
'atom/browser/api/event_emitter.cc', 'atom/browser/api/event_emitter.cc',
@ -93,8 +93,6 @@
'atom/browser/browser_observer.h', 'atom/browser/browser_observer.h',
'atom/browser/devtools_delegate.cc', 'atom/browser/devtools_delegate.cc',
'atom/browser/devtools_delegate.h', 'atom/browser/devtools_delegate.h',
'atom/browser/devtools_web_contents_observer.cc',
'atom/browser/devtools_web_contents_observer.h',
'atom/browser/mac/atom_application.h', 'atom/browser/mac/atom_application.h',
'atom/browser/mac/atom_application.mm', 'atom/browser/mac/atom_application.mm',
'atom/browser/mac/atom_application_delegate.h', 'atom/browser/mac/atom_application_delegate.h',

View file

@ -1,37 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/common/api/api_messages.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "content/public/browser/render_view_host.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
using content::RenderViewHost;
namespace {
bool Send(const string16& channel, int process_id, int routing_id,
const base::ListValue& arguments) {
RenderViewHost* render_view_host(RenderViewHost::FromID(
process_id, routing_id));
if (!render_view_host) {
node::ThrowError("Invalid render view host");
return false;
}
return render_view_host->Send(new AtomViewMsg_Message(routing_id, channel,
arguments));
}
void Initialize(v8::Handle<v8::Object> exports) {
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
dict.SetMethod("send", &Send);
}
} // namespace
NODE_MODULE(atom_browser_ipc, Initialize)

View file

@ -0,0 +1,206 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "native_mate/object_template_builder.h"
namespace atom {
namespace api {
WebContents::WebContents(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
web_contents_(web_contents) {
}
void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
base::ListValue args;
args.AppendInteger(render_view_host->GetProcess()->GetID());
args.AppendInteger(render_view_host->GetRoutingID());
Emit("render-view-deleted", args);
}
void WebContents::RenderProcessGone(base::TerminationStatus status) {
Emit("crashed");
}
void WebContents::DidFinishLoad(int64 frame_id,
const GURL& validated_url,
bool is_main_frame,
content::RenderViewHost* render_view_host) {
Emit("did-finish-load");
}
void WebContents::DidStartLoading(content::RenderViewHost* render_view_host) {
Emit("did-start-loading");
}
void WebContents::DidStopLoading(content::RenderViewHost* render_view_host) {
Emit("did-stop-loading");
}
bool WebContents::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebContents, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void WebContents::WebContentsDestroyed(content::WebContents*) {
// The RenderViewDeleted was not called when the WebContents is destroyed.
RenderViewDeleted(web_contents_->GetRenderViewHost());
Emit("destroyed");
}
bool WebContents::IsAlive() const {
return web_contents() != NULL;
}
void WebContents::LoadURL(const GURL& url) {
content::NavigationController::LoadURLParams params(url);
params.transition_type = content::PAGE_TRANSITION_TYPED;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
web_contents()->GetController().LoadURLWithParams(params);
}
GURL WebContents::GetURL() const {
return web_contents()->GetURL();
}
string16 WebContents::GetTitle() const {
return web_contents()->GetTitle();
}
bool WebContents::IsLoading() const {
return web_contents()->IsLoading();
}
bool WebContents::IsWaitingForResponse() const {
return web_contents()->IsWaitingForResponse();
}
void WebContents::Stop() {
web_contents()->Stop();
}
void WebContents::Reload() {
web_contents()->GetController().Reload(false);
}
void WebContents::ReloadIgnoringCache() {
web_contents()->GetController().ReloadIgnoringCache(false);
}
bool WebContents::CanGoBack() const {
return web_contents()->GetController().CanGoBack();
}
bool WebContents::CanGoForward() const {
return web_contents()->GetController().CanGoForward();
}
bool WebContents::CanGoToOffset(int offset) const {
return web_contents()->GetController().CanGoToOffset(offset);
}
void WebContents::GoBack() {
web_contents()->GetController().GoBack();
}
void WebContents::GoForward() {
web_contents()->GetController().GoForward();
}
void WebContents::GoToIndex(int index) {
web_contents()->GetController().GoToIndex(index);
}
void WebContents::GoToOffset(int offset) {
web_contents()->GetController().GoToOffset(offset);
}
int WebContents::GetRoutingID() const {
return web_contents()->GetRoutingID();
}
int WebContents::GetProcessID() const {
return web_contents()->GetRenderProcessHost()->GetID();
}
bool WebContents::IsCrashed() const {
return web_contents()->IsCrashed();
}
void WebContents::ExecuteJavaScript(const string16& code) {
web_contents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
string16(), code);
}
bool WebContents::SendIPCMessage(const string16& channel,
const base::ListValue& args) {
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
}
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("isAlive", &WebContents::IsAlive)
.SetMethod("loadUrl", &WebContents::LoadURL)
.SetMethod("getUrl", &WebContents::GetURL)
.SetMethod("getTitle", &WebContents::GetTitle)
.SetMethod("isLoading", &WebContents::IsLoading)
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
.SetMethod("stop", &WebContents::Stop)
.SetMethod("reload", &WebContents::Reload)
.SetMethod("reloadIgnoringCache", &WebContents::ReloadIgnoringCache)
.SetMethod("canGoBack", &WebContents::CanGoBack)
.SetMethod("canGoForward", &WebContents::CanGoForward)
.SetMethod("canGoToOffset", &WebContents::CanGoToOffset)
.SetMethod("goBack", &WebContents::GoBack)
.SetMethod("goForward", &WebContents::GoForward)
.SetMethod("goToIndex", &WebContents::GoToIndex)
.SetMethod("goToOffset", &WebContents::GoToOffset)
.SetMethod("getRoutingId", &WebContents::GetRoutingID)
.SetMethod("getProcessId", &WebContents::GetProcessID)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("_send", &WebContents::SendIPCMessage);
}
void WebContents::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
// webContents.emit(channel, new Event(), args...);
Emit(UTF16ToUTF8(channel), args, web_contents(), NULL);
}
void WebContents::OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* message) {
// webContents.emit(channel, new Event(sender, message), args...);
Emit(UTF16ToUTF8(channel), args, web_contents(), message);
}
// static
mate::Handle<WebContents> WebContents::Create(
v8::Isolate* isolate, content::WebContents* web_contents) {
return CreateHandle(isolate, new WebContents(web_contents));
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,84 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_
#define ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_
#include "atom/browser/api/event_emitter.h"
#include "content/public/browser/web_contents_observer.h"
#include "native_mate/handle.h"
namespace atom {
namespace api {
class WebContents : public mate::EventEmitter,
public content::WebContentsObserver {
public:
static mate::Handle<WebContents> Create(v8::Isolate* isolate,
content::WebContents* web_contents);
bool IsAlive() const;
void LoadURL(const GURL& url);
GURL GetURL() const;
string16 GetTitle() const;
bool IsLoading() const;
bool IsWaitingForResponse() const;
void Stop();
void Reload();
void ReloadIgnoringCache();
bool CanGoBack() const;
bool CanGoForward() const;
bool CanGoToOffset(int offset) const;
void GoBack();
void GoForward();
void GoToIndex(int index);
void GoToOffset(int offset);
int GetRoutingID() const;
int GetProcessID() const;
bool IsCrashed() const;
void ExecuteJavaScript(const string16& code);
bool SendIPCMessage(const string16& channel, const base::ListValue& args);
protected:
explicit WebContents(content::WebContents* web_contents);
// mate::Wrappable implementations:
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) OVERRIDE;
// content::WebContentsObserver implementations:
virtual void RenderViewDeleted(content::RenderViewHost*) OVERRIDE;
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
virtual void DidFinishLoad(
int64 frame_id,
const GURL& validated_url,
bool is_main_frame,
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidStartLoading(
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void DidStopLoading(
content::RenderViewHost* render_view_host) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE;
private:
// Called when received a message from renderer.
void OnRendererMessage(const string16& channel, const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* message);
content::WebContents* web_contents_; // Weak.
DISALLOW_COPY_AND_ASSIGN(WebContents);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_

View file

@ -4,15 +4,12 @@
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/common/native_mate_converters/function_converter.h" #include "atom/common/native_mate_converters/function_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "native_mate/constructor.h" #include "native_mate/constructor.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
@ -22,8 +19,6 @@
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
using content::NavigationController;
namespace mate { namespace mate {
template<> template<>
@ -86,12 +81,6 @@ void Window::OnPageTitleUpdated(bool* prevent_default,
*prevent_default = Emit("page-title-updated", args); *prevent_default = Emit("page-title-updated", args);
} }
void Window::OnLoadingStateChanged(bool is_loading) {
base::ListValue args;
args.AppendBoolean(is_loading);
Emit("loading-state-changed", args);
}
void Window::WillCloseWindow(bool* prevent_default) { void Window::WillCloseWindow(bool* prevent_default) {
*prevent_default = Emit("close"); *prevent_default = Emit("close");
} }
@ -114,17 +103,6 @@ void Window::OnRendererResponsive() {
Emit("responsive"); Emit("responsive");
} }
void Window::OnRenderViewDeleted(int process_id, int routing_id) {
base::ListValue args;
args.AppendInteger(process_id);
args.AppendInteger(routing_id);
Emit("render-view-deleted", args);
}
void Window::OnRendererCrashed() {
Emit("crashed");
}
// static // static
mate::Wrappable* Window::New(mate::Arguments* args, mate::Wrappable* Window::New(mate::Arguments* args,
const base::DictionaryValue& options) { const base::DictionaryValue& options) {
@ -326,96 +304,13 @@ void Window::CapturePage(mate::Arguments* args) {
window_->CapturePage(rect, base::Bind(&OnCapturePageDone, callback)); window_->CapturePage(rect, base::Bind(&OnCapturePageDone, callback));
} }
string16 Window::GetPageTitle() { mate::Handle<WebContents> Window::GetWebContents(v8::Isolate* isolate) const {
return window_->GetWebContents()->GetTitle(); return WebContents::Create(isolate, window_->GetWebContents());
} }
bool Window::IsLoading() { mate::Handle<WebContents> Window::GetDevToolsWebContents(
return window_->GetWebContents()->IsLoading(); v8::Isolate* isolate) const {
} return WebContents::Create(isolate, window_->GetDevToolsWebContents());
bool Window::IsWaitingForResponse() {
return window_->GetWebContents()->IsWaitingForResponse();
}
void Window::Stop() {
window_->GetWebContents()->Stop();
}
int Window::GetRoutingID() {
return window_->GetWebContents()->GetRoutingID();
}
int Window::GetProcessID() {
return window_->GetWebContents()->GetRenderProcessHost()->GetID();
}
bool Window::IsCrashed() {
return window_->GetWebContents()->IsCrashed();
}
mate::Dictionary Window::GetDevTools(v8::Isolate* isolate) {
mate::Dictionary dict(mate::Dictionary::CreateEmpty(isolate));
content::WebContents* web_contents = window_->GetDevToolsWebContents();
dict.Set("processId", web_contents->GetRenderProcessHost()->GetID());
dict.Set("routingId", web_contents->GetRoutingID());
return dict;
}
void Window::ExecuteJavaScriptInDevTools(const std::string& code) {
window_->ExecuteJavaScriptInDevTools(code);
}
void Window::LoadURL(const GURL& url) {
NavigationController& controller = window_->GetWebContents()->GetController();
content::NavigationController::LoadURLParams params(url);
params.transition_type = content::PAGE_TRANSITION_TYPED;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
controller.LoadURLWithParams(params);
}
GURL Window::GetURL() {
NavigationController& controller = window_->GetWebContents()->GetController();
if (!controller.GetActiveEntry())
return GURL();
return controller.GetActiveEntry()->GetVirtualURL();
}
bool Window::CanGoBack() {
return window_->GetWebContents()->GetController().CanGoBack();
}
bool Window::CanGoForward() {
return window_->GetWebContents()->GetController().CanGoForward();
}
bool Window::CanGoToOffset(int offset) {
return window_->GetWebContents()->GetController().CanGoToOffset(offset);
}
void Window::GoBack() {
window_->GetWebContents()->GetController().GoBack();
}
void Window::GoForward() {
window_->GetWebContents()->GetController().GoForward();
}
void Window::GoToIndex(int index) {
window_->GetWebContents()->GetController().GoToIndex(index);
}
void Window::GoToOffset(int offset) {
window_->GetWebContents()->GetController().GoToOffset(offset);
}
void Window::Reload() {
window_->GetWebContents()->GetController().Reload(false);
}
void Window::ReloadIgnoringCache() {
window_->GetWebContents()->GetController().ReloadIgnoringCache(false);
} }
// static // static
@ -462,27 +357,8 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("blurWebView", &Window::BlurWebView) .SetMethod("blurWebView", &Window::BlurWebView)
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused) .SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
.SetMethod("capturePage", &Window::CapturePage) .SetMethod("capturePage", &Window::CapturePage)
.SetMethod("getPageTitle", &Window::GetPageTitle) .SetMethod("_getWebContents", &Window::GetWebContents)
.SetMethod("isLoading", &Window::IsLoading) .SetMethod("_getDevToolsWebContents", &Window::GetDevToolsWebContents);
.SetMethod("isWaitingForResponse", &Window::IsWaitingForResponse)
.SetMethod("stop", &Window::Stop)
.SetMethod("getRoutingId", &Window::GetRoutingID)
.SetMethod("getProcessId", &Window::GetProcessID)
.SetMethod("isCrashed", &Window::IsCrashed)
.SetMethod("getDevTools", &Window::GetDevTools)
.SetMethod("executeJavaScriptInDevTools",
&Window::ExecuteJavaScriptInDevTools)
.SetMethod("loadUrl", &Window::LoadURL)
.SetMethod("getUrl", &Window::GetURL)
.SetMethod("canGoBack", &Window::CanGoBack)
.SetMethod("canGoForward", &Window::CanGoForward)
.SetMethod("canGoToOffset", &Window::CanGoToOffset)
.SetMethod("goBack", &Window::GoBack)
.SetMethod("goForward", &Window::GoForward)
.SetMethod("goToIndex", &Window::GoToIndex)
.SetMethod("goToOffset", &Window::GoToOffset)
.SetMethod("reload", &Window::Reload)
.SetMethod("reloadIgnoringCache", &Window::ReloadIgnoringCache);
} }
} // namespace api } // namespace api

View file

@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "atom/browser/native_window_observer.h" #include "atom/browser/native_window_observer.h"
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/event_emitter.h"
#include "native_mate/handle.h"
class GURL; class GURL;
@ -29,6 +30,8 @@ class NativeWindow;
namespace api { namespace api {
class WebContents;
class Window : public mate::EventEmitter, class Window : public mate::EventEmitter,
public NativeWindowObserver { public NativeWindowObserver {
public: public:
@ -47,14 +50,11 @@ class Window : public mate::EventEmitter,
// Implementations of NativeWindowObserver: // Implementations of NativeWindowObserver:
virtual void OnPageTitleUpdated(bool* prevent_default, virtual void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) OVERRIDE; const std::string& title) OVERRIDE;
virtual void OnLoadingStateChanged(bool is_loading) OVERRIDE;
virtual void WillCloseWindow(bool* prevent_default) OVERRIDE; virtual void WillCloseWindow(bool* prevent_default) OVERRIDE;
virtual void OnWindowClosed() OVERRIDE; virtual void OnWindowClosed() OVERRIDE;
virtual void OnWindowBlur() OVERRIDE; virtual void OnWindowBlur() OVERRIDE;
virtual void OnRendererUnresponsive() OVERRIDE; virtual void OnRendererUnresponsive() OVERRIDE;
virtual void OnRendererResponsive() OVERRIDE; virtual void OnRendererResponsive() OVERRIDE;
virtual void OnRenderViewDeleted(int process_id, int routing_id) OVERRIDE;
virtual void OnRendererCrashed() OVERRIDE;
private: private:
// APIs for NativeWindow. // APIs for NativeWindow.
@ -100,30 +100,8 @@ class Window : public mate::EventEmitter,
void CapturePage(mate::Arguments* args); void CapturePage(mate::Arguments* args);
// APIs for WebContents. // APIs for WebContents.
string16 GetPageTitle(); mate::Handle<WebContents> GetWebContents(v8::Isolate* isolate) const;
bool IsLoading(); mate::Handle<WebContents> GetDevToolsWebContents(v8::Isolate* isolate) const;
bool IsWaitingForResponse();
void Stop();
int GetRoutingID();
int GetProcessID();
bool IsCrashed();
// APIs for devtools.
mate::Dictionary GetDevTools(v8::Isolate* isolate);
void ExecuteJavaScriptInDevTools(const std::string& code);
// APIs for NavigationController.
void LoadURL(const GURL& url);
GURL GetURL();
bool CanGoBack();
bool CanGoForward();
bool CanGoToOffset(int offset);
void GoBack();
void GoForward();
void GoToIndex(int index);
void GoToOffset(int offset);
void Reload();
void ReloadIgnoringCache();
scoped_ptr<NativeWindow> window_; scoped_ptr<NativeWindow> window_;

View file

@ -1,93 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_browser_bindings.h"
#include <vector>
#include "atom/browser/api/event.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/v8_value_converter.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "atom/common/node_includes.h"
namespace atom {
AtomBrowserBindings::AtomBrowserBindings() {
}
void AtomBrowserBindings::OnRendererMessage(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
// process.emit(channel, 'message', process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(mate::ConvertToV8(node_isolate, channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
void AtomBrowserBindings::OnRendererMessageSync(
int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args,
content::WebContents* sender,
IPC::Message* message) {
v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
// Create the event object.
mate::Handle<mate::Event> event = mate::Event::Create(node_isolate);
event->SetSenderAndMessage(sender, message);
// process.emit(channel, 'sync-message', event, process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(mate::ConvertToV8(node_isolate, channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(event.ToV8());
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
} // namespace atom

View file

@ -1,49 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_H_
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_H_
#include "atom/common/api/atom_bindings.h"
#include "base/strings/string16.h"
namespace base {
class ListValue;
}
namespace content {
class WebContents;
}
namespace IPC {
class Message;
}
namespace atom {
class AtomBrowserBindings : public AtomBindings {
public:
AtomBrowserBindings();
// Called when received a message from renderer.
void OnRendererMessage(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(int process_id,
int routing_id,
const string16& channel,
const base::ListValue& args,
content::WebContents* sender,
IPC::Message* message);
private:
DISALLOW_COPY_AND_ASSIGN(AtomBrowserBindings);
};
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_H_

View file

@ -24,6 +24,13 @@ bool EventEmitter::Emit(const base::StringPiece& name) {
bool EventEmitter::Emit(const base::StringPiece& name, bool EventEmitter::Emit(const base::StringPiece& name,
const base::ListValue& args) { const base::ListValue& args) {
return Emit(name, args, NULL, NULL);
}
bool EventEmitter::Emit(const base::StringPiece& name,
const base::ListValue& args,
content::WebContents* sender,
IPC::Message* message) {
v8::Locker locker(node_isolate); v8::Locker locker(node_isolate);
v8::HandleScope handle_scope(node_isolate); v8::HandleScope handle_scope(node_isolate);
@ -31,6 +38,8 @@ bool EventEmitter::Emit(const base::StringPiece& name,
scoped_ptr<atom::V8ValueConverter> converter(new atom::V8ValueConverter); scoped_ptr<atom::V8ValueConverter> converter(new atom::V8ValueConverter);
mate::Handle<mate::Event> event = mate::Event::Create(node_isolate); mate::Handle<mate::Event> event = mate::Event::Create(node_isolate);
if (sender && message)
event->SetSenderAndMessage(sender, message);
// v8_args = [name, event, args...]; // v8_args = [name, event, args...];
std::vector<v8::Handle<v8::Value>> v8_args; std::vector<v8::Handle<v8::Value>> v8_args;

View file

@ -11,6 +11,14 @@ namespace base {
class ListValue; class ListValue;
} }
namespace content {
class WebContents;
}
namespace IPC {
class Message;
}
namespace mate { namespace mate {
// Provide helperers to emit event in JavaScript. // Provide helperers to emit event in JavaScript.
@ -18,12 +26,16 @@ class EventEmitter : public Wrappable {
protected: protected:
EventEmitter(); EventEmitter();
// this.emit(name); // this.emit(name, new Event());
bool Emit(const base::StringPiece& name); bool Emit(const base::StringPiece& name);
// this.emit(name, args...); // this.emit(name, new Event(), args...);
bool Emit(const base::StringPiece& name, const base::ListValue& args); bool Emit(const base::StringPiece& name, const base::ListValue& args);
// this.emit(name, new Event(sender, message), args...);
bool Emit(const base::StringPiece& name, const base::ListValue& args,
content::WebContents* sender, IPC::Message* message);
private: private:
DISALLOW_COPY_AND_ASSIGN(EventEmitter); DISALLOW_COPY_AND_ASSIGN(EventEmitter);
}; };

View file

@ -1,6 +1,7 @@
EventEmitter = require('events').EventEmitter EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map' IDWeakMap = require 'id-weak-map'
app = require 'app' app = require 'app'
wrapWebContents = require('web-contents').wrap
BrowserWindow = process.atomBinding('window').BrowserWindow BrowserWindow = process.atomBinding('window').BrowserWindow
BrowserWindow::__proto__ = EventEmitter.prototype BrowserWindow::__proto__ = EventEmitter.prototype
@ -14,6 +15,20 @@ BrowserWindow::_init = ->
menu = app.getApplicationMenu() menu = app.getApplicationMenu()
@setMenu menu if menu? @setMenu menu if menu?
@webContents = @getWebContents()
@webContents.once 'destroyed', => @webContents = null
# Define getter for devToolsWebContents.
devToolsWebContents = null
@__defineGetter__ 'devToolsWebContents', ->
if @isDevToolsOpened()
# Get a new devToolsWebContents if previous one has been destroyed, it
# could happen when the devtools has been closed and then reopened.
devToolsWebContents = null unless devToolsWebContents?.isAlive()
devToolsWebContents ?= @getDevToolsWebContents()
else
devToolsWebContents = null
# Remember the window. # Remember the window.
id = BrowserWindow.windows.add this id = BrowserWindow.windows.add this
@ -24,12 +39,18 @@ BrowserWindow::_init = ->
# Tell the rpc server that a render view has been deleted and we need to # Tell the rpc server that a render view has been deleted and we need to
# release all objects owned by it. # release all objects owned by it.
@on 'render-view-deleted', (event, processId, routingId) -> @webContents.on 'render-view-deleted', (event, processId, routingId) ->
process.emit 'ATOM_BROWSER_RELEASE_RENDER_VIEW', processId, routingId process.emit 'ATOM_BROWSER_RELEASE_RENDER_VIEW', "#{processId}-#{routingId}"
BrowserWindow::toggleDevTools = -> BrowserWindow::toggleDevTools = ->
if @isDevToolsOpened() then @closeDevTools() else @openDevTools() if @isDevToolsOpened() then @closeDevTools() else @openDevTools()
BrowserWindow::getWebContents = ->
wrapWebContents @_getWebContents()
BrowserWindow::getDevToolsWebContents = ->
wrapWebContents @_getDevToolsWebContents()
BrowserWindow::restart = -> BrowserWindow::restart = ->
@loadUrl(@getUrl()) @loadUrl(@getUrl())
@ -50,16 +71,30 @@ BrowserWindow.getFocusedWindow = ->
windows = BrowserWindow.getAllWindows() windows = BrowserWindow.getAllWindows()
return window for window in windows when window.isFocused() return window for window in windows when window.isFocused()
BrowserWindow.fromProcessIdAndRoutingId = (processId, routingId) -> BrowserWindow.fromWebContents = (webContents) ->
windows = BrowserWindow.getAllWindows() windows = BrowserWindow.getAllWindows()
return window for window in windows when window.getProcessId() == processId and return window for window in windows when webContents.equal window.webContents
window.getRoutingId() == routingId
BrowserWindow.fromDevTools = (processId, routingId) -> BrowserWindow.fromDevToolsWebContents = (webContents) ->
windows = BrowserWindow.getAllWindows() windows = BrowserWindow.getAllWindows()
for window in windows when window.isDevToolsOpened() return window for window in windows when webContents.equal window.devToolsWebContents
devtools = window.getDevTools()
return window if devtools.processId == processId and # Helpers.
devtools.routingId == routingId BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
# Be compatible with old API.
BrowserWindow::getUrl = -> @webContents.getUrl()
BrowserWindow::reload = -> @webContents.reload()
BrowserWindow::reloadIgnoringCache = -> @webContents.reloadIgnoringCache()
BrowserWindow::getPageTitle = -> @webContents.getTitle()
BrowserWindow::isLoading = -> @webContents.isLoading()
BrowserWindow::isWaitingForResponse = -> @webContents.isWaitingForResponse()
BrowserWindow::stop = -> @webContents.stop()
BrowserWindow::getRoutingId = -> @webContents.getRoutingId()
BrowserWindow::getProcessId = -> @webContents.getProcessId()
BrowserWindow::isCrashed = -> @webContents.isCrashed()
BrowserWindow::executeJavaScriptInDevTools = (code) ->
@devToolsWebContents.executeJavaScript code
module.exports = BrowserWindow module.exports = BrowserWindow

View file

@ -1,32 +1,3 @@
EventEmitter = require('events').EventEmitter EventEmitter = require('events').EventEmitter
send = process.atomBinding('ipc').send
sendWrap = (channel, processId, routingId, args...) -> module.exports = new EventEmitter
BrowserWindow = require 'browser-window'
if processId?.constructor is BrowserWindow
window = processId
args = [routingId, args...]
processId = window.getProcessId()
routingId = window.getRoutingId()
send channel, processId, routingId, [args...]
class Ipc extends EventEmitter
constructor: ->
process.on 'ATOM_INTERNAL_MESSAGE', (args...) =>
@emit(args...)
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (channel, event, args...) =>
set = (value) -> event.sendReply JSON.stringify(value)
Object.defineProperty event, 'returnValue', {set}
Object.defineProperty event, 'result', {set}
@emit(channel, event, args...)
send: (processId, routingId, args...) ->
@sendChannel(processId, routingId, 'message', args...)
sendChannel: (args...) ->
sendWrap('ATOM_INTERNAL_MESSAGE', args...)
module.exports = new Ipc

View file

@ -0,0 +1,27 @@
EventEmitter = require('events').EventEmitter
ipc = require 'ipc'
module.exports.wrap = (webContents) ->
return null unless webContents.isAlive()
# webContents is an EventEmitter.
webContents.__proto__ = EventEmitter.prototype
# WebContents::send(channel, args..)
webContents.send = (args...) ->
@_send 'ATOM_INTERNAL_MESSAGE', [args...]
# The processId and routingId and identify a webContents.
webContents.getId = -> "#{@getProcessId()}-#{@getRoutingId()}"
webContents.equal = (other) -> @getId() is other.getId()
# Dispatch IPC messages to the ipc module.
webContents.on 'ipc-message', (event, channel, args...) =>
Object.defineProperty event, 'sender', value: webContents
ipc.emit channel, event, args...
webContents.on 'ipc-message-sync', (event, channel, args...) =>
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
Object.defineProperty event, 'sender', value: webContents
ipc.emit channel, event, args...
webContents

View file

@ -4,10 +4,10 @@
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h" #include "atom/common/node_bindings.h"
#include "net/proxy/proxy_resolver_v8.h" #include "net/proxy/proxy_resolver_v8.h"
@ -23,7 +23,7 @@ namespace atom {
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL; AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
AtomBrowserMainParts::AtomBrowserMainParts() AtomBrowserMainParts::AtomBrowserMainParts()
: atom_bindings_(new AtomBrowserBindings), : atom_bindings_(new AtomBindings),
browser_(new Browser), browser_(new Browser),
node_bindings_(NodeBindings::Create(true)) { node_bindings_(NodeBindings::Create(true)) {
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts"; DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";

View file

@ -9,7 +9,7 @@
namespace atom { namespace atom {
class AtomBrowserBindings; class AtomBindings;
class Browser; class Browser;
class NodeBindings; class NodeBindings;
@ -20,7 +20,6 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
static AtomBrowserMainParts* Get(); static AtomBrowserMainParts* Get();
AtomBrowserBindings* atom_bindings() { return atom_bindings_.get(); }
Browser* browser() { return browser_.get(); } Browser* browser() { return browser_.get(); }
protected: protected:
@ -37,7 +36,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
#endif #endif
private: private:
scoped_ptr<AtomBrowserBindings> atom_bindings_; scoped_ptr<AtomBindings> atom_bindings_;
scoped_ptr<Browser> browser_; scoped_ptr<Browser> browser_;
scoped_ptr<NodeBindings> node_bindings_; scoped_ptr<NodeBindings> node_bindings_;

View file

@ -1,64 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atom/browser/devtools_web_contents_observer.h"
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/common/api/api_messages.h"
#include "base/logging.h"
#include "content/public/browser/render_process_host.h"
#include "ipc/ipc_message_macros.h"
namespace atom {
DevToolsWebContentsObserver::DevToolsWebContentsObserver(
NativeWindow* native_window,
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
inspected_window_(native_window) {
DCHECK(native_window);
}
DevToolsWebContentsObserver::~DevToolsWebContentsObserver() {
}
bool DevToolsWebContentsObserver::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DevToolsWebContentsObserver, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void DevToolsWebContentsObserver::OnRendererMessage(
const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetRoutingID(),
channel,
args);
}
void DevToolsWebContentsObserver::OnRendererMessageSync(
const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetRoutingID(),
channel,
args,
web_contents(),
reply_msg);
}
} // namespace atom

View file

@ -1,41 +0,0 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_DEVTOOLS_WEB_CONTENTS_OBSERVER_H_
#define ATOM_BROWSER_DEVTOOLS_WEB_CONTENTS_OBSERVER_H_
#include "content/public/browser/web_contents_observer.h"
namespace base {
class ListValue;
}
namespace atom {
class NativeWindow;
class DevToolsWebContentsObserver : public content::WebContentsObserver {
public:
DevToolsWebContentsObserver(NativeWindow* native_window,
content::WebContents* web_contents);
virtual ~DevToolsWebContentsObserver();
protected:
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
void OnRendererMessage(const string16& channel,
const base::ListValue& args);
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg);
private:
NativeWindow* inspected_window_;
DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
};
} // namespace atom
#endif // ATOM_BROWSER_DEVTOOLS_WEB_CONTENTS_OBSERVER_H_

View file

@ -29,13 +29,11 @@ class ObjectsStore
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
@objects[id] @objects[id]
@forRenderView: (processId, routingId) -> @forRenderView: (key) ->
key = "#{processId}_#{routingId}"
@stores[key] = new ObjectsStore unless @stores[key]? @stores[key] = new ObjectsStore unless @stores[key]?
@stores[key] @stores[key]
@releaseForRenderView: (processId, routingId) -> @releaseForRenderView: (key) ->
key = "#{processId}_#{routingId}"
delete @stores[key] delete @stores[key]
class ObjectsRegistry extends EventEmitter class ObjectsRegistry extends EventEmitter
@ -52,7 +50,7 @@ class ObjectsRegistry extends EventEmitter
# Register a new object, the object would be kept referenced until you release # Register a new object, the object would be kept referenced until you release
# it explicitly. # it explicitly.
add: (processId, routingId, obj) -> add: (key, obj) ->
# Some native objects may already been added to objectsWeakMap, be care not # Some native objects may already been added to objectsWeakMap, be care not
# to add it twice. # to add it twice.
@objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId' @objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
@ -63,7 +61,7 @@ class ObjectsRegistry extends EventEmitter
# with the storeId. # with the storeId.
# We use a difference key because the same object can be referenced for # We use a difference key because the same object can be referenced for
# multiple times by the same renderer view. # multiple times by the same renderer view.
store = ObjectsStore.forRenderView processId, routingId store = ObjectsStore.forRenderView key
storeId = store.add obj storeId = store.add obj
[id, storeId] [id, storeId]
@ -73,12 +71,12 @@ class ObjectsRegistry extends EventEmitter
@objectsWeakMap.get id @objectsWeakMap.get id
# Remove an object according to its storeId. # Remove an object according to its storeId.
remove: (processId, routingId, storeId) -> remove: (key, storeId) ->
ObjectsStore.forRenderView(processId, routingId).remove storeId ObjectsStore.forRenderView(key).remove storeId
# Clear all references to objects from renderer view. # Clear all references to objects from renderer view.
clear: (processId, routingId) -> clear: (key) ->
@emit "release-renderer-view-#{processId}-#{routingId}" @emit "clear-#{key}"
ObjectsStore.releaseForRenderView processId, routingId ObjectsStore.releaseForRenderView key
module.exports = new ObjectsRegistry module.exports = new ObjectsRegistry

View file

@ -4,7 +4,7 @@ objectsRegistry = require './objects-registry.js'
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'
# Convert a real value into meta data. # Convert a real value into meta data.
valueToMeta = (processId, routingId, value) -> valueToMeta = (sender, value) ->
meta = type: typeof value meta = type: typeof value
meta.type = 'value' if value is null meta.type = 'value' if value is null
@ -15,14 +15,14 @@ valueToMeta = (processId, routingId, value) ->
if meta.type is 'array' if meta.type is 'array'
meta.members = [] meta.members = []
meta.members.push valueToMeta(processId, routingId, el) for el in value meta.members.push valueToMeta(sender, el) for el in value
else if meta.type is 'object' or meta.type is 'function' else if meta.type is 'object' or meta.type is 'function'
meta.name = value.constructor.name meta.name = value.constructor.name
# Reference the original value if it's an object, because when it's # 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 # passed to renderer we would assume the renderer keeps a reference of
# it. # it.
[meta.id, meta.storeId] = objectsRegistry.add processId, routingId, value [meta.id, meta.storeId] = objectsRegistry.add sender.getId(), value
meta.members = [] meta.members = []
meta.members.push {name: prop, type: typeof field} for prop, field of value meta.members.push {name: prop, type: typeof field} for prop, field of value
@ -37,12 +37,12 @@ errorToMeta = (error) ->
type: 'error', message: error.message, stack: (error.stack || error) type: 'error', message: error.message, stack: (error.stack || error)
# Convert array of meta data from renderer into array of real values. # Convert array of meta data from renderer into array of real values.
unwrapArgs = (processId, routingId, args) -> unwrapArgs = (sender, args) ->
metaToValue = (meta) -> metaToValue = (meta) ->
switch meta.type switch meta.type
when 'value' then meta.value when 'value' then meta.value
when 'remote-object' then objectsRegistry.get meta.id when 'remote-object' then objectsRegistry.get meta.id
when 'array' then unwrapArgs processId, routingId, meta.value when 'array' then unwrapArgs sender, meta.value
when 'object' when 'object'
ret = v8Util.createObjectWithName meta.name ret = v8Util.createObjectWithName meta.name
for member in meta.members for member in meta.members
@ -53,15 +53,15 @@ unwrapArgs = (processId, routingId, args) ->
-> returnValue -> returnValue
when 'function' when 'function'
rendererReleased = false rendererReleased = false
objectsRegistry.once "release-renderer-view-#{processId}-#{routingId}", -> objectsRegistry.once "clear-#{sender.getId()}", ->
rendererReleased = true rendererReleased = true
ret = -> ret = ->
throw new Error('Calling a callback of released renderer view') if rendererReleased throw new Error('Calling a callback of released renderer view') if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments) sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)
v8Util.setDestructor ret, -> v8Util.setDestructor ret, ->
return if rendererReleased return if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id sender.send 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id
ret ret
else throw new TypeError("Unknown type: #{meta.type}") else throw new TypeError("Unknown type: #{meta.type}")
@ -69,78 +69,78 @@ unwrapArgs = (processId, routingId, args) ->
# Call a function and send reply asynchronously if it's a an asynchronous # Call a function and send reply asynchronously if it's a an asynchronous
# style function and the caller didn't pass a callback. # style function and the caller didn't pass a callback.
callFunction = (event, processId, routingId, func, caller, args) -> callFunction = (event, func, caller, args) ->
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function' if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
args.push (ret) -> args.push (ret) ->
event.returnValue = valueToMeta processId, routingId, ret event.returnValue = valueToMeta event.sender, ret
func.apply caller, args func.apply caller, args
else else
ret = func.apply caller, args ret = func.apply caller, args
event.returnValue = valueToMeta processId, routingId, ret event.returnValue = valueToMeta event.sender, ret
# Send by BrowserWindow when its render view is deleted. # Send by BrowserWindow when its render view is deleted.
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (processId, routingId) -> process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) ->
objectsRegistry.clear processId, routingId objectsRegistry.clear id
ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) -> ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
try try
event.returnValue = valueToMeta processId, routingId, require(module) event.returnValue = valueToMeta event.sender, require(module)
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) -> ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
try try
event.returnValue = valueToMeta processId, routingId, global[name] event.returnValue = valueToMeta event.sender, global[name]
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) -> ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
try try
BrowserWindow = require 'browser-window' BrowserWindow = require 'browser-window'
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId window = BrowserWindow.fromWebContents event.sender
window = BrowserWindow.fromDevTools processId, routingId unless window? window = BrowserWindow.fromDevToolsWebContents event.sender unless window?
event.returnValue = valueToMeta processId, routingId, window event.returnValue = valueToMeta event.sender, window
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) -> ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
constructor = objectsRegistry.get id constructor = objectsRegistry.get id
# Call new with array of arguments. # Call new with array of arguments.
# http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible # http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
obj = new (Function::bind.apply(constructor, [null].concat(args))) obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta processId, routingId, obj event.returnValue = valueToMeta event.sender, obj
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) -> ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
func = objectsRegistry.get id func = objectsRegistry.get id
callFunction event, processId, routingId, func, global, args callFunction event, func, global, args
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, method, args) -> ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
constructor = objectsRegistry.get(id)[method] constructor = objectsRegistry.get(id)[method]
# Call new with array of arguments. # Call new with array of arguments.
obj = new (Function::bind.apply(constructor, [null].concat(args))) obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta processId, routingId, obj event.returnValue = valueToMeta event.sender, obj
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, processId, routingId, id, method, args) -> ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
try try
args = unwrapArgs processId, routingId, args args = unwrapArgs event.sender, args
obj = objectsRegistry.get id obj = objectsRegistry.get id
callFunction event, processId, routingId, obj[method], obj, args callFunction event, obj[method], obj, args
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, processId, routingId, id, name, value) -> ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
try try
obj = objectsRegistry.get id obj = objectsRegistry.get id
obj[name] = value obj[name] = value
@ -148,12 +148,12 @@ ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, processId, routingId, id, name, value)
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, processId, routingId, id, name) -> ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
try try
obj = objectsRegistry.get id obj = objectsRegistry.get id
event.returnValue = valueToMeta processId, routingId, obj[name] event.returnValue = valueToMeta event.sender, obj[name]
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) -> ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, storeId) ->
objectsRegistry.remove processId, routingId, storeId objectsRegistry.remove event.sender.getId(), storeId

View file

@ -8,13 +8,10 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "atom/browser/api/atom_browser_bindings.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_javascript_dialog_manager.h" #include "atom/browser/atom_javascript_dialog_manager.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/devtools_delegate.h" #include "atom/browser/devtools_delegate.h"
#include "atom/browser/devtools_web_contents_observer.h"
#include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/file_dialog.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "atom/common/api/api_messages.h" #include "atom/common/api/api_messages.h"
@ -195,12 +192,8 @@ bool NativeWindow::HasModalDialog() {
void NativeWindow::OpenDevTools() { void NativeWindow::OpenDevTools() {
if (devtools_window_) { if (devtools_window_) {
devtools_window_->Focus(true); devtools_window_->Focus(true);
devtools_web_contents_observer_.reset(new DevToolsWebContentsObserver(
this, devtools_window_->GetWebContents()));
} else { } else {
inspectable_web_contents()->ShowDevTools(); inspectable_web_contents()->ShowDevTools();
devtools_web_contents_observer_.reset(new DevToolsWebContentsObserver(
this, GetDevToolsWebContents()));
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Temporary fix for flashing devtools, try removing this after upgraded to // Temporary fix for flashing devtools, try removing this after upgraded to
// Chrome 32. // Chrome 32.
@ -229,11 +222,6 @@ void NativeWindow::InspectElement(int x, int y) {
agent->InspectElement(x, y); agent->InspectElement(x, y);
} }
void NativeWindow::ExecuteJavaScriptInDevTools(const std::string& script) {
GetDevToolsWebContents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
string16(), base::UTF8ToUTF16(script));
}
void NativeWindow::FocusOnWebView() { void NativeWindow::FocusOnWebView() {
GetWebContents()->GetRenderViewHost()->Focus(); GetWebContents()->GetRenderViewHost()->Focus();
} }
@ -305,14 +293,6 @@ void NativeWindow::DestroyWebContents() {
if (!inspectable_web_contents_) if (!inspectable_web_contents_)
return; return;
// The OnRenderViewDeleted is not called when the WebContents is destroyed
// directly (e.g. when closing the window), so we make sure it's always
// emitted to users by sending it before window is closed..
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnRenderViewDeleted(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID()));
inspectable_web_contents_.reset(); inspectable_web_contents_.reset();
} }
@ -437,13 +417,6 @@ void NativeWindow::DeactivateContents(content::WebContents* contents) {
BlurWebView(); BlurWebView();
} }
void NativeWindow::LoadingStateChanged(content::WebContents* source) {
bool is_loading = source->IsLoading();
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnLoadingStateChanged(is_loading));
}
void NativeWindow::MoveContents(content::WebContents* source, void NativeWindow::MoveContents(content::WebContents* source,
const gfx::Rect& pos) { const gfx::Rect& pos) {
SetPosition(pos.origin()); SetPosition(pos.origin());
@ -482,16 +455,6 @@ void NativeWindow::RendererResponsive(content::WebContents* source) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive()); FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
} }
void NativeWindow::RenderViewDeleted(content::RenderViewHost* rvh) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnRenderViewDeleted(rvh->GetProcess()->GetID(),
rvh->GetRoutingID()));
}
void NativeWindow::RenderProcessGone(base::TerminationStatus status) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed());
}
void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) { void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since // Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired. // there are two virtual functions named BeforeUnloadFired.
@ -500,9 +463,6 @@ void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
bool NativeWindow::OnMessageReceived(const IPC::Message& message) { bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
bool handled = true; bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NativeWindow, message) IPC_BEGIN_MESSAGE_MAP(NativeWindow, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions, IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions,
UpdateDraggableRegions) UpdateDraggableRegions)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
@ -628,28 +588,8 @@ void NativeWindow::CallDevToolsFunction(const std::string& function_name,
} }
} }
} }
ExecuteJavaScriptInDevTools(function_name + "(" + params + ");"); GetDevToolsWebContents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
} string16(), base::UTF8ToUTF16(function_name + "(" + params + ");"));
void NativeWindow::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(),
channel,
args);
}
void NativeWindow::OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(),
channel,
args,
GetWebContents(),
reply_msg);
} }
} // namespace atom } // namespace atom

View file

@ -46,7 +46,6 @@ namespace atom {
class AtomJavaScriptDialogManager; class AtomJavaScriptDialogManager;
class DevToolsDelegate; class DevToolsDelegate;
class DevToolsWebContentsObserver;
struct DraggableRegion; struct DraggableRegion;
class NativeWindow : public brightray::DefaultWebContentsDelegate, class NativeWindow : public brightray::DefaultWebContentsDelegate,
@ -136,7 +135,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void CloseDevTools(); virtual void CloseDevTools();
virtual bool IsDevToolsOpened(); virtual bool IsDevToolsOpened();
virtual void InspectElement(int x, int y); virtual void InspectElement(int x, int y);
virtual void ExecuteJavaScriptInDevTools(const std::string& script);
virtual void FocusOnWebView(); virtual void FocusOnWebView();
virtual void BlurWebView(); virtual void BlurWebView();
@ -220,7 +218,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual bool CanOverscrollContent() const OVERRIDE; virtual bool CanOverscrollContent() const OVERRIDE;
virtual void ActivateContents(content::WebContents* contents) OVERRIDE; virtual void ActivateContents(content::WebContents* contents) OVERRIDE;
virtual void DeactivateContents(content::WebContents* contents) OVERRIDE; virtual void DeactivateContents(content::WebContents* contents) OVERRIDE;
virtual void LoadingStateChanged(content::WebContents* source) OVERRIDE;
virtual void MoveContents(content::WebContents* source, virtual void MoveContents(content::WebContents* source,
const gfx::Rect& pos) OVERRIDE; const gfx::Rect& pos) OVERRIDE;
virtual void CloseContents(content::WebContents* source) OVERRIDE; virtual void CloseContents(content::WebContents* source) OVERRIDE;
@ -230,8 +227,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void RendererResponsive(content::WebContents* source) OVERRIDE; virtual void RendererResponsive(content::WebContents* source) OVERRIDE;
// Implementations of content::WebContentsObserver. // Implementations of content::WebContentsObserver.
virtual void RenderViewDeleted(content::RenderViewHost*) OVERRIDE;
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE; virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
@ -274,13 +269,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
bool succeed, bool succeed,
const SkBitmap& bitmap); const SkBitmap& bitmap);
void OnRendererMessage(const string16& channel,
const base::ListValue& args);
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
IPC::Message* reply_msg);
// Notification manager. // Notification manager.
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
@ -305,9 +293,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
base::WeakPtr<NativeWindow> devtools_window_; base::WeakPtr<NativeWindow> devtools_window_;
scoped_ptr<DevToolsDelegate> devtools_delegate_; scoped_ptr<DevToolsDelegate> devtools_delegate_;
// WebContentsObserver for the WebContents of devtools.
scoped_ptr<DevToolsWebContentsObserver> devtools_web_contents_observer_;
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_; scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
// Notice that inspectable_web_contents_ must be placed after dialog_manager_, // Notice that inspectable_web_contents_ must be placed after dialog_manager_,

View file

@ -17,9 +17,6 @@ class NativeWindowObserver {
virtual void OnPageTitleUpdated(bool* prevent_default, virtual void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) {} const std::string& title) {}
// Called when the window is starting or is done loading a page.
virtual void OnLoadingStateChanged(bool is_loading) {}
// Called when the window is gonna closed. // Called when the window is gonna closed.
virtual void WillCloseWindow(bool* prevent_default) {} virtual void WillCloseWindow(bool* prevent_default) {}
@ -34,12 +31,6 @@ class NativeWindowObserver {
// Called when renderer recovers. // Called when renderer recovers.
virtual void OnRendererResponsive() {} virtual void OnRendererResponsive() {}
// Called when a render view has been deleted.
virtual void OnRenderViewDeleted(int process_id, int routing_id) {}
// Called when renderer has crashed.
virtual void OnRendererCrashed() {}
}; };
} // namespace atom } // namespace atom

View file

@ -12,7 +12,6 @@ NODE_EXT_LIST_START
NODE_EXT_LIST_ITEM(atom_browser_app) NODE_EXT_LIST_ITEM(atom_browser_app)
NODE_EXT_LIST_ITEM(atom_browser_auto_updater) NODE_EXT_LIST_ITEM(atom_browser_auto_updater)
NODE_EXT_LIST_ITEM(atom_browser_dialog) NODE_EXT_LIST_ITEM(atom_browser_dialog)
NODE_EXT_LIST_ITEM(atom_browser_ipc)
NODE_EXT_LIST_ITEM(atom_browser_menu) NODE_EXT_LIST_ITEM(atom_browser_menu)
NODE_EXT_LIST_ITEM(atom_browser_power_monitor) NODE_EXT_LIST_ITEM(atom_browser_power_monitor)
NODE_EXT_LIST_ITEM(atom_browser_protocol) NODE_EXT_LIST_ITEM(atom_browser_protocol)

View file

@ -10,15 +10,13 @@ class Ipc extends EventEmitter
process.removeAllListeners 'ATOM_INTERNAL_MESSAGE' process.removeAllListeners 'ATOM_INTERNAL_MESSAGE'
send: (args...) -> send: (args...) ->
@sendChannel 'message', args... ipc.send 'ipc-message', [args...]
sendChannel: (args...) ->
ipc.send 'ATOM_INTERNAL_MESSAGE', [args...]
sendSync: (args...) -> sendSync: (args...) ->
@sendSync 'sync-message', args... JSON.parse ipc.sendSync('ipc-message-sync', [args...])
sendChannelSync: (args...) -> # Discarded
JSON.parse ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', [args...]) sendChannel: -> @send.apply this, arguments
sendChannelSync: -> @sendSync.apply this, arguments
module.exports = new Ipc module.exports = new Ipc

View file

@ -7,7 +7,7 @@ example is:
var BrowserWindow = require('browser-window'); var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600, show: false }); var win = new BrowserWindow({ width: 800, height: 600, show: false });
win.on('destroyed', function() { win.on('closed', function() {
win = null; win = null;
}); });
@ -86,13 +86,6 @@ you should explictly set `sandbox` to `none`:
Emitted when the document changed its title, calling `event.preventDefault()` Emitted when the document changed its title, calling `event.preventDefault()`
would prevent the native window's title to change. would prevent the native window's title to change.
### Event: 'loading-state-changed'
* `event` Event
* `isLoading` Boolean
Emitted when the window is starting or is done loading a page.
### Event: 'close' ### Event: 'close'
* `event` Event * `event` Event
@ -137,10 +130,6 @@ Emiited when the web page becomes unresponsive.
Emitted when the unresponsive web page becomes responsive again. Emitted when the unresponsive web page becomes responsive again.
### Event: 'crashed'
Emitted when the renderer process is crashed.
### Event: 'blur' ### Event: 'blur'
Emiited when window loses focus. Emiited when window loses focus.
@ -153,12 +142,20 @@ Returns an array of all opened browser windows.
Returns the window that is focused in this application. Returns the window that is focused in this application.
### Class Method: BrowserWindow.fromProcessIdAndRoutingId(processId, routingId) ### Class Method: BrowserWindow.fromWebContents(webContents)
* `processId` Integer * `webContents` WebContents
* `routingId` Integer
Find a window according to its `processId` and `routingId`. Find a window according to the `webContents` it owns
### BrowserWindow.webContents
The `WebContents` object this window owns, all web page related events and
operations would be done via it.
### BrowserWindow.devToolsWebContents
Get the `WebContents` of devtools of this window.
### BrowserWindow.destroy() ### BrowserWindow.destroy()
@ -334,13 +331,6 @@ Closes the developer tools.
Starts inspecting element at position (`x`, `y`). Starts inspecting element at position (`x`, `y`).
### BrowserWindow.executeJavaScriptInDevTools(code)
* `code` String
Evaluate `code` in devtools to use
[InspectorFrontendAPI](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/devtools/front_end/InspectorFrontendAPI.js&q=InspectorFrontendAPI&sq=package:chromium&type=cs)
### BrowserWindow.focusOnWebView() ### BrowserWindow.focusOnWebView()
### BrowserWindow.blurWebView() ### BrowserWindow.blurWebView()
@ -366,82 +356,113 @@ encode it and use data URL to embed the image in HTML.
[remote](../renderer/remote.md) if you are going to use this API in renderer [remote](../renderer/remote.md) if you are going to use this API in renderer
process. process.
### BrowserWindow.getPageTitle()
Returns the title of web page.
### BrowserWindow.isLoading()
Returns whether web page is still loading resources.
### BrowserWindow.isWaitingForResponse()
Returns whether web page is waiting for a first-response for the main resource
of the page.
### BrowserWindow.stop()
Stops any pending navigation.
### BrowserWindow.getProcessId()
Returns window's process ID. The process ID and routing ID can be used
together to locate a window.
### BrowserWindow.getRoutingId()
Returns window's routing ID. The process ID and routing ID can be used
together to locate a window.
### BrowserWindow.loadUrl(url) ### BrowserWindow.loadUrl(url)
Same with `webContents.loadUrl(url)`.
## Class: WebContents
A `WebContents` is responsible for rendering and controlling a web page.
`WebContents` is an
[EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter).
### Event: 'crashed'
Emitted when the renderer process is crashed.
### Event: 'did-finish-load'
Emitted when the navigation is done, i.e. the spinner of the tab will stop
spinning, and the onload event was dispatched.
### Event: 'did-start-loading'
### Event: 'did-stop-loading'
### WebContents.loadUrl(url)
* `url` URL * `url` URL
Loads the `url` in the window, the `url` must contains the protocol prefix, Loads the `url` in the window, the `url` must contains the protocol prefix,
e.g. the `http://` or `file://`. e.g. the `http://` or `file://`.
### BrowserWindow.getUrl() ### WebContents.getUrl()
Returns URL of current web page. Returns URL of current web page.
### BrowserWindow.canGoBack() ### WebContents.getTitle()
Returns the title of web page.
### WebContents.isLoading()
Returns whether web page is still loading resources.
### WebContents.isWaitingForResponse()
Returns whether web page is waiting for a first-response for the main resource
of the page.
### WebContents.stop()
Stops any pending navigation.
### WebContents.reload()
Reloads current page.
### WebContents.reloadIgnoringCache()
Reloads current page and ignores cache.
### WebContents.canGoBack()
Returns whether the web page can go back. Returns whether the web page can go back.
### BrowserWindow.canGoForward() ### WebContents.canGoForward()
Returns whether the web page can go forward. Returns whether the web page can go forward.
### BrowserWindow.canGoToOffset(offset) ### WebContents.canGoToOffset(offset)
* `offset` Integer * `offset` Integer
Returns whether the web page can go to `offset`. Returns whether the web page can go to `offset`.
### BrowserWindow.goBack() ### WebContents.goBack()
Makes the web page go back. Makes the web page go back.
### BrowserWindow.goForward() ### WebContents.goForward()
Makes the web page go forward. Makes the web page go forward.
### BrowserWindow.goToIndex(index) ### WebContents.goToIndex(index)
* `index` Integer * `index` Integer
Navigates to the specified absolute index. Navigates to the specified absolute index.
### BrowserWindow.goToOffset(offset) ### WebContents.goToOffset(offset)
* `offset` Integer * `offset` Integer
Navigates to the specified offset from the "current entry". Navigates to the specified offset from the "current entry".
### BrowserWindow.reload() ### WebContents.IsCrashed()
Reloads current window. Whether the renderer process has crashed.
### BrowserWindow.reloadIgnoringCache() ### WebContents.executeJavaScript(code)
Reloads current window and ignores cache. * `code` String
Evaluate `code` in page.
### WebContents.send(channel[, args...])
* `channel` String
Send `args..` to the web page via `channel` in asynchronous message, the web
page can handle it by listening to the `channel` event of `ipc` module.

View file

@ -1,52 +1,45 @@
# ipc (browser) # ipc (browser)
The `ipc` module allows developers to send asynchronous messages to renderers. Handles asynchronous and synchronous message sent from web page.
To avoid possible dead-locks, it's not allowed to send synchronous messages in
browser.
## Event: 'message' The messages sent from web page would be emitted to this module, the event name
is the `channel` when sending message. To reply a synchronous message, you need
to set `event.returnValue`, to send an asynchronous back to the sender, you can
use `event.sender.send(...)`.
* `processId` Integer An example of sending and handling messages:
* `routingId` Integer
Emitted when renderer sent a message to the browser.
## Event: 'sync-message'
* `event` Object
* `processId` Integer
* `routingId` Integer
Emitted when renderer sent a synchronous message to the browser. The receiver
should store the result in `event.returnValue`.
**Note:** Due to the limitation of `EventEmitter`, returning value in the
event handler has no effect, so we have to store the result by using the
`event` parameter.
## ipc.send(processId, routingId, [args...])
* `processId` Integer
* `routingId` Integer
Send `args...` to the renderer specified by `processId` and `routingId` and
return immediately, the renderer should handle the message by listening to the
`message` event.
## ipc.sendChannel(processId, routingId, channel, [args...])
* `processId` Integer
* `routingId` Integer
* `channel` String
This is the same with ipc.send, except that the renderer should listen to the
`channel` event. The ipc.send(processId, routingId, args...) can be seen as
ipc.sendChannel(processId, routingId, 'message', args...).
**Note:** If the the first argument (e.g. `processId`) is a `BrowserWindow`,
`ipc.sendChannel` would automatically get the `processId` and `routingId`
from it, so you can send a message to window like this:
```javascript ```javascript
ipc.sendChannel(browserWindow, 'message', ...); // In browser.
var ipc = require('ipc');
ipc.on('asynchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.sender.send('asynchronous-reply', 'pong');
});
ipc.on('synchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.returnValue = 'pong'.
});
``` ```
```javascript
// In web page.
var ipc = require('ipc');
console.log(ipc.sendSync('synchronous-message', 'ping')); // prints "pong"
ipc.on('asynchronous-reply', function(arg) {
console.log(arg); // prints "pong"
});
ipc.send('asynchronous-message', 'ping');
```
### Class: Event
## Event.returnValue
Assign to this to return an value to synchronous messages.
## Event.sender
The `WebContents` of the web page that has sent the message.

View file

@ -5,75 +5,18 @@ asynchronous messages to the browser, and also receive messages sent from
browser. If you want to make use of modules of browser from renderer, you browser. If you want to make use of modules of browser from renderer, you
might consider using the [remote](remote.md) module. might consider using the [remote](remote.md) module.
An example of echoing messages between browser and renderer: See [ipc (browser)](../browser/ipc-browser.md) for examples.
```javascript ## ipc.send(channel[, args...])
// In browser:
var ipc = require('ipc');
ipc.on('message', function(processId, routingId, m) {
ipc.send(processId, routingId, m);
});
```
```javascript Send `args..` to the web page via `channel` in asynchronous message, the browser
// In renderer: process can handle it by listening to the `channel` event of `ipc` module.
var ipc = require('ipc');
ipc.on('message', function(m) {
console.log('Received message', m);
});
ipc.send('Hello world');
```
An example of sending synchronous message from renderer to browser: ## ipc.sendSync(channel[, args...])
```javascript Send `args..` to the web page via `channel` in synchronous message, and returns
// In browser: the result sent from browser. The browser process can handle it by listening to
var ipc = require('ipc'); the `channel` event of `ipc` module, and returns by setting `event.returnValue`.
ipc.on('browser-data-request', function(event, processId, routingId, message) {
event.returnValue = 'THIS SOME DATA FROM THE BROWSER';
});
```
```javascript
// In renderer:
var ipc = require('ipc');
console.log(ipc.sendChannelSync('browser-data-request', 'THIS IS FROM THE RENDERER'));
```
## Event: 'message'
Emitted when browser sent a message to this window.
## ipc.send([args...])
Send all arguments to the browser and return immediately, the browser should
handle the message by listening to the `message` event.
## ipc.sendSync([args...])
Send all arguments to the browser synchronously, and returns the result sent
from browser. The browser should handle the message by listening to the
`sync-message` event.
**Note:** Usually developers should never use this API, since sending **Note:** Usually developers should never use this API, since sending
synchronous message would block the browser. synchronous message would block the whole web page.
## ipc.sendChannel(channel, [args...])
* `channel` String
This is the same with `ipc.send`, except that the browser should listen to the
`channel` event. The `ipc.send(args...)` can be seen as
`ipc.sendChannel('message', args...)`.
## ipc.sendChannelSync(channel, [args...])
* `channel` String
This is the same with `ipc.sendSync`, except that the browser should listen to
the `channel` event. The `ipc.sendSync(args...)` can be seen as
`ipc.sendChannelSync('sync-message', args...)`.
**Note:** Usually developers should never use this API, since sending
synchronous message would block the browser.

View file

@ -18,9 +18,8 @@ describe 'browser-window module', ->
describe 'BrowserWindow.close()', -> describe 'BrowserWindow.close()', ->
it 'should emit unload handler', (done) -> it 'should emit unload handler', (done) ->
w.on 'loading-state-changed', (event, isLoading) -> w.webContents.on 'did-finish-load', ->
if (!isLoading) w.close()
w.close()
w.on 'closed', -> w.on 'closed', ->
test = path.join(fixtures, 'api', 'unload') test = path.join(fixtures, 'api', 'unload')
content = fs.readFileSync(test) content = fs.readFileSync(test)
@ -32,9 +31,8 @@ describe 'browser-window module', ->
it 'should emit beforeunload handler', (done) -> it 'should emit beforeunload handler', (done) ->
w.on 'onbeforeunload', -> w.on 'onbeforeunload', ->
done() done()
w.on 'loading-state-changed', (event, isLoading) -> w.webContents.on 'did-finish-load', ->
if (!isLoading) w.close()
w.close()
w.loadUrl 'file://' + path.join(fixtures, 'api', 'beforeunload-false.html') w.loadUrl 'file://' + path.join(fixtures, 'api', 'beforeunload-false.html')
describe 'window.close()', -> describe 'window.close()', ->
@ -53,18 +51,9 @@ describe 'browser-window module', ->
w.loadUrl 'file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html') w.loadUrl 'file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')
describe 'BrowserWindow.loadUrl(url)', -> describe 'BrowserWindow.loadUrl(url)', ->
it 'should emit loading-state-changed event', (done) -> it 'should emit did-start-loading event', (done) ->
count = 0 w.webContents.on 'did-start-loading', ->
w.on 'loading-state-changed', (event, isLoading) -> done()
if count == 0
assert.equal isLoading, true
else if count == 1
assert.equal isLoading, false
done()
else
assert false
++count
w.loadUrl 'about:blank' w.loadUrl 'about:blank'
describe 'BrowserWindow.focus()', -> describe 'BrowserWindow.focus()', ->

View file

@ -48,13 +48,13 @@ describe 'ipc module', ->
print_name = remote.require path.join(fixtures, 'module', 'print_name.js') print_name = remote.require path.join(fixtures, 'module', 'print_name.js')
assert.equal print_name.print(buf), 'Buffer' assert.equal print_name.print(buf), 'Buffer'
describe 'ipc.send', -> describe 'ipc.sender.send', ->
it 'should work when sending an object containing id property', (done) -> it 'should work when sending an object containing id property', (done) ->
obj = id: 1, name: 'ly' obj = id: 1, name: 'ly'
ipc.once 'message', (message) -> ipc.once 'message', (message) ->
assert.deepEqual message, obj assert.deepEqual message, obj
done() done()
ipc.send obj ipc.send 'message', obj
describe 'ipc.sendSync', -> describe 'ipc.sendSync', ->
it 'can be replied by setting event.returnValue', -> it 'can be replied by setting event.returnValue', ->

View file

@ -8,8 +8,8 @@ var window = null;
app.commandLine.appendSwitch('js-flags', '--expose_gc'); app.commandLine.appendSwitch('js-flags', '--expose_gc');
ipc.on('message', function() { ipc.on('message', function(event, arg) {
ipc.send.apply(this, arguments); event.sender.send('message', arg);
}); });
ipc.on('console.log', function(pid, rid, args) { ipc.on('console.log', function(pid, rid, args) {
@ -24,11 +24,11 @@ ipc.on('process.exit', function(pid, rid, code) {
process.exit(code); process.exit(code);
}); });
ipc.on('eval', function(ev, pid, rid, script) { ipc.on('eval', function(ev, script) {
ev.returnValue = eval(script); ev.returnValue = eval(script);
}); });
ipc.on('echo', function(ev, pid, rid, msg) { ipc.on('echo', function(ev, msg) {
ev.returnValue = msg; ev.returnValue = msg;
}); });