Merge remote-tracking branch 'atom/master'

This commit is contained in:
Plusb Preco 2015-08-21 11:41:07 +09:00
commit ad24c11f32
171 changed files with 4032 additions and 968 deletions

View file

@ -22,3 +22,7 @@ matrix:
- env: TARGET_ARCH=ia32 - env: TARGET_ARCH=ia32
script: './script/cibuild' script: './script/cibuild'
branches:
only:
- master

View file

@ -2,8 +2,8 @@
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: :+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to uphold this code. This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
[code-of-conduct]: http://todogroup.org/opencodeofconduct/#Electron/opensource@github.com By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com.
The following is a set of guidelines for contributing to Electron. The following is a set of guidelines for contributing to Electron.
These are just guidelines, not rules, use your best judgment and feel free to These are just guidelines, not rules, use your best judgment and feel free to

View file

@ -14,8 +14,8 @@ editor](https://github.com/atom/atom).
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements. announcements.
This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to uphold this code. This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
[code-of-conduct]: http://todogroup.org/opencodeofconduct/#Electron/opensource@github.com By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com.
## Downloads ## Downloads

View file

@ -4,7 +4,7 @@
'product_name%': 'Electron', 'product_name%': 'Electron',
'company_name%': 'GitHub, Inc', 'company_name%': 'GitHub, Inc',
'company_abbr%': 'github', 'company_abbr%': 'github',
'version%': '0.29.2', 'version%': '0.30.4',
}, },
'includes': [ 'includes': [
'filenames.gypi', 'filenames.gypi',

View file

@ -17,6 +17,7 @@
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.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/file_path_converter.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/environment.h" #include "base/environment.h"
@ -25,7 +26,6 @@
#include "brightray/browser/brightray_paths.h" #include "brightray/browser/brightray_paths.h"
#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/gpu_data_manager.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_cert_request_info.h"

View file

@ -5,10 +5,11 @@
#include <set> #include <set>
#include <string> #include <string>
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_util.h"
#include "content/public/browser/tracing_controller.h" #include "content/public/browser/tracing_controller.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
@ -46,6 +47,31 @@ struct Converter<base::trace_event::TraceOptions> {
namespace { namespace {
using CompletionCallback = base::Callback<void(const base::FilePath&)>;
scoped_refptr<TracingController::TraceDataSink> GetTraceDataSink(
const base::FilePath& path, const CompletionCallback& callback) {
base::FilePath result_file_path = path;
if (result_file_path.empty() && !base::CreateTemporaryFile(&result_file_path))
LOG(ERROR) << "Creating temporary file failed";
return TracingController::CreateFileSink(result_file_path,
base::Bind(callback,
result_file_path));
}
void StopRecording(const base::FilePath& path,
const CompletionCallback& callback) {
TracingController::GetInstance()->DisableRecording(
GetTraceDataSink(path, callback));
}
void CaptureMonitoringSnapshot(const base::FilePath& path,
const CompletionCallback& callback) {
TracingController::GetInstance()->CaptureMonitoringSnapshot(
GetTraceDataSink(path, callback));
}
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused, void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) { v8::Local<v8::Context> context, void* priv) {
auto controller = base::Unretained(TracingController::GetInstance()); auto controller = base::Unretained(TracingController::GetInstance());
@ -54,14 +80,12 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
&TracingController::GetCategories, controller)); &TracingController::GetCategories, controller));
dict.SetMethod("startRecording", base::Bind( dict.SetMethod("startRecording", base::Bind(
&TracingController::EnableRecording, controller)); &TracingController::EnableRecording, controller));
dict.SetMethod("stopRecording", base::Bind( dict.SetMethod("stopRecording", &StopRecording);
&TracingController::DisableRecording, controller, nullptr));
dict.SetMethod("startMonitoring", base::Bind( dict.SetMethod("startMonitoring", base::Bind(
&TracingController::EnableMonitoring, controller)); &TracingController::EnableMonitoring, controller));
dict.SetMethod("stopMonitoring", base::Bind( dict.SetMethod("stopMonitoring", base::Bind(
&TracingController::DisableMonitoring, controller)); &TracingController::DisableMonitoring, controller));
dict.SetMethod("captureMonitoringSnapshot", base::Bind( dict.SetMethod("captureMonitoringSnapshot", &CaptureMonitoringSnapshot);
&TracingController::CaptureMonitoringSnapshot, controller, nullptr));
dict.SetMethod("getTraceBufferUsage", base::Bind( dict.SetMethod("getTraceBufferUsage", base::Bind(
&TracingController::GetTraceBufferUsage, controller)); &TracingController::GetTraceBufferUsage, controller));
dict.SetMethod("setWatchEvent", base::Bind( dict.SetMethod("setWatchEvent", base::Bind(

View file

@ -4,13 +4,14 @@
#include "atom/browser/api/atom_api_cookies.h" #include "atom/browser/api/atom_api_cookies.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/values.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/cookies/cookie_monster.h" #include "net/cookies/cookie_monster.h"
@ -179,8 +180,8 @@ namespace atom {
namespace api { namespace api {
Cookies::Cookies(content::BrowserContext* browser_context) : Cookies::Cookies(content::BrowserContext* browser_context)
browser_context_(browser_context) { : request_context_getter_(browser_context->GetRequestContext()) {
} }
Cookies::~Cookies() { Cookies::~Cookies() {
@ -198,11 +199,9 @@ void Cookies::Get(const base::DictionaryValue& options,
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter, void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
const CookiesCallback& callback) { const CookiesCallback& callback) {
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
std::string url; std::string url;
filter->GetString("url", &url); filter->GetString("url", &url);
if (!GetCookieListFromStore(cookie_store, url, if (!GetCookieListFromStore(GetCookieStore(), url,
base::Bind(&Cookies::OnGetCookies, base::Unretained(this), base::Bind(&Cookies::OnGetCookies, base::Unretained(this),
Passed(&filter), callback))) { Passed(&filter), callback))) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
@ -245,9 +244,7 @@ void Cookies::Remove(const mate::Dictionary& details,
void Cookies::RemoveCookiesOnIOThread(const GURL& url, const std::string& name, void Cookies::RemoveCookiesOnIOThread(const GURL& url, const std::string& name,
const CookiesCallback& callback) { const CookiesCallback& callback) {
net::CookieStore* cookie_store = browser_context_->GetRequestContext() GetCookieStore()->DeleteCookieAsync(url, name,
->GetURLRequestContext()->cookie_store();
cookie_store->DeleteCookieAsync(url, name,
base::Bind(&Cookies::OnRemoveCookies, base::Unretained(this), callback)); base::Bind(&Cookies::OnRemoveCookies, base::Unretained(this), callback));
} }
@ -286,8 +283,6 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
const GURL& url, const GURL& url,
const CookiesCallback& callback) { const CookiesCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
std::string name, value, domain, path; std::string name, value, domain, path;
bool secure = false; bool secure = false;
@ -308,7 +303,7 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
base::Time::FromDoubleT(expiration_date); base::Time::FromDoubleT(expiration_date);
} }
cookie_store->GetCookieMonster()->SetCookieWithDetailsAsync( GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
url, url,
name, name,
value, value,
@ -337,6 +332,10 @@ mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
.SetMethod("set", &Cookies::Set); .SetMethod("set", &Cookies::Set);
} }
net::CookieStore* Cookies::GetCookieStore() {
return request_context_getter_->GetURLRequestContext()->cookie_store();
}
// static // static
mate::Handle<Cookies> Cookies::Create( mate::Handle<Cookies> Cookies::Create(
v8::Isolate* isolate, v8::Isolate* isolate,

View file

@ -8,17 +8,27 @@
#include <string> #include <string>
#include "base/callback.h" #include "base/callback.h"
#include "base/values.h"
#include "native_mate/wrappable.h" #include "native_mate/wrappable.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "native_mate/dictionary.h"
#include "net/cookies/canonical_cookie.h" #include "net/cookies/canonical_cookie.h"
namespace base {
class DictionaryValue;
}
namespace content { namespace content {
class BrowserContext; class BrowserContext;
} }
namespace mate {
class Dictionary;
}
namespace net {
class CookieStore;
class URLRequestContextGetter;
}
namespace atom { namespace atom {
namespace api { namespace api {
@ -60,13 +70,15 @@ class Cookies : public mate::Wrappable {
void OnSetCookies(const CookiesCallback& callback, void OnSetCookies(const CookiesCallback& callback,
bool set_success); bool set_success);
// mate::Wrappable:
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override; v8::Isolate* isolate) override;
private: private:
content::BrowserContext* browser_context_; // Must be called on IO thread.
net::CookieStore* GetCookieStore();
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
DISALLOW_COPY_AND_ASSIGN(Cookies); DISALLOW_COPY_AND_ASSIGN(Cookies);
}; };

View file

@ -10,9 +10,9 @@
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/file_dialog.h"
#include "atom/browser/ui/message_box.h" #include "atom/browser/ui/message_box.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/file_path_converter.h"
#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/image_converter.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
@ -42,28 +42,24 @@ namespace {
void ShowMessageBox(int type, void ShowMessageBox(int type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
const std::vector<std::string>& texts, int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
atom::NativeWindow* window, atom::NativeWindow* window,
mate::Arguments* args) { mate::Arguments* args) {
// FIXME We are exceeding the parameters limit of base::Bind here, so we have
// to pass some parameters in an array. We should remove this once we have
// variadic template support in base::Bind.
const std::string& title = texts[0];
const std::string& message = texts[1];
const std::string& detail = texts[2];
v8::Local<v8::Value> peek = args->PeekNext(); v8::Local<v8::Value> peek = args->PeekNext();
atom::MessageBoxCallback callback; atom::MessageBoxCallback callback;
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(), if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
peek, peek,
&callback)) { &callback)) {
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id, atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id,
title, message, detail, icon, callback); options, title, message, detail, icon, callback);
} else { } else {
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
buttons, cancel_id, title, message, buttons, cancel_id, options, title,
detail, icon); message, detail, icon);
args->Return(chosen); args->Return(chosen);
} }
} }

View file

@ -7,8 +7,8 @@
#include <string> #include <string>
#include "atom/common/native_mate_converters/accelerator_converter.h" #include "atom/common/native_mate_converters/accelerator_converter.h"
#include "atom/common/native_mate_converters/callback.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"

View file

@ -6,9 +6,9 @@
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/common/native_mate_converters/accelerator_converter.h" #include "atom/common/native_mate_converters/accelerator_converter.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/callback.h"
#include "native_mate/constructor.h" #include "native_mate/constructor.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
@ -20,7 +20,7 @@ namespace atom {
namespace api { namespace api {
Menu::Menu() Menu::Menu()
: model_(new ui::SimpleMenuModel(this)), : model_(new AtomMenuModel(this)),
parent_(NULL) { parent_(NULL) {
} }

View file

@ -8,9 +8,9 @@
#include <string> #include <string>
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "ui/base/models/simple_menu_model.h"
#include "native_mate/wrappable.h" #include "native_mate/wrappable.h"
namespace atom { namespace atom {
@ -18,7 +18,7 @@ namespace atom {
namespace api { namespace api {
class Menu : public mate::Wrappable, class Menu : public mate::Wrappable,
public ui::SimpleMenuModel::Delegate { public AtomMenuModel::Delegate {
public: public:
static mate::Wrappable* Create(); static mate::Wrappable* Create();
@ -33,7 +33,7 @@ class Menu : public mate::Wrappable,
static void SendActionToFirstResponder(const std::string& action); static void SendActionToFirstResponder(const std::string& action);
#endif #endif
ui::SimpleMenuModel* model() const { return model_.get(); } AtomMenuModel* model() const { return model_.get(); }
protected: protected:
Menu(); Menu();
@ -42,7 +42,7 @@ class Menu : public mate::Wrappable,
// mate::Wrappable: // mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override; void AfterInit(v8::Isolate* isolate) override;
// ui::SimpleMenuModel::Delegate implementations: // ui::SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override; bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override; bool IsCommandIdEnabled(int command_id) const override;
bool IsCommandIdVisible(int command_id) const override; bool IsCommandIdVisible(int command_id) const override;
@ -54,7 +54,7 @@ class Menu : public mate::Wrappable,
virtual void Popup(Window* window) = 0; virtual void Popup(Window* window) = 0;
virtual void PopupAt(Window* window, int x, int y) = 0; virtual void PopupAt(Window* window, int x, int y) = 0;
scoped_ptr<ui::SimpleMenuModel> model_; scoped_ptr<AtomMenuModel> model_;
Menu* parent_; Menu* parent_;
private: private:
@ -102,9 +102,9 @@ class Menu : public mate::Wrappable,
namespace mate { namespace mate {
template<> template<>
struct Converter<ui::SimpleMenuModel*> { struct Converter<atom::AtomMenuModel*> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val, static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
ui::SimpleMenuModel** out) { atom::AtomMenuModel** out) {
// null would be tranfered to NULL. // null would be tranfered to NULL.
if (val->IsNull()) { if (val->IsNull()) {
*out = nullptr; *out = nullptr;

View file

@ -7,12 +7,13 @@
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/net/adapter_request_job.h" #include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/net/atom_url_request_job_factory.h" #include "atom/browser/net/atom_url_request_job_factory.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/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
@ -62,16 +63,13 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
registry_(registry) { registry_(registry) {
} }
// AdapterRequestJob: void GetJobTypeInUI(const Protocol::JsProtocolHandler& callback) {
void GetJobTypeInUI() override {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Locker locker(registry_->isolate()); v8::Locker locker(registry_->isolate());
v8::HandleScope handle_scope(registry_->isolate()); v8::HandleScope handle_scope(registry_->isolate());
// Call the JS handler. // Call the JS handler.
Protocol::JsProtocolHandler callback =
registry_->GetProtocolHandler(request()->url().scheme());
v8::Local<v8::Value> result = callback.Run(request()); v8::Local<v8::Value> result = callback.Run(request());
// Determine the type of the job we are going to create. // Determine the type of the job we are going to create.
@ -130,9 +128,23 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
dict.Get("method", &method); dict.Get("method", &method);
dict.Get("referrer", &referrer); dict.Get("referrer", &referrer);
v8::Local<v8::Value> value;
mate::Handle<Session> session;
scoped_refptr<net::URLRequestContextGetter> request_context_getter;
// "session" null -> pass nullptr;
// "session" a Session object -> use passed session.
// "session" undefined -> use current session;
if (dict.Get("session", &session))
request_context_getter =
session->browser_context()->GetRequestContext();
else if (dict.Get("session", &value) && value->IsNull())
request_context_getter = nullptr;
else
request_context_getter = registry_->request_context_getter();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(), base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
registry_->browser_context(), url, method, referrer)); request_context_getter, url, method, referrer));
return; return;
} }
} }
@ -151,6 +163,14 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
GetWeakPtr(), net::ERR_NOT_IMPLEMENTED)); GetWeakPtr(), net::ERR_NOT_IMPLEMENTED));
} }
// AdapterRequestJob:
void GetJobType() override {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&CustomProtocolRequestJob::GetJobTypeInUI,
base::Unretained(this),
registry_->GetProtocolHandler(request()->url().scheme())));
}
private: private:
Protocol* registry_; // Weak, the Protocol class is expected to live forever. Protocol* registry_; // Weak, the Protocol class is expected to live forever.
}; };
@ -211,7 +231,7 @@ std::string ConvertErrorCode(int error_code) {
} // namespace } // namespace
Protocol::Protocol(AtomBrowserContext* browser_context) Protocol::Protocol(AtomBrowserContext* browser_context)
: browser_context_(browser_context), : request_context_getter_(browser_context->GetRequestContext()),
job_factory_(browser_context->job_factory()) { job_factory_(browser_context->job_factory()) {
CHECK(job_factory_); CHECK(job_factory_);
} }
@ -335,6 +355,10 @@ int Protocol::InterceptProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler) { const JsProtocolHandler& handler) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Force the request context to initialize, otherwise we might have nothing
// to intercept.
request_context_getter_->GetURLRequestContext();
if (!job_factory_->HasProtocolHandler(scheme)) if (!job_factory_->HasProtocolHandler(scheme))
return ERR_NO_SCHEME; return ERR_NO_SCHEME;

View file

@ -16,6 +16,7 @@
namespace net { namespace net {
class URLRequest; class URLRequest;
class URLRequestContextGetter;
} }
namespace atom { namespace atom {
@ -46,7 +47,9 @@ class Protocol : public mate::EventEmitter {
JsProtocolHandler GetProtocolHandler(const std::string& scheme); JsProtocolHandler GetProtocolHandler(const std::string& scheme);
AtomBrowserContext* browser_context() const { return browser_context_; } net::URLRequestContextGetter* request_context_getter() {
return request_context_getter_.get();
}
protected: protected:
explicit Protocol(AtomBrowserContext* browser_context); explicit Protocol(AtomBrowserContext* browser_context);
@ -94,7 +97,8 @@ class Protocol : public mate::EventEmitter {
const JsProtocolHandler& handler); const JsProtocolHandler& handler);
int UninterceptProtocolInIO(const std::string& scheme); int UninterceptProtocolInIO(const std::string& scheme);
AtomBrowserContext* browser_context_; scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
AtomURLRequestJobFactory* job_factory_; AtomURLRequestJobFactory* job_factory_;
ProtocolHandlersMap protocol_handlers_; ProtocolHandlersMap protocol_handlers_;

View file

@ -9,16 +9,22 @@
#include "atom/browser/api/atom_api_cookies.h" #include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "base/thread_task_runner_handle.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "native_mate/callback.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/disk_cache/disk_cache.h" #include "net/disk_cache/disk_cache.h"
#include "net/proxy/proxy_service.h" #include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_context_getter.h"
@ -157,9 +163,10 @@ class ResolveProxyHelper {
}; };
// Runs the callback in UI thread. // Runs the callback in UI thread.
void RunCallbackInUI(const net::CompletionCallback& callback, int result) { template <typename ...T>
void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(callback, result)); BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
} }
// Callback of HttpCache::GetBackend. // Callback of HttpCache::GetBackend.
@ -169,19 +176,19 @@ void OnGetBackend(disk_cache::Backend** backend_ptr,
if (result != net::OK) { if (result != net::OK) {
RunCallbackInUI(callback, result); RunCallbackInUI(callback, result);
} else if (backend_ptr && *backend_ptr) { } else if (backend_ptr && *backend_ptr) {
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI, callback)); (*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>, callback));
} else { } else {
RunCallbackInUI(callback, net::ERR_FAILED); RunCallbackInUI<int>(callback, net::ERR_FAILED);
} }
} }
void ClearHttpCacheInIO(content::BrowserContext* browser_context, void ClearHttpCacheInIO(
const net::CompletionCallback& callback) { const scoped_refptr<net::URLRequestContextGetter>& context_getter,
auto request_context = const net::CompletionCallback& callback) {
browser_context->GetRequestContext()->GetURLRequestContext(); auto request_context = context_getter->GetURLRequestContext();
auto http_cache = request_context->http_transaction_factory()->GetCache(); auto http_cache = request_context->http_transaction_factory()->GetCache();
if (!http_cache) if (!http_cache)
RunCallbackInUI(callback, net::ERR_FAILED); RunCallbackInUI<int>(callback, net::ERR_FAILED);
// Call GetBackend and make the backend's ptr accessable in OnGetBackend. // Call GetBackend and make the backend's ptr accessable in OnGetBackend.
using BackendPtr = disk_cache::Backend*; using BackendPtr = disk_cache::Backend*;
@ -193,6 +200,16 @@ void ClearHttpCacheInIO(content::BrowserContext* browser_context,
on_get_backend.Run(net::OK); on_get_backend.Run(net::OK);
} }
void SetProxyInIO(net::URLRequestContextGetter* getter,
const std::string& proxy,
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));
RunCallbackInUI(callback);
}
} // namespace } // namespace
Session::Session(AtomBrowserContext* browser_context) Session::Session(AtomBrowserContext* browser_context)
@ -210,7 +227,7 @@ void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
void Session::ClearCache(const net::CompletionCallback& callback) { void Session::ClearCache(const net::CompletionCallback& callback) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&ClearHttpCacheInIO, base::Bind(&ClearHttpCacheInIO,
base::Unretained(browser_context_), make_scoped_refptr(browser_context_->GetRequestContext()),
callback)); callback));
} }
@ -232,6 +249,18 @@ void Session::ClearStorageData(mate::Arguments* args) {
base::Time(), base::Time::Max(), callback); base::Time(), base::Time::Max(), callback);
} }
void Session::SetProxy(const std::string& proxy,
const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
}
void Session::SetDownloadPath(const base::FilePath& path) {
browser_context_->prefs()->SetFilePath(
prefs::kDownloadDefaultDirectory, path);
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) { v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) { if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context_); auto handle = atom::api::Cookies::Create(isolate, browser_context_);
@ -246,6 +275,8 @@ mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
.SetMethod("resolveProxy", &Session::ResolveProxy) .SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache) .SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData) .SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetProperty("cookies", &Session::Cookies); .SetProperty("cookies", &Session::Cookies);
} }

View file

@ -13,6 +13,10 @@
class GURL; class GURL;
namespace base {
class FilePath;
}
namespace mate { namespace mate {
class Arguments; class Arguments;
} }
@ -31,6 +35,8 @@ class Session: public mate::TrackableObject<Session> {
static mate::Handle<Session> CreateFrom( static mate::Handle<Session> CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context); v8::Isolate* isolate, AtomBrowserContext* browser_context);
AtomBrowserContext* browser_context() const { return browser_context_; }
protected: protected:
explicit Session(AtomBrowserContext* browser_context); explicit Session(AtomBrowserContext* browser_context);
~Session(); ~Session();
@ -43,6 +49,8 @@ class Session: public mate::TrackableObject<Session> {
void ResolveProxy(const GURL& url, ResolveProxyCallback callback); void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback); void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args); void ClearStorageData(mate::Arguments* args);
void SetProxy(const std::string& proxy, const base::Closure& callback);
void SetDownloadPath(const base::FilePath& path);
v8::Local<v8::Value> Cookies(v8::Isolate* isolate); v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
v8::Global<v8::Value> cookies_; v8::Global<v8::Value> cookies_;

View file

@ -14,6 +14,7 @@
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/constructor.h" #include "native_mate/constructor.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
@ -40,12 +41,25 @@ mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
return new Tray(image); return new Tray(image);
} }
void Tray::OnClicked(const gfx::Rect& bounds) { void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
Emit("clicked", bounds); v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("clicked",
ModifiersToObject(isolate(), modifiers), bounds);
} }
void Tray::OnDoubleClicked() { void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
Emit("double-clicked"); v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("double-clicked",
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",
ModifiersToObject(isolate(), modifiers), bounds);
} }
void Tray::OnBalloonShow() { void Tray::OnBalloonShow() {
@ -60,6 +74,10 @@ void Tray::OnBalloonClosed() {
Emit("balloon-closed"); Emit("balloon-closed");
} }
void Tray::OnDropFiles(const std::vector<std::string>& files) {
Emit("drop-files", files);
}
bool Tray::IsDestroyed() const { bool Tray::IsDestroyed() const {
return !tray_icon_; return !tray_icon_;
} }
@ -102,10 +120,26 @@ void Tray::DisplayBalloon(mate::Arguments* args,
tray_icon_->DisplayBalloon(icon, title, content); tray_icon_->DisplayBalloon(icon, title, content);
} }
void Tray::PopUpContextMenu(mate::Arguments* args) {
gfx::Point pos;
args->GetNext(&pos);
tray_icon_->PopUpContextMenu(pos);
}
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) { void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
tray_icon_->SetContextMenu(menu->model()); tray_icon_->SetContextMenu(menu->model());
} }
v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
int modifiers) {
mate::Dictionary obj(isolate, v8::Object::New(isolate));
obj.Set("shiftKey", static_cast<bool>(modifiers & ui::EF_SHIFT_DOWN));
obj.Set("ctrlKey", static_cast<bool>(modifiers & ui::EF_CONTROL_DOWN));
obj.Set("altKey", static_cast<bool>(modifiers & ui::EF_ALT_DOWN));
obj.Set("metaKey", static_cast<bool>(modifiers & ui::EF_COMMAND_DOWN));
return obj.GetHandle();
}
// static // static
void Tray::BuildPrototype(v8::Isolate* isolate, void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
@ -117,6 +151,7 @@ void Tray::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setTitle", &Tray::SetTitle) .SetMethod("setTitle", &Tray::SetTitle)
.SetMethod("setHighlightMode", &Tray::SetHighlightMode) .SetMethod("setHighlightMode", &Tray::SetHighlightMode)
.SetMethod("displayBalloon", &Tray::DisplayBalloon) .SetMethod("displayBalloon", &Tray::DisplayBalloon)
.SetMethod("popUpContextMenu", &Tray::PopUpContextMenu)
.SetMethod("_setContextMenu", &Tray::SetContextMenu); .SetMethod("_setContextMenu", &Tray::SetContextMenu);
} }

View file

@ -6,6 +6,7 @@
#define ATOM_BROWSER_API_ATOM_API_TRAY_H_ #define ATOM_BROWSER_API_ATOM_API_TRAY_H_
#include <string> #include <string>
#include <vector>
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/event_emitter.h"
#include "atom/browser/ui/tray_icon_observer.h" #include "atom/browser/ui/tray_icon_observer.h"
@ -41,11 +42,13 @@ class Tray : public mate::EventEmitter,
virtual ~Tray(); virtual ~Tray();
// TrayIconObserver: // TrayIconObserver:
void OnClicked(const gfx::Rect&) override; void OnClicked(const gfx::Rect& bounds, int modifiers) override;
void OnDoubleClicked() override; void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
void OnBalloonShow() override; void OnBalloonShow() override;
void OnBalloonClicked() override; void OnBalloonClicked() override;
void OnBalloonClosed() override; void OnBalloonClosed() override;
void OnDropFiles(const std::vector<std::string>& files) override;
// mate::Wrappable: // mate::Wrappable:
bool IsDestroyed() const override; bool IsDestroyed() const override;
@ -57,9 +60,12 @@ class Tray : public mate::EventEmitter,
void SetTitle(mate::Arguments* args, const std::string& title); void SetTitle(mate::Arguments* args, const std::string& title);
void SetHighlightMode(mate::Arguments* args, bool highlight); void SetHighlightMode(mate::Arguments* args, bool highlight);
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options); void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
void PopUpContextMenu(mate::Arguments* args);
void SetContextMenu(mate::Arguments* args, Menu* menu); void SetContextMenu(mate::Arguments* args, Menu* menu);
private: private:
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
scoped_ptr<TrayIcon> tray_icon_; scoped_ptr<TrayIcon> tray_icon_;
DISALLOW_COPY_AND_ASSIGN(Tray); DISALLOW_COPY_AND_ASSIGN(Tray);

View file

@ -13,7 +13,9 @@
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/web_view_guest_delegate.h" #include "atom/browser/web_view_guest_delegate.h"
#include "atom/common/api/api_messages.h" #include "atom/common/api/api_messages.h"
#include "atom/common/event_emitter_caller.h" #include "atom/common/api/event_emitter_caller.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/gfx_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/image_converter.h"
@ -36,7 +38,6 @@
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "content/public/browser/site_instance.h" #include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/http/http_response_headers.h" #include "net/http/http_response_headers.h"
@ -563,12 +564,17 @@ void WebContents::SetUserAgent(const std::string& user_agent) {
base::Bind(&SetUserAgentInIO, getter, user_agent)); base::Bind(&SetUserAgentInIO, getter, user_agent));
} }
std::string WebContents::GetUserAgent() {
return web_contents()->GetUserAgentOverride();
}
void WebContents::InsertCSS(const std::string& css) { void WebContents::InsertCSS(const std::string& css) {
web_contents()->InsertCSS(css); web_contents()->InsertCSS(css);
} }
void WebContents::ExecuteJavaScript(const base::string16& code) { void WebContents::ExecuteJavaScript(const base::string16& code,
web_contents()->GetMainFrame()->ExecuteJavaScript(code); bool has_user_gesture) {
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
} }
void WebContents::OpenDevTools(mate::Arguments* args) { void WebContents::OpenDevTools(mate::Arguments* args) {
@ -685,6 +691,22 @@ void WebContents::PrintToPDF(const base::DictionaryValue& setting,
PrintToPDF(setting, callback); PrintToPDF(setting, callback);
} }
void WebContents::AddWorkSpace(const base::FilePath& path) {
if (path.empty()) {
node::ThrowError(isolate(), "path cannot be empty");
return;
}
DevToolsAddFileSystem(path);
}
void WebContents::RemoveWorkSpace(const base::FilePath& path) {
if (path.empty()) {
node::ThrowError(isolate(), "path cannot be empty");
return;
}
DevToolsRemoveFileSystem(path);
}
void WebContents::Undo() { void WebContents::Undo() {
web_contents()->Undo(); web_contents()->Undo();
} }
@ -729,6 +751,14 @@ void WebContents::ReplaceMisspelling(const base::string16& word) {
web_contents()->ReplaceMisspelling(word); web_contents()->ReplaceMisspelling(word);
} }
void WebContents::Focus() {
web_contents()->Focus();
}
void WebContents::TabTraverse(bool reverse) {
web_contents()->FocusThroughTabTraversal(reverse);
}
bool WebContents::SendIPCMessage(const base::string16& channel, bool WebContents::SendIPCMessage(const base::string16& channel,
const base::ListValue& args) { const base::ListValue& args) {
return Send(new AtomViewMsg_Message(routing_id(), channel, args)); return Send(new AtomViewMsg_Message(routing_id(), channel, args));
@ -767,6 +797,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("_goToOffset", &WebContents::GoToOffset) .SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed) .SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("setUserAgent", &WebContents::SetUserAgent) .SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS) .SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript) .SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools) .SetMethod("openDevTools", &WebContents::OpenDevTools)
@ -787,6 +818,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("unselect", &WebContents::Unselect) .SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace) .SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling) .SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage, true) .SetMethod("_send", &WebContents::SendIPCMessage, true)
.SetMethod("setSize", &WebContents::SetSize) .SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency) .SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
@ -797,6 +830,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker) .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print) .SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF) .SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session) .SetProperty("session", &WebContents::Session)
.Build()); .Build());

View file

@ -37,8 +37,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
public content::WebContentsObserver { public content::WebContentsObserver {
public: public:
// For node.js callback function type: function(error, buffer) // For node.js callback function type: function(error, buffer)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)> using PrintToPDFCallback =
PrintToPDFCallback; base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
// Create from an existing WebContents. // Create from an existing WebContents.
static mate::Handle<WebContents> CreateFrom( static mate::Handle<WebContents> CreateFrom(
@ -63,8 +63,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
void GoToOffset(int offset); void GoToOffset(int offset);
bool IsCrashed() const; bool IsCrashed() const;
void SetUserAgent(const std::string& user_agent); void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent();
void InsertCSS(const std::string& css); void InsertCSS(const std::string& css);
void ExecuteJavaScript(const base::string16& code); void ExecuteJavaScript(const base::string16& code,
bool has_user_gesture);
void OpenDevTools(mate::Arguments* args); void OpenDevTools(mate::Arguments* args);
void CloseDevTools(); void CloseDevTools();
bool IsDevToolsOpened(); bool IsDevToolsOpened();
@ -82,6 +84,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
void PrintToPDF(const base::DictionaryValue& setting, void PrintToPDF(const base::DictionaryValue& setting,
const PrintToPDFCallback& callback); const PrintToPDFCallback& callback);
// DevTools workspace api.
void AddWorkSpace(const base::FilePath& path);
void RemoveWorkSpace(const base::FilePath& path);
// Editing commands. // Editing commands.
void Undo(); void Undo();
void Redo(); void Redo();
@ -95,6 +101,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
void Replace(const base::string16& word); void Replace(const base::string16& word);
void ReplaceMisspelling(const base::string16& word); void ReplaceMisspelling(const base::string16& word);
// Focus.
void Focus();
void TabTraverse(bool reverse);
// Sending messages to browser. // Sending messages to browser.
bool SendIPCMessage(const base::string16& channel, bool SendIPCMessage(const base::string16& channel,
const base::ListValue& args); const base::ListValue& args);

View file

@ -8,18 +8,43 @@
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "native_mate/callback.h"
#include "native_mate/constructor.h" #include "native_mate/constructor.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#if defined(OS_WIN)
#include "atom/browser/native_window_views.h"
#include "atom/browser/ui/win/taskbar_host.h"
#endif
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#if defined(OS_WIN)
namespace mate {
template<>
struct Converter<atom::TaskbarHost::ThumbarButton> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
atom::TaskbarHost::ThumbarButton* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("click", &(out->clicked_callback));
dict.Get("tooltip", &(out->tooltip));
dict.Get("flags", &out->flags);
return dict.Get("icon", &(out->icon));
}
};
} // namespace mate
#endif
namespace atom { namespace atom {
namespace api { namespace api {
@ -413,6 +438,21 @@ void Window::SetOverlayIcon(const gfx::Image& overlay,
window_->SetOverlayIcon(overlay, description); window_->SetOverlayIcon(overlay, description);
} }
bool Window::SetThumbarButtons(mate::Arguments* args) {
#if defined(OS_WIN)
std::vector<TaskbarHost::ThumbarButton> buttons;
if (!args->GetNext(&buttons)) {
args->ThrowError();
return false;
}
auto window = static_cast<NativeWindowViews*>(window_.get());
return window->taskbar_host().SetThumbarButtons(
window->GetAcceleratedWidget(), buttons);
#else
return false;
#endif
}
void Window::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) { void Window::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
mate::Handle<Menu> menu; mate::Handle<Menu> menu;
if (value->IsObject() && if (value->IsObject() &&
@ -451,6 +491,12 @@ void Window::ShowDefinitionForSelection() {
} }
#endif #endif
void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) {
gfx::Size extra_size;
args->GetNext(&extra_size);
window_->SetAspectRatio(aspect_ratio, extra_size);
}
void Window::SetVisibleOnAllWorkspaces(bool visible) { void Window::SetVisibleOnAllWorkspaces(bool visible) {
return window_->SetVisibleOnAllWorkspaces(visible); return window_->SetVisibleOnAllWorkspaces(visible);
} }
@ -498,6 +544,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("isMinimized", &Window::IsMinimized) .SetMethod("isMinimized", &Window::IsMinimized)
.SetMethod("setFullScreen", &Window::SetFullScreen) .SetMethod("setFullScreen", &Window::SetFullScreen)
.SetMethod("isFullScreen", &Window::IsFullscreen) .SetMethod("isFullScreen", &Window::IsFullscreen)
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
.SetMethod("getBounds", &Window::GetBounds) .SetMethod("getBounds", &Window::GetBounds)
.SetMethod("setBounds", &Window::SetBounds) .SetMethod("setBounds", &Window::SetBounds)
.SetMethod("getSize", &Window::GetSize) .SetMethod("getSize", &Window::GetSize)
@ -531,6 +578,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("capturePage", &Window::CapturePage) .SetMethod("capturePage", &Window::CapturePage)
.SetMethod("setProgressBar", &Window::SetProgressBar) .SetMethod("setProgressBar", &Window::SetProgressBar)
.SetMethod("setOverlayIcon", &Window::SetOverlayIcon) .SetMethod("setOverlayIcon", &Window::SetOverlayIcon)
.SetMethod("setThumbarButtons", &Window::SetThumbarButtons)
.SetMethod("setMenu", &Window::SetMenu) .SetMethod("setMenu", &Window::SetMenu)
.SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar) .SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar)
.SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide) .SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide)

View file

@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "atom/browser/api/trackable_object.h" #include "atom/browser/api/trackable_object.h"
#include "atom/browser/native_window.h"
#include "atom/browser/native_window_observer.h" #include "atom/browser/native_window_observer.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
@ -129,11 +130,13 @@ class Window : public mate::TrackableObject<Window>,
void SetProgressBar(double progress); void SetProgressBar(double progress);
void SetOverlayIcon(const gfx::Image& overlay, void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description); const std::string& description);
bool SetThumbarButtons(mate::Arguments* args);
void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu); void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu);
void SetAutoHideMenuBar(bool auto_hide); void SetAutoHideMenuBar(bool auto_hide);
bool IsMenuBarAutoHide(); bool IsMenuBarAutoHide();
void SetMenuBarVisibility(bool visible); void SetMenuBarVisibility(bool visible);
bool IsMenuBarVisible(); bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void ShowDefinitionForSelection(); void ShowDefinitionForSelection();

View file

@ -37,9 +37,8 @@ v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
EventEmitter::EventEmitter() { EventEmitter::EventEmitter() {
} }
v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate, v8::Local<v8::Object> EventEmitter::CreateJSEvent(
content::WebContents* sender, v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
IPC::Message* message) {
v8::Local<v8::Object> event; v8::Local<v8::Object> event;
bool use_native_event = sender && message; bool use_native_event = sender && message;
@ -54,4 +53,12 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
return event; return event;
} }
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
v8::Local<v8::Object> event = CreateEventObject(isolate);
event->SetPrototype(custom_event->CreationContext(), custom_event);
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
return event;
}
} // namespace mate } // namespace mate

View file

@ -7,7 +7,7 @@
#include <vector> #include <vector>
#include "atom/common/event_emitter_caller.h" #include "atom/common/api/event_emitter_caller.h"
#include "native_mate/wrappable.h" #include "native_mate/wrappable.h"
namespace content { namespace content {
@ -25,6 +25,14 @@ class EventEmitter : public Wrappable {
public: public:
typedef std::vector<v8::Local<v8::Value>> ValueArray; typedef std::vector<v8::Local<v8::Value>> ValueArray;
// this.emit(name, event, args...);
template<typename... Args>
bool EmitCustomEvent(const base::StringPiece& name,
v8::Local<v8::Object> event,
const Args&... args) {
return EmitWithEvent(name, CreateCustomEvent(isolate(), event), args...);
}
// this.emit(name, new Event(), args...); // this.emit(name, new Event(), args...);
template<typename... Args> template<typename... Args>
bool Emit(const base::StringPiece& name, const Args&... args) { bool Emit(const base::StringPiece& name, const Args&... args) {
@ -37,21 +45,31 @@ class EventEmitter : public Wrappable {
content::WebContents* sender, content::WebContents* sender,
IPC::Message* message, IPC::Message* message,
const Args&... args) { const Args&... args) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message); v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...); return EmitWithEvent(name, event, args...);
return event->Get(
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
} }
protected: protected:
EventEmitter(); EventEmitter();
private: private:
// this.emit(name, event, args...);
template<typename... Args>
bool EmitWithEvent(const base::StringPiece& name,
v8::Local<v8::Object> event,
const Args&... args) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
return event->Get(
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
}
v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate, v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
content::WebContents* sender, content::WebContents* sender,
IPC::Message* message); IPC::Message* message);
v8::Local<v8::Object> CreateCustomEvent(
v8::Isolate* isolate, v8::Local<v8::Object> event);
DISALLOW_COPY_AND_ASSIGN(EventEmitter); DISALLOW_COPY_AND_ASSIGN(EventEmitter);
}; };

View file

@ -30,6 +30,15 @@ BrowserWindow::_init = ->
@webContents.on 'crashed', => @webContents.on 'crashed', =>
@emit 'crashed' @emit 'crashed'
# 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,
# if we do it later we might move focus in the page.
# Though this hack is only needed on OS X when the app is launched from
# Finder, we still do it on all platforms in case of other bugs we don't know.
@webContents.once 'load-url', ->
@focus()
# Redirect focus/blur event to app instance too. # Redirect focus/blur event to app instance too.
@on 'blur', (event) => @on 'blur', (event) =>
app.emit 'browser-window-blur', event, this app.emit 'browser-window-blur', event, this

View file

@ -1,7 +1 @@
module.exports = process.atomBinding 'content_tracing' module.exports = process.atomBinding 'content_tracing'
# Mirrored from content::TracingController::Options
module.exports.DEFAULT_OPTIONS = 0
module.exports.ENABLE_SYSTRACE = 1 << 0
module.exports.ENABLE_SAMPLING = 1 << 1
module.exports.RECORD_CONTINUOUSLY = 1 << 2

View file

@ -11,6 +11,9 @@ fileDialogProperties =
messageBoxTypes = ['none', 'info', 'warning', 'error', 'question'] messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']
messageBoxOptions =
noLink: 1 << 0
parseArgs = (window, options, callback) -> parseArgs = (window, options, callback) ->
unless window is null or window?.constructor is BrowserWindow unless window is null or window?.constructor is BrowserWindow
# Shift. # Shift.
@ -101,10 +104,15 @@ module.exports =
options.cancelId = i options.cancelId = i
break break
flags = if options.noLink then messageBoxOptions.noLink else 0
binding.showMessageBox messageBoxType, binding.showMessageBox messageBoxType,
options.buttons, options.buttons,
options.cancelId, options.cancelId,
[options.title, options.message, options.detail], flags,
options.title,
options.message,
options.detail,
options.icon, options.icon,
window, window,
callback callback

View file

@ -40,6 +40,7 @@ class NavigationController
loadUrl: (url, options={}) -> loadUrl: (url, options={}) ->
@pendingIndex = -1 @pendingIndex = -1
@webContents._loadUrl url, options @webContents._loadUrl url, options
@webContents.emit 'load-url', url, options
getUrl: -> getUrl: ->
if @currentIndex is -1 if @currentIndex is -1

View file

@ -59,6 +59,6 @@ class RequestErrorJob
protocol.RequestHttpJob = protocol.RequestHttpJob =
class RequestHttpJob class RequestHttpJob
constructor: ({@url, @method, @referrer}) -> constructor: ({@session, @url, @method, @referrer}) ->
module.exports = protocol module.exports = protocol

View file

@ -3,8 +3,12 @@ bindings = process.atomBinding 'tray'
Tray = bindings.Tray Tray = bindings.Tray
Tray::__proto__ = EventEmitter.prototype Tray::__proto__ = EventEmitter.prototype
Tray::setContextMenu = (menu) -> Tray::setContextMenu = (menu) ->
@_setContextMenu menu @_setContextMenu menu
@menu = menu # Keep a strong reference of menu. @menu = menu # Keep a strong reference of menu.
# Keep compatibility with old APIs.
Tray::popContextMenu = Tray::popUpContextMenu
module.exports = Tray module.exports = Tray

View file

@ -6,6 +6,34 @@ ipc = require 'ipc'
nextId = 0 nextId = 0
getNextId = -> ++nextId getNextId = -> ++nextId
PDFPageSize =
A4:
custom_display_name: "A4"
height_microns: 297000
name: "ISO_A4"
is_default: "true"
width_microns: 210000
A3:
custom_display_name: "A3"
height_microns: 420000
name: "ISO_A3"
width_microns: 297000
Legal:
custom_display_name: "Legal"
height_microns: 355600
name: "NA_LEGAL"
width_microns: 215900
Letter:
custom_display_name: "Letter"
height_microns: 279400
name: "NA_LETTER"
width_microns: 215900
Tabloid:
height_microns: 431800
name: "NA_LEDGER"
width_microns: 279400
custom_display_name: "Tabloid"
wrapWebContents = (webContents) -> wrapWebContents = (webContents) ->
# webContents is an EventEmitter. # webContents is an EventEmitter.
webContents.__proto__ = EventEmitter.prototype webContents.__proto__ = EventEmitter.prototype
@ -18,11 +46,11 @@ wrapWebContents = (webContents) ->
# web contents has been loaded. # web contents has been loaded.
webContents.loaded = false webContents.loaded = false
webContents.once 'did-finish-load', -> @loaded = true webContents.once 'did-finish-load', -> @loaded = true
webContents.executeJavaScript = (code) -> webContents.executeJavaScript = (code, hasUserGesture=false) ->
if @loaded if @loaded
@_executeJavaScript code @_executeJavaScript code, hasUserGesture
else else
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code) webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
# The navigation controller. # The navigation controller.
controller = new NavigationController(webContents) controller = new NavigationController(webContents)
@ -41,32 +69,27 @@ wrapWebContents = (webContents) ->
webContents.printToPDF = (options, callback) -> webContents.printToPDF = (options, callback) ->
printingSetting = printingSetting =
pageRage:[], pageRage: []
mediaSize: mediaSize: {}
height_microns:297000, landscape: false
is_default:true, color: 2
name:"ISO_A4", headerFooterEnabled: false
width_microns:210000, marginsType: 0
custom_display_name:"A4", isFirstRequest: false
landscape:false, requestID: getNextId()
color:2, previewModifiable: true
headerFooterEnabled:false, printToPDF: true
marginsType:0, printWithCloudPrint: false
isFirstRequest:false, printWithPrivet: false
requestID: getNextId(), printWithExtension: false
previewModifiable:true, deviceName: "Save as PDF"
printToPDF:true, generateDraftData: true
printWithCloudPrint:false, fitToPageEnabled: false
printWithPrivet:false, duplex: 0
printWithExtension:false, copies: 1
deviceName:"Save as PDF", collate: true
generateDraftData:true, shouldPrintBackgrounds: false
fitToPageEnabled:false, shouldPrintSelectionOnly: false
duplex:0,
copies:1,
collate:true,
shouldPrintBackgrounds:false,
shouldPrintSelectionOnly:false
if options.landscape if options.landscape
printingSetting.landscape = options.landscape printingSetting.landscape = options.landscape
@ -77,6 +100,11 @@ wrapWebContents = (webContents) ->
if options.printBackgrounds if options.printBackgrounds
printingSetting.shouldPrintBackgrounds = options.printBackground printingSetting.shouldPrintBackgrounds = options.printBackground
if options.pageSize and PDFPageSize[options.pageSize]
printingSetting.mediaSize = PDFPageSize[options.pageSize]
else
printingSetting.mediaSize = PDFPageSize['A4']
@_printToPDF printingSetting, callback @_printToPDF printingSetting, callback
binding._setWrapWebContents wrapWebContents binding._setWrapWebContents wrapWebContents

View file

@ -4,6 +4,10 @@
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/atom_access_token_store.h" #include "atom/browser/atom_access_token_store.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
@ -190,10 +194,20 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
if (process_type != "renderer") if (process_type != "renderer")
return; return;
// The registered standard schemes.
if (!g_custom_schemes.empty()) if (!g_custom_schemes.empty())
command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes, command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes,
g_custom_schemes); g_custom_schemes);
#if defined(OS_WIN)
// Append --app-user-model-id.
PWSTR current_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&current_app_id))) {
command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id);
CoTaskMemFree(current_app_id);
}
#endif
NativeWindow* window; NativeWindow* window;
WebViewManager::WebViewInfo info; WebViewManager::WebViewInfo info;
ProcessOwner owner = GetProcessOwner(process_id, &window, &info); ProcessOwner owner = GetProcessOwner(process_id, &window, &info);

View file

@ -15,10 +15,13 @@
#include "atom/common/chrome_version.h" #include "atom/common/chrome_version.h"
#include "atom/common/options_switches.h" #include "atom/common/options_switches.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/threading/sequenced_worker_pool.h" #include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h" #include "base/threading/worker_pool.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/common/url_constants.h" #include "content/public/common/url_constants.h"
#include "content/public/common/user_agent.h" #include "content/public/common/user_agent.h"
@ -146,4 +149,11 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
return guest_manager_.get(); return guest_manager_.get();
} }
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
base::FilePath());
pref_registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
base::FilePath());
}
} // namespace atom } // namespace atom

View file

@ -32,6 +32,9 @@ class AtomBrowserContext : public brightray::BrowserContext {
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override; content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
content::BrowserPluginGuestManager* GetGuestManager() override; content::BrowserPluginGuestManager* GetGuestManager() override;
// brightray::BrowserContext:
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
AtomURLRequestJobFactory* job_factory() const { return job_factory_; } AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
private: private:

View file

@ -6,10 +6,13 @@
#include <string> #include <string>
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/file_dialog.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h" #include "content/public/browser/download_manager.h"
@ -77,6 +80,11 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
return; return;
} }
// Remeber the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
path.DirName());
callback.Run(path, callback.Run(path,
content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DownloadItem::TARGET_DISPOSITION_PROMPT,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path); content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
@ -92,9 +100,14 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
const content::DownloadTargetCallback& callback) { const content::DownloadTargetCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (default_download_path_.empty()) { AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
base::FilePath default_download_path = browser_context->prefs()->GetFilePath(
prefs::kDownloadDefaultDirectory);
// If users didn't set download path, use 'Downloads' directory by default.
if (default_download_path.empty()) {
auto path = download_manager_->GetBrowserContext()->GetPath(); auto path = download_manager_->GetBrowserContext()->GetPath();
default_download_path_ = path.Append(FILE_PATH_LITERAL("Downloads")); default_download_path = path.Append(FILE_PATH_LITERAL("Downloads"));
} }
if (!download->GetForcedFilePath().empty()) { if (!download->GetForcedFilePath().empty()) {
@ -118,7 +131,7 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
download->GetContentDisposition(), download->GetContentDisposition(),
download->GetSuggestedFilename(), download->GetSuggestedFilename(),
download->GetMimeType(), download->GetMimeType(),
default_download_path_, default_download_path,
download_path_callback)); download_path_callback));
return true; return true;
} }

View file

@ -47,7 +47,6 @@ class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
private: private:
content::DownloadManager* download_manager_; content::DownloadManager* download_manager_;
base::FilePath default_download_path_;
base::WeakPtrFactory<AtomDownloadManagerDelegate> weak_ptr_factory_; base::WeakPtrFactory<AtomDownloadManagerDelegate> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AtomDownloadManagerDelegate); DISALLOW_COPY_AND_ASSIGN(AtomDownloadManagerDelegate);

View file

@ -274,16 +274,21 @@ void CommonWebContentsDelegate::DevToolsAppendToFile(
base::Unretained(this), url)); base::Unretained(this), url));
} }
void CommonWebContentsDelegate::DevToolsAddFileSystem() { void CommonWebContentsDelegate::DevToolsAddFileSystem(
file_dialog::Filters filters; const base::FilePath& file_system_path) {
base::FilePath default_path; base::FilePath path = file_system_path;
std::vector<base::FilePath> paths; if (path.empty()) {
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY; file_dialog::Filters filters;
if (!file_dialog::ShowOpenDialog(owner_window(), "", default_path, base::FilePath default_path;
filters, flag, &paths)) std::vector<base::FilePath> paths;
return; int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
if (!file_dialog::ShowOpenDialog(owner_window(), "", default_path,
filters, flag, &paths))
return;
path = paths[0];
}
base::FilePath path = paths[0];
std::string registered_name; std::string registered_name;
std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(), std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(),
path, path,
@ -313,20 +318,20 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem() {
} }
void CommonWebContentsDelegate::DevToolsRemoveFileSystem( void CommonWebContentsDelegate::DevToolsRemoveFileSystem(
const std::string& file_system_path) { const base::FilePath& file_system_path) {
if (!web_contents_) if (!web_contents_)
return; return;
base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path); storage::IsolatedContext::GetInstance()->
storage::IsolatedContext::GetInstance()->RevokeFileSystemByPath(path); RevokeFileSystemByPath(file_system_path);
for (auto it = saved_paths_.begin(); it != saved_paths_.end(); ++it) for (auto it = saved_paths_.begin(); it != saved_paths_.end(); ++it)
if (it->second == path) { if (it->second == file_system_path) {
saved_paths_.erase(it); saved_paths_.erase(it);
break; break;
} }
base::StringValue file_system_path_value(file_system_path); base::StringValue file_system_path_value(file_system_path.AsUTF8Unsafe());
web_contents_->CallClientFunction( web_contents_->CallClientFunction(
"DevToolsAPI.fileSystemRemoved", "DevToolsAPI.fileSystemRemoved",
&file_system_path_value, &file_system_path_value,

View file

@ -80,8 +80,9 @@ class CommonWebContentsDelegate
bool save_as) override; bool save_as) override;
void DevToolsAppendToFile(const std::string& url, void DevToolsAppendToFile(const std::string& url,
const std::string& content) override; const std::string& content) override;
void DevToolsAddFileSystem() override; void DevToolsAddFileSystem(const base::FilePath& path) override;
void DevToolsRemoveFileSystem(const std::string& file_system_path) override; void DevToolsRemoveFileSystem(
const base::FilePath& file_system_path) override;
private: private:
// Callback for when DevToolsSaveToFile has completed. // Callback for when DevToolsSaveToFile has completed.

View file

@ -237,7 +237,7 @@ app.once('ready', function() {
}, },
{ {
label: 'Toggle &Developer Tools', label: 'Toggle &Developer Tools',
accelerator: 'Alt+Ctrl+I', accelerator: 'Shift+Ctrl+I',
click: function() { click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow(); var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) if (focusedWindow)

View file

@ -3,6 +3,7 @@ webContents = require 'web-contents'
webViewManager = null # Doesn't exist in early initialization. webViewManager = null # Doesn't exist in early initialization.
supportedWebViewEvents = [ supportedWebViewEvents = [
'load-commit'
'did-finish-load' 'did-finish-load'
'did-fail-load' 'did-fail-load'
'did-frame-finish-load' 'did-frame-finish-load'

View file

@ -64,3 +64,6 @@ ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, mess
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) -> ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
BrowserWindow.fromId(guestId)?.webContents?[method] args... BrowserWindow.fromId(guestId)?.webContents?[method] args...
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_IS_GUEST_WINDOW', (event) ->
event.returnValue = v8Util.getHiddenValue(event.sender, 'embedder') isnt undefined

View file

@ -38,7 +38,7 @@ process.on 'uncaughtException', (error) ->
# Show error in GUI. # Show error in GUI.
stack = error.stack ? "#{error.name}: #{error.message}" stack = error.stack ? "#{error.name}: #{error.message}"
message = "Uncaught Exception:\n#{stack}" message = "Uncaught Exception:\n#{stack}"
require('dialog').showErrorBox 'A JavaScript error occured in the browser process', message require('dialog').showErrorBox 'A JavaScript error occurred in the main process', message
# Emit 'exit' event on quit. # Emit 'exit' event on quit.
app = require 'app' app = require 'app'

View file

@ -10,6 +10,7 @@ valueToMeta = (sender, value) ->
meta.type = 'buffer' if Buffer.isBuffer value meta.type = 'buffer' if Buffer.isBuffer value
meta.type = 'value' if value is null meta.type = 'value' if value is null
meta.type = 'array' if Array.isArray value meta.type = 'array' if Array.isArray value
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
# Treat the arguments object as array. # Treat the arguments object as array.
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length? meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
@ -29,6 +30,8 @@ valueToMeta = (sender, value) ->
meta.members.push {name: prop, type: typeof field} for prop, field of value meta.members.push {name: prop, type: typeof field} for prop, field of value
else if meta.type is 'buffer' else if meta.type is 'buffer'
meta.value = Array::slice.call value, 0 meta.value = Array::slice.call value, 0
else if meta.type is 'promise'
meta.then = valueToMeta(sender, value.then.bind(value))
else else
meta.type = 'value' meta.type = 'value'
meta.value = value meta.value = value
@ -47,6 +50,7 @@ unwrapArgs = (sender, args) ->
when 'remote-object' then objectsRegistry.get meta.id when 'remote-object' then objectsRegistry.get meta.id
when 'array' then unwrapArgs sender, meta.value when 'array' then unwrapArgs sender, meta.value
when 'buffer' then new Buffer(meta.value) when 'buffer' then new Buffer(meta.value)
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
when 'object' when 'object'
ret = v8Util.createObjectWithName meta.name ret = v8Util.createObjectWithName meta.name
for member in meta.members for member in meta.members

View file

@ -8,10 +8,6 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
@ -72,6 +68,22 @@ const char* kWebRuntimeFeatures[] = {
switches::kPageVisibility, switches::kPageVisibility,
}; };
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
scoped_ptr<SkRegion> sk_region(new SkRegion);
for (const DraggableRegion& region : regions) {
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region.Pass();
}
} // namespace } // namespace
NativeWindow::NativeWindow( NativeWindow::NativeWindow(
@ -85,6 +97,7 @@ NativeWindow::NativeWindow(
node_integration_(true), node_integration_(true),
has_dialog_attached_(false), has_dialog_attached_(false),
zoom_factor_(1.0), zoom_factor_(1.0),
aspect_ratio_(0.0),
inspectable_web_contents_(inspectable_web_contents), inspectable_web_contents_(inspectable_web_contents),
weak_factory_(this) { weak_factory_(this) {
inspectable_web_contents->GetView()->SetDelegate(this); inspectable_web_contents->GetView()->SetDelegate(this);
@ -246,6 +259,20 @@ bool NativeWindow::IsMenuBarVisible() {
return true; return true;
} }
double NativeWindow::GetAspectRatio() {
return aspect_ratio_;
}
gfx::Size NativeWindow::GetAspectRatioExtraSize() {
return aspect_ratio_extraSize_;
}
void NativeWindow::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
aspect_ratio_ = aspect_ratio;
aspect_ratio_extraSize_ = extra_size;
}
bool NativeWindow::HasModalDialog() { bool NativeWindow::HasModalDialog() {
return has_dialog_attached_; return has_dialog_attached_;
} }
@ -369,15 +396,6 @@ void NativeWindow::AppendExtraCommandLineSwitches(
command_line->AppendSwitchASCII(switches::kZoomFactor, command_line->AppendSwitchASCII(switches::kZoomFactor,
base::DoubleToString(zoom_factor_)); base::DoubleToString(zoom_factor_));
#if defined(OS_WIN)
// Append --app-user-model-id.
PWSTR current_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&current_app_id))) {
command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id);
CoTaskMemFree(current_app_id);
}
#endif
if (web_preferences_.IsEmpty()) if (web_preferences_.IsEmpty())
return; return;
@ -424,6 +442,10 @@ void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
prefs->allow_displaying_insecure_content = !b; prefs->allow_displaying_insecure_content = !b;
prefs->allow_running_insecure_content = !b; prefs->allow_running_insecure_content = !b;
} }
if (web_preferences_.Get("allow-displaying-insecure-content", &b))
prefs->allow_displaying_insecure_content = b;
if (web_preferences_.Get("allow-running-insecure-content", &b))
prefs->allow_running_insecure_content = b;
if (web_preferences_.Get("extra-plugin-dirs", &list)) { if (web_preferences_.Get("extra-plugin-dirs", &list)) {
if (content::PluginService::GetInstance()->NPAPIPluginsSupported()) { if (content::PluginService::GetInstance()->NPAPIPluginsSupported()) {
for (size_t i = 0; i < list.size(); ++i) for (size_t i = 0; i < list.size(); ++i)
@ -500,6 +522,12 @@ void NativeWindow::NotifyWindowLeaveHtmlFullScreen() {
OnWindowLeaveHtmlFullScreen()); OnWindowLeaveHtmlFullScreen());
} }
void NativeWindow::NotifyWindowExecuteWindowsCommand(
const std::string& command) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnExecuteWindowsCommand(command));
}
void NativeWindow::DevToolsFocused() { void NativeWindow::DevToolsFocused() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsFocus()); FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsFocus());
} }
@ -534,7 +562,7 @@ void NativeWindow::BeforeUnloadDialogCancelled() {
void NativeWindow::TitleWasSet(content::NavigationEntry* entry, void NativeWindow::TitleWasSet(content::NavigationEntry* entry,
bool explicit_set) { bool explicit_set) {
bool prevent_default = false; bool prevent_default = false;
std::string text = base::UTF16ToUTF8(entry->GetTitle()); std::string text = entry ? base::UTF16ToUTF8(entry->GetTitle()) : "";
FOR_EACH_OBSERVER(NativeWindowObserver, FOR_EACH_OBSERVER(NativeWindowObserver,
observers_, observers_,
OnPageTitleUpdated(&prevent_default, text)); OnPageTitleUpdated(&prevent_default, text));
@ -553,6 +581,14 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
return handled; return handled;
} }
void NativeWindow::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
draggable_region_ = DraggableRegionsToSkRegion(regions);
}
void NativeWindow::ScheduleUnresponsiveEvent(int ms) { void NativeWindow::ScheduleUnresponsiveEvent(int ms) {
if (!window_unresposive_closure_.IsCancelled()) if (!window_unresposive_closure_.IsCancelled())
return; return;

View file

@ -23,6 +23,8 @@
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
class SkRegion;
namespace base { namespace base {
class CommandLine; class CommandLine;
} }
@ -57,7 +59,7 @@ struct DraggableRegion;
class NativeWindow : public content::WebContentsObserver, class NativeWindow : public content::WebContentsObserver,
public brightray::InspectableWebContentsViewDelegate { public brightray::InspectableWebContentsViewDelegate {
public: public:
typedef base::Callback<void(const SkBitmap& bitmap)> CapturePageCallback; using CapturePageCallback = base::Callback<void(const SkBitmap& bitmap)>;
class DialogScope { class DialogScope {
public: public:
@ -93,6 +95,7 @@ class NativeWindow : public content::WebContentsObserver,
virtual void Close() = 0; virtual void Close() = 0;
virtual void CloseImmediately() = 0; virtual void CloseImmediately() = 0;
virtual bool IsClosed() const { return is_closed_; }
virtual void Focus(bool focus) = 0; virtual void Focus(bool focus) = 0;
virtual bool IsFocused() = 0; virtual bool IsFocused() = 0;
virtual void Show() = 0; virtual void Show() = 0;
@ -137,14 +140,17 @@ class NativeWindow : public content::WebContentsObserver,
virtual void SetMenu(ui::MenuModel* menu); virtual void SetMenu(ui::MenuModel* menu);
virtual bool HasModalDialog(); virtual bool HasModalDialog();
virtual gfx::NativeWindow GetNativeWindow() = 0; virtual gfx::NativeWindow GetNativeWindow() = 0;
// Taskbar/Dock APIs.
virtual void SetProgressBar(double progress) = 0; virtual void SetProgressBar(double progress) = 0;
virtual void SetOverlayIcon(const gfx::Image& overlay, virtual void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) = 0; const std::string& description) = 0;
// Workspace APIs.
virtual void SetVisibleOnAllWorkspaces(bool visible) = 0; virtual void SetVisibleOnAllWorkspaces(bool visible) = 0;
virtual bool IsVisibleOnAllWorkspaces() = 0; virtual bool IsVisibleOnAllWorkspaces() = 0;
virtual bool IsClosed() const { return is_closed_; } // Webview APIs.
virtual void FocusOnWebView(); virtual void FocusOnWebView();
virtual void BlurWebView(); virtual void BlurWebView();
virtual bool IsWebViewFocused(); virtual bool IsWebViewFocused();
@ -163,6 +169,11 @@ class NativeWindow : public content::WebContentsObserver,
virtual void SetMenuBarVisibility(bool visible); virtual void SetMenuBarVisibility(bool visible);
virtual bool IsMenuBarVisible(); virtual bool IsMenuBarVisible();
// Set the aspect ratio when resizing window.
double GetAspectRatio();
gfx::Size GetAspectRatioExtraSize();
void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
base::WeakPtr<NativeWindow> GetWeakPtr() { base::WeakPtr<NativeWindow> GetWeakPtr() {
return weak_factory_.GetWeakPtr(); return weak_factory_.GetWeakPtr();
} }
@ -198,11 +209,11 @@ class NativeWindow : public content::WebContentsObserver,
void NotifyWindowLeaveFullScreen(); void NotifyWindowLeaveFullScreen();
void NotifyWindowEnterHtmlFullScreen(); void NotifyWindowEnterHtmlFullScreen();
void NotifyWindowLeaveHtmlFullScreen(); void NotifyWindowLeaveHtmlFullScreen();
void NotifyWindowExecuteWindowsCommand(const std::string& command);
void AddObserver(NativeWindowObserver* obs) { void AddObserver(NativeWindowObserver* obs) {
observers_.AddObserver(obs); observers_.AddObserver(obs);
} }
void RemoveObserver(NativeWindowObserver* obs) { void RemoveObserver(NativeWindowObserver* obs) {
observers_.RemoveObserver(obs); observers_.RemoveObserver(obs);
} }
@ -212,6 +223,10 @@ class NativeWindow : public content::WebContentsObserver,
} }
bool has_frame() const { return has_frame_; } bool has_frame() const { return has_frame_; }
bool transparent() const { return transparent_; }
SkRegion* draggable_region() const { return draggable_region_.get(); }
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
gfx::ImageSkia icon() const { return icon_; }
void set_has_dialog_attached(bool has_dialog_attached) { void set_has_dialog_attached(bool has_dialog_attached) {
has_dialog_attached_ = has_dialog_attached; has_dialog_attached_ = has_dialog_attached;
@ -221,10 +236,6 @@ class NativeWindow : public content::WebContentsObserver,
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents, NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
const mate::Dictionary& options); const mate::Dictionary& options);
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) = 0;
// brightray::InspectableWebContentsViewDelegate: // brightray::InspectableWebContentsViewDelegate:
void DevToolsFocused() override; void DevToolsFocused() override;
void DevToolsOpened() override; void DevToolsOpened() override;
@ -236,22 +247,11 @@ class NativeWindow : public content::WebContentsObserver,
void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override; void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override;
bool OnMessageReceived(const IPC::Message& message) override; bool OnMessageReceived(const IPC::Message& message) override;
// Whether window has standard frame.
bool has_frame_;
// Whether window is transparent.
bool transparent_;
// Whether window can be resized larger than screen.
bool enable_larger_than_screen_;
// Window icon.
gfx::ImageSkia icon_;
// Observers of this window.
ObserverList<NativeWindowObserver> observers_;
private: private:
// Called when the window needs to update its draggable region.
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions);
// Schedule a notification unresponsive event. // Schedule a notification unresponsive event.
void ScheduleUnresponsiveEvent(int ms); void ScheduleUnresponsiveEvent(int ms);
@ -263,6 +263,22 @@ class NativeWindow : public content::WebContentsObserver,
const SkBitmap& bitmap, const SkBitmap& bitmap,
content::ReadbackResponse response); content::ReadbackResponse response);
// Whether window has standard frame.
bool has_frame_;
// Whether window is transparent.
bool transparent_;
// For custom drag, the whole window is non-draggable and the draggable region
// has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Whether window can be resized larger than screen.
bool enable_larger_than_screen_;
// Window icon.
gfx::ImageSkia icon_;
// The windows has been closed. // The windows has been closed.
bool is_closed_; bool is_closed_;
@ -285,9 +301,17 @@ class NativeWindow : public content::WebContentsObserver,
// Page's default zoom factor. // Page's default zoom factor.
double zoom_factor_; double zoom_factor_;
// Used to maintain the aspect ratio of a view which is inside of the
// content view.
double aspect_ratio_;
gfx::Size aspect_ratio_extraSize_;
// The page this window is viewing. // The page this window is viewing.
brightray::InspectableWebContents* inspectable_web_contents_; brightray::InspectableWebContents* inspectable_web_contents_;
// Observers of this window.
ObserverList<NativeWindowObserver> observers_;
base::WeakPtrFactory<NativeWindow> weak_factory_; base::WeakPtrFactory<NativeWindow> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NativeWindow); DISALLOW_COPY_AND_ASSIGN(NativeWindow);

View file

@ -11,13 +11,11 @@
#include <vector> #include <vector>
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
@class AtomNSWindow; @class AtomNSWindow;
@class AtomNSWindowDelegate; @class AtomNSWindowDelegate;
@class FullSizeContentView; @class FullSizeContentView;
class SkRegion;
namespace atom { namespace atom {
@ -88,9 +86,6 @@ class NativeWindowMac : public NativeWindow {
void ClipWebView(); void ClipWebView();
protected: protected:
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) override;
// NativeWindow: // NativeWindow:
void HandleKeyboardEvent( void HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
@ -117,10 +112,6 @@ class NativeWindowMac : public NativeWindow {
// The presentation options before entering kiosk mode. // The presentation options before entering kiosk mode.
NSApplicationPresentationOptions kiosk_options_; NSApplicationPresentationOptions kiosk_options_;
// For custom drag, the whole window is non-draggable and the draggable region
// has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Mouse location since the last mouse event, in screen coordinates. This is // Mouse location since the last mouse event, in screen coordinates. This is
// used in custom drag to compute the window movement. // used in custom drag to compute the window movement.
NSPoint last_mouse_offset_; NSPoint last_mouse_offset_;

View file

@ -20,7 +20,26 @@
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
static const CGFloat kAtomWindowCornerRadius = 4.0; namespace {
// The radius of rounded corner.
const CGFloat kAtomWindowCornerRadius = 4.0;
// Prevents window from resizing during the scope.
class ScopedDisableResize {
public:
ScopedDisableResize() { disable_resize_ = true; }
~ScopedDisableResize() { disable_resize_ = false; }
static bool IsResizeDisabled() { return disable_resize_; }
private:
static bool disable_resize_;
};
bool ScopedDisableResize::disable_resize_ = false;
} // namespace
@interface NSView (PrivateMethods) @interface NSView (PrivateMethods)
- (CGFloat)roundedCornerRadius; - (CGFloat)roundedCornerRadius;
@ -95,6 +114,44 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
shell_->NotifyWindowBlur(); shell_->NotifyWindowBlur();
} }
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
double aspectRatio = shell_->GetAspectRatio();
if (aspectRatio > 0.0) {
gfx::Size windowSize = shell_->GetSize();
gfx::Size contentSize = shell_->GetContentSize();
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
double extraWidthPlusFrame =
windowSize.width() - contentSize.width() + extraSize.width();
double extraHeightPlusFrame =
windowSize.height() - contentSize.height() + extraSize.height();
newSize.width =
roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio +
extraWidthPlusFrame);
// If the new width is less than the frame size use it as the primary
// constraint. This ensures that the value returned by this method will
// never be larger than the users requested window size.
if (newSize.width <= frameSize.width) {
newSize.height =
roundf((newSize.width - extraWidthPlusFrame) / aspectRatio +
extraHeightPlusFrame);
} else {
newSize.height =
roundf((frameSize.width - extraWidthPlusFrame) / aspectRatio +
extraHeightPlusFrame);
newSize.width =
roundf((newSize.height - extraHeightPlusFrame) * aspectRatio +
extraWidthPlusFrame);
}
}
return newSize;
}
- (void)windowDidResize:(NSNotification*)notification { - (void)windowDidResize:(NSNotification*)notification {
if (!shell_->has_frame()) if (!shell_->has_frame())
shell_->ClipWebView(); shell_->ClipWebView();
@ -176,8 +233,12 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
enable_larger_than_screen_ = enable; enable_larger_than_screen_ = enable;
} }
// Enable the window to be larger than screen.
- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen { - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen {
// Resizing is disabled.
if (ScopedDisableResize::IsResizeDisabled())
return [self frame];
// Enable the window to be larger than screen.
if (enable_larger_than_screen_) if (enable_larger_than_screen_)
return frameRect; return frameRect;
else else
@ -280,29 +341,6 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
namespace atom { namespace atom {
namespace {
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
SkRegion* DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
SkRegion* sk_region = new SkRegion;
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end();
++iter) {
const DraggableRegion& region = *iter;
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region;
}
} // namespace
NativeWindowMac::NativeWindowMac( NativeWindowMac::NativeWindowMac(
brightray::InspectableWebContents* web_contents, brightray::InspectableWebContents* web_contents,
const mate::Dictionary& options) const mate::Dictionary& options)
@ -325,7 +363,7 @@ NativeWindowMac::NativeWindowMac(
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask; NSMiniaturizableWindowMask | NSResizableWindowMask;
if (!useStandardWindow || transparent_ || !has_frame_) { if (!useStandardWindow || transparent() || !has_frame()) {
styleMask |= NSTexturedBackgroundWindowMask; styleMask |= NSTexturedBackgroundWindowMask;
} }
@ -335,12 +373,12 @@ NativeWindowMac::NativeWindowMac(
backing:NSBackingStoreBuffered backing:NSBackingStoreBuffered
defer:YES]); defer:YES]);
[window_ setShell:this]; [window_ setShell:this];
[window_ setEnableLargerThanScreen:enable_larger_than_screen_]; [window_ setEnableLargerThanScreen:enable_larger_than_screen()];
window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]); window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
[window_ setDelegate:window_delegate_]; [window_ setDelegate:window_delegate_];
if (transparent_) { if (transparent()) {
// Make window has transparent background. // Make window has transparent background.
[window_ setOpaque:NO]; [window_ setOpaque:NO];
[window_ setHasShadow:NO]; [window_ setHasShadow:NO];
@ -348,7 +386,7 @@ NativeWindowMac::NativeWindowMac(
} }
// Remove non-transparent corners, see http://git.io/vfonD. // Remove non-transparent corners, see http://git.io/vfonD.
if (!has_frame_) if (!has_frame())
[window_ setOpaque:NO]; [window_ setOpaque:NO];
// We will manage window's lifetime ourselves. // We will manage window's lifetime ourselves.
@ -357,7 +395,7 @@ NativeWindowMac::NativeWindowMac(
// On OS X the initial window size doesn't include window frame. // On OS X the initial window size doesn't include window frame.
bool use_content_size = false; bool use_content_size = false;
options.Get(switches::kUseContentSize, &use_content_size); options.Get(switches::kUseContentSize, &use_content_size);
if (has_frame_ && !use_content_size) if (!has_frame() || !use_content_size)
SetSize(gfx::Size(width, height)); SetSize(gfx::Size(width, height));
// Enable the NSView to accept first mouse event. // Enable the NSView to accept first mouse event.
@ -494,6 +532,11 @@ gfx::Rect NativeWindowMac::GetBounds() {
} }
void NativeWindowMac::SetContentSize(const gfx::Size& size) { void NativeWindowMac::SetContentSize(const gfx::Size& size) {
if (!has_frame()) {
SetSize(size);
return;
}
NSRect frame_nsrect = [window_ frame]; NSRect frame_nsrect = [window_ frame];
NSSize frame = frame_nsrect.size; NSSize frame = frame_nsrect.size;
NSSize content = [window_ contentRectForFrameRect:frame_nsrect].size; NSSize content = [window_ contentRectForFrameRect:frame_nsrect].size;
@ -507,6 +550,9 @@ void NativeWindowMac::SetContentSize(const gfx::Size& size) {
} }
gfx::Size NativeWindowMac::GetContentSize() { gfx::Size NativeWindowMac::GetContentSize() {
if (!has_frame())
return GetSize();
NSRect bounds = [[window_ contentView] bounds]; NSRect bounds = [[window_ contentView] bounds];
return gfx::Size(bounds.size.width, bounds.size.height); return gfx::Size(bounds.size.width, bounds.size.height);
} }
@ -538,12 +584,15 @@ gfx::Size NativeWindowMac::GetMaximumSize() {
} }
void NativeWindowMac::SetResizable(bool resizable) { void NativeWindowMac::SetResizable(bool resizable) {
// Change styleMask for frameless causes the window to change size, so we have
// to explicitly disables that.
ScopedDisableResize disable_resize;
if (resizable) { if (resizable) {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:YES]; [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:YES];
[window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask]; [window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask];
} else { } else {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO]; [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
[window_ setStyleMask:[window_ styleMask] ^ NSResizableWindowMask]; [window_ setStyleMask:[window_ styleMask] & (~NSResizableWindowMask)];
} }
} }
@ -565,7 +614,7 @@ void NativeWindowMac::Center() {
void NativeWindowMac::SetTitle(const std::string& title) { void NativeWindowMac::SetTitle(const std::string& title) {
// We don't want the title to show in transparent window. // We don't want the title to show in transparent window.
if (transparent_) if (transparent())
return; return;
[window_ setTitle:base::SysUTF8ToNSString(title)]; [window_ setTitle:base::SysUTF8ToNSString(title)];
@ -701,7 +750,7 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
} }
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const { bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
if (!draggable_region_) if (!draggable_region())
return false; return false;
if (!web_contents()) if (!web_contents())
return false; return false;
@ -710,7 +759,7 @@ bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
// |draggable_region_| is stored in local platform-indepdent coordiate system // |draggable_region_| is stored in local platform-indepdent coordiate system
// while |point| is in local Cocoa coordinate system. Do the conversion // while |point| is in local Cocoa coordinate system. Do the conversion
// to match these two. // to match these two.
return draggable_region_->contains(point.x, webViewHeight - point.y); return draggable_region()->contains(point.x, webViewHeight - point.y);
} }
void NativeWindowMac::HandleMouseEvent(NSEvent* event) { void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
@ -730,15 +779,6 @@ void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
} }
} }
void NativeWindowMac::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
draggable_region_.reset(DraggableRegionsToSkRegion(regions));
}
void NativeWindowMac::HandleKeyboardEvent( void NativeWindowMac::HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent& event) { const content::NativeWebKeyboardEvent& event) {
@ -765,7 +805,7 @@ void NativeWindowMac::HandleKeyboardEvent(
void NativeWindowMac::InstallView() { void NativeWindowMac::InstallView() {
NSView* view = inspectable_web_contents()->GetView()->GetNativeView(); NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
if (has_frame_) { if (has_frame()) {
// Add layer with white background for the contents view. // Add layer with white background for the contents view.
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]); base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)]; [layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];

View file

@ -4,10 +4,6 @@
#include "atom/browser/native_window_views.h" #include "atom/browser/native_window_views.h"
#if defined(OS_WIN)
#include <shobjidl.h>
#endif
#include <string> #include <string>
#include <vector> #include <vector>
@ -20,7 +16,6 @@
#include "brightray/browser/inspectable_web_contents_view.h" #include "brightray/browser/inspectable_web_contents_view.h"
#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/native_web_keyboard_event.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h" #include "ui/base/hit_test.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
@ -36,26 +31,20 @@
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/ui/views/global_menu_bar_x11.h" #include "atom/browser/ui/views/global_menu_bar_x11.h"
#include "atom/browser/ui/views/frameless_view.h" #include "atom/browser/ui/views/frameless_view.h"
#include "atom/browser/ui/views/native_frame_view.h"
#include "atom/browser/ui/x/window_state_watcher.h" #include "atom/browser/ui/x/window_state_watcher.h"
#include "atom/browser/ui/x/x_window_utils.h" #include "atom/browser/ui/x/x_window_utils.h"
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "chrome/browser/ui/libgtk2ui/unity_service.h" #include "chrome/browser/ui/libgtk2ui/unity_service.h"
#include "dbus/bus.h"
#include "dbus/object_proxy.h"
#include "dbus/message.h"
#include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
#include "ui/views/window/native_frame_view.h" #include "ui/views/window/native_frame_view.h"
#elif defined(OS_WIN) #elif defined(OS_WIN)
#include "atom/browser/ui/views/win_frame_view.h" #include "atom/browser/ui/views/win_frame_view.h"
#include "base/win/scoped_comptr.h" #include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
#include "base/win/windows_version.h"
#include "ui/base/win/shell.h" #include "ui/base/win/shell.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/win/dpi.h" #include "ui/gfx/win/dpi.h"
#include "ui/views/win/hwnd_util.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif #endif
namespace atom { namespace atom {
@ -69,42 +58,6 @@ const int kMenuBarHeight = 20;
const int kMenuBarHeight = 25; const int kMenuBarHeight = 25;
#endif #endif
#if defined(USE_X11)
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
bool ShouldUseGlobalMenuBar() {
dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
dbus::ObjectProxy* object_proxy =
bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
dbus::MethodCall method_call(DBUS_INTERFACE_DBUS, "ListNames");
scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
bus->ShutdownAndBlock();
return false;
}
dbus::MessageReader reader(response.get());
dbus::MessageReader array_reader(NULL);
if (!reader.PopArray(&array_reader)) {
bus->ShutdownAndBlock();
return false;
}
while (array_reader.HasMoreData()) {
std::string name;
if (array_reader.PopString(&name) &&
name == "com.canonical.AppMenu.Registrar") {
bus->ShutdownAndBlock();
return true;
}
}
bus->ShutdownAndBlock();
return false;
}
#endif
bool IsAltKey(const content::NativeWebKeyboardEvent& event) { bool IsAltKey(const content::NativeWebKeyboardEvent& event) {
#if defined(USE_X11) #if defined(USE_X11)
// 164 and 165 represent VK_LALT and VK_RALT. // 164 and 165 represent VK_LALT and VK_RALT.
@ -183,7 +136,7 @@ const char* AppCommandToString(int command_id) {
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE: case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
return "dictate-or-command-control-toggle"; return "dictate-or-command-control-toggle";
default: default:
return "unkown"; return "unknown";
} }
} }
#endif #endif
@ -231,7 +184,7 @@ NativeWindowViews::NativeWindowViews(
options.Get(switches::kResizable, &resizable_); options.Get(switches::kResizable, &resizable_);
#endif #endif
if (enable_larger_than_screen_) if (enable_larger_than_screen())
// We need to set a default maximum window size here otherwise Windows // We need to set a default maximum window size here otherwise Windows
// will not allow us to resize the window larger than scree. // will not allow us to resize the window larger than scree.
// Setting directly to INT_MAX somehow doesn't work, so we just devide // Setting directly to INT_MAX somehow doesn't work, so we just devide
@ -251,12 +204,20 @@ NativeWindowViews::NativeWindowViews(
params.bounds = bounds; params.bounds = bounds;
params.delegate = this; params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW; params.type = views::Widget::InitParams::TYPE_WINDOW;
params.remove_standard_frame = !has_frame_; params.remove_standard_frame = !has_frame();
if (transparent_) if (transparent())
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
#if defined(USE_X11) #if defined(OS_WIN)
params.native_widget =
new views::DesktopNativeWidgetAura(window_.get());
atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin(
this,
window_.get(),
static_cast<views::DesktopNativeWidgetAura*>(params.native_widget));
params.desktop_window_tree_host = atom_desktop_window_tree_host_win_;
#elif defined(USE_X11)
std::string name = Browser::Get()->GetName(); std::string name = Browser::Get()->GetName();
// Set WM_WINDOW_ROLE. // Set WM_WINDOW_ROLE.
params.wm_role_name = "browser-window"; params.wm_role_name = "browser-window";
@ -311,24 +272,24 @@ NativeWindowViews::NativeWindowViews(
set_background(views::Background::CreateStandardPanelBackground()); set_background(views::Background::CreateStandardPanelBackground());
AddChildView(web_view_); AddChildView(web_view_);
if (has_frame_ && if (has_frame() &&
options.Get(switches::kUseContentSize, &use_content_size_) && options.Get(switches::kUseContentSize, &use_content_size_) &&
use_content_size_) use_content_size_)
bounds = ContentBoundsToWindowBounds(bounds); bounds = ContentBoundsToWindowBounds(bounds);
#if defined(OS_WIN) #if defined(OS_WIN)
if (!has_frame_) { if (!has_frame()) {
// Set Window style so that we get a minimize and maximize animation when // Set Window style so that we get a minimize and maximize animation when
// frameless. // frameless.
DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
WS_CAPTION; WS_CAPTION;
// We should not show a frame for transparent window. // We should not show a frame for transparent window.
if (transparent_) if (transparent())
frame_style &= ~(WS_THICKFRAME | WS_CAPTION); frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style); ::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
} }
if (transparent_) { if (transparent()) {
// Transparent window on Windows has to have WS_EX_COMPOSITED style. // Transparent window on Windows has to have WS_EX_COMPOSITED style.
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE); LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
ex_style |= WS_EX_COMPOSITED; ex_style |= WS_EX_COMPOSITED;
@ -338,14 +299,14 @@ NativeWindowViews::NativeWindowViews(
// TODO(zcbenz): This was used to force using native frame on Windows 2003, we // TODO(zcbenz): This was used to force using native frame on Windows 2003, we
// should check whether setting it in InitParams can work. // should check whether setting it in InitParams can work.
if (has_frame_) { if (has_frame()) {
window_->set_frame_type(views::Widget::FrameType::FRAME_TYPE_FORCE_NATIVE); window_->set_frame_type(views::Widget::FrameType::FRAME_TYPE_FORCE_NATIVE);
window_->FrameTypeChanged(); window_->FrameTypeChanged();
} }
// The given window is most likely not rectangular since it uses // The given window is most likely not rectangular since it uses
// transparency and has no standard frame, don't show a shadow for it. // transparency and has no standard frame, don't show a shadow for it.
if (transparent_ && !has_frame_) if (transparent() && !has_frame())
wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE); wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE);
window_->UpdateWindowIcon(); window_->UpdateWindowIcon();
@ -468,7 +429,7 @@ gfx::Rect NativeWindowViews::GetBounds() {
} }
void NativeWindowViews::SetContentSize(const gfx::Size& size) { void NativeWindowViews::SetContentSize(const gfx::Size& size) {
if (!has_frame_) { if (!has_frame()) {
NativeWindow::SetSize(size); NativeWindow::SetSize(size);
return; return;
} }
@ -479,7 +440,7 @@ void NativeWindowViews::SetContentSize(const gfx::Size& size) {
} }
gfx::Size NativeWindowViews::GetContentSize() { gfx::Size NativeWindowViews::GetContentSize() {
if (!has_frame_) if (!has_frame())
return GetSize(); return GetSize();
gfx::Size content_size = gfx::Size content_size =
@ -491,14 +452,6 @@ gfx::Size NativeWindowViews::GetContentSize() {
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) { void NativeWindowViews::SetMinimumSize(const gfx::Size& size) {
minimum_size_ = size; minimum_size_ = size;
#if defined(USE_X11)
XSizeHints size_hints;
size_hints.flags = PMinSize;
size_hints.min_width = size.width();
size_hints.min_height = size.height();
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
#endif
} }
gfx::Size NativeWindowViews::GetMinimumSize() { gfx::Size NativeWindowViews::GetMinimumSize() {
@ -507,14 +460,6 @@ gfx::Size NativeWindowViews::GetMinimumSize() {
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) { void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size; maximum_size_ = size;
#if defined(USE_X11)
XSizeHints size_hints;
size_hints.flags = PMaxSize;
size_hints.max_width = size.width();
size_hints.max_height = size.height();
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
#endif
} }
gfx::Size NativeWindowViews::GetMaximumSize() { gfx::Size NativeWindowViews::GetMaximumSize() {
@ -643,7 +588,7 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
#endif #endif
// Do not show menu bar in frameless window. // Do not show menu bar in frameless window.
if (!has_frame_) if (!has_frame())
return; return;
if (!menu_bar_) { if (!menu_bar_) {
@ -668,24 +613,7 @@ gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
void NativeWindowViews::SetProgressBar(double progress) { void NativeWindowViews::SetProgressBar(double progress) {
#if defined(OS_WIN) #if defined(OS_WIN)
if (base::win::GetVersion() < base::win::VERSION_WIN7) taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress);
return;
base::win::ScopedComPtr<ITaskbarList3> taskbar;
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
CLSCTX_INPROC_SERVER) ||
FAILED(taskbar->HrInit()))) {
return;
}
HWND frame = views::HWNDForNativeWindow(GetNativeWindow());
if (progress > 1.0) {
taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
} else if (progress < 0) {
taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
} else if (progress >= 0) {
taskbar->SetProgressValue(frame,
static_cast<int>(progress * 100),
100);
}
#elif defined(USE_X11) #elif defined(USE_X11)
if (unity::IsRunning()) { if (unity::IsRunning()) {
unity::SetProgressFraction(progress); unity::SetProgressFraction(progress);
@ -696,22 +624,7 @@ void NativeWindowViews::SetProgressBar(double progress) {
void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay, void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) { const std::string& description) {
#if defined(OS_WIN) #if defined(OS_WIN)
if (base::win::GetVersion() < base::win::VERSION_WIN7) taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay, description);
return;
base::win::ScopedComPtr<ITaskbarList3> taskbar;
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
CLSCTX_INPROC_SERVER) ||
FAILED(taskbar->HrInit()))) {
return;
}
HWND frame = views::HWNDForNativeWindow(GetNativeWindow());
std::wstring wstr = std::wstring(description.begin(), description.end());
taskbar->SetOverlayIcon(frame,
IconUtil::CreateHICONFromSkBitmap(overlay.AsBitmap()),
wstr.c_str());
#endif #endif
} }
@ -768,29 +681,6 @@ gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() {
return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
} }
void NativeWindowViews::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
if (has_frame_)
return;
SkRegion* draggable_region = new SkRegion;
// By default, the whole window is non-draggable. We need to explicitly
// include those draggable regions.
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end(); ++iter) {
const DraggableRegion& region = *iter;
draggable_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
draggable_region_.reset(draggable_region);
}
void NativeWindowViews::OnWidgetActivationChanged( void NativeWindowViews::OnWidgetActivationChanged(
views::Widget* widget, bool active) { views::Widget* widget, bool active) {
if (widget != window_.get()) if (widget != window_.get())
@ -850,7 +740,7 @@ bool NativeWindowViews::ShouldHandleSystemCommands() const {
} }
gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() { gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() {
return icon_; return icon();
} }
gfx::ImageSkia NativeWindowViews::GetWindowIcon() { gfx::ImageSkia NativeWindowViews::GetWindowIcon() {
@ -873,12 +763,12 @@ bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child, gfx::NativeView child,
const gfx::Point& location) { const gfx::Point& location) {
// App window should claim mouse events that fall within the draggable region. // App window should claim mouse events that fall within the draggable region.
if (draggable_region_ && if (draggable_region() &&
draggable_region_->contains(location.x(), location.y())) draggable_region()->contains(location.x(), location.y()))
return false; return false;
// And the events on border for dragging resizable frameless window. // And the events on border for dragging resizable frameless window.
if (!has_frame_ && CanResize()) { if (!has_frame() && CanResize()) {
FramelessView* frame = static_cast<FramelessView*>( FramelessView* frame = static_cast<FramelessView*>(
window_->non_client_view()->frame_view()); window_->non_client_view()->frame_view());
return frame->ResizingBorderHitTest(location) == HTNOWHERE; return frame->ResizingBorderHitTest(location) == HTNOWHERE;
@ -898,8 +788,8 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
frame_view->Init(this, widget); frame_view->Init(this, widget);
return frame_view; return frame_view;
#else #else
if (has_frame_) { if (has_frame()) {
return new views::NativeFrameView(widget); return new NativeFrameView(this, widget);
} else { } else {
FramelessView* frame_view = new FramelessView; FramelessView* frame_view = new FramelessView;
frame_view->Init(this, widget); frame_view->Init(this, widget);
@ -929,10 +819,8 @@ bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
} else if ((command_id & sc_mask) == SC_MAXIMIZE) { } else if ((command_id & sc_mask) == SC_MAXIMIZE) {
NotifyWindowMaximize(); NotifyWindowMaximize();
} else { } else {
std::string command = AppCommandToString(command_id & sc_mask); std::string command = AppCommandToString(command_id);
FOR_EACH_OBSERVER(NativeWindowObserver, NotifyWindowExecuteWindowsCommand(command);
observers_,
OnExecuteWindowsCommand(command));
} }
return false; return false;
} }
@ -950,6 +838,17 @@ void NativeWindowViews::GetDevToolsWindowWMClass(
} }
#endif #endif
#if defined(OS_WIN)
bool NativeWindowViews::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
// Handle thumbar button click message.
if (message == WM_COMMAND && HIWORD(w_param) == THBN_CLICKED)
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
else
return false;
}
#endif
void NativeWindowViews::HandleKeyboardEvent( void NativeWindowViews::HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent& event) { const content::NativeWebKeyboardEvent& event) {

View file

@ -14,6 +14,11 @@
#include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/widget_observer.h" #include "ui/views/widget/widget_observer.h"
#if defined(OS_WIN)
#include "atom/browser/ui/win/message_handler_delegate.h"
#include "atom/browser/ui/win/taskbar_host.h"
#endif
namespace views { namespace views {
class UnhandledKeyboardEventHandler; class UnhandledKeyboardEventHandler;
} }
@ -24,7 +29,14 @@ class GlobalMenuBarX11;
class MenuBar; class MenuBar;
class WindowStateWatcher; class WindowStateWatcher;
#if defined(OS_WIN)
class AtomDesktopWindowTreeHostWin;
#endif
class NativeWindowViews : public NativeWindow, class NativeWindowViews : public NativeWindow,
#if defined(OS_WIN)
public MessageHandlerDelegate,
#endif
public views::WidgetDelegateView, public views::WidgetDelegateView,
public views::WidgetObserver { public views::WidgetObserver {
public: public:
@ -82,14 +94,13 @@ class NativeWindowViews : public NativeWindow,
gfx::AcceleratedWidget GetAcceleratedWidget(); gfx::AcceleratedWidget GetAcceleratedWidget();
SkRegion* draggable_region() const { return draggable_region_.get(); }
views::Widget* widget() const { return window_.get(); } views::Widget* widget() const { return window_.get(); }
private: #if defined(OS_WIN)
// NativeWindow: TaskbarHost& taskbar_host() { return taskbar_host_; }
void UpdateDraggableRegions( #endif
const std::vector<DraggableRegion>& regions) override;
private:
// views::WidgetObserver: // views::WidgetObserver:
void OnWidgetActivationChanged( void OnWidgetActivationChanged(
views::Widget* widget, bool active) override; views::Widget* widget, bool active) override;
@ -127,6 +138,12 @@ class NativeWindowViews : public NativeWindow,
std::string* name, std::string* class_name) override; std::string* name, std::string* class_name) override;
#endif #endif
#if defined(OS_WIN)
// MessageHandlerDelegate:
bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
#endif
// NativeWindow: // NativeWindow:
void HandleKeyboardEvent( void HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
@ -159,9 +176,13 @@ class NativeWindowViews : public NativeWindow,
// Handles window state events. // Handles window state events.
scoped_ptr<WindowStateWatcher> window_state_watcher_; scoped_ptr<WindowStateWatcher> window_state_watcher_;
#elif defined(OS_WIN) #elif defined(OS_WIN)
// Weak ref.
AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_;
// Records window was whether restored from minimized state or maximized // Records window was whether restored from minimized state or maximized
// state. // state.
bool is_minimized_; bool is_minimized_;
// In charge of running taskbar related APIs.
TaskbarHost taskbar_host_;
#endif #endif
// Handles unhandled keyboard messages coming back from the renderer process. // Handles unhandled keyboard messages coming back from the renderer process.
@ -177,8 +198,6 @@ class NativeWindowViews : public NativeWindow,
gfx::Size maximum_size_; gfx::Size maximum_size_;
gfx::Size widget_size_; gfx::Size widget_size_;
scoped_ptr<SkRegion> draggable_region_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews); DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
}; };

View file

@ -4,7 +4,6 @@
#include "atom/browser/net/adapter_request_job.h" #include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/atom_browser_context.h"
#include "base/threading/sequenced_worker_pool.h" #include "base/threading/sequenced_worker_pool.h"
#include "atom/browser/net/url_request_buffer_job.h" #include "atom/browser/net/url_request_buffer_job.h"
#include "atom/browser/net/url_request_fetch_job.h" #include "atom/browser/net/url_request_fetch_job.h"
@ -28,11 +27,7 @@ AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
void AdapterRequestJob::Start() { void AdapterRequestJob::Start() {
DCHECK(!real_job_.get()); DCHECK(!real_job_.get());
content::BrowserThread::PostTask( GetJobType();
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
weak_factory_.GetWeakPtr()));
} }
void AdapterRequestJob::Kill() { void AdapterRequestJob::Kill() {
@ -44,7 +39,11 @@ bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
int buf_size, int buf_size,
int *bytes_read) { int *bytes_read) {
DCHECK(!real_job_.get()); DCHECK(!real_job_.get());
return real_job_->ReadRawData(buf, buf_size, bytes_read); // Read post-filtered data if available.
if (real_job_->HasFilter())
return real_job_->Read(buf, buf_size, bytes_read);
else
return real_job_->ReadRawData(buf, buf_size, bytes_read);
} }
bool AdapterRequestJob::IsRedirectResponse(GURL* location, bool AdapterRequestJob::IsRedirectResponse(GURL* location,
@ -76,6 +75,11 @@ int AdapterRequestJob::GetResponseCode() const {
return real_job_->GetResponseCode(); return real_job_->GetResponseCode();
} }
void AdapterRequestJob::GetLoadTimingInfo(
net::LoadTimingInfo* load_timing_info) const {
real_job_->GetLoadTimingInfo(load_timing_info);
}
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() { base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
return weak_factory_.GetWeakPtr(); return weak_factory_.GetWeakPtr();
} }
@ -115,7 +119,7 @@ void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
} }
void AdapterRequestJob::CreateHttpJobAndStart( void AdapterRequestJob::CreateHttpJobAndStart(
AtomBrowserContext* browser_context, scoped_refptr<net::URLRequestContextGetter> request_context_getter,
const GURL& url, const GURL& url,
const std::string& method, const std::string& method,
const std::string& referrer) { const std::string& referrer) {
@ -124,7 +128,7 @@ void AdapterRequestJob::CreateHttpJobAndStart(
return; return;
} }
real_job_ = new URLRequestFetchJob(browser_context, request(), real_job_ = new URLRequestFetchJob(request_context_getter, request(),
network_delegate(), url, method, referrer); network_delegate(), url, method, referrer);
real_job_->Start(); real_job_->Start();
} }
@ -132,10 +136,13 @@ void AdapterRequestJob::CreateHttpJobAndStart(
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() { void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
real_job_ = protocol_handler_->MaybeCreateJob(request(), real_job_ = protocol_handler_->MaybeCreateJob(request(),
network_delegate()); network_delegate());
if (!real_job_.get()) if (!real_job_.get()) {
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED); CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
else } else {
// Copy headers from original request.
real_job_->SetExtraRequestHeaders(request()->extra_request_headers());
real_job_->Start(); real_job_->Start();
}
} }
} // namespace atom } // namespace atom

View file

@ -10,6 +10,7 @@
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_job.h" #include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h" #include "net/url_request/url_request_job_factory.h"
#include "v8/include/v8.h" #include "v8/include/v8.h"
@ -45,13 +46,15 @@ class AdapterRequestJob : public net::URLRequestJob {
bool GetCharset(std::string* charset) override; bool GetCharset(std::string* charset) override;
void GetResponseInfo(net::HttpResponseInfo* info) override; void GetResponseInfo(net::HttpResponseInfo* info) override;
int GetResponseCode() const override; int GetResponseCode() const override;
void GetLoadTimingInfo(
net::LoadTimingInfo* load_timing_info) const override;
base::WeakPtr<AdapterRequestJob> GetWeakPtr(); base::WeakPtr<AdapterRequestJob> GetWeakPtr();
ProtocolHandler* default_protocol_handler() { return protocol_handler_; } ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
// Override this function to determine which job should be started. // Override this function to determine which job should be started.
virtual void GetJobTypeInUI() = 0; virtual void GetJobType() = 0;
void CreateErrorJobAndStart(int error_code); void CreateErrorJobAndStart(int error_code);
void CreateStringJobAndStart(const std::string& mime_type, void CreateStringJobAndStart(const std::string& mime_type,
@ -61,10 +64,11 @@ class AdapterRequestJob : public net::URLRequestJob {
const std::string& charset, const std::string& charset,
scoped_refptr<base::RefCountedBytes> data); scoped_refptr<base::RefCountedBytes> data);
void CreateFileJobAndStart(const base::FilePath& path); void CreateFileJobAndStart(const base::FilePath& path);
void CreateHttpJobAndStart(AtomBrowserContext* browser_context, void CreateHttpJobAndStart(
const GURL& url, scoped_refptr<net::URLRequestContextGetter> request_context_getter,
const std::string& method, const GURL& url,
const std::string& referrer); const std::string& method,
const std::string& referrer);
void CreateJobFromProtocolHandlerAndStart(); void CreateJobFromProtocolHandlerAndStart();
private: private:

View file

@ -7,13 +7,14 @@
#include <algorithm> #include <algorithm>
#include <string> #include <string>
#include "atom/browser/atom_browser_context.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/http/http_response_headers.h" #include "net/http/http_response_headers.h"
#include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_response_writer.h" #include "net/url_request/url_fetcher_response_writer.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_status.h" #include "net/url_request/url_request_status.h"
namespace atom { namespace atom {
@ -74,7 +75,7 @@ class ResponsePiper : public net::URLFetcherResponseWriter {
} // namespace } // namespace
URLRequestFetchJob::URLRequestFetchJob( URLRequestFetchJob::URLRequestFetchJob(
AtomBrowserContext* browser_context, scoped_refptr<net::URLRequestContextGetter> request_context_getter,
net::URLRequest* request, net::URLRequest* request,
net::NetworkDelegate* network_delegate, net::NetworkDelegate* network_delegate,
const GURL& url, const GURL& url,
@ -90,7 +91,12 @@ URLRequestFetchJob::URLRequestFetchJob(
request_type = GetRequestType(method); request_type = GetRequestType(method);
fetcher_.reset(net::URLFetcher::Create(url, request_type, this)); fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
fetcher_->SetRequestContext(browser_context->url_request_context_getter()); // Use request context if provided else create one.
if (request_context_getter)
fetcher_->SetRequestContext(request_context_getter.get());
else
fetcher_->SetRequestContext(GetRequestContext());
fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this))); fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
// Use |request|'s referrer if |referrer| is not specified. // Use |request|'s referrer if |referrer| is not specified.
@ -101,10 +107,18 @@ URLRequestFetchJob::URLRequestFetchJob(
} }
// Use |request|'s headers. // Use |request|'s headers.
net::HttpRequestHeaders headers; fetcher_->SetExtraRequestHeaders(request->extra_request_headers().ToString());
if (request->GetFullRequestHeaders(&headers)) { }
fetcher_->SetExtraRequestHeaders(headers.ToString());
net::URLRequestContextGetter* URLRequestFetchJob::GetRequestContext() {
if (!url_request_context_getter_.get()) {
auto task_runner = base::ThreadTaskRunnerHandle::Get();
net::URLRequestContextBuilder builder;
builder.set_proxy_service(net::ProxyService::CreateDirect());
url_request_context_getter_ =
new net::TrivialURLRequestContextGetter(builder.Build(), task_runner);
} }
return url_request_context_getter_.get();
} }
void URLRequestFetchJob::HeadersCompleted() { void URLRequestFetchJob::HeadersCompleted() {

View file

@ -7,6 +7,7 @@
#include <string> #include <string>
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_job.h" #include "net/url_request/url_request_job.h"
@ -17,13 +18,14 @@ class AtomBrowserContext;
class URLRequestFetchJob : public net::URLRequestJob, class URLRequestFetchJob : public net::URLRequestJob,
public net::URLFetcherDelegate { public net::URLFetcherDelegate {
public: public:
URLRequestFetchJob(AtomBrowserContext* browser_context, URLRequestFetchJob(scoped_refptr<net::URLRequestContextGetter> context_getter,
net::URLRequest* request, net::URLRequest* request,
net::NetworkDelegate* network_delegate, net::NetworkDelegate* network_delegate,
const GURL& url, const GURL& url,
const std::string& method, const std::string& method,
const std::string& referrer); const std::string& referrer);
net::URLRequestContextGetter* GetRequestContext();
void HeadersCompleted(); void HeadersCompleted();
int DataAvailable(net::IOBuffer* buffer, int num_bytes); int DataAvailable(net::IOBuffer* buffer, int num_bytes);
@ -41,6 +43,7 @@ class URLRequestFetchJob : public net::URLRequestJob,
void OnURLFetchComplete(const net::URLFetcher* source) override; void OnURLFetchComplete(const net::URLFetcher* source) override;
private: private:
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
scoped_ptr<net::URLFetcher> fetcher_; scoped_ptr<net::URLFetcher> fetcher_;
scoped_refptr<net::IOBuffer> pending_buffer_; scoped_refptr<net::IOBuffer> pending_buffer_;
int pending_buffer_size_; int pending_buffer_size_;

View file

@ -17,7 +17,7 @@
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>atom.icns</string> <string>atom.icns</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.29.2</string> <string>0.30.4</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.8.0</string> <string>10.8.0</string>
<key>NSMainNibFile</key> <key>NSMainNibFile</key>

View file

@ -56,8 +56,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,29,2,0 FILEVERSION 0,30,4,0
PRODUCTVERSION 0,29,2,0 PRODUCTVERSION 0,30,4,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -74,12 +74,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "GitHub, Inc." VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron" VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.29.2" VALUE "FileVersion", "0.30.4"
VALUE "InternalName", "electron.exe" VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe" VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron" VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.29.2" VALUE "ProductVersion", "0.30.4"
VALUE "SquirrelAwareVersion", "1" VALUE "SquirrelAwareVersion", "1"
END END
END END

View file

@ -0,0 +1,22 @@
// 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/ui/atom_menu_model.h"
namespace atom {
AtomMenuModel::AtomMenuModel(Delegate* delegate)
: ui::SimpleMenuModel(delegate),
delegate_(delegate) {
}
AtomMenuModel::~AtomMenuModel() {
}
void AtomMenuModel::MenuClosed() {
ui::SimpleMenuModel::MenuClosed();
FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());
}
} // namespace atom

View file

@ -0,0 +1,47 @@
// 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_UI_ATOM_MENU_MODEL_H_
#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
#include "base/observer_list.h"
#include "ui/base/models/simple_menu_model.h"
namespace atom {
class AtomMenuModel : public ui::SimpleMenuModel {
public:
class Delegate : public ui::SimpleMenuModel::Delegate {
public:
virtual ~Delegate() {}
};
class Observer {
public:
virtual ~Observer() {}
// Notifies the menu has been closed.
virtual void MenuClosed() {}
};
explicit AtomMenuModel(Delegate* delegate);
virtual ~AtomMenuModel();
void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
// ui::SimpleMenuModel:
void MenuClosed() override;
private:
Delegate* delegate_; // weak ref.
ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_

View file

@ -5,61 +5,15 @@
#import "atom/browser/ui/cocoa/atom_menu_controller.h" #import "atom/browser/ui/cocoa/atom_menu_controller.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h" #include "ui/base/accelerators/platform_accelerator_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/models/simple_menu_model.h" #include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
namespace {
bool isLeftButtonEvent(NSEvent* event) {
NSEventType type = [event type];
return type == NSLeftMouseDown ||
type == NSLeftMouseDragged ||
type == NSLeftMouseUp;
}
bool isRightButtonEvent(NSEvent* event) {
NSEventType type = [event type];
return type == NSRightMouseDown ||
type == NSRightMouseDragged ||
type == NSRightMouseUp;
}
bool isMiddleButtonEvent(NSEvent* event) {
if ([event buttonNumber] != 2)
return false;
NSEventType type = [event type];
return type == NSOtherMouseDown ||
type == NSOtherMouseDragged ||
type == NSOtherMouseUp;
}
int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
int flags = 0;
flags |= (modifiers & NSAlphaShiftKeyMask) ? ui::EF_CAPS_LOCK_DOWN : 0;
flags |= (modifiers & NSShiftKeyMask) ? ui::EF_SHIFT_DOWN : 0;
flags |= (modifiers & NSControlKeyMask) ? ui::EF_CONTROL_DOWN : 0;
flags |= (modifiers & NSAlternateKeyMask) ? ui::EF_ALT_DOWN : 0;
flags |= (modifiers & NSCommandKeyMask) ? ui::EF_COMMAND_DOWN : 0;
flags |= isLeftButtonEvent(event) ? ui::EF_LEFT_MOUSE_BUTTON : 0;
flags |= isRightButtonEvent(event) ? ui::EF_RIGHT_MOUSE_BUTTON : 0;
flags |= isMiddleButtonEvent(event) ? ui::EF_MIDDLE_MOUSE_BUTTON : 0;
return flags;
}
// Retrieves a bitsum of ui::EventFlags from NSEvent.
int EventFlagsFromNSEvent(NSEvent* event) {
NSUInteger modifiers = [event modifierFlags];
return EventFlagsFromNSEventWithModifiers(event, modifiers);
}
} // namespace
@interface AtomMenuController (Private) @interface AtomMenuController (Private)
- (void)addSeparatorToMenu:(NSMenu*)menu - (void)addSeparatorToMenu:(NSMenu*)menu
atIndex:(int)index; atIndex:(int)index;
@ -166,8 +120,7 @@ int EventFlagsFromNSEvent(NSEvent* event) {
[item setTarget:nil]; [item setTarget:nil];
[item setAction:nil]; [item setAction:nil];
ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index); ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index);
NSMenu* submenu = NSMenu* submenu = [self menuFromModel:submenuModel];
[self menuFromModel:(ui::SimpleMenuModel*)submenuModel];
[submenu setTitle:[item title]]; [submenu setTitle:[item title]];
[item setSubmenu:submenu]; [item setSubmenu:submenu];
@ -246,8 +199,9 @@ int EventFlagsFromNSEvent(NSEvent* event) {
[[sender representedObject] pointerValue]); [[sender representedObject] pointerValue]);
DCHECK(model); DCHECK(model);
if (model) { if (model) {
int event_flags = EventFlagsFromNSEvent([NSApp currentEvent]); NSEvent* event = [NSApp currentEvent];
model->ActivatedAt(modelIndex, event_flags); model->ActivatedAt(modelIndex,
ui::EventFlagsFromModifiers([event modifierFlags]));
} }
} }

View file

@ -18,25 +18,11 @@ namespace file_dialog {
namespace { namespace {
CFStringRef CreateUTIFromExtension(const std::string& ext) {
base::ScopedCFTypeRef<CFStringRef> ext_cf(base::SysUTF8ToCFStringRef(ext));
return UTTypeCreatePreferredIdentifierForTag(
kUTTagClassFilenameExtension, ext_cf.get(), NULL);
}
void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) { void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
NSMutableSet* file_type_set = [NSMutableSet set]; NSMutableSet* file_type_set = [NSMutableSet set];
for (size_t i = 0; i < filters.size(); ++i) { for (size_t i = 0; i < filters.size(); ++i) {
const Filter& filter = filters[i]; const Filter& filter = filters[i];
for (size_t j = 0; j < filter.second.size(); ++j) { for (size_t j = 0; j < filter.second.size(); ++j) {
base::ScopedCFTypeRef<CFStringRef> uti(
CreateUTIFromExtension(filter.second[j]));
[file_type_set addObject:base::mac::CFToNSCast(uti.get())];
// Always allow the extension itself, in case the UTI doesn't map
// back to the original extension correctly. This occurs with dynamic
// UTIs on 10.7 and 10.8.
// See http://crbug.com/148840, http://openradar.me/12316273
base::ScopedCFTypeRef<CFStringRef> ext_cf( base::ScopedCFTypeRef<CFStringRef> ext_cf(
base::SysUTF8ToCFStringRef(filter.second[j])); base::SysUTF8ToCFStringRef(filter.second[j]));
[file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())]; [file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];

View file

@ -27,12 +27,18 @@ enum MessageBoxType {
MESSAGE_BOX_TYPE_QUESTION, MESSAGE_BOX_TYPE_QUESTION,
}; };
enum MessageBoxOptions {
MESSAGE_BOX_NONE = 0,
MESSAGE_BOX_NO_LINK = 1 << 0,
};
typedef base::Callback<void(int code)> MessageBoxCallback; typedef base::Callback<void(int code)> MessageBoxCallback;
int ShowMessageBox(NativeWindow* parent_window, int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
@ -42,6 +48,7 @@ void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,

View file

@ -162,6 +162,7 @@ int ShowMessageBox(NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
@ -174,6 +175,7 @@ void ShowMessageBox(NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,

View file

@ -95,6 +95,7 @@ int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
@ -127,6 +128,7 @@ void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,

View file

@ -10,6 +10,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "atom/browser/browser.h"
#include "atom/browser/native_window_views.h" #include "atom/browser/native_window_views.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
@ -72,6 +73,7 @@ int ShowMessageBoxUTF16(HWND parent,
MessageBoxType type, MessageBoxType type,
const std::vector<base::string16>& buttons, const std::vector<base::string16>& buttons,
int cancel_id, int cancel_id,
int options,
const base::string16& title, const base::string16& title,
const base::string16& message, const base::string16& message,
const base::string16& detail, const base::string16& detail,
@ -86,7 +88,12 @@ int ShowMessageBoxUTF16(HWND parent,
config.hInstance = GetModuleHandle(NULL); config.hInstance = GetModuleHandle(NULL);
config.dwFlags = flags; config.dwFlags = flags;
if (!title.empty()) // TaskDialogIndirect doesn't allow empty name, if we set empty title it
// will show "electron.exe" in title.
base::string16 app_name = base::UTF8ToUTF16(Browser::Get()->GetName());
if (title.empty())
config.pszWindowTitle = app_name.c_str();
else
config.pszWindowTitle = title.c_str(); config.pszWindowTitle = title.c_str();
base::win::ScopedHICON hicon; base::win::ScopedHICON hicon;
@ -122,11 +129,17 @@ int ShowMessageBoxUTF16(HWND parent,
// and custom buttons in pButtons. // and custom buttons in pButtons.
std::map<int, int> id_map; std::map<int, int> id_map;
std::vector<TASKDIALOG_BUTTON> dialog_buttons; std::vector<TASKDIALOG_BUTTON> dialog_buttons;
MapToCommonID(buttons, &id_map, &config.dwCommonButtons, &dialog_buttons); if (options & MESSAGE_BOX_NO_LINK) {
for (size_t i = 0; i < buttons.size(); ++i)
dialog_buttons.push_back({i + kIDStart, buttons[i].c_str()});
} else {
MapToCommonID(buttons, &id_map, &config.dwCommonButtons, &dialog_buttons);
}
if (dialog_buttons.size() > 0) { if (dialog_buttons.size() > 0) {
config.pButtons = &dialog_buttons.front(); config.pButtons = &dialog_buttons.front();
config.cButtons = dialog_buttons.size(); config.cButtons = dialog_buttons.size();
config.dwFlags |= TDF_USE_COMMAND_LINKS; // custom buttons as links. if (!(options & MESSAGE_BOX_NO_LINK))
config.dwFlags |= TDF_USE_COMMAND_LINKS; // custom buttons as links.
} }
int id = 0; int id = 0;
@ -144,13 +157,14 @@ void RunMessageBoxInNewThread(base::Thread* thread,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
int result = ShowMessageBox(parent, type, buttons, cancel_id, title, message, int result = ShowMessageBox(parent, type, buttons, cancel_id, options, title,
detail, icon); message, detail, icon);
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result)); content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
content::BrowserThread::DeleteSoon( content::BrowserThread::DeleteSoon(
@ -163,6 +177,7 @@ int ShowMessageBox(NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
@ -180,6 +195,7 @@ int ShowMessageBox(NativeWindow* parent,
type, type,
utf16_buttons, utf16_buttons,
cancel_id, cancel_id,
options,
base::UTF8ToUTF16(title), base::UTF8ToUTF16(title),
base::UTF8ToUTF16(message), base::UTF8ToUTF16(message),
base::UTF8ToUTF16(detail), base::UTF8ToUTF16(detail),
@ -190,6 +206,7 @@ void ShowMessageBox(NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int cancel_id, int cancel_id,
int options,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
@ -207,12 +224,12 @@ void ShowMessageBox(NativeWindow* parent,
unretained->message_loop()->PostTask( unretained->message_loop()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained), base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained),
parent, type, buttons, cancel_id, title, message, detail, icon, parent, type, buttons, cancel_id, options, title, message,
callback)); detail, icon, callback));
} }
void ShowErrorBox(const base::string16& title, const base::string16& content) { void ShowErrorBox(const base::string16& title, const base::string16& content) {
ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, 0, L"Error", title, ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, 0, 0, L"Error", title,
content, gfx::ImageSkia()); content, gfx::ImageSkia());
} }

View file

@ -26,12 +26,16 @@ void TrayIcon::DisplayBalloon(const gfx::Image& icon,
const base::string16& contents) { const base::string16& contents) {
} }
void TrayIcon::NotifyClicked(const gfx::Rect& bounds) { void TrayIcon::PopUpContextMenu(const gfx::Point& pos) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds));
} }
void TrayIcon::NotifyDoubleClicked() { void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDoubleClicked()); FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds, modifiers));
}
void TrayIcon::NotifyDoubleClicked(const gfx::Rect& bounds, int modifiers) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_,
OnDoubleClicked(bounds, modifiers));
} }
void TrayIcon::NotifyBalloonShow() { void TrayIcon::NotifyBalloonShow() {
@ -46,4 +50,13 @@ void TrayIcon::NotifyBalloonClosed() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClosed()); FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClosed());
} }
void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds, int modifiers) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_,
OnRightClicked(bounds, modifiers));
}
void TrayIcon::NotfiyDropFiles(const std::vector<std::string>& files) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files));
}
} // namespace atom } // namespace atom

View file

@ -6,6 +6,7 @@
#define ATOM_BROWSER_UI_TRAY_ICON_H_ #define ATOM_BROWSER_UI_TRAY_ICON_H_
#include <string> #include <string>
#include <vector>
#include "atom/browser/ui/tray_icon_observer.h" #include "atom/browser/ui/tray_icon_observer.h"
#include "base/observer_list.h" #include "base/observer_list.h"
@ -46,16 +47,21 @@ class TrayIcon {
const base::string16& title, const base::string16& title,
const base::string16& contents); const base::string16& contents);
virtual void PopUpContextMenu(const gfx::Point& pos);
// Set the context menu for this icon. // Set the context menu for this icon.
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0; virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0;
void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); } void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); }
void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); } void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); }
void NotifyClicked(const gfx::Rect& = gfx::Rect()); void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
void NotifyDoubleClicked(); void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
void NotifyBalloonShow(); void NotifyBalloonShow();
void NotifyBalloonClicked(); void NotifyBalloonClicked();
void NotifyBalloonClosed(); void NotifyBalloonClosed();
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(),
int modifiers = 0);
void NotfiyDropFiles(const std::vector<std::string>& files);
protected: protected:
TrayIcon(); TrayIcon();

View file

@ -9,15 +9,17 @@
#include <string> #include <string>
#include "atom/browser/ui/atom_menu_model.h"
#include "atom/browser/ui/tray_icon.h" #include "atom/browser/ui/tray_icon.h"
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
@class AtomMenuController; @class AtomMenuController;
@class StatusItemController; @class StatusItemView;
namespace atom { namespace atom {
class TrayIconCocoa : public TrayIcon { class TrayIconCocoa : public TrayIcon,
public AtomMenuModel::Observer {
public: public:
TrayIconCocoa(); TrayIconCocoa();
virtual ~TrayIconCocoa(); virtual ~TrayIconCocoa();
@ -27,16 +29,23 @@ class TrayIconCocoa : public TrayIcon {
void SetToolTip(const std::string& tool_tip) override; void SetToolTip(const std::string& tool_tip) override;
void SetTitle(const std::string& title) override; void SetTitle(const std::string& title) override;
void SetHighlightMode(bool highlight) override; void SetHighlightMode(bool highlight) override;
void PopUpContextMenu(const gfx::Point& pos) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private: protected:
base::scoped_nsobject<NSStatusItem> item_; // AtomMenuModel::Observer:
void MenuClosed() override;
base::scoped_nsobject<StatusItemController> controller_; private:
// Atom custom view for NSStatusItem.
base::scoped_nsobject<StatusItemView> status_item_view_;
// Status menu shown when right-clicking the system icon. // Status menu shown when right-clicking the system icon.
base::scoped_nsobject<AtomMenuController> menu_; base::scoped_nsobject<AtomMenuController> menu_;
// Used for unregistering observer.
AtomMenuModel* menu_model_; // weak ref.
DISALLOW_COPY_AND_ASSIGN(TrayIconCocoa); DISALLOW_COPY_AND_ASSIGN(TrayIconCocoa);
}; };

View file

@ -6,84 +6,333 @@
#include "atom/browser/ui/cocoa/atom_menu_controller.h" #include "atom/browser/ui/cocoa/atom_menu_controller.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
@interface StatusItemController : NSObject { namespace {
// By default, OS X sets 4px to tray image as left and right padding margin.
const CGFloat kHorizontalMargin = 4;
// OS X tends to make the title 2px lower.
const CGFloat kVerticalTitleMargin = 2;
} // namespace
@interface StatusItemView : NSView {
atom::TrayIconCocoa* trayIcon_; // weak atom::TrayIconCocoa* trayIcon_; // weak
AtomMenuController* menuController_; // weak
BOOL isHighlightEnable_;
BOOL inMouseEventSequence_;
base::scoped_nsobject<NSImage> image_;
base::scoped_nsobject<NSImage> alternateImage_;
base::scoped_nsobject<NSImageView> image_view_;
base::scoped_nsobject<NSString> title_;
base::scoped_nsobject<NSStatusItem> statusItem_;
} }
- (id)initWithIcon:(atom::TrayIconCocoa*)icon;
- (void)handleClick:(id)sender;
- (void)handleDoubleClick:(id)sender;
@end // @interface StatusItemController @end // @interface StatusItemView
@implementation StatusItemController @implementation StatusItemView
- (id)initWithIcon:(atom::TrayIconCocoa*)icon { - (id)initWithImage:(NSImage*)image icon:(atom::TrayIconCocoa*)icon {
image_.reset([image copy]);
trayIcon_ = icon; trayIcon_ = icon;
isHighlightEnable_ = YES;
// Get the initial size.
NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
NSRect frame = NSMakeRect(0, 0, [self fullWidth], [statusBar thickness]);
if ((self = [super initWithFrame:frame])) {
// Setup the image view.
NSRect iconFrame = frame;
iconFrame.size.width = [self iconWidth];
image_view_.reset([[NSImageView alloc] initWithFrame:iconFrame]);
[image_view_ setImageScaling:NSImageScaleNone];
[image_view_ setImageAlignment:NSImageAlignCenter];
[self addSubview:image_view_];
// Unregister image_view_ as a dragged destination, allows its parent view
// (StatusItemView) handle dragging events.
[image_view_ unregisterDraggedTypes];
NSArray* types = [NSArray arrayWithObjects:NSFilenamesPboardType, nil];
[self registerForDraggedTypes:types];
// Create the status item.
statusItem_.reset([[[NSStatusBar systemStatusBar]
statusItemWithLength:NSWidth(frame)] retain]);
[statusItem_ setView:self];
}
return self; return self;
} }
- (void)handleClick:(id)sender { - (void)removeItem {
// Get the frame of the NSStatusItem. [[NSStatusBar systemStatusBar] removeStatusItem:statusItem_];
NSRect frame = [NSApp currentEvent].window.frame; statusItem_.reset();
}
- (void)drawRect:(NSRect)dirtyRect {
// Draw the tray icon and title that align with NSStatusItem, layout:
// ----------------
// | icon | title |
/// ----------------
// Draw background.
BOOL highlight = [self shouldHighlight];
CGFloat thickness = [[statusItem_ statusBar] thickness];
NSRect statusItemBounds = NSMakeRect(0, 0, [statusItem_ length], thickness);
[statusItem_ drawStatusBarBackgroundInRect:statusItemBounds
withHighlight:highlight];
// Make use of NSImageView to draw the image, which can correctly draw
// template image under dark menu bar.
if (highlight && alternateImage_ &&
[image_view_ image] != alternateImage_.get()) {
[image_view_ setImage:alternateImage_];
} else if ([image_view_ image] != image_.get()) {
[image_view_ setImage:image_];
}
if (title_) {
// Highlight the text when icon is highlighted or in dark mode.
highlight |= [self isDarkMode];
// Draw title.
NSRect titleDrawRect = NSMakeRect(
[self iconWidth], -kVerticalTitleMargin, [self titleWidth], thickness);
[title_ drawInRect:titleDrawRect
withAttributes:[self titleAttributesWithHighlight:highlight]];
}
}
- (BOOL)isDarkMode {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSString* mode = [defaults stringForKey:@"AppleInterfaceStyle"];
return mode && [mode isEqualToString:@"Dark"];
}
// The width of the full status item.
- (CGFloat)fullWidth {
if (title_)
return [self iconWidth] + [self titleWidth] + kHorizontalMargin;
else
return [self iconWidth];
}
// The width of the icon.
- (CGFloat)iconWidth {
CGFloat thickness = [[NSStatusBar systemStatusBar] thickness];
CGFloat imageHeight = [image_ size].height;
CGFloat imageWidth = [image_ size].width;
CGFloat iconWidth = imageWidth;
if (imageWidth < thickness) {
// Image's width must be larger than menu bar's height.
iconWidth = thickness;
} else {
CGFloat verticalMargin = thickness - imageHeight;
// Image must have same horizontal vertical margin.
if (verticalMargin > 0 && imageWidth != imageHeight)
iconWidth = imageWidth + verticalMargin;
CGFloat horizontalMargin = thickness - imageWidth;
// Image must have at least kHorizontalMargin horizontal margin on each
// side.
if (horizontalMargin < 2 * kHorizontalMargin)
iconWidth = imageWidth + 2 * kHorizontalMargin;
}
return iconWidth;
}
// The width of the title.
- (CGFloat)titleWidth {
if (!title_)
return 0;
base::scoped_nsobject<NSAttributedString> attributes(
[[NSAttributedString alloc] initWithString:title_
attributes:[self titleAttributes]]);
return [attributes size].width;
}
- (NSDictionary*)titleAttributesWithHighlight:(BOOL)highlight {
NSFont* font = [NSFont menuBarFontOfSize:0];
NSColor* foregroundColor = highlight ?
[NSColor whiteColor] :
[NSColor colorWithRed:0.265625 green:0.25390625 blue:0.234375 alpha:1.0];
return [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
foregroundColor, NSForegroundColorAttributeName,
nil];
}
- (NSDictionary*)titleAttributes {
return [self titleAttributesWithHighlight:[self isDarkMode]];
}
- (void)setImage:(NSImage*)image {
image_.reset([image copy]);
[self setNeedsDisplay:YES];
}
- (void)setAlternateImage:(NSImage*)image {
alternateImage_.reset([image copy]);
}
- (void)setHighlight:(BOOL)highlight {
isHighlightEnable_ = highlight;
}
- (void)setTitle:(NSString*)title {
if (title.length > 0)
title_.reset([title copy]);
else
title_.reset();
[statusItem_ setLength:[self fullWidth]];
[self setNeedsDisplay:YES];
}
- (void)setMenuController:(AtomMenuController*)menu {
menuController_ = menu;
}
- (void)mouseDown:(NSEvent*)event {
inMouseEventSequence_ = YES;
[self setNeedsDisplay:YES];
}
- (void)mouseUp:(NSEvent*)event {
if (!inMouseEventSequence_) {
// If the menu is showing, when user clicked the tray icon, the `mouseDown`
// event will be dissmissed, we need to close the menu at this time.
[self setNeedsDisplay:YES];
return;
}
inMouseEventSequence_ = NO;
// Show menu when single clicked on the icon.
if (event.clickCount == 1 && menuController_)
[statusItem_ popUpStatusItemMenu:[menuController_ menu]];
// Don't emit click events when menu is showing.
if (menuController_)
return;
// Single click event.
if (event.clickCount == 1)
trayIcon_->NotifyClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
// Double click event.
if (event.clickCount == 2)
trayIcon_->NotifyDoubleClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
[self setNeedsDisplay:YES];
}
- (void)popUpContextMenu {
if (menuController_ && ![menuController_ isMenuOpen]) {
// Redraw the dray icon to show highlight if it is enabled.
[self setNeedsDisplay:YES];
[statusItem_ popUpStatusItemMenu:[menuController_ menu]];
// The popUpStatusItemMenu returns only after the showing menu is closed.
// When it returns, we need to redraw the tray icon to not show highlight.
[self setNeedsDisplay:YES];
}
}
- (void)rightMouseUp:(NSEvent*)event {
trayIcon_->NotifyRightClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
return NSDragOperationCopy;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
NSPasteboard* pboard = [sender draggingPasteboard];
if ([[pboard types] containsObject:NSFilenamesPboardType]) {
std::vector<std::string> dropFiles;
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for (NSString* file in files)
dropFiles.push_back(base::SysNSStringToUTF8(file));
trayIcon_->NotfiyDropFiles(dropFiles);
return YES;
}
return NO;
}
- (BOOL)shouldHighlight {
BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen];
return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen);
}
- (gfx::Rect)getBoundsFromEvent:(NSEvent*)event {
NSRect frame = event.window.frame;
gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame)); gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
// Flip coordinates to gfx (0,0 in top-left corner) using current screen.
NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame)); bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
return bounds;
trayIcon_->NotifyClicked(bounds);
} }
- (void)handleDoubleClick:(id)sender {
trayIcon_->NotifyDoubleClicked();
}
@end @end
namespace atom { namespace atom {
TrayIconCocoa::TrayIconCocoa() { TrayIconCocoa::TrayIconCocoa() : menu_model_(nullptr) {
controller_.reset([[StatusItemController alloc] initWithIcon:this]);
item_.reset([[[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength] retain]);
[item_ setEnabled:YES];
[item_ setTarget:controller_];
[item_ setAction:@selector(handleClick:)];
[item_ setDoubleAction:@selector(handleDoubleClick:)];
[item_ setHighlightMode:YES];
} }
TrayIconCocoa::~TrayIconCocoa() { TrayIconCocoa::~TrayIconCocoa() {
// Remove the status item from the status bar. [status_item_view_ removeItem];
[[NSStatusBar systemStatusBar] removeStatusItem:item_]; if (menu_model_)
menu_model_->RemoveObserver(this);
} }
void TrayIconCocoa::SetImage(const gfx::Image& image) { void TrayIconCocoa::SetImage(const gfx::Image& image) {
[item_ setImage:image.AsNSImage()]; if (status_item_view_) {
[status_item_view_ setImage:image.AsNSImage()];
} else {
status_item_view_.reset(
[[StatusItemView alloc] initWithImage:image.AsNSImage()
icon:this]);
}
} }
void TrayIconCocoa::SetPressedImage(const gfx::Image& image) { void TrayIconCocoa::SetPressedImage(const gfx::Image& image) {
[item_ setAlternateImage:image.AsNSImage()]; [status_item_view_ setAlternateImage:image.AsNSImage()];
} }
void TrayIconCocoa::SetToolTip(const std::string& tool_tip) { void TrayIconCocoa::SetToolTip(const std::string& tool_tip) {
[item_ setToolTip:base::SysUTF8ToNSString(tool_tip)]; [status_item_view_ setToolTip:base::SysUTF8ToNSString(tool_tip)];
} }
void TrayIconCocoa::SetTitle(const std::string& title) { void TrayIconCocoa::SetTitle(const std::string& title) {
[item_ setTitle:base::SysUTF8ToNSString(title)]; [status_item_view_ setTitle:base::SysUTF8ToNSString(title)];
} }
void TrayIconCocoa::SetHighlightMode(bool highlight) { void TrayIconCocoa::SetHighlightMode(bool highlight) {
[item_ setHighlightMode:highlight]; [status_item_view_ setHighlight:highlight];
}
void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos) {
[status_item_view_ popUpContextMenu];
} }
void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) { void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) {
// Substribe to MenuClosed event.
if (menu_model_)
menu_model_->RemoveObserver(this);
static_cast<AtomMenuModel*>(menu_model)->AddObserver(this);
// Create native menu.
menu_.reset([[AtomMenuController alloc] initWithModel:menu_model]); menu_.reset([[AtomMenuController alloc] initWithModel:menu_model]);
[item_ setMenu:[menu_ menu]]; [status_item_view_ setMenuController:menu_.get()];
}
void TrayIconCocoa::MenuClosed() {
[status_item_view_ setNeedsDisplay:YES];
} }
// static // static

View file

@ -5,6 +5,9 @@
#ifndef ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_ #ifndef ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_
#define ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_ #define ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_
#include <string>
#include <vector>
namespace gfx { namespace gfx {
class Rect; class Rect;
} }
@ -13,11 +16,13 @@ namespace atom {
class TrayIconObserver { class TrayIconObserver {
public: public:
virtual void OnClicked(const gfx::Rect&) {} virtual void OnClicked(const gfx::Rect& bounds, int modifiers) {}
virtual void OnDoubleClicked() {} virtual void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {}
virtual void OnBalloonShow() {} virtual void OnBalloonShow() {}
virtual void OnBalloonClicked() {} virtual void OnBalloonClicked() {}
virtual void OnBalloonClosed() {} virtual void OnBalloonClosed() {}
virtual void OnRightClicked(const gfx::Rect& bounds, int modifiers) {}
virtual void OnDropFiles(const std::vector<std::string>& files) {}
protected: protected:
virtual ~TrayIconObserver() {} virtual ~TrayIconObserver() {}

View file

@ -0,0 +1,35 @@
// 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/ui/views/native_frame_view.h"
#include "atom/browser/native_window_views.h"
namespace atom {
namespace {
const char kViewClassName[] = "AtomNativeFrameView";
} // namespace
NativeFrameView::NativeFrameView(NativeWindowViews* window,
views::Widget* widget)
: views::NativeFrameView(widget),
window_(window) {
}
gfx::Size NativeFrameView::GetMinimumSize() const {
return window_->GetMinimumSize();
}
gfx::Size NativeFrameView::GetMaximumSize() const {
return window_->GetMaximumSize();
}
const char* NativeFrameView::GetClassName() const {
return kViewClassName;
}
} // namespace atom

View file

@ -0,0 +1,34 @@
// 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_UI_VIEWS_NATIVE_FRAME_VIEW_H_
#define ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_
#include "ui/views/window/native_frame_view.h"
namespace atom {
class NativeWindowViews;
// Like the views::NativeFrameView, but returns the min/max size from the
// NativeWindowViews.
class NativeFrameView : public views::NativeFrameView {
public:
NativeFrameView(NativeWindowViews* window, views::Widget* widget);
protected:
// views::View:
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
const char* GetClassName() const override;
private:
NativeWindowViews* window_; // weak ref.
DISALLOW_COPY_AND_ASSIGN(NativeFrameView);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_

View file

@ -0,0 +1,28 @@
// 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/ui/win/atom_desktop_window_tree_host_win.h"
#include "atom/browser/ui/win/message_handler_delegate.h"
namespace atom {
AtomDesktopWindowTreeHostWin::AtomDesktopWindowTreeHostWin(
MessageHandlerDelegate* delegate,
views::internal::NativeWidgetDelegate* native_widget_delegate,
views::DesktopNativeWidgetAura* desktop_native_widget_aura)
: views::DesktopWindowTreeHostWin(native_widget_delegate,
desktop_native_widget_aura),
delegate_(delegate) {
}
AtomDesktopWindowTreeHostWin::~AtomDesktopWindowTreeHostWin() {
}
bool AtomDesktopWindowTreeHostWin::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
return delegate_->PreHandleMSG(message, w_param, l_param, result);
}
} // namespace atom

View file

@ -0,0 +1,39 @@
// 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_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_
#define ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_
#include <windows.h>
#include <vector>
#include "atom/browser/native_window.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
namespace atom {
class MessageHandlerDelegate;
class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin {
public:
AtomDesktopWindowTreeHostWin(
MessageHandlerDelegate* delegate,
views::internal::NativeWidgetDelegate* native_widget_delegate,
views::DesktopNativeWidgetAura* desktop_native_widget_aura);
~AtomDesktopWindowTreeHostWin() override;
protected:
bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
private:
MessageHandlerDelegate* delegate_; // weak ref
DISALLOW_COPY_AND_ASSIGN(AtomDesktopWindowTreeHostWin);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_

View file

@ -0,0 +1,14 @@
// 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/ui/win/message_handler_delegate.h"
namespace atom {
bool MessageHandlerDelegate::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
return false;
}
} // namespace atom

View file

@ -0,0 +1,26 @@
// 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_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_
#define ATOM_BROWSER_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_
#include <windows.h>
namespace atom {
class MessageHandlerDelegate {
public:
// Catch-all message handling and filtering. Called before
// HWNDMessageHandler's built-in handling, which may pre-empt some
// expectations in Views/Aura if messages are consumed. Returns true if the
// message was consumed by the delegate and should not be processed further
// by the HWNDMessageHandler. In this case, |result| is returned. |result| is
// not modified otherwise.
virtual bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_

View file

@ -4,7 +4,10 @@
#include "atom/browser/ui/win/notify_icon.h" #include "atom/browser/ui/win/notify_icon.h"
#include <shobjidl.h>
#include "atom/browser/ui/win/notify_icon_host.h" #include "atom/browser/ui/win/notify_icon_host.h"
#include "base/md5.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
@ -25,10 +28,34 @@ NotifyIcon::NotifyIcon(NotifyIconHost* host,
icon_id_(id), icon_id_(id),
window_(window), window_(window),
message_id_(message), message_id_(message),
menu_model_(NULL) { menu_model_(NULL),
has_tray_app_id_hash_(false) {
// NB: If we have an App Model ID, we should propagate that to the tray.
// Doing this prevents duplicate items from showing up in the notification
// preferences (i.e. "Always Show / Show notifications only / etc")
PWSTR explicit_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&explicit_app_id))) {
// GUIDs and MD5 hashes are the same length. So convenient!
base::MD5Sum(explicit_app_id,
sizeof(wchar_t) * wcslen(explicit_app_id),
reinterpret_cast<base::MD5Digest*>(&tray_app_id_hash_));
// Set the GUID to version 4 as described in RFC 4122, section 4.4.
// The format of GUID version 4 must be like
// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where y is one of [8, 9, A, B].
tray_app_id_hash_.Data3 &= 0x0fff;
tray_app_id_hash_.Data3 |= 0x4000;
// Set y to one of [8, 9, A, B].
tray_app_id_hash_.Data4[0] = 1;
has_tray_app_id_hash_ = true;
CoTaskMemFree(explicit_app_id);
}
NOTIFYICONDATA icon_data; NOTIFYICONDATA icon_data;
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags = NIF_MESSAGE; icon_data.uFlags |= NIF_MESSAGE;
icon_data.uCallbackMessage = message_id_; icon_data.uCallbackMessage = message_id_;
BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data);
// This can happen if the explorer process isn't running when we try to // This can happen if the explorer process isn't running when we try to
@ -46,39 +73,34 @@ NotifyIcon::~NotifyIcon() {
} }
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos, void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
bool left_mouse_click) { int modifiers,
// Pass to the observer if appropriate. bool left_mouse_click,
bool double_button_click) {
NOTIFYICONIDENTIFIER icon_id;
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
icon_id.uID = icon_id_;
icon_id.hWnd = window_;
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
if (has_tray_app_id_hash_)
memcpy(reinterpret_cast<void*>(&icon_id.guidItem),
&tray_app_id_hash_,
sizeof(GUID));
RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect);
if (left_mouse_click) { if (left_mouse_click) {
NOTIFYICONIDENTIFIER icon_id; if (double_button_click) // double left click
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER)); NotifyDoubleClicked(gfx::Rect(rect), modifiers);
icon_id.uID = icon_id_; else // single left click
icon_id.hWnd = window_; NotifyClicked(gfx::Rect(rect), modifiers);
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect);
NotifyClicked(gfx::Rect(rect));
return; return;
} else if (!double_button_click) { // single right click
if (menu_model_)
PopUpContextMenu(cursor_pos);
else
NotifyRightClicked(gfx::Rect(rect), modifiers);
} }
if (!menu_model_)
return;
// Set our window as the foreground window, so the context menu closes when
// we click away from it.
if (!SetForegroundWindow(window_))
return;
views::MenuRunner menu_runner(
menu_model_,
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
ignore_result(menu_runner.RunMenuAt(
NULL,
NULL,
gfx::Rect(cursor_pos, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
} }
void NotifyIcon::ResetIcon() { void NotifyIcon::ResetIcon() {
@ -87,7 +109,7 @@ void NotifyIcon::ResetIcon() {
// Delete any previously existing icon. // Delete any previously existing icon.
Shell_NotifyIcon(NIM_DELETE, &icon_data); Shell_NotifyIcon(NIM_DELETE, &icon_data);
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags = NIF_MESSAGE; icon_data.uFlags |= NIF_MESSAGE;
icon_data.uCallbackMessage = message_id_; icon_data.uCallbackMessage = message_id_;
icon_data.hIcon = icon_.Get(); icon_data.hIcon = icon_.Get();
// If we have an image, then set the NIF_ICON flag, which tells // If we have an image, then set the NIF_ICON flag, which tells
@ -104,7 +126,7 @@ void NotifyIcon::SetImage(const gfx::Image& image) {
// Create the icon. // Create the icon.
NOTIFYICONDATA icon_data; NOTIFYICONDATA icon_data;
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags = NIF_ICON; icon_data.uFlags |= NIF_ICON;
icon_.Set(IconUtil::CreateHICONFromSkBitmap(image.AsBitmap())); icon_.Set(IconUtil::CreateHICONFromSkBitmap(image.AsBitmap()));
icon_data.hIcon = icon_.Get(); icon_data.hIcon = icon_.Get();
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
@ -121,7 +143,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
// Create the icon. // Create the icon.
NOTIFYICONDATA icon_data; NOTIFYICONDATA icon_data;
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags = NIF_TIP; icon_data.uFlags |= NIF_TIP;
wcscpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str()); wcscpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str());
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
if (!result) if (!result)
@ -133,7 +155,7 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
const base::string16& contents) { const base::string16& contents) {
NOTIFYICONDATA icon_data; NOTIFYICONDATA icon_data;
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags = NIF_INFO; icon_data.uFlags |= NIF_INFO;
icon_data.dwInfoFlags = NIIF_INFO; icon_data.dwInfoFlags = NIIF_INFO;
wcscpy_s(icon_data.szInfoTitle, title.c_str()); wcscpy_s(icon_data.szInfoTitle, title.c_str());
wcscpy_s(icon_data.szInfo, contents.c_str()); wcscpy_s(icon_data.szInfo, contents.c_str());
@ -151,6 +173,26 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
LOG(WARNING) << "Unable to create status tray balloon."; LOG(WARNING) << "Unable to create status tray balloon.";
} }
void NotifyIcon::PopUpContextMenu(const gfx::Point& pos) {
// Returns if context menu isn't set.
if (!menu_model_)
return;
// Set our window as the foreground window, so the context menu closes when
// we click away from it.
if (!SetForegroundWindow(window_))
return;
views::MenuRunner menu_runner(
menu_model_,
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
ignore_result(menu_runner.RunMenuAt(
NULL,
NULL,
gfx::Rect(pos, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
}
void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) { void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
menu_model_ = menu_model; menu_model_ = menu_model;
} }
@ -160,6 +202,13 @@ void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
icon_data->cbSize = sizeof(NOTIFYICONDATA); icon_data->cbSize = sizeof(NOTIFYICONDATA);
icon_data->hWnd = window_; icon_data->hWnd = window_;
icon_data->uID = icon_id_; icon_data->uID = icon_id_;
if (has_tray_app_id_hash_) {
icon_data->uFlags |= NIF_GUID;
memcpy(reinterpret_cast<void*>(&icon_data->guidItem),
&tray_app_id_hash_,
sizeof(GUID));
}
} }
} // namespace atom } // namespace atom

View file

@ -33,7 +33,10 @@ class NotifyIcon : public TrayIcon {
// Handles a click event from the user - if |left_button_click| is true and // Handles a click event from the user - if |left_button_click| is true and
// there is a registered observer, passes the click event to the observer, // there is a registered observer, passes the click event to the observer,
// otherwise displays the context menu if there is one. // otherwise displays the context menu if there is one.
void HandleClickEvent(const gfx::Point& cursor_pos, bool left_button_click); void HandleClickEvent(const gfx::Point& cursor_pos,
int modifiers,
bool left_button_click,
bool double_button_click);
// Re-creates the status tray icon now after the taskbar has been created. // Re-creates the status tray icon now after the taskbar has been created.
void ResetIcon(); void ResetIcon();
@ -49,6 +52,7 @@ class NotifyIcon : public TrayIcon {
void DisplayBalloon(const gfx::Image& icon, void DisplayBalloon(const gfx::Image& icon,
const base::string16& title, const base::string16& title,
const base::string16& contents) override; const base::string16& contents) override;
void PopUpContextMenu(const gfx::Point& pos) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private: private:
@ -75,6 +79,10 @@ class NotifyIcon : public TrayIcon {
// The context menu. // The context menu.
ui::SimpleMenuModel* menu_model_; ui::SimpleMenuModel* menu_model_;
// A hash of the app model ID
GUID tray_app_id_hash_;
bool has_tray_app_id_hash_;
DISALLOW_COPY_AND_ASSIGN(NotifyIcon); DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
}; };

View file

@ -5,13 +5,16 @@
#include "atom/browser/ui/win/notify_icon_host.h" #include "atom/browser/ui/win/notify_icon_host.h"
#include <commctrl.h> #include <commctrl.h>
#include <winuser.h>
#include "atom/browser/ui/win/notify_icon.h" #include "atom/browser/ui/win/notify_icon.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/threading/non_thread_safe.h" #include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/win/win_util.h"
#include "base/win/wrapped_window_proc.h" #include "base/win/wrapped_window_proc.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
#include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/win/hwnd_util.h"
@ -26,6 +29,24 @@ const UINT kBaseIconId = 2;
const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow"; const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow";
bool IsWinPressed() {
return ((::GetKeyState(VK_LWIN) & 0x8000) == 0x8000) ||
((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000);
}
int GetKeyboardModifers() {
int modifiers = ui::EF_NONE;
if (base::win::IsShiftPressed())
modifiers |= ui::EF_SHIFT_DOWN;
if (base::win::IsCtrlPressed())
modifiers |= ui::EF_CONTROL_DOWN;
if (base::win::IsAltPressed())
modifiers |= ui::EF_ALT_DOWN;
if (IsWinPressed())
modifiers |= ui::EF_COMMAND_DOWN;
return modifiers;
}
} // namespace } // namespace
NotifyIconHost::NotifyIconHost() NotifyIconHost::NotifyIconHost()
@ -146,12 +167,18 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_CONTEXTMENU: case WM_CONTEXTMENU:
// Walk our icons, find which one was clicked on, and invoke its // Walk our icons, find which one was clicked on, and invoke its
// HandleClickEvent() method. // HandleClickEvent() method.
gfx::Point cursor_pos( gfx::Point cursor_pos(
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint()); gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN); win_icon->HandleClickEvent(
cursor_pos,
GetKeyboardModifers(),
(lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
(lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK));
return TRUE; return TRUE;
} }
} }

View file

@ -0,0 +1,165 @@
// 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/ui/win/taskbar_host.h"
#include <string>
#include "base/stl_util.h"
#include "base/win/scoped_gdi_object.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/icon_util.h"
namespace atom {
namespace {
// From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#thumbbars
// The thumbnail toolbar has a maximum of seven buttons due to the limited room.
const size_t kMaxButtonsCount = 7;
// The base id of Thumbar button.
const int kButtonIdBase = 40001;
bool GetThumbarButtonFlags(const std::vector<std::string>& flags,
THUMBBUTTONFLAGS* out) {
THUMBBUTTONFLAGS result = THBF_ENABLED; // THBF_ENABLED == 0
for (const auto& flag : flags) {
if (flag == "disabled")
result |= THBF_DISABLED;
else if (flag == "dismissonclick")
result |= THBF_DISMISSONCLICK;
else if (flag == "nobackground")
result |= THBF_NOBACKGROUND;
else if (flag == "hidden")
result |= THBF_HIDDEN;
else if (flag == "noninteractive")
result |= THBF_NONINTERACTIVE;
else
return false;
}
*out = result;
return true;
}
} // namespace
TaskbarHost::TaskbarHost() : thumbar_buttons_added_(false) {
}
TaskbarHost::~TaskbarHost() {
}
bool TaskbarHost::SetThumbarButtons(
HWND window, const std::vector<ThumbarButton>& buttons) {
if (buttons.size() > kMaxButtonsCount || !InitailizeTaskbar())
return false;
callback_map_.clear();
// The number of buttons in thumbar can not be changed once it is created,
// so we have to claim kMaxButtonsCount buttons initialy in case users add
// more buttons later.
base::win::ScopedHICON icons[kMaxButtonsCount] = {};
THUMBBUTTON thumb_buttons[kMaxButtonsCount] = {};
for (size_t i = 0; i < kMaxButtonsCount; ++i) {
THUMBBUTTON& thumb_button = thumb_buttons[i];
// Set ID.
thumb_button.iId = kButtonIdBase + i;
thumb_button.dwMask = THB_FLAGS;
if (i >= buttons.size()) {
// This button is used to occupy the place in toolbar, and it does not
// show.
thumb_button.dwFlags = THBF_HIDDEN;
continue;
}
// This button is user's button.
const ThumbarButton& button = buttons[i];
// Generate flags.
thumb_button.dwFlags = THBF_ENABLED;
if (!GetThumbarButtonFlags(button.flags, &thumb_button.dwFlags))
return false;
// Set icon.
if (!button.icon.IsEmpty()) {
thumb_button.dwMask |= THB_ICON;
icons[i] = IconUtil::CreateHICONFromSkBitmap(button.icon.AsBitmap());
thumb_button.hIcon = icons[i].Get();
}
// Set tooltip.
if (!button.tooltip.empty()) {
thumb_button.dwMask |= THB_TOOLTIP;
wcscpy_s(thumb_button.szTip, base::UTF8ToUTF16(button.tooltip).c_str());
}
// Save callback.
callback_map_[thumb_button.iId] = button.clicked_callback;
}
// Finally add them to taskbar.
HRESULT r;
if (thumbar_buttons_added_)
r = taskbar_->ThumbBarUpdateButtons(window, kMaxButtonsCount,
thumb_buttons);
else
r = taskbar_->ThumbBarAddButtons(window, kMaxButtonsCount, thumb_buttons);
thumbar_buttons_added_ = true;
return SUCCEEDED(r);
}
bool TaskbarHost::SetProgressBar(HWND window, double value) {
if (!InitailizeTaskbar())
return false;
HRESULT r;
if (value > 1.0)
r = taskbar_->SetProgressState(window, TBPF_INDETERMINATE);
else if (value < 0)
r = taskbar_->SetProgressState(window, TBPF_NOPROGRESS);
else
r = taskbar_->SetProgressValue(window, static_cast<int>(value * 100), 100);
return SUCCEEDED(r);
}
bool TaskbarHost::SetOverlayIcon(
HWND window, const gfx::Image& overlay, const std::string& text) {
if (!InitailizeTaskbar())
return false;
base::win::ScopedHICON icon(
IconUtil::CreateHICONFromSkBitmap(overlay.AsBitmap()));
return SUCCEEDED(
taskbar_->SetOverlayIcon(window, icon, base::UTF8ToUTF16(text).c_str()));
}
bool TaskbarHost::HandleThumbarButtonEvent(int button_id) {
if (ContainsKey(callback_map_, button_id)) {
auto callback = callback_map_[button_id];
if (!callback.is_null())
callback.Run();
return true;
}
return false;
}
bool TaskbarHost::InitailizeTaskbar() {
if (FAILED(taskbar_.CreateInstance(CLSID_TaskbarList,
nullptr,
CLSCTX_INPROC_SERVER)) ||
FAILED(taskbar_->HrInit())) {
return false;
} else {
return true;
}
}
} // namespace atom

View file

@ -0,0 +1,64 @@
// 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_UI_WIN_TASKBAR_HOST_H_
#define ATOM_BROWSER_UI_WIN_TASKBAR_HOST_H_
#include <shobjidl.h>
#include <map>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/win/scoped_comptr.h"
#include "ui/gfx/image/image.h"
namespace atom {
class TaskbarHost {
public:
struct ThumbarButton {
std::string tooltip;
gfx::Image icon;
std::vector<std::string> flags;
base::Closure clicked_callback;
};
TaskbarHost();
virtual ~TaskbarHost();
// Add or update the buttons in thumbar.
bool SetThumbarButtons(
HWND window, const std::vector<ThumbarButton>& buttons);
// Set the progress state in taskbar.
bool SetProgressBar(HWND window, double value);
// Set the overlay icon in taskbar.
bool SetOverlayIcon(
HWND window, const gfx::Image& overlay, const std::string& text);
// Called by the window that there is a button in thumbar clicked.
bool HandleThumbarButtonEvent(int button_id);
private:
// Initailize the taskbar object.
bool InitailizeTaskbar();
using CallbackMap = std::map<int, base::Closure>;
CallbackMap callback_map_;
// The COM object of taskbar.
base::win::ScopedComPtr<ITaskbarList3> taskbar_;
// Whether we have already added the buttons to thumbar.
bool thumbar_buttons_added_;
DISALLOW_COPY_AND_ASSIGN(TaskbarHost);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_TASKBAR_HOST_H_

View file

@ -7,6 +7,9 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "dbus/bus.h"
#include "dbus/object_proxy.h"
#include "dbus/message.h"
#include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util.h"
namespace atom { namespace atom {
@ -46,4 +49,37 @@ void SetWindowType(::Window xwindow, const std::string& type) {
reinterpret_cast<unsigned char*>(&window_type), 1); reinterpret_cast<unsigned char*>(&window_type), 1);
} }
bool ShouldUseGlobalMenuBar() {
dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
dbus::ObjectProxy* object_proxy =
bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
dbus::MethodCall method_call(DBUS_INTERFACE_DBUS, "ListNames");
scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
bus->ShutdownAndBlock();
return false;
}
dbus::MessageReader reader(response.get());
dbus::MessageReader array_reader(NULL);
if (!reader.PopArray(&array_reader)) {
bus->ShutdownAndBlock();
return false;
}
while (array_reader.HasMoreData()) {
std::string name;
if (array_reader.PopString(&name) &&
name == "com.canonical.AppMenu.Registrar") {
bus->ShutdownAndBlock();
return true;
}
}
bus->ShutdownAndBlock();
return false;
}
} // namespace atom } // namespace atom

View file

@ -22,6 +22,9 @@ void SetWMSpecState(::Window xwindow, bool enabled, ::Atom state);
// Sets the _NET_WM_WINDOW_TYPE of window. // Sets the _NET_WM_WINDOW_TYPE of window.
void SetWindowType(::Window xwindow, const std::string& type); void SetWindowType(::Window xwindow, const std::string& type);
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
bool ShouldUseGlobalMenuBar();
} // namespace atom } // namespace atom
#endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_ #endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_

View file

@ -4,17 +4,66 @@
#include "atom/browser/web_dialog_helper.h" #include "atom/browser/web_dialog_helper.h"
#include <string>
#include <vector> #include <vector>
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/file_dialog.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_enumerator.h" #include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/file_chooser_file_info.h" #include "content/public/common/file_chooser_file_info.h"
#include "net/base/mime_util.h"
#include "ui/shell_dialogs/selected_file_info.h" #include "ui/shell_dialogs/selected_file_info.h"
namespace {
file_dialog::Filters GetFileTypesFromAcceptType(
const std::vector<base::string16>& accept_types) {
file_dialog::Filters filters;
if (accept_types.empty())
return filters;
std::vector<base::FilePath::StringType> extensions;
for (const auto& accept_type : accept_types) {
std::string ascii_type = base::UTF16ToASCII(accept_type);
if (ascii_type[0] == '.') {
// If the type starts with a period it is assumed to be a file extension,
// like `.txt`, // so we just have to add it to the list.
base::FilePath::StringType extension(
ascii_type.begin(), ascii_type.end());
// Skip the first character.
extensions.push_back(extension.substr(1));
} else {
// For MIME Type, `audio/*, vidio/*, image/*
net::GetExtensionsForMimeType(ascii_type, &extensions);
}
}
// If no valid exntesion is added, return empty filters.
if (extensions.empty())
return filters;
filters.push_back(file_dialog::Filter());
for (const auto& extension : extensions) {
#if defined(OS_WIN)
filters[0].second.push_back(base::UTF16ToASCII(extension));
#else
filters[0].second.push_back(extension);
#endif
}
return filters;
}
} // namespace
namespace atom { namespace atom {
WebDialogHelper::WebDialogHelper(NativeWindow* window) WebDialogHelper::WebDialogHelper(NativeWindow* window)
@ -25,15 +74,18 @@ WebDialogHelper::WebDialogHelper(NativeWindow* window)
WebDialogHelper::~WebDialogHelper() { WebDialogHelper::~WebDialogHelper() {
} }
void WebDialogHelper::RunFileChooser(content::WebContents* web_contents, void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
const content::FileChooserParams& params) { const content::FileChooserParams& params) {
std::vector<content::FileChooserFileInfo> result; std::vector<content::FileChooserFileInfo> result;
file_dialog::Filters filters = GetFileTypesFromAcceptType(
params.accept_types);
if (params.mode == content::FileChooserParams::Save) { if (params.mode == content::FileChooserParams::Save) {
base::FilePath path; base::FilePath path;
if (file_dialog::ShowSaveDialog(window_, if (file_dialog::ShowSaveDialog(window_,
base::UTF16ToUTF8(params.title), base::UTF16ToUTF8(params.title),
params.default_file_name, params.default_file_name,
file_dialog::Filters(), filters,
&path)) { &path)) {
content::FileChooserFileInfo info; content::FileChooserFileInfo info;
info.file_path = path; info.file_path = path;
@ -56,10 +108,14 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
} }
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
window_->web_contents()->GetBrowserContext());
base::FilePath default_file_path = browser_context->prefs()->GetFilePath(
prefs::kSelectFileLastDirectory).Append(params.default_file_name);
if (file_dialog::ShowOpenDialog(window_, if (file_dialog::ShowOpenDialog(window_,
base::UTF16ToUTF8(params.title), base::UTF16ToUTF8(params.title),
params.default_file_name, default_file_path,
file_dialog::Filters(), filters,
flags, flags,
&paths)) { &paths)) {
for (auto& path : paths) { for (auto& path : paths) {
@ -68,6 +124,10 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
info.display_name = path.BaseName().value(); info.display_name = path.BaseName().value();
result.push_back(info); result.push_back(info);
} }
if (!paths.empty()) {
browser_context->prefs()->SetFilePath(prefs::kSelectFileLastDirectory,
paths[0].DirName());
}
} }
} }

View file

@ -5,7 +5,9 @@
#include "atom/browser/web_view_guest_delegate.h" #include "atom/browser/web_view_guest_delegate.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/guest_host.h" #include "content/public/browser/guest_host.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
@ -128,6 +130,12 @@ void WebViewGuestDelegate::RenderViewReady() {
render_view_host_view->SetBackgroundColor(SK_ColorTRANSPARENT); render_view_host_view->SetBackgroundColor(SK_ColorTRANSPARENT);
} }
void WebViewGuestDelegate::DidCommitProvisionalLoadForFrame(
content::RenderFrameHost* render_frame_host,
const GURL& url, ui::PageTransition transition_type) {
api_web_contents_->Emit("load-commit", url, !render_frame_host->GetParent());
}
void WebViewGuestDelegate::DidAttach(int guest_proxy_routing_id) { void WebViewGuestDelegate::DidAttach(int guest_proxy_routing_id) {
api_web_contents_->Emit("did-attach"); api_web_contents_->Emit("did-attach");
} }

View file

@ -59,6 +59,9 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate,
protected: protected:
// content::WebContentsObserver: // content::WebContentsObserver:
void RenderViewReady() override; void RenderViewReady() override;
void DidCommitProvisionalLoadForFrame(
content::RenderFrameHost* render_frame_host,
const GURL& url, ui::PageTransition transition_type) override;
// content::BrowserPluginGuestDelegate: // content::BrowserPluginGuestDelegate:
void DidAttach(int guest_proxy_routing_id) final; void DidAttach(int guest_proxy_routing_id) final;

View file

@ -34,6 +34,10 @@ IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
base::string16 /* channel */, base::string16 /* channel */,
base::ListValue /* arguments */) base::ListValue /* arguments */)
IPC_MESSAGE_ROUTED2(AtomViewMsg_ExecuteJavaScript,
base::string16 /* code */,
bool /* has user gesture */)
// Sent by the renderer when the draggable regions are updated. // Sent by the renderer when the draggable regions are updated.
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions, IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions,
std::vector<atom::DraggableRegion> /* regions */) std::vector<atom::DraggableRegion> /* regions */)

View file

@ -8,9 +8,9 @@
#include "atom_natives.h" // NOLINT: This file is generated with coffee2c. #include "atom_natives.h" // NOLINT: This file is generated with coffee2c.
#include "atom/common/asar/archive.h" #include "atom/common/asar/archive.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/file_path_converter.h"
#include "native_mate/arguments.h" #include "native_mate/arguments.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "native_mate/wrappable.h" #include "native_mate/wrappable.h"

View file

@ -78,7 +78,7 @@ bool AddImageSkiaRep(gfx::ImageSkia* image,
if (!decoded) if (!decoded)
return false; return false;
image->AddRepresentation(gfx::ImageSkiaRep(*decoded.release(), scale_factor)); image->AddRepresentation(gfx::ImageSkiaRep(*decoded, scale_factor));
return true; return true;
} }
@ -113,7 +113,7 @@ bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
} }
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
bool IsTemplateImage(const base::FilePath& path) { bool IsTemplateFilename(const base::FilePath& path) {
return (MatchPattern(path.value(), "*Template.*") || return (MatchPattern(path.value(), "*Template.*") ||
MatchPattern(path.value(), "*Template@*x.*")); MatchPattern(path.value(), "*Template@*x.*"));
} }
@ -139,6 +139,7 @@ mate::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder(
.SetMethod("isEmpty", &NativeImage::IsEmpty) .SetMethod("isEmpty", &NativeImage::IsEmpty)
.SetMethod("getSize", &NativeImage::GetSize) .SetMethod("getSize", &NativeImage::GetSize)
.SetMethod("setTemplateImage", &NativeImage::SetTemplateImage) .SetMethod("setTemplateImage", &NativeImage::SetTemplateImage)
.SetMethod("isTemplateImage", &NativeImage::IsTemplateImage)
.Build()); .Build());
return mate::ObjectTemplateBuilder( return mate::ObjectTemplateBuilder(
@ -180,6 +181,10 @@ gfx::Size NativeImage::GetSize() {
#if !defined(OS_MACOSX) #if !defined(OS_MACOSX)
void NativeImage::SetTemplateImage(bool setAsTemplate) { void NativeImage::SetTemplateImage(bool setAsTemplate) {
} }
bool NativeImage::IsTemplateImage() {
return false;
}
#endif #endif
// static // static
@ -217,7 +222,7 @@ mate::Handle<NativeImage> NativeImage::CreateFromPath(
gfx::Image image(image_skia); gfx::Image image(image_skia);
mate::Handle<NativeImage> handle = Create(isolate, image); mate::Handle<NativeImage> handle = Create(isolate, image);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
if (IsTemplateImage(path)) if (IsTemplateFilename(path))
handle->SetTemplateImage(true); handle->SetTemplateImage(true);
#endif #endif
return handle; return handle;

View file

@ -67,6 +67,8 @@ class NativeImage : public mate::Wrappable {
// Mark the image as template image. // Mark the image as template image.
void SetTemplateImage(bool setAsTemplate); void SetTemplateImage(bool setAsTemplate);
// Determine if the image is a template image.
bool IsTemplateImage();
gfx::Image image_; gfx::Image image_;

View file

@ -14,6 +14,10 @@ void NativeImage::SetTemplateImage(bool setAsTemplate) {
[image_.AsNSImage() setTemplate:setAsTemplate]; [image_.AsNSImage() setTemplate:setAsTemplate];
} }
bool NativeImage::IsTemplateImage() {
return [image_.AsNSImage() isTemplate];
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom

View file

@ -98,6 +98,10 @@ void AtomBindings::OnCallNextTick(uv_async_t* handle) {
if (tick_info->in_tick()) if (tick_info->in_tick())
continue; continue;
if (tick_info->length() == 0) {
env->isolate()->RunMicrotasks();
}
if (tick_info->length() == 0) { if (tick_info->length() == 0) {
tick_info->set_index(0); tick_info->set_index(0);
continue; continue;

View file

@ -0,0 +1,32 @@
// 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/common/api/event_emitter_caller.h"
#include "atom/common/api/locker.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
#include "atom/common/node_includes.h"
namespace mate {
namespace internal {
v8::Local<v8::Value> CallEmitWithArgs(v8::Isolate* isolate,
v8::Local<v8::Object> obj,
ValueVector* args) {
// Perform microtask checkpoint after running JavaScript.
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
// Use node::MakeCallback to call the callback, and it will also run pending
// tasks in Node.js.
return node::MakeCallback(
isolate, obj, "emit", args->size(), &args->front());
}
} // namespace internal
} // namespace mate

View file

@ -2,8 +2,8 @@
// Use of this source code is governed by the MIT license that can be // Use of this source code is governed by the MIT license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef ATOM_COMMON_EVENT_EMITTER_CALLER_H_ #ifndef ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_
#define ATOM_COMMON_EVENT_EMITTER_CALLER_H_ #define ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_
#include <vector> #include <vector>
@ -50,4 +50,4 @@ v8::Local<v8::Value> EmitEvent(v8::Isolate* isolate,
} // namespace mate } // namespace mate
#endif // ATOM_COMMON_EVENT_EMITTER_CALLER_H_ #endif // ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_

View file

@ -1,3 +1,5 @@
savedGlobal = global # the "global.global" might be deleted later
module.exports = module.exports =
class CallbacksRegistry class CallbacksRegistry
constructor: -> constructor: ->
@ -16,10 +18,10 @@ class CallbacksRegistry
@callbacks[id] ? -> @callbacks[id] ? ->
call: (id, args...) -> call: (id, args...) ->
@get(id).call global, args... @get(id).call savedGlobal, args...
apply: (id, args...) -> apply: (id, args...) ->
@get(id).apply global, args... @get(id).apply savedGlobal, args...
remove: (id) -> remove: (id) ->
delete @callbacks[id] delete @callbacks[id]

17
atom/common/api/locker.cc Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "atom/common/api/locker.h"
namespace mate {
Locker::Locker(v8::Isolate* isolate) {
if (IsBrowserProcess())
locker_.reset(new v8::Locker(isolate));
}
Locker::~Locker() {
}
} // namespace mate

34
atom/common/api/locker.h Normal file
View file

@ -0,0 +1,34 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef ATOM_COMMON_API_LOCKER_H_
#define ATOM_COMMON_API_LOCKER_H_
#include "base/memory/scoped_ptr.h"
#include "v8/include/v8.h"
namespace mate {
// Only lock when lockers are used in current thread.
class Locker {
public:
explicit Locker(v8::Isolate* isolate);
~Locker();
// Returns whether current process is browser process, currently we detect it
// by checking whether current has used V8 Lock, but it might be a bad idea.
static inline bool IsBrowserProcess() { return v8::Locker::IsActive(); }
private:
void* operator new(size_t size);
void operator delete(void*, size_t);
scoped_ptr<v8::Locker> locker_;
DISALLOW_COPY_AND_ASSIGN(Locker);
};
} // namespace mate
#endif // ATOM_COMMON_API_LOCKER_H_

View file

@ -54,6 +54,11 @@ bool GetChildNode(const base::DictionaryValue* root,
const std::string& name, const std::string& name,
const base::DictionaryValue* dir, const base::DictionaryValue* dir,
const base::DictionaryValue** out) { const base::DictionaryValue** out) {
if (name == "") {
*out = root;
return true;
}
const base::DictionaryValue* files = NULL; const base::DictionaryValue* files = NULL;
return GetFilesNode(root, dir, &files) && return GetFilesNode(root, dir, &files) &&
files->GetDictionaryWithoutPathExpansion(name, out); files->GetDictionaryWithoutPathExpansion(name, out);

View file

@ -6,8 +6,8 @@
#define ATOM_VERSION_H #define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0 #define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 29 #define ATOM_MINOR_VERSION 30
#define ATOM_PATCH_VERSION 2 #define ATOM_PATCH_VERSION 4
#define ATOM_VERSION_IS_RELEASE 1 #define ATOM_VERSION_IS_RELEASE 1

View file

@ -21,6 +21,7 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
MiniDumpWithProcessThreadData | // Get PEB and TEB. MiniDumpWithProcessThreadData | // Get PEB and TEB.
MiniDumpWithUnloadedModules); // Get unloaded modules when available. MiniDumpWithUnloadedModules); // Get unloaded modules when available.
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service"; const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
} // namespace } // namespace
@ -47,12 +48,15 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
base::string16 pipe_name = ReplaceStringPlaceholders( base::string16 pipe_name = ReplaceStringPlaceholders(
kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL); kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL);
base::string16 wait_name = ReplaceStringPlaceholders(
kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL);
// Wait until the crash service is started. // Wait until the crash service is started.
HANDLE waiting_event = HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
::CreateEventW(NULL, TRUE, FALSE, L"g_atom_shell_crash_service"); if (wait_event != NULL) {
if (waiting_event != INVALID_HANDLE_VALUE) WaitForSingleObject(wait_event, 1000);
WaitForSingleObject(waiting_event, 1000); CloseHandle(wait_event);
}
// ExceptionHandler() attaches our handler and ~ExceptionHandler() detaches // ExceptionHandler() attaches our handler and ~ExceptionHandler() detaches
// it, so we must explicitly reset *before* we instantiate our new handler // it, so we must explicitly reset *before* we instantiate our new handler

View file

@ -14,6 +14,7 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "vendor/breakpad/src/client/windows/crash_generation/client_info.h" #include "vendor/breakpad/src/client/windows/crash_generation/client_info.h"
@ -24,6 +25,9 @@ namespace breakpad {
namespace { namespace {
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
const wchar_t kClassNameFormat[] = L"$1CrashServiceWindow";
const wchar_t kTestPipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; const wchar_t kTestPipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
const wchar_t kGoogleReportURL[] = L"https://clients2.google.com/cr/report"; const wchar_t kGoogleReportURL[] = L"https://clients2.google.com/cr/report";
@ -111,13 +115,18 @@ LRESULT __stdcall CrashSvcWndProc(HWND hwnd, UINT message,
// This is the main and only application window. // This is the main and only application window.
HWND g_top_window = NULL; HWND g_top_window = NULL;
bool CreateTopWindow(HINSTANCE instance, bool visible) { bool CreateTopWindow(HINSTANCE instance,
const base::string16& application_name,
bool visible) {
base::string16 class_name = ReplaceStringPlaceholders(
kClassNameFormat, application_name, NULL);
WNDCLASSEXW wcx = {0}; WNDCLASSEXW wcx = {0};
wcx.cbSize = sizeof(wcx); wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW; wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = CrashSvcWndProc; wcx.lpfnWndProc = CrashSvcWndProc;
wcx.hInstance = instance; wcx.hInstance = instance;
wcx.lpszClassName = L"crash_svc_class"; wcx.lpszClassName = class_name.c_str();
ATOM atom = ::RegisterClassExW(&wcx); ATOM atom = ::RegisterClassExW(&wcx);
DWORD style = visible ? WS_POPUPWINDOW | WS_VISIBLE : WS_OVERLAPPED; DWORD style = visible ? WS_POPUPWINDOW | WS_VISIBLE : WS_OVERLAPPED;
@ -193,7 +202,8 @@ CrashService::~CrashService() {
delete sender_; delete sender_;
} }
bool CrashService::Initialize(const base::FilePath& operating_dir, bool CrashService::Initialize(const base::string16& application_name,
const base::FilePath& operating_dir,
const base::FilePath& dumps_path) { const base::FilePath& dumps_path) {
using google_breakpad::CrashReportSender; using google_breakpad::CrashReportSender;
using google_breakpad::CrashGenerationServer; using google_breakpad::CrashGenerationServer;
@ -260,6 +270,7 @@ bool CrashService::Initialize(const base::FilePath& operating_dir,
} }
if (!CreateTopWindow(::GetModuleHandleW(NULL), if (!CreateTopWindow(::GetModuleHandleW(NULL),
application_name,
!cmd_line.HasSwitch(kNoWindow))) { !cmd_line.HasSwitch(kNoWindow))) {
LOG(ERROR) << "could not create window"; LOG(ERROR) << "could not create window";
if (security_attributes.lpSecurityDescriptor) if (security_attributes.lpSecurityDescriptor)
@ -298,11 +309,10 @@ bool CrashService::Initialize(const base::FilePath& operating_dir,
// Create or open an event to signal the browser process that the crash // Create or open an event to signal the browser process that the crash
// service is initialized. // service is initialized.
HANDLE running_event = base::string16 wait_name = ReplaceStringPlaceholders(
::CreateEventW(NULL, TRUE, TRUE, L"g_atom_shell_crash_service"); kWaitEventFormat, application_name, NULL);
// If the browser already had the event open, the CreateEvent call did not HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
// signal it. We need to do it manually. ::SetEvent(wait_event);
::SetEvent(running_event);
return true; return true;
} }

View file

@ -37,7 +37,8 @@ class CrashService {
// other members in that case. |operating_dir| is where the CrashService // other members in that case. |operating_dir| is where the CrashService
// should store breakpad's checkpoint file. |dumps_path| is the directory // should store breakpad's checkpoint file. |dumps_path| is the directory
// where the crash dumps should be stored. // where the crash dumps should be stored.
bool Initialize(const base::FilePath& operating_dir, bool Initialize(const base::string16& application_name,
const base::FilePath& operating_dir,
const base::FilePath& dumps_path); const base::FilePath& dumps_path);
// Command line switches: // Command line switches:

Some files were not shown because too many files have changed in this diff Show more