Merge remote-tracking branch 'atom/master'

This commit is contained in:
joshaber 2015-10-06 14:24:05 -04:00
commit 4cb3e2ecb5
170 changed files with 2471 additions and 892 deletions

View file

@ -8,7 +8,7 @@
:zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap: :zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap:
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와 Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [Node.js](https://nodejs.org) 와
[Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다. [Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다.
Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요. Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
@ -41,7 +41,7 @@ Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문
## 참조 문서 (번역) ## 참조 문서 (번역)
- [브라질 포르투칼어](https://github.com/atom/electron/tree/master/docs-translations/pt-BR) - [브라질 포르투칼어](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
- [한국어](https://github.com/atom/electron/tree/master/docs-translations/ko) - [한국어](https://github.com/atom/electron/tree/master/docs-translations/ko-KR)
- [일본어](https://github.com/atom/electron/tree/master/docs-translations/jp) - [일본어](https://github.com/atom/electron/tree/master/docs-translations/jp)
- [스페인어](https://github.com/atom/electron/tree/master/docs-translations/es) - [스페인어](https://github.com/atom/electron/tree/master/docs-translations/es)
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) - [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)

View file

@ -7,7 +7,7 @@
:zap: *Formerly known as Atom Shell* :zap: :zap: *Formerly known as Atom Shell* :zap:
The Electron framework lets you write cross-platform desktop applications The Electron framework lets you write cross-platform desktop applications
using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org) and
[Chromium](http://www.chromium.org) and is used in the [Atom [Chromium](http://www.chromium.org) and is used in the [Atom
editor](https://github.com/atom/atom). editor](https://github.com/atom/atom).
@ -15,7 +15,7 @@ Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements. announcements.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). 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 By participating, you are expected to uphold this code. Please report
unacceptable behavior to atom@github.com. unacceptable behavior to atom@github.com.
## Downloads ## Downloads
@ -47,7 +47,7 @@ contains documents describing how to build and contribute to Electron.
## Documentation Translations ## Documentation Translations
- [Brazilian Portuguese](https://github.com/atom/electron/tree/master/docs-translations/pt-BR) - [Brazilian Portuguese](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
- [Korean](https://github.com/atom/electron/tree/master/docs-translations/ko) - [Korean](https://github.com/atom/electron/tree/master/docs-translations/ko-KR)
- [Japanese](https://github.com/atom/electron/tree/master/docs-translations/jp) - [Japanese](https://github.com/atom/electron/tree/master/docs-translations/jp)
- [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es) - [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es)
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) - [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
@ -55,12 +55,12 @@ contains documents describing how to build and contribute to Electron.
## Community ## Community
You can ask questions and interact with the community in the following You can ask questions and interact with the community in the following
locations: locations:
- [`electron`](http://discuss.atom.io/category/electron) category on the Atom - [`electron`](http://discuss.atom.io/category/electron) category on the Atom
forums forums
- `#atom-shell` channel on Freenode - `#atom-shell` channel on Freenode
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack - [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron) Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
for a community maintained list of useful example apps, tools and resources. for a community maintained list of useful example apps, tools and resources.

View file

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

View file

@ -27,10 +27,10 @@ AtomMainDelegate::~AtomMainDelegate() {
} }
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) { bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Disable logging out to debug.log on Windows
logging::LoggingSettings settings; logging::LoggingSettings settings;
#if defined(OS_WIN) #if defined(OS_WIN)
#if defined(DEBUG) #if defined(DEBUG)
// Print logging to debug.log on Windows
settings.logging_dest = logging::LOG_TO_ALL; settings.logging_dest = logging::LOG_TO_ALL;
settings.log_file = L"debug.log"; settings.log_file = L"debug.log";
settings.lock_log = logging::LOCK_LOG_FILE; settings.lock_log = logging::LOCK_LOG_FILE;
@ -41,6 +41,12 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
#else // defined(OS_WIN) #else // defined(OS_WIN)
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif // !defined(OS_WIN) #endif // !defined(OS_WIN)
// Only enable logging when --enable-logging is specified.
auto command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kEnableLogging))
settings.logging_dest = logging::LOG_NONE;
logging::InitLogging(settings); logging::InitLogging(settings);
// Logging with pid and timestamp. // Logging with pid and timestamp.

View file

@ -0,0 +1,201 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_download_item.h"
#include <map>
#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 "atom/common/node_includes.h"
#include "base/memory/linked_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "native_mate/dictionary.h"
#include "net/base/filename_util.h"
namespace mate {
template<>
struct Converter<content::DownloadItem::DownloadState> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::DownloadItem::DownloadState state) {
std::string download_state;
switch (state) {
case content::DownloadItem::COMPLETE:
download_state = "completed";
break;
case content::DownloadItem::CANCELLED:
download_state = "cancelled";
break;
case content::DownloadItem::INTERRUPTED:
download_state = "interrupted";
break;
default:
break;
}
return ConvertToV8(isolate, download_state);
}
};
} // namespace mate
namespace atom {
namespace api {
namespace {
// The wrapDownloadItem funtion which is implemented in JavaScript
using WrapDownloadItemCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapDownloadItemCallback g_wrap_download_item;
char kDownloadItemSavePathKey[] = "DownloadItemSavePathKey";
std::map<uint32, linked_ptr<v8::Global<v8::Value>>> g_download_item_objects;
} // namespace
DownloadItem::SavePathData::SavePathData(const base::FilePath& path) :
path_(path) {
}
const base::FilePath& DownloadItem::SavePathData::path() {
return path_;
}
DownloadItem::DownloadItem(content::DownloadItem* download_item) :
download_item_(download_item) {
download_item_->AddObserver(this);
}
DownloadItem::~DownloadItem() {
Destroy();
}
void DownloadItem::Destroy() {
if (download_item_) {
download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
}
}
bool DownloadItem::IsDestroyed() const {
return download_item_ == nullptr;
}
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
}
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) {
Destroy();
}
int64 DownloadItem::GetReceivedBytes() {
return download_item_->GetReceivedBytes();
}
int64 DownloadItem::GetTotalBytes() {
return download_item_->GetTotalBytes();
}
const GURL& DownloadItem::GetUrl() {
return download_item_->GetURL();
}
std::string DownloadItem::GetMimeType() {
return download_item_->GetMimeType();
}
bool DownloadItem::HasUserGesture() {
return download_item_->HasUserGesture();
}
std::string DownloadItem::GetFilename() {
return base::UTF16ToUTF8(net::GenerateFileName(GetUrl(),
GetContentDisposition(),
std::string(),
download_item_->GetSuggestedFilename(),
GetMimeType(),
std::string()).LossyDisplayName());
}
std::string DownloadItem::GetContentDisposition() {
return download_item_->GetContentDisposition();
}
void DownloadItem::SetSavePath(const base::FilePath& path) {
download_item_->SetUserData(UserDataKey(), new SavePathData(path));
}
void DownloadItem::Pause() {
download_item_->Pause();
}
void DownloadItem::Resume() {
download_item_->Resume();
}
void DownloadItem::Cancel() {
download_item_->Cancel(true);
}
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("pause", &DownloadItem::Pause)
.SetMethod("resume", &DownloadItem::Resume)
.SetMethod("cancel", &DownloadItem::Cancel)
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
.SetMethod("getUrl", &DownloadItem::GetUrl)
.SetMethod("getMimeType", &DownloadItem::GetMimeType)
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
.SetMethod("getFilename", &DownloadItem::GetFilename)
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
.SetMethod("setSavePath", &DownloadItem::SetSavePath);
}
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
// static
mate::Handle<DownloadItem> DownloadItem::Create(
v8::Isolate* isolate, content::DownloadItem* item) {
auto handle = mate::CreateHandle(isolate, new DownloadItem(item));
g_wrap_download_item.Run(handle.ToV8());
g_download_item_objects[item->GetId()] = make_linked_ptr(
new v8::Global<v8::Value>(isolate, handle.ToV8()));
return handle;
}
// static
void* DownloadItem::UserDataKey() {
return &kDownloadItemSavePathKey;
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
dict.SetMethod("_clearWrapDownloadItem", &atom::api::ClearWrapDownloadItem);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_download_item, Initialize);

View file

@ -0,0 +1,72 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/files/file_path.h"
#include "content/public/browser/download_item.h"
#include "native_mate/handle.h"
#include "url/gurl.h"
namespace atom {
namespace api {
class DownloadItem : public mate::EventEmitter,
public content::DownloadItem::Observer {
public:
class SavePathData : public base::SupportsUserData::Data {
public:
explicit SavePathData(const base::FilePath& path);
const base::FilePath& path();
private:
base::FilePath path_;
};
static mate::Handle<DownloadItem> Create(v8::Isolate* isolate,
content::DownloadItem* item);
static void* UserDataKey();
protected:
explicit DownloadItem(content::DownloadItem* download_item);
~DownloadItem();
// Override content::DownloadItem::Observer methods
void OnDownloadUpdated(content::DownloadItem* download) override;
void OnDownloadDestroyed(content::DownloadItem* download) override;
void Pause();
void Resume();
void Cancel();
int64 GetReceivedBytes();
int64 GetTotalBytes();
std::string GetMimeType();
bool HasUserGesture();
std::string GetFilename();
std::string GetContentDisposition();
const GURL& GetUrl();
void SetSavePath(const base::FilePath& path);
private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
void Destroy();
content::DownloadItem* download_item_;
DISALLOW_COPY_AND_ASSIGN(DownloadItem);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_

View file

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include "atom/browser/api/atom_api_cookies.h" #include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/api/atom_api_download_item.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
@ -18,6 +19,8 @@
#include "base/prefs/pref_service.h" #include "base/prefs/pref_service.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h" #include "base/thread_task_runner_handle.h"
#include "brightray/browser/net/devtools_network_conditions.h"
#include "brightray/browser/net/devtools_network_controller.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
@ -101,19 +104,6 @@ struct Converter<ClearStorageDataOptions> {
} }
}; };
template<>
struct Converter<content::DownloadItem*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::DownloadItem* val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("url", val->GetURL());
dict.Set("filename", val->GetSuggestedFilename());
dict.Set("mimeType", val->GetMimeType());
dict.Set("hasUserGesture", val->HasUserGesture());
return dict.GetHandle();
}
};
} // namespace mate } // namespace mate
namespace atom { namespace atom {
@ -245,11 +235,12 @@ Session::~Session() {
} }
void Session::OnDownloadCreated(content::DownloadManager* manager, void Session::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) { content::DownloadItem* item) {
auto web_contents = item->GetWebContents(); auto web_contents = item->GetWebContents();
bool prevent_default = Emit("will-download", item, bool prevent_default = Emit(
api::WebContents::CreateFrom(isolate(), "will-download",
web_contents)); DownloadItem::Create(isolate(), item),
api::WebContents::CreateFrom(isolate(), web_contents));
if (prevent_default) { if (prevent_default) {
item->Cancel(true); item->Cancel(true);
item->Remove(); item->Remove();
@ -305,6 +296,43 @@ void Session::SetDownloadPath(const base::FilePath& path) {
prefs::kDownloadDefaultDirectory, path); prefs::kDownloadDefaultDirectory, path);
} }
void Session::EnableNetworkEmulation(const mate::Dictionary& options) {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions;
bool offline = false;
double latency, download_throughput, upload_throughput;
if (options.Get("offline", &offline) && offline) {
conditions.reset(new brightray::DevToolsNetworkConditions(offline));
} else {
options.Get("latency", &latency);
options.Get("downloadThroughput", &download_throughput);
options.Get("uploadThroughput", &upload_throughput);
conditions.reset(
new brightray::DevToolsNetworkConditions(false,
latency,
download_throughput,
upload_throughput));
}
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
void Session::DisableNetworkEmulation() {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions(
new brightray::DevToolsNetworkConditions(false));
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) { v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) { if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context()); auto handle = atom::api::Cookies::Create(isolate, browser_context());
@ -321,6 +349,8 @@ mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
.SetMethod("clearStorageData", &Session::ClearStorageData) .SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy) .SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath) .SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetProperty("cookies", &Session::Cookies); .SetProperty("cookies", &Session::Cookies);
} }

View file

@ -20,6 +20,7 @@ class FilePath;
namespace mate { namespace mate {
class Arguments; class Arguments;
class Dictionary;
} }
namespace atom { namespace atom {
@ -65,6 +66,8 @@ class Session: public mate::TrackableObject<Session>,
void ClearStorageData(mate::Arguments* args); void ClearStorageData(mate::Arguments* args);
void SetProxy(const std::string& proxy, const base::Closure& callback); void SetProxy(const std::string& proxy, const base::Closure& callback);
void SetDownloadPath(const base::FilePath& path); void SetDownloadPath(const base::FilePath& path);
void EnableNetworkEmulation(const mate::Dictionary& options);
void DisableNetworkEmulation();
v8::Local<v8::Value> Cookies(v8::Isolate* isolate); v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
// Cached object for cookies API. // Cached object for cookies API.

View file

@ -7,6 +7,7 @@
#include <set> #include <set>
#include "atom/browser/api/atom_api_session.h" #include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
@ -26,6 +27,7 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/printing/print_preview_message_handler.h" #include "chrome/browser/printing/print_preview_message_handler.h"
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
@ -120,6 +122,33 @@ struct Converter<WindowOpenDisposition> {
} }
}; };
template<>
struct Converter<net::HttpResponseHeaders*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
net::HttpResponseHeaders* headers) {
base::DictionaryValue response_headers;
if (headers) {
void* iter = nullptr;
std::string key;
std::string value;
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
key = base::StringToLowerASCII(key);
value = base::StringToLowerASCII(value);
if (response_headers.HasKey(key)) {
base::ListValue* values = nullptr;
if (response_headers.GetList(key, &values))
values->AppendString(value);
} else {
scoped_ptr<base::ListValue> values(new base::ListValue());
values->AppendString(value);
response_headers.Set(key, values.Pass());
}
}
}
return ConvertToV8(isolate, response_headers);
}
};
} // namespace mate } // namespace mate
@ -131,7 +160,7 @@ namespace {
v8::Persistent<v8::ObjectTemplate> template_; v8::Persistent<v8::ObjectTemplate> template_;
// The wrapWebContents funtion which is implemented in JavaScript // The wrapWebContents function which is implemented in JavaScript
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>; using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapWebContentsCallback g_wrap_web_contents; WrapWebContentsCallback g_wrap_web_contents;
@ -201,7 +230,9 @@ WebContents::WebContents(v8::Isolate* isolate,
AttachAsUserData(web_contents); AttachAsUserData(web_contents);
InitWithWebContents(web_contents); InitWithWebContents(web_contents);
// Save the preferences. managed_web_contents()->GetView()->SetDelegate(this);
// Save the preferences in C++.
base::DictionaryValue web_preferences; base::DictionaryValue web_preferences;
mate::ConvertFromV8(isolate, options.GetHandle(), &web_preferences); mate::ConvertFromV8(isolate, options.GetHandle(), &web_preferences);
new WebContentsPreferences(web_contents, &web_preferences); new WebContentsPreferences(web_contents, &web_preferences);
@ -414,30 +445,6 @@ void WebContents::DidStopLoading() {
void WebContents::DidGetResourceResponseStart( void WebContents::DidGetResourceResponseStart(
const content::ResourceRequestDetails& details) { const content::ResourceRequestDetails& details) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
base::DictionaryValue response_headers;
net::HttpResponseHeaders* headers = details.headers.get();
if (!headers)
return;
void* iter = nullptr;
std::string key;
std::string value;
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
key = base::StringToLowerASCII(key);
value = base::StringToLowerASCII(value);
if (response_headers.HasKey(key)) {
base::ListValue* values = nullptr;
if (response_headers.GetList(key, &values))
values->AppendString(value);
} else {
scoped_ptr<base::ListValue> values(new base::ListValue());
values->AppendString(value);
response_headers.Set(key, values.Pass());
}
}
Emit("did-get-response-details", Emit("did-get-response-details",
details.socket_address.IsEmpty(), details.socket_address.IsEmpty(),
details.url, details.url,
@ -445,7 +452,7 @@ void WebContents::DidGetResourceResponseStart(
details.http_response_code, details.http_response_code,
details.method, details.method,
details.referrer, details.referrer,
response_headers); details.headers.get());
} }
void WebContents::DidGetRedirectForResourceRequest( void WebContents::DidGetRedirectForResourceRequest(
@ -454,7 +461,11 @@ void WebContents::DidGetRedirectForResourceRequest(
Emit("did-get-redirect-request", Emit("did-get-redirect-request",
details.url, details.url,
details.new_url, details.new_url,
(details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME)); (details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME),
details.http_response_code,
details.method,
details.referrer,
details.headers.get());
} }
void WebContents::DidNavigateMainFrame( void WebContents::DidNavigateMainFrame(
@ -484,6 +495,33 @@ void WebContents::DidUpdateFaviconURL(
Emit("page-favicon-updated", unique_urls); Emit("page-favicon-updated", unique_urls);
} }
void WebContents::DevToolsFocused() {
Emit("devtools-focused");
}
void WebContents::DevToolsOpened() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto handle = WebContents::CreateFrom(
isolate(), managed_web_contents()->GetDevToolsWebContents());
devtools_web_contents_.Reset(isolate(), handle.ToV8());
// Inherit owner window in devtools.
if (owner_window())
handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(),
owner_window());
Emit("devtools-opened");
}
void WebContents::DevToolsClosed() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
devtools_web_contents_.Reset();
Emit("devtools-closed");
}
bool WebContents::OnMessageReceived(const IPC::Message& message) { bool WebContents::OnMessageReceived(const IPC::Message& message) {
bool handled = true; bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebContents, message) IPC_BEGIN_MESSAGE_MAP(WebContents, message)
@ -691,10 +729,6 @@ void WebContents::InspectServiceWorker() {
} }
} }
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, session_);
}
void WebContents::HasServiceWorker( void WebContents::HasServiceWorker(
const base::Callback<void(bool)>& callback) { const base::Callback<void(bool)>& callback) {
auto context = GetServiceWorkerContext(web_contents()); auto context = GetServiceWorkerContext(web_contents());
@ -880,6 +914,30 @@ bool WebContents::IsGuest() const {
return type_ == WEB_VIEW; return type_ == WEB_VIEW;
} }
v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
WebContentsPreferences* web_preferences =
WebContentsPreferences::FromWebContents(web_contents());
return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
}
v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
if (owner_window())
return Window::From(isolate(), owner_window());
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, session_);
}
v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
if (devtools_web_contents_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
}
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
v8::Isolate* isolate) { v8::Isolate* isolate) {
if (template_.IsEmpty()) if (template_.IsEmpty())
@ -935,6 +993,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("setSize", &WebContents::SetSize) .SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency) .SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest) .SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker) .SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker", .SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker) &WebContents::UnregisterServiceWorker)
@ -943,7 +1003,9 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("_printToPDF", &WebContents::PrintToPDF) .SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace) .SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace) .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session) .SetProperty("session", &WebContents::Session, true)
.SetProperty("devToolsWebContents",
&WebContents::DevToolsWebContents, true)
.Build()); .Build());
return mate::ObjectTemplateBuilder( return mate::ObjectTemplateBuilder(
@ -988,7 +1050,7 @@ mate::Handle<WebContents> WebContents::CreateFrom(
// static // static
mate::Handle<WebContents> WebContents::Create( mate::Handle<WebContents> WebContents::Create(
v8::Isolate* isolate, const mate::Dictionary& options) { v8::Isolate* isolate, const mate::Dictionary& options) {
auto handle = mate::CreateHandle(isolate, new WebContents(isolate, options)); auto handle = mate::CreateHandle(isolate, new WebContents(isolate, options));
g_wrap_web_contents.Run(handle.ToV8()); g_wrap_web_contents.Run(handle.ToV8());
return handle; return handle;
} }

View file

@ -83,7 +83,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
void DisableDeviceEmulation(); void DisableDeviceEmulation();
void InspectElement(int x, int y); void InspectElement(int x, int y);
void InspectServiceWorker(); void InspectServiceWorker();
v8::Local<v8::Value> Session(v8::Isolate* isolate);
void HasServiceWorker(const base::Callback<void(bool)>&); void HasServiceWorker(const base::Callback<void(bool)>&);
void UnregisterServiceWorker(const base::Callback<void(bool)>&); void UnregisterServiceWorker(const base::Callback<void(bool)>&);
void SetAudioMuted(bool muted); void SetAudioMuted(bool muted);
@ -132,6 +131,16 @@ class WebContents : public mate::TrackableObject<WebContents>,
void SetAllowTransparency(bool allow); void SetAllowTransparency(bool allow);
bool IsGuest() const; bool IsGuest() const;
// Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
// Returns the owner window.
v8::Local<v8::Value> GetOwnerBrowserWindow();
// Properties.
v8::Local<v8::Value> Session(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
protected: protected:
explicit WebContents(content::WebContents* web_contents); explicit WebContents(content::WebContents* web_contents);
WebContents(v8::Isolate* isolate, const mate::Dictionary& options); WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
@ -215,6 +224,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
void PluginCrashed(const base::FilePath& plugin_path, void PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) override; base::ProcessId plugin_pid) override;
// brightray::InspectableWebContentsViewDelegate:
void DevToolsFocused() override;
void DevToolsOpened() override;
void DevToolsClosed() override;
private: private:
enum Type { enum Type {
BROWSER_WINDOW, // Used by BrowserWindow. BROWSER_WINDOW, // Used by BrowserWindow.
@ -234,6 +248,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
IPC::Message* message); IPC::Message* message);
v8::Global<v8::Value> session_; v8::Global<v8::Value> session_;
v8::Global<v8::Value> devtools_web_contents_;
scoped_ptr<WebViewGuestDelegate> guest_delegate_; scoped_ptr<WebViewGuestDelegate> guest_delegate_;

View file

@ -82,12 +82,17 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
web_contents_.Reset(isolate, web_contents.ToV8()); web_contents_.Reset(isolate, web_contents.ToV8());
api_web_contents_ = web_contents.get(); api_web_contents_ = web_contents.get();
// Keep a copy of the options for later use.
mate::Dictionary(isolate, web_contents->GetWrapper(isolate)).Set(
"browserWindowOptions", options);
// Creates BrowserWindow. // Creates BrowserWindow.
window_.reset(NativeWindow::Create(web_contents->managed_web_contents(), window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
options)); options));
web_contents->SetOwnerWindow(window_.get()); web_contents->SetOwnerWindow(window_.get());
window_->InitFromOptions(options); window_->InitFromOptions(options);
window_->AddObserver(this); window_->AddObserver(this);
AttachAsUserData(window_.get());
} }
Window::~Window() { Window::~Window() {
@ -180,28 +185,6 @@ void Window::OnRendererResponsive() {
Emit("responsive"); Emit("responsive");
} }
void Window::OnDevToolsFocus() {
Emit("devtools-focused");
}
void Window::OnDevToolsOpened() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto handle = WebContents::CreateFrom(
isolate(), api_web_contents_->GetDevToolsWebContents());
devtools_web_contents_.Reset(isolate(), handle.ToV8());
Emit("devtools-opened");
}
void Window::OnDevToolsClosed() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
devtools_web_contents_.Reset();
Emit("devtools-closed");
}
void Window::OnExecuteWindowsCommand(const std::string& command_name) { void Window::OnExecuteWindowsCommand(const std::string& command_name) {
Emit("app-command", command_name); Emit("app-command", command_name);
} }
@ -536,13 +519,6 @@ v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, web_contents_); return v8::Local<v8::Value>::New(isolate, web_contents_);
} }
v8::Local<v8::Value> Window::DevToolsWebContents(v8::Isolate* isolate) {
if (devtools_web_contents_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
}
// static // static
void Window::BuildPrototype(v8::Isolate* isolate, void Window::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
@ -614,8 +590,17 @@ void Window::BuildPrototype(v8::Isolate* isolate,
&Window::ShowDefinitionForSelection) &Window::ShowDefinitionForSelection)
#endif #endif
.SetProperty("id", &Window::ID, true) .SetProperty("id", &Window::ID, true)
.SetProperty("webContents", &Window::WebContents, true) .SetProperty("webContents", &Window::WebContents, true);
.SetProperty("devToolsWebContents", &Window::DevToolsWebContents, true); }
// static
v8::Local<v8::Value> Window::From(v8::Isolate* isolate,
NativeWindow* native_window) {
auto existing = TrackableObject::FromWrappedClass(isolate, native_window);
if (existing)
return existing->GetWrapper(isolate);
else
return v8::Null(isolate);
} }
} // namespace api } // namespace api

View file

@ -43,6 +43,10 @@ class Window : public mate::TrackableObject<Window>,
static void BuildPrototype(v8::Isolate* isolate, static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype); v8::Local<v8::ObjectTemplate> prototype);
// Returns the BrowserWindow object from |native_window|.
static v8::Local<v8::Value> From(v8::Isolate* isolate,
NativeWindow* native_window);
NativeWindow* window() const { return window_.get(); } NativeWindow* window() const { return window_.get(); }
protected: protected:
@ -69,9 +73,6 @@ class Window : public mate::TrackableObject<Window>,
void OnWindowLeaveHtmlFullScreen() override; void OnWindowLeaveHtmlFullScreen() override;
void OnRendererUnresponsive() override; void OnRendererUnresponsive() override;
void OnRendererResponsive() override; void OnRendererResponsive() override;
void OnDevToolsFocus() override;
void OnDevToolsOpened() override;
void OnDevToolsClosed() override;
void OnExecuteWindowsCommand(const std::string& command_name) override; void OnExecuteWindowsCommand(const std::string& command_name) override;
// mate::Wrappable: // mate::Wrappable:
@ -150,10 +151,8 @@ class Window : public mate::TrackableObject<Window>,
int32_t ID() const; int32_t ID() const;
v8::Local<v8::Value> WebContents(v8::Isolate* isolate); v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
v8::Global<v8::Value> web_contents_; v8::Global<v8::Value> web_contents_;
v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> menu_; v8::Global<v8::Value> menu_;
api::WebContents* api_web_contents_; api::WebContents* api_web_contents_;

View file

@ -2,6 +2,7 @@ EventEmitter = require('events').EventEmitter
bindings = process.atomBinding 'app' bindings = process.atomBinding 'app'
sessionBindings = process.atomBinding 'session' sessionBindings = process.atomBinding 'session'
downloadItemBindings = process.atomBinding 'download_item'
app = bindings.app app = bindings.app
app.__proto__ = EventEmitter.prototype app.__proto__ = EventEmitter.prototype
@ -10,6 +11,15 @@ wrapSession = (session) ->
# session is an Event Emitter. # session is an Event Emitter.
session.__proto__ = EventEmitter.prototype session.__proto__ = EventEmitter.prototype
wrapDownloadItem = (download_item) ->
# download_item is an Event Emitter.
download_item.__proto__ = EventEmitter.prototype
# Be compatible with old APIs.
download_item.url = download_item.getUrl()
download_item.filename = download_item.getFilename()
download_item.mimeType = download_item.getMimeType()
download_item.hasUserGesture = download_item.hasUserGesture()
app.setApplicationMenu = (menu) -> app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu require('menu').setApplicationMenu menu
@ -51,5 +61,8 @@ app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-wi
sessionBindings._setWrapSession wrapSession sessionBindings._setWrapSession wrapSession
process.once 'exit', sessionBindings._clearWrapSession process.once 'exit', sessionBindings._clearWrapSession
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
process.once 'exit', downloadItemBindings._clearWrapDownloadItem
# Only one App object pemitted. # Only one App object pemitted.
module.exports = app module.exports = app

View file

@ -48,6 +48,15 @@ BrowserWindow::_init = ->
# Notify the creation of the window. # Notify the creation of the window.
app.emit 'browser-window-created', {}, this app.emit 'browser-window-created', {}, this
# Be compatible with old APIs.
@webContents.on 'devtools-focused', => @emit 'devtools-focused'
@webContents.on 'devtools-opened', => @emit 'devtools-opened'
@webContents.on 'devtools-closed', => @emit 'devtools-closed'
Object.defineProperty this, 'devToolsWebContents',
enumerable: true,
configurable: false,
get: -> @webContents.devToolsWebContents
BrowserWindow.getFocusedWindow = -> BrowserWindow.getFocusedWindow = ->
windows = BrowserWindow.getAllWindows() windows = BrowserWindow.getAllWindows()
return window for window in windows when window.isFocused() return window for window in windows when window.isFocused()

View file

@ -79,7 +79,11 @@ Menu::_init = ->
v8Util.setHiddenValue group[0], 'checked', true unless checked v8Util.setHiddenValue group[0], 'checked', true unless checked
Menu::popup = (window, x, y) -> Menu::popup = (window, x, y) ->
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow unless window?.constructor is BrowserWindow
# Shift.
y = x
x = window
window = BrowserWindow.getFocusedWindow()
if x? and y? if x? and y?
@_popupAt(window, x, y) @_popupAt(window, x, y)
else else

View file

@ -12,6 +12,7 @@
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_quota_permission_context.h" #include "atom/browser/atom_quota_permission_context.h"
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "atom/browser/atom_speech_recognition_manager_delegate.h" #include "atom/browser/atom_speech_recognition_manager_delegate.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
@ -30,6 +31,7 @@
#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/site_instance.h" #include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h" #include "content/public/common/web_preferences.h"
@ -226,6 +228,13 @@ void AtomBrowserClient::SelectClientCertificate(
delegate.Pass()); delegate.Pass());
} }
void AtomBrowserClient::ResourceDispatcherHostCreated() {
resource_dispatcher_host_delegate_.reset(
new AtomResourceDispatcherHostDelegate);
content::ResourceDispatcherHost::Get()->SetDelegate(
resource_dispatcher_host_delegate_.get());
}
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts( brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) { const content::MainFunctionParams&) {
v8::V8::Initialize(); // Init V8 before creating main parts. v8::V8::Initialize(); // Init V8 before creating main parts.

View file

@ -23,6 +23,8 @@ class SSLCertRequestInfo;
namespace atom { namespace atom {
class AtomResourceDispatcherHostDelegate;
class AtomBrowserClient : public brightray::BrowserClient, class AtomBrowserClient : public brightray::BrowserClient,
public content::RenderProcessHostObserver { public content::RenderProcessHostObserver {
public: public:
@ -56,6 +58,7 @@ class AtomBrowserClient : public brightray::BrowserClient,
content::WebContents* web_contents, content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override; scoped_ptr<content::ClientCertificateDelegate> delegate) override;
void ResourceDispatcherHostCreated() override;
// brightray::BrowserClient: // brightray::BrowserClient:
brightray::BrowserMainParts* OverrideCreateBrowserMainParts( brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
@ -68,6 +71,9 @@ class AtomBrowserClient : public brightray::BrowserClient,
// pending_render_process => current_render_process. // pending_render_process => current_render_process.
std::map<int, int> pending_processes_; std::map<int, int> pending_processes_;
scoped_ptr<AtomResourceDispatcherHostDelegate>
resource_dispatcher_host_delegate_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient); DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
}; };

View file

@ -6,6 +6,7 @@
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_download_manager_delegate.h" #include "atom/browser/atom_download_manager_delegate.h"
#include "atom/browser/atom_ssl_config_service.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/net/atom_url_request_job_factory.h" #include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/browser/net/asar/asar_protocol_handler.h" #include "atom/browser/net/asar/asar_protocol_handler.h"
@ -156,6 +157,10 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
return guest_manager_.get(); return guest_manager_.get();
} }
net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() {
return new AtomSSLConfigService;
}
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) { void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory, pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
base::FilePath()); base::FilePath());

View file

@ -27,6 +27,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
content::URLRequestInterceptorScopedVector* interceptors) override; content::URLRequestInterceptorScopedVector* interceptors) override;
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory( net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
const base::FilePath& base_path) override; const base::FilePath& base_path) override;
net::SSLConfigService* CreateSSLConfigService() override;
// content::BrowserContext: // content::BrowserContext:
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override; content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;

View file

@ -52,13 +52,16 @@ void AtomBrowserMainParts::RegisterDestructionCallback(
destruction_callbacks_.push_back(callback); destruction_callbacks_.push_back(callback);
} }
void AtomBrowserMainParts::PreEarlyInitialization() {
brightray::BrowserMainParts::PreEarlyInitialization();
#if defined(OS_POSIX)
HandleSIGCHLD();
#endif
}
void AtomBrowserMainParts::PostEarlyInitialization() { void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization(); brightray::BrowserMainParts::PostEarlyInitialization();
#if defined(USE_X11)
SetDPIFromGSettings();
#endif
{ {
// Temporary set the bridge_task_runner_ as current thread's task runner, // Temporary set the bridge_task_runner_ as current thread's task runner,
// so we can fool gin::PerIsolateData to use it as its task runner, instead // so we can fool gin::PerIsolateData to use it as its task runner, instead
@ -116,6 +119,13 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
#endif #endif
} }
void AtomBrowserMainParts::PostMainMessageLoopStart() {
brightray::BrowserMainParts::PostMainMessageLoopStart();
#if defined(OS_POSIX)
HandleShutdownSignals();
#endif
}
void AtomBrowserMainParts::PostMainMessageLoopRun() { void AtomBrowserMainParts::PostMainMessageLoopRun() {
brightray::BrowserMainParts::PostMainMessageLoopRun(); brightray::BrowserMainParts::PostMainMessageLoopRun();

View file

@ -39,8 +39,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
protected: protected:
// content::BrowserMainParts: // content::BrowserMainParts:
void PreEarlyInitialization() override;
void PostEarlyInitialization() override; void PostEarlyInitialization() override;
void PreMainMessageLoopRun() override; void PreMainMessageLoopRun() override;
void PostMainMessageLoopStart() override;
void PostMainMessageLoopRun() override; void PostMainMessageLoopRun() override;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void PreMainMessageLoopStart() override; void PreMainMessageLoopStart() override;
@ -48,8 +50,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
#endif #endif
private: private:
#if defined(USE_X11) #if defined(OS_POSIX)
void SetDPIFromGSettings(); // Set signal handlers.
void HandleSIGCHLD();
void HandleShutdownSignals();
#endif #endif
// A fake BrowserProcess object that used to feed the source code from chrome. // A fake BrowserProcess object that used to feed the source code from chrome.

View file

@ -1,73 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_browser_main_parts.h"
#include <gio/gio.h>
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "ui/gfx/switches.h"
namespace atom {
namespace {
const char* kInterfaceSchema = "org.gnome.desktop.interface";
const char* kScaleFactor = "scaling-factor";
bool SchemaExists(const char* schema_name) {
const gchar* const* schemas = g_settings_list_schemas();
while (*schemas) {
if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0)
return true;
schemas++;
}
return false;
}
bool KeyExists(GSettings* client, const char* key) {
gchar** keys = g_settings_list_keys(client);
if (!keys)
return false;
gchar** iter = keys;
while (*iter) {
if (strcmp(*iter, key) == 0)
break;
iter++;
}
bool exists = *iter != NULL;
g_strfreev(keys);
return exists;
}
void GetDPIFromGSettings(guint* scale_factor) {
GSettings* client = nullptr;
if (!SchemaExists(kInterfaceSchema) ||
!(client = g_settings_new(kInterfaceSchema))) {
VLOG(1) << "Cannot create gsettings client.";
return;
}
if (KeyExists(client, kScaleFactor))
*scale_factor = g_settings_get_uint(client, kScaleFactor);
g_object_unref(client);
}
} // namespace
void AtomBrowserMainParts::SetDPIFromGSettings() {
guint scale_factor = 1;
GetDPIFromGSettings(&scale_factor);
if (scale_factor == 0)
scale_factor = 1;
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kForceDeviceScaleFactor, base::UintToString(scale_factor));
}
} // namespace atom

View file

@ -0,0 +1,225 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
// Most code came from: chrome/browser/chrome_browser_main_posix.cc.
#include "atom/browser/atom_browser_main_parts.h"
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>
#include "atom/browser/browser.h"
#include "base/posix/eintr_wrapper.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace atom {
namespace {
// See comment in |PreEarlyInitialization()|, where sigaction is called.
void SIGCHLDHandler(int signal) {
}
// The OSX fork() implementation can crash in the child process before
// fork() returns. In that case, the shutdown pipe will still be
// shared with the parent process. To prevent child crashes from
// causing parent shutdowns, |g_pipe_pid| is the pid for the process
// which registered |g_shutdown_pipe_write_fd|.
// See <http://crbug.com/175341>.
pid_t g_pipe_pid = -1;
int g_shutdown_pipe_write_fd = -1;
int g_shutdown_pipe_read_fd = -1;
// Common code between SIG{HUP, INT, TERM}Handler.
void GracefulShutdownHandler(int signal) {
// Reinstall the default handler. We had one shot at graceful shutdown.
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = SIG_DFL;
RAW_CHECK(sigaction(signal, &action, NULL) == 0);
RAW_CHECK(g_pipe_pid == getpid());
RAW_CHECK(g_shutdown_pipe_write_fd != -1);
RAW_CHECK(g_shutdown_pipe_read_fd != -1);
size_t bytes_written = 0;
do {
int rv = HANDLE_EINTR(
write(g_shutdown_pipe_write_fd,
reinterpret_cast<const char*>(&signal) + bytes_written,
sizeof(signal) - bytes_written));
RAW_CHECK(rv >= 0);
bytes_written += rv;
} while (bytes_written < sizeof(signal));
}
// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGHUPHandler(int signal) {
RAW_CHECK(signal == SIGHUP);
GracefulShutdownHandler(signal);
}
// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGINTHandler(int signal) {
RAW_CHECK(signal == SIGINT);
GracefulShutdownHandler(signal);
}
// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGTERMHandler(int signal) {
RAW_CHECK(signal == SIGTERM);
GracefulShutdownHandler(signal);
}
class ShutdownDetector : public base::PlatformThread::Delegate {
public:
explicit ShutdownDetector(int shutdown_fd);
void ThreadMain() override;
private:
const int shutdown_fd_;
DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
};
ShutdownDetector::ShutdownDetector(int shutdown_fd)
: shutdown_fd_(shutdown_fd) {
CHECK_NE(shutdown_fd_, -1);
}
// These functions are used to help us diagnose crash dumps that happen
// during the shutdown process.
NOINLINE void ShutdownFDReadError() {
// Ensure function isn't optimized away.
asm("");
sleep(UINT_MAX);
}
NOINLINE void ShutdownFDClosedError() {
// Ensure function isn't optimized away.
asm("");
sleep(UINT_MAX);
}
NOINLINE void ExitPosted() {
// Ensure function isn't optimized away.
asm("");
sleep(UINT_MAX);
}
void ShutdownDetector::ThreadMain() {
base::PlatformThread::SetName("CrShutdownDetector");
int signal;
size_t bytes_read = 0;
ssize_t ret;
do {
ret = HANDLE_EINTR(
read(shutdown_fd_,
reinterpret_cast<char*>(&signal) + bytes_read,
sizeof(signal) - bytes_read));
if (ret < 0) {
NOTREACHED() << "Unexpected error: " << strerror(errno);
ShutdownFDReadError();
break;
} else if (ret == 0) {
NOTREACHED() << "Unexpected closure of shutdown pipe.";
ShutdownFDClosedError();
break;
}
bytes_read += ret;
} while (bytes_read < sizeof(signal));
VLOG(1) << "Handling shutdown for signal " << signal << ".";
base::Closure task =
base::Bind(&Browser::Quit, base::Unretained(Browser::Get()));
if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
// Without a UI thread to post the exit task to, there aren't many
// options. Raise the signal again. The default handler will pick it up
// and cause an ungraceful exit.
RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
kill(getpid(), signal);
// The signal may be handled on another thread. Give that a chance to
// happen.
sleep(3);
// We really should be dead by now. For whatever reason, we're not. Exit
// immediately, with the exit status set to the signal number with bit 8
// set. On the systems that we care about, this exit status is what is
// normally used to indicate an exit by this signal's default handler.
// This mechanism isn't a de jure standard, but even in the worst case, it
// should at least result in an immediate exit.
RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
_exit(signal | (1 << 7));
}
ExitPosted();
}
} // namespace
void AtomBrowserMainParts::HandleSIGCHLD() {
// We need to accept SIGCHLD, even though our handler is a no-op because
// otherwise we cannot wait on children. (According to POSIX 2001.)
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = SIGCHLDHandler;
CHECK_EQ(sigaction(SIGCHLD, &action, NULL), 0);
}
void AtomBrowserMainParts::HandleShutdownSignals() {
int pipefd[2];
int ret = pipe(pipefd);
if (ret < 0) {
PLOG(DFATAL) << "Failed to create pipe";
} else {
g_pipe_pid = getpid();
g_shutdown_pipe_read_fd = pipefd[0];
g_shutdown_pipe_write_fd = pipefd[1];
#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
#else
// ASan instrumentation and -finstrument-functions (used for keeping the
// shadow stacks) bloat the stack frames, so we need to increase the stack
// size to avoid hitting the guard page.
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
#endif
// TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
// if you change this, you'll probably need to change the suppression.
if (!base::PlatformThread::CreateNonJoinable(
kShutdownDetectorThreadStackSize,
new ShutdownDetector(g_shutdown_pipe_read_fd))) {
LOG(DFATAL) << "Failed to create shutdown detector task.";
}
}
// Setup signal handlers for shutdown AFTER shutdown pipe is setup because
// it may be called right away after handler is set.
// If adding to this list of signal handlers, note the new signal probably
// needs to be reset in child processes. See
// base/process_util_posix.cc:LaunchProcess.
// We need to handle SIGTERM, because that is how many POSIX-based distros ask
// processes to quit gracefully at shutdown time.
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = SIGTERMHandler;
CHECK_EQ(sigaction(SIGTERM, &action, NULL), 0);
// Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
// the browser process is being debugged, GDB will catch the SIGINT first.
action.sa_handler = SIGINTHandler;
CHECK_EQ(sigaction(SIGINT, &action, NULL), 0);
// And SIGHUP, for when the terminal disappears. On shutdown, many Linux
// distros send SIGHUP, SIGTERM, and then SIGKILL.
action.sa_handler = SIGHUPHandler;
CHECK_EQ(sigaction(SIGHUP, &action, NULL), 0);
}
} // namespace atom

View file

@ -6,6 +6,7 @@
#include <string> #include <string>
#include "atom/browser/api/atom_api_download_item.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/file_dialog.h"
@ -73,18 +74,19 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
if (relay) if (relay)
window = relay->window.get(); window = relay->window.get();
file_dialog::Filters filters;
base::FilePath path; base::FilePath path;
if (!file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path, if (file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path,
filters, &path)) { file_dialog::Filters(), &path)) {
return; // Remember the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
path.DirName());
} }
// Remeber the last selected download directory. // Running the DownloadTargetCallback with an empty FilePath signals that the
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>( // download should be cancelled.
download_manager_->GetBrowserContext()); // If user cancels the file save dialog, run the callback with empty FilePath.
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
path.DirName());
callback.Run(path, callback.Run(path,
content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DownloadItem::TARGET_DISPOSITION_PROMPT,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path); content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
@ -100,6 +102,25 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
const content::DownloadTargetCallback& callback) { const content::DownloadTargetCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!download->GetForcedFilePath().empty()) {
callback.Run(download->GetForcedFilePath(),
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download->GetForcedFilePath());
return true;
}
base::SupportsUserData::Data* save_path = download->GetUserData(
atom::api::DownloadItem::UserDataKey());
if (save_path) {
const base::FilePath& default_download_path =
static_cast<api::DownloadItem::SavePathData*>(save_path)->path();
callback.Run(default_download_path,
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
default_download_path);
return true;
}
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>( AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext()); download_manager_->GetBrowserContext());
base::FilePath default_download_path = browser_context->prefs()->GetFilePath( base::FilePath default_download_path = browser_context->prefs()->GetFilePath(
@ -110,14 +131,6 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
default_download_path = path.Append(FILE_PATH_LITERAL("Downloads")); default_download_path = path.Append(FILE_PATH_LITERAL("Downloads"));
} }
if (!download->GetForcedFilePath().empty()) {
callback.Run(download->GetForcedFilePath(),
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download->GetForcedFilePath());
return true;
}
CreateDownloadPathCallback download_path_callback = CreateDownloadPathCallback download_path_callback =
base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated, base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),

View file

@ -0,0 +1,32 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "atom/common/platform_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/escape.h"
#include "url/gurl.h"
using content::BrowserThread;
namespace atom {
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
}
bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol(
const GURL& url,
int render_process_id,
int render_view_id,
bool is_main_frame,
ui::PageTransition transition,
bool has_user_gesture) {
GURL escaped_url(net::EscapeExternalHandlerValue(url.spec()));
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(base::IgnoreResult(platform_util::OpenExternal), escaped_url));
return true;
}
} // namespace atom

View file

@ -0,0 +1,28 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#include "content/public/browser/resource_dispatcher_host_delegate.h"
namespace atom {
class AtomResourceDispatcherHostDelegate
: public content::ResourceDispatcherHostDelegate {
public:
AtomResourceDispatcherHostDelegate();
// content::ResourceDispatcherHostDelegate:
bool HandleExternalProtocol(const GURL& url,
int render_process_id,
int render_view_id,
bool is_main_frame,
ui::PageTransition transition,
bool has_user_gesture) override;
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_

View file

@ -0,0 +1,47 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_ssl_config_service.h"
#include <string>
#include "base/command_line.h"
#include "atom/common/options_switches.h"
#include "content/public/browser/browser_thread.h"
#include "net/socket/ssl_client_socket.h"
namespace atom {
namespace {
uint16 GetSSLProtocolVersion(const std::string& version_string) {
uint16 version = 0; // Invalid
if (version_string == "tls1")
version = net::SSL_PROTOCOL_VERSION_TLS1;
else if (version_string == "tls1.1")
version = net::SSL_PROTOCOL_VERSION_TLS1_1;
else if (version_string == "tls1.2")
version = net::SSL_PROTOCOL_VERSION_TLS1_2;
return version;
}
} // namespace
AtomSSLConfigService::AtomSSLConfigService() {
auto cmd_line = base::CommandLine::ForCurrentProcess();
if (cmd_line->HasSwitch(switches::kSSLVersionFallbackMin)) {
auto version_string =
cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin);
config_.version_fallback_min = GetSSLProtocolVersion(version_string);
}
}
AtomSSLConfigService::~AtomSSLConfigService() {
}
void AtomSSLConfigService::GetSSLConfig(net::SSLConfig* config) {
*config = config_;
}
} // namespace atom

View file

@ -0,0 +1,28 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_
#define ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_
#include "net/ssl/ssl_config_service.h"
namespace atom {
class AtomSSLConfigService : public net::SSLConfigService {
public:
AtomSSLConfigService();
~AtomSSLConfigService() override;
// net::SSLConfigService:
void GetSSLConfig(net::SSLConfig* config) override;
private:
net::SSLConfig config_;
DISALLOW_COPY_AND_ASSIGN(AtomSSLConfigService);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_

View file

@ -16,7 +16,8 @@ namespace atom {
Browser::Browser() Browser::Browser()
: is_quiting_(false), : is_quiting_(false),
is_ready_(false) { is_ready_(false),
is_shutdown_(false) {
WindowList::AddObserver(this); WindowList::AddObserver(this);
} }
@ -30,6 +31,9 @@ Browser* Browser::Get() {
} }
void Browser::Quit() { void Browser::Quit() {
if (is_quiting_)
return;
is_quiting_ = HandleBeforeQuit(); is_quiting_ = HandleBeforeQuit();
if (!is_quiting_) if (!is_quiting_)
return; return;
@ -42,9 +46,13 @@ void Browser::Quit() {
} }
void Browser::Shutdown() { void Browser::Shutdown() {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit()); if (is_shutdown_)
return;
is_shutdown_ = true;
is_quiting_ = true; is_quiting_ = true;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
base::MessageLoop::current()->PostTask( base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
} }
@ -121,6 +129,9 @@ void Browser::ClientCertificateSelector(
} }
void Browser::NotifyAndShutdown() { void Browser::NotifyAndShutdown() {
if (is_shutdown_)
return;
bool prevent_default = false; bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default)); FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));

View file

@ -159,6 +159,9 @@ class Browser : public WindowListObserver {
// Whether "ready" event has been emitted. // Whether "ready" event has been emitted.
bool is_ready_; bool is_ready_;
// The browse is being shutdown.
bool is_shutdown_;
std::string version_override_; std::string version_override_;
std::string name_override_; std::string name_override_;

View file

@ -21,6 +21,14 @@
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "storage/browser/fileapi/isolated_context.h" #include "storage/browser/fileapi/isolated_context.h"
#if defined(TOOLKIT_VIEWS)
#include "atom/browser/native_window_views.h"
#endif
#if defined(USE_X11)
#include "atom/browser/browser.h"
#endif
using content::BrowserThread; using content::BrowserThread;
namespace atom { namespace atom {
@ -128,7 +136,11 @@ void CommonWebContentsDelegate::InitWithWebContents(
} }
void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) { void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) {
content::WebContents* web_contents = GetWebContents(); SetOwnerWindow(GetWebContents(), owner_window);
}
void CommonWebContentsDelegate::SetOwnerWindow(
content::WebContents* web_contents, NativeWindow* owner_window) {
owner_window_ = owner_window->GetWeakPtr(); owner_window_ = owner_window->GetWeakPtr();
NativeWindowRelay* relay = new NativeWindowRelay(owner_window_); NativeWindowRelay* relay = new NativeWindowRelay(owner_window_);
web_contents->SetUserData(relay->key, relay); web_contents->SetUserData(relay->key, relay);
@ -355,6 +367,23 @@ void CommonWebContentsDelegate::OnDevToolsAppendToFile(
"DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr); "DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr);
} }
#if defined(TOOLKIT_VIEWS)
gfx::ImageSkia CommonWebContentsDelegate::GetDevToolsWindowIcon() {
if (!owner_window())
return gfx::ImageSkia();
return static_cast<views::WidgetDelegate*>(static_cast<NativeWindowViews*>(
owner_window()))->GetWindowAppIcon();
}
#endif
#if defined(USE_X11)
void CommonWebContentsDelegate::GetDevToolsWindowWMClass(
std::string* name, std::string* class_name) {
*class_name = Browser::Get()->GetName();
*name = base::StringToLowerASCII(*class_name);
}
#endif
void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) { void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) {
// Window is already in fullscreen mode, save the state. // Window is already in fullscreen mode, save the state.
if (enter_fullscreen && owner_window_->IsFullscreen()) { if (enter_fullscreen && owner_window_->IsFullscreen()) {

View file

@ -12,6 +12,7 @@
#include "brightray/browser/default_web_contents_delegate.h" #include "brightray/browser/default_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents_impl.h" #include "brightray/browser/inspectable_web_contents_impl.h"
#include "brightray/browser/inspectable_web_contents_delegate.h" #include "brightray/browser/inspectable_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents_view_delegate.h"
namespace atom { namespace atom {
@ -21,7 +22,8 @@ class WebDialogHelper;
class CommonWebContentsDelegate class CommonWebContentsDelegate
: public brightray::DefaultWebContentsDelegate, : public brightray::DefaultWebContentsDelegate,
public brightray::InspectableWebContentsDelegate { public brightray::InspectableWebContentsDelegate,
public brightray::InspectableWebContentsViewDelegate {
public: public:
CommonWebContentsDelegate(); CommonWebContentsDelegate();
virtual ~CommonWebContentsDelegate(); virtual ~CommonWebContentsDelegate();
@ -32,6 +34,8 @@ class CommonWebContentsDelegate
// Set the window as owner window. // Set the window as owner window.
void SetOwnerWindow(NativeWindow* owner_window); void SetOwnerWindow(NativeWindow* owner_window);
void SetOwnerWindow(content::WebContents* web_contents,
NativeWindow* owner_window);
// Destroy the managed InspectableWebContents object. // Destroy the managed InspectableWebContents object.
void DestroyWebContents(); void DestroyWebContents();
@ -86,6 +90,15 @@ class CommonWebContentsDelegate
void DevToolsRemoveFileSystem( void DevToolsRemoveFileSystem(
const base::FilePath& file_system_path) override; const base::FilePath& file_system_path) override;
// brightray::InspectableWebContentsViewDelegate:
#if defined(TOOLKIT_VIEWS)
gfx::ImageSkia GetDevToolsWindowIcon() override;
#endif
#if defined(USE_X11)
void GetDevToolsWindowWMClass(
std::string* name, std::string* class_name) override;
#endif
private: private:
// Callback for when DevToolsSaveToFile has completed. // Callback for when DevToolsSaveToFile has completed.
void OnDevToolsSaveToFile(const std::string& url); void OnDevToolsSaveToFile(const std::string& url);

View file

@ -13,8 +13,8 @@ app.on('window-all-closed', function() {
// Parse command line options. // Parse command line options.
var argv = process.argv.slice(1); var argv = process.argv.slice(1);
var option = { file: null, help: null, version: null, webdriver: null }; var option = { file: null, help: null, version: null, webdriver: null, modules: [] };
for (var i in argv) { for (var i = 0; i < argv.length; i++) {
if (argv[i] == '--version' || argv[i] == '-v') { if (argv[i] == '--version' || argv[i] == '-v') {
option.version = true; option.version = true;
break; break;
@ -23,6 +23,9 @@ for (var i in argv) {
break; break;
} else if (argv[i] == '--test-type=webdriver') { } else if (argv[i] == '--test-type=webdriver') {
option.webdriver = true; option.webdriver = true;
} else if (argv[i] == '--require' || argv[i] == '-r') {
option.modules.push(argv[++i]);
continue;
} else if (argv[i][0] == '-') { } else if (argv[i][0] == '-') {
continue; continue;
} else { } else {
@ -212,6 +215,10 @@ app.once('ready', function() {
Menu.setApplicationMenu(menu); Menu.setApplicationMenu(menu);
}); });
if (option.modules.length > 0) {
require('module')._preloadModules(option.modules);
}
// Start the specified app if there is one specified in command line, otherwise // Start the specified app if there is one specified in command line, otherwise
// start the default app. // start the default app.
if (option.file && !option.webdriver) { if (option.file && !option.webdriver) {
@ -253,6 +260,7 @@ if (option.file && !option.webdriver) {
helpMessage += "A path to an Electron application may be specified. The path must be to \n"; helpMessage += "A path to an Electron application may be specified. The path must be to \n";
helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n"; helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
helpMessage += "Options:\n"; helpMessage += "Options:\n";
helpMessage += " -r, --require Module to preload (option can be repeated)";
helpMessage += " -h, --help Print this usage message.\n"; helpMessage += " -h, --help Print this usage message.\n";
helpMessage += " -v, --version Print the version."; helpMessage += " -v, --version Print the version.";
console.log(helpMessage); console.log(helpMessage);

View file

@ -84,6 +84,8 @@ createGuest = (embedder, params) ->
if params.allowtransparency? if params.allowtransparency?
@setAllowTransparency params.allowtransparency @setAllowTransparency params.allowtransparency
guest.allowPopups = params.allowpopups
# Dispatch events to embedder. # Dispatch events to embedder.
for event in supportedWebViewEvents for event in supportedWebViewEvents
do (event) -> do (event) ->

View file

@ -4,6 +4,17 @@ BrowserWindow = require 'browser-window'
frameToGuest = {} frameToGuest = {}
# Merge |options| with the |embedder|'s window's options.
mergeBrowserWindowOptions = (embedder, options) ->
if embedder.browserWindowOptions?
# Inherit the original options if it is a BrowserWindow.
options.__proto__ = embedder.browserWindowOptions
else
# Or only inherit web-preferences if it is a webview.
options['web-preferences'] ?= {}
options['web-preferences'].__proto__ = embedder.getWebPreferences()
options
# Create a new guest created by |embedder| with |options|. # Create a new guest created by |embedder| with |options|.
createGuest = (embedder, url, frameName, options) -> createGuest = (embedder, url, frameName, options) ->
guest = frameToGuest[frameName] guest = frameToGuest[frameName]
@ -40,11 +51,12 @@ createGuest = (embedder, url, frameName, options) ->
# Routed window.open messages. # Routed window.open messages.
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) -> ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) ->
[url, frameName, options] = args [url, frameName, options] = args
event.sender.emit 'new-window', event, url, frameName, 'new-window' options = mergeBrowserWindowOptions event.sender, options
if event.sender.isGuest() or event.defaultPrevented event.sender.emit 'new-window', event, url, frameName, 'new-window', options
if (event.sender.isGuest() and not event.sender.allowPopups) or event.defaultPrevented
event.returnValue = null event.returnValue = null
else else
event.returnValue = createGuest event.sender, args... event.returnValue = createGuest event.sender, url, frameName, options
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', (event, guestId) -> ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', (event, guestId) ->
BrowserWindow.fromId(guestId)?.destroy() BrowserWindow.fromId(guestId)?.destroy()

View file

@ -7,14 +7,17 @@ Module = require 'module'
# we need to restore it here. # we need to restore it here.
process.argv.splice 1, 1 process.argv.splice 1, 1
# Clear search paths.
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')
# Import common settings.
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
# Add browser/api/lib to module search paths, which contains javascript part of # Add browser/api/lib to module search paths, which contains javascript part of
# Electron's built-in libraries. # Electron's built-in libraries.
globalPaths = Module.globalPaths globalPaths = Module.globalPaths
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
# Import common settings.
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
if process.platform is 'win32' if process.platform is 'win32'
# Redirect node's console to use our own implementations, since node can not # Redirect node's console to use our own implementations, since node can not
# handle console output when running as GUI program. # handle console output when running as GUI program.
@ -64,7 +67,9 @@ for packagePath in searchPaths
catch e catch e
continue continue
throw new Error("Unable to find a valid app") unless packageJson? unless packageJson?
process.nextTick -> process.exit 1
throw new Error("Unable to find a valid app")
# Set application's version. # Set application's version.
app.setVersion packageJson.version if packageJson.version? app.setVersion packageJson.version if packageJson.version?

View file

@ -34,6 +34,7 @@ class ObjectsRegistry extends EventEmitter
@dereference id, 1 @dereference id, 1
# Also reduce the count in owner. # Also reduce the count in owner.
pointer = @owners[webContentsId] pointer = @owners[webContentsId]
return unless pointer?
--pointer[id] --pointer[id]
delete pointer[id] if pointer[id] is 0 delete pointer[id] if pointer[id] is 0
@ -57,6 +58,7 @@ class ObjectsRegistry extends EventEmitter
# Private: Dereference the object from store. # Private: Dereference the object from store.
dereference: (id, count) -> dereference: (id, count) ->
pointer = @storage[id] pointer = @storage[id]
return unless pointer?
pointer.count -= count pointer.count -= count
if pointer.count is 0 if pointer.count is 0
v8Util.deleteHiddenValue pointer.object, 'atomId' v8Util.deleteHiddenValue pointer.object, 'atomId'

View file

@ -106,16 +106,9 @@ ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, guestInstanceId) -> ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
try try
BrowserWindow = require 'browser-window' event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow()
if guestInstanceId?
guestViewManager = require './guest-view-manager'
window = BrowserWindow.fromWebContents guestViewManager.getEmbedder(guestInstanceId)
else
window = BrowserWindow.fromWebContents event.sender
window = BrowserWindow.fromDevToolsWebContents event.sender unless window?
event.returnValue = valueToMeta event.sender, window
catch e catch e
event.returnValue = errorToMeta e event.returnValue = errorToMeta e

View file

@ -68,6 +68,7 @@ NativeWindow::NativeWindow(
const mate::Dictionary& options) const mate::Dictionary& options)
: content::WebContentsObserver(inspectable_web_contents->GetWebContents()), : content::WebContentsObserver(inspectable_web_contents->GetWebContents()),
has_frame_(true), has_frame_(true),
force_using_draggable_region_(false),
transparent_(false), transparent_(false),
enable_larger_than_screen_(false), enable_larger_than_screen_(false),
is_closed_(false), is_closed_(false),
@ -75,8 +76,6 @@ NativeWindow::NativeWindow(
aspect_ratio_(0.0), aspect_ratio_(0.0),
inspectable_web_contents_(inspectable_web_contents), inspectable_web_contents_(inspectable_web_contents),
weak_factory_(this) { weak_factory_(this) {
inspectable_web_contents->GetView()->SetDelegate(this);
options.Get(switches::kFrame, &has_frame_); options.Get(switches::kFrame, &has_frame_);
options.Get(switches::kTransparent, &transparent_); options.Get(switches::kTransparent, &transparent_);
options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_); options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_);
@ -113,27 +112,34 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
int x = -1, y = -1; int x = -1, y = -1;
bool center; bool center;
if (options.Get(switches::kX, &x) && options.Get(switches::kY, &y)) { if (options.Get(switches::kX, &x) && options.Get(switches::kY, &y)) {
int width = -1, height = -1; SetPosition(gfx::Point(x, y));
options.Get(switches::kWidth, &width);
options.Get(switches::kHeight, &height);
SetBounds(gfx::Rect(x, y, width, height));
} else if (options.Get(switches::kCenter, &center) && center) { } else if (options.Get(switches::kCenter, &center) && center) {
Center(); Center();
} }
extensions::SizeConstraints size_constraints;
int min_height = 0, min_width = 0; int min_height = 0, min_width = 0;
if (options.Get(switches::kMinHeight, &min_height) | if (options.Get(switches::kMinHeight, &min_height) |
options.Get(switches::kMinWidth, &min_width)) { options.Get(switches::kMinWidth, &min_width)) {
SetMinimumSize(gfx::Size(min_width, min_height)); size_constraints.set_minimum_size(gfx::Size(min_width, min_height));
} }
int max_height = INT_MAX, max_width = INT_MAX; int max_height = INT_MAX, max_width = INT_MAX;
if (options.Get(switches::kMaxHeight, &max_height) | if (options.Get(switches::kMaxHeight, &max_height) |
options.Get(switches::kMaxWidth, &max_width)) { options.Get(switches::kMaxWidth, &max_width)) {
SetMaximumSize(gfx::Size(max_width, max_height)); size_constraints.set_maximum_size(gfx::Size(max_width, max_height));
} }
bool use_content_size = false;
options.Get(switches::kUseContentSize, &use_content_size);
if (use_content_size) {
SetContentSizeConstraints(size_constraints);
} else {
SetSizeConstraints(size_constraints);
}
#if defined(OS_WIN) || defined(USE_X11)
bool resizable; bool resizable;
if (options.Get(switches::kResizable, &resizable)) { if (options.Get(switches::kResizable, &resizable)) {
SetResizable(resizable); SetResizable(resizable);
} }
#endif
bool top; bool top;
if (options.Get(switches::kAlwaysOnTop, &top) && top) { if (options.Get(switches::kAlwaysOnTop, &top) && top) {
SetAlwaysOnTop(true); SetAlwaysOnTop(true);
@ -179,6 +185,67 @@ gfx::Point NativeWindow::GetPosition() {
return GetBounds().origin(); return GetBounds().origin();
} }
void NativeWindow::SetContentSize(const gfx::Size& size) {
SetSize(ContentSizeToWindowSize(size));
}
gfx::Size NativeWindow::GetContentSize() {
return WindowSizeToContentSize(GetSize());
}
void NativeWindow::SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) {
extensions::SizeConstraints content_constraints;
if (window_constraints.HasMaximumSize())
content_constraints.set_maximum_size(
WindowSizeToContentSize(window_constraints.GetMaximumSize()));
if (window_constraints.HasMinimumSize())
content_constraints.set_minimum_size(
WindowSizeToContentSize(window_constraints.GetMinimumSize()));
SetContentSizeConstraints(content_constraints);
}
extensions::SizeConstraints NativeWindow::GetSizeConstraints() {
extensions::SizeConstraints content_constraints = GetContentSizeConstraints();
extensions::SizeConstraints window_constraints;
if (content_constraints.HasMaximumSize())
window_constraints.set_maximum_size(
ContentSizeToWindowSize(content_constraints.GetMaximumSize()));
if (content_constraints.HasMinimumSize())
window_constraints.set_minimum_size(
ContentSizeToWindowSize(content_constraints.GetMinimumSize()));
return window_constraints;
}
void NativeWindow::SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) {
size_constraints_ = size_constraints;
}
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() {
return size_constraints_;
}
void NativeWindow::SetMinimumSize(const gfx::Size& size) {
extensions::SizeConstraints size_constraints;
size_constraints.set_minimum_size(size);
SetSizeConstraints(size_constraints);
}
gfx::Size NativeWindow::GetMinimumSize() {
return GetSizeConstraints().GetMinimumSize();
}
void NativeWindow::SetMaximumSize(const gfx::Size& size) {
extensions::SizeConstraints size_constraints;
size_constraints.set_maximum_size(size);
SetSizeConstraints(size_constraints);
}
gfx::Size NativeWindow::GetMaximumSize() {
return GetSizeConstraints().GetMaximumSize();
}
void NativeWindow::SetRepresentedFilename(const std::string& filename) { void NativeWindow::SetRepresentedFilename(const std::string& filename) {
} }
@ -412,18 +479,6 @@ void NativeWindow::NotifyWindowExecuteWindowsCommand(
OnExecuteWindowsCommand(command)); OnExecuteWindowsCommand(command));
} }
void NativeWindow::DevToolsFocused() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsFocus());
}
void NativeWindow::DevToolsOpened() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsOpened());
}
void NativeWindow::DevToolsClosed() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsClosed());
}
void NativeWindow::RenderViewCreated( void NativeWindow::RenderViewCreated(
content::RenderViewHost* render_view_host) { content::RenderViewHost* render_view_host) {
if (!transparent_) if (!transparent_)
@ -468,7 +523,7 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
void NativeWindow::UpdateDraggableRegions( void NativeWindow::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) { const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window. // Draggable region is not supported for non-frameless window.
if (has_frame_) if (has_frame_ && !force_using_draggable_region_)
return; return;
draggable_region_ = DraggableRegionsToSkRegion(regions); draggable_region_ = DraggableRegionsToSkRegion(regions);
} }

View file

@ -15,10 +15,11 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "brightray/browser/inspectable_web_contents_view_delegate.h" #include "base/supports_user_data.h"
#include "content/public/browser/readback_types.h" #include "content/public/browser/readback_types.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
#include "extensions/browser/app_window/size_constraints.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
@ -50,8 +51,8 @@ namespace atom {
struct DraggableRegion; struct DraggableRegion;
class NativeWindow : public content::WebContentsObserver, class NativeWindow : public base::SupportsUserData,
public brightray::InspectableWebContentsViewDelegate { public content::WebContentsObserver {
public: public:
using CapturePageCallback = base::Callback<void(const SkBitmap& bitmap)>; using CapturePageCallback = base::Callback<void(const SkBitmap& bitmap)>;
@ -110,12 +111,18 @@ class NativeWindow : public content::WebContentsObserver,
virtual gfx::Size GetSize(); virtual gfx::Size GetSize();
virtual void SetPosition(const gfx::Point& position); virtual void SetPosition(const gfx::Point& position);
virtual gfx::Point GetPosition(); virtual gfx::Point GetPosition();
virtual void SetContentSize(const gfx::Size& size) = 0; virtual void SetContentSize(const gfx::Size& size);
virtual gfx::Size GetContentSize() = 0; virtual gfx::Size GetContentSize();
virtual void SetMinimumSize(const gfx::Size& size) = 0; virtual void SetSizeConstraints(
virtual gfx::Size GetMinimumSize() = 0; const extensions::SizeConstraints& size_constraints);
virtual void SetMaximumSize(const gfx::Size& size) = 0; virtual extensions::SizeConstraints GetSizeConstraints();
virtual gfx::Size GetMaximumSize() = 0; virtual void SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints);
virtual extensions::SizeConstraints GetContentSizeConstraints();
virtual void SetMinimumSize(const gfx::Size& size);
virtual gfx::Size GetMinimumSize();
virtual void SetMaximumSize(const gfx::Size& size);
virtual gfx::Size GetMaximumSize();
virtual void SetResizable(bool resizable) = 0; virtual void SetResizable(bool resizable) = 0;
virtual bool IsResizable() = 0; virtual bool IsResizable() = 0;
virtual void SetAlwaysOnTop(bool top) = 0; virtual void SetAlwaysOnTop(bool top) = 0;
@ -219,6 +226,13 @@ class NativeWindow : public content::WebContentsObserver,
bool enable_larger_than_screen() const { return enable_larger_than_screen_; } bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
gfx::ImageSkia icon() const { return icon_; } gfx::ImageSkia icon() const { return icon_; }
bool force_using_draggable_region() const {
return force_using_draggable_region_;
}
void set_force_using_draggable_region(bool force) {
force_using_draggable_region_ = true;
}
void set_has_dialog_attached(bool has_dialog_attached) { void set_has_dialog_attached(bool has_dialog_attached) {
has_dialog_attached_ = has_dialog_attached; has_dialog_attached_ = has_dialog_attached;
} }
@ -227,10 +241,9 @@ class NativeWindow : public content::WebContentsObserver,
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents, NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
const mate::Dictionary& options); const mate::Dictionary& options);
// brightray::InspectableWebContentsViewDelegate: // Converts between content size to window size.
void DevToolsFocused() override; virtual gfx::Size ContentSizeToWindowSize(const gfx::Size& size) = 0;
void DevToolsOpened() override; virtual gfx::Size WindowSizeToContentSize(const gfx::Size& size) = 0;
void DevToolsClosed() override;
// content::WebContentsObserver: // content::WebContentsObserver:
void RenderViewCreated(content::RenderViewHost* render_view_host) override; void RenderViewCreated(content::RenderViewHost* render_view_host) override;
@ -257,6 +270,9 @@ class NativeWindow : public content::WebContentsObserver,
// Whether window has standard frame. // Whether window has standard frame.
bool has_frame_; bool has_frame_;
// Force the window to be aware of draggable regions.
bool force_using_draggable_region_;
// Whether window is transparent. // Whether window is transparent.
bool transparent_; bool transparent_;
@ -264,6 +280,9 @@ class NativeWindow : public content::WebContentsObserver,
// has to been explicitly provided. // has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag. scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Minimum and maximum size, stored as content size.
extensions::SizeConstraints size_constraints_;
// Whether window can be resized larger than screen. // Whether window can be resized larger than screen.
bool enable_larger_than_screen_; bool enable_larger_than_screen_;

View file

@ -44,12 +44,8 @@ class NativeWindowMac : public NativeWindow {
bool IsFullscreen() const override; bool IsFullscreen() const override;
void SetBounds(const gfx::Rect& bounds) override; void SetBounds(const gfx::Rect& bounds) override;
gfx::Rect GetBounds() override; gfx::Rect GetBounds() override;
void SetContentSize(const gfx::Size& size) override; void SetContentSizeConstraints(
gfx::Size GetContentSize() override; const extensions::SizeConstraints& size_constraints) override;
void SetMinimumSize(const gfx::Size& size) override;
gfx::Size GetMinimumSize() override;
void SetMaximumSize(const gfx::Size& size) override;
gfx::Size GetMaximumSize() override;
void SetResizable(bool resizable) override; void SetResizable(bool resizable) override;
bool IsResizable() override; bool IsResizable() override;
void SetAlwaysOnTop(bool top) override; void SetAlwaysOnTop(bool top) override;
@ -89,6 +85,10 @@ class NativeWindowMac : public NativeWindow {
const content::NativeWebKeyboardEvent&) override; const content::NativeWebKeyboardEvent&) override;
private: private:
// NativeWindow:
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
void InstallView(); void InstallView();
void UninstallView(); void UninstallView();

View file

@ -350,22 +350,25 @@ NativeWindowMac::NativeWindowMac(
bool useStandardWindow = true; bool useStandardWindow = true;
options.Get(switches::kStandardWindow, &useStandardWindow); options.Get(switches::kStandardWindow, &useStandardWindow);
bool resizable = true;
options.Get(switches::kResizable, &resizable);
// New title bar styles are available in Yosemite or newer
std::string titleBarStyle;
if (base::mac::IsOSYosemiteOrLater())
options.Get(switches::kTitleBarStyle, &titleBarStyle);
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask; NSMiniaturizableWindowMask;
if (!useStandardWindow || transparent() || !has_frame()) { if (!useStandardWindow || transparent() || !has_frame()) {
styleMask |= NSTexturedBackgroundWindowMask; styleMask |= NSTexturedBackgroundWindowMask;
} }
if (resizable) {
std::string titleBarStyle = "default"; styleMask |= NSResizableWindowMask;
options.Get(switches::kTitleBarStyle, &titleBarStyle); }
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
if (base::mac::IsOSYosemiteOrLater()) { styleMask |= NSFullSizeContentViewWindowMask;
// New title bar styles are available in Yosemite or newer styleMask |= NSUnifiedTitleAndToolbarWindowMask;
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
styleMask |= NSFullSizeContentViewWindowMask;
styleMask |= NSUnifiedTitleAndToolbarWindowMask;
}
} }
window_.reset([[AtomNSWindow alloc] window_.reset([[AtomNSWindow alloc]
@ -393,18 +396,18 @@ NativeWindowMac::NativeWindowMac(
// We will manage window's lifetime ourselves. // We will manage window's lifetime ourselves.
[window_ setReleasedWhenClosed:NO]; [window_ setReleasedWhenClosed:NO];
// Configure title bar look on Yosemite or newer // Hide the title bar.
if (base::mac::IsOSYosemiteOrLater()) { if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) { [window_ setTitlebarAppearsTransparent:YES];
[window_ setTitlebarAppearsTransparent:YES]; [window_ setTitleVisibility:NSWindowTitleHidden];
[window_ setTitleVisibility:NSWindowTitleHidden]; if (titleBarStyle == "hidden-inset") {
if (titleBarStyle == "hidden-inset") { base::scoped_nsobject<NSToolbar> toolbar(
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]; [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
toolbar.showsBaselineSeparator = NO; [toolbar setShowsBaselineSeparator:NO];
[window_ setToolbar:toolbar]; [window_ setToolbar:toolbar];
[toolbar release];
}
} }
// We should be aware of draggable regions when using hidden titlebar.
set_force_using_draggable_region(true);
} }
// On OS X the initial window size doesn't include window frame. // On OS X the initial window size doesn't include window frame.
@ -436,6 +439,11 @@ NativeWindowMac::NativeWindowMac(
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
InstallView(); InstallView();
// Install the DraggableRegionView if it is forced to use draggable regions
// for normal window.
if (has_frame() && force_using_draggable_region())
InstallDraggableRegionView();
} }
NativeWindowMac::~NativeWindowMac() { NativeWindowMac::~NativeWindowMac() {
@ -546,56 +554,30 @@ gfx::Rect NativeWindowMac::GetBounds() {
return bounds; return bounds;
} }
void NativeWindowMac::SetContentSize(const gfx::Size& size) { void NativeWindowMac::SetContentSizeConstraints(
if (!has_frame()) { const extensions::SizeConstraints& size_constraints) {
SetSize(size); auto convertSize = [this](const gfx::Size& size) {
return; // Our frameless window still has titlebar attached, so setting contentSize
// will result in actual content size being larger.
if (!has_frame()) {
NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
NSRect content = [window_ contentRectForFrameRect:frame];
return content.size;
} else {
return NSMakeSize(size.width(), size.height());
}
};
NSView* content = [window_ contentView];
if (size_constraints.HasMinimumSize()) {
NSSize min_size = convertSize(size_constraints.GetMinimumSize());
[window_ setContentMinSize:[content convertSize:min_size toView:nil]];
} }
if (size_constraints.HasMaximumSize()) {
NSRect frame_nsrect = [window_ frame]; NSSize max_size = convertSize(size_constraints.GetMaximumSize());
NSSize frame = frame_nsrect.size; [window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
NSSize content = [window_ contentRectForFrameRect:frame_nsrect].size; }
NativeWindow::SetContentSizeConstraints(size_constraints);
int width = size.width() + frame.width - content.width;
int height = size.height() + frame.height - content.height;
frame_nsrect.origin.y -= height - frame_nsrect.size.height;
frame_nsrect.size.width = width;
frame_nsrect.size.height = height;
[window_ setFrame:frame_nsrect display:YES];
}
gfx::Size NativeWindowMac::GetContentSize() {
if (!has_frame())
return GetSize();
NSRect bounds = [[window_ contentView] bounds];
return gfx::Size(bounds.size.width, bounds.size.height);
}
void NativeWindowMac::SetMinimumSize(const gfx::Size& size) {
NSSize min_size = NSMakeSize(size.width(), size.height());
NSView* content = [window_ contentView];
[window_ setContentMinSize:[content convertSize:min_size toView:nil]];
}
gfx::Size NativeWindowMac::GetMinimumSize() {
NSView* content = [window_ contentView];
NSSize min_size = [content convertSize:[window_ contentMinSize]
fromView:nil];
return gfx::Size(min_size.width, min_size.height);
}
void NativeWindowMac::SetMaximumSize(const gfx::Size& size) {
NSSize max_size = NSMakeSize(size.width(), size.height());
NSView* content = [window_ contentView];
[window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
}
gfx::Size NativeWindowMac::GetMaximumSize() {
NSView* content = [window_ contentView];
NSSize max_size = [content convertSize:[window_ contentMaxSize]
fromView:nil];
return gfx::Size(max_size.width, max_size.height);
} }
void NativeWindowMac::SetResizable(bool resizable) { void NativeWindowMac::SetResizable(bool resizable) {
@ -818,6 +800,24 @@ void NativeWindowMac::HandleKeyboardEvent(
} }
} }
gfx::Size NativeWindowMac::ContentSizeToWindowSize(const gfx::Size& size) {
if (!has_frame())
return size;
NSRect content = NSMakeRect(0, 0, size.width(), size.height());
NSRect frame = [window_ frameRectForContentRect:content];
return gfx::Size(frame.size);
}
gfx::Size NativeWindowMac::WindowSizeToContentSize(const gfx::Size& size) {
if (!has_frame())
return size;
NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
NSRect content = [window_ contentRectForFrameRect:frame];
return gfx::Size(content.size);
}
void NativeWindowMac::InstallView() { void NativeWindowMac::InstallView() {
// Make sure the bottom corner is rounded: http://crbug.com/396264. // Make sure the bottom corner is rounded: http://crbug.com/396264.
[[window_ contentView] setWantsLayer:YES]; [[window_ contentView] setWantsLayer:YES];

View file

@ -55,11 +55,6 @@ class NativeWindowObserver {
virtual void OnWindowEnterHtmlFullScreen() {} virtual void OnWindowEnterHtmlFullScreen() {}
virtual void OnWindowLeaveHtmlFullScreen() {} virtual void OnWindowLeaveHtmlFullScreen() {}
// Redirect devtools events.
virtual void OnDevToolsFocus() {}
virtual void OnDevToolsOpened() {}
virtual void OnDevToolsClosed() {}
// Called when renderer is hung. // Called when renderer is hung.
virtual void OnRendererUnresponsive() {} virtual void OnRendererUnresponsive() {}

View file

@ -77,70 +77,6 @@ bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
(modifiers == (Modifiers::AltKey | Modifiers::IsRight)); (modifiers == (Modifiers::AltKey | Modifiers::IsRight));
} }
#if defined(OS_WIN)
// Convert Win32 WM_APPCOMMANDS to strings.
const char* AppCommandToString(int command_id) {
switch (command_id) {
case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward";
case APPCOMMAND_BROWSER_FORWARD : return "browser-forward";
case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh";
case APPCOMMAND_BROWSER_STOP : return "browser-stop";
case APPCOMMAND_BROWSER_SEARCH : return "browser-search";
case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites";
case APPCOMMAND_BROWSER_HOME : return "browser-home";
case APPCOMMAND_VOLUME_MUTE : return "volume-mute";
case APPCOMMAND_VOLUME_DOWN : return "volume-down";
case APPCOMMAND_VOLUME_UP : return "volume-up";
case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack";
case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack";
case APPCOMMAND_MEDIA_STOP : return "media-stop";
case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause";
case APPCOMMAND_LAUNCH_MAIL : return "launch-mail";
case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select";
case APPCOMMAND_LAUNCH_APP1 : return "launch-app1";
case APPCOMMAND_LAUNCH_APP2 : return "launch-app2";
case APPCOMMAND_BASS_DOWN : return "bass-down";
case APPCOMMAND_BASS_BOOST : return "bass-boost";
case APPCOMMAND_BASS_UP : return "bass-up";
case APPCOMMAND_TREBLE_DOWN : return "treble-down";
case APPCOMMAND_TREBLE_UP : return "treble-up";
case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute";
case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down";
case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up";
case APPCOMMAND_HELP : return "help";
case APPCOMMAND_FIND : return "find";
case APPCOMMAND_NEW : return "new";
case APPCOMMAND_OPEN : return "open";
case APPCOMMAND_CLOSE : return "close";
case APPCOMMAND_SAVE : return "save";
case APPCOMMAND_PRINT : return "print";
case APPCOMMAND_UNDO : return "undo";
case APPCOMMAND_REDO : return "redo";
case APPCOMMAND_COPY : return "copy";
case APPCOMMAND_CUT : return "cut";
case APPCOMMAND_PASTE : return "paste";
case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail";
case APPCOMMAND_FORWARD_MAIL : return "forward-mail";
case APPCOMMAND_SEND_MAIL : return "send-mail";
case APPCOMMAND_SPELL_CHECK : return "spell-check";
case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle";
case APPCOMMAND_CORRECTION_LIST : return "correction-list";
case APPCOMMAND_MEDIA_PLAY : return "media-play";
case APPCOMMAND_MEDIA_PAUSE : return "media-pause";
case APPCOMMAND_MEDIA_RECORD : return "media-record";
case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward";
case APPCOMMAND_MEDIA_REWIND : return "media-rewind";
case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up";
case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down";
case APPCOMMAND_DELETE : return "delete";
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
return "dictate-or-command-control-toggle";
default:
return "unknown";
}
}
#endif
class NativeWindowClientView : public views::ClientView { class NativeWindowClientView : public views::ClientView {
public: public:
NativeWindowClientView(views::Widget* widget, NativeWindowClientView(views::Widget* widget,
@ -169,9 +105,6 @@ NativeWindowViews::NativeWindowViews(
menu_bar_autohide_(false), menu_bar_autohide_(false),
menu_bar_visible_(false), menu_bar_visible_(false),
menu_bar_alt_pressed_(false), menu_bar_alt_pressed_(false),
#if defined(OS_WIN)
is_minimized_(false),
#endif
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler), keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
use_content_size_(false), use_content_size_(false),
resizable_(true) { resizable_(true) {
@ -189,7 +122,8 @@ NativeWindowViews::NativeWindowViews(
// will not allow us to resize the window larger than scree. // will not allow us to resize the window larger than scree.
// Setting directly to INT_MAX somehow doesn't work, so we just devide // Setting directly to INT_MAX somehow doesn't work, so we just devide
// by 10, which should still be large enough. // by 10, which should still be large enough.
maximum_size_.SetSize(INT_MAX / 10, INT_MAX / 10); SetContentSizeConstraints(extensions::SizeConstraints(
gfx::Size(), gfx::Size(INT_MAX / 10, INT_MAX / 10)));
int width = 800, height = 600; int width = 800, height = 600;
options.Get(switches::kWidth, &width); options.Get(switches::kWidth, &width);
@ -228,6 +162,9 @@ NativeWindowViews::NativeWindowViews(
window_->Init(params); window_->Init(params);
bool fullscreen = false;
options.Get(switches::kFullscreen, &fullscreen);
#if defined(USE_X11) #if defined(USE_X11)
// Start monitoring window states. // Start monitoring window states.
window_state_watcher_.reset(new WindowStateWatcher(this)); window_state_watcher_.reset(new WindowStateWatcher(this));
@ -253,8 +190,7 @@ NativeWindowViews::NativeWindowViews(
} }
// Before the window is mapped, there is no SHOW_FULLSCREEN_STATE. // Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
bool fullscreen = false; if (fullscreen) {
if (options.Get(switches::kFullscreen, & fullscreen) && fullscreen) {
state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN")); state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
} }
@ -272,12 +208,15 @@ NativeWindowViews::NativeWindowViews(
set_background(views::Background::CreateStandardPanelBackground()); set_background(views::Background::CreateStandardPanelBackground());
AddChildView(web_view_); AddChildView(web_view_);
if (has_frame() &&
options.Get(switches::kUseContentSize, &use_content_size_) &&
use_content_size_)
bounds = ContentBoundsToWindowBounds(bounds);
#if defined(OS_WIN) #if defined(OS_WIN)
// Save initial window state.
if (fullscreen)
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
else
last_window_state_ = ui::SHOW_STATE_NORMAL;
last_normal_size_ = gfx::Size(widget_size_);
if (!has_frame()) { if (!has_frame()) {
// Set Window style so that we get a minimize and maximize animation when // Set Window style so that we get a minimize and maximize animation when
// frameless. // frameless.
@ -309,8 +248,14 @@ NativeWindowViews::NativeWindowViews(
if (transparent() && !has_frame()) if (transparent() && !has_frame())
wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE); wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE);
gfx::Size size = bounds.size();
if (has_frame() &&
options.Get(switches::kUseContentSize, &use_content_size_) &&
use_content_size_)
size = ContentSizeToWindowSize(size);
window_->UpdateWindowIcon(); window_->UpdateWindowIcon();
window_->CenterWindow(bounds.size()); window_->CenterWindow(size);
Layout(); Layout();
} }
@ -388,11 +333,16 @@ bool NativeWindowViews::IsMinimized() {
void NativeWindowViews::SetFullScreen(bool fullscreen) { void NativeWindowViews::SetFullScreen(bool fullscreen) {
#if defined(OS_WIN) #if defined(OS_WIN)
// There is no native fullscreen state on Windows. // There is no native fullscreen state on Windows.
window_->SetFullscreen(fullscreen); if (fullscreen) {
if (fullscreen) last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
NotifyWindowEnterFullScreen(); NotifyWindowEnterFullScreen();
else } else {
last_window_state_ = ui::SHOW_STATE_NORMAL;
NotifyWindowLeaveFullScreen(); NotifyWindowLeaveFullScreen();
}
// We set the new value after notifying, so we can handle the size event
// correctly.
window_->SetFullscreen(fullscreen);
#else #else
if (IsVisible()) if (IsVisible())
window_->SetFullscreen(fullscreen); window_->SetFullscreen(fullscreen);
@ -428,42 +378,23 @@ gfx::Rect NativeWindowViews::GetBounds() {
return window_->GetWindowBoundsInScreen(); return window_->GetWindowBoundsInScreen();
} }
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
if (!has_frame()) {
NativeWindow::SetSize(size);
return;
}
gfx::Rect bounds = window_->GetWindowBoundsInScreen();
bounds.set_size(size);
SetBounds(ContentBoundsToWindowBounds(bounds));
}
gfx::Size NativeWindowViews::GetContentSize() { gfx::Size NativeWindowViews::GetContentSize() {
if (!has_frame()) #if defined(OS_WIN)
return GetSize(); if (IsMinimized())
return NativeWindow::GetContentSize();
#endif
gfx::Size content_size = return web_view_->size();
window_->non_client_view()->frame_view()->GetBoundsForClientView().size();
if (menu_bar_ && menu_bar_visible_)
content_size.set_height(content_size.height() - kMenuBarHeight);
return content_size;
} }
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) { void NativeWindowViews::SetContentSizeConstraints(
minimum_size_ = size; const extensions::SizeConstraints& size_constraints) {
} NativeWindow::SetContentSizeConstraints(size_constraints);
window_->OnSizeConstraintsChanged();
gfx::Size NativeWindowViews::GetMinimumSize() { #if defined(USE_X11)
return minimum_size_; if (resizable_)
} old_size_constraints_ = size_constraints;
#endif
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size;
}
gfx::Size NativeWindowViews::GetMaximumSize() {
return maximum_size_;
} }
void NativeWindowViews::SetResizable(bool resizable) { void NativeWindowViews::SetResizable(bool resizable) {
@ -482,11 +413,13 @@ void NativeWindowViews::SetResizable(bool resizable) {
// On Linux there is no "resizable" property of a window, we have to set // On Linux there is no "resizable" property of a window, we have to set
// both the minimum and maximum size to the window size to achieve it. // both the minimum and maximum size to the window size to achieve it.
if (resizable) { if (resizable) {
SetMaximumSize(gfx::Size()); SetContentSizeConstraints(old_size_constraints_);
SetMinimumSize(gfx::Size());
} else { } else {
SetMaximumSize(GetSize()); old_size_constraints_ = GetContentSizeConstraints();
SetMinimumSize(GetSize()); resizable_ = false;
gfx::Size content_size = GetContentSize();
SetContentSizeConstraints(
extensions::SizeConstraints(content_size, content_size));
} }
} }
#endif #endif
@ -598,8 +531,24 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
if (!menu_bar_autohide_) { if (!menu_bar_autohide_) {
SetMenuBarVisibility(true); SetMenuBarVisibility(true);
if (use_content_size_) if (use_content_size_) {
// Enlarge the size constraints for the menu.
extensions::SizeConstraints constraints = GetContentSizeConstraints();
if (constraints.HasMinimumSize()) {
gfx::Size min_size = constraints.GetMinimumSize();
min_size.set_height(min_size.height() + kMenuBarHeight);
constraints.set_minimum_size(min_size);
}
if (constraints.HasMaximumSize()) {
gfx::Size max_size = constraints.GetMaximumSize();
max_size.set_height(max_size.height() + kMenuBarHeight);
constraints.set_maximum_size(max_size);
}
SetContentSizeConstraints(constraints);
// Resize the window to make sure content size is not changed.
SetContentSize(content_size); SetContentSize(content_size);
}
} }
} }
@ -802,53 +751,47 @@ void NativeWindowViews::OnWidgetMove() {
NotifyWindowMove(); NotifyWindowMove();
} }
gfx::Size NativeWindowViews::ContentSizeToWindowSize(const gfx::Size& size) {
if (!has_frame())
return size;
gfx::Size window_size(size);
#if defined(OS_WIN) #if defined(OS_WIN)
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) { gfx::Rect dpi_bounds =
// Windows uses the 4 lower order bits of |command_id| for type-specific gfx::Rect(gfx::Point(), gfx::win::DIPToScreenSize(size));
// information so we must exclude this when comparing. gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
static const int sc_mask = 0xFFF0; window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
if ((command_id & sc_mask) == SC_MINIMIZE) { window_size = window_bounds.size();
NotifyWindowMinimize();
is_minimized_ = true;
} else if ((command_id & sc_mask) == SC_RESTORE) {
if (is_minimized_)
NotifyWindowRestore();
else
NotifyWindowUnmaximize();
is_minimized_ = false;
} else if ((command_id & sc_mask) == SC_MAXIMIZE) {
NotifyWindowMaximize();
} else {
std::string command = AppCommandToString(command_id);
NotifyWindowExecuteWindowsCommand(command);
}
return false;
}
#endif #endif
gfx::ImageSkia NativeWindowViews::GetDevToolsWindowIcon() { if (menu_bar_ && menu_bar_visible_)
return GetWindowAppIcon(); window_size.set_height(window_size.height() + kMenuBarHeight);
return window_size;
} }
#if defined(USE_X11) gfx::Size NativeWindowViews::WindowSizeToContentSize(const gfx::Size& size) {
void NativeWindowViews::GetDevToolsWindowWMClass( if (!has_frame())
std::string* name, std::string* class_name) { return size;
*class_name = Browser::Get()->GetName();
*name = base::StringToLowerASCII(*class_name);
}
#endif
gfx::Size content_size(size);
#if defined(OS_WIN) #if defined(OS_WIN)
bool NativeWindowViews::PreHandleMSG( content_size = gfx::win::DIPToScreenSize(content_size);
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) { RECT rect;
// Handle thumbar button click message. SetRectEmpty(&rect);
if (message == WM_COMMAND && HIWORD(w_param) == THBN_CLICKED) HWND hwnd = GetAcceleratedWidget();
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param)); DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
else DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
return false; AdjustWindowRectEx(&rect, style, FALSE, ex_style);
} content_size.set_width(content_size.width() - (rect.right - rect.left));
content_size.set_height(content_size.height() - (rect.bottom - rect.top));
content_size = gfx::win::ScreenToDIPSize(content_size);
#endif #endif
if (menu_bar_ && menu_bar_visible_)
content_size.set_height(content_size.height() - kMenuBarHeight);
return content_size;
}
void NativeWindowViews::HandleKeyboardEvent( void NativeWindowViews::HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent& event) { const content::NativeWebKeyboardEvent& event) {
@ -880,9 +823,6 @@ void NativeWindowViews::HandleKeyboardEvent(
// When a single Alt is pressed: // When a single Alt is pressed:
menu_bar_alt_pressed_ = true; menu_bar_alt_pressed_ = true;
} else if (event.type == blink::WebInputEvent::KeyUp && IsAltKey(event) && } else if (event.type == blink::WebInputEvent::KeyUp && IsAltKey(event) &&
#if defined(USE_X11)
event.modifiers == 0 &&
#endif
menu_bar_alt_pressed_) { menu_bar_alt_pressed_) {
// When a single Alt is released right after a Alt is pressed: // When a single Alt is released right after a Alt is pressed:
menu_bar_alt_pressed_ = false; menu_bar_alt_pressed_ = false;
@ -893,6 +833,14 @@ void NativeWindowViews::HandleKeyboardEvent(
} }
} }
gfx::Size NativeWindowViews::GetMinimumSize() {
return NativeWindow::GetMinimumSize();
}
gfx::Size NativeWindowViews::GetMaximumSize() {
return NativeWindow::GetMaximumSize();
}
bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) { bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) {
return accelerator_util::TriggerAcceleratorTableCommand( return accelerator_util::TriggerAcceleratorTableCommand(
&accelerator_table_, accelerator); &accelerator_table_, accelerator);
@ -915,26 +863,6 @@ void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
} }
} }
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
const gfx::Rect& bounds) {
gfx::Point origin = bounds.origin();
#if defined(OS_WIN)
gfx::Rect dpi_bounds = gfx::win::DIPToScreenRect(bounds);
gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
#else
gfx::Rect window_bounds =
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
#endif
// The window's position would also be changed, but we only want to change
// the size.
window_bounds.set_origin(origin);
if (menu_bar_ && menu_bar_visible_)
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
return window_bounds;
}
ui::WindowShowState NativeWindowViews::GetRestoredState() { ui::WindowShowState NativeWindowViews::GetRestoredState() {
if (IsMaximized()) if (IsMaximized())
return ui::SHOW_STATE_MAXIMIZED; return ui::SHOW_STATE_MAXIMIZED;

View file

@ -63,12 +63,9 @@ class NativeWindowViews : public NativeWindow,
bool IsFullscreen() const override; bool IsFullscreen() const override;
void SetBounds(const gfx::Rect& bounds) override; void SetBounds(const gfx::Rect& bounds) override;
gfx::Rect GetBounds() override; gfx::Rect GetBounds() override;
void SetContentSize(const gfx::Size& size) override;
gfx::Size GetContentSize() override; gfx::Size GetContentSize() override;
void SetMinimumSize(const gfx::Size& size) override; void SetContentSizeConstraints(
gfx::Size GetMinimumSize() override; const extensions::SizeConstraints& size_constraints) override;
void SetMaximumSize(const gfx::Size& size) override;
gfx::Size GetMaximumSize() override;
void SetResizable(bool resizable) override; void SetResizable(bool resizable) override;
bool IsResizable() override; bool IsResizable() override;
void SetAlwaysOnTop(bool top) override; void SetAlwaysOnTop(bool top) override;
@ -131,34 +128,29 @@ class NativeWindowViews : public NativeWindow,
bool ExecuteWindowsCommand(int command_id) override; bool ExecuteWindowsCommand(int command_id) override;
#endif #endif
// brightray::InspectableWebContentsViewDelegate:
gfx::ImageSkia GetDevToolsWindowIcon() override;
#if defined(USE_X11)
void GetDevToolsWindowWMClass(
std::string* name, std::string* class_name) override;
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
// MessageHandlerDelegate: // MessageHandlerDelegate:
bool PreHandleMSG( bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override; UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
void HandleSizeEvent(WPARAM w_param, LPARAM l_param);
#endif #endif
// NativeWindow: // NativeWindow:
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
void HandleKeyboardEvent( void HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent& event) override; const content::NativeWebKeyboardEvent& event) override;
// views::View: // views::View:
gfx::Size GetMinimumSize() override;
gfx::Size GetMaximumSize() override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override; bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
// Register accelerators supported by the menu model. // Register accelerators supported by the menu model.
void RegisterAccelerators(ui::MenuModel* menu_model); void RegisterAccelerators(ui::MenuModel* menu_model);
// Converts between client area and window area, since we include the menu bar
// in client area we need to substract/add menu bar's height in convertions.
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& content_bounds);
// Returns the restore state for the window. // Returns the restore state for the window.
ui::WindowShowState GetRestoredState(); ui::WindowShowState GetRestoredState();
@ -175,12 +167,23 @@ class NativeWindowViews : public NativeWindow,
// Handles window state events. // Handles window state events.
scoped_ptr<WindowStateWatcher> window_state_watcher_; scoped_ptr<WindowStateWatcher> window_state_watcher_;
// The "resizable" flag on Linux is implemented by setting size constraints,
// we need to make sure size constraints are restored when window becomes
// resizable again.
extensions::SizeConstraints old_size_constraints_;
#elif defined(OS_WIN) #elif defined(OS_WIN)
// Weak ref. // Weak ref.
AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_; AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_;
// Records window was whether restored from minimized state or maximized
// state. ui::WindowShowState last_window_state_;
bool is_minimized_;
// There's an issue with restore on Windows, that sometimes causes the Window
// to receive the wrong size (#2498). To circumvent that, we keep tabs on the
// size of the window while in the normal state (not maximized, minimized or
// fullscreen), so we restore it correctly.
gfx::Size last_normal_size_;
// In charge of running taskbar related APIs. // In charge of running taskbar related APIs.
TaskbarHost taskbar_host_; TaskbarHost taskbar_host_;
#endif #endif
@ -194,8 +197,6 @@ class NativeWindowViews : public NativeWindow,
bool use_content_size_; bool use_content_size_;
bool resizable_; bool resizable_;
std::string title_; std::string title_;
gfx::Size minimum_size_;
gfx::Size maximum_size_;
gfx::Size widget_size_; gfx::Size widget_size_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews); DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);

View file

@ -0,0 +1,145 @@
// 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/native_window_views.h"
namespace atom {
namespace {
// Convert Win32 WM_APPCOMMANDS to strings.
const char* AppCommandToString(int command_id) {
switch (command_id) {
case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward";
case APPCOMMAND_BROWSER_FORWARD : return "browser-forward";
case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh";
case APPCOMMAND_BROWSER_STOP : return "browser-stop";
case APPCOMMAND_BROWSER_SEARCH : return "browser-search";
case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites";
case APPCOMMAND_BROWSER_HOME : return "browser-home";
case APPCOMMAND_VOLUME_MUTE : return "volume-mute";
case APPCOMMAND_VOLUME_DOWN : return "volume-down";
case APPCOMMAND_VOLUME_UP : return "volume-up";
case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack";
case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack";
case APPCOMMAND_MEDIA_STOP : return "media-stop";
case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause";
case APPCOMMAND_LAUNCH_MAIL : return "launch-mail";
case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select";
case APPCOMMAND_LAUNCH_APP1 : return "launch-app1";
case APPCOMMAND_LAUNCH_APP2 : return "launch-app2";
case APPCOMMAND_BASS_DOWN : return "bass-down";
case APPCOMMAND_BASS_BOOST : return "bass-boost";
case APPCOMMAND_BASS_UP : return "bass-up";
case APPCOMMAND_TREBLE_DOWN : return "treble-down";
case APPCOMMAND_TREBLE_UP : return "treble-up";
case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute";
case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down";
case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up";
case APPCOMMAND_HELP : return "help";
case APPCOMMAND_FIND : return "find";
case APPCOMMAND_NEW : return "new";
case APPCOMMAND_OPEN : return "open";
case APPCOMMAND_CLOSE : return "close";
case APPCOMMAND_SAVE : return "save";
case APPCOMMAND_PRINT : return "print";
case APPCOMMAND_UNDO : return "undo";
case APPCOMMAND_REDO : return "redo";
case APPCOMMAND_COPY : return "copy";
case APPCOMMAND_CUT : return "cut";
case APPCOMMAND_PASTE : return "paste";
case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail";
case APPCOMMAND_FORWARD_MAIL : return "forward-mail";
case APPCOMMAND_SEND_MAIL : return "send-mail";
case APPCOMMAND_SPELL_CHECK : return "spell-check";
case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle";
case APPCOMMAND_CORRECTION_LIST : return "correction-list";
case APPCOMMAND_MEDIA_PLAY : return "media-play";
case APPCOMMAND_MEDIA_PAUSE : return "media-pause";
case APPCOMMAND_MEDIA_RECORD : return "media-record";
case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward";
case APPCOMMAND_MEDIA_REWIND : return "media-rewind";
case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up";
case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down";
case APPCOMMAND_DELETE : return "delete";
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
return "dictate-or-command-control-toggle";
default:
return "unknown";
}
}
} // namespace
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
std::string command = AppCommandToString(command_id);
NotifyWindowExecuteWindowsCommand(command);
return false;
}
bool NativeWindowViews::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
switch (message) {
case WM_COMMAND:
// Handle thumbar button click message.
if (HIWORD(w_param) == THBN_CLICKED)
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
return false;
case WM_SIZE:
// Handle window state change.
HandleSizeEvent(w_param, l_param);
return false;
default:
return false;
}
}
void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
// Here we handle the WM_SIZE event in order to figure out what is the current
// window state and notify the user accordingly.
switch (w_param) {
case SIZE_MAXIMIZED:
last_window_state_ = ui::SHOW_STATE_MAXIMIZED;
NotifyWindowMaximize();
break;
case SIZE_MINIMIZED:
last_window_state_ = ui::SHOW_STATE_MINIMIZED;
NotifyWindowMinimize();
break;
case SIZE_RESTORED:
if (last_window_state_ == ui::SHOW_STATE_NORMAL) {
// Window was resized so we save it's new size.
last_normal_size_ = GetSize();
} else {
switch (last_window_state_) {
case ui::SHOW_STATE_MAXIMIZED:
last_window_state_ = ui::SHOW_STATE_NORMAL;
// When the window is restored we resize it to the previous known
// normal size.
NativeWindow::SetSize(last_normal_size_);
NotifyWindowUnmaximize();
break;
case ui::SHOW_STATE_MINIMIZED:
if (IsFullscreen()) {
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
NotifyWindowEnterFullScreen();
} else {
last_window_state_ = ui::SHOW_STATE_NORMAL;
// When the window is restored we resize it to the previous known
// normal size.
NativeWindow::SetSize(last_normal_size_);
NotifyWindowRestore();
}
break;
}
}
break;
}
}
} // namespace atom

View file

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

View file

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

View file

@ -79,6 +79,9 @@ class FileDialog {
if (!title.empty()) if (!title.empty())
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str()); GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
if (!filterspec.empty())
GetPtr()->SetDefaultExtension(filterspec.front().pszSpec);
SetDefaultFolder(default_path); SetDefaultFolder(default_path);
} }

View file

@ -104,11 +104,11 @@ gfx::Size FramelessView::GetPreferredSize() const {
} }
gfx::Size FramelessView::GetMinimumSize() const { gfx::Size FramelessView::GetMinimumSize() const {
return window_->GetMinimumSize(); return window_->GetContentSizeConstraints().GetMinimumSize();
} }
gfx::Size FramelessView::GetMaximumSize() const { gfx::Size FramelessView::GetMaximumSize() const {
return window_->GetMaximumSize(); return window_->GetContentSizeConstraints().GetMaximumSize();
} }
const char* FramelessView::GetClassName() const { const char* FramelessView::GetClassName() const {

View file

@ -4,7 +4,7 @@
#include "atom/browser/ui/views/native_frame_view.h" #include "atom/browser/ui/views/native_frame_view.h"
#include "atom/browser/native_window_views.h" #include "atom/browser/native_window.h"
namespace atom { namespace atom {
@ -14,8 +14,7 @@ const char kViewClassName[] = "AtomNativeFrameView";
} // namespace } // namespace
NativeFrameView::NativeFrameView(NativeWindowViews* window, NativeFrameView::NativeFrameView(NativeWindow* window, views::Widget* widget)
views::Widget* widget)
: views::NativeFrameView(widget), : views::NativeFrameView(widget),
window_(window) { window_(window) {
} }

View file

@ -9,13 +9,13 @@
namespace atom { namespace atom {
class NativeWindowViews; class NativeWindow;
// Like the views::NativeFrameView, but returns the min/max size from the // Like the views::NativeFrameView, but returns the min/max size from the
// NativeWindowViews. // NativeWindowViews.
class NativeFrameView : public views::NativeFrameView { class NativeFrameView : public views::NativeFrameView {
public: public:
NativeFrameView(NativeWindowViews* window, views::Widget* widget); NativeFrameView(NativeWindow* window, views::Widget* widget);
protected: protected:
// views::View: // views::View:
@ -24,7 +24,7 @@ class NativeFrameView : public views::NativeFrameView {
const char* GetClassName() const override; const char* GetClassName() const override;
private: private:
NativeWindowViews* window_; // weak ref. NativeWindow* window_; // weak ref.
DISALLOW_COPY_AND_ASSIGN(NativeFrameView); DISALLOW_COPY_AND_ASSIGN(NativeFrameView);
}; };

View file

@ -5,7 +5,6 @@
#include "atom/browser/ui/views/win_frame_view.h" #include "atom/browser/ui/views/win_frame_view.h"
#include "atom/browser/native_window_views.h" #include "atom/browser/native_window_views.h"
#include "ui/gfx/win/dpi.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/win/hwnd_util.h" #include "ui/views/win/hwnd_util.h"
@ -39,16 +38,6 @@ int WinFrameView::NonClientHitTest(const gfx::Point& point) {
return FramelessView::NonClientHitTest(point); return FramelessView::NonClientHitTest(point);
} }
gfx::Size WinFrameView::GetMinimumSize() const {
gfx::Size size = FramelessView::GetMinimumSize();
return gfx::win::DIPToScreenSize(size);
}
gfx::Size WinFrameView::GetMaximumSize() const {
gfx::Size size = FramelessView::GetMaximumSize();
return gfx::win::DIPToScreenSize(size);
}
const char* WinFrameView::GetClassName() const { const char* WinFrameView::GetClassName() const {
return kViewClassName; return kViewClassName;
} }

View file

@ -20,8 +20,6 @@ class WinFrameView : public FramelessView {
int NonClientHitTest(const gfx::Point& point) override; int NonClientHitTest(const gfx::Point& point) override;
// views::View: // views::View:
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
const char* GetClassName() const override; const char* GetClassName() const override;
private: private:

View file

@ -4,10 +4,7 @@
#include "atom/browser/ui/win/notify_icon.h" #include "atom/browser/ui/win/notify_icon.h"
#include <shobjidl.h>
#include "atom/browser/ui/win/notify_icon_host.h" #include "atom/browser/ui/win/notify_icon_host.h"
#include "base/md5.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
@ -28,31 +25,7 @@ NotifyIcon::NotifyIcon(NotifyIconHost* host,
icon_id_(id), icon_id_(id),
window_(window), window_(window),
message_id_(message), message_id_(message),
menu_model_(NULL), menu_model_(NULL) {
has_tray_app_id_hash_(false) {
// NB: If we have an App Model ID, we should propagate that to the tray.
// Doing this prevents duplicate items from showing up in the notification
// preferences (i.e. "Always Show / Show notifications only / etc")
PWSTR explicit_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&explicit_app_id))) {
// GUIDs and MD5 hashes are the same length. So convenient!
base::MD5Sum(explicit_app_id,
sizeof(wchar_t) * wcslen(explicit_app_id),
reinterpret_cast<base::MD5Digest*>(&tray_app_id_hash_));
// Set the GUID to version 4 as described in RFC 4122, section 4.4.
// The format of GUID version 4 must be like
// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where y is one of [8, 9, A, B].
tray_app_id_hash_.Data3 &= 0x0fff;
tray_app_id_hash_.Data3 |= 0x4000;
// Set y to one of [8, 9, A, B].
tray_app_id_hash_.Data4[0] = 1;
has_tray_app_id_hash_ = true;
CoTaskMemFree(explicit_app_id);
}
NOTIFYICONDATA icon_data; NOTIFYICONDATA icon_data;
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags |= NIF_MESSAGE; icon_data.uFlags |= NIF_MESSAGE;
@ -81,10 +54,6 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
icon_id.uID = icon_id_; icon_id.uID = icon_id_;
icon_id.hWnd = window_; icon_id.hWnd = window_;
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER); 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 }; RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect); Shell_NotifyIconGetRect(&icon_id, &rect);
@ -202,13 +171,6 @@ void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
icon_data->cbSize = sizeof(NOTIFYICONDATA); icon_data->cbSize = sizeof(NOTIFYICONDATA);
icon_data->hWnd = window_; icon_data->hWnd = window_;
icon_data->uID = icon_id_; icon_data->uID = icon_id_;
if (has_tray_app_id_hash_) {
icon_data->uFlags |= NIF_GUID;
memcpy(reinterpret_cast<void*>(&icon_data->guidItem),
&tray_app_id_hash_,
sizeof(GUID));
}
} }
} // namespace atom } // namespace atom

View file

@ -79,10 +79,6 @@ class NotifyIcon : public TrayIcon {
// The context menu. // The context menu.
ui::SimpleMenuModel* menu_model_; ui::SimpleMenuModel* menu_model_;
// A hash of the app model ID
GUID tray_app_id_hash_;
bool has_tray_app_id_hash_;
DISALLOW_COPY_AND_ASSIGN(NotifyIcon); DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
}; };

View file

@ -6,6 +6,7 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include "base/environment.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "dbus/bus.h" #include "dbus/bus.h"
#include "dbus/object_proxy.h" #include "dbus/object_proxy.h"
@ -50,6 +51,10 @@ void SetWindowType(::Window xwindow, const std::string& type) {
} }
bool ShouldUseGlobalMenuBar() { bool ShouldUseGlobalMenuBar() {
scoped_ptr<base::Environment> env(base::Environment::Create());
if (env->HasVar("ELECTRON_FORCE_WINDOW_MENU_BAR"))
return false;
dbus::Bus::Options options; dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options)); scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));

View file

@ -40,6 +40,9 @@ WebContentsPreferences::WebContentsPreferences(
base::DictionaryValue* web_preferences) { base::DictionaryValue* web_preferences) {
web_preferences_.Swap(web_preferences); web_preferences_.Swap(web_preferences);
web_contents->SetUserData(UserDataKey(), this); web_contents->SetUserData(UserDataKey(), this);
// The "isGuest" is not a preferences field.
web_preferences_.Remove("isGuest", nullptr);
} }
WebContentsPreferences::~WebContentsPreferences() { WebContentsPreferences::~WebContentsPreferences() {
@ -94,7 +97,7 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
if (base::FilePath(preload).IsAbsolute()) if (base::FilePath(preload).IsAbsolute())
command_line->AppendSwitchNative(switches::kPreloadScript, preload); command_line->AppendSwitchNative(switches::kPreloadScript, preload);
else else
LOG(ERROR) << "preload script must have abosulute path."; LOG(ERROR) << "preload script must have absolute path.";
} else if (web_preferences.GetString(switches::kPreloadUrl, &preload)) { } else if (web_preferences.GetString(switches::kPreloadUrl, &preload)) {
// Translate to file path if there is "preload-url" option. // Translate to file path if there is "preload-url" option.
base::FilePath preload_path; base::FilePath preload_path;

View file

@ -37,6 +37,9 @@ class WebContentsPreferences
// $.extend(|web_preferences_|, |new_web_preferences|). // $.extend(|web_preferences_|, |new_web_preferences|).
void Merge(const base::DictionaryValue& new_web_preferences); void Merge(const base::DictionaryValue& new_web_preferences);
// Returns the web preferences.
base::DictionaryValue* web_preferences() { return &web_preferences_; }
private: private:
friend class content::WebContentsUserData<WebContentsPreferences>; friend class content::WebContentsUserData<WebContentsPreferences>;

View file

@ -115,6 +115,14 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
Archive::Archive(const base::FilePath& path) Archive::Archive(const base::FilePath& path)
: path_(path), : path_(path),
file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ), file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ),
#if defined(OS_WIN)
fd_(_open_osfhandle(
reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0)),
#elif defined(OS_POSIX)
fd_(file_.GetPlatformFile()),
#else
fd_(-1),
#endif
header_size_(0) { header_size_(0) {
} }
@ -271,17 +279,7 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
} }
int Archive::GetFD() const { int Archive::GetFD() const {
if (!file_.IsValid()) return fd_;
return -1;
#if defined(OS_WIN)
return
_open_osfhandle(reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0);
#elif defined(OS_POSIX)
return file_.GetPlatformFile();
#else
return -1;
#endif
} }
} // namespace asar } // namespace asar

View file

@ -69,6 +69,7 @@ class Archive {
private: private:
base::FilePath path_; base::FilePath path_;
base::File file_; base::File file_;
int fd_;
uint32 header_size_; uint32 header_size_;
scoped_ptr<base::DictionaryValue> header_; scoped_ptr<base::DictionaryValue> header_;

View file

@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 0 #define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 33 #define ATOM_MINOR_VERSION 33
#define ATOM_PATCH_VERSION 0 #define ATOM_PATCH_VERSION 6
#define ATOM_VERSION_IS_RELEASE 1 #define ATOM_VERSION_IS_RELEASE 1

View file

@ -10,9 +10,10 @@ namespace atom {
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) { ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
*shifted = false; *shifted = false;
switch (c) { switch (c) {
case 8: case 0x7F: return ui::VKEY_BACK; case 0x08: return ui::VKEY_BACK;
case 9: return ui::VKEY_TAB; case 0x7F: return ui::VKEY_DELETE;
case 0xD: case 3: return ui::VKEY_RETURN; case 0x09: return ui::VKEY_TAB;
case 0x0D: return ui::VKEY_RETURN;
case 0x1B: return ui::VKEY_ESCAPE; case 0x1B: return ui::VKEY_ESCAPE;
case ' ': return ui::VKEY_SPACE; case ' ': return ui::VKEY_SPACE;

View file

@ -329,7 +329,7 @@ exports.wrapFsWithAsar = (fs) ->
buffer = new Buffer(info.size) buffer = new Buffer(info.size)
fd = archive.getFd() fd = archive.getFd()
retrun undefined unless fd >= 0 return undefined unless fd >= 0
fs.readSync fd, buffer, 0, info.size, info.offset fs.readSync fd, buffer, 0, info.size, info.offset
buffer.toString 'utf8' buffer.toString 'utf8'

View file

@ -1,8 +1,7 @@
process = global.process fs = require 'fs'
fs = require 'fs' path = require 'path'
path = require 'path' timers = require 'timers'
timers = require 'timers' Module = require 'module'
Module = require 'module'
process.atomBinding = (name) -> process.atomBinding = (name) ->
try try
@ -10,21 +9,8 @@ process.atomBinding = (name) ->
catch e catch e
process.binding "atom_common_#{name}" if /No such module/.test e.message process.binding "atom_common_#{name}" if /No such module/.test e.message
# Global module search paths.
globalPaths = Module.globalPaths
# Don't lookup modules in user-defined search paths, see http://git.io/vf8sF.
homeDir =
if process.platform is 'win32'
process.env.USERPROFILE
else
process.env.HOME
if homeDir # Node only add user-defined search paths when $HOME is defined.
userModulePath = path.resolve homeDir, '.node_modules'
globalPaths.splice globalPaths.indexOf(userModulePath), 2
# Add common/api/lib to module search paths. # Add common/api/lib to module search paths.
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') Module.globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
# setImmediate and process.nextTick makes use of uv_check and uv_prepare to # setImmediate and process.nextTick makes use of uv_check and uv_prepare to
# run the callbacks, however since we only run uv loop on requests, the # run the callbacks, however since we only run uv loop on requests, the
@ -37,6 +23,8 @@ wrapWithActivateUvLoop = (func) ->
process.activateUvLoop() process.activateUvLoop()
func.apply this, arguments func.apply this, arguments
process.nextTick = wrapWithActivateUvLoop process.nextTick process.nextTick = wrapWithActivateUvLoop process.nextTick
global.setImmediate = wrapWithActivateUvLoop timers.setImmediate
global.clearImmediate = timers.clearImmediate
if process.type is 'browser' if process.type is 'browser'
# setTimeout needs to update the polling timeout of the event loop, when # setTimeout needs to update the polling timeout of the event loop, when
@ -45,10 +33,3 @@ if process.type is 'browser'
# recalculate the timeout in browser process. # recalculate the timeout in browser process.
global.setTimeout = wrapWithActivateUvLoop timers.setTimeout global.setTimeout = wrapWithActivateUvLoop timers.setTimeout
global.setInterval = wrapWithActivateUvLoop timers.setInterval global.setInterval = wrapWithActivateUvLoop timers.setInterval
global.setImmediate = wrapWithActivateUvLoop timers.setImmediate
global.clearImmediate = wrapWithActivateUvLoop timers.clearImmediate
else
# There are no setImmediate under renderer process by default, so we need to
# manually setup them here.
global.setImmediate = setImmediate
global.clearImmediate = clearImmediate

View file

@ -0,0 +1,29 @@
path = require 'path'
Module = require 'module'
# Clear Node's global search paths.
Module.globalPaths.length = 0
# Clear current and parent(init.coffee)'s search paths.
module.paths = []
module.parent.paths = []
# Prevent Node from adding paths outside this app to search paths.
Module._nodeModulePaths = (from) ->
from = path.resolve from
# If "from" is outside the app then we do nothing.
skipOutsidePaths = from.startsWith process.resourcesPath
# Following logoic is copied from module.js.
splitRe = if process.platform is 'win32' then /[\/\\]/ else /\//
paths = []
parts = from.split splitRe
for part, tip in parts by -1
continue if part is 'node_modules'
dir = parts.slice(0, tip + 1).join path.sep
break if skipOutsidePaths and not dir.startsWith process.resourcesPath
paths.push path.join(dir, 'node_modules')
paths

View file

@ -9,6 +9,7 @@
#include "atom/common/keyboad_util.h" #include "atom/common/keyboad_util.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/native_web_keyboard_event.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h" #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
@ -29,10 +30,10 @@ int VectorToBitArray(const std::vector<T>& vec) {
namespace mate { namespace mate {
template<> template<>
struct Converter<char> { struct Converter<base::char16> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
char* out) { base::char16* out) {
std::string code = base::StringToLowerASCII(V8ToString(val)); base::string16 code = base::UTF8ToUTF16(V8ToString(val));
if (code.length() != 1) if (code.length() != 1)
return false; return false;
*out = code[0]; *out = code[0];
@ -60,7 +61,7 @@ struct Converter<blink::WebInputEvent::Type> {
else if (type == "mousewheel") else if (type == "mousewheel")
*out = blink::WebInputEvent::MouseWheel; *out = blink::WebInputEvent::MouseWheel;
else if (type == "keydown") else if (type == "keydown")
*out = blink::WebInputEvent::KeyDown; *out = blink::WebInputEvent::RawKeyDown;
else if (type == "keyup") else if (type == "keyup")
*out = blink::WebInputEvent::KeyUp; *out = blink::WebInputEvent::KeyUp;
else if (type == "char") else if (type == "char")
@ -77,6 +78,21 @@ struct Converter<blink::WebInputEvent::Type> {
} }
}; };
template<>
struct Converter<blink::WebMouseEvent::Button> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
blink::WebMouseEvent::Button* out) {
std::string button = base::StringToLowerASCII(V8ToString(val));
if (button == "left")
*out = blink::WebMouseEvent::Button::ButtonLeft;
else if (button == "middle")
*out = blink::WebMouseEvent::Button::ButtonMiddle;
else if (button == "right")
*out = blink::WebMouseEvent::Button::ButtonRight;
return true;
}
};
template<> template<>
struct Converter<blink::WebInputEvent::Modifiers> { struct Converter<blink::WebInputEvent::Modifiers> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
@ -142,16 +158,19 @@ bool Converter<blink::WebKeyboardEvent>::FromV8(
return false; return false;
if (!ConvertFromV8(isolate, val, static_cast<blink::WebInputEvent*>(out))) if (!ConvertFromV8(isolate, val, static_cast<blink::WebInputEvent*>(out)))
return false; return false;
char code; base::char16 code;
if (!dict.Get("keyCode", &code)) if (!dict.Get("keyCode", &code))
return false; return false;
bool shifted = false; bool shifted = false;
out->windowsKeyCode = atom::KeyboardCodeFromCharCode(code, &shifted); out->windowsKeyCode = atom::KeyboardCodeFromCharCode(code, &shifted);
if (out->windowsKeyCode == ui::VKEY_UNKNOWN)
return false;
if (shifted) if (shifted)
out->modifiers |= blink::WebInputEvent::ShiftKey; out->modifiers |= blink::WebInputEvent::ShiftKey;
out->setKeyIdentifierFromWindowsKeyCode(); out->setKeyIdentifierFromWindowsKeyCode();
if (out->type == blink::WebInputEvent::Char ||
out->type == blink::WebInputEvent::RawKeyDown) {
out->text[0] = code;
out->unmodifiedText[0] = code;
}
return true; return true;
} }
@ -176,6 +195,7 @@ bool Converter<blink::WebMouseEvent>::FromV8(
return false; return false;
if (!dict.Get("x", &out->x) || !dict.Get("y", &out->y)) if (!dict.Get("x", &out->x) || !dict.Get("y", &out->y))
return false; return false;
dict.Get("button", &out->button);
dict.Get("globalX", &out->globalX); dict.Get("globalX", &out->globalX);
dict.Get("globalY", &out->globalY); dict.Get("globalY", &out->globalY);
dict.Get("movementX", &out->movementX); dict.Get("movementX", &out->movementX);

View file

@ -34,6 +34,7 @@ REFERENCE_MODULE(atom_browser_app);
REFERENCE_MODULE(atom_browser_auto_updater); REFERENCE_MODULE(atom_browser_auto_updater);
REFERENCE_MODULE(atom_browser_content_tracing); REFERENCE_MODULE(atom_browser_content_tracing);
REFERENCE_MODULE(atom_browser_dialog); REFERENCE_MODULE(atom_browser_dialog);
REFERENCE_MODULE(atom_browser_download_item);
REFERENCE_MODULE(atom_browser_menu); REFERENCE_MODULE(atom_browser_menu);
REFERENCE_MODULE(atom_browser_power_monitor); REFERENCE_MODULE(atom_browser_power_monitor);
REFERENCE_MODULE(atom_browser_power_save_blocker); REFERENCE_MODULE(atom_browser_power_save_blocker);

View file

@ -113,6 +113,10 @@ const char kDisableHttpCache[] = "disable-http-cache";
// Register schemes to standard. // Register schemes to standard.
const char kRegisterStandardSchemes[] = "register-standard-schemes"; const char kRegisterStandardSchemes[] = "register-standard-schemes";
// The minimum SSL/TLS version ("tls1", "tls1.1", or "tls1.2") that
// TLS fallback will accept.
const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
// The browser process app model ID // The browser process app model ID
const char kAppUserModelId[] = "app-user-model-id"; const char kAppUserModelId[] = "app-user-model-id";

View file

@ -59,6 +59,7 @@ extern const char kPageVisibility[];
extern const char kDisableHttpCache[]; extern const char kDisableHttpCache[];
extern const char kRegisterStandardSchemes[]; extern const char kRegisterStandardSchemes[];
extern const char kSSLVersionFallbackMin[];
extern const char kAppUserModelId[]; extern const char kAppUserModelId[];

View file

@ -98,6 +98,16 @@ void WebFrame::RegisterURLSchemeAsBypassingCsp(const std::string& scheme) {
blink::WebString::fromUTF8(scheme)); blink::WebString::fromUTF8(scheme));
} }
void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme) {
// Register scheme to privileged list (https, wss, data, chrome-extension)
blink::WebString privileged_scheme(blink::WebString::fromUTF8(scheme));
blink::WebSecurityPolicy::registerURLSchemeAsSecure(privileged_scheme);
blink::WebSecurityPolicy::registerURLSchemeAsBypassingContentSecurityPolicy(
privileged_scheme);
blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers(
privileged_scheme);
}
mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
v8::Isolate* isolate) { v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate) return mate::ObjectTemplateBuilder(isolate)
@ -116,7 +126,9 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
.SetMethod("registerUrlSchemeAsSecure", .SetMethod("registerUrlSchemeAsSecure",
&WebFrame::RegisterURLSchemeAsSecure) &WebFrame::RegisterURLSchemeAsSecure)
.SetMethod("registerUrlSchemeAsBypassingCsp", .SetMethod("registerUrlSchemeAsBypassingCsp",
&WebFrame::RegisterURLSchemeAsBypassingCsp); &WebFrame::RegisterURLSchemeAsBypassingCsp)
.SetMethod("registerUrlSchemeAsPrivileged",
&WebFrame::RegisterURLSchemeAsPrivileged);
} }
// static // static

View file

@ -58,6 +58,7 @@ class WebFrame : public mate::Wrappable {
void RegisterURLSchemeAsSecure(const std::string& scheme); void RegisterURLSchemeAsSecure(const std::string& scheme);
void RegisterURLSchemeAsBypassingCsp(const std::string& scheme); void RegisterURLSchemeAsBypassingCsp(const std::string& scheme);
void RegisterURLSchemeAsPrivileged(const std::string& scheme);
// mate::Wrappable: // mate::Wrappable:
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(

View file

@ -1,4 +1,3 @@
process = global.process
ipc = require 'ipc' ipc = require 'ipc'
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'
CallbacksRegistry = require 'callbacks-registry' CallbacksRegistry = require 'callbacks-registry'
@ -131,7 +130,7 @@ exports.require = (module) ->
windowCache = null windowCache = null
exports.getCurrentWindow = -> exports.getCurrentWindow = ->
return windowCache if windowCache? return windowCache if windowCache?
meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WINDOW'
windowCache = metaToValue meta windowCache = metaToValue meta
# Get current WebContents object. # Get current WebContents object.

View file

@ -1,23 +1,22 @@
process = global.process events = require 'events'
events = require 'events' path = require 'path'
path = require 'path' url = require 'url'
url = require 'url' Module = require 'module'
Module = require 'module'
# We modified the original process.argv to let node.js load the # We modified the original process.argv to let node.js load the
# atom-renderer.js, we need to restore it here. # atom-renderer.js, we need to restore it here.
process.argv.splice 1, 1 process.argv.splice 1, 1
# Clear search paths.
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')
# Import common settings.
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
# Add renderer/api/lib to require's search paths, which contains javascript part # Add renderer/api/lib to require's search paths, which contains javascript part
# of Atom's built-in libraries. # of Atom's built-in libraries.
globalPaths = Module.globalPaths globalPaths = Module.globalPaths
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
# And also app.
globalPaths.push path.join(process.resourcesPath, 'app')
globalPaths.push path.join(process.resourcesPath, 'app.asar')
# Import common settings.
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
# The global variable will be used by ipc for event dispatching # The global variable will be used by ipc for event dispatching
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'

View file

@ -44,7 +44,7 @@ createMenu = (x, y, items, document) ->
showFileChooserDialog = (callback) -> showFileChooserDialog = (callback) ->
remote = require 'remote' remote = require 'remote'
dialog = remote.require 'dialog' dialog = remote.require 'dialog'
files = dialog.showOpenDialog remote.getCurrentWindow(), null files = dialog.showOpenDialog {}
callback pathToHtml5FileObject files[0] if files? callback pathToHtml5FileObject files[0] if files?
pathToHtml5FileObject = (path) -> pathToHtml5FileObject = (path) ->

View file

@ -1,4 +1,3 @@
process = global.process
ipc = require 'ipc' ipc = require 'ipc'
remote = require 'remote' remote = require 'remote'
@ -71,7 +70,6 @@ window.open = (url, frameName='', features='') ->
if guestId if guestId
new BrowserWindowProxy(guestId) new BrowserWindowProxy(guestId)
else else
console.error 'It is not allowed to open new window from this WebContents'
null null
# Use the dialog API to implement alert(). # Use the dialog API to implement alert().
@ -124,3 +122,7 @@ window.history.go = (offset) -> sendHistoryOperation 'goToOffset', offset
Object.defineProperty window.history, 'length', Object.defineProperty window.history, 'length',
get: -> get: ->
getHistoryOperation 'length' getHistoryOperation 'length'
# Make document.hidden return the correct value.
Object.defineProperty document, 'hidden',
get: -> !remote.getCurrentWindow().isVisible()

View file

@ -16,7 +16,7 @@ WEB_VIEW_EVENTS =
'did-get-redirect-request': ['oldUrl', 'newUrl', 'isMainFrame'] 'did-get-redirect-request': ['oldUrl', 'newUrl', 'isMainFrame']
'dom-ready': [] 'dom-ready': []
'console-message': ['level', 'message', 'line', 'sourceId'] 'console-message': ['level', 'message', 'line', 'sourceId']
'new-window': ['url', 'frameName', 'disposition'] 'new-window': ['url', 'frameName', 'disposition', 'options']
'close': [] 'close': []
'crashed': [] 'crashed': []
'gpu-crashed': [] 'gpu-crashed': []

View file

@ -216,6 +216,7 @@ WebViewImpl::setupWebViewAttributes = ->
@attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this) @attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this)
@attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this) @attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this)
@attributes[webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, this) @attributes[webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, this)
@attributes[webViewConstants.ATTRIBUTE_ALLOWPOPUPS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_ALLOWPOPUPS, this)
@attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this) @attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this)
autosizeAttributes = [ autosizeAttributes = [

View file

@ -13,6 +13,7 @@ module.exports =
ATTRIBUTE_NODEINTEGRATION: 'nodeintegration' ATTRIBUTE_NODEINTEGRATION: 'nodeintegration'
ATTRIBUTE_PLUGINS: 'plugins' ATTRIBUTE_PLUGINS: 'plugins'
ATTRIBUTE_DISABLEWEBSECURITY: 'disablewebsecurity' ATTRIBUTE_DISABLEWEBSECURITY: 'disablewebsecurity'
ATTRIBUTE_ALLOWPOPUPS: 'allowpopups'
ATTRIBUTE_PRELOAD: 'preload' ATTRIBUTE_PRELOAD: 'preload'
ATTRIBUTE_USERAGENT: 'useragent' ATTRIBUTE_USERAGENT: 'useragent'

View file

@ -46,6 +46,7 @@ class WebViewImpl
# that we don't end up allocating a second guest. # that we don't end up allocating a second guest.
if @guestInstanceId if @guestInstanceId
guestViewInternal.destroyGuest @guestInstanceId guestViewInternal.destroyGuest @guestInstanceId
@webContents = null
@guestInstanceId = undefined @guestInstanceId = undefined
@beforeFirstNavigation = true @beforeFirstNavigation = true
@attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true @attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true
@ -188,6 +189,7 @@ class WebViewImpl
attachWindow: (guestInstanceId) -> attachWindow: (guestInstanceId) ->
@guestInstanceId = guestInstanceId @guestInstanceId = guestInstanceId
@webContents = remote.getGuestWebContents @guestInstanceId
return true unless @internalInstanceId return true unless @internalInstanceId
guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildParams() guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildParams()
@ -299,7 +301,7 @@ registerWebViewElement = ->
createHandler = (m) -> createHandler = (m) ->
(args...) -> (args...) ->
internal = v8Util.getHiddenValue this, 'internal' internal = v8Util.getHiddenValue this, 'internal'
remote.getGuestWebContents(internal.guestInstanceId)[m] args... internal.webContents[m] args...
proto[m] = createHandler m for m in methods proto[m] = createHandler m for m in methods
window.WebView = webFrame.registerEmbedderCustomElement 'webview', window.WebView = webFrame.registerEmbedderCustomElement 'webview',

View file

@ -0,0 +1,83 @@
// 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 file.
#include "extensions/browser/app_window/size_constraints.h"
#include <algorithm>
#include "ui/gfx/geometry/insets.h"
namespace extensions {
SizeConstraints::SizeConstraints()
: maximum_size_(kUnboundedSize, kUnboundedSize) {}
SizeConstraints::SizeConstraints(const gfx::Size& min_size,
const gfx::Size& max_size)
: minimum_size_(min_size), maximum_size_(max_size) {}
SizeConstraints::~SizeConstraints() {}
// static
gfx::Size SizeConstraints::AddFrameToConstraints(
const gfx::Size& size_constraints,
const gfx::Insets& frame_insets) {
return gfx::Size(
size_constraints.width() == kUnboundedSize
? kUnboundedSize
: size_constraints.width() + frame_insets.width(),
size_constraints.height() == kUnboundedSize
? kUnboundedSize
: size_constraints.height() + frame_insets.height());
}
gfx::Size SizeConstraints::ClampSize(gfx::Size size) const {
const gfx::Size max_size = GetMaximumSize();
if (max_size.width() != kUnboundedSize)
size.set_width(std::min(size.width(), max_size.width()));
if (max_size.height() != kUnboundedSize)
size.set_height(std::min(size.height(), max_size.height()));
size.SetToMax(GetMinimumSize());
return size;
}
bool SizeConstraints::HasMinimumSize() const {
const gfx::Size min_size = GetMinimumSize();
return min_size.width() != kUnboundedSize ||
min_size.height() != kUnboundedSize;
}
bool SizeConstraints::HasMaximumSize() const {
const gfx::Size max_size = GetMaximumSize();
return max_size.width() != kUnboundedSize ||
max_size.height() != kUnboundedSize;
}
bool SizeConstraints::HasFixedSize() const {
return !GetMinimumSize().IsEmpty() && GetMinimumSize() == GetMaximumSize();
}
gfx::Size SizeConstraints::GetMinimumSize() const {
return minimum_size_;
}
gfx::Size SizeConstraints::GetMaximumSize() const {
return gfx::Size(
maximum_size_.width() == kUnboundedSize
? kUnboundedSize
: std::max(maximum_size_.width(), minimum_size_.width()),
maximum_size_.height() == kUnboundedSize
? kUnboundedSize
: std::max(maximum_size_.height(), minimum_size_.height()));
}
void SizeConstraints::set_minimum_size(const gfx::Size& min_size) {
minimum_size_ = min_size;
}
void SizeConstraints::set_maximum_size(const gfx::Size& max_size) {
maximum_size_ = max_size;
}
} // namespace extensions

View file

@ -0,0 +1,57 @@
// 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 file.
#ifndef EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_
#define EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_
#include "ui/gfx/geometry/size.h"
namespace gfx {
class Insets;
}
namespace extensions {
class SizeConstraints {
public:
// The value SizeConstraints uses to represent an unbounded width or height.
// This is an enum so that it can be declared inline here.
enum { kUnboundedSize = 0 };
SizeConstraints();
SizeConstraints(const gfx::Size& min_size, const gfx::Size& max_size);
~SizeConstraints();
// Adds frame insets to a size constraint.
static gfx::Size AddFrameToConstraints(const gfx::Size& size_constraints,
const gfx::Insets& frame_insets);
// Returns the bounds with its size clamped to the min/max size.
gfx::Size ClampSize(gfx::Size size) const;
// When gfx::Size is used as a min/max size, a zero represents an unbounded
// component. This method checks whether either component is specified.
// Note we can't use gfx::Size::IsEmpty as it returns true if either width
// or height is zero.
bool HasMinimumSize() const;
bool HasMaximumSize() const;
// This returns true if all components are specified, and min and max are
// equal.
bool HasFixedSize() const;
gfx::Size GetMaximumSize() const;
gfx::Size GetMinimumSize() const;
void set_minimum_size(const gfx::Size& min_size);
void set_maximum_size(const gfx::Size& max_size);
private:
gfx::Size minimum_size_;
gfx::Size maximum_size_;
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_

View file

@ -1,5 +1,6 @@
## 개발 가이드 ## 개발 가이드
* [지원하는 플랫폼](tutorial/supported-platforms.md)
* [어플리케이션 배포](tutorial/application-distribution.md) * [어플리케이션 배포](tutorial/application-distribution.md)
* [어플리케이션 패키징](tutorial/application-packaging.md) * [어플리케이션 패키징](tutorial/application-packaging.md)
* [네이티브 Node 모듈 사용하기](tutorial/using-native-node-modules.md) * [네이티브 Node 모듈 사용하기](tutorial/using-native-node-modules.md)
@ -26,7 +27,7 @@
* [`<webview>` 태그](api/web-view-tag.md) * [`<webview>` 태그](api/web-view-tag.md)
* [`window.open` 함수](api/window-open.md) * [`window.open` 함수](api/window-open.md)
### 메인 프로세스를 위한 모듈들: ### 메인 프로세스에서 사용할 수 있는 모듈:
* [app (0% 번역됨)](api/app.md) * [app (0% 번역됨)](api/app.md)
* [auto-updater](api/auto-updater.md) * [auto-updater](api/auto-updater.md)
@ -44,13 +45,13 @@
* [web-contents (0% 번역됨)](api/web-contents.md) * [web-contents (0% 번역됨)](api/web-contents.md)
* [tray](api/tray.md) * [tray](api/tray.md)
### 랜더러 프로세스를 위한 모듈들 (웹 페이지): ### 랜더러 프로세스에서 사용할 수 있는 모듈 (웹 페이지):
* [ipc (renderer)](api/ipc-renderer.md) * [ipc (renderer)](api/ipc-renderer.md)
* [remote](api/remote.md) * [remote](api/remote.md)
* [web-frame](api/web-frame.md) * [web-frame](api/web-frame.md)
### 두 프로세스에서 모두 사용 가능한 모듈들: ### 두 프로세스 모두 사용할 수 있는 모듈:
* [clipboard](api/clipboard.md) * [clipboard](api/clipboard.md)
* [crash-reporter](api/crash-reporter.md) * [crash-reporter](api/crash-reporter.md)

View file

@ -1,6 +1,6 @@
# 크롬 Command-Line 스위치 지원 # 크롬 Command-Line 스위치 지원
다음 Command-Line 스위치들은 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다. 크롬 Command-Line 스위치는 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다.
[app][app]의 [ready][ready]이벤트가 작동하기 전에 [app.commandLine.appendSwitch][append-switch] API를 사용하면 [app][app]의 [ready][ready]이벤트가 작동하기 전에 [app.commandLine.appendSwitch][append-switch] API를 사용하면
어플리케이션 내부에서 스위치들을 추가할 수 있습니다: 어플리케이션 내부에서 스위치들을 추가할 수 있습니다:
@ -80,26 +80,30 @@ Pepper 플래시 플러그인의 버전을 설정합니다.
## --log-net-log=`path` ## --log-net-log=`path`
Net log 이벤트를 지정한 `path`에 로그로 기록합니다. Net log 이벤트를 활성화하고 `path`에 로그를 기록합니다.
## --ssl-version-fallback-min=`version`
TLS fallback에서 사용할 SSL/TLS 최소 버전을 지정합니다. ("tls1", "tls1.1", "tls1.2")
## --enable-logging
Chromium의 로그를 콘솔에 출력합니다.
이 스위치는 어플리케이션이 로드되기 전에 파싱 되므로 `app.commandLine.appendSwitch`에서 사용할 수 없습니다.
## --v=`log_level` ## --v=`log_level`
기본 V-logging 최대 활성화 레벨을 지정합니다. 기본값은 0입니다. 기본적으로 양수를 레벨로 사용합니다. 기본 V-logging 최대 활성화 레벨을 지정합니다. 기본값은 0입니다. 기본적으로 양수를 레벨로 사용합니다.
`--v=-1`를 사용하면 로깅이 비활성화 됩니다. 이 스위치는 `--enable-logging` 스위치를 같이 지정해야 작동합니다.
## --vmodule=`pattern` ## --vmodule=`pattern`
`--v` 옵션에 전달된 값을 덮어쓰고 모듈당 최대 V-logging 레벨을 지정합니다. `--v` 옵션에 전달된 값을 덮어쓰고 모듈당 최대 V-logging 레벨을 지정합니다.
예를 들어 `my_module=2,foo*=3``my_module.*`, `foo*.*`와 같은 파일 이름 패턴을 가진 모든 소스 코드들의 로깅 레벨을 각각 2와 3으로 설정합니다. 예를 들어 `my_module=2,foo*=3``my_module.*`, `foo*.*`와 같은 파일 이름 패턴을 가진 모든 소스 코드들의 로깅 레벨을 각각 2와 3으로 설정합니다.
슬래시(`/`), 백슬래시(`\`)를 포함하는 모든 패턴은 모듈뿐만 아니라 모든 경로명에 대해서도 테스트 됩니다. 또한 슬래시(`/`) 또는 백슬래시(`\`)를 포함하는 패턴은 지정한 경로에 대해 패턴을 테스트 합니다.
예를 들어 `*/foo/bar/*=2` 표현식은 `foo/bar` 디렉터리 안의 모든 소스 코드의 로깅 레벨을 2로 지정합니다. 예를 들어 `*/foo/bar/*=2` 표현식은 `foo/bar` 디렉터리 안의 모든 소스 코드의 로깅 레벨을 2로 지정합니다.
모든 크로미움과 관련된 로그를 비활성화하고 어플리케이션의 로그만 활성화 하려면 다음과 같이 코드를 작성하면 됩니다: 이 스위치는 `--enable-logging` 스위치를 같이 지정해야 작동합니다.
```javascript
app.commandLine.appendSwitch('v', -1);
app.commandLine.appendSwitch('vmodule', 'console=0');
```

View file

@ -1,6 +1,6 @@
# MenuItem # MenuItem
`menu-item` 모듈은 어플리케이션 또는 컨텐츠 [`menu`](menu.md)에 아이템을 추가할 수 있도록 관련 클래스를 제공합니다. `menu-item` 모듈은 어플리케이션 또는 컨텍스트 [`menu`](menu.md)에 아이템을 추가할 수 있도록 관련 클래스를 제공합니다.
[`menu`](menu.md)에서 예제를 확인할 수 있습니다. [`menu`](menu.md)에서 예제를 확인할 수 있습니다.

View file

@ -229,11 +229,11 @@ Menu.setApplicationMenu(menu);
또한 `template`에는 다른 속성도 추가할 수 있으며 메뉴가 만들어질 때 해당 메뉴 아이템의 프로퍼티로 변환됩니다. 또한 `template`에는 다른 속성도 추가할 수 있으며 메뉴가 만들어질 때 해당 메뉴 아이템의 프로퍼티로 변환됩니다.
### `Menu.popup(browserWindow[, x, y])` ### `Menu.popup([browserWindow, x, y])`
* `browserWindow` BrowserWindow * `browserWindow` BrowserWindow (optional)
* `x` Number (optional) * `x` Number (optional)
* `y` Number (만약 `x`를 지정했을 경우 `y` 필수로 지정해야 합니다) * `y` Number (만약 `x`를 지정했을 경우 반드시 `y`도 지정해야 합니다)
메뉴를 `browserWindow` 내부 팝업으로 표시합니다. 메뉴를 `browserWindow` 내부 팝업으로 표시합니다.
옵션으로 메뉴를 표시할 `(x,y)` 좌표를 지정할 수 있습니다. 옵션으로 메뉴를 표시할 `(x,y)` 좌표를 지정할 수 있습니다.

View file

@ -142,4 +142,4 @@ var image = NativeImage.createFromPath('/Users/somebody/images/icon.png');
이미지가 템플릿 이미지인지 확인합니다. 이미지가 템플릿 이미지인지 확인합니다.
[buffer]: https://iojs.org/api/buffer.html#buffer_class_buffer [buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer

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