Merge commit '58567834c7' into web-contents-download-url

Conflicts:
	atom/browser/api/atom_api_web_contents.cc
This commit is contained in:
Charlie Hess 2015-12-03 10:31:51 -08:00
commit f2797d2eab
55 changed files with 555 additions and 402 deletions

View file

@ -322,14 +322,6 @@ void Cookies::OnSetCookies(const CookiesCallback& callback,
callback)); callback));
} }
mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
net::CookieStore* Cookies::GetCookieStore() { net::CookieStore* Cookies::GetCookieStore() {
return request_context_getter_->GetURLRequestContext()->cookie_store(); return request_context_getter_->GetURLRequestContext()->cookie_store();
} }
@ -341,6 +333,15 @@ mate::Handle<Cookies> Cookies::Create(
return mate::CreateHandle(isolate, new Cookies(browser_context)); return mate::CreateHandle(isolate, new Cookies(browser_context));
} }
// static
void Cookies::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom

View file

@ -7,8 +7,8 @@
#include <string> #include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/callback.h" #include "base/callback.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "net/cookies/canonical_cookie.h" #include "net/cookies/canonical_cookie.h"
@ -33,7 +33,7 @@ namespace atom {
namespace api { namespace api {
class Cookies : public mate::Wrappable { class Cookies : public mate::TrackableObject<Cookies> {
public: public:
// node.js style callback function(error, result) // node.js style callback function(error, result)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)> typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
@ -42,6 +42,10 @@ class Cookies : public mate::Wrappable {
static mate::Handle<Cookies> Create(v8::Isolate* isolate, static mate::Handle<Cookies> Create(v8::Isolate* isolate,
content::BrowserContext* browser_context); content::BrowserContext* browser_context);
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit Cookies(content::BrowserContext* browser_context); explicit Cookies(content::BrowserContext* browser_context);
~Cookies(); ~Cookies();
@ -70,10 +74,6 @@ class Cookies : public mate::Wrappable {
void OnSetCookies(const CookiesCallback& callback, void OnSetCookies(const CookiesCallback& callback,
bool set_success); bool set_success);
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private: private:
// Must be called on IO thread. // Must be called on IO thread.
net::CookieStore* GetCookieStore(); net::CookieStore* GetCookieStore();

View file

@ -70,29 +70,20 @@ DownloadItem::DownloadItem(content::DownloadItem* download_item) :
} }
DownloadItem::~DownloadItem() { DownloadItem::~DownloadItem() {
Destroy(); if (download_item_)
} OnDownloadDestroyed(download_item_);
void DownloadItem::Destroy() {
if (download_item_) {
download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
}
}
bool DownloadItem::IsDestroyed() const {
return download_item_ == nullptr;
} }
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) { void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated"); download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
} }
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) { void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download_item) {
Destroy(); download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
} }
int64 DownloadItem::GetReceivedBytes() { int64 DownloadItem::GetReceivedBytes() {
@ -144,9 +135,11 @@ void DownloadItem::Cancel() {
download_item_->Cancel(true); download_item_->Cancel(true);
} }
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder( // static
v8::Isolate* isolate) { void DownloadItem::BuildPrototype(v8::Isolate* isolate,
return mate::ObjectTemplateBuilder(isolate) v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("pause", &DownloadItem::Pause) .SetMethod("pause", &DownloadItem::Pause)
.SetMethod("resume", &DownloadItem::Resume) .SetMethod("resume", &DownloadItem::Resume)
.SetMethod("cancel", &DownloadItem::Cancel) .SetMethod("cancel", &DownloadItem::Cancel)

View file

@ -17,7 +17,7 @@ namespace atom {
namespace api { namespace api {
class DownloadItem : public mate::EventEmitter, class DownloadItem : public mate::TrackableObject<DownloadItem>,
public content::DownloadItem::Observer { public content::DownloadItem::Observer {
public: public:
class SavePathData : public base::SupportsUserData::Data { class SavePathData : public base::SupportsUserData::Data {
@ -32,6 +32,10 @@ class DownloadItem : public mate::EventEmitter,
content::DownloadItem* item); content::DownloadItem* item);
static void* UserDataKey(); static void* UserDataKey();
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit DownloadItem(content::DownloadItem* download_item); explicit DownloadItem(content::DownloadItem* download_item);
~DownloadItem(); ~DownloadItem();
@ -53,13 +57,6 @@ class DownloadItem : public mate::EventEmitter,
void SetSavePath(const base::FilePath& path); void SetSavePath(const base::FilePath& path);
private: private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
void Destroy();
content::DownloadItem* download_item_; content::DownloadItem* download_item_;
DISALLOW_COPY_AND_ASSIGN(DownloadItem); DISALLOW_COPY_AND_ASSIGN(DownloadItem);

View file

@ -23,9 +23,6 @@ GlobalShortcut::GlobalShortcut() {
} }
GlobalShortcut::~GlobalShortcut() { GlobalShortcut::~GlobalShortcut() {
}
void GlobalShortcut::Destroy() {
UnregisterAll(); UnregisterAll();
} }

View file

@ -27,9 +27,6 @@ class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
GlobalShortcut(); GlobalShortcut();
~GlobalShortcut() override; ~GlobalShortcut() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override; v8::Isolate* isolate) override;

View file

@ -27,14 +27,6 @@ Menu::Menu()
Menu::~Menu() { Menu::~Menu() {
} }
void Menu::Destroy() {
model_.reset();
}
bool Menu::IsDestroyed() const {
return !model_;
}
void Menu::AfterInit(v8::Isolate* isolate) { void Menu::AfterInit(v8::Isolate* isolate) {
mate::Dictionary wrappable(isolate, GetWrapper(isolate)); mate::Dictionary wrappable(isolate, GetWrapper(isolate));
mate::Dictionary delegate; mate::Dictionary delegate;
@ -159,6 +151,7 @@ bool Menu::IsVisibleAt(int index) const {
void Menu::BuildPrototype(v8::Isolate* isolate, void Menu::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype) mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("insertItem", &Menu::InsertItemAt) .SetMethod("insertItem", &Menu::InsertItemAt)
.SetMethod("insertCheckItem", &Menu::InsertCheckItemAt) .SetMethod("insertCheckItem", &Menu::InsertCheckItemAt)
.SetMethod("insertRadioItem", &Menu::InsertRadioItemAt) .SetMethod("insertRadioItem", &Menu::InsertRadioItemAt)

View file

@ -39,11 +39,7 @@ class Menu : public mate::TrackableObject<Menu>,
Menu(); Menu();
~Menu() override; ~Menu() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable: // mate::Wrappable:
bool IsDestroyed() const override;
void AfterInit(v8::Isolate* isolate) override; void AfterInit(v8::Isolate* isolate) override;
// ui::SimpleMenuModel::Delegate: // ui::SimpleMenuModel::Delegate:

View file

@ -19,7 +19,6 @@ class MenuMac : public Menu {
protected: protected:
MenuMac(); MenuMac();
void Destroy() override;
void Popup(Window* window) override; void Popup(Window* window) override;
void PopupAt(Window* window, int x, int y) override; void PopupAt(Window* window, int x, int y) override;

View file

@ -18,11 +18,6 @@ namespace api {
MenuMac::MenuMac() { MenuMac::MenuMac() {
} }
void MenuMac::Destroy() {
menu_controller_.reset();
Menu::Destroy();
}
void MenuMac::Popup(Window* window) { void MenuMac::Popup(Window* window) {
NativeWindow* native_window = window->window(); NativeWindow* native_window = window->window();
if (!native_window) if (!native_window)

View file

@ -19,9 +19,6 @@ PowerMonitor::PowerMonitor() {
} }
PowerMonitor::~PowerMonitor() { PowerMonitor::~PowerMonitor() {
}
void PowerMonitor::Destroy() {
base::PowerMonitor::Get()->RemoveObserver(this); base::PowerMonitor::Get()->RemoveObserver(this);
} }

View file

@ -23,9 +23,6 @@ class PowerMonitor : public mate::TrackableObject<PowerMonitor>,
PowerMonitor(); PowerMonitor();
~PowerMonitor() override; ~PowerMonitor() override;
// mate::TrackableObject:
void Destroy() override;
// base::PowerObserver implementations: // base::PowerObserver implementations:
void OnPowerStateChange(bool on_battery_power) override; void OnPowerStateChange(bool on_battery_power) override;
void OnSuspend() override; void OnSuspend() override;

View file

@ -45,11 +45,6 @@ PowerSaveBlocker::PowerSaveBlocker()
PowerSaveBlocker::~PowerSaveBlocker() { PowerSaveBlocker::~PowerSaveBlocker() {
} }
void PowerSaveBlocker::Destroy() {
power_save_blocker_types_.clear();
power_save_blocker_.reset();
}
void PowerSaveBlocker::UpdatePowerSaveBlocker() { void PowerSaveBlocker::UpdatePowerSaveBlocker() {
if (power_save_blocker_types_.empty()) { if (power_save_blocker_types_.empty()) {
power_save_blocker_.reset(); power_save_blocker_.reset();

View file

@ -28,9 +28,6 @@ class PowerSaveBlocker : public mate::TrackableObject<PowerSaveBlocker> {
PowerSaveBlocker(); PowerSaveBlocker();
~PowerSaveBlocker() override; ~PowerSaveBlocker() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override; v8::Isolate* isolate) override;

View file

@ -253,7 +253,6 @@ Session::Session(AtomBrowserContext* browser_context)
Session::~Session() { Session::~Session() {
content::BrowserContext::GetDownloadManager(browser_context())-> content::BrowserContext::GetDownloadManager(browser_context())->
RemoveObserver(this); RemoveObserver(this);
Destroy();
} }
void Session::OnDownloadCreated(content::DownloadManager* manager, void Session::OnDownloadCreated(content::DownloadManager* manager,
@ -271,14 +270,6 @@ void Session::OnDownloadCreated(content::DownloadManager* manager,
} }
} }
bool Session::IsDestroyed() const {
return !browser_context_;
}
void Session::Destroy() {
browser_context_ = nullptr;
}
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) { void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
new ResolveProxyHelper(browser_context(), url, callback); new ResolveProxyHelper(browser_context(), url, callback);
} }
@ -376,20 +367,6 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, cookies_); return v8::Local<v8::Value>::New(isolate, cookies_);
} }
mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
.SetProperty("cookies", &Session::Cookies);
}
// static // static
mate::Handle<Session> Session::CreateFrom( mate::Handle<Session> Session::CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context) { v8::Isolate* isolate, AtomBrowserContext* browser_context) {
@ -410,6 +387,22 @@ mate::Handle<Session> Session::FromPartition(
static_cast<AtomBrowserContext*>(browser_context.get())); static_cast<AtomBrowserContext*>(browser_context.get()));
} }
// static
void Session::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
.SetProperty("cookies", &Session::Cookies);
}
void ClearWrapSession() { void ClearWrapSession() {
g_wrap_session.Reset(); g_wrap_session.Reset();
} }

View file

@ -48,6 +48,10 @@ class Session: public mate::TrackableObject<Session>,
AtomBrowserContext* browser_context() const { return browser_context_.get(); } AtomBrowserContext* browser_context() const { return browser_context_.get(); }
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit Session(AtomBrowserContext* browser_context); explicit Session(AtomBrowserContext* browser_context);
~Session(); ~Session();
@ -56,15 +60,7 @@ class Session: public mate::TrackableObject<Session>,
void OnDownloadCreated(content::DownloadManager* manager, void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override; content::DownloadItem* item) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
private: private:
// mate::TrackableObject:
void Destroy() override;
void ResolveProxy(const GURL& url, ResolveProxyCallback callback); void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback); void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args); void ClearStorageData(mate::Arguments* args);

View file

@ -94,14 +94,6 @@ void Tray::OnDragEnded() {
Emit("drag-end"); Emit("drag-end");
} }
bool Tray::IsDestroyed() const {
return !tray_icon_;
}
void Tray::Destroy() {
tray_icon_.reset();
}
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) { void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
tray_icon_->SetImage(image); tray_icon_->SetImage(image);
} }
@ -137,9 +129,11 @@ void Tray::DisplayBalloon(mate::Arguments* args,
} }
void Tray::PopUpContextMenu(mate::Arguments* args) { void Tray::PopUpContextMenu(mate::Arguments* args) {
mate::Handle<Menu> menu;
args->GetNext(&menu);
gfx::Point pos; gfx::Point pos;
args->GetNext(&pos); args->GetNext(&pos);
tray_icon_->PopUpContextMenu(pos); tray_icon_->PopUpContextMenu(pos, menu.IsEmpty() ? nullptr : menu->model());
} }
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) { void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
@ -160,8 +154,7 @@ v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
void Tray::BuildPrototype(v8::Isolate* isolate, void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype) mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Tray::Destroy, true) .MakeDestroyable()
.SetMethod("isDestroyed", &Tray::IsDestroyed, true)
.SetMethod("setImage", &Tray::SetImage) .SetMethod("setImage", &Tray::SetImage)
.SetMethod("setPressedImage", &Tray::SetPressedImage) .SetMethod("setPressedImage", &Tray::SetPressedImage)
.SetMethod("setToolTip", &Tray::SetToolTip) .SetMethod("setToolTip", &Tray::SetToolTip)

View file

@ -54,12 +54,6 @@ class Tray : public mate::TrackableObject<Tray>,
void OnDragExited() override; void OnDragExited() override;
void OnDragEnded() override; void OnDragEnded() override;
// mate::Wrappable:
bool IsDestroyed() const override;
// mate::TrackableObject:
void Destroy() override;
void SetImage(mate::Arguments* args, const gfx::Image& image); void SetImage(mate::Arguments* args, const gfx::Image& image);
void SetPressedImage(mate::Arguments* args, const gfx::Image& image); void SetPressedImage(mate::Arguments* args, const gfx::Image& image);
void SetToolTip(mate::Arguments* args, const std::string& tool_tip); void SetToolTip(mate::Arguments* args, const std::string& tool_tip);

View file

@ -194,8 +194,6 @@ namespace api {
namespace { namespace {
v8::Persistent<v8::ObjectTemplate> template_;
// The wrapWebContents function which is implemented in JavaScript // The wrapWebContents function which is implemented in JavaScript
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>; using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapWebContentsCallback g_wrap_web_contents; WrapWebContentsCallback g_wrap_web_contents;
@ -290,7 +288,15 @@ WebContents::WebContents(v8::Isolate* isolate,
} }
WebContents::~WebContents() { WebContents::~WebContents() {
Destroy(); if (type_ == WEB_VIEW && managed_web_contents()) {
// When force destroying the "destroyed" event is not emitted.
WebContentsDestroyed();
guest_delegate_->Destroy();
Observe(nullptr);
DestroyWebContents();
}
} }
bool WebContents::AddMessageToConsole(content::WebContents* source, bool WebContents::AddMessageToConsole(content::WebContents* source,
@ -591,19 +597,6 @@ void WebContents::NavigationEntryCommitted(
details.is_in_page, details.did_replace_entry); details.is_in_page, details.did_replace_entry);
} }
void WebContents::Destroy() {
session_.Reset();
if (type_ == WEB_VIEW && managed_web_contents()) {
// When force destroying the "destroyed" event is not emitted.
WebContentsDestroyed();
guest_delegate_->Destroy();
Observe(nullptr);
DestroyWebContents();
}
}
int WebContents::GetID() const { int WebContents::GetID() const {
return web_contents()->GetRenderProcessHost()->GetID(); return web_contents()->GetRenderProcessHost()->GetID();
} }
@ -996,83 +989,73 @@ v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_); return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
} }
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( // static
v8::Isolate* isolate) { void WebContents::BuildPrototype(v8::Isolate* isolate,
if (template_.IsEmpty()) v8::Local<v8::ObjectTemplate> prototype) {
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate) mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &WebContents::Destroy, true) .MakeDestroyable()
.SetMethod("isDestroyed", &WebContents::IsDestroyed, true) .SetMethod("getId", &WebContents::GetID)
.SetMethod("getId", &WebContents::GetID) .SetMethod("equal", &WebContents::Equal)
.SetMethod("equal", &WebContents::Equal) .SetMethod("_loadURL", &WebContents::LoadURL)
.SetMethod("_loadURL", &WebContents::LoadURL) .SetMethod("downloadURL", &WebContents::DownloadURL)
.SetMethod("downloadURL", &WebContents::DownloadURL) .SetMethod("_getURL", &WebContents::GetURL)
.SetMethod("_getURL", &WebContents::GetURL) .SetMethod("getTitle", &WebContents::GetTitle)
.SetMethod("getTitle", &WebContents::GetTitle) .SetMethod("isLoading", &WebContents::IsLoading)
.SetMethod("isLoading", &WebContents::IsLoading) .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse) .SetMethod("_stop", &WebContents::Stop)
.SetMethod("_stop", &WebContents::Stop) .SetMethod("_goBack", &WebContents::GoBack)
.SetMethod("_goBack", &WebContents::GoBack) .SetMethod("_goForward", &WebContents::GoForward)
.SetMethod("_goForward", &WebContents::GoForward) .SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("_goToOffset", &WebContents::GoToOffset) .SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("isCrashed", &WebContents::IsCrashed) .SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("setUserAgent", &WebContents::SetUserAgent) .SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent) .SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("insertCSS", &WebContents::InsertCSS) .SetMethod("savePage", &WebContents::SavePage)
.SetMethod("savePage", &WebContents::SavePage) .SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript) .SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("openDevTools", &WebContents::OpenDevTools) .SetMethod("closeDevTools", &WebContents::CloseDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools) .SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened) .SetMethod("enableDeviceEmulation",
.SetMethod("enableDeviceEmulation", &WebContents::EnableDeviceEmulation)
&WebContents::EnableDeviceEmulation) .SetMethod("disableDeviceEmulation",
.SetMethod("disableDeviceEmulation", &WebContents::DisableDeviceEmulation)
&WebContents::DisableDeviceEmulation) .SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools) .SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("inspectElement", &WebContents::InspectElement) .SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted) .SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted) .SetMethod("undo", &WebContents::Undo)
.SetMethod("undo", &WebContents::Undo) .SetMethod("redo", &WebContents::Redo)
.SetMethod("redo", &WebContents::Redo) .SetMethod("cut", &WebContents::Cut)
.SetMethod("cut", &WebContents::Cut) .SetMethod("copy", &WebContents::Copy)
.SetMethod("copy", &WebContents::Copy) .SetMethod("paste", &WebContents::Paste)
.SetMethod("paste", &WebContents::Paste) .SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
.SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle) .SetMethod("delete", &WebContents::Delete)
.SetMethod("delete", &WebContents::Delete) .SetMethod("selectAll", &WebContents::SelectAll)
.SetMethod("selectAll", &WebContents::SelectAll) .SetMethod("unselect", &WebContents::Unselect)
.SetMethod("unselect", &WebContents::Unselect) .SetMethod("replace", &WebContents::Replace)
.SetMethod("replace", &WebContents::Replace) .SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling) .SetMethod("focus", &WebContents::Focus)
.SetMethod("focus", &WebContents::Focus) .SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("tabTraverse", &WebContents::TabTraverse) .SetMethod("_send", &WebContents::SendIPCMessage)
.SetMethod("_send", &WebContents::SendIPCMessage, true) .SetMethod("sendInputEvent", &WebContents::SendInputEvent)
.SetMethod("sendInputEvent", &WebContents::SendInputEvent) .SetMethod("beginFrameSubscription",
.SetMethod("beginFrameSubscription", &WebContents::BeginFrameSubscription)
&WebContents::BeginFrameSubscription) .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription) .SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setSize", &WebContents::SetSize) .SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency) .SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("isGuest", &WebContents::IsGuest) .SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences) .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow) .SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker) .SetMethod("unregisterServiceWorker",
.SetMethod("unregisterServiceWorker", &WebContents::UnregisterServiceWorker)
&WebContents::UnregisterServiceWorker) .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker) .SetMethod("print", &WebContents::Print)
.SetMethod("print", &WebContents::Print) .SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("_printToPDF", &WebContents::PrintToPDF) .SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace) .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace) .SetProperty("session", &WebContents::Session)
.SetProperty("session", &WebContents::Session, true) .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents);
.SetProperty("devToolsWebContents",
&WebContents::DevToolsWebContents, true)
.Build());
return mate::ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
bool WebContents::IsDestroyed() const {
return !web_contents();
} }
AtomBrowserContext* WebContents::GetBrowserContext() const { AtomBrowserContext* WebContents::GetBrowserContext() const {

View file

@ -54,9 +54,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
static mate::Handle<WebContents> Create( static mate::Handle<WebContents> Create(
v8::Isolate* isolate, const mate::Dictionary& options); v8::Isolate* isolate, const mate::Dictionary& options);
// mate::TrackableObject:
void Destroy() override;
int GetID() const; int GetID() const;
bool Equal(const WebContents* web_contents) const; bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options); void LoadURL(const GURL& url, const mate::Dictionary& options);
@ -145,16 +142,15 @@ class WebContents : public mate::TrackableObject<WebContents>,
v8::Local<v8::Value> Session(v8::Isolate* isolate); v8::Local<v8::Value> Session(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate); v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit WebContents(content::WebContents* web_contents); explicit WebContents(content::WebContents* web_contents);
WebContents(v8::Isolate* isolate, const mate::Dictionary& options); WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
~WebContents(); ~WebContents();
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
// content::WebContentsDelegate: // content::WebContentsDelegate:
bool AddMessageToConsole(content::WebContents* source, bool AddMessageToConsole(content::WebContents* source,
int32 level, int32 level,

View file

@ -157,8 +157,8 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
} }
Window::~Window() { Window::~Window() {
if (window_) if (!window_->IsClosed())
Destroy(); window_->CloseContents(nullptr);
} }
void Window::WillCloseWindow(bool* prevent_default) { void Window::WillCloseWindow(bool* prevent_default) {
@ -166,19 +166,19 @@ void Window::WillCloseWindow(bool* prevent_default) {
} }
void Window::OnWindowClosed() { void Window::OnWindowClosed() {
if (api_web_contents_) { api_web_contents_->DestroyWebContents();
api_web_contents_->DestroyWebContents();
api_web_contents_ = nullptr;
web_contents_.Reset();
}
RemoveFromWeakMap(); RemoveFromWeakMap();
window_->RemoveObserver(this); window_->RemoveObserver(this);
// We can not call Destroy here because we need to call Emit first, but we
// also do not want any method to be used, so just mark as destroyed here.
MarkDestroyed();
Emit("closed"); Emit("closed");
// Clean up the resources after window has been closed. // Destroy the native class when window is closed.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release()); base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
} }
void Window::OnWindowBlur() { void Window::OnWindowBlur() {
@ -276,15 +276,6 @@ mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Arguments* args) {
return new Window(isolate, options); return new Window(isolate, options);
} }
bool Window::IsDestroyed() const {
return !window_ || window_->IsClosed();
}
void Window::Destroy() {
if (window_)
window_->CloseContents(nullptr);
}
void Window::Close() { void Window::Close() {
window_->Close(); window_->Close();
} }
@ -622,8 +613,7 @@ v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
void Window::BuildPrototype(v8::Isolate* isolate, void Window::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype) mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Window::Destroy, true) .MakeDestroyable()
.SetMethod("isDestroyed", &Window::IsDestroyed, true)
.SetMethod("close", &Window::Close) .SetMethod("close", &Window::Close)
.SetMethod("focus", &Window::Focus) .SetMethod("focus", &Window::Focus)
.SetMethod("isFocused", &Window::IsFocused) .SetMethod("isFocused", &Window::IsFocused)
@ -695,8 +685,8 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("showDefinitionForSelection", .SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection) &Window::ShowDefinitionForSelection)
#endif #endif
.SetProperty("id", &Window::ID, true) .SetProperty("id", &Window::ID)
.SetProperty("webContents", &Window::WebContents, true); .SetProperty("webContents", &Window::WebContents);
} }
// static // static

View file

@ -77,13 +77,7 @@ class Window : public mate::TrackableObject<Window>,
void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override; void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override;
#endif #endif
// mate::Wrappable:
bool IsDestroyed() const override;
private: private:
// mate::TrackableObject:
void Destroy() override;
// APIs for NativeWindow. // APIs for NativeWindow.
void Close(); void Close();
void Focus(); void Focus();

View file

@ -65,7 +65,6 @@ wrapDownloadItem = (downloadItem) ->
deprecate.property downloadItem, 'url', 'getURL' deprecate.property downloadItem, 'url', 'getURL'
deprecate.property downloadItem, 'filename', 'getFilename' deprecate.property downloadItem, 'filename', 'getFilename'
deprecate.property downloadItem, 'mimeType', 'getMimeType' deprecate.property downloadItem, 'mimeType', 'getMimeType'
deprecate.property downloadItem, 'hasUserGesture', 'hasUserGesture'
deprecate.rename downloadItem, 'getUrl', 'getURL' deprecate.rename downloadItem, 'getUrl', 'getURL'
downloadItemBindings._setWrapDownloadItem wrapDownloadItem downloadItemBindings._setWrapDownloadItem wrapDownloadItem

View file

@ -30,11 +30,11 @@ class IDUserData : public base::SupportsUserData::Data {
TrackableObjectBase::TrackableObjectBase() TrackableObjectBase::TrackableObjectBase()
: weak_map_id_(0), wrapped_(nullptr), weak_factory_(this) { : weak_map_id_(0), wrapped_(nullptr), weak_factory_(this) {
RegisterDestructionCallback( cleanup_ = RegisterDestructionCallback(GetDestroyClosure());
base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr()));
} }
TrackableObjectBase::~TrackableObjectBase() { TrackableObjectBase::~TrackableObjectBase() {
cleanup_.Run();
} }
void TrackableObjectBase::AfterInit(v8::Isolate* isolate) { void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
@ -42,6 +42,18 @@ void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
AttachAsUserData(wrapped_); AttachAsUserData(wrapped_);
} }
void TrackableObjectBase::MarkDestroyed() {
GetWrapper(isolate())->SetAlignedPointerInInternalField(0, nullptr);
}
base::Closure TrackableObjectBase::GetDestroyClosure() {
return base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr());
}
void TrackableObjectBase::Destroy() {
delete this;
}
void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) { void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) {
if (weak_map_id_ != 0) { if (weak_map_id_ != 0) {
wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_)); wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_));
@ -63,9 +75,9 @@ int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
} }
// static // static
void TrackableObjectBase::RegisterDestructionCallback( base::Closure TrackableObjectBase::RegisterDestructionCallback(
const base::Closure& closure) { const base::Closure& c) {
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(closure); return atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(c);
} }
} // namespace mate } // namespace mate

View file

@ -12,6 +12,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "native_mate/object_template_builder.h"
namespace base { namespace base {
class SupportsUserData; class SupportsUserData;
@ -30,26 +31,32 @@ class TrackableObjectBase : public mate::EventEmitter {
// Wrap TrackableObject into a class that SupportsUserData. // Wrap TrackableObject into a class that SupportsUserData.
void AttachAsUserData(base::SupportsUserData* wrapped); void AttachAsUserData(base::SupportsUserData* wrapped);
// Subclasses should implement this to destroy their native types.
virtual void Destroy() = 0;
protected: protected:
~TrackableObjectBase() override; ~TrackableObjectBase() override;
// mate::Wrappable: // mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override; void AfterInit(v8::Isolate* isolate) override;
// Mark the JS object as destroyed.
void MarkDestroyed();
// Returns a closure that can destroy the native class.
base::Closure GetDestroyClosure();
// Get the weak_map_id from SupportsUserData. // Get the weak_map_id from SupportsUserData.
static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped); static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped);
// Register a callback that should be destroyed before JavaScript environment // Register a callback that should be destroyed before JavaScript environment
// gets destroyed. // gets destroyed.
static void RegisterDestructionCallback(const base::Closure& closure); static base::Closure RegisterDestructionCallback(const base::Closure& c);
int32_t weak_map_id_; int32_t weak_map_id_;
base::SupportsUserData* wrapped_; base::SupportsUserData* wrapped_;
private: private:
void Destroy();
base::Closure cleanup_;
base::WeakPtrFactory<TrackableObjectBase> weak_factory_; base::WeakPtrFactory<TrackableObjectBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase); DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase);
@ -91,11 +98,6 @@ class TrackableObject : public TrackableObjectBase {
return std::vector<v8::Local<v8::Object>>(); return std::vector<v8::Local<v8::Object>>();
} }
TrackableObject() {
RegisterDestructionCallback(
base::Bind(&TrackableObject<T>::ReleaseAllWeakReferences));
}
// Removes this instance from the weak map. // Removes this instance from the weak map.
void RemoveFromWeakMap() { void RemoveFromWeakMap() {
if (weak_map_ && weak_map_->Has(weak_map_id())) if (weak_map_ && weak_map_->Has(weak_map_id()))
@ -103,28 +105,49 @@ class TrackableObject : public TrackableObjectBase {
} }
protected: protected:
TrackableObject() {}
~TrackableObject() override { ~TrackableObject() override {
RemoveFromWeakMap(); RemoveFromWeakMap();
} }
void AfterInit(v8::Isolate* isolate) override { void AfterInit(v8::Isolate* isolate) override {
if (!weak_map_) if (!weak_map_) {
weak_map_.reset(new atom::IDWeakMap); weak_map_.reset(new atom::IDWeakMap);
RegisterDestructionCallback(
base::Bind(&TrackableObject<T>::ReleaseAllWeakReferences));
}
weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate)); weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate));
TrackableObjectBase::AfterInit(isolate); TrackableObjectBase::AfterInit(isolate);
} }
private: private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override {
if (template_.IsEmpty()) {
auto templ = v8::ObjectTemplate::New(isolate);
T::BuildPrototype(isolate, templ);
template_.Reset(isolate, templ);
}
return ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
// Releases all weak references in weak map, called when app is terminating. // Releases all weak references in weak map, called when app is terminating.
static void ReleaseAllWeakReferences() { static void ReleaseAllWeakReferences() {
weak_map_.reset(); weak_map_.reset();
} }
static v8::Persistent<v8::ObjectTemplate> template_;
static scoped_ptr<atom::IDWeakMap> weak_map_; static scoped_ptr<atom::IDWeakMap> weak_map_;
DISALLOW_COPY_AND_ASSIGN(TrackableObject); DISALLOW_COPY_AND_ASSIGN(TrackableObject);
}; };
template<typename T>
v8::Persistent<v8::ObjectTemplate> TrackableObject<T>::template_;
template<typename T> template<typename T>
scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_; scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_;

View file

@ -25,6 +25,11 @@
namespace atom { namespace atom {
template<typename T>
void Erase(T* container, typename T::iterator iter) {
container->erase(iter);
}
// static // static
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL; AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
@ -56,9 +61,10 @@ bool AtomBrowserMainParts::SetExitCode(int code) {
return true; return true;
} }
void AtomBrowserMainParts::RegisterDestructionCallback( base::Closure AtomBrowserMainParts::RegisterDestructionCallback(
const base::Closure& callback) { const base::Closure& callback) {
destruction_callbacks_.push_back(callback); auto iter = destructors_.insert(destructors_.end(), callback);
return base::Bind(&Erase<std::list<base::Closure>>, &destructors_, iter);
} }
void AtomBrowserMainParts::PreEarlyInitialization() { void AtomBrowserMainParts::PreEarlyInitialization() {
@ -150,8 +156,13 @@ void AtomBrowserMainParts::PostMainMessageLoopRun() {
// Make sure destruction callbacks are called before message loop is // Make sure destruction callbacks are called before message loop is
// destroyed, otherwise some objects that need to be deleted on IO thread // destroyed, otherwise some objects that need to be deleted on IO thread
// won't be freed. // won't be freed.
for (const auto& callback : destruction_callbacks_) // We don't use ranged for loop because iterators are getting invalided when
// the callback runs.
for (auto iter = destructors_.begin(); iter != destructors_.end();) {
base::Closure& callback = *iter;
++iter;
callback.Run(); callback.Run();
}
// Destroy JavaScript environment immediately after running destruction // Destroy JavaScript environment immediately after running destruction
// callbacks. // callbacks.

View file

@ -36,7 +36,8 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// Register a callback that should be destroyed before JavaScript environment // Register a callback that should be destroyed before JavaScript environment
// gets destroyed. // gets destroyed.
void RegisterDestructionCallback(const base::Closure& callback); // Returns a closure that can be used to remove |callback| from the list.
base::Closure RegisterDestructionCallback(const base::Closure& callback);
Browser* browser() { return browser_.get(); } Browser* browser() { return browser_.get(); }
@ -82,7 +83,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
base::Timer gc_timer_; base::Timer gc_timer_;
// List of callbacks should be executed before destroying JS env. // List of callbacks should be executed before destroying JS env.
std::list<base::Closure> destruction_callbacks_; std::list<base::Closure> destructors_;
static AtomBrowserMainParts* self_; static AtomBrowserMainParts* self_;

View file

@ -39,11 +39,12 @@ createGuest = (embedder, url, frameName, options) ->
# When |embedder| is destroyed we should also destroy attached guest, and if # When |embedder| is destroyed we should also destroy attached guest, and if
# guest is closed by user then we should prevent |embedder| from double # guest is closed by user then we should prevent |embedder| from double
# closing guest. # closing guest.
guestId = guest.id
closedByEmbedder = -> closedByEmbedder = ->
guest.removeListener 'closed', closedByUser guest.removeListener 'closed', closedByUser
guest.destroy() guest.destroy()
closedByUser = -> closedByUser = ->
embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guest.id embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guestId
embedder.removeListener 'render-view-deleted', closedByEmbedder embedder.removeListener 'render-view-deleted', closedByEmbedder
embedder.once 'render-view-deleted', closedByEmbedder embedder.once 'render-view-deleted', closedByEmbedder
guest.once 'closed', closedByUser guest.once 'closed', closedByUser

View file

@ -26,7 +26,8 @@ void TrayIcon::DisplayBalloon(const gfx::Image& icon,
const base::string16& contents) { const base::string16& contents) {
} }
void TrayIcon::PopUpContextMenu(const gfx::Point& pos) { void TrayIcon::PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model) {
} }
void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) { void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) {

View file

@ -47,7 +47,9 @@ class TrayIcon {
const base::string16& title, const base::string16& title,
const base::string16& contents); const base::string16& contents);
virtual void PopUpContextMenu(const gfx::Point& pos); // Popups the menu.
virtual void PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model);
// Set the context menu for this icon. // Set the context menu for this icon.
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0; virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0;

View file

@ -29,7 +29,8 @@ class TrayIconCocoa : public TrayIcon,
void SetToolTip(const std::string& tool_tip) override; void SetToolTip(const std::string& tool_tip) override;
void SetTitle(const std::string& title) override; void SetTitle(const std::string& title) override;
void SetHighlightMode(bool highlight) override; void SetHighlightMode(bool highlight) override;
void PopUpContextMenu(const gfx::Point& pos) override; void PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
protected: protected:

View file

@ -23,6 +23,7 @@ const CGFloat kVerticalTitleMargin = 2;
atom::TrayIconCocoa* trayIcon_; // weak atom::TrayIconCocoa* trayIcon_; // weak
AtomMenuController* menuController_; // weak AtomMenuController* menuController_; // weak
BOOL isHighlightEnable_; BOOL isHighlightEnable_;
BOOL forceHighlight_;
BOOL inMouseEventSequence_; BOOL inMouseEventSequence_;
base::scoped_nsobject<NSImage> image_; base::scoped_nsobject<NSImage> image_;
base::scoped_nsobject<NSImage> alternateImage_; base::scoped_nsobject<NSImage> alternateImage_;
@ -39,6 +40,8 @@ const CGFloat kVerticalTitleMargin = 2;
image_.reset([image copy]); image_.reset([image copy]);
trayIcon_ = icon; trayIcon_ = icon;
isHighlightEnable_ = YES; isHighlightEnable_ = YES;
forceHighlight_ = NO;
inMouseEventSequence_ = NO;
if ((self = [super initWithFrame: CGRectZero])) { if ((self = [super initWithFrame: CGRectZero])) {
// Setup the image view. // Setup the image view.
@ -238,7 +241,19 @@ const CGFloat kVerticalTitleMargin = 2;
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
- (void)popUpContextMenu { - (void)popUpContextMenu:(ui::SimpleMenuModel*)menu_model {
// Show a custom menu.
if (menu_model) {
base::scoped_nsobject<AtomMenuController> menuController(
[[AtomMenuController alloc] initWithModel:menu_model]);
forceHighlight_ = YES; // Should highlight when showing menu.
[self setNeedsDisplay:YES];
[statusItem_ popUpStatusItemMenu:[menuController menu]];
forceHighlight_ = NO;
[self setNeedsDisplay:YES];
return;
}
if (menuController_ && ![menuController_ isMenuOpen]) { if (menuController_ && ![menuController_ isMenuOpen]) {
// Redraw the dray icon to show highlight if it is enabled. // Redraw the dray icon to show highlight if it is enabled.
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
@ -288,6 +303,8 @@ const CGFloat kVerticalTitleMargin = 2;
} }
- (BOOL)shouldHighlight { - (BOOL)shouldHighlight {
if (isHighlightEnable_ && forceHighlight_)
return true;
BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen]; BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen];
return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen); return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen);
} }
@ -338,8 +355,9 @@ void TrayIconCocoa::SetHighlightMode(bool highlight) {
[status_item_view_ setHighlight:highlight]; [status_item_view_ setHighlight:highlight];
} }
void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos) { void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos,
[status_item_view_ popUpContextMenu]; ui::SimpleMenuModel* menu_model) {
[status_item_view_ popUpContextMenu:menu_model];
} }
void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) { void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) {

View file

@ -13,6 +13,7 @@
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/menu/menu_runner.h" #include "ui/views/controls/menu/menu_runner.h"
namespace atom { namespace atom {
@ -45,8 +46,7 @@ NotifyIcon::~NotifyIcon() {
Shell_NotifyIcon(NIM_DELETE, &icon_data); Shell_NotifyIcon(NIM_DELETE, &icon_data);
} }
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos, void NotifyIcon::HandleClickEvent(int modifiers,
int modifiers,
bool left_mouse_click, bool left_mouse_click,
bool double_button_click) { bool double_button_click) {
NOTIFYICONIDENTIFIER icon_id; NOTIFYICONIDENTIFIER icon_id;
@ -66,7 +66,7 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
return; return;
} else if (!double_button_click) { // single right click } else if (!double_button_click) { // single right click
if (menu_model_) if (menu_model_)
PopUpContextMenu(cursor_pos); PopUpContextMenu(gfx::Point(), menu_model_);
else else
NotifyRightClicked(gfx::Rect(rect), modifiers); NotifyRightClicked(gfx::Rect(rect), modifiers);
} }
@ -142,24 +142,26 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
LOG(WARNING) << "Unable to create status tray balloon."; LOG(WARNING) << "Unable to create status tray balloon.";
} }
void NotifyIcon::PopUpContextMenu(const gfx::Point& pos) { void NotifyIcon::PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model) {
// Returns if context menu isn't set. // Returns if context menu isn't set.
if (!menu_model_) if (!menu_model)
return; return;
// Set our window as the foreground window, so the context menu closes when // Set our window as the foreground window, so the context menu closes when
// we click away from it. // we click away from it.
if (!SetForegroundWindow(window_)) if (!SetForegroundWindow(window_))
return; return;
// Show menu at mouse's position by default.
gfx::Rect rect(pos, gfx::Size());
if (pos.IsOrigin())
rect.set_origin(gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
views::MenuRunner menu_runner( views::MenuRunner menu_runner(
menu_model_, menu_model,
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS); views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
ignore_result(menu_runner.RunMenuAt( ignore_result(menu_runner.RunMenuAt(
NULL, NULL, NULL, rect, views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_MOUSE));
NULL,
gfx::Rect(pos, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
} }
void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) { void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {

View file

@ -33,8 +33,7 @@ class NotifyIcon : public TrayIcon {
// Handles a click event from the user - if |left_button_click| is true and // Handles a click event from the user - if |left_button_click| is true and
// there is a registered observer, passes the click event to the observer, // there is a registered observer, passes the click event to the observer,
// otherwise displays the context menu if there is one. // otherwise displays the context menu if there is one.
void HandleClickEvent(const gfx::Point& cursor_pos, void HandleClickEvent(int modifiers,
int modifiers,
bool left_button_click, bool left_button_click,
bool double_button_click); bool double_button_click);
@ -52,7 +51,8 @@ class NotifyIcon : public TrayIcon {
void DisplayBalloon(const gfx::Image& icon, void DisplayBalloon(const gfx::Image& icon,
const base::string16& title, const base::string16& title,
const base::string16& contents) override; const base::string16& contents) override;
void PopUpContextMenu(const gfx::Point& pos) override; void PopUpContextMenu(const gfx::Point& pos,
ui::SimpleMenuModel* menu_model) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private: private:

View file

@ -15,7 +15,6 @@
#include "base/win/win_util.h" #include "base/win/win_util.h"
#include "base/win/wrapped_window_proc.h" #include "base/win/wrapped_window_proc.h"
#include "ui/events/event_constants.h" #include "ui/events/event_constants.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/win/hwnd_util.h"
namespace atom { namespace atom {
@ -172,10 +171,7 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
case WM_CONTEXTMENU: case WM_CONTEXTMENU:
// Walk our icons, find which one was clicked on, and invoke its // Walk our icons, find which one was clicked on, and invoke its
// HandleClickEvent() method. // HandleClickEvent() method.
gfx::Point cursor_pos(
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
win_icon->HandleClickEvent( win_icon->HandleClickEvent(
cursor_pos,
GetKeyboardModifers(), GetKeyboardModifers(),
(lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK), (lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
(lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK)); (lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK));

View file

@ -18,6 +18,8 @@
namespace { namespace {
v8::Persistent<v8::ObjectTemplate> template_;
class Archive : public mate::Wrappable { class Archive : public mate::Wrappable {
public: public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate, static v8::Local<v8::Value> Create(v8::Isolate* isolate,
@ -101,15 +103,20 @@ class Archive : public mate::Wrappable {
// mate::Wrappable: // mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) { mate::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate) if (template_.IsEmpty())
.SetValue("path", archive_->path()) template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.SetMethod("getFileInfo", &Archive::GetFileInfo) .SetValue("path", archive_->path())
.SetMethod("stat", &Archive::Stat) .SetMethod("getFileInfo", &Archive::GetFileInfo)
.SetMethod("readdir", &Archive::Readdir) .SetMethod("stat", &Archive::Stat)
.SetMethod("realpath", &Archive::Realpath) .SetMethod("readdir", &Archive::Readdir)
.SetMethod("copyFileOut", &Archive::CopyFileOut) .SetMethod("realpath", &Archive::Realpath)
.SetMethod("getFd", &Archive::GetFD) .SetMethod("copyFileOut", &Archive::CopyFileOut)
.SetMethod("destroy", &Archive::Destroy); .SetMethod("getFd", &Archive::GetFD)
.SetMethod("destroy", &Archive::Destroy)
.Build());
return mate::ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
} }
private: private:

View file

@ -272,7 +272,8 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
} }
scoped_ptr<ScopedTemporaryFile> temp_file(new ScopedTemporaryFile); scoped_ptr<ScopedTemporaryFile> temp_file(new ScopedTemporaryFile);
if (!temp_file->InitFromFile(&file_, info.offset, info.size)) base::FilePath::StringType ext = path.Extension();
if (!temp_file->InitFromFile(&file_, ext, info.offset, info.size))
return false; return false;
#if defined(OS_POSIX) #if defined(OS_POSIX)

View file

@ -28,20 +28,34 @@ ScopedTemporaryFile::~ScopedTemporaryFile() {
} }
} }
bool ScopedTemporaryFile::Init() { bool ScopedTemporaryFile::Init(const base::FilePath::StringType& ext) {
if (!path_.empty()) if (!path_.empty())
return true; return true;
base::ThreadRestrictions::ScopedAllowIO allow_io; base::ThreadRestrictions::ScopedAllowIO allow_io;
return base::CreateTemporaryFile(&path_); if (!base::CreateTemporaryFile(&path_))
return false;
#if defined(OS_WIN)
// Keep the original extension.
if (!ext.empty()) {
base::FilePath new_path = path_.AddExtension(ext);
if (!base::Move(path_, new_path))
return false;
path_ = new_path;
}
#endif
return true;
} }
bool ScopedTemporaryFile::InitFromFile(base::File* src, bool ScopedTemporaryFile::InitFromFile(base::File* src,
const base::FilePath::StringType& ext,
uint64 offset, uint64 size) { uint64 offset, uint64 size) {
if (!src->IsValid()) if (!src->IsValid())
return false; return false;
if (!Init()) if (!Init(ext))
return false; return false;
std::vector<char> buf(size); std::vector<char> buf(size);

View file

@ -22,11 +22,13 @@ class ScopedTemporaryFile {
ScopedTemporaryFile(); ScopedTemporaryFile();
virtual ~ScopedTemporaryFile(); virtual ~ScopedTemporaryFile();
// Init an empty temporary file. // Init an empty temporary file with a certain extension.
bool Init(); bool Init(const base::FilePath::StringType& ext);
// Init an temporary file and fill it with content of |path|. // Init an temporary file and fill it with content of |path|.
bool InitFromFile(base::File* src, uint64 offset, uint64 size); bool InitFromFile(base::File* src,
const base::FilePath::StringType& ext,
uint64 offset, uint64 size);
base::FilePath path() const { return path_; } base::FilePath path() const { return path_; }

View file

@ -4,7 +4,9 @@
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/browser/atom_browser_main_parts.h" #include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace mate { namespace mate {
@ -56,31 +58,59 @@ v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
} // namespace } // namespace
// Destroy the class on UI thread when possible.
struct DeleteOnUIThread {
template<typename T>
static void Destruct(const T* x) {
if (Locker::IsBrowserProcess() &&
!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, x);
} else {
delete x;
}
}
};
// Like v8::Global, but ref-counted.
template<typename T>
class RefCountedGlobal : public base::RefCountedThreadSafe<RefCountedGlobal<T>,
DeleteOnUIThread> {
public:
RefCountedGlobal(v8::Isolate* isolate, v8::Local<v8::Value> value)
: handle_(isolate, v8::Local<T>::Cast(value)) {
}
bool IsAlive() const {
return !handle_.IsEmpty();
}
v8::Local<T> NewHandle(v8::Isolate* isolate) const {
return v8::Local<T>::New(isolate, handle_);
}
private:
v8::Global<T> handle_;
DISALLOW_COPY_AND_ASSIGN(RefCountedGlobal);
};
SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value) SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value)
: v8_function_(new RefCountedPersistent<v8::Function>(isolate, value)), : v8_function_(new RefCountedGlobal<v8::Function>(isolate, value)) {
weak_factory_(this) {
Init();
} }
SafeV8Function::SafeV8Function(const SafeV8Function& other) SafeV8Function::SafeV8Function(const SafeV8Function& other)
: v8_function_(other.v8_function_), : v8_function_(other.v8_function_) {
weak_factory_(this) {
Init();
} }
v8::Local<v8::Function> SafeV8Function::NewHandle() const { SafeV8Function::~SafeV8Function() {
return v8_function_->NewHandle();
} }
void SafeV8Function::Init() { bool SafeV8Function::IsAlive() const {
if (Locker::IsBrowserProcess() && atom::AtomBrowserMainParts::Get()) return v8_function_.get() && v8_function_->IsAlive();
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(&SafeV8Function::FreeHandle, weak_factory_.GetWeakPtr()));
} }
void SafeV8Function::FreeHandle() { v8::Local<v8::Function> SafeV8Function::NewHandle(v8::Isolate* isolate) const {
Locker locker(v8_function_->isolate()); return v8_function_->NewHandle(isolate);
v8_function_ = nullptr;
} }
v8::Local<v8::Value> CreateFunctionFromTranslater( v8::Local<v8::Value> CreateFunctionFromTranslater(

View file

@ -19,23 +19,21 @@ namespace mate {
namespace internal { namespace internal {
// Manages the V8 function with RAII, and automatically cleans the handle when template<typename T>
// JavaScript context is destroyed, even when the class is not destroyed. class RefCountedGlobal;
// Manages the V8 function with RAII.
class SafeV8Function { class SafeV8Function {
public: public:
SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value); SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
SafeV8Function(const SafeV8Function& other); SafeV8Function(const SafeV8Function& other);
~SafeV8Function();
bool is_alive() const { return v8_function_.get(); } bool IsAlive() const;
v8::Local<v8::Function> NewHandle(v8::Isolate* isolate) const;
v8::Local<v8::Function> NewHandle() const;
private: private:
void Init(); scoped_refptr<RefCountedGlobal<v8::Function>> v8_function_;
void FreeHandle();
scoped_refptr<RefCountedPersistent<v8::Function>> v8_function_;
base::WeakPtrFactory<SafeV8Function> weak_factory_;
}; };
// Helper to invoke a V8 function with C++ parameters. // Helper to invoke a V8 function with C++ parameters.
@ -49,12 +47,12 @@ struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
ArgTypes... raw) { ArgTypes... raw) {
Locker locker(isolate); Locker locker(isolate);
v8::EscapableHandleScope handle_scope(isolate); v8::EscapableHandleScope handle_scope(isolate);
if (!function.is_alive()) if (!function.IsAlive())
return v8::Null(isolate); return v8::Null(isolate);
scoped_ptr<blink::WebScopedRunV8Script> script_scope( scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ? Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate)); nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function.NewHandle(); v8::Local<v8::Function> holder = function.NewHandle(isolate);
v8::Local<v8::Context> context = holder->CreationContext(); v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... }; std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
@ -70,12 +68,12 @@ struct V8FunctionInvoker<void(ArgTypes...)> {
ArgTypes... raw) { ArgTypes... raw) {
Locker locker(isolate); Locker locker(isolate);
v8::HandleScope handle_scope(isolate); v8::HandleScope handle_scope(isolate);
if (!function.is_alive()) if (!function.IsAlive())
return; return;
scoped_ptr<blink::WebScopedRunV8Script> script_scope( scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ? Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate)); nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function.NewHandle(); v8::Local<v8::Function> holder = function.NewHandle(isolate);
v8::Local<v8::Context> context = holder->CreationContext(); v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... }; std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
@ -91,12 +89,12 @@ struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
Locker locker(isolate); Locker locker(isolate);
v8::HandleScope handle_scope(isolate); v8::HandleScope handle_scope(isolate);
ReturnType ret = ReturnType(); ReturnType ret = ReturnType();
if (!function.is_alive()) if (!function.IsAlive())
return ret; return ret;
scoped_ptr<blink::WebScopedRunV8Script> script_scope( scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ? Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate)); nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function.NewHandle(); v8::Local<v8::Function> holder = function.NewHandle(isolate);
v8::Local<v8::Context> context = holder->CreationContext(); v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... }; std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };

View file

@ -30,6 +30,13 @@ process.once('loaded', function() {
}); });
``` ```
## Properties
### `process.noAsar`
이 속성을 `true`로 지정하면 Node 빌트인 모듈의 `asar` 아카이브 지원을 비활성화 시킬
수 있습니다.
## Methods ## Methods
`process` 객체는 다음과 같은 메서드를 가지고 있습니다: `process` 객체는 다음과 같은 메서드를 가지고 있습니다:

View file

@ -184,12 +184,16 @@ __주의:__ `bounds`는 OS X 와 Windows에서만 작동합니다.
트레이에 풍선 팝업을 생성합니다. 트레이에 풍선 팝업을 생성합니다.
### `Tray.popContextMenu([position])` _OS X_ _Windows_ ### `Tray.popUpContextMenu([menu, position])` _OS X_ _Windows_
* `position` Object (optional) - 팝업 메뉴 위치 * `menu` Menu (optional)
* `position` Object (optional) - 팝업 메뉴의 위치
* `x` Integer * `x` Integer
* `y` Integer * `y` Integer
트레이 아이콘의 컨텍스트 메뉴를 팝업시킵니다. `menu`가 전달되면, `menu`가 트레이
메뉴의 컨텍스트 메뉴 대신 표시됩니다.
`position`은 Windows에서만 사용할 수 있으며 기본값은 (0, 0)입니다. `position`은 Windows에서만 사용할 수 있으며 기본값은 (0, 0)입니다.
### `Tray.setContextMenu(menu)` ### `Tray.setContextMenu(menu)`

View file

@ -441,7 +441,7 @@ Returns:
프레임 문서의 로드가 끝나면 발생하는 이벤트입니다. 프레임 문서의 로드가 끝나면 발생하는 이벤트입니다.
### Event: 'page-title-set' ### Event: 'page-title-updated'
Returns: Returns:
@ -449,7 +449,7 @@ Returns:
* `explicitSet` Boolean * `explicitSet` Boolean
탐색하는 동안에 페이지의 제목이 설정되면 발생하는 이벤트입니다. `explicitSet`는 파일 탐색하는 동안에 페이지의 제목이 설정되면 발생하는 이벤트입니다. `explicitSet`는 파일
URL에서 합(synthesised)된 제목인 경우 false로 표시됩니다. URL에서 합(synthesised)된 제목인 경우 false로 표시됩니다.
### Event: 'page-favicon-updated' ### Event: 'page-favicon-updated'

View file

@ -103,6 +103,14 @@ var originalFs = require('original-fs');
originalFs.readFileSync('/path/to/example.asar'); originalFs.readFileSync('/path/to/example.asar');
``` ```
또한 `process.noAsar``true`로 지정하면 `fs` 모듈의 `asar` 지원을 비활성화 시킬 수
있습니다.
```javascript
process.noAsar = true;
fs.readFileSync('/path/to/example.asar');
```
## Node API의 한계 ## Node API의 한계
`asar` 아카이브를 Node API가 최대한 디렉터리 구조로 작동하도록 노력해왔지만 여전히 `asar` 아카이브를 Node API가 최대한 디렉터리 구조로 작동하도록 노력해왔지만 여전히

View file

@ -19,9 +19,9 @@
## node-inspector로 디버깅 하기 ## node-inspector로 디버깅 하기
__참고:__ Electron은 node v0.11.13 버전을 사용합니다. 그리고 현재 node-inspector __참고:__ Electron은 현재 node-inspector 유틸리티와 호환성 문제가 있습니다. 따라서
유틸리티와 호환성 문제가 있습니다. 추가로 node-inspector 콘솔 내에서 메인 프로세스의 node-inspector 콘솔 내에서 메인 프로세스의 `process` 객체를 탐색할 경우 크래시가
`process` 객체를 탐색할 경우 크래시가 발생할 수 있습니다. 발생할 수 있습니다.
### 1. [node-inspector][node-inspector] 서버 시작 ### 1. [node-inspector][node-inspector] 서버 시작

View file

@ -4,6 +4,10 @@ Electron은 v0.34.0 버전부터 앱 패키지를 Mac App Store(MAS)에 제출
되었습니다. 이 가이드는 어플리케이션을 앱 스토어에 등록하는 방법과 빌드의 한계에 대한 되었습니다. 이 가이드는 어플리케이션을 앱 스토어에 등록하는 방법과 빌드의 한계에 대한
설명을 제공합니다. 설명을 제공합니다.
__참고:__ Mac App Store에 어플리케이션을 등록하려면
[Apple Developer Program][developer-program]에 등록되어 있어야 하며 비용이 발생할
수 있습니다.
## 앱 스토어에 어플리케이션을 등록하는 방법 ## 앱 스토어에 어플리케이션을 등록하는 방법
다음 몇 가지 간단한 절차에 따라 앱 스토어에 어플리케이션을 등록하는 방법을 알아봅니다. 다음 몇 가지 간단한 절차에 따라 앱 스토어에 어플리케이션을 등록하는 방법을 알아봅니다.
@ -109,6 +113,7 @@ productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RES
**역주:** [Mac 앱 배포 가이드 공식 문서](https://developer.apple.com/osx/distribution/kr/) **역주:** [Mac 앱 배포 가이드 공식 문서](https://developer.apple.com/osx/distribution/kr/)
[developer-program]: https://developer.apple.com/support/compare-memberships/
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html [submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps [nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps
[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html [enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html

View file

@ -40,8 +40,8 @@ selecione a *tag* que corresponde à sua versão.
### Módulos para o Processo Principal: ### Módulos para o Processo Principal:
* [app](../../docs/api/app.md) * [app](api/app.md)
* [autoUpdater](../../docs/api/auto-updater.md) * [autoUpdater](api/auto-updater.md)
* [BrowserWindow](../../docs/api/browser-window.md) * [BrowserWindow](../../docs/api/browser-window.md)
* [contentTracing](../../docs/api/content-tracing.md) * [contentTracing](../../docs/api/content-tracing.md)
* [dialog](../../docs/api/dialog.md) * [dialog](../../docs/api/dialog.md)

View file

@ -1,7 +1,7 @@
# Acelerador (teclas de atalhos) # Acelerador (teclas de atalhos)
Um acelerador é uma string que representa um atalho de tecla. Isso pode conter Um acelerador é uma string que representa um atalho de tecla. Ele pode conter
multiplos modificadores e códigos chaves, combinado pelo caracter `+`. múltiplos modificadores e códigos chaves, combinados pelo caractere `+`.
Exemplos: Exemplos:
@ -11,13 +11,13 @@ Exemplos:
## Aviso sobre plataformas ## Aviso sobre plataformas
No Linux e no Windows a tecla `Command` não tem nenhum efeito, No Linux e no Windows a tecla `Command` não tem nenhum efeito,
então use `CommandOrControl` que representa a tecla `Command` existente no OSX e então use `CommandOrControl` que representa a tecla `Command` existente no OS X e
`Control` no Linux e no Windows para definir aceleradores (atalhos). `Control` no Linux e no Windows para definir aceleradores (atalhos).
A chave `Super` está mapeada para a tecla `Windows` para Windows e Linux, A chave `Super` está mapeada para a tecla `Windows` para Windows e Linux,
e para a tecla `Cmd` para OSX. e para a tecla `Cmd` para OS X.
## Modificadores disponiveis ## Modificadores disponíveis
* `Command` (ou `Cmd` abreviado) * `Command` (ou `Cmd` abreviado)
* `Control` (ou `Ctrl` abreviado) * `Control` (ou `Ctrl` abreviado)
@ -26,21 +26,21 @@ e para a tecla `Cmd` para OSX.
* `Shift` * `Shift`
* `Super` * `Super`
## Códigos chaves disponiveis ## Códigos chaves disponíveis
* `0` to `9` * `0` até `9`
* `A` to `Z` * `A` até `Z`
* `F1` to `F24` * `F1` até `F24`
* Punctuations like `~`, `!`, `@`, `#`, `$`, etc. * Pontuações como `~`, `!`, `@`, `#`, `$`, etc.
* `Plus` * `Plus`
* `Space` * `Space`
* `Backspace` * `Backspace`
* `Delete` * `Delete`
* `Insert` * `Insert`
* `Return` (or `Enter` as alias) * `Return` (ou `Enter` como pseudônimo)
* `Up`, `Down`, `Left` and `Right` * `Up`, `Down`, `Left` e `Right`
* `Home` and `End` * `Home` e `End`
* `PageUp` and `PageDown` * `PageUp` e `PageDown`
* `Escape` (or `Esc` for short) * `Escape` (ou `Esc` abreviado)
* `VolumeUp`, `VolumeDown` and `VolumeMute` * `VolumeUp`, `VolumeDown` e `VolumeMute`
* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` and `MediaPlayPause` * `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` e `MediaPlayPause`

View file

@ -0,0 +1,85 @@
# autoUpdater
Este módulo oferece uma interface para o framework de atualização automática `Squirrel`.
## Avisos sobre Plataformas
Embora o `autoUpdater` ofereça uma API uniforme para diferentes plataformas, existem diferenças sutis em cada plataforma.
### OS X
No OS X, o módulo `autoUpdater` é construído sobre o [Squirrel.Mac][squirrel-mac], o que significa que você não precisa de nenhuma configuração especial para fazê-lo funcionar. Para requerimentos de servidor, você pode ler [Server Support][server-support].
### Windows
No Windows, você deve instalar seu aplicativo na máquina de um usuário antes que possa usar o auto-updater, então é recomendado utilizar o módulo [grunt-electron-installer][installer] para gerar um instalador do Windows.
O instalador gerado com Squirrel irá criar um ícone de atalho com um [Application User Model ID][app-user-model-id] no formato `com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`, por exemplo: `com.squirrel.slack.Slack` e `com.squirrel.code.Code`. Você precisa usar o mesmo ID para seu aplicativo a API `app.setAppUserModelId`, senão o Windows não conseguirá fixar seu aplicativo corretamente na barra de tarefas.
A configuração do servidor também é diferente do OS X. Você pode ler a documentação do [Squirrel.Windows][squirrel-windows] para mais detalhes.
### Linux
Não há suporte nativo do auto-updater para Linux, então é recomendado utilizar o gerenciador de pacotes da distribuição para atualizar seu aplicativo.
## Eventos
O objeto `autoUpdater` emite os seguintes eventos:
### Evento: 'error'
Retorna:
* `error` Error
Emitido quando há um erro durante a atualização.
### Evento: 'checking-for-update'
Emitido quando está verificando se uma atualização foi inicializada.
### Evento: 'update-available'
Emitido quando há uma atualização disponível. A autalização é baixada automaticamente.
### Evento: 'update-not-available'
Emitido quando não há uma atualização disponível.
### Evento: 'update-downloaded'
Retorna:
* `event` Event
* `releaseNotes` String
* `releaseName` String
* `releaseDate` Date
* `updateURL` String
Emitido quando uma atualização foi baixada.
No Windows apenas `releaseName` está disponível.
## Métodos
O objeto `autoUpdater` possui os seguintes métodos:
### `autoUpdater.setFeedURL(url)`
* `url` String
Define a `url` e inicializa o auto-updater. A `url` não pode ser alterada uma vez que foi definida.
### `autoUpdater.checkForUpdates()`
Pergunta ao servidor se há uma atualização. Você deve chamar `setFeedURL` antes de usar esta API.
### `autoUpdater.quitAndInstall()`
Reinicia o aplicativo e instala a atualização após esta ter sido baixada. Só deve ser chamado após o `update-downloaded` ter sido emitido.
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
[installer]: https://github.com/atom/grunt-electron-installer
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx

View file

@ -1,20 +1,46 @@
# process # process
O objeto `process` no Electron tem as seguintes diferenças de um upstream node: O objeto `process` no Electron tem as seguintes diferenças do objeto no upstream node:
* `process.type` String - Tipo de processo, pode ser `browser` (i.e. main process) * `process.type` String - Tipo de processo, pode ser `browser` (processo principal)
ou `renderer`. ou `renderer`.
* `process.versions['electron']` String - Versão do Electron. * `process.versions['electron']` String - Versão do Electron.
* `process.versions['chrome']` String - Versão do Chromium. * `process.versions['chrome']` String - Versão do Chromium.
* `process.resourcesPath` String - Caminho para os códigos fontes JavaScript. * `process.resourcesPath` String - Caminho para o código fonte JavaScript.
* `process.mas` Boolean - Para build da Mac App Store, este valor é `true`, para outros builds é `undefined`.
## Eventos
### Evento: 'loaded'
Emitido quando o Electron carregou seu script de inicialização interno e está começando a carregar a página web ou o script principal.
Pode ser utilizado pelo script pré-carregamento (preload.js abaixo) para adicionar símbolos globais do Node removidos para o escopo global quando a integração do node é desligada:
```js
// preload.js
var _setImmediate = setImmediate;
var _clearImmediate = clearImmediate;
process.once('loaded', function() {
global.setImmediate = _setImmediate;
global.clearImmediate = _clearImmediate;
});
```
## Propriedades
### `process.noAsar`
Definir isto para `true` pode desabilitar o suporte para arquivos `asar` nos módulos nativos do Node.
# Métodos # Métodos
O objeto `process` tem os seguintes método:
O objeto `process` tem os seguintes métodos:
### `process.hang` ### `process.hang`
Afeta a thread principal do processo atual. Faz com que o *thread* principal do processo congele.
## process.setFdLimit(MaxDescritores) _OS X_ _Linux_ ### `process.setFdLimit(maxDescriptors)` _OS X_ _Linux_
* `maxDescriptors` Integer * `maxDescriptors` Integer

View file

@ -1,11 +1,11 @@
# shell # shell
O módulo `shell` fornece funções relacionadas intereções com o OS do usuário. O módulo `shell` fornece funções relacionadas à integração com o desktop.
Um exemplo para abrir uma URL no browser padrão do usuário: Um exemplo para abrir uma URL no browser padrão do usuário:
```javascript ```javascript
var shell = require('shell'); const shell = require('shell');
shell.openExternal('https://github.com'); shell.openExternal('https://github.com');
``` ```
@ -17,26 +17,26 @@ O módulo `shell` tem os seguintes métodos:
* `fullPath` String * `fullPath` String
Exibe o arquivo no gerenciador de arquivos padrão do sistema. Se possivel, seleciona o arquivo automaticamente. Exibe o arquivo num gerenciador de arquivos. Se possivel, seleciona o arquivo.
### `shell.openItem(fullPath)` ### `shell.openItem(fullPath)`
* `fullPath` String * `fullPath` String
Abre o arquivo em seu programa padrão. Abre o arquivo de maneira padrão do desktop.
### `shell.openExternal(url)` ### `shell.openExternal(url)`
* `url` String * `url` String
Abre o arquivo seguido de um protocol em seu programa padrão. (Por Abre a URL de protocolo externo de maneira padrão do desktop. (Por
exemplo, mailto:foo@bar.com.) exemplo, mailto: URLs no programa de email padrão do usuário)
### `shell.moveItemToTrash(fullPath)` ### `shell.moveItemToTrash(fullPath)`
* `fullPath` String * `fullPath` String
Move o arquivo para a lixeira e retorna um boolean com o resultado da operação. Move o arquivo para a lixeira e retorna um status boolean com o resultado da operação.
### `shell.beep()` ### `shell.beep()`

View file

@ -187,12 +187,16 @@ when the tray icon is clicked. Defaults to true.
Displays a tray balloon. Displays a tray balloon.
### `Tray.popUpContextMenu([position])` _OS X_ _Windows_ ### `Tray.popUpContextMenu([menu, position])` _OS X_ _Windows_
* `position` Object (optional)- The pop up position. * `menu` Menu (optional)
* `position` Object (optional) - The pop up position.
* `x` Integer * `x` Integer
* `y` Integer * `y` Integer
Popups the context menu of tray icon. When `menu` is passed, the `menu` will
showed instead of the tray's context menu.
The `position` is only available on Windows, and it is (0, 0) by default. The `position` is only available on Windows, and it is (0, 0) by default.
### `Tray.setContextMenu(menu)` ### `Tray.setContextMenu(menu)`

View file

@ -19,7 +19,7 @@ Like `--debug` but pauses the script on the first line.
## Use node-inspector for Debugging ## Use node-inspector for Debugging
__Note:__ Electron uses node v0.11.13, which currently doesn't work very well __Note:__ Electron doesn't currently work very well
with node-inspector, and the main process will crash if you inspect the with node-inspector, and the main process will crash if you inspect the
`process` object under node-inspector's console. `process` object under node-inspector's console.

View file

@ -424,6 +424,8 @@ describe 'asar package', ->
assert.equal internalModuleReadFile(p).toString().trim(), 'a' assert.equal internalModuleReadFile(p).toString().trim(), 'a'
describe 'process.noAsar', -> describe 'process.noAsar', ->
errorName = if process.platform is 'win32' then 'ENOENT' else 'ENOTDIR'
beforeEach -> beforeEach ->
process.noAsar = true process.noAsar = true
afterEach -> afterEach ->
@ -432,22 +434,22 @@ describe 'asar package', ->
it 'disables asar support in sync API', -> it 'disables asar support in sync API', ->
file = path.join fixtures, 'asar', 'a.asar', 'file1' file = path.join fixtures, 'asar', 'a.asar', 'file1'
dir = path.join fixtures, 'asar', 'a.asar', 'dir1' dir = path.join fixtures, 'asar', 'a.asar', 'dir1'
assert.throws (-> fs.readFileSync file), /ENOTDIR/ assert.throws (-> fs.readFileSync file), new RegExp(errorName)
assert.throws (-> fs.lstatSync file), /ENOTDIR/ assert.throws (-> fs.lstatSync file), new RegExp(errorName)
assert.throws (-> fs.realpathSync file), /ENOTDIR/ assert.throws (-> fs.realpathSync file), new RegExp(errorName)
assert.throws (-> fs.readdirSync dir), /ENOTDIR/ assert.throws (-> fs.readdirSync dir), new RegExp(errorName)
it 'disables asar support in async API', (done) -> it 'disables asar support in async API', (done) ->
file = path.join fixtures, 'asar', 'a.asar', 'file1' file = path.join fixtures, 'asar', 'a.asar', 'file1'
dir = path.join fixtures, 'asar', 'a.asar', 'dir1' dir = path.join fixtures, 'asar', 'a.asar', 'dir1'
fs.readFile file, (error) -> fs.readFile file, (error) ->
assert.equal error.code, 'ENOTDIR' assert.equal error.code, errorName
fs.lstat file, (error) -> fs.lstat file, (error) ->
assert.equal error.code, 'ENOTDIR' assert.equal error.code, errorName
fs.realpath file, (error) -> fs.realpath file, (error) ->
assert.equal error.code, 'ENOTDIR' assert.equal error.code, errorName
fs.readdir dir, (error) -> fs.readdir dir, (error) ->
assert.equal error.code, 'ENOTDIR' assert.equal error.code, errorName
done() done()
it 'treats *.asar as normal file', -> it 'treats *.asar as normal file', ->