Merge branch 'master' into desktop-capture-api

This commit is contained in:
Cheng Zhao 2015-12-08 12:43:44 +08:00
commit 04f7ceab73
464 changed files with 18563 additions and 4629 deletions

View file

@ -7,26 +7,29 @@
#include <string>
#include <vector>
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/login_handler.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "brightray/browser/brightray_paths.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_switches.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h"
@ -61,21 +64,6 @@ struct Converter<Browser::UserTask> {
};
#endif
template<>
struct Converter<scoped_refptr<net::X509Certificate>> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const scoped_refptr<net::X509Certificate>& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
std::string encoded_data;
net::X509Certificate::GetPEMEncoded(
val->os_cert_handle(), &encoded_data);
dict.Set("data", encoded_data);
dict.Set("issuerName", val->issuer().GetDisplayName());
return dict.GetHandle();
}
};
} // namespace mate
@ -99,22 +87,47 @@ int GetPathConstant(const std::string& name) {
return base::DIR_HOME;
else if (name == "temp")
return base::DIR_TEMP;
else if (name == "userDesktop")
else if (name == "userDesktop" || name == "desktop")
return base::DIR_USER_DESKTOP;
else if (name == "exe")
return base::FILE_EXE;
else if (name == "module")
return base::FILE_MODULE;
else if (name == "documents")
return chrome::DIR_USER_DOCUMENTS;
else if (name == "downloads")
return chrome::DIR_DEFAULT_DOWNLOADS;
else if (name == "music")
return chrome::DIR_USER_MUSIC;
else if (name == "pictures")
return chrome::DIR_USER_PICTURES;
else if (name == "videos")
return chrome::DIR_USER_VIDEOS;
else
return -1;
}
bool NotificationCallbackWrapper(
const ProcessSingleton::NotificationCallback& callback,
const base::CommandLine::StringVector& cmd,
const base::FilePath& cwd) {
// Make sure the callback is called after app gets ready.
if (Browser::Get()->is_ready()) {
callback.Run(cmd, cwd);
} else {
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
task_runner->PostTask(
FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
}
// ProcessSingleton needs to know whether current process is quiting.
return !Browser::Get()->is_shutting_down();
}
void OnClientCertificateSelected(
v8::Isolate* isolate,
std::shared_ptr<content::ClientCertificateDelegate> delegate,
mate::Arguments* args) {
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
mate::Dictionary cert_data;
if (!(args->Length() == 1 && args->GetNext(&cert_data))) {
args->ThrowError();
@ -128,18 +141,29 @@ void OnClientCertificateSelected(
net::X509Certificate::CreateCertificateListFromBytes(
encoded_data.data(), encoded_data.size(),
net::X509Certificate::FORMAT_AUTO);
delegate->ContinueWithCertificate(certs[0].get());
}
void PassLoginInformation(scoped_refptr<LoginHandler> login_handler,
mate::Arguments* args) {
base::string16 username, password;
if (args->GetNext(&username) && args->GetNext(&password))
login_handler->Login(username, password);
else
login_handler->CancelAuth();
}
} // namespace
App::App() {
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this);
Browser::Get()->AddObserver(this);
content::GpuDataManager::GetInstance()->AddObserver(this);
}
App::~App() {
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(
nullptr);
Browser::Get()->RemoveObserver(this);
content::GpuDataManager::GetInstance()->RemoveObserver(this);
}
@ -158,6 +182,11 @@ void App::OnWindowAllClosed() {
void App::OnQuit() {
Emit("quit");
if (process_singleton_.get()) {
process_singleton_->Cleanup();
process_singleton_.reset();
}
}
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
@ -177,26 +206,62 @@ void App::OnWillFinishLaunching() {
}
void App::OnFinishLaunching() {
// Create the defaultSession.
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto browser_context = static_cast<AtomBrowserContext*>(
AtomBrowserMainParts::Get()->browser_context());
auto handle = Session::CreateFrom(isolate(), browser_context);
default_session_.Reset(isolate(), handle.ToV8());
Emit("ready");
}
void App::OnSelectCertificate(
void App::OnLogin(LoginHandler* login_handler) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
bool prevent_default = Emit(
"login",
WebContents::CreateFrom(isolate(), login_handler->GetWebContents()),
login_handler->request(),
login_handler->auth_info(),
base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler)));
// Default behavior is to always cancel the auth.
if (!prevent_default)
login_handler->CancelAuth();
}
void App::AllowCertificateError(
int pid,
int fid,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
content::ResourceType resource_type,
bool overridable,
bool strict_enforcement,
bool expired_previous_decision,
const base::Callback<void(bool)>& callback,
content::CertificateRequestResultType* request) {
auto rfh = content::RenderFrameHost::FromID(pid, fid);
auto web_contents = content::WebContents::FromRenderFrameHost(rfh);
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
bool prevent_default = Emit("certificate-error",
WebContents::CreateFrom(isolate(), web_contents),
request_url,
net::ErrorToString(cert_error),
ssl_info.cert,
callback);
// Deny the certificate by default.
if (!prevent_default)
*request = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
}
void App::SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {
std::shared_ptr<content::ClientCertificateDelegate>
shared_delegate(delegate.release());
bool prevent_default =
Emit("select-certificate",
api::WebContents::CreateFrom(isolate(), web_contents),
Emit("select-client-certificate",
WebContents::CreateFrom(isolate(), web_contents),
cert_request_info->host_and_port.ToString(),
cert_request_info->client_certs,
base::Bind(&OnClientCertificateSelected,
@ -242,22 +307,36 @@ void App::SetDesktopName(const std::string& desktop_name) {
#endif
}
void App::SetAppUserModelId(const std::string& app_id) {
#if defined(OS_WIN)
base::string16 app_id_utf16 = base::UTF8ToUTF16(app_id);
SetCurrentProcessExplicitAppUserModelID(app_id_utf16.c_str());
#endif
void App::AllowNTLMCredentialsForAllDomains(bool should_allow) {
auto browser_context = static_cast<AtomBrowserContext*>(
AtomBrowserMainParts::Get()->browser_context());
browser_context->AllowNTLMCredentialsForAllDomains(should_allow);
}
std::string App::GetLocale() {
return l10n_util::GetApplicationLocale("");
}
v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
if (default_session_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, default_session_);
bool App::MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback) {
if (process_singleton_.get())
return false;
base::FilePath user_dir;
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
process_singleton_.reset(new ProcessSingleton(
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
case ProcessSingleton::NotifyResult::LOCK_ERROR:
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
process_singleton_.reset();
return true;
case ProcessSingleton::NotifyResult::PROCESS_NONE:
default: // Shouldn't be needed, but VS warns if it is not there.
return false;
}
}
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
@ -265,6 +344,7 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
auto browser = base::Unretained(Browser::Get());
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("quit", base::Bind(&Browser::Quit, browser))
.SetMethod("exit", base::Bind(&Browser::Exit, browser))
.SetMethod("focus", base::Bind(&Browser::Focus, browser))
.SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser))
.SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser))
@ -275,6 +355,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
base::Bind(&Browser::AddRecentDocument, browser))
.SetMethod("clearRecentDocuments",
base::Bind(&Browser::ClearRecentDocuments, browser))
.SetMethod("setAppUserModelId",
base::Bind(&Browser::SetAppUserModelID, browser))
#if defined(OS_WIN)
.SetMethod("setUserTasks",
base::Bind(&Browser::SetUserTasks, browser))
@ -282,9 +364,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
.SetMethod("setPath", &App::SetPath)
.SetMethod("getPath", &App::GetPath)
.SetMethod("setDesktopName", &App::SetDesktopName)
.SetMethod("setAppUserModelId", &App::SetAppUserModelId)
.SetMethod("allowNTLMCredentialsForAllDomains",
&App::AllowNTLMCredentialsForAllDomains)
.SetMethod("getLocale", &App::GetLocale)
.SetProperty("defaultSession", &App::DefaultSession);
.SetMethod("makeSingleInstance", &App::MakeSingleInstance);
}
// static
@ -301,6 +384,16 @@ namespace {
void AppendSwitch(const std::string& switch_string, mate::Arguments* args) {
auto command_line = base::CommandLine::ForCurrentProcess();
if (switch_string == atom::switches::kPpapiFlashPath ||
switch_string == atom::switches::kClientCertificate ||
switch_string == switches::kLogNetLog) {
base::FilePath path;
args->GetNext(&path);
command_line->AppendSwitchPath(switch_string, path);
return;
}
std::string value;
if (args->GetNext(&value))
command_line->AppendSwitchASCII(switch_string, value);

View file

@ -8,7 +8,10 @@
#include <string>
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/browser_observer.h"
#include "atom/common/native_mate_converters/callback.h"
#include "chrome/browser/process_singleton.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/handle.h"
@ -24,7 +27,8 @@ namespace atom {
namespace api {
class App : public mate::EventEmitter,
class App : public AtomBrowserClient::Delegate,
public mate::EventEmitter,
public BrowserObserver,
public content::GpuDataManagerObserver {
public:
@ -44,7 +48,22 @@ class App : public mate::EventEmitter,
void OnActivate(bool has_visible_windows) override;
void OnWillFinishLaunching() override;
void OnFinishLaunching() override;
void OnSelectCertificate(
void OnLogin(LoginHandler* login_handler) override;
// content::ContentBrowserClient:
void AllowCertificateError(
int render_process_id,
int render_frame_id,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
content::ResourceType resource_type,
bool overridable,
bool strict_enforcement,
bool expired_previous_decision,
const base::Callback<void(bool)>& callback,
content::CertificateRequestResultType* request) override;
void SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
@ -64,11 +83,12 @@ class App : public mate::EventEmitter,
const base::FilePath& path);
void SetDesktopName(const std::string& desktop_name);
void SetAppUserModelId(const std::string& app_id);
void AllowNTLMCredentialsForAllDomains(bool should_allow);
bool MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback);
std::string GetLocale();
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
v8::Global<v8::Value> default_session_;
scoped_ptr<ProcessSingleton> process_singleton_;
DISALLOW_COPY_AND_ASSIGN(App);
};

View file

@ -5,12 +5,31 @@
#include "atom/browser/api/atom_api_auto_updater.h"
#include "base/time/time.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/node_includes.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
namespace mate {
template<>
struct Converter<base::Time> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const base::Time& val) {
v8::MaybeLocal<v8::Value> date = v8::Date::New(
isolate->GetCurrentContext(), val.ToJsTime());
if (date.IsEmpty())
return v8::Null(isolate);
else
return date.ToLocalChecked();
}
};
} // namespace mate
namespace atom {
namespace api {
@ -20,11 +39,18 @@ AutoUpdater::AutoUpdater() {
}
AutoUpdater::~AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(NULL);
auto_updater::AutoUpdater::SetDelegate(nullptr);
}
void AutoUpdater::OnError(const std::string& error) {
Emit("error", error);
void AutoUpdater::OnError(const std::string& message) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
EmitCustomEvent(
"error",
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
// Message is also emitted to keep compatibility with old code.
message);
}
void AutoUpdater::OnCheckingForUpdate() {
@ -42,26 +68,36 @@ void AutoUpdater::OnUpdateNotAvailable() {
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) {
quit_and_install_ = quit_and_install;
Emit("update-downloaded-raw", release_notes, release_name,
release_date.ToJsTime(), update_url);
const std::string& url) {
Emit("update-downloaded", release_notes, release_name, release_date, url,
// Keep compatibility with old APIs.
base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
}
void AutoUpdater::OnWindowAllClosed() {
QuitAndInstall();
}
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL)
.SetMethod("setFeedURL", &auto_updater::AutoUpdater::SetFeedURL)
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall);
.SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
}
void AutoUpdater::QuitAndInstall() {
if (quit_and_install_.is_null())
Browser::Get()->Shutdown();
else
quit_and_install_.Run();
// If we don't have any window then quitAndInstall immediately.
WindowList* window_list = WindowList::GetInstance();
if (window_list->size() == 0) {
auto_updater::AutoUpdater::QuitAndInstall();
return;
}
// Otherwise do the restart after all windows have been closed.
window_list->AddObserver(this);
for (NativeWindow* window : *window_list)
window->Close();
}
// static

View file

@ -7,9 +7,9 @@
#include <string>
#include "base/callback.h"
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/auto_updater_delegate.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/window_list_observer.h"
#include "native_mate/handle.h"
namespace atom {
@ -17,7 +17,8 @@ namespace atom {
namespace api {
class AutoUpdater : public mate::EventEmitter,
public auto_updater::AutoUpdaterDelegate {
public auto_updater::Delegate,
public WindowListObserver {
public:
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
@ -25,17 +26,18 @@ class AutoUpdater : public mate::EventEmitter,
AutoUpdater();
virtual ~AutoUpdater();
// AutoUpdaterDelegate implementations.
// Delegate implementations.
void OnError(const std::string& error) override;
void OnCheckingForUpdate() override;
void OnUpdateAvailable() override;
void OnUpdateNotAvailable() override;
void OnUpdateDownloaded(
const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) override;
void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url) override;
// WindowListObserver:
void OnWindowAllClosed() override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -44,8 +46,6 @@ class AutoUpdater : public mate::EventEmitter,
private:
void QuitAndInstall();
base::Closure quit_and_install_;
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
};

View file

@ -204,7 +204,7 @@ void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
Passed(&filter), callback))) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&RunGetCookiesCallbackOnUIThread, isolate(),
"Url is not valid", net::CookieList(), callback));
"URL is not valid", net::CookieList(), callback));
}
}
@ -229,7 +229,7 @@ void Cookies::Remove(const mate::Dictionary& details,
error_message = "Details(url, name) of removing cookie are required.";
}
if (error_message.empty() && !url.is_valid()) {
error_message = "Url is not valid.";
error_message = "URL is not valid.";
}
if (!error_message.empty()) {
RunRemoveCookiesCallbackOnUIThread(isolate(), error_message, callback);
@ -261,7 +261,7 @@ void Cookies::Set(const base::DictionaryValue& options,
GURL gurl(url);
if (error_message.empty() && !gurl.is_valid()) {
error_message = "Url is not valid.";
error_message = "URL is not valid.";
}
if (!error_message.empty()) {
@ -322,14 +322,6 @@ void Cookies::OnSetCookies(const CookiesCallback& 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() {
return request_context_getter_->GetURLRequestContext()->cookie_store();
}
@ -341,6 +333,15 @@ mate::Handle<Cookies> Cookies::Create(
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 atom

View file

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

View file

@ -6,6 +6,7 @@
#include <map>
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
@ -30,7 +31,7 @@ struct Converter<content::DownloadItem::DownloadState> {
download_state = "cancelled";
break;
case content::DownloadItem::INTERRUPTED:
download_state = "interrputed";
download_state = "interrupted";
break;
default:
break;
@ -69,29 +70,20 @@ DownloadItem::DownloadItem(content::DownloadItem* download_item) :
}
DownloadItem::~DownloadItem() {
Destroy();
}
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;
if (download_item_)
OnDownloadDestroyed(download_item_);
}
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
}
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) {
Destroy();
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* 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;
}
int64 DownloadItem::GetReceivedBytes() {
@ -102,7 +94,7 @@ int64 DownloadItem::GetTotalBytes() {
return download_item_->GetTotalBytes();
}
const GURL& DownloadItem::GetUrl() {
const GURL& DownloadItem::GetURL() {
return download_item_->GetURL();
}
@ -115,7 +107,7 @@ bool DownloadItem::HasUserGesture() {
}
std::string DownloadItem::GetFilename() {
return base::UTF16ToUTF8(net::GenerateFileName(GetUrl(),
return base::UTF16ToUTF8(net::GenerateFileName(GetURL(),
GetContentDisposition(),
std::string(),
download_item_->GetSuggestedFilename(),
@ -143,15 +135,17 @@ void DownloadItem::Cancel() {
download_item_->Cancel(true);
}
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
// static
void DownloadItem::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("pause", &DownloadItem::Pause)
.SetMethod("resume", &DownloadItem::Resume)
.SetMethod("cancel", &DownloadItem::Cancel)
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
.SetMethod("getUrl", &DownloadItem::GetUrl)
.SetMethod("getURL", &DownloadItem::GetURL)
.SetMethod("getMimeType", &DownloadItem::GetMimeType)
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
.SetMethod("getFilename", &DownloadItem::GetFilename)
@ -159,14 +153,6 @@ mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
.SetMethod("setSavePath", &DownloadItem::SetSavePath);
}
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
// static
mate::Handle<DownloadItem> DownloadItem::Create(
v8::Isolate* isolate, content::DownloadItem* item) {
@ -182,6 +168,18 @@ void* DownloadItem::UserDataKey() {
return &kDownloadItemSavePathKey;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapDownloadItem));
}
} // namespace api
} // namespace atom
@ -193,7 +191,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
dict.SetMethod("_clearWrapDownloadItem", &atom::api::ClearWrapDownloadItem);
}
} // namespace

View file

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

View file

@ -8,9 +8,9 @@
#include <map>
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/callback.h"
#include "chrome/browser/extensions/global_shortcut_listener.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h"
#include "ui/base/accelerators/accelerator.h"
@ -19,13 +19,13 @@ namespace atom {
namespace api {
class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
public mate::Wrappable {
public mate::TrackableObject<GlobalShortcut> {
public:
static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate);
protected:
GlobalShortcut();
virtual ~GlobalShortcut();
~GlobalShortcut() override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(

View file

@ -151,6 +151,7 @@ bool Menu::IsVisibleAt(int index) const {
void Menu::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("insertItem", &Menu::InsertItemAt)
.SetMethod("insertCheckItem", &Menu::InsertCheckItemAt)
.SetMethod("insertRadioItem", &Menu::InsertRadioItemAt)

View file

@ -8,16 +8,16 @@
#include <string>
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "native_mate/wrappable.h"
namespace atom {
namespace api {
class Menu : public mate::Wrappable,
class Menu : public mate::TrackableObject<Menu>,
public AtomMenuModel::Delegate {
public:
static mate::Wrappable* Create();
@ -37,7 +37,7 @@ class Menu : public mate::Wrappable,
protected:
Menu();
virtual ~Menu();
~Menu() override;
// mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override;

View file

@ -5,7 +5,7 @@
#ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/api/trackable_object.h"
#include "base/compiler_specific.h"
#include "base/power_monitor/power_observer.h"
#include "native_mate/handle.h"
@ -14,14 +14,14 @@ namespace atom {
namespace api {
class PowerMonitor : public mate::EventEmitter,
class PowerMonitor : public mate::TrackableObject<PowerMonitor>,
public base::PowerObserver {
public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate);
protected:
PowerMonitor();
virtual ~PowerMonitor();
~PowerMonitor() override;
// base::PowerObserver implementations:
void OnPowerStateChange(bool on_battery_power) override;

View file

@ -7,10 +7,10 @@
#include <map>
#include "atom/browser/api/trackable_object.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/power_save_blocker.h"
#include "native_mate/handle.h"
#include "native_mate/wrappable.h"
namespace mate {
class Dictionary;
@ -20,13 +20,13 @@ namespace atom {
namespace api {
class PowerSaveBlocker : public mate::Wrappable {
class PowerSaveBlocker : public mate::TrackableObject<PowerSaveBlocker> {
public:
static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate);
protected:
PowerSaveBlocker();
virtual ~PowerSaveBlocker();
~PowerSaveBlocker() override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -48,7 +48,6 @@ class PowerSaveBlocker : public mate::Wrappable {
std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>;
PowerSaveBlockerTypeMap power_save_blocker_types_;
DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker);
};

View file

@ -12,27 +12,12 @@
#include "atom/browser/net/url_request_fetch_job.h"
#include "atom/browser/net/url_request_string_job.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/node_includes.h"
#include "native_mate/dictionary.h"
using content::BrowserThread;
namespace mate {
template<>
struct Converter<const net::URLRequest*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const net::URLRequest* val) {
return mate::ObjectTemplateBuilder(isolate)
.SetValue("method", val->method())
.SetValue("url", val->url().spec())
.SetValue("referrer", val->referrer())
.Build()->NewInstance();
}
};
} // namespace mate
namespace atom {
namespace api {
@ -52,7 +37,7 @@ mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
.SetMethod("registerBufferProtocol",
&Protocol::RegisterProtocol<URLRequestBufferJob>)
.SetMethod("registerFileProtocol",
&Protocol::RegisterProtocol<UrlRequestAsyncAsarJob>)
&Protocol::RegisterProtocol<URLRequestAsyncAsarJob>)
.SetMethod("registerHttpProtocol",
&Protocol::RegisterProtocol<URLRequestFetchJob>)
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
@ -62,7 +47,7 @@ mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
.SetMethod("interceptBufferProtocol",
&Protocol::InterceptProtocol<URLRequestBufferJob>)
.SetMethod("interceptFileProtocol",
&Protocol::InterceptProtocol<UrlRequestAsyncAsarJob>)
&Protocol::InterceptProtocol<URLRequestAsyncAsarJob>)
.SetMethod("interceptHttpProtocol",
&Protocol::InterceptProtocol<URLRequestFetchJob>)
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);

View file

@ -41,7 +41,7 @@ std::vector<std::string> MetricsToArray(uint32_t metrics) {
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR)
array.push_back("scaleFactor");
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_ROTATION)
array.push_back("rotaion");
array.push_back("rotation");
return array;
}

View file

@ -9,16 +9,22 @@
#include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/api/atom_api_download_item.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/api/save_page_handler.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/net/atom_cert_verifier.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/node_includes.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
#include "brightray/browser/net/devtools_network_conditions.h"
#include "brightray/browser/net/devtools_network_controller.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
@ -45,7 +51,7 @@ struct ClearStorageDataOptions {
uint32 GetStorageMask(const std::vector<std::string>& storage_types) {
uint32 storage_mask = 0;
for (const auto& it : storage_types) {
auto type = base::StringToLowerASCII(it);
auto type = base::ToLowerASCII(it);
if (type == "appcache")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
else if (type == "cookies")
@ -69,7 +75,7 @@ uint32 GetStorageMask(const std::vector<std::string>& storage_types) {
uint32 GetQuotaMask(const std::vector<std::string>& quota_types) {
uint32 quota_mask = 0;
for (const auto& it : quota_types) {
auto type = base::StringToLowerASCII(it);
auto type = base::ToLowerASCII(it);
if (type == "temporary")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY;
else if (type == "persistent")
@ -102,6 +108,24 @@ struct Converter<ClearStorageDataOptions> {
}
};
template<>
struct Converter<net::ProxyConfig> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
net::ProxyConfig* out) {
std::string proxy;
if (!ConvertFromV8(isolate, val, &proxy))
return false;
auto pac_url = GURL(proxy);
if (pac_url.is_valid()) {
out->set_pac_url(pac_url);
} else {
out->proxy_rules().ParseFromString(proxy);
}
return true;
}
};
} // namespace mate
namespace atom {
@ -206,12 +230,13 @@ void ClearHttpCacheInIO(
}
void SetProxyInIO(net::URLRequestContextGetter* getter,
const std::string& proxy,
const net::ProxyConfig& config,
const base::Closure& callback) {
net::ProxyConfig config;
config.proxy_rules().ParseFromString(proxy);
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
proxy_service->ResetConfigService(make_scoped_ptr(
new net::ProxyConfigServiceFixed(config)));
// Refetches and applies the new pac script if provided.
proxy_service->ForceReloadProxyConfig();
RunCallbackInUI(callback);
}
@ -229,12 +254,13 @@ Session::Session(AtomBrowserContext* browser_context)
Session::~Session() {
content::BrowserContext::GetDownloadManager(browser_context())->
RemoveObserver(this);
Destroy();
}
void Session::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) {
auto web_contents = item->GetWebContents();
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
return;
bool prevent_default = Emit(
"will-download",
DownloadItem::Create(isolate(), item),
@ -245,14 +271,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) {
new ResolveProxyHelper(browser_context(), url, callback);
}
@ -282,11 +300,11 @@ void Session::ClearStorageData(mate::Arguments* args) {
base::Time(), base::Time::Max(), callback);
}
void Session::SetProxy(const std::string& proxy,
void Session::SetProxy(const net::ProxyConfig& config,
const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback));
}
void Session::SetDownloadPath(const base::FilePath& path) {
@ -294,6 +312,54 @@ void Session::SetDownloadPath(const base::FilePath& path) {
prefs::kDownloadDefaultDirectory, path);
}
void Session::EnableNetworkEmulation(const mate::Dictionary& options) {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions;
bool offline = false;
double latency, download_throughput, upload_throughput;
if (options.Get("offline", &offline) && offline) {
conditions.reset(new brightray::DevToolsNetworkConditions(offline));
} else {
options.Get("latency", &latency);
options.Get("downloadThroughput", &download_throughput);
options.Get("uploadThroughput", &upload_throughput);
conditions.reset(
new brightray::DevToolsNetworkConditions(false,
latency,
download_throughput,
upload_throughput));
}
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
void Session::DisableNetworkEmulation() {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions(
new brightray::DevToolsNetworkConditions(false));
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
mate::Arguments* args) {
AtomCertVerifier::VerifyProc proc;
if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) {
args->ThrowError("Must pass null or function");
return;
}
browser_context_->cert_verifier()->SetVerifyProc(proc);
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context());
@ -302,17 +368,6 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
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)
.SetProperty("cookies", &Session::Cookies);
}
// static
mate::Handle<Session> Session::CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
@ -333,14 +388,34 @@ mate::Handle<Session> Session::FromPartition(
static_cast<AtomBrowserContext*>(browser_context.get()));
}
void SetWrapSession(const WrapSessionCallback& callback) {
g_wrap_session = callback;
// 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() {
g_wrap_session.Reset();
}
void SetWrapSession(const WrapSessionCallback& callback) {
g_wrap_session = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapSession));
}
} // namespace api
} // namespace atom
@ -353,7 +428,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
mate::Dictionary dict(isolate, exports);
dict.SetMethod("fromPartition", &atom::api::Session::FromPartition);
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
dict.SetMethod("_clearWrapSession", &atom::api::ClearWrapSession);
}
} // namespace

View file

@ -20,6 +20,11 @@ class FilePath;
namespace mate {
class Arguments;
class Dictionary;
}
namespace net {
class ProxyConfig;
}
namespace atom {
@ -43,6 +48,10 @@ class Session: public mate::TrackableObject<Session>,
AtomBrowserContext* browser_context() const { return browser_context_.get(); }
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected:
explicit Session(AtomBrowserContext* browser_context);
~Session();
@ -51,20 +60,15 @@ class Session: public mate::TrackableObject<Session>,
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
private:
// mate::TrackableObject:
void Destroy() override;
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args);
void SetProxy(const std::string& proxy, const base::Closure& callback);
void SetProxy(const net::ProxyConfig& config, const base::Closure& callback);
void SetDownloadPath(const base::FilePath& path);
void EnableNetworkEmulation(const mate::Dictionary& options);
void DisableNetworkEmulation();
void SetCertVerifyProc(v8::Local<v8::Value> proc, mate::Arguments* args);
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
// Cached object for cookies API.

View file

@ -44,21 +44,21 @@ mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("clicked",
EmitCustomEvent("click",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("double-clicked",
EmitCustomEvent("double-click",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("right-clicked",
EmitCustomEvent("right-click",
ModifiersToObject(isolate(), modifiers), bounds);
}
@ -67,23 +67,31 @@ void Tray::OnBalloonShow() {
}
void Tray::OnBalloonClicked() {
Emit("balloon-clicked");
Emit("balloon-click");
}
void Tray::OnBalloonClosed() {
Emit("balloon-closed");
}
void Tray::OnDrop() {
Emit("drop");
}
void Tray::OnDropFiles(const std::vector<std::string>& files) {
Emit("drop-files", files);
}
bool Tray::IsDestroyed() const {
return !tray_icon_;
void Tray::OnDragEntered() {
Emit("drag-enter");
}
void Tray::Destroy() {
tray_icon_.reset();
void Tray::OnDragExited() {
Emit("drag-leave");
}
void Tray::OnDragEnded() {
Emit("drag-end");
}
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
@ -121,9 +129,11 @@ void Tray::DisplayBalloon(mate::Arguments* args,
}
void Tray::PopUpContextMenu(mate::Arguments* args) {
mate::Handle<Menu> menu;
args->GetNext(&menu);
gfx::Point 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) {
@ -144,7 +154,7 @@ v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Tray::Destroy, true)
.MakeDestroyable()
.SetMethod("setImage", &Tray::SetImage)
.SetMethod("setPressedImage", &Tray::SetPressedImage)
.SetMethod("setToolTip", &Tray::SetToolTip)

View file

@ -8,7 +8,7 @@
#include <string>
#include <vector>
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/ui/tray_icon_observer.h"
#include "base/memory/scoped_ptr.h"
@ -29,7 +29,7 @@ namespace api {
class Menu;
class Tray : public mate::EventEmitter,
class Tray : public mate::TrackableObject<Tray>,
public TrayIconObserver {
public:
static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image);
@ -39,7 +39,7 @@ class Tray : public mate::EventEmitter,
protected:
explicit Tray(const gfx::Image& image);
virtual ~Tray();
~Tray() override;
// TrayIconObserver:
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
@ -48,12 +48,12 @@ class Tray : public mate::EventEmitter,
void OnBalloonShow() override;
void OnBalloonClicked() override;
void OnBalloonClosed() override;
void OnDrop() override;
void OnDropFiles(const std::vector<std::string>& files) override;
void OnDragEntered() override;
void OnDragExited() override;
void OnDragEnded() override;
// mate::Wrappable:
bool IsDestroyed() const override;
void Destroy();
void SetImage(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);

View file

@ -7,6 +7,7 @@
#include <set>
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
@ -17,6 +18,7 @@
#include "atom/common/api/event_emitter_caller.h"
#include "atom/common/native_mate_converters/blink_converter.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/content_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
@ -26,9 +28,11 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/printing/print_preview_message_handler.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/navigation_details.h"
@ -43,12 +47,14 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/context_menu_params.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/base/l10n/l10n_util.h"
#include "atom/common/node_includes.h"
@ -60,9 +66,21 @@ struct PrintSettings {
};
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::string accept_lang,
std::string user_agent) {
getter->GetURLRequestContext()->set_http_user_agent_settings(
new net::StaticHttpUserAgentSettings("en-us,en", user_agent));
new net::StaticHttpUserAgentSettings(
net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang),
user_agent));
}
bool NotifyZoomLevelChanged(
double level, content::WebContents* guest_web_contents) {
guest_web_contents->SendToAllFrames(
new AtomViewMsg_SetZoomLevel(MSG_ROUTING_NONE, level));
// Return false to iterate over all guests.
return false;
}
} // namespace
@ -130,8 +148,7 @@ struct Converter<net::HttpResponseHeaders*> {
std::string key;
std::string value;
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
key = base::StringToLowerASCII(key);
value = base::StringToLowerASCII(value);
key = base::ToLowerASCII(key);
if (response_headers.HasKey(key)) {
base::ListValue* values = nullptr;
if (response_headers.GetList(key, &values))
@ -147,6 +164,27 @@ struct Converter<net::HttpResponseHeaders*> {
}
};
template<>
struct Converter<content::SavePageType> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
content::SavePageType* out) {
std::string save_type;
if (!ConvertFromV8(isolate, val, &save_type))
return false;
save_type = base::ToLowerASCII(save_type);
if (save_type == "htmlonly") {
*out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
} else if (save_type == "htmlcomplete") {
*out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
} else if (save_type == "mhtml") {
*out = content::SAVE_PAGE_TYPE_AS_MHTML;
} else {
return false;
}
return true;
}
};
} // namespace mate
@ -156,8 +194,6 @@ namespace api {
namespace {
v8::Persistent<v8::ObjectTemplate> template_;
// The wrapWebContents function which is implemented in JavaScript
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapWebContentsCallback g_wrap_web_contents;
@ -228,10 +264,10 @@ WebContents::WebContents(v8::Isolate* isolate,
AttachAsUserData(web_contents);
InitWithWebContents(web_contents);
managed_web_contents()->GetView()->SetDelegate(this);
// Save the preferences in C++.
base::DictionaryValue web_preferences;
mate::ConvertFromV8(isolate, options.GetHandle(), &web_preferences);
new WebContentsPreferences(web_contents, &web_preferences);
new WebContentsPreferences(web_contents, options);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
@ -252,7 +288,15 @@ WebContents::WebContents(v8::Isolate* isolate,
}
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,
@ -367,6 +411,15 @@ void WebContents::RendererResponsive(content::WebContents* source) {
owner_window()->RendererResponsive(source);
}
bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) {
if (!params.custom_context.is_pepper_menu)
return false;
Emit("pepper-context-menu", std::make_pair(params, web_contents()));
web_contents()->NotifyContextMenuClosed(params.custom_context);
return true;
}
void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired.
@ -413,14 +466,13 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
Emit("did-finish-load");
}
// this error occurs when host could not be found
void WebContents::DidFailProvisionalLoad(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
const GURL& url,
int error_code,
const base::string16& error_description,
bool was_ignored_by_handler) {
Emit("did-fail-load", error_code, error_description, validated_url);
Emit("did-fail-provisional-load", error_code, error_description, url);
}
void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
@ -473,9 +525,10 @@ void WebContents::DidNavigateMainFrame(
void WebContents::TitleWasSet(content::NavigationEntry* entry,
bool explicit_set) {
// Back/Forward navigation may have pruned entries.
if (entry)
Emit("page-title-set", entry->GetTitle(), explicit_set);
Emit("-page-title-updated", entry->GetTitle(), explicit_set);
else
Emit("-page-title-updated", "", explicit_set);
}
void WebContents::DidUpdateFaviconURL(
@ -491,12 +544,40 @@ void WebContents::DidUpdateFaviconURL(
Emit("page-favicon-updated", unique_urls);
}
void WebContents::DevToolsFocused() {
Emit("devtools-focused");
}
void WebContents::DevToolsOpened() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto handle = WebContents::CreateFrom(
isolate(), managed_web_contents()->GetDevToolsWebContents());
devtools_web_contents_.Reset(isolate(), handle.ToV8());
// Inherit owner window in devtools.
if (owner_window())
handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(),
owner_window());
Emit("devtools-opened");
}
void WebContents::DevToolsClosed() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
devtools_web_contents_.Reset();
Emit("devtools-closed");
}
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_HANDLER(AtomViewHostMsg_ZoomLevelChanged, OnZoomLevelChanged)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@ -516,23 +597,6 @@ void WebContents::NavigationEntryCommitted(
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();
}
}
bool WebContents::IsAlive() const {
return web_contents() != NULL;
}
int WebContents::GetID() const {
return web_contents()->GetRenderProcessHost()->GetID();
}
@ -553,12 +617,25 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
if (options.Get("userAgent", &user_agent))
SetUserAgent(user_agent);
std::string extra_headers;
if (options.Get("extraHeaders", &extra_headers))
params.extra_headers = extra_headers;
params.transition_type = ui::PAGE_TRANSITION_TYPED;
params.should_clear_history_list = true;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
web_contents()->GetController().LoadURLWithParams(params);
}
void WebContents::DownloadURL(const GURL& url) {
auto browser_context = web_contents()->GetBrowserContext();
auto download_manager =
content::BrowserContext::GetDownloadManager(browser_context);
download_manager->DownloadUrl(
content::DownloadUrlParameters::FromWebContents(web_contents(), url));
}
GURL WebContents::GetURL() const {
return web_contents()->GetURL();
}
@ -579,10 +656,6 @@ void WebContents::Stop() {
web_contents()->Stop();
}
void WebContents::ReloadIgnoringCache() {
web_contents()->GetController().ReloadIgnoringCache(false);
}
void WebContents::GoBack() {
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
web_contents()->GetController().GoBack();
@ -606,8 +679,10 @@ void WebContents::SetUserAgent(const std::string& user_agent) {
web_contents()->SetUserAgentOverride(user_agent);
scoped_refptr<net::URLRequestContextGetter> getter =
web_contents()->GetBrowserContext()->GetRequestContext();
auto accept_lang = l10n_util::GetApplicationLocale("");
getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
base::Bind(&SetUserAgentInIO, getter, user_agent));
base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent));
}
std::string WebContents::GetUserAgent() {
@ -618,6 +693,13 @@ void WebContents::InsertCSS(const std::string& css) {
web_contents()->InsertCSS(css);
}
bool WebContents::SavePage(const base::FilePath& full_file_path,
const content::SavePageType& save_type,
const SavePageHandler::SavePageCallback& callback) {
auto handler = new SavePageHandler(web_contents(), callback);
return handler->Handle(full_file_path, save_type);
}
void WebContents::ExecuteJavaScript(const base::string16& code,
bool has_user_gesture) {
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
@ -698,10 +780,6 @@ void WebContents::InspectServiceWorker() {
}
}
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, session_);
}
void WebContents::HasServiceWorker(
const base::Callback<void(bool)>& callback) {
auto context = GetServiceWorkerContext(web_contents());
@ -893,79 +971,91 @@ v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
}
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
if (template_.IsEmpty())
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.SetMethod("destroy", &WebContents::Destroy, true)
.SetMethod("isAlive", &WebContents::IsAlive, true)
.SetMethod("getId", &WebContents::GetID)
.SetMethod("equal", &WebContents::Equal)
.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("_reloadIgnoringCache", &WebContents::ReloadIgnoringCache)
.SetMethod("_goBack", &WebContents::GoBack)
.SetMethod("_goForward", &WebContents::GoForward)
.SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("enableDeviceEmulation",
&WebContents::EnableDeviceEmulation)
.SetMethod("disableDeviceEmulation",
&WebContents::DisableDeviceEmulation)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("undo", &WebContents::Undo)
.SetMethod("redo", &WebContents::Redo)
.SetMethod("cut", &WebContents::Cut)
.SetMethod("copy", &WebContents::Copy)
.SetMethod("paste", &WebContents::Paste)
.SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
.SetMethod("delete", &WebContents::Delete)
.SetMethod("selectAll", &WebContents::SelectAll)
.SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage, true)
.SetMethod("sendInputEvent", &WebContents::SendInputEvent)
.SetMethod("beginFrameSubscription",
&WebContents::BeginFrameSubscription)
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session)
.Build());
return mate::ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
if (owner_window())
return Window::From(isolate(), owner_window());
else
return v8::Null(isolate());
}
bool WebContents::IsDestroyed() const {
return !IsAlive();
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, session_);
}
v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
if (devtools_web_contents_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
}
// static
void WebContents::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("getId", &WebContents::GetID)
.SetMethod("equal", &WebContents::Equal)
.SetMethod("_loadURL", &WebContents::LoadURL)
.SetMethod("downloadURL", &WebContents::DownloadURL)
.SetMethod("_getURL", &WebContents::GetURL)
.SetMethod("getTitle", &WebContents::GetTitle)
.SetMethod("isLoading", &WebContents::IsLoading)
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
.SetMethod("_stop", &WebContents::Stop)
.SetMethod("_goBack", &WebContents::GoBack)
.SetMethod("_goForward", &WebContents::GoForward)
.SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("savePage", &WebContents::SavePage)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("enableDeviceEmulation",
&WebContents::EnableDeviceEmulation)
.SetMethod("disableDeviceEmulation",
&WebContents::DisableDeviceEmulation)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("undo", &WebContents::Undo)
.SetMethod("redo", &WebContents::Redo)
.SetMethod("cut", &WebContents::Cut)
.SetMethod("copy", &WebContents::Copy)
.SetMethod("paste", &WebContents::Paste)
.SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
.SetMethod("delete", &WebContents::Delete)
.SetMethod("selectAll", &WebContents::SelectAll)
.SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage)
.SetMethod("sendInputEvent", &WebContents::SendInputEvent)
.SetMethod("beginFrameSubscription",
&WebContents::BeginFrameSubscription)
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session)
.SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents);
}
AtomBrowserContext* WebContents::GetBrowserContext() const {
@ -985,6 +1075,15 @@ void WebContents::OnRendererMessageSync(const base::string16& channel,
EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
}
void WebContents::OnZoomLevelChanged(double level) {
auto manager = web_contents()->GetBrowserContext()->GetGuestManager();
if (!manager)
return;
manager->ForEachGuest(web_contents(),
base::Bind(&NotifyZoomLevelChanged,
level));
}
// static
mate::Handle<WebContents> WebContents::CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents) {
@ -1007,14 +1106,18 @@ mate::Handle<WebContents> WebContents::Create(
return handle;
}
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
g_wrap_web_contents = callback;
}
void ClearWrapWebContents() {
g_wrap_web_contents.Reset();
}
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
g_wrap_web_contents = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapWebContents));
}
} // namespace api
} // namespace atom
@ -1028,7 +1131,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
mate::Dictionary dict(isolate, exports);
dict.SetMethod("create", &atom::api::WebContents::Create);
dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents);
dict.SetMethod("_clearWrapWebContents", &atom::api::ClearWrapWebContents);
}
} // namespace

View file

@ -9,6 +9,7 @@
#include <vector>
#include "atom/browser/api/frame_subscriber.h"
#include "atom/browser/api/save_page_handler.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/common_web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
@ -53,13 +54,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
static mate::Handle<WebContents> Create(
v8::Isolate* isolate, const mate::Dictionary& options);
// mate::TrackableObject:
void Destroy() override;
bool IsAlive() const;
int GetID() const;
bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options);
void DownloadURL(const GURL& url);
GURL GetURL() const;
base::string16 GetTitle() const;
bool IsLoading() const;
@ -73,6 +71,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent();
void InsertCSS(const std::string& css);
bool SavePage(const base::FilePath& full_file_path,
const content::SavePageType& save_type,
const SavePageHandler::SavePageCallback& callback);
void ExecuteJavaScript(const base::string16& code,
bool has_user_gesture);
void OpenDevTools(mate::Arguments* args);
@ -83,7 +84,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
void DisableDeviceEmulation();
void InspectElement(int x, int y);
void InspectServiceWorker();
v8::Local<v8::Value> Session(v8::Isolate* isolate);
void HasServiceWorker(const base::Callback<void(bool)>&);
void UnregisterServiceWorker(const base::Callback<void(bool)>&);
void SetAudioMuted(bool muted);
@ -135,16 +135,22 @@ class WebContents : public mate::TrackableObject<WebContents>,
// Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
// Returns the owner window.
v8::Local<v8::Value> GetOwnerBrowserWindow();
// Properties.
v8::Local<v8::Value> Session(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:
explicit WebContents(content::WebContents* web_contents);
WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
~WebContents();
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
// content::WebContentsDelegate:
bool AddMessageToConsole(content::WebContents* source,
int32 level,
@ -179,6 +185,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
void ExitFullscreenModeForTab(content::WebContents* source) override;
void RendererUnresponsive(content::WebContents* source) override;
void RendererResponsive(content::WebContents* source) override;
bool HandleContextMenu(const content::ContextMenuParams& params) override;
// content::WebContentsObserver:
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
@ -218,6 +225,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
void PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) override;
// brightray::InspectableWebContentsViewDelegate:
void DevToolsFocused() override;
void DevToolsOpened() override;
void DevToolsClosed() override;
private:
enum Type {
BROWSER_WINDOW, // Used by BrowserWindow.
@ -236,7 +248,12 @@ class WebContents : public mate::TrackableObject<WebContents>,
const base::ListValue& args,
IPC::Message* message);
// Called when guests need to be notified of
// embedders' zoom level change.
void OnZoomLevelChanged(double level);
v8::Global<v8::Value> session_;
v8::Global<v8::Value> devtools_web_contents_;
scoped_ptr<WebViewGuestDelegate> guest_delegate_;

View file

@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "atom/browser/api/atom_api_window.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_web_contents.h"
@ -60,22 +61,82 @@ void OnCapturePageDone(
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
}
// Converts min-width to minWidth, returns false if no conversion is needed.
bool TranslateOldKey(const std::string& key, std::string* new_key) {
if (key.find('-') == std::string::npos)
return false;
new_key->reserve(key.size());
bool next_upper_case = false;
for (char c : key) {
if (c == '-') {
next_upper_case = true;
} else if (next_upper_case) {
new_key->push_back(base::ToUpperASCII(c));
next_upper_case = false;
} else {
new_key->push_back(c);
}
}
return true;
}
// Converts min-width to minWidth recursively in the dictionary.
void TranslateOldOptions(v8::Isolate* isolate, v8::Local<v8::Object> options) {
auto context = isolate->GetCurrentContext();
auto maybe_keys = options->GetOwnPropertyNames(context);
if (maybe_keys.IsEmpty())
return;
std::vector<std::string> keys;
if (!mate::ConvertFromV8(isolate, maybe_keys.ToLocalChecked(), &keys))
return;
mate::Dictionary dict(isolate, options);
for (const auto& key : keys) {
v8::Local<v8::Value> value;
if (!dict.Get(key, &value)) // Shouldn't happen, but guard it anyway.
continue;
// Go recursively.
v8::Local<v8::Object> sub_options;
if (mate::ConvertFromV8(isolate, value, &sub_options))
TranslateOldOptions(isolate, sub_options);
// Translate key.
std::string new_key;
if (TranslateOldKey(key, &new_key)) {
dict.Set(new_key, value);
dict.Delete(key);
}
}
}
#if defined(OS_WIN)
// Converts binary data to Buffer.
v8::Local<v8::Value> ToBuffer(v8::Isolate* isolate, void* val, int size) {
auto buffer = node::Buffer::New(isolate, static_cast<char*>(val), size);
if (buffer.IsEmpty())
return v8::Null(isolate);
else
return buffer.ToLocalChecked();
}
#endif
} // namespace
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
// Use options['web-preferences'] to create WebContents.
// Be compatible with old style field names like min-width.
TranslateOldOptions(isolate, options.GetHandle());
// Use options.webPreferences to create WebContents.
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
options.Get(switches::kWebPreferences, &web_preferences);
options.Get(options::kWebPreferences, &web_preferences);
// Be compatible with old options which are now in web_preferences.
v8::Local<v8::Value> value;
if (options.Get(switches::kNodeIntegration, &value))
web_preferences.Set(switches::kNodeIntegration, value);
if (options.Get(switches::kPreloadScript, &value))
web_preferences.Set(switches::kPreloadScript, value);
if (options.Get(switches::kZoomFactor, &value))
web_preferences.Set(switches::kZoomFactor, value);
if (options.Get(options::kNodeIntegration, &value))
web_preferences.Set(options::kNodeIntegration, value);
if (options.Get(options::kPreloadScript, &value))
web_preferences.Set(options::kPreloadScript, value);
if (options.Get(options::kZoomFactor, &value))
web_preferences.Set(options::kZoomFactor, value);
// Creates the WebContents used by BrowserWindow.
auto web_contents = WebContents::Create(isolate, web_preferences);
@ -92,16 +153,16 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
web_contents->SetOwnerWindow(window_.get());
window_->InitFromOptions(options);
window_->AddObserver(this);
AttachAsUserData(window_.get());
}
Window::~Window() {
if (window_)
Destroy();
}
if (!window_->IsClosed())
window_->CloseContents(nullptr);
void Window::OnPageTitleUpdated(bool* prevent_default,
const std::string& title) {
*prevent_default = Emit("page-title-updated", title);
// Destroy the native window in next tick because the native code might be
// iterating all windows.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release());
}
void Window::WillCloseWindow(bool* prevent_default) {
@ -109,19 +170,19 @@ void Window::WillCloseWindow(bool* prevent_default) {
}
void Window::OnWindowClosed() {
if (api_web_contents_) {
api_web_contents_->DestroyWebContents();
api_web_contents_ = nullptr;
web_contents_.Reset();
}
api_web_contents_->DestroyWebContents();
RemoveFromWeakMap();
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");
// Clean up the resources after window has been closed.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release());
// Destroy the native class when window is closed.
base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
}
void Window::OnWindowBlur() {
@ -184,60 +245,45 @@ void Window::OnRendererResponsive() {
Emit("responsive");
}
void Window::OnDevToolsFocus() {
Emit("devtools-focused");
}
void Window::OnDevToolsOpened() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto handle = WebContents::CreateFrom(
isolate(), api_web_contents_->GetDevToolsWebContents());
devtools_web_contents_.Reset(isolate(), handle.ToV8());
Emit("devtools-opened");
}
void Window::OnDevToolsClosed() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
devtools_web_contents_.Reset();
Emit("devtools-closed");
}
void Window::OnExecuteWindowsCommand(const std::string& command_name) {
Emit("app-command", command_name);
}
#if defined(OS_WIN)
void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {
if (IsWindowMessageHooked(message)) {
messages_callback_map_[message].Run(
ToBuffer(isolate(), static_cast<void*>(&w_param), sizeof(WPARAM)),
ToBuffer(isolate(), static_cast<void*>(&l_param), sizeof(LPARAM)));
}
}
#endif
// static
mate::Wrappable* Window::New(v8::Isolate* isolate,
const mate::Dictionary& options) {
mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Arguments* args) {
if (!Browser::Get()->is_ready()) {
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
isolate, "Cannot create BrowserWindow before app is ready")));
return nullptr;
}
if (args->Length() > 1) {
args->ThrowError();
return nullptr;
}
mate::Dictionary options;
if (!(args->Length() == 1 && args->GetNext(&options))) {
options = mate::Dictionary::CreateEmpty(isolate);
}
return new Window(isolate, options);
}
bool Window::IsDestroyed() const {
return !window_ || window_->IsClosed();
}
void Window::Destroy() {
if (window_)
window_->CloseContents(nullptr);
}
void Window::Close() {
window_->Close();
}
bool Window::IsClosed() {
return window_->IsClosed();
}
void Window::Focus() {
window_->Focus(true);
}
@ -406,6 +452,10 @@ bool Window::IsKiosk() {
return window_->IsKiosk();
}
void Window::SetBackgroundColor(const std::string& color_name) {
window_->SetBackgroundColor(color_name);
}
void Window::FocusOnWebView() {
window_->FocusOnWebView();
}
@ -509,6 +559,29 @@ bool Window::IsMenuBarVisible() {
return window_->IsMenuBarVisible();
}
#if defined(OS_WIN)
bool Window::HookWindowMessage(UINT message,
const MessageCallback& callback) {
messages_callback_map_[message] = callback;
return true;
}
void Window::UnhookWindowMessage(UINT message) {
if (!ContainsKey(messages_callback_map_, message))
return;
messages_callback_map_.erase(message);
}
bool Window::IsWindowMessageHooked(UINT message) {
return ContainsKey(messages_callback_map_, message);
}
void Window::UnhookAllWindowMessages() {
messages_callback_map_.clear();
}
#endif
#if defined(OS_MACOSX)
void Window::ShowDefinitionForSelection() {
window_->ShowDefinitionForSelection();
@ -540,20 +613,12 @@ v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, web_contents_);
}
v8::Local<v8::Value> Window::DevToolsWebContents(v8::Isolate* isolate) {
if (devtools_web_contents_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
}
// static
void Window::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Window::Destroy, true)
.MakeDestroyable()
.SetMethod("close", &Window::Close)
.SetMethod("isClosed", &Window::IsClosed)
.SetMethod("focus", &Window::Focus)
.SetMethod("isFocused", &Window::IsFocused)
.SetMethod("show", &Window::Show)
@ -592,6 +657,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
.SetMethod("setKiosk", &Window::SetKiosk)
.SetMethod("isKiosk", &Window::IsKiosk)
.SetMethod("setBackgroundColor", &Window::SetBackgroundColor)
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
@ -613,13 +679,28 @@ void Window::BuildPrototype(v8::Isolate* isolate,
&Window::SetVisibleOnAllWorkspaces)
.SetMethod("isVisibleOnAllWorkspaces",
&Window::IsVisibleOnAllWorkspaces)
#if defined(OS_WIN)
.SetMethod("hookWindowMessage", &Window::HookWindowMessage)
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
.SetMethod("unhookWindowMessage", &Window::UnhookWindowMessage)
.SetMethod("unhookAllWindowMessages", &Window::UnhookAllWindowMessages)
#endif
#if defined(OS_MACOSX)
.SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection)
#endif
.SetProperty("id", &Window::ID, true)
.SetProperty("webContents", &Window::WebContents, true)
.SetProperty("devToolsWebContents", &Window::DevToolsWebContents, true);
.SetProperty("id", &Window::ID)
.SetProperty("webContents", &Window::WebContents);
}
// static
v8::Local<v8::Value> Window::From(v8::Isolate* isolate,
NativeWindow* native_window) {
auto existing = TrackableObject::FromWrappedClass(isolate, native_window);
if (existing)
return existing->GetWrapper(isolate);
else
return v8::Null(isolate);
}
} // namespace api

View file

@ -5,6 +5,7 @@
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <map>
#include <string>
#include <vector>
@ -37,12 +38,15 @@ class WebContents;
class Window : public mate::TrackableObject<Window>,
public NativeWindowObserver {
public:
static mate::Wrappable* New(v8::Isolate* isolate,
const mate::Dictionary& options);
static mate::Wrappable* New(v8::Isolate* isolate, mate::Arguments* args);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
// Returns the BrowserWindow object from |native_window|.
static v8::Local<v8::Value> From(v8::Isolate* isolate,
NativeWindow* native_window);
NativeWindow* window() const { return window_.get(); }
protected:
@ -50,8 +54,6 @@ class Window : public mate::TrackableObject<Window>,
virtual ~Window();
// NativeWindowObserver:
void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) override;
void WillCloseWindow(bool* prevent_default) override;
void OnWindowClosed() override;
void OnWindowBlur() override;
@ -69,21 +71,15 @@ class Window : public mate::TrackableObject<Window>,
void OnWindowLeaveHtmlFullScreen() override;
void OnRendererUnresponsive() override;
void OnRendererResponsive() override;
void OnDevToolsFocus() override;
void OnDevToolsOpened() override;
void OnDevToolsClosed() override;
void OnExecuteWindowsCommand(const std::string& command_name) override;
// mate::Wrappable:
bool IsDestroyed() const override;
#if defined(OS_WIN)
void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override;
#endif
private:
// mate::TrackableObject:
void Destroy() override;
// APIs for NativeWindow.
void Close();
bool IsClosed();
void Focus();
bool IsFocused();
void Show();
@ -121,6 +117,7 @@ class Window : public mate::TrackableObject<Window>,
void SetSkipTaskbar(bool skip);
void SetKiosk(bool kiosk);
bool IsKiosk();
void SetBackgroundColor(const std::string& color_name);
void FocusOnWebView();
void BlurWebView();
bool IsWebViewFocused();
@ -141,6 +138,16 @@ class Window : public mate::TrackableObject<Window>,
bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_WIN)
typedef base::Callback<void(v8::Local<v8::Value>,
v8::Local<v8::Value>)> MessageCallback;
bool HookWindowMessage(UINT message, const MessageCallback& callback);
bool IsWindowMessageHooked(UINT message);
void UnhookWindowMessage(UINT message);
void UnhookAllWindowMessages();
#endif
#if defined(OS_MACOSX)
void ShowDefinitionForSelection();
#endif
@ -150,10 +157,13 @@ class Window : public mate::TrackableObject<Window>,
int32_t ID() const;
v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
#if defined(OS_WIN)
typedef std::map<UINT, MessageCallback> MessageCallbackMap;
MessageCallbackMap messages_callback_map_;
#endif
v8::Global<v8::Value> web_contents_;
v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> menu_;
api::WebContents* api_web_contents_;

View file

@ -24,12 +24,11 @@ bool FrameSubscriber::ShouldCaptureFrame(
base::TimeTicks present_time,
scoped_refptr<media::VideoFrame>* storage,
DeliverFrameCallback* callback) {
*storage = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size_,
gfx::Rect(size_), size_,
base::TimeDelta());
*storage = media::VideoFrame::CreateFrame(
media::PIXEL_FORMAT_YV12,
size_, gfx::Rect(size_), size_, base::TimeDelta());
*callback = base::Bind(&FrameSubscriber::OnFrameDelivered,
base::Unretained(this),
*storage);
base::Unretained(this), *storage);
return true;
}
@ -38,6 +37,9 @@ void FrameSubscriber::OnFrameDelivered(
if (!result)
return;
v8::Locker locker(isolate_);
v8::HandleScope handle_scope(isolate_);
gfx::Rect rect = frame->visible_rect();
size_t rgb_arr_size = rect.width() * rect.height() * 4;
v8::MaybeLocal<v8::Object> buffer = node::Buffer::New(isolate_, rgb_arr_size);
@ -56,8 +58,6 @@ void FrameSubscriber::OnFrameDelivered(
rect.width() * 4,
media::YV12);
v8::Locker locker(isolate_);
v8::HandleScope handle_scope(isolate_);
callback_.Run(buffer.ToLocalChecked());
}

View file

@ -1,30 +1,17 @@
EventEmitter = require('events').EventEmitter
{deprecate, session, Menu} = require 'electron'
{EventEmitter} = require 'events'
bindings = process.atomBinding 'app'
sessionBindings = process.atomBinding 'session'
downloadItemBindings = process.atomBinding 'download_item'
app = bindings.app
app.__proto__ = EventEmitter.prototype
wrapSession = (session) ->
# session is an Event Emitter.
session.__proto__ = EventEmitter.prototype
wrapDownloadItem = (download_item) ->
# download_item is an Event Emitter.
download_item.__proto__ = EventEmitter.prototype
# Be compatible with old APIs.
download_item.url = download_item.getUrl()
download_item.filename = download_item.getFilename()
download_item.mimeType = download_item.getMimeType()
download_item.hasUserGesture = download_item.hasUserGesture()
app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu
Menu.setApplicationMenu menu
app.getApplicationMenu = ->
require('menu').getApplicationMenu()
Menu.getApplicationMenu()
app.commandLine =
appendSwitch: bindings.appendSwitch,
@ -47,22 +34,39 @@ app.setAppPath = (path) ->
app.getAppPath = ->
appPath
# Be compatible with old API.
app.once 'ready', -> @emit 'finish-launching'
app.terminate = app.quit
app.exit = process.exit
app.getHomeDir = -> @getPath 'home'
app.getDataPath = -> @getPath 'userData'
app.setDataPath = (path) -> @setPath 'userData', path
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows
# Routes the events to webContents.
for name in ['login', 'certificate-error', 'select-client-certificate']
do (name) ->
app.on name, (event, webContents, args...) ->
webContents.emit name, event, args...
# Session wrapper.
sessionBindings._setWrapSession wrapSession
process.once 'exit', sessionBindings._clearWrapSession
# Deprecated.
app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', ->
@getPath 'home'
app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', ->
@getPath 'userData'
app.setDataPath = deprecate 'app.setDataPath', 'app.setPath', (path) ->
@setPath 'userData', path
app.resolveProxy = deprecate 'app.resolveProxy', 'session.defaultSession.resolveProxy', (url, callback) ->
session.defaultSession.resolveProxy url, callback
deprecate.rename app, 'terminate', 'quit'
deprecate.event app, 'finish-launching', 'ready', ->
setImmediate => # give default app a chance to setup default menu.
@emit 'finish-launching'
deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) ->
@emit 'activate-with-no-open-windows', event if not hasVisibleWindows
deprecate.event app, 'select-certificate', 'select-client-certificate'
# Wrappers for native classes.
wrapDownloadItem = (downloadItem) ->
# downloadItem is an EventEmitter.
downloadItem.__proto__ = EventEmitter.prototype
# Deprecated.
deprecate.property downloadItem, 'url', 'getURL'
deprecate.property downloadItem, 'filename', 'getFilename'
deprecate.property downloadItem, 'mimeType', 'getMimeType'
deprecate.rename downloadItem, 'getUrl', 'getURL'
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
process.once 'exit', downloadItemBindings._clearWrapDownloadItem
# Only one App object pemitted.
module.exports = app

View file

@ -1,6 +0,0 @@
module.exports =
browserMainParts:
preMainMessageLoopRun: ->
setImmediate ->
module.exports.browserMainParts.preMainMessageLoopRun()

View file

@ -1,24 +1,12 @@
autoUpdater = process.atomBinding('auto_updater').autoUpdater
EventEmitter = require('events').EventEmitter
{deprecate} = require 'electron'
autoUpdater.__proto__ = EventEmitter.prototype
autoUpdater =
if process.platform is 'win32'
require './auto-updater/auto-updater-win'
else
require './auto-updater/auto-updater-native'
autoUpdater.on 'update-downloaded-raw', (args...) ->
args[3] = new Date(args[3]) # releaseDate
@emit 'update-downloaded', args..., => @quitAndInstall()
autoUpdater.quitAndInstall = ->
# If we don't have any window then quitAndInstall immediately.
BrowserWindow = require 'browser-window'
windows = BrowserWindow.getAllWindows()
if windows.length is 0
@_quitAndInstall()
return
# Do the restart after all windows have been closed.
app = require 'app'
app.removeAllListeners 'window-all-closed'
app.once 'window-all-closed', @_quitAndInstall.bind(this)
win.close() for win in windows
# Deprecated.
deprecate.rename autoUpdater, 'setFeedUrl', 'setFeedURL'
module.exports = autoUpdater

View file

@ -0,0 +1,6 @@
{EventEmitter} = require 'events'
{autoUpdater} = process.atomBinding 'auto_updater'
autoUpdater.__proto__ = EventEmitter.prototype
module.exports = autoUpdater

View file

@ -0,0 +1,42 @@
{app} = require 'electron'
{EventEmitter} = require 'events'
url = require 'url'
squirrelUpdate = require './squirrel-update-win'
class AutoUpdater extends EventEmitter
quitAndInstall: ->
squirrelUpdate.processStart()
app.quit()
setFeedURL: (updateURL) ->
@updateURL = updateURL
checkForUpdates: ->
return @emitError 'Update URL is not set' unless @updateURL
return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported()
@emit 'checking-for-update'
squirrelUpdate.download @updateURL, (error, update) =>
return @emitError error if error?
return @emit 'update-not-available' unless update?
@emit 'update-available'
squirrelUpdate.update @updateURL, (error) =>
return @emitError error if error?
{releaseNotes, version} = update
# Following information is not available on Windows, so fake them.
date = new Date
url = @updateURL
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
# Private: Emit both error object and message, this is to keep compatibility
# with Old APIs.
emitError: (message) ->
@emit 'error', new Error(message), message
module.exports = new AutoUpdater

View file

@ -0,0 +1,67 @@
fs = require 'fs'
path = require 'path'
{spawn} = require 'child_process'
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
exeName = path.basename process.execPath
# Spawn a command and invoke the callback when it completes with an error
# and the output from standard out.
spawnUpdate = (args, detached, callback) ->
try
spawnedProcess = spawn updateExe, args, {detached}
catch error
# Shouldn't happen, but still guard it.
process.nextTick -> callback error
return
stdout = ''
stderr = ''
spawnedProcess.stdout.on 'data', (data) -> stdout += data
spawnedProcess.stderr.on 'data', (data) -> stderr += data
errorEmitted = false
spawnedProcess.on 'error', (error) ->
errorEmitted = true
callback error
spawnedProcess.on 'exit', (code, signal) ->
# We may have already emitted an error.
return if errorEmitted
# Process terminated with error.
if code isnt 0
return callback "Command failed: #{signal ? code}\n#{stderr}"
# Success.
callback null, stdout
# Start an instance of the installed app.
exports.processStart = (callback) ->
spawnUpdate ['--processStart', exeName], true, ->
# Download the releases specified by the URL and write new results to stdout.
exports.download = (updateURL, callback) ->
spawnUpdate ['--download', updateURL], false, (error, stdout) ->
return callback(error) if error?
try
# Last line of output is the JSON details about the releases
json = stdout.trim().split('\n').pop()
update = JSON.parse(json)?.releasesToApply?.pop?()
catch
return callback "Invalid result:\n#{stdout}"
callback null, update
# Update the application to the latest remote version specified by URL.
exports.update = (updateURL, callback) ->
spawnUpdate ['--update', updateURL], false, callback
# Is the Update.exe installed with the current application?
exports.supported = ->
try
fs.accessSync updateExe, fs.R_OK
return true
catch
return false

View file

@ -1,11 +1,12 @@
EventEmitter = require('events').EventEmitter
app = require 'app'
ipc = require 'ipc'
{ipcMain, deprecate} = require 'electron'
{EventEmitter} = require 'events'
BrowserWindow = process.atomBinding('window').BrowserWindow
{BrowserWindow} = process.atomBinding 'window'
BrowserWindow::__proto__ = EventEmitter.prototype
BrowserWindow::_init = ->
{app} = require 'electron' # avoid recursive require.
# Simulate the application menu on platforms other than OS X.
if process.platform isnt 'darwin'
menu = app.getApplicationMenu()
@ -14,7 +15,7 @@ BrowserWindow::_init = ->
# Make new windows requested by links behave like "window.open"
@webContents.on '-new-window', (event, url, frameName) ->
options = show: true, width: 800, height: 600
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
ipcMain.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
# window.resizeTo(...)
# window.moveTo(...)
@ -30,6 +31,11 @@ BrowserWindow::_init = ->
@webContents.on 'crashed', =>
@emit 'crashed'
# Change window title to page title.
@webContents.on 'page-title-updated', (event, title, explicitSet) =>
@emit 'page-title-updated', event, title
@setTitle title unless event.defaultPrevented
# Sometimes the webContents doesn't get focus when window is shown, so we have
# to force focusing on webContents in this case. The safest way is to focus it
# when we first start to load URL, if we do it earlier it won't have effect,
@ -48,6 +54,15 @@ BrowserWindow::_init = ->
# Notify the creation of the window.
app.emit 'browser-window-created', {}, this
# Be compatible with old APIs.
@webContents.on 'devtools-focused', => @emit 'devtools-focused'
@webContents.on 'devtools-opened', => @emit 'devtools-opened'
@webContents.on 'devtools-closed', => @emit 'devtools-closed'
Object.defineProperty this, 'devToolsWebContents',
enumerable: true,
configurable: false,
get: -> @webContents.devToolsWebContents
BrowserWindow.getFocusedWindow = ->
windows = BrowserWindow.getAllWindows()
return window for window in windows when window.isFocused()
@ -61,33 +76,37 @@ BrowserWindow.fromDevToolsWebContents = (webContents) ->
return window for window in windows when window.devToolsWebContents?.equal webContents
# Helpers.
BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
# Be compatible with old API.
BrowserWindow::undo = -> @webContents.undo()
BrowserWindow::redo = -> @webContents.redo()
BrowserWindow::cut = -> @webContents.cut()
BrowserWindow::copy = -> @webContents.copy()
BrowserWindow::paste = -> @webContents.paste()
BrowserWindow::selectAll = -> @webContents.selectAll()
BrowserWindow::restart = -> @webContents.reload()
BrowserWindow::getUrl = -> @webContents.getUrl()
BrowserWindow::loadURL = -> @webContents.loadURL.apply @webContents, arguments
BrowserWindow::getURL = -> @webContents.getURL()
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
BrowserWindow::reloadIgnoringCache = -> @webContents.reloadIgnoringCache.apply @webContents, arguments
BrowserWindow::getPageTitle = -> @webContents.getTitle()
BrowserWindow::isLoading = -> @webContents.isLoading()
BrowserWindow::isWaitingForResponse = -> @webContents.isWaitingForResponse()
BrowserWindow::stop = -> @webContents.stop()
BrowserWindow::isCrashed = -> @webContents.isCrashed()
BrowserWindow::executeJavaScriptInDevTools = (code) -> @devToolsWebContents?.executeJavaScript code
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
BrowserWindow::openDevTools = -> @webContents.openDevTools.apply @webContents, arguments
BrowserWindow::closeDevTools = -> @webContents.closeDevTools()
BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened()
BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
BrowserWindow::print = -> @webContents.print.apply @webContents, arguments
BrowserWindow::printToPDF = -> @webContents.printToPDF.apply @webContents, arguments
# Deprecated.
deprecate.member BrowserWindow, 'undo', 'webContents'
deprecate.member BrowserWindow, 'redo', 'webContents'
deprecate.member BrowserWindow, 'cut', 'webContents'
deprecate.member BrowserWindow, 'copy', 'webContents'
deprecate.member BrowserWindow, 'paste', 'webContents'
deprecate.member BrowserWindow, 'selectAll', 'webContents'
deprecate.member BrowserWindow, 'reloadIgnoringCache', 'webContents'
deprecate.member BrowserWindow, 'isLoading', 'webContents'
deprecate.member BrowserWindow, 'isWaitingForResponse', 'webContents'
deprecate.member BrowserWindow, 'stop', 'webContents'
deprecate.member BrowserWindow, 'isCrashed', 'webContents'
deprecate.member BrowserWindow, 'print', 'webContents'
deprecate.member BrowserWindow, 'printToPDF', 'webContents'
deprecate.rename BrowserWindow, 'restart', 'reload'
deprecate.rename BrowserWindow, 'loadUrl', 'loadURL'
deprecate.rename BrowserWindow, 'getUrl', 'getURL'
BrowserWindow::executeJavaScriptInDevTools = deprecate 'executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', (code) ->
@devToolsWebContents?.executeJavaScript code
BrowserWindow::getPageTitle = deprecate 'getPageTitle', 'webContents.getTitle', ->
@webContents?.getTitle()
module.exports = BrowserWindow

View file

@ -1,7 +1,7 @@
{app, BrowserWindow} = require 'electron'
binding = process.atomBinding 'dialog'
v8Util = process.atomBinding 'v8_util'
app = require 'app'
BrowserWindow = require 'browser-window'
fileDialogProperties =
openFile: 1 << 0

View file

@ -0,0 +1,55 @@
# Import common modules.
module.exports = require '../../../../common/api/lib/exports/electron'
Object.defineProperties module.exports,
# Browser side modules, please sort with alphabet order.
app:
enumerable: true
get: -> require '../app'
autoUpdater:
enumerable: true
get: -> require '../auto-updater'
BrowserWindow:
enumerable: true
get: -> require '../browser-window'
contentTracing:
enumerable: true
get: -> require '../content-tracing'
dialog:
enumerable: true
get: -> require '../dialog'
ipcMain:
enumerable: true
get: -> require '../ipc-main'
globalShortcut:
enumerable: true
get: -> require '../global-shortcut'
Menu:
enumerable: true
get: -> require '../menu'
MenuItem:
enumerable: true
get: -> require '../menu-item'
powerMonitor:
enumerable: true
get: -> require '../power-monitor'
powerSaveBlocker:
enumerable: true
get: -> require '../power-save-blocker'
protocol:
enumerable: true
get: -> require '../protocol'
screen:
enumerable: true
get: -> require '../screen'
session:
enumerable: true
get: -> require '../session'
Tray:
enumerable: true
get: -> require '../tray'
# The internal modules, invisible unless you know their names.
NavigationController:
get: -> require '../navigation-controller'
webContents:
get: -> require '../web-contents'

View file

@ -1,5 +1,3 @@
bindings = process.atomBinding 'global_shortcut'
globalShortcut = bindings.globalShortcut
{globalShortcut} = process.atomBinding 'global_shortcut'
module.exports = globalShortcut

View file

@ -0,0 +1,3 @@
{EventEmitter} = require 'events'
module.exports = new EventEmitter

View file

@ -1,3 +1,6 @@
EventEmitter = require('events').EventEmitter
{deprecate, ipcMain} = require 'electron'
module.exports = new EventEmitter
# This module is deprecated, we mirror everything from ipcMain.
deprecate.warn 'ipc module', 'require("electron").ipcMain'
module.exports = ipcMain

View file

@ -1,4 +1,3 @@
BrowserWindow = require 'browser-window'
v8Util = process.atomBinding 'v8_util'
nextCommandId = 0
@ -14,11 +13,16 @@ rolesMap =
minimize: 'minimize'
close: 'close'
# Maps methods that should be called directly on the BrowserWindow instance
methodInBrowserWindow =
minimize: true
close: true
class MenuItem
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
constructor: (options) ->
Menu = require 'menu'
{Menu} = require 'electron'
{click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
@ -43,8 +47,12 @@ class MenuItem
# Manually flip the checked flags when clicked.
@checked = !@checked if @type in ['checkbox', 'radio']
if @role and rolesMap[@role] and process.platform isnt 'darwin'
focusedWindow?[rolesMap[@role]]()
if @role and rolesMap[@role] and process.platform isnt 'darwin' and focusedWindow?
methodName = rolesMap[@role]
if methodInBrowserWindow[methodName]
focusedWindow[methodName]()
else
focusedWindow.webContents?[methodName]()
else if typeof click is 'function'
click this, focusedWindow
else if typeof @selector is 'string'

View file

@ -1,8 +1,7 @@
BrowserWindow = require 'browser-window'
EventEmitter = require('events').EventEmitter
MenuItem = require 'menu-item'
v8Util = process.atomBinding 'v8_util'
{BrowserWindow, MenuItem} = require 'electron'
{EventEmitter} = require 'events'
v8Util = process.atomBinding 'v8_util'
bindings = process.atomBinding 'menu'
# Automatically generated radio menu item's group id.
@ -79,7 +78,11 @@ Menu::_init = ->
v8Util.setHiddenValue group[0], 'checked', true unless checked
Menu::popup = (window, x, y) ->
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
unless window?.constructor is BrowserWindow
# Shift.
y = x
x = window
window = BrowserWindow.getFocusedWindow()
if x? and y?
@_popupAt(window, x, y)
else

View file

@ -1,15 +1,15 @@
ipc = require 'ipc'
{ipcMain} = require 'electron'
# The history operation in renderer is redirected to browser.
ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
ipcMain.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
event.sender[method] args...
ipc.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) ->
ipcMain.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) ->
event.returnValue = event.sender[method] args...
# JavaScript implementation of Chromium's NavigationController.
# Instead of relying on Chromium for history control, we compeletely do history
# control on user land, and only rely on WebContents.loadUrl for navigation.
# control on user land, and only rely on WebContents.loadURL for navigation.
# This helps us avoid Chromium's various optimizations so we can ensure renderer
# process is restarted everytime.
class NavigationController
@ -17,9 +17,9 @@ class NavigationController
@clearHistory()
# webContents may have already navigated to a page.
if @webContents._getUrl()
if @webContents._getURL()
@currentIndex++
@history.push @webContents._getUrl()
@history.push @webContents._getURL()
@webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) =>
if @inPageIndex > -1 and not inPage
@ -42,12 +42,12 @@ class NavigationController
@currentIndex++
@history.push url
loadUrl: (url, options={}) ->
loadURL: (url, options={}) ->
@pendingIndex = -1
@webContents._loadUrl url, options
@webContents._loadURL url, options
@webContents.emit 'load-url', url, options
getUrl: ->
getURL: ->
if @currentIndex is -1
''
else
@ -59,11 +59,11 @@ class NavigationController
reload: ->
@pendingIndex = @currentIndex
@webContents._loadUrl @getUrl(), {}
@webContents._loadURL @getURL(), {}
reloadIgnoringCache: ->
@webContents._reloadIgnoringCache() # Rely on WebContents to clear cache.
@reload()
@pendingIndex = @currentIndex
@webContents._loadURL @getURL(), {extraHeaders: "pragma: no-cache\n"}
canGoBack: ->
@getActiveIndex() > 0
@ -89,7 +89,7 @@ class NavigationController
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
@webContents._goBack()
else
@webContents._loadUrl @history[@pendingIndex], {}
@webContents._loadURL @history[@pendingIndex], {}
goForward: ->
return unless @canGoForward()
@ -97,12 +97,12 @@ class NavigationController
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
@webContents._goForward()
else
@webContents._loadUrl @history[@pendingIndex], {}
@webContents._loadURL @history[@pendingIndex], {}
goToIndex: (index) ->
return unless @canGoToIndex index
@pendingIndex = index
@webContents._loadUrl @history[@pendingIndex], {}
@webContents._loadURL @history[@pendingIndex], {}
goToOffset: (offset) ->
return unless @canGoToOffset offset

View file

@ -1,5 +1,6 @@
powerMonitor = process.atomBinding('power_monitor').powerMonitor
EventEmitter = require('events').EventEmitter
{EventEmitter} = require 'events'
{powerMonitor} = process.atomBinding 'power_monitor'
powerMonitor.__proto__ = EventEmitter.prototype

View file

@ -1,3 +1,3 @@
bindings = process.atomBinding 'power_save_blocker'
{powerSaveBlocker} = process.atomBinding 'power_save_blocker'
module.exports = bindings.powerSaveBlocker
module.exports = powerSaveBlocker

View file

@ -1,7 +1,8 @@
app = require 'app'
{app} = require 'electron'
throw new Error('Can not initialize protocol module before app is ready') unless app.isReady()
protocol = process.atomBinding('protocol').protocol
{protocol} = process.atomBinding 'protocol'
# Warn about removed APIs.
logAndThrow = (callback, message) ->

View file

@ -1,6 +1,6 @@
EventEmitter = require('events').EventEmitter
{EventEmitter} = require 'events'
{screen} = process.atomBinding 'screen'
screen = process.atomBinding('screen').screen
screen.__proto__ = EventEmitter.prototype
module.exports = screen

View file

@ -0,0 +1,23 @@
{EventEmitter} = require 'events'
bindings = process.atomBinding 'session'
PERSIST_PERFIX = 'persist:'
# Returns the Session from |partition| string.
exports.fromPartition = (partition='') ->
if partition.startsWith PERSIST_PERFIX
bindings.fromPartition partition.substr(PERSIST_PERFIX.length), false
else
bindings.fromPartition partition, true
# Returns the default session.
Object.defineProperty exports, 'defaultSession',
enumerable: true
get: -> exports.fromPartition ''
wrapSession = (session) ->
# session is an EventEmitter.
session.__proto__ = EventEmitter.prototype
bindings._setWrapSession wrapSession

View file

@ -1,14 +1,19 @@
EventEmitter = require('events').EventEmitter
bindings = process.atomBinding 'tray'
{deprecate} = require 'electron'
{EventEmitter} = require 'events'
Tray = bindings.Tray
{Tray} = process.atomBinding 'tray'
Tray::__proto__ = EventEmitter.prototype
Tray::_init = ->
# Deprecated.
deprecate.rename this, 'popContextMenu', 'popUpContextMenu'
deprecate.event this, 'clicked', 'click'
deprecate.event this, 'double-clicked', 'double-click'
deprecate.event this, 'right-clicked', 'right-click'
deprecate.event this, 'balloon-clicked', 'balloon-click'
Tray::setContextMenu = (menu) ->
@_setContextMenu menu
@menu = menu # Keep a strong reference of menu.
# Keep compatibility with old APIs.
Tray::popContextMenu = Tray::popUpContextMenu
module.exports = Tray

View file

@ -1,7 +1,7 @@
EventEmitter = require('events').EventEmitter
NavigationController = require './navigation-controller'
{EventEmitter} = require 'events'
{deprecate, ipcMain, session, NavigationController, Menu} = require 'electron'
binding = process.atomBinding 'web_contents'
ipc = require 'ipc'
nextId = 0
getNextId = -> ++nextId
@ -45,7 +45,7 @@ wrapWebContents = (webContents) ->
# Make sure webContents.executeJavaScript would run the code only when the
# web contents has been loaded.
webContents.executeJavaScript = (code, hasUserGesture=false) ->
if @getUrl() and not @isLoading()
if @getURL() and not @isLoading()
@_executeJavaScript code, hasUserGesture
else
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
@ -59,11 +59,32 @@ wrapWebContents = (webContents) ->
# Dispatch IPC messages to the ipc module.
webContents.on 'ipc-message', (event, packed) ->
[channel, args...] = packed
ipc.emit channel, event, args...
ipcMain.emit channel, event, args...
webContents.on 'ipc-message-sync', (event, packed) ->
[channel, args...] = packed
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
ipc.emit channel, event, args...
ipcMain.emit channel, event, args...
# Handle context menu action request from pepper plugin.
webContents.on 'pepper-context-menu', (event, params) ->
menu = Menu.buildFromTemplate params.menu
menu.popup params.x, params.y
# This error occurs when host could not be found.
webContents.on 'did-fail-provisional-load', (args...) ->
# Calling loadURL during this event might cause crash, so delay the event
# until next tick.
setImmediate => @emit 'did-fail-load', args...
# Delays the page-title-updated event to next tick.
webContents.on '-page-title-updated', (args...) ->
setImmediate => @emit 'page-title-updated', args...
# Deprecated.
deprecate.rename webContents, 'loadUrl', 'loadURL'
deprecate.rename webContents, 'getUrl', 'getURL'
deprecate.event webContents, 'page-title-set', 'page-title-updated', (args...) ->
@emit 'page-title-set', args...
webContents.printToPDF = (options, callback) ->
printingSetting =
@ -106,7 +127,6 @@ wrapWebContents = (webContents) ->
@_printToPDF printingSetting, callback
binding._setWrapWebContents wrapWebContents
process.once 'exit', binding._clearWrapWebContents
module.exports.create = (options={}) ->
binding.create(options)

View file

@ -0,0 +1,83 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/save_page_handler.h"
#include <string>
#include "atom/browser/atom_browser_context.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "content/public/browser/web_contents.h"
namespace atom {
namespace api {
SavePageHandler::SavePageHandler(content::WebContents* web_contents,
const SavePageCallback& callback)
: web_contents_(web_contents),
callback_(callback) {
}
SavePageHandler::~SavePageHandler() {
}
void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) {
// OnDownloadCreated is invoked during WebContents::SavePage, so the |item|
// here is the one stated by WebContents::SavePage.
item->AddObserver(this);
}
bool SavePageHandler::Handle(const base::FilePath& full_path,
const content::SavePageType& save_type) {
auto download_manager = content::BrowserContext::GetDownloadManager(
web_contents_->GetBrowserContext());
download_manager->AddObserver(this);
// Chromium will create a 'foo_files' directory under the directory of saving
// page 'foo.html' for holding other resource files of 'foo.html'.
base::FilePath saved_main_directory_path = full_path.DirName().Append(
full_path.RemoveExtension().BaseName().value() +
FILE_PATH_LITERAL("_files"));
bool result = web_contents_->SavePage(full_path,
saved_main_directory_path,
save_type);
download_manager->RemoveObserver(this);
// If initialization fails which means fail to create |DownloadItem|, we need
// to delete the |SavePageHandler| instance to avoid memory-leak.
if (!result)
delete this;
return result;
}
void SavePageHandler::OnDownloadUpdated(content::DownloadItem* item) {
if (item->IsDone()) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (item->GetState() == content::DownloadItem::COMPLETE) {
callback_.Run(v8::Null(isolate));
} else {
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(
isolate, "Fail to save page");
callback_.Run(v8::Exception::Error(error_message));
}
Destroy(item);
}
}
void SavePageHandler::Destroy(content::DownloadItem* item) {
item->RemoveObserver(this);
delete this;
}
// static
bool SavePageHandler::IsSavePageTypes(const std::string& type) {
return type == "multipart/related" || type == "text/html";
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,60 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
#define ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
#include <string>
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/save_page_type.h"
#include "v8/include/v8.h"
namespace base {
class FilePath;
}
namespace content {
class WebContents;
}
namespace atom {
namespace api {
// A self-destroyed class for handling save page request.
class SavePageHandler : public content::DownloadManager::Observer,
public content::DownloadItem::Observer {
public:
using SavePageCallback = base::Callback<void(v8::Local<v8::Value>)>;
SavePageHandler(content::WebContents* web_contents,
const SavePageCallback& callback);
~SavePageHandler();
bool Handle(const base::FilePath& full_path,
const content::SavePageType& save_type);
static bool IsSavePageTypes(const std::string& type);
private:
void Destroy(content::DownloadItem* item);
// content::DownloadManager::Observer:
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override;
// content::DownloadItem::Observer:
void OnDownloadUpdated(content::DownloadItem* item) override;
content::WebContents* web_contents_; // weak
SavePageCallback callback_;
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_

View file

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

View file

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