Merge remote-tracking branch 'atom/master'
This commit is contained in:
commit
ad24c11f32
171 changed files with 4032 additions and 968 deletions
|
@ -22,3 +22,7 @@ matrix:
|
|||
- env: TARGET_ARCH=ia32
|
||||
|
||||
script: './script/cibuild'
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
:+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.
|
||||
[code-of-conduct]: http://todogroup.org/opencodeofconduct/#Electron/opensource@github.com
|
||||
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
|
||||
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.
|
||||
These are just guidelines, not rules, use your best judgment and feel free to
|
||||
|
|
|
@ -14,8 +14,8 @@ editor](https://github.com/atom/atom).
|
|||
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
|
||||
announcements.
|
||||
|
||||
This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to uphold this code.
|
||||
[code-of-conduct]: http://todogroup.org/opencodeofconduct/#Electron/opensource@github.com
|
||||
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com.
|
||||
|
||||
## Downloads
|
||||
|
||||
|
|
2
atom.gyp
2
atom.gyp
|
@ -4,7 +4,7 @@
|
|||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.29.2',
|
||||
'version%': '0.30.4',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/browser.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 "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
|
@ -25,7 +26,6 @@
|
|||
#include "brightray/browser/brightray_paths.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
#include "content/public/browser/gpu_data_manager.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "content/public/browser/tracing_controller.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
@ -46,6 +47,31 @@ struct Converter<base::trace_event::TraceOptions> {
|
|||
|
||||
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,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
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));
|
||||
dict.SetMethod("startRecording", base::Bind(
|
||||
&TracingController::EnableRecording, controller));
|
||||
dict.SetMethod("stopRecording", base::Bind(
|
||||
&TracingController::DisableRecording, controller, nullptr));
|
||||
dict.SetMethod("stopRecording", &StopRecording);
|
||||
dict.SetMethod("startMonitoring", base::Bind(
|
||||
&TracingController::EnableMonitoring, controller));
|
||||
dict.SetMethod("stopMonitoring", base::Bind(
|
||||
&TracingController::DisableMonitoring, controller));
|
||||
dict.SetMethod("captureMonitoringSnapshot", base::Bind(
|
||||
&TracingController::CaptureMonitoringSnapshot, controller, nullptr));
|
||||
dict.SetMethod("captureMonitoringSnapshot", &CaptureMonitoringSnapshot);
|
||||
dict.SetMethod("getTraceBufferUsage", base::Bind(
|
||||
&TracingController::GetTraceBufferUsage, controller));
|
||||
dict.SetMethod("setWatchEvent", base::Bind(
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
|
||||
#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/value_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/cookies/cookie_monster.h"
|
||||
|
@ -179,8 +180,8 @@ namespace atom {
|
|||
|
||||
namespace api {
|
||||
|
||||
Cookies::Cookies(content::BrowserContext* browser_context) :
|
||||
browser_context_(browser_context) {
|
||||
Cookies::Cookies(content::BrowserContext* browser_context)
|
||||
: request_context_getter_(browser_context->GetRequestContext()) {
|
||||
}
|
||||
|
||||
Cookies::~Cookies() {
|
||||
|
@ -198,11 +199,9 @@ void Cookies::Get(const base::DictionaryValue& options,
|
|||
|
||||
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
||||
const CookiesCallback& callback) {
|
||||
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
|
||||
->GetURLRequestContext()->cookie_store();
|
||||
std::string url;
|
||||
filter->GetString("url", &url);
|
||||
if (!GetCookieListFromStore(cookie_store, url,
|
||||
if (!GetCookieListFromStore(GetCookieStore(), url,
|
||||
base::Bind(&Cookies::OnGetCookies, base::Unretained(this),
|
||||
Passed(&filter), callback))) {
|
||||
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,
|
||||
const CookiesCallback& callback) {
|
||||
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
|
||||
->GetURLRequestContext()->cookie_store();
|
||||
cookie_store->DeleteCookieAsync(url, name,
|
||||
GetCookieStore()->DeleteCookieAsync(url, name,
|
||||
base::Bind(&Cookies::OnRemoveCookies, base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
|
@ -286,8 +283,6 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
|||
const GURL& url,
|
||||
const CookiesCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
|
||||
->GetURLRequestContext()->cookie_store();
|
||||
|
||||
std::string name, value, domain, path;
|
||||
bool secure = false;
|
||||
|
@ -308,7 +303,7 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
|||
base::Time::FromDoubleT(expiration_date);
|
||||
}
|
||||
|
||||
cookie_store->GetCookieMonster()->SetCookieWithDetailsAsync(
|
||||
GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
|
||||
url,
|
||||
name,
|
||||
value,
|
||||
|
@ -337,6 +332,10 @@ mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
|
|||
.SetMethod("set", &Cookies::Set);
|
||||
}
|
||||
|
||||
net::CookieStore* Cookies::GetCookieStore() {
|
||||
return request_context_getter_->GetURLRequestContext()->cookie_store();
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<Cookies> Cookies::Create(
|
||||
v8::Isolate* isolate,
|
||||
|
|
|
@ -8,17 +8,27 @@
|
|||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/values.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "net/cookies/canonical_cookie.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class CookieStore;
|
||||
class URLRequestContextGetter;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
@ -60,13 +70,15 @@ class Cookies : public mate::Wrappable {
|
|||
void OnSetCookies(const CookiesCallback& callback,
|
||||
bool set_success);
|
||||
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
// mate::Wrappable:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.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/image_converter.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
@ -42,28 +42,24 @@ namespace {
|
|||
void ShowMessageBox(int type,
|
||||
const std::vector<std::string>& buttons,
|
||||
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,
|
||||
atom::NativeWindow* window,
|
||||
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();
|
||||
atom::MessageBoxCallback callback;
|
||||
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id,
|
||||
title, message, detail, icon, callback);
|
||||
options, title, message, detail, icon, callback);
|
||||
} else {
|
||||
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
|
||||
buttons, cancel_id, title, message,
|
||||
detail, icon);
|
||||
buttons, cancel_id, options, title,
|
||||
message, detail, icon);
|
||||
args->Return(chosen);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include <string>
|
||||
|
||||
#include "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
#include "atom/browser/native_window.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/string16_converter.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
|
@ -20,7 +20,7 @@ namespace atom {
|
|||
namespace api {
|
||||
|
||||
Menu::Menu()
|
||||
: model_(new ui::SimpleMenuModel(this)),
|
||||
: model_(new AtomMenuModel(this)),
|
||||
parent_(NULL) {
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
#include <string>
|
||||
|
||||
#include "atom/browser/api/atom_api_window.h"
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace atom {
|
||||
|
@ -18,7 +18,7 @@ namespace atom {
|
|||
namespace api {
|
||||
|
||||
class Menu : public mate::Wrappable,
|
||||
public ui::SimpleMenuModel::Delegate {
|
||||
public AtomMenuModel::Delegate {
|
||||
public:
|
||||
static mate::Wrappable* Create();
|
||||
|
||||
|
@ -33,7 +33,7 @@ class Menu : public mate::Wrappable,
|
|||
static void SendActionToFirstResponder(const std::string& action);
|
||||
#endif
|
||||
|
||||
ui::SimpleMenuModel* model() const { return model_.get(); }
|
||||
AtomMenuModel* model() const { return model_.get(); }
|
||||
|
||||
protected:
|
||||
Menu();
|
||||
|
@ -42,7 +42,7 @@ class Menu : public mate::Wrappable,
|
|||
// mate::Wrappable:
|
||||
void AfterInit(v8::Isolate* isolate) override;
|
||||
|
||||
// ui::SimpleMenuModel::Delegate implementations:
|
||||
// ui::SimpleMenuModel::Delegate:
|
||||
bool IsCommandIdChecked(int command_id) const override;
|
||||
bool IsCommandIdEnabled(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 PopupAt(Window* window, int x, int y) = 0;
|
||||
|
||||
scoped_ptr<ui::SimpleMenuModel> model_;
|
||||
scoped_ptr<AtomMenuModel> model_;
|
||||
Menu* parent_;
|
||||
|
||||
private:
|
||||
|
@ -102,9 +102,9 @@ class Menu : public mate::Wrappable,
|
|||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<ui::SimpleMenuModel*> {
|
||||
struct Converter<atom::AtomMenuModel*> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
ui::SimpleMenuModel** out) {
|
||||
atom::AtomMenuModel** out) {
|
||||
// null would be tranfered to NULL.
|
||||
if (val->IsNull()) {
|
||||
*out = nullptr;
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.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/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/gurl_converter.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
|
||||
|
@ -62,16 +63,13 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
|||
registry_(registry) {
|
||||
}
|
||||
|
||||
// AdapterRequestJob:
|
||||
void GetJobTypeInUI() override {
|
||||
void GetJobTypeInUI(const Protocol::JsProtocolHandler& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
v8::Locker locker(registry_->isolate());
|
||||
v8::HandleScope handle_scope(registry_->isolate());
|
||||
|
||||
// Call the JS handler.
|
||||
Protocol::JsProtocolHandler callback =
|
||||
registry_->GetProtocolHandler(request()->url().scheme());
|
||||
v8::Local<v8::Value> result = callback.Run(request());
|
||||
|
||||
// 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("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,
|
||||
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
|
||||
registry_->browser_context(), url, method, referrer));
|
||||
request_context_getter, url, method, referrer));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -151,6 +163,14 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
|||
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:
|
||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||
};
|
||||
|
@ -211,7 +231,7 @@ std::string ConvertErrorCode(int error_code) {
|
|||
} // namespace
|
||||
|
||||
Protocol::Protocol(AtomBrowserContext* browser_context)
|
||||
: browser_context_(browser_context),
|
||||
: request_context_getter_(browser_context->GetRequestContext()),
|
||||
job_factory_(browser_context->job_factory()) {
|
||||
CHECK(job_factory_);
|
||||
}
|
||||
|
@ -335,6 +355,10 @@ int Protocol::InterceptProtocolInIO(const std::string& scheme,
|
|||
const JsProtocolHandler& handler) {
|
||||
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))
|
||||
return ERR_NO_SCHEME;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
namespace net {
|
||||
class URLRequest;
|
||||
class URLRequestContextGetter;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
@ -46,7 +47,9 @@ class Protocol : public mate::EventEmitter {
|
|||
|
||||
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
|
||||
|
||||
AtomBrowserContext* browser_context() const { return browser_context_; }
|
||||
net::URLRequestContextGetter* request_context_getter() {
|
||||
return request_context_getter_.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit Protocol(AtomBrowserContext* browser_context);
|
||||
|
@ -94,7 +97,8 @@ class Protocol : public mate::EventEmitter {
|
|||
const JsProtocolHandler& handler);
|
||||
int UninterceptProtocolInIO(const std::string& scheme);
|
||||
|
||||
AtomBrowserContext* browser_context_;
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
ProtocolHandlersMap protocol_handlers_;
|
||||
|
||||
|
|
|
@ -9,16 +9,22 @@
|
|||
|
||||
#include "atom/browser/api/atom_api_cookies.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 "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/thread_task_runner_handle.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "content/public/browser/browser_thread.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 "net/base/load_flags.h"
|
||||
#include "net/disk_cache/disk_cache.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_getter.h"
|
||||
|
||||
|
@ -157,9 +163,10 @@ class ResolveProxyHelper {
|
|||
};
|
||||
|
||||
// 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::UI, FROM_HERE, base::Bind(callback, result));
|
||||
BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
|
||||
}
|
||||
|
||||
// Callback of HttpCache::GetBackend.
|
||||
|
@ -169,19 +176,19 @@ void OnGetBackend(disk_cache::Backend** backend_ptr,
|
|||
if (result != net::OK) {
|
||||
RunCallbackInUI(callback, result);
|
||||
} else if (backend_ptr && *backend_ptr) {
|
||||
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI, callback));
|
||||
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>, callback));
|
||||
} else {
|
||||
RunCallbackInUI(callback, net::ERR_FAILED);
|
||||
RunCallbackInUI<int>(callback, net::ERR_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearHttpCacheInIO(content::BrowserContext* browser_context,
|
||||
const net::CompletionCallback& callback) {
|
||||
auto request_context =
|
||||
browser_context->GetRequestContext()->GetURLRequestContext();
|
||||
void ClearHttpCacheInIO(
|
||||
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
||||
const net::CompletionCallback& callback) {
|
||||
auto request_context = context_getter->GetURLRequestContext();
|
||||
auto http_cache = request_context->http_transaction_factory()->GetCache();
|
||||
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.
|
||||
using BackendPtr = disk_cache::Backend*;
|
||||
|
@ -193,6 +200,16 @@ void ClearHttpCacheInIO(content::BrowserContext* browser_context,
|
|||
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
|
||||
|
||||
Session::Session(AtomBrowserContext* browser_context)
|
||||
|
@ -210,7 +227,7 @@ void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
|
|||
void Session::ClearCache(const net::CompletionCallback& callback) {
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&ClearHttpCacheInIO,
|
||||
base::Unretained(browser_context_),
|
||||
make_scoped_refptr(browser_context_->GetRequestContext()),
|
||||
callback));
|
||||
}
|
||||
|
||||
|
@ -232,6 +249,18 @@ void Session::ClearStorageData(mate::Arguments* args) {
|
|||
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) {
|
||||
if (cookies_.IsEmpty()) {
|
||||
auto handle = atom::api::Cookies::Create(isolate, browser_context_);
|
||||
|
@ -246,6 +275,8 @@ mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
|
|||
.SetMethod("resolveProxy", &Session::ResolveProxy)
|
||||
.SetMethod("clearCache", &Session::ClearCache)
|
||||
.SetMethod("clearStorageData", &Session::ClearStorageData)
|
||||
.SetMethod("setProxy", &Session::SetProxy)
|
||||
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
|
||||
.SetProperty("cookies", &Session::Cookies);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
|
||||
class GURL;
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Arguments;
|
||||
}
|
||||
|
@ -31,6 +35,8 @@ class Session: public mate::TrackableObject<Session> {
|
|||
static mate::Handle<Session> CreateFrom(
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
|
||||
AtomBrowserContext* browser_context() const { return browser_context_; }
|
||||
|
||||
protected:
|
||||
explicit Session(AtomBrowserContext* browser_context);
|
||||
~Session();
|
||||
|
@ -43,6 +49,8 @@ class Session: public mate::TrackableObject<Session> {
|
|||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void ClearCache(const net::CompletionCallback& callback);
|
||||
void ClearStorageData(mate::Arguments* args);
|
||||
void SetProxy(const std::string& proxy, const base::Closure& callback);
|
||||
void SetDownloadPath(const base::FilePath& path);
|
||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||
|
||||
v8::Global<v8::Value> cookies_;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/gfx/image/image.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);
|
||||
}
|
||||
|
||||
void Tray::OnClicked(const gfx::Rect& bounds) {
|
||||
Emit("clicked", bounds);
|
||||
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitCustomEvent("clicked",
|
||||
ModifiersToObject(isolate(), modifiers), bounds);
|
||||
}
|
||||
|
||||
void Tray::OnDoubleClicked() {
|
||||
Emit("double-clicked");
|
||||
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
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() {
|
||||
|
@ -60,6 +74,10 @@ void Tray::OnBalloonClosed() {
|
|||
Emit("balloon-closed");
|
||||
}
|
||||
|
||||
void Tray::OnDropFiles(const std::vector<std::string>& files) {
|
||||
Emit("drop-files", files);
|
||||
}
|
||||
|
||||
bool Tray::IsDestroyed() const {
|
||||
return !tray_icon_;
|
||||
}
|
||||
|
@ -102,10 +120,26 @@ void Tray::DisplayBalloon(mate::Arguments* args,
|
|||
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) {
|
||||
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
|
||||
void Tray::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> prototype) {
|
||||
|
@ -117,6 +151,7 @@ void Tray::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setTitle", &Tray::SetTitle)
|
||||
.SetMethod("setHighlightMode", &Tray::SetHighlightMode)
|
||||
.SetMethod("displayBalloon", &Tray::DisplayBalloon)
|
||||
.SetMethod("popUpContextMenu", &Tray::PopUpContextMenu)
|
||||
.SetMethod("_setContextMenu", &Tray::SetContextMenu);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define ATOM_BROWSER_API_ATOM_API_TRAY_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/ui/tray_icon_observer.h"
|
||||
|
@ -41,11 +42,13 @@ class Tray : public mate::EventEmitter,
|
|||
virtual ~Tray();
|
||||
|
||||
// TrayIconObserver:
|
||||
void OnClicked(const gfx::Rect&) override;
|
||||
void OnDoubleClicked() override;
|
||||
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnBalloonShow() override;
|
||||
void OnBalloonClicked() override;
|
||||
void OnBalloonClosed() override;
|
||||
void OnDropFiles(const std::vector<std::string>& files) override;
|
||||
|
||||
// mate::Wrappable:
|
||||
bool IsDestroyed() const override;
|
||||
|
@ -57,9 +60,12 @@ class Tray : public mate::EventEmitter,
|
|||
void SetTitle(mate::Arguments* args, const std::string& title);
|
||||
void SetHighlightMode(mate::Arguments* args, bool highlight);
|
||||
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
|
||||
void PopUpContextMenu(mate::Arguments* args);
|
||||
void SetContextMenu(mate::Arguments* args, Menu* menu);
|
||||
|
||||
private:
|
||||
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
|
||||
|
||||
scoped_ptr<TrayIcon> tray_icon_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Tray);
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/web_view_guest_delegate.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/gurl_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/site_instance.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.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));
|
||||
}
|
||||
|
||||
std::string WebContents::GetUserAgent() {
|
||||
return web_contents()->GetUserAgentOverride();
|
||||
}
|
||||
|
||||
void WebContents::InsertCSS(const std::string& css) {
|
||||
web_contents()->InsertCSS(css);
|
||||
}
|
||||
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code) {
|
||||
web_contents()->GetMainFrame()->ExecuteJavaScript(code);
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture) {
|
||||
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
|
||||
}
|
||||
|
||||
void WebContents::OpenDevTools(mate::Arguments* args) {
|
||||
|
@ -685,6 +691,22 @@ void WebContents::PrintToPDF(const base::DictionaryValue& setting,
|
|||
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() {
|
||||
web_contents()->Undo();
|
||||
}
|
||||
|
@ -729,6 +751,14 @@ void WebContents::ReplaceMisspelling(const base::string16& 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,
|
||||
const base::ListValue& args) {
|
||||
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
|
||||
|
@ -767,6 +797,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
|||
.SetMethod("_goToOffset", &WebContents::GoToOffset)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
|
||||
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
|
||||
.SetMethod("insertCSS", &WebContents::InsertCSS)
|
||||
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
|
||||
.SetMethod("openDevTools", &WebContents::OpenDevTools)
|
||||
|
@ -787,6 +818,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
|||
.SetMethod("unselect", &WebContents::Unselect)
|
||||
.SetMethod("replace", &WebContents::Replace)
|
||||
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
|
||||
.SetMethod("focus", &WebContents::Focus)
|
||||
.SetMethod("tabTraverse", &WebContents::TabTraverse)
|
||||
.SetMethod("_send", &WebContents::SendIPCMessage, true)
|
||||
.SetMethod("setSize", &WebContents::SetSize)
|
||||
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
|
||||
|
@ -797,6 +830,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
|||
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
|
||||
.SetMethod("print", &WebContents::Print)
|
||||
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
|
||||
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
|
||||
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
|
||||
.SetProperty("session", &WebContents::Session)
|
||||
.Build());
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
public content::WebContentsObserver {
|
||||
public:
|
||||
// For node.js callback function type: function(error, buffer)
|
||||
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
|
||||
PrintToPDFCallback;
|
||||
using PrintToPDFCallback =
|
||||
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
|
||||
|
||||
// Create from an existing WebContents.
|
||||
static mate::Handle<WebContents> CreateFrom(
|
||||
|
@ -63,8 +63,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void GoToOffset(int offset);
|
||||
bool IsCrashed() const;
|
||||
void SetUserAgent(const std::string& user_agent);
|
||||
std::string GetUserAgent();
|
||||
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 CloseDevTools();
|
||||
bool IsDevToolsOpened();
|
||||
|
@ -82,6 +84,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void PrintToPDF(const base::DictionaryValue& setting,
|
||||
const PrintToPDFCallback& callback);
|
||||
|
||||
// DevTools workspace api.
|
||||
void AddWorkSpace(const base::FilePath& path);
|
||||
void RemoveWorkSpace(const base::FilePath& path);
|
||||
|
||||
// Editing commands.
|
||||
void Undo();
|
||||
void Redo();
|
||||
|
@ -95,6 +101,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void Replace(const base::string16& word);
|
||||
void ReplaceMisspelling(const base::string16& word);
|
||||
|
||||
// Focus.
|
||||
void Focus();
|
||||
void TabTraverse(bool reverse);
|
||||
|
||||
// Sending messages to browser.
|
||||
bool SendIPCMessage(const base::string16& channel,
|
||||
const base::ListValue& args);
|
||||
|
|
|
@ -8,18 +8,43 @@
|
|||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/browser.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/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.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"
|
||||
|
||||
#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 api {
|
||||
|
@ -413,6 +438,21 @@ void Window::SetOverlayIcon(const gfx::Image& overlay,
|
|||
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) {
|
||||
mate::Handle<Menu> menu;
|
||||
if (value->IsObject() &&
|
||||
|
@ -451,6 +491,12 @@ void Window::ShowDefinitionForSelection() {
|
|||
}
|
||||
#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) {
|
||||
return window_->SetVisibleOnAllWorkspaces(visible);
|
||||
}
|
||||
|
@ -498,6 +544,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("isMinimized", &Window::IsMinimized)
|
||||
.SetMethod("setFullScreen", &Window::SetFullScreen)
|
||||
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
||||
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
|
||||
.SetMethod("getBounds", &Window::GetBounds)
|
||||
.SetMethod("setBounds", &Window::SetBounds)
|
||||
.SetMethod("getSize", &Window::GetSize)
|
||||
|
@ -531,6 +578,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("capturePage", &Window::CapturePage)
|
||||
.SetMethod("setProgressBar", &Window::SetProgressBar)
|
||||
.SetMethod("setOverlayIcon", &Window::SetOverlayIcon)
|
||||
.SetMethod("setThumbarButtons", &Window::SetThumbarButtons)
|
||||
.SetMethod("setMenu", &Window::SetMenu)
|
||||
.SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar)
|
||||
.SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/native_window_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
|
@ -129,11 +130,13 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void SetProgressBar(double progress);
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description);
|
||||
bool SetThumbarButtons(mate::Arguments* args);
|
||||
void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu);
|
||||
void SetAutoHideMenuBar(bool auto_hide);
|
||||
bool IsMenuBarAutoHide();
|
||||
void SetMenuBarVisibility(bool visible);
|
||||
bool IsMenuBarVisible();
|
||||
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void ShowDefinitionForSelection();
|
||||
|
|
|
@ -37,9 +37,8 @@ v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
|
|||
EventEmitter::EventEmitter() {
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message) {
|
||||
v8::Local<v8::Object> EventEmitter::CreateJSEvent(
|
||||
v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
|
||||
v8::Local<v8::Object> event;
|
||||
bool use_native_event = sender && message;
|
||||
|
||||
|
@ -54,4 +53,12 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
|
|||
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
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/event_emitter_caller.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace content {
|
||||
|
@ -25,6 +25,14 @@ class EventEmitter : public Wrappable {
|
|||
public:
|
||||
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...);
|
||||
template<typename... Args>
|
||||
bool Emit(const base::StringPiece& name, const Args&... args) {
|
||||
|
@ -37,21 +45,31 @@ class EventEmitter : public Wrappable {
|
|||
content::WebContents* sender,
|
||||
IPC::Message* message,
|
||||
const Args&... args) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
||||
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
|
||||
return event->Get(
|
||||
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
|
||||
return EmitWithEvent(name, event, args...);
|
||||
}
|
||||
|
||||
protected:
|
||||
EventEmitter();
|
||||
|
||||
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,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message);
|
||||
v8::Local<v8::Object> CreateCustomEvent(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> event);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
|
||||
};
|
||||
|
|
|
@ -30,6 +30,15 @@ BrowserWindow::_init = ->
|
|||
@webContents.on '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.
|
||||
@on 'blur', (event) =>
|
||||
app.emit 'browser-window-blur', event, this
|
||||
|
|
|
@ -1,7 +1 @@
|
|||
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
|
||||
|
|
|
@ -11,6 +11,9 @@ fileDialogProperties =
|
|||
|
||||
messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']
|
||||
|
||||
messageBoxOptions =
|
||||
noLink: 1 << 0
|
||||
|
||||
parseArgs = (window, options, callback) ->
|
||||
unless window is null or window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
|
@ -101,10 +104,15 @@ module.exports =
|
|||
options.cancelId = i
|
||||
break
|
||||
|
||||
flags = if options.noLink then messageBoxOptions.noLink else 0
|
||||
|
||||
binding.showMessageBox messageBoxType,
|
||||
options.buttons,
|
||||
options.cancelId,
|
||||
[options.title, options.message, options.detail],
|
||||
flags,
|
||||
options.title,
|
||||
options.message,
|
||||
options.detail,
|
||||
options.icon,
|
||||
window,
|
||||
callback
|
||||
|
|
|
@ -40,6 +40,7 @@ class NavigationController
|
|||
loadUrl: (url, options={}) ->
|
||||
@pendingIndex = -1
|
||||
@webContents._loadUrl url, options
|
||||
@webContents.emit 'load-url', url, options
|
||||
|
||||
getUrl: ->
|
||||
if @currentIndex is -1
|
||||
|
|
|
@ -59,6 +59,6 @@ class RequestErrorJob
|
|||
|
||||
protocol.RequestHttpJob =
|
||||
class RequestHttpJob
|
||||
constructor: ({@url, @method, @referrer}) ->
|
||||
constructor: ({@session, @url, @method, @referrer}) ->
|
||||
|
||||
module.exports = protocol
|
||||
|
|
|
@ -3,8 +3,12 @@ bindings = process.atomBinding 'tray'
|
|||
|
||||
Tray = bindings.Tray
|
||||
Tray::__proto__ = EventEmitter.prototype
|
||||
|
||||
Tray::setContextMenu = (menu) ->
|
||||
@_setContextMenu menu
|
||||
@menu = menu # Keep a strong reference of menu.
|
||||
|
||||
# Keep compatibility with old APIs.
|
||||
Tray::popContextMenu = Tray::popUpContextMenu
|
||||
|
||||
module.exports = Tray
|
||||
|
|
|
@ -6,6 +6,34 @@ ipc = require 'ipc'
|
|||
nextId = 0
|
||||
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) ->
|
||||
# webContents is an EventEmitter.
|
||||
webContents.__proto__ = EventEmitter.prototype
|
||||
|
@ -18,11 +46,11 @@ wrapWebContents = (webContents) ->
|
|||
# web contents has been loaded.
|
||||
webContents.loaded = false
|
||||
webContents.once 'did-finish-load', -> @loaded = true
|
||||
webContents.executeJavaScript = (code) ->
|
||||
webContents.executeJavaScript = (code, hasUserGesture=false) ->
|
||||
if @loaded
|
||||
@_executeJavaScript code
|
||||
@_executeJavaScript code, hasUserGesture
|
||||
else
|
||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code)
|
||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
|
||||
|
||||
# The navigation controller.
|
||||
controller = new NavigationController(webContents)
|
||||
|
@ -41,32 +69,27 @@ wrapWebContents = (webContents) ->
|
|||
|
||||
webContents.printToPDF = (options, callback) ->
|
||||
printingSetting =
|
||||
pageRage:[],
|
||||
mediaSize:
|
||||
height_microns:297000,
|
||||
is_default:true,
|
||||
name:"ISO_A4",
|
||||
width_microns:210000,
|
||||
custom_display_name:"A4",
|
||||
landscape:false,
|
||||
color:2,
|
||||
headerFooterEnabled:false,
|
||||
marginsType:0,
|
||||
isFirstRequest:false,
|
||||
requestID: getNextId(),
|
||||
previewModifiable:true,
|
||||
printToPDF:true,
|
||||
printWithCloudPrint:false,
|
||||
printWithPrivet:false,
|
||||
printWithExtension:false,
|
||||
deviceName:"Save as PDF",
|
||||
generateDraftData:true,
|
||||
fitToPageEnabled:false,
|
||||
duplex:0,
|
||||
copies:1,
|
||||
collate:true,
|
||||
shouldPrintBackgrounds:false,
|
||||
shouldPrintSelectionOnly:false
|
||||
pageRage: []
|
||||
mediaSize: {}
|
||||
landscape: false
|
||||
color: 2
|
||||
headerFooterEnabled: false
|
||||
marginsType: 0
|
||||
isFirstRequest: false
|
||||
requestID: getNextId()
|
||||
previewModifiable: true
|
||||
printToPDF: true
|
||||
printWithCloudPrint: false
|
||||
printWithPrivet: false
|
||||
printWithExtension: false
|
||||
deviceName: "Save as PDF"
|
||||
generateDraftData: true
|
||||
fitToPageEnabled: false
|
||||
duplex: 0
|
||||
copies: 1
|
||||
collate: true
|
||||
shouldPrintBackgrounds: false
|
||||
shouldPrintSelectionOnly: false
|
||||
|
||||
if options.landscape
|
||||
printingSetting.landscape = options.landscape
|
||||
|
@ -77,6 +100,11 @@ wrapWebContents = (webContents) ->
|
|||
if options.printBackgrounds
|
||||
printingSetting.shouldPrintBackgrounds = options.printBackground
|
||||
|
||||
if options.pageSize and PDFPageSize[options.pageSize]
|
||||
printingSetting.mediaSize = PDFPageSize[options.pageSize]
|
||||
else
|
||||
printingSetting.mediaSize = PDFPageSize['A4']
|
||||
|
||||
@_printToPDF printingSetting, callback
|
||||
|
||||
binding._setWrapWebContents wrapWebContents
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
#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_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
|
@ -190,10 +194,20 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
|||
if (process_type != "renderer")
|
||||
return;
|
||||
|
||||
// The registered standard schemes.
|
||||
if (!g_custom_schemes.empty())
|
||||
command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes,
|
||||
g_custom_schemes);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Append --app-user-model-id.
|
||||
PWSTR current_app_id;
|
||||
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(¤t_app_id))) {
|
||||
command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id);
|
||||
CoTaskMemFree(current_app_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
NativeWindow* window;
|
||||
WebViewManager::WebViewInfo info;
|
||||
ProcessOwner owner = GetProcessOwner(process_id, &window, &info);
|
||||
|
|
|
@ -15,10 +15,13 @@
|
|||
#include "atom/common/chrome_version.h"
|
||||
#include "atom/common/options_switches.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/stringprintf.h"
|
||||
#include "base/threading/sequenced_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/common/url_constants.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
|
@ -146,4 +149,11 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
|
|||
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
|
||||
|
|
|
@ -32,6 +32,9 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
|||
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
|
||||
content::BrowserPluginGuestManager* GetGuestManager() override;
|
||||
|
||||
// brightray::BrowserContext:
|
||||
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
private:
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "base/bind.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_thread.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
|
@ -77,6 +80,11 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
|||
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,
|
||||
content::DownloadItem::TARGET_DISPOSITION_PROMPT,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
|
||||
|
@ -92,9 +100,14 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
|
|||
const content::DownloadTargetCallback& callback) {
|
||||
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();
|
||||
default_download_path_ = path.Append(FILE_PATH_LITERAL("Downloads"));
|
||||
default_download_path = path.Append(FILE_PATH_LITERAL("Downloads"));
|
||||
}
|
||||
|
||||
if (!download->GetForcedFilePath().empty()) {
|
||||
|
@ -118,7 +131,7 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
|
|||
download->GetContentDisposition(),
|
||||
download->GetSuggestedFilename(),
|
||||
download->GetMimeType(),
|
||||
default_download_path_,
|
||||
default_download_path,
|
||||
download_path_callback));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
|
|||
|
||||
private:
|
||||
content::DownloadManager* download_manager_;
|
||||
base::FilePath default_download_path_;
|
||||
base::WeakPtrFactory<AtomDownloadManagerDelegate> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomDownloadManagerDelegate);
|
||||
|
|
|
@ -274,16 +274,21 @@ void CommonWebContentsDelegate::DevToolsAppendToFile(
|
|||
base::Unretained(this), url));
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::DevToolsAddFileSystem() {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path;
|
||||
std::vector<base::FilePath> paths;
|
||||
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
|
||||
if (!file_dialog::ShowOpenDialog(owner_window(), "", default_path,
|
||||
filters, flag, &paths))
|
||||
return;
|
||||
void CommonWebContentsDelegate::DevToolsAddFileSystem(
|
||||
const base::FilePath& file_system_path) {
|
||||
base::FilePath path = file_system_path;
|
||||
if (path.empty()) {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path;
|
||||
std::vector<base::FilePath> paths;
|
||||
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 file_system_id = RegisterFileSystem(GetDevToolsWebContents(),
|
||||
path,
|
||||
|
@ -313,20 +318,20 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem() {
|
|||
}
|
||||
|
||||
void CommonWebContentsDelegate::DevToolsRemoveFileSystem(
|
||||
const std::string& file_system_path) {
|
||||
const base::FilePath& file_system_path) {
|
||||
if (!web_contents_)
|
||||
return;
|
||||
|
||||
base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
|
||||
storage::IsolatedContext::GetInstance()->RevokeFileSystemByPath(path);
|
||||
storage::IsolatedContext::GetInstance()->
|
||||
RevokeFileSystemByPath(file_system_path);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
base::StringValue file_system_path_value(file_system_path);
|
||||
base::StringValue file_system_path_value(file_system_path.AsUTF8Unsafe());
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.fileSystemRemoved",
|
||||
&file_system_path_value,
|
||||
|
|
|
@ -80,8 +80,9 @@ class CommonWebContentsDelegate
|
|||
bool save_as) override;
|
||||
void DevToolsAppendToFile(const std::string& url,
|
||||
const std::string& content) override;
|
||||
void DevToolsAddFileSystem() override;
|
||||
void DevToolsRemoveFileSystem(const std::string& file_system_path) override;
|
||||
void DevToolsAddFileSystem(const base::FilePath& path) override;
|
||||
void DevToolsRemoveFileSystem(
|
||||
const base::FilePath& file_system_path) override;
|
||||
|
||||
private:
|
||||
// Callback for when DevToolsSaveToFile has completed.
|
||||
|
|
|
@ -237,7 +237,7 @@ app.once('ready', function() {
|
|||
},
|
||||
{
|
||||
label: 'Toggle &Developer Tools',
|
||||
accelerator: 'Alt+Ctrl+I',
|
||||
accelerator: 'Shift+Ctrl+I',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
|
|
|
@ -3,6 +3,7 @@ webContents = require 'web-contents'
|
|||
webViewManager = null # Doesn't exist in early initialization.
|
||||
|
||||
supportedWebViewEvents = [
|
||||
'load-commit'
|
||||
'did-finish-load'
|
||||
'did-fail-load'
|
||||
'did-frame-finish-load'
|
||||
|
|
|
@ -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...) ->
|
||||
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
|
||||
|
|
|
@ -38,7 +38,7 @@ process.on 'uncaughtException', (error) ->
|
|||
# Show error in GUI.
|
||||
stack = error.stack ? "#{error.name}: #{error.message}"
|
||||
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.
|
||||
app = require 'app'
|
||||
|
|
|
@ -10,6 +10,7 @@ valueToMeta = (sender, value) ->
|
|||
meta.type = 'buffer' if Buffer.isBuffer value
|
||||
meta.type = 'value' if value is null
|
||||
meta.type = 'array' if Array.isArray value
|
||||
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
|
||||
|
||||
# Treat the arguments object as array.
|
||||
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
|
||||
else if meta.type is 'buffer'
|
||||
meta.value = Array::slice.call value, 0
|
||||
else if meta.type is 'promise'
|
||||
meta.then = valueToMeta(sender, value.then.bind(value))
|
||||
else
|
||||
meta.type = 'value'
|
||||
meta.value = value
|
||||
|
@ -47,6 +50,7 @@ unwrapArgs = (sender, args) ->
|
|||
when 'remote-object' then objectsRegistry.get meta.id
|
||||
when 'array' then unwrapArgs sender, meta.value
|
||||
when 'buffer' then new Buffer(meta.value)
|
||||
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
|
||||
when 'object'
|
||||
ret = v8Util.createObjectWithName meta.name
|
||||
for member in meta.members
|
||||
|
|
|
@ -8,10 +8,6 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
|
@ -72,6 +68,22 @@ const char* kWebRuntimeFeatures[] = {
|
|||
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
|
||||
|
||||
NativeWindow::NativeWindow(
|
||||
|
@ -85,6 +97,7 @@ NativeWindow::NativeWindow(
|
|||
node_integration_(true),
|
||||
has_dialog_attached_(false),
|
||||
zoom_factor_(1.0),
|
||||
aspect_ratio_(0.0),
|
||||
inspectable_web_contents_(inspectable_web_contents),
|
||||
weak_factory_(this) {
|
||||
inspectable_web_contents->GetView()->SetDelegate(this);
|
||||
|
@ -246,6 +259,20 @@ bool NativeWindow::IsMenuBarVisible() {
|
|||
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() {
|
||||
return has_dialog_attached_;
|
||||
}
|
||||
|
@ -369,15 +396,6 @@ void NativeWindow::AppendExtraCommandLineSwitches(
|
|||
command_line->AppendSwitchASCII(switches::kZoomFactor,
|
||||
base::DoubleToString(zoom_factor_));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Append --app-user-model-id.
|
||||
PWSTR current_app_id;
|
||||
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(¤t_app_id))) {
|
||||
command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id);
|
||||
CoTaskMemFree(current_app_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (web_preferences_.IsEmpty())
|
||||
return;
|
||||
|
||||
|
@ -424,6 +442,10 @@ void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
|
|||
prefs->allow_displaying_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 (content::PluginService::GetInstance()->NPAPIPluginsSupported()) {
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
|
@ -500,6 +522,12 @@ void NativeWindow::NotifyWindowLeaveHtmlFullScreen() {
|
|||
OnWindowLeaveHtmlFullScreen());
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowExecuteWindowsCommand(
|
||||
const std::string& command) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
|
||||
OnExecuteWindowsCommand(command));
|
||||
}
|
||||
|
||||
void NativeWindow::DevToolsFocused() {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsFocus());
|
||||
}
|
||||
|
@ -534,7 +562,7 @@ void NativeWindow::BeforeUnloadDialogCancelled() {
|
|||
void NativeWindow::TitleWasSet(content::NavigationEntry* entry,
|
||||
bool explicit_set) {
|
||||
bool prevent_default = false;
|
||||
std::string text = base::UTF16ToUTF8(entry->GetTitle());
|
||||
std::string text = entry ? base::UTF16ToUTF8(entry->GetTitle()) : "";
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
OnPageTitleUpdated(&prevent_default, text));
|
||||
|
@ -553,6 +581,14 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
|
|||
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) {
|
||||
if (!window_unresposive_closure_.IsCancelled())
|
||||
return;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
class SkRegion;
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
@ -57,7 +59,7 @@ struct DraggableRegion;
|
|||
class NativeWindow : public content::WebContentsObserver,
|
||||
public brightray::InspectableWebContentsViewDelegate {
|
||||
public:
|
||||
typedef base::Callback<void(const SkBitmap& bitmap)> CapturePageCallback;
|
||||
using CapturePageCallback = base::Callback<void(const SkBitmap& bitmap)>;
|
||||
|
||||
class DialogScope {
|
||||
public:
|
||||
|
@ -93,6 +95,7 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
|
||||
virtual void Close() = 0;
|
||||
virtual void CloseImmediately() = 0;
|
||||
virtual bool IsClosed() const { return is_closed_; }
|
||||
virtual void Focus(bool focus) = 0;
|
||||
virtual bool IsFocused() = 0;
|
||||
virtual void Show() = 0;
|
||||
|
@ -137,14 +140,17 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
virtual void SetMenu(ui::MenuModel* menu);
|
||||
virtual bool HasModalDialog();
|
||||
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
||||
|
||||
// Taskbar/Dock APIs.
|
||||
virtual void SetProgressBar(double progress) = 0;
|
||||
virtual void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) = 0;
|
||||
|
||||
// Workspace APIs.
|
||||
virtual void SetVisibleOnAllWorkspaces(bool visible) = 0;
|
||||
virtual bool IsVisibleOnAllWorkspaces() = 0;
|
||||
|
||||
virtual bool IsClosed() const { return is_closed_; }
|
||||
|
||||
// Webview APIs.
|
||||
virtual void FocusOnWebView();
|
||||
virtual void BlurWebView();
|
||||
virtual bool IsWebViewFocused();
|
||||
|
@ -163,6 +169,11 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
virtual void SetMenuBarVisibility(bool visible);
|
||||
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() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
@ -198,11 +209,11 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
void NotifyWindowLeaveFullScreen();
|
||||
void NotifyWindowEnterHtmlFullScreen();
|
||||
void NotifyWindowLeaveHtmlFullScreen();
|
||||
void NotifyWindowExecuteWindowsCommand(const std::string& command);
|
||||
|
||||
void AddObserver(NativeWindowObserver* obs) {
|
||||
observers_.AddObserver(obs);
|
||||
}
|
||||
|
||||
void RemoveObserver(NativeWindowObserver* obs) {
|
||||
observers_.RemoveObserver(obs);
|
||||
}
|
||||
|
@ -212,6 +223,10 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
}
|
||||
|
||||
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) {
|
||||
has_dialog_attached_ = has_dialog_attached;
|
||||
|
@ -221,10 +236,6 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
|
||||
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:
|
||||
void DevToolsFocused() override;
|
||||
void DevToolsOpened() override;
|
||||
|
@ -236,22 +247,11 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) 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:
|
||||
// Called when the window needs to update its draggable region.
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// Schedule a notification unresponsive event.
|
||||
void ScheduleUnresponsiveEvent(int ms);
|
||||
|
||||
|
@ -263,6 +263,22 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
const SkBitmap& bitmap,
|
||||
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.
|
||||
bool is_closed_;
|
||||
|
||||
|
@ -285,9 +301,17 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
// Page's default 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.
|
||||
brightray::InspectableWebContents* inspectable_web_contents_;
|
||||
|
||||
// Observers of this window.
|
||||
ObserverList<NativeWindowObserver> observers_;
|
||||
|
||||
base::WeakPtrFactory<NativeWindow> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindow);
|
||||
|
|
|
@ -11,13 +11,11 @@
|
|||
#include <vector>
|
||||
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
|
||||
@class AtomNSWindow;
|
||||
@class AtomNSWindowDelegate;
|
||||
@class FullSizeContentView;
|
||||
class SkRegion;
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -88,9 +86,6 @@ class NativeWindowMac : public NativeWindow {
|
|||
void ClipWebView();
|
||||
|
||||
protected:
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
|
||||
// NativeWindow:
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
|
@ -117,10 +112,6 @@ class NativeWindowMac : public NativeWindow {
|
|||
// The presentation options before entering kiosk mode.
|
||||
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
|
||||
// used in custom drag to compute the window movement.
|
||||
NSPoint last_mouse_offset_;
|
||||
|
|
|
@ -20,7 +20,26 @@
|
|||
#include "content/public/browser/render_widget_host_view.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)
|
||||
- (CGFloat)roundedCornerRadius;
|
||||
|
@ -95,6 +114,44 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
|||
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 {
|
||||
if (!shell_->has_frame())
|
||||
shell_->ClipWebView();
|
||||
|
@ -176,8 +233,12 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
|||
enable_larger_than_screen_ = enable;
|
||||
}
|
||||
|
||||
// Enable the window to be larger than 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_)
|
||||
return frameRect;
|
||||
else
|
||||
|
@ -280,29 +341,6 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
|||
|
||||
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(
|
||||
brightray::InspectableWebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
|
@ -325,7 +363,7 @@ NativeWindowMac::NativeWindowMac(
|
|||
|
||||
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask;
|
||||
if (!useStandardWindow || transparent_ || !has_frame_) {
|
||||
if (!useStandardWindow || transparent() || !has_frame()) {
|
||||
styleMask |= NSTexturedBackgroundWindowMask;
|
||||
}
|
||||
|
||||
|
@ -335,12 +373,12 @@ NativeWindowMac::NativeWindowMac(
|
|||
backing:NSBackingStoreBuffered
|
||||
defer:YES]);
|
||||
[window_ setShell:this];
|
||||
[window_ setEnableLargerThanScreen:enable_larger_than_screen_];
|
||||
[window_ setEnableLargerThanScreen:enable_larger_than_screen()];
|
||||
|
||||
window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
|
||||
[window_ setDelegate:window_delegate_];
|
||||
|
||||
if (transparent_) {
|
||||
if (transparent()) {
|
||||
// Make window has transparent background.
|
||||
[window_ setOpaque:NO];
|
||||
[window_ setHasShadow:NO];
|
||||
|
@ -348,7 +386,7 @@ NativeWindowMac::NativeWindowMac(
|
|||
}
|
||||
|
||||
// Remove non-transparent corners, see http://git.io/vfonD.
|
||||
if (!has_frame_)
|
||||
if (!has_frame())
|
||||
[window_ setOpaque:NO];
|
||||
|
||||
// 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.
|
||||
bool use_content_size = false;
|
||||
options.Get(switches::kUseContentSize, &use_content_size);
|
||||
if (has_frame_ && !use_content_size)
|
||||
if (!has_frame() || !use_content_size)
|
||||
SetSize(gfx::Size(width, height));
|
||||
|
||||
// Enable the NSView to accept first mouse event.
|
||||
|
@ -494,6 +532,11 @@ gfx::Rect NativeWindowMac::GetBounds() {
|
|||
}
|
||||
|
||||
void NativeWindowMac::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame()) {
|
||||
SetSize(size);
|
||||
return;
|
||||
}
|
||||
|
||||
NSRect frame_nsrect = [window_ frame];
|
||||
NSSize frame = 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() {
|
||||
if (!has_frame())
|
||||
return GetSize();
|
||||
|
||||
NSRect bounds = [[window_ contentView] bounds];
|
||||
return gfx::Size(bounds.size.width, bounds.size.height);
|
||||
}
|
||||
|
@ -538,12 +584,15 @@ gfx::Size NativeWindowMac::GetMaximumSize() {
|
|||
}
|
||||
|
||||
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) {
|
||||
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:YES];
|
||||
[window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask];
|
||||
} else {
|
||||
[[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) {
|
||||
// We don't want the title to show in transparent window.
|
||||
if (transparent_)
|
||||
if (transparent())
|
||||
return;
|
||||
|
||||
[window_ setTitle:base::SysUTF8ToNSString(title)];
|
||||
|
@ -701,7 +750,7 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
|
|||
}
|
||||
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region_)
|
||||
if (!draggable_region())
|
||||
return false;
|
||||
if (!web_contents())
|
||||
return false;
|
||||
|
@ -710,7 +759,7 @@ bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
|||
// |draggable_region_| is stored in local platform-indepdent coordiate system
|
||||
// while |point| is in local Cocoa coordinate system. Do the conversion
|
||||
// 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) {
|
||||
|
@ -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(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
|
@ -765,7 +805,7 @@ void NativeWindowMac::HandleKeyboardEvent(
|
|||
|
||||
void NativeWindowMac::InstallView() {
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
if (has_frame_) {
|
||||
if (has_frame()) {
|
||||
// Add layer with white background for the contents view.
|
||||
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
|
||||
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shobjidl.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -20,7 +16,6 @@
|
|||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
@ -36,26 +31,20 @@
|
|||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/ui/views/global_menu_bar_x11.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/x_window_utils.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/nix/xdg_util.h"
|
||||
#include "base/strings/string_util.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/gfx/x/x11_types.h"
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
#elif defined(OS_WIN)
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
#include "base/win/scoped_comptr.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "ui/gfx/icon_util.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
|
||||
|
||||
namespace atom {
|
||||
|
@ -69,42 +58,6 @@ const int kMenuBarHeight = 20;
|
|||
const int kMenuBarHeight = 25;
|
||||
#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) {
|
||||
#if defined(USE_X11)
|
||||
// 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:
|
||||
return "dictate-or-command-control-toggle";
|
||||
default:
|
||||
return "unkown";
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -231,7 +184,7 @@ NativeWindowViews::NativeWindowViews(
|
|||
options.Get(switches::kResizable, &resizable_);
|
||||
#endif
|
||||
|
||||
if (enable_larger_than_screen_)
|
||||
if (enable_larger_than_screen())
|
||||
// We need to set a default maximum window size here otherwise Windows
|
||||
// will not allow us to resize the window larger than scree.
|
||||
// Setting directly to INT_MAX somehow doesn't work, so we just devide
|
||||
|
@ -251,12 +204,20 @@ NativeWindowViews::NativeWindowViews(
|
|||
params.bounds = bounds;
|
||||
params.delegate = this;
|
||||
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;
|
||||
|
||||
#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();
|
||||
// Set WM_WINDOW_ROLE.
|
||||
params.wm_role_name = "browser-window";
|
||||
|
@ -311,24 +272,24 @@ NativeWindowViews::NativeWindowViews(
|
|||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
AddChildView(web_view_);
|
||||
|
||||
if (has_frame_ &&
|
||||
if (has_frame() &&
|
||||
options.Get(switches::kUseContentSize, &use_content_size_) &&
|
||||
use_content_size_)
|
||||
bounds = ContentBoundsToWindowBounds(bounds);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
if (!has_frame_) {
|
||||
if (!has_frame()) {
|
||||
// Set Window style so that we get a minimize and maximize animation when
|
||||
// frameless.
|
||||
DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
|
||||
WS_CAPTION;
|
||||
// We should not show a frame for transparent window.
|
||||
if (transparent_)
|
||||
if (transparent())
|
||||
frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
|
||||
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
|
||||
}
|
||||
|
||||
if (transparent_) {
|
||||
if (transparent()) {
|
||||
// Transparent window on Windows has to have WS_EX_COMPOSITED style.
|
||||
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
|
||||
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
|
||||
// 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_->FrameTypeChanged();
|
||||
}
|
||||
|
||||
// The given window is most likely not rectangular since it uses
|
||||
// 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);
|
||||
|
||||
window_->UpdateWindowIcon();
|
||||
|
@ -468,7 +429,7 @@ gfx::Rect NativeWindowViews::GetBounds() {
|
|||
}
|
||||
|
||||
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame_) {
|
||||
if (!has_frame()) {
|
||||
NativeWindow::SetSize(size);
|
||||
return;
|
||||
}
|
||||
|
@ -479,7 +440,7 @@ void NativeWindowViews::SetContentSize(const gfx::Size& size) {
|
|||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetContentSize() {
|
||||
if (!has_frame_)
|
||||
if (!has_frame())
|
||||
return GetSize();
|
||||
|
||||
gfx::Size content_size =
|
||||
|
@ -491,14 +452,6 @@ gfx::Size NativeWindowViews::GetContentSize() {
|
|||
|
||||
void NativeWindowViews::SetMinimumSize(const gfx::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() {
|
||||
|
@ -507,14 +460,6 @@ gfx::Size NativeWindowViews::GetMinimumSize() {
|
|||
|
||||
void NativeWindowViews::SetMaximumSize(const gfx::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() {
|
||||
|
@ -643,7 +588,7 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
|||
#endif
|
||||
|
||||
// Do not show menu bar in frameless window.
|
||||
if (!has_frame_)
|
||||
if (!has_frame())
|
||||
return;
|
||||
|
||||
if (!menu_bar_) {
|
||||
|
@ -668,24 +613,7 @@ gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
|
|||
|
||||
void NativeWindowViews::SetProgressBar(double progress) {
|
||||
#if defined(OS_WIN)
|
||||
if (base::win::GetVersion() < base::win::VERSION_WIN7)
|
||||
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);
|
||||
}
|
||||
taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress);
|
||||
#elif defined(USE_X11)
|
||||
if (unity::IsRunning()) {
|
||||
unity::SetProgressFraction(progress);
|
||||
|
@ -696,22 +624,7 @@ void NativeWindowViews::SetProgressBar(double progress) {
|
|||
void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) {
|
||||
#if defined(OS_WIN)
|
||||
if (base::win::GetVersion() < base::win::VERSION_WIN7)
|
||||
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());
|
||||
taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay, description);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -768,29 +681,6 @@ gfx::AcceleratedWidget NativeWindowViews::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(
|
||||
views::Widget* widget, bool active) {
|
||||
if (widget != window_.get())
|
||||
|
@ -850,7 +740,7 @@ bool NativeWindowViews::ShouldHandleSystemCommands() const {
|
|||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() {
|
||||
return icon_;
|
||||
return icon();
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowIcon() {
|
||||
|
@ -873,12 +763,12 @@ bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
|||
gfx::NativeView child,
|
||||
const gfx::Point& location) {
|
||||
// App window should claim mouse events that fall within the draggable region.
|
||||
if (draggable_region_ &&
|
||||
draggable_region_->contains(location.x(), location.y()))
|
||||
if (draggable_region() &&
|
||||
draggable_region()->contains(location.x(), location.y()))
|
||||
return false;
|
||||
|
||||
// And the events on border for dragging resizable frameless window.
|
||||
if (!has_frame_ && CanResize()) {
|
||||
if (!has_frame() && CanResize()) {
|
||||
FramelessView* frame = static_cast<FramelessView*>(
|
||||
window_->non_client_view()->frame_view());
|
||||
return frame->ResizingBorderHitTest(location) == HTNOWHERE;
|
||||
|
@ -898,8 +788,8 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
|
|||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
#else
|
||||
if (has_frame_) {
|
||||
return new views::NativeFrameView(widget);
|
||||
if (has_frame()) {
|
||||
return new NativeFrameView(this, widget);
|
||||
} else {
|
||||
FramelessView* frame_view = new FramelessView;
|
||||
frame_view->Init(this, widget);
|
||||
|
@ -929,10 +819,8 @@ bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
|
|||
} else if ((command_id & sc_mask) == SC_MAXIMIZE) {
|
||||
NotifyWindowMaximize();
|
||||
} else {
|
||||
std::string command = AppCommandToString(command_id & sc_mask);
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
OnExecuteWindowsCommand(command));
|
||||
std::string command = AppCommandToString(command_id);
|
||||
NotifyWindowExecuteWindowsCommand(command);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -950,6 +838,17 @@ void NativeWindowViews::GetDevToolsWindowWMClass(
|
|||
}
|
||||
#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(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
#include "ui/views/widget/widget_delegate.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 {
|
||||
class UnhandledKeyboardEventHandler;
|
||||
}
|
||||
|
@ -24,7 +29,14 @@ class GlobalMenuBarX11;
|
|||
class MenuBar;
|
||||
class WindowStateWatcher;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
class AtomDesktopWindowTreeHostWin;
|
||||
#endif
|
||||
|
||||
class NativeWindowViews : public NativeWindow,
|
||||
#if defined(OS_WIN)
|
||||
public MessageHandlerDelegate,
|
||||
#endif
|
||||
public views::WidgetDelegateView,
|
||||
public views::WidgetObserver {
|
||||
public:
|
||||
|
@ -82,14 +94,13 @@ class NativeWindowViews : public NativeWindow,
|
|||
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget();
|
||||
|
||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||
views::Widget* widget() const { return window_.get(); }
|
||||
|
||||
private:
|
||||
// NativeWindow:
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
#if defined(OS_WIN)
|
||||
TaskbarHost& taskbar_host() { return taskbar_host_; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// views::WidgetObserver:
|
||||
void OnWidgetActivationChanged(
|
||||
views::Widget* widget, bool active) override;
|
||||
|
@ -127,6 +138,12 @@ class NativeWindowViews : public NativeWindow,
|
|||
std::string* name, std::string* class_name) override;
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// MessageHandlerDelegate:
|
||||
bool PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
|
||||
#endif
|
||||
|
||||
// NativeWindow:
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
|
@ -159,9 +176,13 @@ class NativeWindowViews : public NativeWindow,
|
|||
// Handles window state events.
|
||||
scoped_ptr<WindowStateWatcher> window_state_watcher_;
|
||||
#elif defined(OS_WIN)
|
||||
// Weak ref.
|
||||
AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_;
|
||||
// Records window was whether restored from minimized state or maximized
|
||||
// state.
|
||||
bool is_minimized_;
|
||||
// In charge of running taskbar related APIs.
|
||||
TaskbarHost taskbar_host_;
|
||||
#endif
|
||||
|
||||
// Handles unhandled keyboard messages coming back from the renderer process.
|
||||
|
@ -177,8 +198,6 @@ class NativeWindowViews : public NativeWindow,
|
|||
gfx::Size maximum_size_;
|
||||
gfx::Size widget_size_;
|
||||
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "atom/browser/net/adapter_request_job.h"
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "atom/browser/net/url_request_buffer_job.h"
|
||||
#include "atom/browser/net/url_request_fetch_job.h"
|
||||
|
@ -28,11 +27,7 @@ AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
|
|||
|
||||
void AdapterRequestJob::Start() {
|
||||
DCHECK(!real_job_.get());
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
GetJobType();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Kill() {
|
||||
|
@ -44,7 +39,11 @@ bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
|
|||
int buf_size,
|
||||
int *bytes_read) {
|
||||
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,
|
||||
|
@ -76,6 +75,11 @@ int AdapterRequestJob::GetResponseCode() const {
|
|||
return real_job_->GetResponseCode();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const {
|
||||
real_job_->GetLoadTimingInfo(load_timing_info);
|
||||
}
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
@ -115,7 +119,7 @@ void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
|
|||
}
|
||||
|
||||
void AdapterRequestJob::CreateHttpJobAndStart(
|
||||
AtomBrowserContext* browser_context,
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer) {
|
||||
|
@ -124,7 +128,7 @@ void AdapterRequestJob::CreateHttpJobAndStart(
|
|||
return;
|
||||
}
|
||||
|
||||
real_job_ = new URLRequestFetchJob(browser_context, request(),
|
||||
real_job_ = new URLRequestFetchJob(request_context_getter, request(),
|
||||
network_delegate(), url, method, referrer);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
@ -132,10 +136,13 @@ void AdapterRequestJob::CreateHttpJobAndStart(
|
|||
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
|
||||
real_job_ = protocol_handler_->MaybeCreateJob(request(),
|
||||
network_delegate());
|
||||
if (!real_job_.get())
|
||||
if (!real_job_.get()) {
|
||||
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
|
||||
else
|
||||
} else {
|
||||
// Copy headers from original request.
|
||||
real_job_->SetExtraRequestHeaders(request()->extra_request_headers());
|
||||
real_job_->Start();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/memory/weak_ptr.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_factory.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
@ -45,13 +46,15 @@ class AdapterRequestJob : public net::URLRequestJob {
|
|||
bool GetCharset(std::string* charset) override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
int GetResponseCode() const override;
|
||||
void GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const override;
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
|
||||
|
||||
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
|
||||
|
||||
// Override this function to determine which job should be started.
|
||||
virtual void GetJobTypeInUI() = 0;
|
||||
virtual void GetJobType() = 0;
|
||||
|
||||
void CreateErrorJobAndStart(int error_code);
|
||||
void CreateStringJobAndStart(const std::string& mime_type,
|
||||
|
@ -61,10 +64,11 @@ class AdapterRequestJob : public net::URLRequestJob {
|
|||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data);
|
||||
void CreateFileJobAndStart(const base::FilePath& path);
|
||||
void CreateHttpJobAndStart(AtomBrowserContext* browser_context,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
void CreateHttpJobAndStart(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
void CreateJobFromProtocolHandlerAndStart();
|
||||
|
||||
private:
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/thread_task_runner_handle.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_fetcher.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"
|
||||
|
||||
namespace atom {
|
||||
|
@ -74,7 +75,7 @@ class ResponsePiper : public net::URLFetcherResponseWriter {
|
|||
} // namespace
|
||||
|
||||
URLRequestFetchJob::URLRequestFetchJob(
|
||||
AtomBrowserContext* browser_context,
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
|
@ -90,7 +91,12 @@ URLRequestFetchJob::URLRequestFetchJob(
|
|||
request_type = GetRequestType(method);
|
||||
|
||||
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)));
|
||||
|
||||
// Use |request|'s referrer if |referrer| is not specified.
|
||||
|
@ -101,10 +107,18 @@ URLRequestFetchJob::URLRequestFetchJob(
|
|||
}
|
||||
|
||||
// Use |request|'s headers.
|
||||
net::HttpRequestHeaders headers;
|
||||
if (request->GetFullRequestHeaders(&headers)) {
|
||||
fetcher_->SetExtraRequestHeaders(headers.ToString());
|
||||
fetcher_->SetExtraRequestHeaders(request->extra_request_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() {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_fetcher_delegate.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
|
||||
|
@ -17,13 +18,14 @@ class AtomBrowserContext;
|
|||
class URLRequestFetchJob : public net::URLRequestJob,
|
||||
public net::URLFetcherDelegate {
|
||||
public:
|
||||
URLRequestFetchJob(AtomBrowserContext* browser_context,
|
||||
URLRequestFetchJob(scoped_refptr<net::URLRequestContextGetter> context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
|
||||
net::URLRequestContextGetter* GetRequestContext();
|
||||
void HeadersCompleted();
|
||||
int DataAvailable(net::IOBuffer* buffer, int num_bytes);
|
||||
|
||||
|
@ -41,6 +43,7 @@ class URLRequestFetchJob : public net::URLRequestJob,
|
|||
void OnURLFetchComplete(const net::URLFetcher* source) override;
|
||||
|
||||
private:
|
||||
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
|
||||
scoped_ptr<net::URLFetcher> fetcher_;
|
||||
scoped_refptr<net::IOBuffer> pending_buffer_;
|
||||
int pending_buffer_size_;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.29.2</string>
|
||||
<string>0.30.4</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
|
|
@ -56,8 +56,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,29,2,0
|
||||
PRODUCTVERSION 0,29,2,0
|
||||
FILEVERSION 0,30,4,0
|
||||
PRODUCTVERSION 0,30,4,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -74,12 +74,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.29.2"
|
||||
VALUE "FileVersion", "0.30.4"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.29.2"
|
||||
VALUE "ProductVersion", "0.30.4"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
|
22
atom/browser/ui/atom_menu_model.cc
Normal file
22
atom/browser/ui/atom_menu_model.cc
Normal 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
|
47
atom/browser/ui/atom_menu_model.h
Normal file
47
atom/browser/ui/atom_menu_model.h
Normal 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_
|
|
@ -5,61 +5,15 @@
|
|||
|
||||
#import "atom/browser/ui/cocoa/atom_menu_controller.h"
|
||||
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/base/accelerators/platform_accelerator_cocoa.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"
|
||||
|
||||
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)
|
||||
- (void)addSeparatorToMenu:(NSMenu*)menu
|
||||
atIndex:(int)index;
|
||||
|
@ -166,8 +120,7 @@ int EventFlagsFromNSEvent(NSEvent* event) {
|
|||
[item setTarget:nil];
|
||||
[item setAction:nil];
|
||||
ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index);
|
||||
NSMenu* submenu =
|
||||
[self menuFromModel:(ui::SimpleMenuModel*)submenuModel];
|
||||
NSMenu* submenu = [self menuFromModel:submenuModel];
|
||||
[submenu setTitle:[item title]];
|
||||
[item setSubmenu:submenu];
|
||||
|
||||
|
@ -246,8 +199,9 @@ int EventFlagsFromNSEvent(NSEvent* event) {
|
|||
[[sender representedObject] pointerValue]);
|
||||
DCHECK(model);
|
||||
if (model) {
|
||||
int event_flags = EventFlagsFromNSEvent([NSApp currentEvent]);
|
||||
model->ActivatedAt(modelIndex, event_flags);
|
||||
NSEvent* event = [NSApp currentEvent];
|
||||
model->ActivatedAt(modelIndex,
|
||||
ui::EventFlagsFromModifiers([event modifierFlags]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,25 +18,11 @@ namespace file_dialog {
|
|||
|
||||
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) {
|
||||
NSMutableSet* file_type_set = [NSMutableSet set];
|
||||
for (size_t i = 0; i < filters.size(); ++i) {
|
||||
const Filter& filter = filters[i];
|
||||
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::SysUTF8ToCFStringRef(filter.second[j]));
|
||||
[file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];
|
||||
|
|
|
@ -27,12 +27,18 @@ enum MessageBoxType {
|
|||
MESSAGE_BOX_TYPE_QUESTION,
|
||||
};
|
||||
|
||||
enum MessageBoxOptions {
|
||||
MESSAGE_BOX_NONE = 0,
|
||||
MESSAGE_BOX_NO_LINK = 1 << 0,
|
||||
};
|
||||
|
||||
typedef base::Callback<void(int code)> MessageBoxCallback;
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
@ -42,6 +48,7 @@ void ShowMessageBox(NativeWindow* parent_window,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
|
|
@ -162,6 +162,7 @@ int ShowMessageBox(NativeWindow* parent,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
@ -174,6 +175,7 @@ void ShowMessageBox(NativeWindow* parent,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
|
|
@ -95,6 +95,7 @@ int ShowMessageBox(NativeWindow* parent_window,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
@ -127,6 +128,7 @@ void ShowMessageBox(NativeWindow* parent_window,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/strings/string_util.h"
|
||||
|
@ -72,6 +73,7 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
MessageBoxType type,
|
||||
const std::vector<base::string16>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const base::string16& title,
|
||||
const base::string16& message,
|
||||
const base::string16& detail,
|
||||
|
@ -86,7 +88,12 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
config.hInstance = GetModuleHandle(NULL);
|
||||
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();
|
||||
|
||||
base::win::ScopedHICON hicon;
|
||||
|
@ -122,11 +129,17 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
// and custom buttons in pButtons.
|
||||
std::map<int, int> id_map;
|
||||
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) {
|
||||
config.pButtons = &dialog_buttons.front();
|
||||
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;
|
||||
|
@ -144,13 +157,14 @@ void RunMessageBoxInNewThread(base::Thread* thread,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
int result = ShowMessageBox(parent, type, buttons, cancel_id, title, message,
|
||||
detail, icon);
|
||||
int result = ShowMessageBox(parent, type, buttons, cancel_id, options, title,
|
||||
message, detail, icon);
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
|
||||
content::BrowserThread::DeleteSoon(
|
||||
|
@ -163,6 +177,7 @@ int ShowMessageBox(NativeWindow* parent,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
@ -180,6 +195,7 @@ int ShowMessageBox(NativeWindow* parent,
|
|||
type,
|
||||
utf16_buttons,
|
||||
cancel_id,
|
||||
options,
|
||||
base::UTF8ToUTF16(title),
|
||||
base::UTF8ToUTF16(message),
|
||||
base::UTF8ToUTF16(detail),
|
||||
|
@ -190,6 +206,7 @@ void ShowMessageBox(NativeWindow* parent,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
@ -207,12 +224,12 @@ void ShowMessageBox(NativeWindow* parent,
|
|||
unretained->message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained),
|
||||
parent, type, buttons, cancel_id, title, message, detail, icon,
|
||||
callback));
|
||||
parent, type, buttons, cancel_id, options, title, message,
|
||||
detail, icon, callback));
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -26,12 +26,16 @@ void TrayIcon::DisplayBalloon(const gfx::Image& icon,
|
|||
const base::string16& contents) {
|
||||
}
|
||||
|
||||
void TrayIcon::NotifyClicked(const gfx::Rect& bounds) {
|
||||
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds));
|
||||
void TrayIcon::PopUpContextMenu(const gfx::Point& pos) {
|
||||
}
|
||||
|
||||
void TrayIcon::NotifyDoubleClicked() {
|
||||
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDoubleClicked());
|
||||
void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
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() {
|
||||
|
@ -46,4 +50,13 @@ void TrayIcon::NotifyBalloonClosed() {
|
|||
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
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define ATOM_BROWSER_UI_TRAY_ICON_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/ui/tray_icon_observer.h"
|
||||
#include "base/observer_list.h"
|
||||
|
@ -46,16 +47,21 @@ class TrayIcon {
|
|||
const base::string16& title,
|
||||
const base::string16& contents);
|
||||
|
||||
virtual void PopUpContextMenu(const gfx::Point& pos);
|
||||
|
||||
// Set the context menu for this icon.
|
||||
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0;
|
||||
|
||||
void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); }
|
||||
void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); }
|
||||
void NotifyClicked(const gfx::Rect& = gfx::Rect());
|
||||
void NotifyDoubleClicked();
|
||||
void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
|
||||
void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
|
||||
void NotifyBalloonShow();
|
||||
void NotifyBalloonClicked();
|
||||
void NotifyBalloonClosed();
|
||||
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(),
|
||||
int modifiers = 0);
|
||||
void NotfiyDropFiles(const std::vector<std::string>& files);
|
||||
|
||||
protected:
|
||||
TrayIcon();
|
||||
|
|
|
@ -9,15 +9,17 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
#include "atom/browser/ui/tray_icon.h"
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
|
||||
@class AtomMenuController;
|
||||
@class StatusItemController;
|
||||
@class StatusItemView;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class TrayIconCocoa : public TrayIcon {
|
||||
class TrayIconCocoa : public TrayIcon,
|
||||
public AtomMenuModel::Observer {
|
||||
public:
|
||||
TrayIconCocoa();
|
||||
virtual ~TrayIconCocoa();
|
||||
|
@ -27,16 +29,23 @@ class TrayIconCocoa : public TrayIcon {
|
|||
void SetToolTip(const std::string& tool_tip) override;
|
||||
void SetTitle(const std::string& title) override;
|
||||
void SetHighlightMode(bool highlight) override;
|
||||
void PopUpContextMenu(const gfx::Point& pos) override;
|
||||
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
|
||||
|
||||
private:
|
||||
base::scoped_nsobject<NSStatusItem> item_;
|
||||
protected:
|
||||
// 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.
|
||||
base::scoped_nsobject<AtomMenuController> menu_;
|
||||
|
||||
// Used for unregistering observer.
|
||||
AtomMenuModel* menu_model_; // weak ref.
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TrayIconCocoa);
|
||||
};
|
||||
|
||||
|
|
|
@ -6,84 +6,333 @@
|
|||
|
||||
#include "atom/browser/ui/cocoa/atom_menu_controller.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/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
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
- (void)handleClick:(id)sender {
|
||||
// Get the frame of the NSStatusItem.
|
||||
NSRect frame = [NSApp currentEvent].window.frame;
|
||||
- (void)removeItem {
|
||||
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem_];
|
||||
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));
|
||||
// Flip coordinates to gfx (0,0 in top-left corner) using current screen.
|
||||
NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
|
||||
bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
|
||||
|
||||
trayIcon_->NotifyClicked(bounds);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (void)handleDoubleClick:(id)sender {
|
||||
trayIcon_->NotifyDoubleClicked();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace atom {
|
||||
|
||||
TrayIconCocoa::TrayIconCocoa() {
|
||||
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() : menu_model_(nullptr) {
|
||||
}
|
||||
|
||||
TrayIconCocoa::~TrayIconCocoa() {
|
||||
// Remove the status item from the status bar.
|
||||
[[NSStatusBar systemStatusBar] removeStatusItem:item_];
|
||||
[status_item_view_ removeItem];
|
||||
if (menu_model_)
|
||||
menu_model_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
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) {
|
||||
[item_ setAlternateImage:image.AsNSImage()];
|
||||
[status_item_view_ setAlternateImage:image.AsNSImage()];
|
||||
}
|
||||
|
||||
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) {
|
||||
[item_ setTitle:base::SysUTF8ToNSString(title)];
|
||||
[status_item_view_ setTitle:base::SysUTF8ToNSString(title)];
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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]);
|
||||
[item_ setMenu:[menu_ menu]];
|
||||
[status_item_view_ setMenuController:menu_.get()];
|
||||
}
|
||||
|
||||
void TrayIconCocoa::MenuClosed() {
|
||||
[status_item_view_ setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#ifndef ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_
|
||||
#define ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gfx {
|
||||
class Rect;
|
||||
}
|
||||
|
@ -13,11 +16,13 @@ namespace atom {
|
|||
|
||||
class TrayIconObserver {
|
||||
public:
|
||||
virtual void OnClicked(const gfx::Rect&) {}
|
||||
virtual void OnDoubleClicked() {}
|
||||
virtual void OnClicked(const gfx::Rect& bounds, int modifiers) {}
|
||||
virtual void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {}
|
||||
virtual void OnBalloonShow() {}
|
||||
virtual void OnBalloonClicked() {}
|
||||
virtual void OnBalloonClosed() {}
|
||||
virtual void OnRightClicked(const gfx::Rect& bounds, int modifiers) {}
|
||||
virtual void OnDropFiles(const std::vector<std::string>& files) {}
|
||||
|
||||
protected:
|
||||
virtual ~TrayIconObserver() {}
|
||||
|
|
35
atom/browser/ui/views/native_frame_view.cc
Normal file
35
atom/browser/ui/views/native_frame_view.cc
Normal 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
|
34
atom/browser/ui/views/native_frame_view.h
Normal file
34
atom/browser/ui/views/native_frame_view.h
Normal 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_
|
28
atom/browser/ui/win/atom_desktop_window_tree_host_win.cc
Normal file
28
atom/browser/ui/win/atom_desktop_window_tree_host_win.cc
Normal 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
|
39
atom/browser/ui/win/atom_desktop_window_tree_host_win.h
Normal file
39
atom/browser/ui/win/atom_desktop_window_tree_host_win.h
Normal 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_
|
14
atom/browser/ui/win/message_handler_delegate.cc
Normal file
14
atom/browser/ui/win/message_handler_delegate.cc
Normal 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
|
26
atom/browser/ui/win/message_handler_delegate.h
Normal file
26
atom/browser/ui/win/message_handler_delegate.h
Normal 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_
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
#include "atom/browser/ui/win/notify_icon.h"
|
||||
|
||||
#include <shobjidl.h>
|
||||
|
||||
#include "atom/browser/ui/win/notify_icon_host.h"
|
||||
#include "base/md5.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
@ -25,10 +28,34 @@ NotifyIcon::NotifyIcon(NotifyIconHost* host,
|
|||
icon_id_(id),
|
||||
window_(window),
|
||||
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;
|
||||
InitIconData(&icon_data);
|
||||
icon_data.uFlags = NIF_MESSAGE;
|
||||
icon_data.uFlags |= NIF_MESSAGE;
|
||||
icon_data.uCallbackMessage = message_id_;
|
||||
BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data);
|
||||
// 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,
|
||||
bool left_mouse_click) {
|
||||
// Pass to the observer if appropriate.
|
||||
int modifiers,
|
||||
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) {
|
||||
NOTIFYICONIDENTIFIER icon_id;
|
||||
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
|
||||
icon_id.uID = icon_id_;
|
||||
icon_id.hWnd = window_;
|
||||
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
|
||||
|
||||
RECT rect = { 0 };
|
||||
Shell_NotifyIconGetRect(&icon_id, &rect);
|
||||
|
||||
NotifyClicked(gfx::Rect(rect));
|
||||
if (double_button_click) // double left click
|
||||
NotifyDoubleClicked(gfx::Rect(rect), modifiers);
|
||||
else // single left click
|
||||
NotifyClicked(gfx::Rect(rect), modifiers);
|
||||
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() {
|
||||
|
@ -87,7 +109,7 @@ void NotifyIcon::ResetIcon() {
|
|||
// Delete any previously existing icon.
|
||||
Shell_NotifyIcon(NIM_DELETE, &icon_data);
|
||||
InitIconData(&icon_data);
|
||||
icon_data.uFlags = NIF_MESSAGE;
|
||||
icon_data.uFlags |= NIF_MESSAGE;
|
||||
icon_data.uCallbackMessage = message_id_;
|
||||
icon_data.hIcon = icon_.Get();
|
||||
// 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.
|
||||
NOTIFYICONDATA icon_data;
|
||||
InitIconData(&icon_data);
|
||||
icon_data.uFlags = NIF_ICON;
|
||||
icon_data.uFlags |= NIF_ICON;
|
||||
icon_.Set(IconUtil::CreateHICONFromSkBitmap(image.AsBitmap()));
|
||||
icon_data.hIcon = icon_.Get();
|
||||
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
|
||||
|
@ -121,7 +143,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
|
|||
// Create the icon.
|
||||
NOTIFYICONDATA 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());
|
||||
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
|
||||
if (!result)
|
||||
|
@ -133,7 +155,7 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
|
|||
const base::string16& contents) {
|
||||
NOTIFYICONDATA icon_data;
|
||||
InitIconData(&icon_data);
|
||||
icon_data.uFlags = NIF_INFO;
|
||||
icon_data.uFlags |= NIF_INFO;
|
||||
icon_data.dwInfoFlags = NIIF_INFO;
|
||||
wcscpy_s(icon_data.szInfoTitle, title.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.";
|
||||
}
|
||||
|
||||
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) {
|
||||
menu_model_ = menu_model;
|
||||
}
|
||||
|
@ -160,6 +202,13 @@ void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
|
|||
icon_data->cbSize = sizeof(NOTIFYICONDATA);
|
||||
icon_data->hWnd = window_;
|
||||
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
|
||||
|
|
|
@ -33,7 +33,10 @@ class NotifyIcon : public TrayIcon {
|
|||
// 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,
|
||||
// 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.
|
||||
void ResetIcon();
|
||||
|
@ -49,6 +52,7 @@ class NotifyIcon : public TrayIcon {
|
|||
void DisplayBalloon(const gfx::Image& icon,
|
||||
const base::string16& title,
|
||||
const base::string16& contents) override;
|
||||
void PopUpContextMenu(const gfx::Point& pos) override;
|
||||
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
|
||||
|
||||
private:
|
||||
|
@ -75,6 +79,10 @@ class NotifyIcon : public TrayIcon {
|
|||
// The context menu.
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,13 +5,16 @@
|
|||
#include "atom/browser/ui/win/notify_icon_host.h"
|
||||
|
||||
#include <commctrl.h>
|
||||
#include <winuser.h>
|
||||
|
||||
#include "atom/browser/ui/win/notify_icon.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/threading/non_thread_safe.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "base/win/wrapped_window_proc.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
#include "ui/gfx/win/hwnd_util.h"
|
||||
|
||||
|
@ -26,6 +29,24 @@ const UINT kBaseIconId = 2;
|
|||
|
||||
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
|
||||
|
||||
NotifyIconHost::NotifyIconHost()
|
||||
|
@ -146,12 +167,18 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
|
|||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_LBUTTONDBLCLK:
|
||||
case WM_RBUTTONDBLCLK:
|
||||
case WM_CONTEXTMENU:
|
||||
// Walk our icons, find which one was clicked on, and invoke its
|
||||
// HandleClickEvent() method.
|
||||
gfx::Point cursor_pos(
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
165
atom/browser/ui/win/taskbar_host.cc
Normal file
165
atom/browser/ui/win/taskbar_host.cc
Normal 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
|
64
atom/browser/ui/win/taskbar_host.h
Normal file
64
atom/browser/ui/win/taskbar_host.h
Normal 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_
|
|
@ -7,6 +7,9 @@
|
|||
#include <X11/Xatom.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"
|
||||
|
||||
namespace atom {
|
||||
|
@ -46,4 +49,37 @@ void SetWindowType(::Window xwindow, const std::string& type) {
|
|||
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
|
||||
|
|
|
@ -22,6 +22,9 @@ void SetWMSpecState(::Window xwindow, bool enabled, ::Atom state);
|
|||
// Sets the _NET_WM_WINDOW_TYPE of window.
|
||||
void SetWindowType(::Window xwindow, const std::string& type);
|
||||
|
||||
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
|
||||
bool ShouldUseGlobalMenuBar();
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_
|
||||
|
|
|
@ -4,17 +4,66 @@
|
|||
|
||||
#include "atom/browser/web_dialog_helper.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "base/bind.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 "chrome/common/pref_names.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/file_chooser_file_info.h"
|
||||
#include "net/base/mime_util.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 {
|
||||
|
||||
WebDialogHelper::WebDialogHelper(NativeWindow* window)
|
||||
|
@ -25,15 +74,18 @@ WebDialogHelper::WebDialogHelper(NativeWindow* window)
|
|||
WebDialogHelper::~WebDialogHelper() {
|
||||
}
|
||||
|
||||
|
||||
void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) {
|
||||
std::vector<content::FileChooserFileInfo> result;
|
||||
file_dialog::Filters filters = GetFileTypesFromAcceptType(
|
||||
params.accept_types);
|
||||
if (params.mode == content::FileChooserParams::Save) {
|
||||
base::FilePath path;
|
||||
if (file_dialog::ShowSaveDialog(window_,
|
||||
base::UTF16ToUTF8(params.title),
|
||||
params.default_file_name,
|
||||
file_dialog::Filters(),
|
||||
filters,
|
||||
&path)) {
|
||||
content::FileChooserFileInfo info;
|
||||
info.file_path = path;
|
||||
|
@ -56,10 +108,14 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
|
|||
}
|
||||
|
||||
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_,
|
||||
base::UTF16ToUTF8(params.title),
|
||||
params.default_file_name,
|
||||
file_dialog::Filters(),
|
||||
default_file_path,
|
||||
filters,
|
||||
flags,
|
||||
&paths)) {
|
||||
for (auto& path : paths) {
|
||||
|
@ -68,6 +124,10 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
|
|||
info.display_name = path.BaseName().value();
|
||||
result.push_back(info);
|
||||
}
|
||||
if (!paths.empty()) {
|
||||
browser_context->prefs()->SetFilePath(prefs::kSelectFileLastDirectory,
|
||||
paths[0].DirName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#include "atom/browser/web_view_guest_delegate.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/render_frame_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
|
||||
|
@ -128,6 +130,12 @@ void WebViewGuestDelegate::RenderViewReady() {
|
|||
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) {
|
||||
api_web_contents_->Emit("did-attach");
|
||||
}
|
||||
|
|
|
@ -59,6 +59,9 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate,
|
|||
protected:
|
||||
// content::WebContentsObserver:
|
||||
void RenderViewReady() override;
|
||||
void DidCommitProvisionalLoadForFrame(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const GURL& url, ui::PageTransition transition_type) override;
|
||||
|
||||
// content::BrowserPluginGuestDelegate:
|
||||
void DidAttach(int guest_proxy_routing_id) final;
|
||||
|
|
|
@ -34,6 +34,10 @@ IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
|
|||
base::string16 /* channel */,
|
||||
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.
|
||||
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions,
|
||||
std::vector<atom::DraggableRegion> /* regions */)
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
#include "atom_natives.h" // NOLINT: This file is generated with coffee2c.
|
||||
#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 "native_mate/arguments.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
|
|
@ -78,7 +78,7 @@ bool AddImageSkiaRep(gfx::ImageSkia* image,
|
|||
if (!decoded)
|
||||
return false;
|
||||
|
||||
image->AddRepresentation(gfx::ImageSkiaRep(*decoded.release(), scale_factor));
|
||||
image->AddRepresentation(gfx::ImageSkiaRep(*decoded, scale_factor));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
|
|||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
bool IsTemplateImage(const base::FilePath& path) {
|
||||
bool IsTemplateFilename(const base::FilePath& path) {
|
||||
return (MatchPattern(path.value(), "*Template.*") ||
|
||||
MatchPattern(path.value(), "*Template@*x.*"));
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ mate::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder(
|
|||
.SetMethod("isEmpty", &NativeImage::IsEmpty)
|
||||
.SetMethod("getSize", &NativeImage::GetSize)
|
||||
.SetMethod("setTemplateImage", &NativeImage::SetTemplateImage)
|
||||
.SetMethod("isTemplateImage", &NativeImage::IsTemplateImage)
|
||||
.Build());
|
||||
|
||||
return mate::ObjectTemplateBuilder(
|
||||
|
@ -180,6 +181,10 @@ gfx::Size NativeImage::GetSize() {
|
|||
#if !defined(OS_MACOSX)
|
||||
void NativeImage::SetTemplateImage(bool setAsTemplate) {
|
||||
}
|
||||
|
||||
bool NativeImage::IsTemplateImage() {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
|
@ -217,7 +222,7 @@ mate::Handle<NativeImage> NativeImage::CreateFromPath(
|
|||
gfx::Image image(image_skia);
|
||||
mate::Handle<NativeImage> handle = Create(isolate, image);
|
||||
#if defined(OS_MACOSX)
|
||||
if (IsTemplateImage(path))
|
||||
if (IsTemplateFilename(path))
|
||||
handle->SetTemplateImage(true);
|
||||
#endif
|
||||
return handle;
|
||||
|
|
|
@ -67,6 +67,8 @@ class NativeImage : public mate::Wrappable {
|
|||
|
||||
// Mark the image as template image.
|
||||
void SetTemplateImage(bool setAsTemplate);
|
||||
// Determine if the image is a template image.
|
||||
bool IsTemplateImage();
|
||||
|
||||
gfx::Image image_;
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@ void NativeImage::SetTemplateImage(bool setAsTemplate) {
|
|||
[image_.AsNSImage() setTemplate:setAsTemplate];
|
||||
}
|
||||
|
||||
bool NativeImage::IsTemplateImage() {
|
||||
return [image_.AsNSImage() isTemplate];
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -98,6 +98,10 @@ void AtomBindings::OnCallNextTick(uv_async_t* handle) {
|
|||
if (tick_info->in_tick())
|
||||
continue;
|
||||
|
||||
if (tick_info->length() == 0) {
|
||||
env->isolate()->RunMicrotasks();
|
||||
}
|
||||
|
||||
if (tick_info->length() == 0) {
|
||||
tick_info->set_index(0);
|
||||
continue;
|
||||
|
|
32
atom/common/api/event_emitter_caller.cc
Normal file
32
atom/common/api/event_emitter_caller.cc
Normal 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
|
|
@ -2,8 +2,8 @@
|
|||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_EVENT_EMITTER_CALLER_H_
|
||||
#define ATOM_COMMON_EVENT_EMITTER_CALLER_H_
|
||||
#ifndef ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_
|
||||
#define ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -50,4 +50,4 @@ v8::Local<v8::Value> EmitEvent(v8::Isolate* isolate,
|
|||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_EVENT_EMITTER_CALLER_H_
|
||||
#endif // ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_
|
|
@ -1,3 +1,5 @@
|
|||
savedGlobal = global # the "global.global" might be deleted later
|
||||
|
||||
module.exports =
|
||||
class CallbacksRegistry
|
||||
constructor: ->
|
||||
|
@ -16,10 +18,10 @@ class CallbacksRegistry
|
|||
@callbacks[id] ? ->
|
||||
|
||||
call: (id, args...) ->
|
||||
@get(id).call global, args...
|
||||
@get(id).call savedGlobal, args...
|
||||
|
||||
apply: (id, args...) ->
|
||||
@get(id).apply global, args...
|
||||
@get(id).apply savedGlobal, args...
|
||||
|
||||
remove: (id) ->
|
||||
delete @callbacks[id]
|
||||
|
|
17
atom/common/api/locker.cc
Normal file
17
atom/common/api/locker.cc
Normal 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
34
atom/common/api/locker.h
Normal 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_
|
|
@ -54,6 +54,11 @@ bool GetChildNode(const base::DictionaryValue* root,
|
|||
const std::string& name,
|
||||
const base::DictionaryValue* dir,
|
||||
const base::DictionaryValue** out) {
|
||||
if (name == "") {
|
||||
*out = root;
|
||||
return true;
|
||||
}
|
||||
|
||||
const base::DictionaryValue* files = NULL;
|
||||
return GetFilesNode(root, dir, &files) &&
|
||||
files->GetDictionaryWithoutPathExpansion(name, out);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#define ATOM_VERSION_H
|
||||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 29
|
||||
#define ATOM_PATCH_VERSION 2
|
||||
#define ATOM_MINOR_VERSION 30
|
||||
#define ATOM_PATCH_VERSION 4
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
|
|||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
||||
|
||||
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
|
||||
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
|
||||
|
||||
} // namespace
|
||||
|
@ -47,12 +48,15 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
|
|||
|
||||
base::string16 pipe_name = ReplaceStringPlaceholders(
|
||||
kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL);
|
||||
base::string16 wait_name = ReplaceStringPlaceholders(
|
||||
kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL);
|
||||
|
||||
// Wait until the crash service is started.
|
||||
HANDLE waiting_event =
|
||||
::CreateEventW(NULL, TRUE, FALSE, L"g_atom_shell_crash_service");
|
||||
if (waiting_event != INVALID_HANDLE_VALUE)
|
||||
WaitForSingleObject(waiting_event, 1000);
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
|
||||
if (wait_event != NULL) {
|
||||
WaitForSingleObject(wait_event, 1000);
|
||||
CloseHandle(wait_event);
|
||||
}
|
||||
|
||||
// ExceptionHandler() attaches our handler and ~ExceptionHandler() detaches
|
||||
// it, so we must explicitly reset *before* we instantiate our new handler
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "vendor/breakpad/src/client/windows/crash_generation/client_info.h"
|
||||
|
@ -24,6 +25,9 @@ namespace breakpad {
|
|||
|
||||
namespace {
|
||||
|
||||
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
|
||||
const wchar_t kClassNameFormat[] = L"$1CrashServiceWindow";
|
||||
|
||||
const wchar_t kTestPipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
|
||||
|
||||
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.
|
||||
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};
|
||||
wcx.cbSize = sizeof(wcx);
|
||||
wcx.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcx.lpfnWndProc = CrashSvcWndProc;
|
||||
wcx.hInstance = instance;
|
||||
wcx.lpszClassName = L"crash_svc_class";
|
||||
wcx.lpszClassName = class_name.c_str();
|
||||
ATOM atom = ::RegisterClassExW(&wcx);
|
||||
DWORD style = visible ? WS_POPUPWINDOW | WS_VISIBLE : WS_OVERLAPPED;
|
||||
|
||||
|
@ -193,7 +202,8 @@ CrashService::~CrashService() {
|
|||
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) {
|
||||
using google_breakpad::CrashReportSender;
|
||||
using google_breakpad::CrashGenerationServer;
|
||||
|
@ -260,6 +270,7 @@ bool CrashService::Initialize(const base::FilePath& operating_dir,
|
|||
}
|
||||
|
||||
if (!CreateTopWindow(::GetModuleHandleW(NULL),
|
||||
application_name,
|
||||
!cmd_line.HasSwitch(kNoWindow))) {
|
||||
LOG(ERROR) << "could not create window";
|
||||
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
|
||||
// service is initialized.
|
||||
HANDLE running_event =
|
||||
::CreateEventW(NULL, TRUE, TRUE, L"g_atom_shell_crash_service");
|
||||
// If the browser already had the event open, the CreateEvent call did not
|
||||
// signal it. We need to do it manually.
|
||||
::SetEvent(running_event);
|
||||
base::string16 wait_name = ReplaceStringPlaceholders(
|
||||
kWaitEventFormat, application_name, NULL);
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
|
||||
::SetEvent(wait_event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@ class CrashService {
|
|||
// other members in that case. |operating_dir| is where the CrashService
|
||||
// should store breakpad's checkpoint file. |dumps_path| is the directory
|
||||
// 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);
|
||||
|
||||
// Command line switches:
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue