Merge remote-tracking branch 'ups/master'

This commit is contained in:
renaesop 2017-05-09 09:44:24 +08:00
commit cba5e96496
485 changed files with 17051 additions and 3798 deletions

3
.gitmodules vendored
View file

@ -22,3 +22,6 @@
[submodule "vendor/boto"] [submodule "vendor/boto"]
path = vendor/boto path = vendor/boto
url = https://github.com/boto/boto.git url = https://github.com/boto/boto.git
[submodule "vendor/pdf_viewer"]
path = vendor/pdf_viewer
url = https://github.com/electron/pdf-viewer.git

View file

@ -20,4 +20,16 @@ Thanks for opening an issue! A few things to keep in mind:
### How to reproduce ### How to reproduce
<!-- For bugs, provide sample code or a repo URL that demos the problem --> <!--
Your best chance of getting this bug looked at quickly is to provide a REPOSITORY that can be cloned and run.
You can fork https://github.com/electron/electron-quick-start and include a link to the branch with your changes.
If you provide a URL, please list the commands required to clone/setup/run your repo e.g.
$ git clone $YOUR_URL -b $BRANCH
$ npm install
$ npm start || electron .
-->

View file

@ -1,16 +1,16 @@
[![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/) [![Electron Logo](https://electron.atom.io/images/electron-logo.svg)](https://electron.atom.io/)
[![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) [![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/kvxe4byi7jcxbe26/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/bc56v83355fi3369/branch/master?svg=true)](https://ci.appveyor.com/project/electron-bot/electron/branch/master)
[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev) [![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev)
[![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) [![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/)
:memo: Available Translations: [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) :memo: Available Translations: [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) | [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es/project/README.md) | [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR/project/README.md)
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 [Node.js](https://nodejs.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 by the [Atom [Chromium](http://www.chromium.org) and is used by the [Atom
editor](https://github.com/atom/atom) and many other [apps](http://electron.atom.io/apps). editor](https://github.com/atom/atom) and many other [apps](https://electron.atom.io/apps).
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements. announcements.
@ -54,6 +54,7 @@ contains documents describing how to build and contribute to Electron.
- [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN) - [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN)
- [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW) - [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW)
- [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR) - [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR)
- [Thai](https://github.com/electron/electron/tree/master/docs-Translations/th-TH)
- [Ukrainian](https://github.com/electron/electron/tree/master/docs-translations/uk-UA) - [Ukrainian](https://github.com/electron/electron/tree/master/docs-translations/uk-UA)
- [Russian](https://github.com/electron/electron/tree/master/docs-translations/ru-RU) - [Russian](https://github.com/electron/electron/tree/master/docs-translations/ru-RU)
- [French](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) - [French](https://github.com/electron/electron/tree/master/docs-translations/fr-FR)
@ -71,10 +72,11 @@ locations:
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
- [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)* - [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
- [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)* - [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
- [`electron-jp`](https://electron-jp.slack.com) *(Japanese)* - [`electron-jp`](https://electron-jp.slack.com) *(Japanese)*
- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turkish)* - [`electron-tr`](http://electron-tr.herokuapp.com) *(Turkish)*
- [`electron-id`](https://electron-id.slack.com) *(Indonesia)* - [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron) Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)

9
SECURITY.md Normal file
View file

@ -0,0 +1,9 @@
# Reporting Security Issues
The Electron team and community take security bugs in Electron seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
To report a security issue, email [electron@github.com](mailto:electron@github.com) and include the word "SECURITY" in the subject line.
The Electron team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
Report security bugs in third-party modules to the person or team maintaining the module. You can also report a vulnerability through the [Node Security Project](https://nodesecurity.io/report).

View file

@ -7,6 +7,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "atom/common/atom_constants.h"
#include "atom/common/atom_version.h" #include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h" #include "atom/common/chrome_version.h"
#include "atom/common/options_switches.h" #include "atom/common/options_switches.h"
@ -18,6 +19,7 @@
#include "content/public/common/content_constants.h" #include "content/public/common/content_constants.h"
#include "content/public/common/pepper_plugin_info.h" #include "content/public/common/pepper_plugin_info.h"
#include "content/public/common/user_agent.h" #include "content/public/common/user_agent.h"
#include "pdf/pdf.h"
#include "ppapi/shared_impl/ppapi_permissions.h" #include "ppapi/shared_impl/ppapi_permissions.h"
#include "third_party/widevine/cdm/stub/widevine_cdm_version.h" #include "third_party/widevine/cdm/stub/widevine_cdm_version.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
@ -42,7 +44,7 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path,
std::vector<std::string> flash_version_numbers = base::SplitString( std::vector<std::string> flash_version_numbers = base::SplitString(
version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (flash_version_numbers.size() < 1) if (flash_version_numbers.empty())
flash_version_numbers.push_back("11"); flash_version_numbers.push_back("11");
// |SplitString()| puts in an empty string given an empty string. :( // |SplitString()| puts in an empty string given an empty string. :(
else if (flash_version_numbers[0].empty()) else if (flash_version_numbers[0].empty())
@ -108,6 +110,25 @@ content::PepperPluginInfo CreateWidevineCdmInfo(const base::FilePath& path,
} }
#endif #endif
void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) {
content::PepperPluginInfo pdf_info;
pdf_info.is_internal = true;
pdf_info.is_out_of_process = true;
pdf_info.name = "Chromium PDF Viewer";
pdf_info.description = "Portable Document Format";
pdf_info.path = base::FilePath::FromUTF8Unsafe(kPdfPluginPath);
content::WebPluginMimeType pdf_mime_type(kPdfPluginMimeType, "pdf",
"Portable Document Format");
pdf_info.mime_types.push_back(pdf_mime_type);
pdf_info.internal_entry_points.get_interface = chrome_pdf::PPP_GetInterface;
pdf_info.internal_entry_points.initialize_module =
chrome_pdf::PPP_InitializeModule;
pdf_info.internal_entry_points.shutdown_module =
chrome_pdf::PPP_ShutdownModule;
pdf_info.permissions = ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV;
plugins->push_back(pdf_info);
}
void ConvertStringWithSeparatorToVector(std::vector<std::string>* vec, void ConvertStringWithSeparatorToVector(std::vector<std::string>* vec,
const char* separator, const char* separator,
const char* cmd_switch) { const char* cmd_switch) {
@ -190,6 +211,7 @@ void AtomContentClient::AddPepperPlugins(
#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_PEPPER_CDMS) #if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_PEPPER_CDMS)
AddWidevineCdmFromCommandLine(plugins); AddWidevineCdmFromCommandLine(plugins);
#endif #endif
ComputeBuiltInPlugins(plugins);
} }
void AtomContentClient::AddServiceWorkerSchemes( void AtomContentClient::AddServiceWorkerSchemes(

View file

@ -102,6 +102,9 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
#if defined(OS_WIN) #if defined(OS_WIN)
// Ignore invalid parameter errors. // Ignore invalid parameter errors.
_set_invalid_parameter_handler(InvalidParameterHandler); _set_invalid_parameter_handler(InvalidParameterHandler);
// Disable the ActiveVerifier, which is used by Chrome to track possible
// bugs, but no use in Electron.
base::win::DisableHandleVerifier();
#endif #endif
return brightray::MainDelegate::BasicStartupComplete(exit_code); return brightray::MainDelegate::BasicStartupComplete(exit_code);

View file

@ -30,14 +30,16 @@
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "brightray/browser/brightray_paths.h" #include "brightray/browser/brightray_paths.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/icon_manager.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_child_process_host.h"
#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "media/audio/audio_manager.h" #include "media/audio/audio_manager.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_cert_request_info.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
@ -335,6 +337,26 @@ namespace api {
namespace { namespace {
class AppIdProcessIterator : public base::ProcessIterator {
public:
AppIdProcessIterator() : base::ProcessIterator(nullptr) {}
protected:
bool IncludeEntry() override {
return (entry().parent_pid() == base::GetCurrentProcId() ||
entry().pid() == base::GetCurrentProcId());
}
};
IconLoader::IconSize GetIconSizeByString(const std::string& size) {
if (size == "small") {
return IconLoader::IconSize::SMALL;
} else if (size == "large") {
return IconLoader::IconSize::LARGE;
}
return IconLoader::IconSize::NORMAL;
}
// Return the path constant from string. // Return the path constant from string.
int GetPathConstant(const std::string& name) { int GetPathConstant(const std::string& name) {
if (name == "appData") if (name == "appData")
@ -416,7 +438,7 @@ void OnClientCertificateSelected(
auto certs = net::X509Certificate::CreateCertificateListFromBytes( auto certs = net::X509Certificate::CreateCertificateListFromBytes(
data.c_str(), data.length(), net::X509Certificate::FORMAT_AUTO); data.c_str(), data.length(), net::X509Certificate::FORMAT_AUTO);
if (certs.size() > 0) if (!certs.empty())
delegate->ContinueWithCertificate(certs[0].get()); delegate->ContinueWithCertificate(certs[0].get());
} }
@ -462,6 +484,21 @@ int ImportIntoCertStore(
} }
#endif #endif
void OnIconDataAvailable(v8::Isolate* isolate,
const App::FileIconCallback& callback,
gfx::Image* icon) {
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (icon && !icon->IsEmpty()) {
callback.Run(v8::Null(isolate), *icon);
} else {
v8::Local<v8::String> error_message =
v8::String::NewFromUtf8(isolate, "Failed to get file icon.");
callback.Run(v8::Exception::Error(error_message), gfx::Image());
}
}
} // namespace } // namespace
App::App(v8::Isolate* isolate) { App::App(v8::Isolate* isolate) {
@ -494,7 +531,7 @@ void App::OnQuit() {
int exitCode = AtomBrowserMainParts::Get()->GetExitCode(); int exitCode = AtomBrowserMainParts::Get()->GetExitCode();
Emit("quit", exitCode); Emit("quit", exitCode);
if (process_singleton_.get()) { if (process_singleton_) {
process_singleton_->Cleanup(); process_singleton_->Cleanup();
process_singleton_.reset(); process_singleton_.reset();
} }
@ -629,6 +666,14 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) {
status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
} }
base::FilePath App::GetAppPath() const {
return app_path_;
}
void App::SetAppPath(const base::FilePath& app_path) {
app_path_ = app_path;
}
base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) { base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) {
bool succeed = false; bool succeed = false;
base::FilePath path; base::FilePath path;
@ -669,7 +714,7 @@ std::string App::GetLocale() {
bool App::MakeSingleInstance( bool App::MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback) { const ProcessSingleton::NotificationCallback& callback) {
if (process_singleton_.get()) if (process_singleton_)
return false; return false;
base::FilePath user_dir; base::FilePath user_dir;
@ -690,7 +735,7 @@ bool App::MakeSingleInstance(
} }
void App::ReleaseSingleInstance() { void App::ReleaseSingleInstance() {
if (process_singleton_.get()) { if (process_singleton_) {
process_singleton_->Cleanup(); process_singleton_->Cleanup();
process_singleton_.reset(); process_singleton_.reset();
} }
@ -841,6 +886,84 @@ JumpListResult App::SetJumpList(v8::Local<v8::Value> val,
} }
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
void App::GetFileIcon(const base::FilePath& path,
mate::Arguments* args) {
mate::Dictionary options;
IconLoader::IconSize icon_size;
FileIconCallback callback;
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
base::FilePath normalized_path = path.NormalizePathSeparators();
if (!args->GetNext(&options)) {
icon_size = IconLoader::IconSize::NORMAL;
} else {
std::string icon_size_string;
options.Get("size", &icon_size_string);
icon_size = GetIconSizeByString(icon_size_string);
}
if (!args->GetNext(&callback)) {
args->ThrowError("Missing required callback function");
return;
}
auto icon_manager = g_browser_process->GetIconManager();
gfx::Image* icon =
icon_manager->LookupIconFromFilepath(normalized_path, icon_size);
if (icon) {
callback.Run(v8::Null(isolate()), *icon);
} else {
icon_manager->LoadIcon(
normalized_path, icon_size,
base::Bind(&OnIconDataAvailable, isolate(), callback),
&cancelable_task_tracker_);
}
}
std::vector<mate::Dictionary> App::GetAppMemoryInfo(v8::Isolate* isolate) {
AppIdProcessIterator process_iterator;
auto process_entry = process_iterator.NextProcessEntry();
std::vector<mate::Dictionary> result;
while (process_entry != nullptr) {
int64_t pid = process_entry->pid();
auto process = base::Process::OpenWithExtraPrivileges(pid);
#if defined(OS_MACOSX)
std::unique_ptr<base::ProcessMetrics> metrics(
base::ProcessMetrics::CreateProcessMetrics(
process.Handle(), content::BrowserChildProcessHost::GetPortProvider()));
#else
std::unique_ptr<base::ProcessMetrics> metrics(
base::ProcessMetrics::CreateProcessMetrics(process.Handle()));
#endif
mate::Dictionary pid_dict = mate::Dictionary::CreateEmpty(isolate);
mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate);
memory_dict.Set("workingSetSize",
static_cast<double>(metrics->GetWorkingSetSize() >> 10));
memory_dict.Set("peakWorkingSetSize",
static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10));
size_t private_bytes, shared_bytes;
if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
memory_dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
memory_dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
}
pid_dict.Set("memory", memory_dict);
pid_dict.Set("pid", pid);
result.push_back(pid_dict);
process_entry = process_iterator.NextProcessEntry();
}
return result;
}
// static // static
mate::Handle<App> App::Create(v8::Isolate* isolate) { mate::Handle<App> App::Create(v8::Isolate* isolate) {
return mate::CreateHandle(isolate, new App(isolate)); return mate::CreateHandle(isolate, new App(isolate));
@ -896,6 +1019,8 @@ void App::BuildPrototype(
.SetMethod("isUnityRunning", .SetMethod("isUnityRunning",
base::Bind(&Browser::IsUnityRunning, browser)) base::Bind(&Browser::IsUnityRunning, browser))
#endif #endif
.SetMethod("setAppPath", &App::SetAppPath)
.SetMethod("getAppPath", &App::GetAppPath)
.SetMethod("setPath", &App::SetPath) .SetMethod("setPath", &App::SetPath)
.SetMethod("getPath", &App::GetPath) .SetMethod("getPath", &App::GetPath)
.SetMethod("setDesktopName", &App::SetDesktopName) .SetMethod("setDesktopName", &App::SetDesktopName)
@ -909,7 +1034,9 @@ void App::BuildPrototype(
.SetMethod("isAccessibilitySupportEnabled", .SetMethod("isAccessibilitySupportEnabled",
&App::IsAccessibilitySupportEnabled) &App::IsAccessibilitySupportEnabled)
.SetMethod("disableHardwareAcceleration", .SetMethod("disableHardwareAcceleration",
&App::DisableHardwareAcceleration); &App::DisableHardwareAcceleration)
.SetMethod("getFileIcon", &App::GetFileIcon)
.SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo);
} }
} // namespace api } // namespace api

View file

@ -13,8 +13,12 @@
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/browser_observer.h" #include "atom/browser/browser_observer.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "base/process/process_iterator.h"
#include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/icon_manager.h"
#include "chrome/browser/process_singleton.h" #include "chrome/browser/process_singleton.h"
#include "content/public/browser/gpu_data_manager_observer.h" #include "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/dictionary.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "net/base/completion_callback.h" #include "net/base/completion_callback.h"
@ -43,6 +47,9 @@ class App : public AtomBrowserClient::Delegate,
public BrowserObserver, public BrowserObserver,
public content::GpuDataManagerObserver { public content::GpuDataManagerObserver {
public: public:
using FileIconCallback = base::Callback<void(v8::Local<v8::Value>,
const gfx::Image&)>;
static mate::Handle<App> Create(v8::Isolate* isolate); static mate::Handle<App> Create(v8::Isolate* isolate);
static void BuildPrototype(v8::Isolate* isolate, static void BuildPrototype(v8::Isolate* isolate,
@ -65,6 +72,8 @@ class App : public AtomBrowserClient::Delegate,
std::unique_ptr<CertificateManagerModel> model); std::unique_ptr<CertificateManagerModel> model);
#endif #endif
base::FilePath GetAppPath() const;
protected: protected:
explicit App(v8::Isolate* isolate); explicit App(v8::Isolate* isolate);
~App() override; ~App() override;
@ -110,6 +119,8 @@ class App : public AtomBrowserClient::Delegate,
void OnGpuProcessCrashed(base::TerminationStatus status) override; void OnGpuProcessCrashed(base::TerminationStatus status) override;
private: private:
void SetAppPath(const base::FilePath& app_path);
// Get/Set the pre-defined path in PathService. // Get/Set the pre-defined path in PathService.
base::FilePath GetPath(mate::Arguments* args, const std::string& name); base::FilePath GetPath(mate::Arguments* args, const std::string& name);
void SetPath(mate::Arguments* args, void SetPath(mate::Arguments* args,
@ -129,6 +140,10 @@ class App : public AtomBrowserClient::Delegate,
void ImportCertificate(const base::DictionaryValue& options, void ImportCertificate(const base::DictionaryValue& options,
const net::CompletionCallback& callback); const net::CompletionCallback& callback);
#endif #endif
void GetFileIcon(const base::FilePath& path,
mate::Arguments* args);
std::vector<mate::Dictionary> GetAppMemoryInfo(v8::Isolate* isolate);
#if defined(OS_WIN) #if defined(OS_WIN)
// Get the current Jump List settings. // Get the current Jump List settings.
@ -144,6 +159,11 @@ class App : public AtomBrowserClient::Delegate,
std::unique_ptr<CertificateManagerModel> certificate_manager_model_; std::unique_ptr<CertificateManagerModel> certificate_manager_model_;
#endif #endif
// Tracks tasks requesting file icons.
base::CancelableTaskTracker cancelable_task_tracker_;
base::FilePath app_path_;
DISALLOW_COPY_AND_ASSIGN(App); DISALLOW_COPY_AND_ASSIGN(App);
}; };

View file

@ -7,6 +7,7 @@
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "atom/common/api/event_emitter_caller.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "base/time/time.h" #include "base/time/time.h"
@ -47,7 +48,9 @@ void AutoUpdater::OnError(const std::string& message) {
v8::Locker locker(isolate()); v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate()); v8::HandleScope handle_scope(isolate());
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message)); auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
EmitCustomEvent( mate::EmitEvent(
isolate(),
GetWrapper(),
"error", "error",
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(), error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
// Message is also emitted to keep compatibility with old code. // Message is also emitted to keep compatibility with old code.
@ -87,16 +90,14 @@ void AutoUpdater::SetFeedURL(const std::string& url, mate::Arguments* args) {
void AutoUpdater::QuitAndInstall() { void AutoUpdater::QuitAndInstall() {
// If we don't have any window then quitAndInstall immediately. // If we don't have any window then quitAndInstall immediately.
WindowList* window_list = WindowList::GetInstance(); if (WindowList::IsEmpty()) {
if (window_list->size() == 0) {
auto_updater::AutoUpdater::QuitAndInstall(); auto_updater::AutoUpdater::QuitAndInstall();
return; return;
} }
// Otherwise do the restart after all windows have been closed. // Otherwise do the restart after all windows have been closed.
window_list->AddObserver(this); WindowList::AddObserver(this);
for (NativeWindow* window : *window_list) WindowList::CloseAllWindows();
window->Close();
} }
// static // static

View file

@ -0,0 +1,162 @@
// Copyright (c) 2017 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_browser_view.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_browser_view.h"
#include "atom/common/color_util.h"
#include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/geometry/rect.h"
namespace mate {
template <>
struct Converter<atom::AutoResizeFlags> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
atom::AutoResizeFlags* auto_resize_flags) {
mate::Dictionary params;
if (!ConvertFromV8(isolate, val, &params)) {
return false;
}
uint8_t flags = 0;
bool width = false;
if (params.Get("width", &width) && width) {
flags |= atom::kAutoResizeWidth;
}
bool height = false;
if (params.Get("height", &height) && height) {
flags |= atom::kAutoResizeHeight;
}
*auto_resize_flags = static_cast<atom::AutoResizeFlags>(flags);
return true;
}
};
} // namespace mate
namespace atom {
namespace api {
BrowserView::BrowserView(v8::Isolate* isolate,
v8::Local<v8::Object> wrapper,
const mate::Dictionary& options)
: api_web_contents_(nullptr) {
Init(isolate, wrapper, options);
}
void BrowserView::Init(v8::Isolate* isolate,
v8::Local<v8::Object> wrapper,
const mate::Dictionary& options) {
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
options.Get(options::kWebPreferences, &web_preferences);
web_preferences.Set("isBrowserView", true);
mate::Handle<class WebContents> web_contents =
WebContents::Create(isolate, web_preferences);
web_contents_.Reset(isolate, web_contents.ToV8());
api_web_contents_ = web_contents.get();
view_.reset(NativeBrowserView::Create(
api_web_contents_->managed_web_contents()->GetView()));
InitWith(isolate, wrapper);
}
BrowserView::~BrowserView() {
api_web_contents_->DestroyWebContents(true /* async */);
}
// static
mate::WrappableBase* BrowserView::New(mate::Arguments* args) {
if (!Browser::Get()->is_ready()) {
args->ThrowError("Cannot create BrowserView before app is ready");
return nullptr;
}
if (args->Length() > 1) {
args->ThrowError("Too many arguments");
return nullptr;
}
mate::Dictionary options;
if (!(args->Length() == 1 && args->GetNext(&options))) {
options = mate::Dictionary::CreateEmpty(args->isolate());
}
return new BrowserView(args->isolate(), args->GetThis(), options);
}
int32_t BrowserView::ID() const {
return weak_map_id();
}
void BrowserView::SetAutoResize(AutoResizeFlags flags) {
view_->SetAutoResizeFlags(flags);
}
void BrowserView::SetBounds(const gfx::Rect& bounds) {
view_->SetBounds(bounds);
}
void BrowserView::SetBackgroundColor(const std::string& color_name) {
view_->SetBackgroundColor(ParseHexColor(color_name));
}
v8::Local<v8::Value> BrowserView::WebContents() {
if (web_contents_.IsEmpty()) {
return v8::Null(isolate());
}
return v8::Local<v8::Value>::New(isolate(), web_contents_);
}
// static
void BrowserView::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "BrowserView"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.MakeDestroyable()
.SetMethod("setAutoResize", &BrowserView::SetAutoResize)
.SetMethod("setBounds", &BrowserView::SetBounds)
.SetMethod("setBackgroundColor", &BrowserView::SetBackgroundColor)
.SetProperty("webContents", &BrowserView::WebContents)
.SetProperty("id", &BrowserView::ID);
}
} // namespace api
} // namespace atom
namespace {
using atom::api::BrowserView;
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
v8::Isolate* isolate = context->GetIsolate();
BrowserView::SetConstructor(isolate, base::Bind(&BrowserView::New));
mate::Dictionary browser_view(
isolate, BrowserView::GetConstructor(isolate)->GetFunction());
mate::Dictionary dict(isolate, exports);
dict.Set("BrowserView", browser_view);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_browser_view, Initialize)

View file

@ -0,0 +1,72 @@
// Copyright (c) 2017 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_BROWSER_VIEW_H_
#define ATOM_BROWSER_API_ATOM_API_BROWSER_VIEW_H_
#include <memory>
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/native_browser_view.h"
#include "native_mate/handle.h"
namespace gfx {
class Rect;
}
namespace mate {
class Arguments;
class Dictionary;
} // namespace mate
namespace atom {
class NativeBrowserView;
namespace api {
class WebContents;
class BrowserView : public mate::TrackableObject<BrowserView> {
public:
static mate::WrappableBase* New(mate::Arguments* args);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype);
NativeBrowserView* view() const { return view_.get(); }
int32_t ID() const;
protected:
BrowserView(v8::Isolate* isolate,
v8::Local<v8::Object> wrapper,
const mate::Dictionary& options);
~BrowserView() override;
private:
void Init(v8::Isolate* isolate,
v8::Local<v8::Object> wrapper,
const mate::Dictionary& options);
void SetAutoResize(AutoResizeFlags flags);
void SetBounds(const gfx::Rect& bounds);
void SetBackgroundColor(const std::string& color_name);
v8::Local<v8::Value> WebContents();
v8::Global<v8::Value> web_contents_;
class WebContents* api_web_contents_;
std::unique_ptr<NativeBrowserView> view_;
DISALLOW_COPY_AND_ASSIGN(BrowserView);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_BROWSER_VIEW_H_

View file

@ -179,6 +179,13 @@ void OnSetCookie(const Cookies::SetCallback& callback, bool success) {
base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED)); base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED));
} }
// Flushes cookie store in IO thread.
void FlushCookieStoreOnIOThread(
scoped_refptr<net::URLRequestContextGetter> getter,
const base::Closure& callback) {
GetCookieStore(getter)->FlushStore(base::Bind(RunCallbackInUI, callback));
}
// Sets cookie with |details| in IO thread. // Sets cookie with |details| in IO thread.
void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter, void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::unique_ptr<base::DictionaryValue> details, std::unique_ptr<base::DictionaryValue> details,
@ -265,6 +272,13 @@ void Cookies::Set(const base::DictionaryValue& details,
base::Bind(SetCookieOnIO, getter, Passed(&copied), callback)); base::Bind(SetCookieOnIO, getter, Passed(&copied), callback));
} }
void Cookies::FlushStore(const base::Closure& callback) {
auto getter = make_scoped_refptr(request_context_getter_);
content::BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(FlushCookieStoreOnIOThread, getter, callback));
}
void Cookies::OnCookieChanged(const net::CanonicalCookie& cookie, void Cookies::OnCookieChanged(const net::CanonicalCookie& cookie,
bool removed, bool removed,
net::CookieStore::ChangeCause cause) { net::CookieStore::ChangeCause cause) {
@ -286,7 +300,8 @@ void Cookies::BuildPrototype(v8::Isolate* isolate,
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetMethod("get", &Cookies::Get) .SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove) .SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set); .SetMethod("set", &Cookies::Set)
.SetMethod("flushStore", &Cookies::FlushStore);
} }
} // namespace api } // namespace api

View file

@ -53,6 +53,7 @@ class Cookies : public mate::TrackableObject<Cookies>,
void Remove(const GURL& url, const std::string& name, void Remove(const GURL& url, const std::string& name,
const base::Closure& callback); const base::Closure& callback);
void Set(const base::DictionaryValue& details, const SetCallback& callback); void Set(const base::DictionaryValue& details, const SetCallback& callback);
void FlushStore(const base::Closure& callback);
// AtomCookieDelegate::Observer: // AtomCookieDelegate::Observer:
void OnCookieChanged(const net::CanonicalCookie& cookie, void OnCookieChanged(const net::CanonicalCookie& cookie,

View file

@ -9,7 +9,6 @@
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
@ -45,12 +44,23 @@ void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host,
const std::string& message) { const std::string& message) {
DCHECK(agent_host == agent_host_.get()); DCHECK(agent_host == agent_host_.get());
std::unique_ptr<base::Value> parsed_message(base::JSONReader::Read(message)); v8::Locker locker(isolate());
if (!parsed_message->IsType(base::Value::TYPE_DICTIONARY)) v8::HandleScope handle_scope(isolate());
return;
v8::Local<v8::String> local_message =
v8::String::NewFromUtf8(isolate(), message.data());
v8::MaybeLocal<v8::Value> parsed_message = v8::JSON::Parse(
isolate()->GetCurrentContext(), local_message);
if (parsed_message.IsEmpty()) {
return;
}
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
if (!mate::ConvertFromV8(isolate(), parsed_message.ToLocalChecked(),
dict.get())) {
return;
}
base::DictionaryValue* dict =
static_cast<base::DictionaryValue*>(parsed_message.get());
int id; int id;
if (!dict->GetInteger("id", &id)) { if (!dict->GetInteger("id", &id)) {
std::string method; std::string method;

View file

@ -8,11 +8,13 @@
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/ui/certificate_trust.h"
#include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/file_dialog.h"
#include "atom/browser/ui/message_box.h" #include "atom/browser/ui/message_box.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
@ -35,6 +37,27 @@ struct Converter<file_dialog::Filter> {
} }
}; };
template<>
struct Converter<file_dialog::DialogSettings> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
file_dialog::DialogSettings* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("window", &(out->parent_window));
dict.Get("title", &(out->title));
dict.Get("message", &(out->message));
dict.Get("buttonLabel", &(out->button_label));
dict.Get("nameFieldLabel", &(out->name_field_label));
dict.Get("defaultPath", &(out->default_path));
dict.Get("filters", &(out->filters));
dict.Get("properties", &(out->properties));
dict.Get("showsTagField", &(out->shows_tag_field));
return true;
}
};
} // namespace mate } // namespace mate
namespace { namespace {
@ -47,6 +70,8 @@ void ShowMessageBox(int type,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
atom::NativeWindow* window, atom::NativeWindow* window,
mate::Arguments* args) { mate::Arguments* args) {
@ -55,56 +80,44 @@ void ShowMessageBox(int type,
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(), if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
peek, peek,
&callback)) { &callback)) {
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, atom::ShowMessageBox(window, static_cast<atom::MessageBoxType>(type),
default_id, cancel_id, options, title, buttons, default_id, cancel_id, options, title,
message, detail, icon, callback); message, detail, checkbox_label, checkbox_checked,
icon, callback);
} else { } else {
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, int chosen = atom::ShowMessageBox(
buttons, default_id, cancel_id, window, static_cast<atom::MessageBoxType>(type), buttons, default_id,
options, title, message, detail, icon); cancel_id, options, title, message, detail, icon);
args->Return(chosen); args->Return(chosen);
} }
} }
void ShowOpenDialog(const std::string& title, void ShowOpenDialog(const file_dialog::DialogSettings& settings,
const std::string& button_label,
const base::FilePath& default_path,
const file_dialog::Filters& filters,
int properties,
atom::NativeWindow* window,
mate::Arguments* args) { mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext(); v8::Local<v8::Value> peek = args->PeekNext();
file_dialog::OpenDialogCallback callback; file_dialog::OpenDialogCallback callback;
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(), if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(),
peek, peek,
&callback)) { &callback)) {
file_dialog::ShowOpenDialog(window, title, button_label, default_path, file_dialog::ShowOpenDialog(settings, callback);
filters, properties, callback);
} else { } else {
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
if (file_dialog::ShowOpenDialog(window, title, button_label, default_path, if (file_dialog::ShowOpenDialog(settings, &paths))
filters, properties, &paths))
args->Return(paths); args->Return(paths);
} }
} }
void ShowSaveDialog(const std::string& title, void ShowSaveDialog(const file_dialog::DialogSettings& settings,
const std::string& button_label,
const base::FilePath& default_path,
const file_dialog::Filters& filters,
atom::NativeWindow* window,
mate::Arguments* args) { mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext(); v8::Local<v8::Value> peek = args->PeekNext();
file_dialog::SaveDialogCallback callback; file_dialog::SaveDialogCallback callback;
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(), if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(),
peek, peek,
&callback)) { &callback)) {
file_dialog::ShowSaveDialog(window, title, button_label, default_path, file_dialog::ShowSaveDialog(settings, callback);
filters, callback);
} else { } else {
base::FilePath path; base::FilePath path;
if (file_dialog::ShowSaveDialog(window, title, button_label, default_path, if (file_dialog::ShowSaveDialog(settings, &path))
filters, &path))
args->Return(path); args->Return(path);
} }
} }
@ -116,6 +129,10 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
dict.SetMethod("showErrorBox", &atom::ShowErrorBox); dict.SetMethod("showErrorBox", &atom::ShowErrorBox);
dict.SetMethod("showOpenDialog", &ShowOpenDialog); dict.SetMethod("showOpenDialog", &ShowOpenDialog);
dict.SetMethod("showSaveDialog", &ShowSaveDialog); dict.SetMethod("showSaveDialog", &ShowSaveDialog);
#if defined(OS_MACOSX) || defined(OS_WIN)
dict.SetMethod("showCertificateTrustDialog",
&certificate_trust::ShowCertificateTrust);
#endif
} }
} // namespace } // namespace

View file

@ -78,7 +78,6 @@ DownloadItem::~DownloadItem() {
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) { void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
if (download_item_->IsDone()) { if (download_item_->IsDone()) {
Emit("done", item->GetState()); Emit("done", item->GetState());
// Destroy the item once item is downloaded. // Destroy the item once item is downloaded.
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, GetDestroyClosure()); FROM_HERE, GetDestroyClosure());
@ -111,7 +110,6 @@ bool DownloadItem::CanResume() const {
void DownloadItem::Cancel() { void DownloadItem::Cancel() {
download_item_->Cancel(true); download_item_->Cancel(true);
download_item_->Remove();
} }
int64_t DownloadItem::GetReceivedBytes() const { int64_t DownloadItem::GetReceivedBytes() const {

View file

@ -176,7 +176,8 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt) .SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
.SetMethod("isEnabledAt", &Menu::IsEnabledAt) .SetMethod("isEnabledAt", &Menu::IsEnabledAt)
.SetMethod("isVisibleAt", &Menu::IsVisibleAt) .SetMethod("isVisibleAt", &Menu::IsVisibleAt)
.SetMethod("popupAt", &Menu::PopupAt); .SetMethod("popupAt", &Menu::PopupAt)
.SetMethod("closePopupAt", &Menu::ClosePopupAt);
} }
} // namespace api } // namespace api

View file

@ -53,9 +53,9 @@ class Menu : public mate::TrackableObject<Menu>,
void ExecuteCommand(int command_id, int event_flags) override; void ExecuteCommand(int command_id, int event_flags) override;
void MenuWillShow(ui::SimpleMenuModel* source) override; void MenuWillShow(ui::SimpleMenuModel* source) override;
virtual void PopupAt(Window* window, virtual void PopupAt(
int x = -1, int y = -1, Window* window, int x, int y, int positioning_item, bool async) = 0;
int positioning_item = 0) = 0; virtual void ClosePopupAt(int32_t window_id) = 0;
std::unique_ptr<AtomMenuModel> model_; std::unique_ptr<AtomMenuModel> model_;
Menu* parent_; Menu* parent_;

View file

@ -7,10 +7,13 @@
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include <map>
#include <string> #include <string>
#import "atom/browser/ui/cocoa/atom_menu_controller.h" #import "atom/browser/ui/cocoa/atom_menu_controller.h"
using base::scoped_nsobject;
namespace atom { namespace atom {
namespace api { namespace api {
@ -19,15 +22,25 @@ class MenuMac : public Menu {
protected: protected:
MenuMac(v8::Isolate* isolate, v8::Local<v8::Object> wrapper); MenuMac(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
void PopupAt(Window* window, int x, int y, int positioning_item) override; void PopupAt(
Window* window, int x, int y, int positioning_item, bool async) override;
base::scoped_nsobject<AtomMenuController> menu_controller_; void PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
int32_t window_id, int x, int y, int positioning_item,
bool async);
void ClosePopupAt(int32_t window_id) override;
private: private:
friend class Menu; friend class Menu;
static void SendActionToFirstResponder(const std::string& action); static void SendActionToFirstResponder(const std::string& action);
scoped_nsobject<AtomMenuController> menu_controller_;
// window ID -> open context menu
std::map<int32_t, scoped_nsobject<AtomMenuController>> popup_controllers_;
base::WeakPtrFactory<MenuMac> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MenuMac); DISALLOW_COPY_AND_ASSIGN(MenuMac);
}; };

View file

@ -6,35 +6,58 @@
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/unresponsive_suppressor.h" #include "atom/browser/unresponsive_suppressor.h"
#include "base/mac/scoped_sending_event.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_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 "brightray/browser/inspectable_web_contents_view.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
using content::BrowserThread;
namespace atom { namespace atom {
namespace api { namespace api {
MenuMac::MenuMac(v8::Isolate* isolate, v8::Local<v8::Object> wrapper) MenuMac::MenuMac(v8::Isolate* isolate, v8::Local<v8::Object> wrapper)
: Menu(isolate, wrapper) { : Menu(isolate, wrapper),
weak_factory_(this) {
} }
void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) { void MenuMac::PopupAt(
Window* window, int x, int y, int positioning_item, bool async) {
NativeWindow* native_window = window->window(); NativeWindow* native_window = window->window();
if (!native_window) if (!native_window)
return; return;
auto popup = base::Bind(&MenuMac::PopupOnUI, weak_factory_.GetWeakPtr(),
native_window->GetWeakPtr(), window->ID(), x, y,
positioning_item, async);
if (async)
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, popup);
else
popup.Run();
}
void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
int32_t window_id, int x, int y, int positioning_item,
bool async) {
if (!native_window)
return;
brightray::InspectableWebContents* web_contents = brightray::InspectableWebContents* web_contents =
native_window->inspectable_web_contents(); native_window->inspectable_web_contents();
if (!web_contents) if (!web_contents)
return; return;
base::scoped_nsobject<AtomMenuController> menu_controller( auto close_callback = base::Bind(&MenuMac::ClosePopupAt,
[[AtomMenuController alloc] initWithModel:model_.get() weak_factory_.GetWeakPtr(), window_id);
popup_controllers_[window_id] = base::scoped_nsobject<AtomMenuController>(
[[AtomMenuController alloc] initWithModel:model()
useDefaultAccelerator:NO]); useDefaultAccelerator:NO]);
NSMenu* menu = [menu_controller menu]; NSMenu* menu = [popup_controllers_[window_id] menu];
NSView* view = web_contents->GetView()->GetNativeView(); NSView* view = web_contents->GetView()->GetNativeView();
// Which menu item to show. // Which menu item to show.
@ -69,11 +92,33 @@ void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) {
if (rightmostMenuPoint > screenRight) if (rightmostMenuPoint > screenRight)
position.x = position.x - [menu size].width; position.x = position.x - [menu size].width;
// Don't emit unresponsive event when showing menu.
atom::UnresponsiveSuppressor suppressor;
// Show the menu. if (async) {
[menu popUpMenuPositioningItem:item atLocation:position inView:view]; [popup_controllers_[window_id] setCloseCallback:close_callback];
// Make sure events can be pumped while the menu is up.
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
// One of the events that could be pumped is |window.close()|.
// User-initiated event-tracking loops protect against this by
// setting flags in -[CrApplication sendEvent:], but since
// web-content menus are initiated by IPC message the setup has to
// be done manually.
base::mac::ScopedSendingEvent sendingEventScoper;
// Don't emit unresponsive event when showing menu.
atom::UnresponsiveSuppressor suppressor;
[menu popUpMenuPositioningItem:item atLocation:position inView:view];
} else {
// Don't emit unresponsive event when showing menu.
atom::UnresponsiveSuppressor suppressor;
[menu popUpMenuPositioningItem:item atLocation:position inView:view];
close_callback.Run();
}
}
void MenuMac::ClosePopupAt(int32_t window_id) {
popup_controllers_.erase(window_id);
} }
// static // static

View file

@ -8,17 +8,20 @@
#include "atom/browser/unresponsive_suppressor.h" #include "atom/browser/unresponsive_suppressor.h"
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
#include "ui/views/controls/menu/menu_runner.h"
using views::MenuRunner;
namespace atom { namespace atom {
namespace api { namespace api {
MenuViews::MenuViews(v8::Isolate* isolate, v8::Local<v8::Object> wrapper) MenuViews::MenuViews(v8::Isolate* isolate, v8::Local<v8::Object> wrapper)
: Menu(isolate, wrapper) { : Menu(isolate, wrapper),
weak_factory_(this) {
} }
void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) { void MenuViews::PopupAt(
Window* window, int x, int y, int positioning_item, bool async) {
NativeWindow* native_window = static_cast<NativeWindow*>(window->window()); NativeWindow* native_window = static_cast<NativeWindow*>(window->window());
if (!native_window) if (!native_window)
return; return;
@ -38,14 +41,20 @@ void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) {
location = gfx::Point(origin.x() + x, origin.y() + y); location = gfx::Point(origin.x() + x, origin.y() + y);
} }
int flags = MenuRunner::CONTEXT_MENU | MenuRunner::HAS_MNEMONICS;
if (async)
flags |= MenuRunner::ASYNC;
// Don't emit unresponsive event when showing menu. // Don't emit unresponsive event when showing menu.
atom::UnresponsiveSuppressor suppressor; atom::UnresponsiveSuppressor suppressor;
// Show the menu. // Show the menu.
views::MenuRunner menu_runner( int32_t window_id = window->ID();
model(), auto close_callback = base::Bind(
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS); &MenuViews::ClosePopupAt, weak_factory_.GetWeakPtr(), window_id);
ignore_result(menu_runner.RunMenuAt( menu_runners_[window_id] = std::unique_ptr<MenuRunner>(new MenuRunner(
model(), flags, close_callback));
ignore_result(menu_runners_[window_id]->RunMenuAt(
static_cast<NativeWindowViews*>(window->window())->widget(), static_cast<NativeWindowViews*>(window->window())->widget(),
NULL, NULL,
gfx::Rect(location, gfx::Size()), gfx::Rect(location, gfx::Size()),
@ -53,6 +62,10 @@ void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) {
ui::MENU_SOURCE_MOUSE)); ui::MENU_SOURCE_MOUSE));
} }
void MenuViews::ClosePopupAt(int32_t window_id) {
menu_runners_.erase(window_id);
}
// static // static
mate::WrappableBase* Menu::New(mate::Arguments* args) { mate::WrappableBase* Menu::New(mate::Arguments* args) {
return new MenuViews(args->isolate(), args->GetThis()); return new MenuViews(args->isolate(), args->GetThis());

View file

@ -5,8 +5,12 @@
#ifndef ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_ #ifndef ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_ #define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
#include <map>
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include "base/memory/weak_ptr.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
#include "ui/views/controls/menu/menu_runner.h"
namespace atom { namespace atom {
@ -17,9 +21,16 @@ class MenuViews : public Menu {
MenuViews(v8::Isolate* isolate, v8::Local<v8::Object> wrapper); MenuViews(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
protected: protected:
void PopupAt(Window* window, int x, int y, int positioning_item) override; void PopupAt(
Window* window, int x, int y, int positioning_item, bool async) override;
void ClosePopupAt(int32_t window_id) override;
private: private:
// window ID -> open context menu
std::map<int32_t, std::unique_ptr<views::MenuRunner>> menu_runners_;
base::WeakPtrFactory<MenuViews> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MenuViews); DISALLOW_COPY_AND_ASSIGN(MenuViews);
}; };

View file

@ -204,6 +204,18 @@ struct Converter<net::ProxyConfig> {
} }
}; };
template<>
struct Converter<atom::VerifyRequestParams> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
atom::VerifyRequestParams val) {
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
dict.Set("hostname", val.hostname);
dict.Set("certificate", val.certificate);
dict.Set("verificationResult", val.default_result);
return dict.GetHandle();
}
};
} // namespace mate } // namespace mate
namespace atom { namespace atom {
@ -221,7 +233,7 @@ class ResolveProxyHelper {
public: public:
ResolveProxyHelper(AtomBrowserContext* browser_context, ResolveProxyHelper(AtomBrowserContext* browser_context,
const GURL& url, const GURL& url,
Session::ResolveProxyCallback callback) const Session::ResolveProxyCallback& callback)
: callback_(callback), : callback_(callback),
original_thread_(base::ThreadTaskRunnerHandle::Get()) { original_thread_(base::ThreadTaskRunnerHandle::Get()) {
scoped_refptr<net::URLRequestContextGetter> context_getter = scoped_refptr<net::URLRequestContextGetter> context_getter =
@ -738,7 +750,7 @@ void Session::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setDownloadPath", &Session::SetDownloadPath) .SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation) .SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation) .SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc) .SetMethod("_setCertificateVerifyProc", &Session::SetCertVerifyProc)
.SetMethod("setPermissionRequestHandler", .SetMethod("setPermissionRequestHandler",
&Session::SetPermissionRequestHandler) &Session::SetPermissionRequestHandler)
.SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache) .SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)

View file

@ -8,6 +8,7 @@
#include "atom/browser/net/atom_url_request.h" #include "atom/browser/net/atom_url_request.h"
#include "atom/common/api/event_emitter_caller.h" #include "atom/common/api/event_emitter_caller.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
@ -145,6 +146,8 @@ mate::WrappableBase* URLRequest::New(mate::Arguments* args) {
dict.Get("method", &method); dict.Get("method", &method);
std::string url; std::string url;
dict.Get("url", &url); dict.Get("url", &url);
std::string redirect_policy;
dict.Get("redirect", &redirect_policy);
std::string partition; std::string partition;
mate::Handle<api::Session> session; mate::Handle<api::Session> session;
if (dict.Get("session", &session)) { if (dict.Get("session", &session)) {
@ -156,8 +159,8 @@ mate::WrappableBase* URLRequest::New(mate::Arguments* args) {
} }
auto browser_context = session->browser_context(); auto browser_context = session->browser_context();
auto api_url_request = new URLRequest(args->isolate(), args->GetThis()); auto api_url_request = new URLRequest(args->isolate(), args->GetThis());
auto atom_url_request = auto atom_url_request = AtomURLRequest::Create(
AtomURLRequest::Create(browser_context, method, url, api_url_request); browser_context, method, url, redirect_policy, api_url_request);
api_url_request->atom_request_ = atom_url_request; api_url_request->atom_request_ = atom_url_request;
@ -176,6 +179,7 @@ void URLRequest::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setExtraHeader", &URLRequest::SetExtraHeader) .SetMethod("setExtraHeader", &URLRequest::SetExtraHeader)
.SetMethod("removeExtraHeader", &URLRequest::RemoveExtraHeader) .SetMethod("removeExtraHeader", &URLRequest::RemoveExtraHeader)
.SetMethod("setChunkedUpload", &URLRequest::SetChunkedUpload) .SetMethod("setChunkedUpload", &URLRequest::SetChunkedUpload)
.SetMethod("followRedirect", &URLRequest::FollowRedirect)
.SetMethod("_setLoadFlags", &URLRequest::SetLoadFlags) .SetMethod("_setLoadFlags", &URLRequest::SetLoadFlags)
.SetProperty("notStarted", &URLRequest::NotStarted) .SetProperty("notStarted", &URLRequest::NotStarted)
.SetProperty("finished", &URLRequest::Finished) .SetProperty("finished", &URLRequest::Finished)
@ -246,6 +250,17 @@ void URLRequest::Cancel() {
Close(); Close();
} }
void URLRequest::FollowRedirect() {
if (request_state_.Canceled() || request_state_.Closed()) {
return;
}
DCHECK(atom_request_);
if (atom_request_) {
atom_request_->FollowRedirect();
}
}
bool URLRequest::SetExtraHeader(const std::string& name, bool URLRequest::SetExtraHeader(const std::string& name,
const std::string& value) { const std::string& value) {
// Request state must be in the initial non started state. // Request state must be in the initial non started state.
@ -305,6 +320,24 @@ void URLRequest::SetLoadFlags(int flags) {
} }
} }
void URLRequest::OnReceivedRedirect(
int status_code,
const std::string& method,
const GURL& url,
scoped_refptr<net::HttpResponseHeaders> response_headers) {
if (request_state_.Canceled() || request_state_.Closed()) {
return;
}
DCHECK(atom_request_);
if (!atom_request_) {
return;
}
EmitRequestEvent(false, "redirect", status_code, method, url,
response_headers.get());
}
void URLRequest::OnAuthenticationRequired( void URLRequest::OnAuthenticationRequired(
scoped_refptr<const net::AuthChallengeInfo> auth_info) { scoped_refptr<const net::AuthChallengeInfo> auth_info) {
if (request_state_.Canceled() || request_state_.Closed()) { if (request_state_.Canceled() || request_state_.Closed()) {

View file

@ -99,6 +99,11 @@ class URLRequest : public mate::EventEmitter<URLRequest> {
v8::Local<v8::FunctionTemplate> prototype); v8::Local<v8::FunctionTemplate> prototype);
// Methods for reporting events into JavaScript. // Methods for reporting events into JavaScript.
void OnReceivedRedirect(
int status_code,
const std::string& method,
const GURL& url,
scoped_refptr<net::HttpResponseHeaders> response_headers);
void OnAuthenticationRequired( void OnAuthenticationRequired(
scoped_refptr<const net::AuthChallengeInfo> auth_info); scoped_refptr<const net::AuthChallengeInfo> auth_info);
void OnResponseStarted( void OnResponseStarted(
@ -170,6 +175,7 @@ class URLRequest : public mate::EventEmitter<URLRequest> {
bool Failed() const; bool Failed() const;
bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last); bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last);
void Cancel(); void Cancel();
void FollowRedirect();
bool SetExtraHeader(const std::string& name, const std::string& value); bool SetExtraHeader(const std::string& name, const std::string& value);
void RemoveExtraHeader(const std::string& name); void RemoveExtraHeader(const std::string& name);
void SetChunkedUpload(bool is_chunked_upload); void SetChunkedUpload(bool is_chunked_upload);

View file

@ -22,6 +22,7 @@
#include "atom/browser/ui/drag_util.h" #include "atom/browser/ui/drag_util.h"
#include "atom/browser/web_contents_permission_helper.h" #include "atom/browser/web_contents_permission_helper.h"
#include "atom/browser/web_contents_preferences.h" #include "atom/browser/web_contents_preferences.h"
#include "atom/browser/web_contents_zoom_controller.h"
#include "atom/browser/web_view_guest_delegate.h" #include "atom/browser/web_view_guest_delegate.h"
#include "atom/common/api/api_messages.h" #include "atom/common/api/api_messages.h"
#include "atom/common/api/event_emitter_caller.h" #include "atom/common/api/event_emitter_caller.h"
@ -46,6 +47,7 @@
#include "chrome/browser/printing/print_preview_message_handler.h" #include "chrome/browser/printing/print_preview_message_handler.h"
#include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/browser/ssl/security_state_tab_helper.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
@ -54,6 +56,9 @@
#include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_handle.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/plugin_service.h" #include "content/public/browser/plugin_service.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
@ -201,6 +206,7 @@ struct Converter<atom::api::WebContents::Type> {
switch (val) { switch (val) {
case Type::BACKGROUND_PAGE: type = "backgroundPage"; break; case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
case Type::BROWSER_WINDOW: type = "window"; break; case Type::BROWSER_WINDOW: type = "window"; break;
case Type::BROWSER_VIEW: type = "browserView"; break;
case Type::REMOTE: type = "remote"; break; case Type::REMOTE: type = "remote"; break;
case Type::WEB_VIEW: type = "webview"; break; case Type::WEB_VIEW: type = "webview"; break;
case Type::OFF_SCREEN: type = "offscreen"; break; case Type::OFF_SCREEN: type = "offscreen"; break;
@ -215,10 +221,12 @@ struct Converter<atom::api::WebContents::Type> {
std::string type; std::string type;
if (!ConvertFromV8(isolate, val, &type)) if (!ConvertFromV8(isolate, val, &type))
return false; return false;
if (type == "webview") { if (type == "backgroundPage") {
*out = Type::WEB_VIEW;
} else if (type == "backgroundPage") {
*out = Type::BACKGROUND_PAGE; *out = Type::BACKGROUND_PAGE;
} else if (type == "browserView") {
*out = Type::BROWSER_VIEW;
} else if (type == "webview") {
*out = Type::WEB_VIEW;
} else if (type == "offscreen") { } else if (type == "offscreen") {
*out = Type::OFF_SCREEN; *out = Type::OFF_SCREEN;
} else { } else {
@ -253,12 +261,28 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
} }
// Called when CapturePage is done. // Called when CapturePage is done.
void OnCapturePageDone(base::Callback<void(const gfx::Image&)> callback, void OnCapturePageDone(const base::Callback<void(const gfx::Image&)>& callback,
const SkBitmap& bitmap, const SkBitmap& bitmap,
content::ReadbackResponse response) { content::ReadbackResponse response) {
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap)); callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
} }
// Set the background color of RenderWidgetHostView.
void SetBackgroundColor(content::WebContents* web_contents) {
const auto view = web_contents->GetRenderWidgetHostView();
if (view) {
WebContentsPreferences* web_preferences =
WebContentsPreferences::FromWebContents(web_contents);
std::string color_name;
if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
&color_name)) {
view->SetBackgroundColor(ParseHexColor(color_name));
} else {
view->SetBackgroundColor(SK_ColorTRANSPARENT);
}
}
}
} // namespace } // namespace
WebContents::WebContents(v8::Isolate* isolate, WebContents::WebContents(v8::Isolate* isolate,
@ -266,11 +290,11 @@ WebContents::WebContents(v8::Isolate* isolate,
Type type) Type type)
: content::WebContentsObserver(web_contents), : content::WebContentsObserver(web_contents),
embedder_(nullptr), embedder_(nullptr),
zoom_controller_(nullptr),
type_(type), type_(type),
request_id_(0), request_id_(0),
background_throttling_(true), background_throttling_(true),
enable_devtools_(true) { enable_devtools_(true) {
if (type == REMOTE) { if (type == REMOTE) {
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
Init(isolate); Init(isolate);
@ -283,9 +307,9 @@ WebContents::WebContents(v8::Isolate* isolate,
} }
} }
WebContents::WebContents(v8::Isolate* isolate, WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
const mate::Dictionary& options)
: embedder_(nullptr), : embedder_(nullptr),
zoom_controller_(nullptr),
type_(BROWSER_WINDOW), type_(BROWSER_WINDOW),
request_id_(0), request_id_(0),
background_throttling_(true), background_throttling_(true),
@ -303,6 +327,8 @@ WebContents::WebContents(v8::Isolate* isolate,
type_ = WEB_VIEW; type_ = WEB_VIEW;
else if (options.Get("isBackgroundPage", &b) && b) else if (options.Get("isBackgroundPage", &b) && b)
type_ = BACKGROUND_PAGE; type_ = BACKGROUND_PAGE;
else if (options.Get("isBrowserView", &b) && b)
type_ = BROWSER_VIEW;
else if (options.Get("offscreen", &b) && b) else if (options.Get("offscreen", &b) && b)
type_ = OFF_SCREEN; type_ = OFF_SCREEN;
@ -355,7 +381,7 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
content::WebContents *web_contents, content::WebContents *web_contents,
mate::Handle<api::Session> session, mate::Handle<api::Session> session,
const mate::Dictionary& options) { const mate::Dictionary& options) {
Observe(web_contents); content::WebContentsObserver::Observe(web_contents);
InitWithWebContents(web_contents, session->browser_context()); InitWithWebContents(web_contents, session->browser_context());
managed_web_contents()->GetView()->SetDelegate(this); managed_web_contents()->GetView()->SetDelegate(this);
@ -363,10 +389,16 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
// Save the preferences in C++. // Save the preferences in C++.
new WebContentsPreferences(web_contents, options); new WebContentsPreferences(web_contents, options);
// Intialize permission helper. // Initialize permission helper.
WebContentsPermissionHelper::CreateForWebContents(web_contents); WebContentsPermissionHelper::CreateForWebContents(web_contents);
// Intialize security state client. // Initialize security state client.
SecurityStateTabHelper::CreateForWebContents(web_contents); SecurityStateTabHelper::CreateForWebContents(web_contents);
// Initialize zoom controller.
WebContentsZoomController::CreateForWebContents(web_contents);
zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents);
double zoom_factor;
if (options.Get(options::kZoomFactor, &zoom_factor))
zoom_controller_->SetDefaultZoomFactor(zoom_factor);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
@ -385,6 +417,11 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
SetOwnerWindow(owner_window); SetOwnerWindow(owner_window);
} }
const content::NavigationController* controller =
&web_contents->GetController();
registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
content::Source<content::NavigationController>(controller));
Init(isolate); Init(isolate);
AttachAsUserData(web_contents); AttachAsUserData(web_contents);
} }
@ -397,14 +434,31 @@ WebContents::~WebContents() {
if (type_ == WEB_VIEW) if (type_ == WEB_VIEW)
guest_delegate_->Destroy(); guest_delegate_->Destroy();
// The WebContentsDestroyed will not be called automatically because we
// unsubscribe from webContents before destroying it. So we have to manually
// call it here to make sure "destroyed" event is emitted.
RenderViewDeleted(web_contents()->GetRenderViewHost()); RenderViewDeleted(web_contents()->GetRenderViewHost());
WebContentsDestroyed();
if (type_ == WEB_VIEW) {
DestroyWebContents(false /* async */);
} else {
if (type_ == BROWSER_WINDOW && owner_window()) {
owner_window()->CloseContents(nullptr);
} else {
DestroyWebContents(true /* async */);
}
// The WebContentsDestroyed will not be called automatically because we
// destroy the webContents in the next tick. So we have to manually
// call it here to make sure "destroyed" event is emitted.
WebContentsDestroyed();
}
} }
} }
void WebContents::DestroyWebContents(bool async) {
// This event is only for internal use, which is emitted when WebContents is
// being destroyed.
Emit("will-destroy");
ResetManagedWebContents(async);
}
bool WebContents::DidAddMessageToConsole(content::WebContents* source, bool WebContents::DidAddMessageToConsole(content::WebContents* source,
int32_t level, int32_t level,
const base::string16& message, const base::string16& message,
@ -454,7 +508,7 @@ void WebContents::AddNewContents(content::WebContents* source,
if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture, if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
initial_rect.x(), initial_rect.y(), initial_rect.width(), initial_rect.x(), initial_rect.y(), initial_rect.width(),
initial_rect.height())) { initial_rect.height())) {
api_web_contents->DestroyWebContents(); api_web_contents->DestroyWebContents(true /* async */);
} }
} }
@ -744,6 +798,30 @@ void WebContents::DidGetRedirectForResourceRequest(
details.headers.get()); details.headers.get());
} }
void WebContents::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() || navigation_handle->IsSamePage())
return;
if (deferred_load_url_.id) {
auto web_contents = navigation_handle->GetWebContents();
auto& controller = web_contents->GetController();
int id = controller.GetPendingEntry()->GetUniqueID();
if (id == deferred_load_url_.id) {
if (!deferred_load_url_.params.url.is_empty()) {
auto params = deferred_load_url_.params;
deferred_load_url_.id = 0;
deferred_load_url_.params =
content::NavigationController::LoadURLParams(GURL());
controller.LoadURLWithParams(params);
SetBackgroundColor(web_contents);
} else {
deferred_load_url_.id = 0;
}
}
}
}
void WebContents::DidFinishNavigation( void WebContents::DidFinishNavigation(
content::NavigationHandle* navigation_handle) { content::NavigationHandle* navigation_handle) {
bool is_main_frame = navigation_handle->IsInMainFrame(); bool is_main_frame = navigation_handle->IsInMainFrame();
@ -769,10 +847,8 @@ void WebContents::DidFinishNavigation(
void WebContents::TitleWasSet(content::NavigationEntry* entry, void WebContents::TitleWasSet(content::NavigationEntry* entry,
bool explicit_set) { bool explicit_set) {
if (entry) auto title = entry ? entry->GetTitle() : base::string16();
Emit("-page-title-updated", entry->GetTitle(), explicit_set); Emit("page-title-updated", title, explicit_set);
else
Emit("-page-title-updated", "", explicit_set);
} }
void WebContents::DidUpdateFaviconURL( void WebContents::DidUpdateFaviconURL(
@ -788,6 +864,32 @@ void WebContents::DidUpdateFaviconURL(
Emit("page-favicon-updated", unique_urls); Emit("page-favicon-updated", unique_urls);
} }
void WebContents::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_NAV_ENTRY_PENDING: {
content::NavigationEntry* entry =
content::Details<content::NavigationEntry>(details).ptr();
content::NavigationEntryImpl* entry_impl =
static_cast<content::NavigationEntryImpl*>(entry);
// In NavigatorImpl::DidStartMainFrameNavigation when there is no
// browser side pending entry available it creates a new one based
// on existing pending entry, hence we track the unique id here
// instead in WebContents::LoadURL with controller.GetPendingEntry()
// TODO(deepak1556): Remove once we have
// https://codereview.chromium.org/2661743002.
if (entry_impl->frame_tree_node_id() == -1) {
deferred_load_url_.id = entry->GetUniqueID();
}
break;
}
default:
NOTREACHED();
break;
}
}
void WebContents::DevToolsReloadPage() { void WebContents::DevToolsReloadPage() {
Emit("devtools-reload-page"); Emit("devtools-reload-page");
} }
@ -830,6 +932,10 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage) IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync, IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync) OnRendererMessageSync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_SetTemporaryZoomLevel,
OnSetTemporaryZoomLevel)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_GetZoomLevel,
OnGetZoomLevel)
IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange, IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
handled = false) handled = false)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
@ -851,10 +957,6 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
// be destroyed on close, and WebContentsDestroyed would be called for it, so // be destroyed on close, and WebContentsDestroyed would be called for it, so
// we need to make sure the api::WebContents is also deleted. // we need to make sure the api::WebContents is also deleted.
void WebContents::WebContentsDestroyed() { void WebContents::WebContentsDestroyed() {
// This event is only for internal use, which is emitted when WebContents is
// being destroyed.
Emit("will-destroy");
// Cleanup relationships with other parts. // Cleanup relationships with other parts.
RemoveFromWeakMap(); RemoveFromWeakMap();
@ -925,26 +1027,25 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST; params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
} }
GURL base_url_for_data_url;
if (options.Get("baseURLForDataURL", &base_url_for_data_url)) {
params.base_url_for_data_url = base_url_for_data_url;
params.load_type = content::NavigationController::LOAD_TYPE_DATA;
}
params.transition_type = ui::PAGE_TRANSITION_TYPED; params.transition_type = ui::PAGE_TRANSITION_TYPED;
params.should_clear_history_list = true; params.should_clear_history_list = true;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
web_contents()->GetController().LoadURLWithParams(params);
// Set the background color of RenderWidgetHostView. if (deferred_load_url_.id) {
deferred_load_url_.params = params;
return;
}
web_contents()->GetController().LoadURLWithParams(params);
// We have to call it right after LoadURL because the RenderViewHost is only // We have to call it right after LoadURL because the RenderViewHost is only
// created after loading a page. // created after loading a page.
const auto view = web_contents()->GetRenderWidgetHostView(); SetBackgroundColor(web_contents());
if (view) {
WebContentsPreferences* web_preferences =
WebContentsPreferences::FromWebContents(web_contents());
std::string color_name;
if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
&color_name)) {
view->SetBackgroundColor(ParseHexColor(color_name));
} else {
view->SetBackgroundColor(SK_ColorTRANSPARENT);
}
}
} }
void WebContents::DownloadURL(const GURL& url) { void WebContents::DownloadURL(const GURL& url) {
@ -1000,6 +1101,23 @@ void WebContents::GoToOffset(int offset) {
web_contents()->GetController().GoToOffset(offset); web_contents()->GetController().GoToOffset(offset);
} }
const std::string WebContents::GetWebRTCIPHandlingPolicy() const {
return web_contents()->
GetMutableRendererPrefs()->webrtc_ip_handling_policy;
}
void WebContents::SetWebRTCIPHandlingPolicy(
const std::string& webrtc_ip_handling_policy) {
if (GetWebRTCIPHandlingPolicy() == webrtc_ip_handling_policy)
return;
web_contents()->GetMutableRendererPrefs()->webrtc_ip_handling_policy =
webrtc_ip_handling_policy;
content::RenderViewHost* host = web_contents()->GetRenderViewHost();
if (host)
host->SyncRendererPrefs();
}
bool WebContents::IsCrashed() const { bool WebContents::IsCrashed() const {
return web_contents()->IsCrashed(); return web_contents()->IsCrashed();
} }
@ -1517,13 +1635,47 @@ int WebContents::GetFrameRate() const {
} }
void WebContents::Invalidate() { void WebContents::Invalidate() {
if (!IsOffScreen()) if (IsOffScreen()) {
return; auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
web_contents()->GetRenderWidgetHostView()); web_contents()->GetRenderWidgetHostView());
if (osr_rwhv) if (osr_rwhv)
osr_rwhv->Invalidate(); osr_rwhv->Invalidate();
} else {
const auto window = owner_window();
if (window)
window->Invalidate();
}
}
void WebContents::SetZoomLevel(double level) {
zoom_controller_->SetZoomLevel(level);
}
double WebContents::GetZoomLevel() {
return zoom_controller_->GetZoomLevel();
}
void WebContents::SetZoomFactor(double factor) {
auto level = content::ZoomFactorToZoomLevel(factor);
SetZoomLevel(level);
}
double WebContents::GetZoomFactor() {
auto level = GetZoomLevel();
return content::ZoomLevelToZoomFactor(level);
}
void WebContents::OnSetTemporaryZoomLevel(double level,
IPC::Message* reply_msg) {
zoom_controller_->SetTemporaryZoomLevel(level);
double new_level = zoom_controller_->GetZoomLevel();
AtomViewHostMsg_SetTemporaryZoomLevel::WriteReplyParams(reply_msg, new_level);
Send(reply_msg);
}
void WebContents::OnGetZoomLevel(IPC::Message* reply_msg) {
AtomViewHostMsg_GetZoomLevel::WriteReplyParams(reply_msg, GetZoomLevel());
Send(reply_msg);
} }
v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) { v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
@ -1654,6 +1806,10 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setFrameRate", &WebContents::SetFrameRate) .SetMethod("setFrameRate", &WebContents::SetFrameRate)
.SetMethod("getFrameRate", &WebContents::GetFrameRate) .SetMethod("getFrameRate", &WebContents::GetFrameRate)
.SetMethod("invalidate", &WebContents::Invalidate) .SetMethod("invalidate", &WebContents::Invalidate)
.SetMethod("setZoomLevel", &WebContents::SetZoomLevel)
.SetMethod("_getZoomLevel", &WebContents::GetZoomLevel)
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
.SetMethod("_getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("getType", &WebContents::GetType) .SetMethod("getType", &WebContents::GetType)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences) .SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow) .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
@ -1671,6 +1827,10 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("copyImageAt", &WebContents::CopyImageAt) .SetMethod("copyImageAt", &WebContents::CopyImageAt)
.SetMethod("capturePage", &WebContents::CapturePage) .SetMethod("capturePage", &WebContents::CapturePage)
.SetMethod("setEmbedder", &WebContents::SetEmbedder) .SetMethod("setEmbedder", &WebContents::SetEmbedder)
.SetMethod("setWebRTCIPHandlingPolicy",
&WebContents::SetWebRTCIPHandlingPolicy)
.SetMethod("getWebRTCIPHandlingPolicy",
&WebContents::GetWebRTCIPHandlingPolicy)
.SetProperty("id", &WebContents::ID) .SetProperty("id", &WebContents::ID)
.SetProperty("session", &WebContents::Session) .SetProperty("session", &WebContents::Session)
.SetProperty("hostWebContents", &WebContents::HostWebContents) .SetProperty("hostWebContents", &WebContents::HostWebContents)

View file

@ -13,6 +13,8 @@
#include "atom/browser/api/trackable_object.h" #include "atom/browser/api/trackable_object.h"
#include "atom/browser/common_web_contents_delegate.h" #include "atom/browser/common_web_contents_delegate.h"
#include "content/common/cursors/webcursor.h" #include "content/common/cursors/webcursor.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/common/favicon_url.h" #include "content/public/common/favicon_url.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
@ -40,20 +42,23 @@ namespace atom {
struct SetSizeParams; struct SetSizeParams;
class AtomBrowserContext; class AtomBrowserContext;
class WebContentsZoomController;
class WebViewGuestDelegate; class WebViewGuestDelegate;
namespace api { namespace api {
class WebContents : public mate::TrackableObject<WebContents>, class WebContents : public mate::TrackableObject<WebContents>,
public CommonWebContentsDelegate, public CommonWebContentsDelegate,
public content::WebContentsObserver { public content::WebContentsObserver,
public content::NotificationObserver {
public: public:
enum Type { enum Type {
BACKGROUND_PAGE, // A DevTools extension background page. BACKGROUND_PAGE, // A DevTools extension background page.
BROWSER_WINDOW, // Used by BrowserWindow. BROWSER_WINDOW, // Used by BrowserWindow.
REMOTE, // Thin wrap around an existing WebContents. BROWSER_VIEW, // Used by BrowserView.
WEB_VIEW, // Used by <webview>. REMOTE, // Thin wrap around an existing WebContents.
OFF_SCREEN, // Used for offscreen rendering WEB_VIEW, // Used by <webview>.
OFF_SCREEN, // Used for offscreen rendering
}; };
// For node.js callback function type: function(error, buffer) // For node.js callback function type: function(error, buffer)
@ -73,6 +78,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
static void BuildPrototype(v8::Isolate* isolate, static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype); v8::Local<v8::FunctionTemplate> prototype);
// Notifies to destroy any guest web contents before destroying self.
void DestroyWebContents(bool async);
int64_t GetID() const; int64_t GetID() const;
int GetProcessID() const; int GetProcessID() const;
Type GetType() const; Type GetType() const;
@ -89,6 +97,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
void GoBack(); void GoBack();
void GoForward(); void GoForward();
void GoToOffset(int offset); void GoToOffset(int offset);
const std::string GetWebRTCIPHandlingPolicy() const;
void SetWebRTCIPHandlingPolicy(const std::string& webrtc_ip_handling_policy);
bool IsCrashed() const; bool IsCrashed() const;
void SetUserAgent(const std::string& user_agent, mate::Arguments* args); void SetUserAgent(const std::string& user_agent, mate::Arguments* args);
std::string GetUserAgent(); std::string GetUserAgent();
@ -176,6 +186,12 @@ class WebContents : public mate::TrackableObject<WebContents>,
int GetFrameRate() const; int GetFrameRate() const;
void Invalidate(); void Invalidate();
// Methods for zoom handling.
void SetZoomLevel(double level);
double GetZoomLevel();
void SetZoomFactor(double factor);
double GetZoomFactor();
// Callback triggered on permission response. // Callback triggered on permission response.
void OnEnterFullscreenModeForTab(content::WebContents* source, void OnEnterFullscreenModeForTab(content::WebContents* source,
const GURL& origin, const GURL& origin,
@ -202,6 +218,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate); v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
v8::Local<v8::Value> Debugger(v8::Isolate* isolate); v8::Local<v8::Value> Debugger(v8::Isolate* isolate);
WebContentsZoomController* GetZoomController() { return zoom_controller_; }
protected: protected:
WebContents(v8::Isolate* isolate, WebContents(v8::Isolate* isolate,
content::WebContents* web_contents, content::WebContents* web_contents,
@ -301,6 +319,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
const content::ResourceRequestDetails& details) override; const content::ResourceRequestDetails& details) override;
void DidGetRedirectForResourceRequest( void DidGetRedirectForResourceRequest(
const content::ResourceRedirectDetails& details) override; const content::ResourceRedirectDetails& details) override;
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation( void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override; content::NavigationHandle* navigation_handle) override;
bool OnMessageReceived(const IPC::Message& message) override; bool OnMessageReceived(const IPC::Message& message) override;
@ -318,6 +338,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
const MediaPlayerId& id) override; const MediaPlayerId& id) override;
void DidChangeThemeColor(SkColor theme_color) override; void DidChangeThemeColor(SkColor theme_color) override;
// content::NotificationObserver:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
// brightray::InspectableWebContentsDelegate: // brightray::InspectableWebContentsDelegate:
void DevToolsReloadPage() override; void DevToolsReloadPage() override;
@ -327,6 +352,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
void DevToolsClosed() override; void DevToolsClosed() override;
private: private:
struct LoadURLParams {
LoadURLParams() : params(GURL()), id(0) {}
content::NavigationController::LoadURLParams params;
int id;
};
AtomBrowserContext* GetBrowserContext() const; AtomBrowserContext* GetBrowserContext() const;
uint32_t GetNextRequestId() { uint32_t GetNextRequestId() {
@ -345,6 +377,14 @@ class WebContents : public mate::TrackableObject<WebContents>,
const base::ListValue& args, const base::ListValue& args,
IPC::Message* message); IPC::Message* message);
// Called when received a synchronous message from renderer to
// set temporary zoom level.
void OnSetTemporaryZoomLevel(double level, IPC::Message* reply_msg);
// Called when received a synchronous message from renderer to
// get the zoom level.
void OnGetZoomLevel(IPC::Message* reply_msg);
v8::Global<v8::Value> session_; v8::Global<v8::Value> session_;
v8::Global<v8::Value> devtools_web_contents_; v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> debugger_; v8::Global<v8::Value> debugger_;
@ -354,6 +394,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
// The host webcontents that may contain this webcontents. // The host webcontents that may contain this webcontents.
WebContents* embedder_; WebContents* embedder_;
// The zoom controller for this webContents.
WebContentsZoomController* zoom_controller_;
// The type of current WebContents. // The type of current WebContents.
Type type_; Type type_;
@ -366,6 +409,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
// Whether to enable devtools. // Whether to enable devtools.
bool enable_devtools_; bool enable_devtools_;
// Container to hold url parms for deferred load when
// there is a pending navigation entry.
LoadURLParams deferred_load_url_;
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(WebContents); DISALLOW_COPY_AND_ASSIGN(WebContents);
}; };

View file

@ -3,10 +3,12 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "atom/browser/web_contents_preferences.h" #include "atom/browser/web_contents_preferences.h"
#include "atom/browser/web_contents_zoom_controller.h"
#include "atom/browser/web_view_manager.h" #include "atom/browser/web_view_manager.h"
#include "atom/common/native_mate_converters/content_converter.h" #include "atom/common/native_mate_converters/content_converter.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
@ -24,6 +26,12 @@ void AddGuest(int guest_instance_id,
manager->AddGuest(guest_instance_id, element_instance_id, embedder, manager->AddGuest(guest_instance_id, element_instance_id, embedder,
guest_web_contents); guest_web_contents);
double zoom_factor;
if (options.GetDouble(atom::options::kZoomFactor, &zoom_factor)) {
atom::WebContentsZoomController::FromWebContents(guest_web_contents)
->SetDefaultZoomFactor(zoom_factor);
}
WebContentsPreferences::FromWebContents(guest_web_contents)->Merge(options); WebContentsPreferences::FromWebContents(guest_web_contents)->Merge(options);
} }

View file

@ -5,6 +5,7 @@
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "atom/browser/api/atom_api_browser_view.h"
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
@ -172,7 +173,7 @@ void Window::WillDestroyNativeObject() {
} }
void Window::OnWindowClosed() { void Window::OnWindowClosed() {
api_web_contents_->DestroyWebContents(); api_web_contents_->DestroyWebContents(true /* async */);
RemoveFromWeakMap(); RemoveFromWeakMap();
window_->RemoveObserver(this); window_->RemoveObserver(this);
@ -190,6 +191,10 @@ void Window::OnWindowClosed() {
FROM_HERE, GetDestroyClosure()); FROM_HERE, GetDestroyClosure());
} }
void Window::OnWindowEndSession() {
Emit("session-end");
}
void Window::OnWindowBlur() { void Window::OnWindowBlur() {
Emit("blur"); Emit("blur");
} }
@ -262,6 +267,14 @@ void Window::OnWindowSwipe(const std::string& direction) {
Emit("swipe", direction); Emit("swipe", direction);
} }
void Window::OnWindowSheetBegin() {
Emit("sheet-begin");
}
void Window::OnWindowSheetEnd() {
Emit("sheet-end");
}
void Window::OnWindowEnterHtmlFullScreen() { void Window::OnWindowEnterHtmlFullScreen() {
Emit("enter-html-full-screen"); Emit("enter-html-full-screen");
} }
@ -282,6 +295,11 @@ void Window::OnExecuteWindowsCommand(const std::string& command_name) {
Emit("app-command", command_name); Emit("app-command", command_name);
} }
void Window::OnTouchBarItemResult(const std::string& item_id,
const base::DictionaryValue& details) {
Emit("-touch-bar-interaction", item_id, details);
}
#if defined(OS_WIN) #if defined(OS_WIN)
void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) { void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {
if (IsWindowMessageHooked(message)) { if (IsWindowMessageHooked(message)) {
@ -811,6 +829,25 @@ std::vector<v8::Local<v8::Object>> Window::GetChildWindows() const {
return child_windows_.Values(isolate()); return child_windows_.Values(isolate());
} }
v8::Local<v8::Value> Window::GetBrowserView() const {
if (browser_view_.IsEmpty()) {
return v8::Null(isolate());
}
return v8::Local<v8::Value>::New(isolate(), browser_view_);
}
void Window::SetBrowserView(v8::Local<v8::Value> value) {
mate::Handle<BrowserView> browser_view;
if (value->IsNull()) {
window_->SetBrowserView(nullptr);
browser_view_.Reset();
} else if (mate::ConvertFromV8(isolate(), value, &browser_view)) {
window_->SetBrowserView(browser_view->view());
browser_view_.Reset(isolate(), value);
}
}
bool Window::IsModal() const { bool Window::IsModal() const {
return window_->is_modal(); return window_->is_modal();
} }
@ -840,15 +877,28 @@ void Window::SetVibrancy(mate::Arguments* args) {
window_->SetVibrancy(type); window_->SetVibrancy(type);
} }
void Window::SetTouchBar(const std::vector<mate::PersistentDictionary>& items) {
window_->SetTouchBar(items);
}
void Window::RefreshTouchBarItem(const std::string& item_id) {
window_->RefreshTouchBarItem(item_id);
}
void Window::SetEscapeTouchBarItem(const mate::PersistentDictionary& item) {
window_->SetEscapeTouchBarItem(item);
}
int32_t Window::ID() const { int32_t Window::ID() const {
return weak_map_id(); return weak_map_id();
} }
v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) { v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
if (web_contents_.IsEmpty()) if (web_contents_.IsEmpty()) {
return v8::Null(isolate); return v8::Null(isolate);
else }
return v8::Local<v8::Value>::New(isolate, web_contents_);
return v8::Local<v8::Value>::New(isolate, web_contents_);
} }
void Window::RemoveFromParentChildWindows() { void Window::RemoveFromParentChildWindows() {
@ -893,6 +943,8 @@ void Window::BuildPrototype(v8::Isolate* isolate,
#endif #endif
.SetMethod("getParentWindow", &Window::GetParentWindow) .SetMethod("getParentWindow", &Window::GetParentWindow)
.SetMethod("getChildWindows", &Window::GetChildWindows) .SetMethod("getChildWindows", &Window::GetChildWindows)
.SetMethod("getBrowserView", &Window::GetBrowserView)
.SetMethod("setBrowserView", &Window::SetBrowserView)
.SetMethod("isModal", &Window::IsModal) .SetMethod("isModal", &Window::IsModal)
.SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle) .SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle)
.SetMethod("getBounds", &Window::GetBounds) .SetMethod("getBounds", &Window::GetBounds)
@ -960,6 +1012,9 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setAutoHideCursor", &Window::SetAutoHideCursor) .SetMethod("setAutoHideCursor", &Window::SetAutoHideCursor)
#endif #endif
.SetMethod("setVibrancy", &Window::SetVibrancy) .SetMethod("setVibrancy", &Window::SetVibrancy)
.SetMethod("_setTouchBarItems", &Window::SetTouchBar)
.SetMethod("_refreshTouchBarItem", &Window::RefreshTouchBarItem)
.SetMethod("_setEscapeTouchBarItem", &Window::SetEscapeTouchBarItem)
#if defined(OS_WIN) #if defined(OS_WIN)
.SetMethod("hookWindowMessage", &Window::HookWindowMessage) .SetMethod("hookWindowMessage", &Window::HookWindowMessage)
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked) .SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)

View file

@ -16,6 +16,7 @@
#include "atom/common/api/atom_api_native_image.h" #include "atom/common/api/atom_api_native_image.h"
#include "atom/common/key_weak_map.h" #include "atom/common/key_weak_map.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "native_mate/persistent_dictionary.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
class GURL; class GURL;
@ -51,6 +52,8 @@ class Window : public mate::TrackableObject<Window>,
NativeWindow* window() const { return window_.get(); } NativeWindow* window() const { return window_.get(); }
int32_t ID() const;
protected: protected:
Window(v8::Isolate* isolate, v8::Local<v8::Object> wrapper, Window(v8::Isolate* isolate, v8::Local<v8::Object> wrapper,
const mate::Dictionary& options); const mate::Dictionary& options);
@ -60,6 +63,7 @@ class Window : public mate::TrackableObject<Window>,
void WillCloseWindow(bool* prevent_default) override; void WillCloseWindow(bool* prevent_default) override;
void WillDestroyNativeObject() override; void WillDestroyNativeObject() override;
void OnWindowClosed() override; void OnWindowClosed() override;
void OnWindowEndSession() override;
void OnWindowBlur() override; void OnWindowBlur() override;
void OnWindowFocus() override; void OnWindowFocus() override;
void OnWindowShow() override; void OnWindowShow() override;
@ -76,6 +80,8 @@ class Window : public mate::TrackableObject<Window>,
void OnWindowScrollTouchEnd() override; void OnWindowScrollTouchEnd() override;
void OnWindowScrollTouchEdge() override; void OnWindowScrollTouchEdge() override;
void OnWindowSwipe(const std::string& direction) override; void OnWindowSwipe(const std::string& direction) override;
void OnWindowSheetBegin() override;
void OnWindowSheetEnd() override;
void OnWindowEnterFullScreen() override; void OnWindowEnterFullScreen() override;
void OnWindowLeaveFullScreen() override; void OnWindowLeaveFullScreen() override;
void OnWindowEnterHtmlFullScreen() override; void OnWindowEnterHtmlFullScreen() override;
@ -83,6 +89,8 @@ class Window : public mate::TrackableObject<Window>,
void OnRendererUnresponsive() override; void OnRendererUnresponsive() override;
void OnRendererResponsive() override; void OnRendererResponsive() override;
void OnExecuteWindowsCommand(const std::string& command_name) override; void OnExecuteWindowsCommand(const std::string& command_name) override;
void OnTouchBarItemResult(const std::string& item_id,
const base::DictionaryValue& details) override;
#if defined(OS_WIN) #if defined(OS_WIN)
void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override; void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override;
@ -175,6 +183,8 @@ class Window : public mate::TrackableObject<Window>,
void SetParentWindow(v8::Local<v8::Value> value, mate::Arguments* args); void SetParentWindow(v8::Local<v8::Value> value, mate::Arguments* args);
v8::Local<v8::Value> GetParentWindow() const; v8::Local<v8::Value> GetParentWindow() const;
std::vector<v8::Local<v8::Object>> GetChildWindows() const; std::vector<v8::Local<v8::Object>> GetChildWindows() const;
v8::Local<v8::Value> GetBrowserView() const;
void SetBrowserView(v8::Local<v8::Value> value);
bool IsModal() const; bool IsModal() const;
v8::Local<v8::Value> GetNativeWindowHandle(); v8::Local<v8::Value> GetNativeWindowHandle();
@ -201,8 +211,10 @@ class Window : public mate::TrackableObject<Window>,
void SetAutoHideCursor(bool auto_hide); void SetAutoHideCursor(bool auto_hide);
void SetVibrancy(mate::Arguments* args); void SetVibrancy(mate::Arguments* args);
void SetTouchBar(const std::vector<mate::PersistentDictionary>& items);
void RefreshTouchBarItem(const std::string& item_id);
void SetEscapeTouchBarItem(const mate::PersistentDictionary& item);
int32_t ID() const;
v8::Local<v8::Value> WebContents(v8::Isolate* isolate); v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
// Remove this window from parent window's |child_windows_|. // Remove this window from parent window's |child_windows_|.
@ -213,6 +225,7 @@ class Window : public mate::TrackableObject<Window>,
MessageCallbackMap messages_callback_map_; MessageCallbackMap messages_callback_map_;
#endif #endif
v8::Global<v8::Value> browser_view_;
v8::Global<v8::Value> web_contents_; v8::Global<v8::Value> web_contents_;
v8::Global<v8::Value> menu_; v8::Global<v8::Value> menu_;
v8::Global<v8::Value> parent_window_; v8::Global<v8::Value> parent_window_;

View file

@ -7,11 +7,13 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "atom/browser/atom_browser_context.h"
#include "atom/common/google_api_key.h" #include "atom/common/google_api_key.h"
#include "base/environment.h" #include "base/environment.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "device/geolocation/geolocation_provider.h" #include "device/geolocation/geolocation_provider.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_context_getter.h"
using content::BrowserThread; using content::BrowserThread;
@ -19,51 +21,40 @@ namespace atom {
namespace internal { namespace internal {
// Loads access tokens and other necessary data on the UI thread, and class GeoURLRequestContextGetter : public net::URLRequestContextGetter {
// calls back to the originator on the originating thread.
class TokenLoadingJob : public base::RefCountedThreadSafe<TokenLoadingJob> {
public: public:
explicit TokenLoadingJob( net::URLRequestContext* GetURLRequestContext() override {
const device::AccessTokenStore::LoadAccessTokensCallback& callback) DCHECK_CURRENTLY_ON(BrowserThread::IO);
: callback_(callback), request_context_getter_(nullptr) {} if (!url_request_context_.get()) {
net::URLRequestContextBuilder builder;
builder.set_proxy_config_service(
net::ProxyService::CreateSystemProxyConfigService(
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE)));
url_request_context_ = builder.Build();
}
return url_request_context_.get();
}
void Run(AtomBrowserContext* browser_context) { scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
DCHECK_CURRENTLY_ON(BrowserThread::UI); const override {
request_context_getter_ = browser_context->GetRequestContext(); return BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
std::unique_ptr<base::Environment> env(base::Environment::Create());
if (!env->GetVar("GOOGLE_API_KEY", &api_key_))
api_key_ = GOOGLEAPIS_API_KEY;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&TokenLoadingJob::RespondOnIOThread, this));
} }
private: private:
friend class base::RefCountedThreadSafe<TokenLoadingJob>; friend class atom::AtomAccessTokenStore;
~TokenLoadingJob() {} GeoURLRequestContextGetter() {}
~GeoURLRequestContextGetter() override {}
void RespondOnIOThread() { std::unique_ptr<net::URLRequestContext> url_request_context_;
// Equivalent to access_token_map[kGeolocationProviderURL]. DISALLOW_COPY_AND_ASSIGN(GeoURLRequestContextGetter);
// Somehow base::string16 is causing compilation errors when used in a pair
// of std::map on Linux, this can work around it.
device::AccessTokenStore::AccessTokenMap access_token_map;
std::pair<GURL, base::string16> token_pair;
token_pair.first = GURL(GOOGLEAPIS_ENDPOINT + api_key_);
access_token_map.insert(token_pair);
callback_.Run(access_token_map, request_context_getter_);
}
device::AccessTokenStore::LoadAccessTokensCallback callback_;
net::URLRequestContextGetter* request_context_getter_;
std::string api_key_;
}; };
} // namespace internal } // namespace internal
AtomAccessTokenStore::AtomAccessTokenStore() { AtomAccessTokenStore::AtomAccessTokenStore()
browser_context_ = AtomBrowserContext::From("", false); : request_context_getter_(new internal::GeoURLRequestContextGetter) {
device::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); device::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices();
} }
@ -72,16 +63,19 @@ AtomAccessTokenStore::~AtomAccessTokenStore() {
void AtomAccessTokenStore::LoadAccessTokens( void AtomAccessTokenStore::LoadAccessTokens(
const LoadAccessTokensCallback& callback) { const LoadAccessTokensCallback& callback) {
scoped_refptr<internal::TokenLoadingJob> job( std::unique_ptr<base::Environment> env(base::Environment::Create());
new internal::TokenLoadingJob(callback)); std::string api_key;
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, if (!env->GetVar("GOOGLE_API_KEY", &api_key))
base::Bind(&AtomAccessTokenStore::RunTokenLoadingJob, api_key = GOOGLEAPIS_API_KEY;
this, base::RetainedRef(job))); // Equivalent to access_token_map[kGeolocationProviderURL].
} // Somehow base::string16 is causing compilation errors when used in a pair
// of std::map on Linux, this can work around it.
device::AccessTokenStore::AccessTokenMap access_token_map;
std::pair<GURL, base::string16> token_pair;
token_pair.first = GURL(GOOGLEAPIS_ENDPOINT + api_key);
access_token_map.insert(token_pair);
void AtomAccessTokenStore::RunTokenLoadingJob( callback.Run(access_token_map, request_context_getter_.get());
scoped_refptr<internal::TokenLoadingJob> job) {
job->Run(browser_context_.get());
} }
void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url, void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url,

View file

@ -9,10 +9,8 @@
namespace atom { namespace atom {
class AtomBrowserContext;
namespace internal { namespace internal {
class TokenLoadingJob; class GeoURLRequestContextGetter;
} }
class AtomAccessTokenStore : public device::AccessTokenStore { class AtomAccessTokenStore : public device::AccessTokenStore {
@ -27,9 +25,7 @@ class AtomAccessTokenStore : public device::AccessTokenStore {
const base::string16& access_token) override; const base::string16& access_token) override;
private: private:
void RunTokenLoadingJob(scoped_refptr<internal::TokenLoadingJob> job); scoped_refptr<internal::GeoURLRequestContextGetter> request_context_getter_;
scoped_refptr<AtomBrowserContext> browser_context_;
DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore); DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore);
}; };

View file

@ -172,6 +172,7 @@ std::string AtomBrowserClient::GetApplicationLocale() {
} }
void AtomBrowserClient::OverrideSiteInstanceForNavigation( void AtomBrowserClient::OverrideSiteInstanceForNavigation(
content::RenderFrameHost* render_frame_host,
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
content::SiteInstance* current_instance, content::SiteInstance* current_instance,
const GURL& url, const GURL& url,
@ -234,6 +235,11 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
} }
#endif #endif
if (delegate_) {
auto app_path = static_cast<api::App*>(delegate_)->GetAppPath();
command_line->AppendSwitchPath(switches::kAppPath, app_path);
}
content::WebContents* web_contents = GetWebContentsFromProcessID(process_id); content::WebContents* web_contents = GetWebContentsFromProcessID(process_id);
if (!web_contents) if (!web_contents)
return; return;

View file

@ -54,6 +54,7 @@ class AtomBrowserClient : public brightray::BrowserClient,
content::WebPreferences* prefs) override; content::WebPreferences* prefs) override;
std::string GetApplicationLocale() override; std::string GetApplicationLocale() override;
void OverrideSiteInstanceForNavigation( void OverrideSiteInstanceForNavigation(
content::RenderFrameHost* render_frame_host,
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
content::SiteInstance* current_instance, content::SiteInstance* current_instance,
const GURL& dest_url, const GURL& dest_url,

View file

@ -8,11 +8,13 @@
#include "atom/browser/atom_access_token_store.h" #include "atom/browser/atom_access_token_store.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_web_ui_controller_factory.h"
#include "atom/browser/bridge_task_runner.h" #include "atom/browser/bridge_task_runner.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/javascript_environment.h" #include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h" #include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h" #include "atom/common/api/atom_bindings.h"
#include "atom/common/asar/asar_util.h"
#include "atom/common/node_bindings.h" #include "atom/common/node_bindings.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "base/command_line.h" #include "base/command_line.h"
@ -59,8 +61,8 @@ AtomBrowserMainParts::AtomBrowserMainParts()
: fake_browser_process_(new BrowserProcess), : fake_browser_process_(new BrowserProcess),
exit_code_(nullptr), exit_code_(nullptr),
browser_(new Browser), browser_(new Browser),
node_bindings_(NodeBindings::Create(true)), node_bindings_(NodeBindings::Create(NodeBindings::BROWSER)),
atom_bindings_(new AtomBindings), atom_bindings_(new AtomBindings(uv_default_loop())),
gc_timer_(true, true) { gc_timer_(true, true) {
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts"; DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
self_ = this; self_ = this;
@ -70,6 +72,7 @@ AtomBrowserMainParts::AtomBrowserMainParts()
} }
AtomBrowserMainParts::~AtomBrowserMainParts() { AtomBrowserMainParts::~AtomBrowserMainParts() {
asar::ClearArchives();
// Leak the JavascriptEnvironment on exit. // Leak the JavascriptEnvironment on exit.
// This is to work around the bug that V8 would be waiting for background // This is to work around the bug that V8 would be waiting for background
// tasks to finish on exit, while somehow it waits forever in Electron, more // tasks to finish on exit, while somehow it waits forever in Electron, more
@ -132,6 +135,7 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
// Create the global environment. // Create the global environment.
node::Environment* env = node::Environment* env =
node_bindings_->CreateEnvironment(js_env_->context()); node_bindings_->CreateEnvironment(js_env_->context());
node_env_.reset(new NodeEnvironment(env));
// Make sure node can get correct environment when debugging. // Make sure node can get correct environment when debugging.
if (node_debugger_->IsRunning()) if (node_debugger_->IsRunning())
@ -165,6 +169,9 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
base::Bind(&v8::Isolate::LowMemoryNotification, base::Bind(&v8::Isolate::LowMemoryNotification,
base::Unretained(js_env_->isolate()))); base::Unretained(js_env_->isolate())));
content::WebUIControllerFactory::RegisterFactory(
AtomWebUIControllerFactory::GetInstance());
brightray::BrowserMainParts::PreMainMessageLoopRun(); brightray::BrowserMainParts::PreMainMessageLoopRun();
bridge_task_runner_->MessageLoopIsReady(); bridge_task_runner_->MessageLoopIsReady();
bridge_task_runner_ = nullptr; bridge_task_runner_ = nullptr;

View file

@ -22,6 +22,7 @@ class Browser;
class JavascriptEnvironment; class JavascriptEnvironment;
class NodeBindings; class NodeBindings;
class NodeDebugger; class NodeDebugger;
class NodeEnvironment;
class BridgeTaskRunner; class BridgeTaskRunner;
class AtomBrowserMainParts : public brightray::BrowserMainParts { class AtomBrowserMainParts : public brightray::BrowserMainParts {
@ -81,6 +82,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
std::unique_ptr<JavascriptEnvironment> js_env_; std::unique_ptr<JavascriptEnvironment> js_env_;
std::unique_ptr<NodeBindings> node_bindings_; std::unique_ptr<NodeBindings> node_bindings_;
std::unique_ptr<AtomBindings> atom_bindings_; std::unique_ptr<AtomBindings> atom_bindings_;
std::unique_ptr<NodeEnvironment> node_env_;
std::unique_ptr<NodeDebugger> node_debugger_; std::unique_ptr<NodeDebugger> node_debugger_;
base::Timer gc_timer_; base::Timer gc_timer_;

View file

@ -90,10 +90,11 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
base::FilePath path; base::FilePath path;
GetItemSavePath(item, &path); GetItemSavePath(item, &path);
// Show save dialog if save path was not set already on item // Show save dialog if save path was not set already on item
if (path.empty() && file_dialog::ShowSaveDialog(window, item->GetURL().spec(), file_dialog::DialogSettings settings;
"", default_path, settings.parent_window = window;
file_dialog::Filters(), settings.title = item->GetURL().spec();
&path)) { settings.default_path = default_path;
if (path.empty() && file_dialog::ShowSaveDialog(settings, &path)) {
// Remember the last selected download directory. // Remember the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>( AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext()); download_manager_->GetBrowserContext());

View file

@ -38,14 +38,9 @@ void AtomJavaScriptDialogManager::RunJavaScriptDialog(
} }
atom::ShowMessageBox(NativeWindow::FromWebContents(web_contents), atom::ShowMessageBox(NativeWindow::FromWebContents(web_contents),
atom::MessageBoxType::MESSAGE_BOX_TYPE_NONE, atom::MessageBoxType::MESSAGE_BOX_TYPE_NONE, buttons, -1,
buttons, 0, atom::MessageBoxOptions::MESSAGE_BOX_NONE, "",
-1, base::UTF16ToUTF8(message_text), "", "", false,
0,
atom::MessageBoxOptions::MESSAGE_BOX_NONE,
"",
base::UTF16ToUTF8(message_text),
"",
gfx::ImageSkia(), gfx::ImageSkia(),
base::Bind(&OnMessageBoxCallback, callback)); base::Bind(&OnMessageBoxCallback, callback));
} }
@ -66,7 +61,9 @@ void AtomJavaScriptDialogManager::CancelDialogs(
// static // static
void AtomJavaScriptDialogManager::OnMessageBoxCallback( void AtomJavaScriptDialogManager::OnMessageBoxCallback(
const DialogClosedCallback& callback, int code) { const DialogClosedCallback& callback,
int code,
bool checkbox_checked) {
callback.Run(code == 0, base::string16()); callback.Run(code == 0, base::string16());
} }

View file

@ -32,7 +32,8 @@ class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager {
private: private:
static void OnMessageBoxCallback(const DialogClosedCallback& callback, static void OnMessageBoxCallback(const DialogClosedCallback& callback,
int code); int code,
bool checkbox_checked);
}; };
} // namespace atom } // namespace atom

View file

@ -6,11 +6,15 @@
#include "atom/browser/login_handler.h" #include "atom/browser/login_handler.h"
#include "atom/browser/web_contents_permission_helper.h" #include "atom/browser/web_contents_permission_helper.h"
#include "atom/common/atom_constants.h"
#include "atom/common/platform_util.h" #include "atom/common/platform_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/stream_info.h"
#include "net/base/escape.h" #include "net/base/escape.h"
#include "net/ssl/client_cert_store.h" #include "net/ssl/client_cert_store.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h" #include "url/gurl.h"
#if defined(USE_NSS_CERTS) #if defined(USE_NSS_CERTS)
@ -57,6 +61,23 @@ void HandleExternalProtocolInUI(
permission_helper->RequestOpenExternalPermission(callback, has_user_gesture); permission_helper->RequestOpenExternalPermission(callback, has_user_gesture);
} }
void OnPdfResourceIntercepted(
const GURL& original_url,
const content::ResourceRequestInfo::WebContentsGetter&
web_contents_getter) {
content::WebContents* web_contents = web_contents_getter.Run();
if (!web_contents)
return;
// The URL passes the original pdf resource url, that will be requested
// by the webui page.
// chrome://pdf-viewer/index.html?src=https://somepage/123.pdf
content::NavigationController::LoadURLParams params(
GURL(base::StringPrintf("%sindex.html?%s=%s", kPdfViewerUIOrigin,
kPdfPluginSrc, original_url.spec().c_str())));
web_contents->GetController().LoadURLWithParams(params);
}
} // namespace } // namespace
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() { AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
@ -95,4 +116,23 @@ AtomResourceDispatcherHostDelegate::CreateClientCertStore(
#endif #endif
} }
bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
net::URLRequest* request,
const base::FilePath& plugin_path,
const std::string& mime_type,
GURL* origin,
std::string* payload) {
const content::ResourceRequestInfo* info =
content::ResourceRequestInfo::ForRequest(request);
if (mime_type == "application/pdf" && info->IsMainFrame()) {
*origin = GURL(kPdfViewerUIOrigin);
content::BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&OnPdfResourceIntercepted, request->url(),
info->GetWebContentsGetterForRequest()));
return true;
}
return false;
}
} // namespace atom } // namespace atom

View file

@ -5,6 +5,8 @@
#ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ #ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ #define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#include <string>
#include "content/public/browser/resource_dispatcher_host_delegate.h" #include "content/public/browser/resource_dispatcher_host_delegate.h"
namespace atom { namespace atom {
@ -22,6 +24,14 @@ class AtomResourceDispatcherHostDelegate
net::URLRequest* request) override; net::URLRequest* request) override;
std::unique_ptr<net::ClientCertStore> CreateClientCertStore( std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
content::ResourceContext* resource_context) override; content::ResourceContext* resource_context) override;
bool ShouldInterceptResourceAsStream(net::URLRequest* request,
const base::FilePath& plugin_path,
const std::string& mime_type,
GURL* origin,
std::string* payload) override;
private:
DISALLOW_COPY_AND_ASSIGN(AtomResourceDispatcherHostDelegate);
}; };
} // namespace atom } // namespace atom

View file

@ -0,0 +1,66 @@
// Copyright (c) 2017 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_web_ui_controller_factory.h"
#include <string>
#include "atom/browser/ui/webui/pdf_viewer_ui.h"
#include "atom/common/atom_constants.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "content/public/browser/web_contents.h"
namespace atom {
// static
AtomWebUIControllerFactory* AtomWebUIControllerFactory::GetInstance() {
return base::Singleton<AtomWebUIControllerFactory>::get();
}
AtomWebUIControllerFactory::AtomWebUIControllerFactory() {}
AtomWebUIControllerFactory::~AtomWebUIControllerFactory() {}
content::WebUI::TypeID AtomWebUIControllerFactory::GetWebUIType(
content::BrowserContext* browser_context,
const GURL& url) const {
if (url.host() == kPdfViewerUIHost) {
return const_cast<AtomWebUIControllerFactory*>(this);
}
return content::WebUI::kNoWebUI;
}
bool AtomWebUIControllerFactory::UseWebUIForURL(
content::BrowserContext* browser_context,
const GURL& url) const {
return GetWebUIType(browser_context, url) != content::WebUI::kNoWebUI;
}
bool AtomWebUIControllerFactory::UseWebUIBindingsForURL(
content::BrowserContext* browser_context,
const GURL& url) const {
return UseWebUIForURL(browser_context, url);
}
content::WebUIController*
AtomWebUIControllerFactory::CreateWebUIControllerForURL(content::WebUI* web_ui,
const GURL& url) const {
if (url.host() == kPdfViewerUIHost) {
base::StringPairs toplevel_params;
base::SplitStringIntoKeyValuePairs(url.query(), '=', '&', &toplevel_params);
std::string stream_id, src;
for (const auto& param : toplevel_params) {
if (param.first == kPdfPluginSrc) {
src = param.second;
}
}
auto browser_context = web_ui->GetWebContents()->GetBrowserContext();
return new PdfViewerUI(browser_context, web_ui, src);
}
return nullptr;
}
} // namespace atom

View file

@ -0,0 +1,40 @@
// Copyright (c) 2017 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_WEB_UI_CONTROLLER_FACTORY_H_
#define ATOM_BROWSER_ATOM_WEB_UI_CONTROLLER_FACTORY_H_
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "content/public/browser/web_ui_controller_factory.h"
namespace atom {
class AtomWebUIControllerFactory : public content::WebUIControllerFactory {
public:
static AtomWebUIControllerFactory* GetInstance();
AtomWebUIControllerFactory();
virtual ~AtomWebUIControllerFactory();
// content::WebUIControllerFactory:
content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
const GURL& url) const override;
bool UseWebUIForURL(content::BrowserContext* browser_context,
const GURL& url) const override;
bool UseWebUIBindingsForURL(content::BrowserContext* browser_context,
const GURL& url) const override;
content::WebUIController* CreateWebUIControllerForURL(
content::WebUI* web_ui,
const GURL& url) const override;
private:
friend struct base::DefaultSingletonTraits<AtomWebUIControllerFactory>;
DISALLOW_COPY_AND_ASSIGN(AtomWebUIControllerFactory);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_WEB_UI_CONTROLLER_FACTORY_H_

View file

@ -27,7 +27,7 @@ namespace {
bool g_update_available = false; bool g_update_available = false;
std::string update_url_ = ""; std::string update_url_ = "";
} } // namespace
std::string AutoUpdater::GetFeedURL() { std::string AutoUpdater::GetFeedURL() {
return update_url_; return update_url_;

View file

@ -43,11 +43,10 @@ void Browser::Quit() {
if (!is_quiting_) if (!is_quiting_)
return; return;
atom::WindowList* window_list = atom::WindowList::GetInstance(); if (atom::WindowList::IsEmpty())
if (window_list->size() == 0)
NotifyAndShutdown(); NotifyAndShutdown();
else
window_list->CloseAllWindows(); atom::WindowList::CloseAllWindows();
} }
void Browser::Exit(mate::Arguments* args) { void Browser::Exit(mate::Arguments* args) {
@ -65,14 +64,12 @@ void Browser::Exit(mate::Arguments* args) {
is_exiting_ = true; is_exiting_ = true;
// Must destroy windows before quitting, otherwise bad things can happen. // Must destroy windows before quitting, otherwise bad things can happen.
atom::WindowList* window_list = atom::WindowList::GetInstance(); if (atom::WindowList::IsEmpty()) {
if (window_list->size() == 0) {
Shutdown(); Shutdown();
} else { } else {
// Unlike Quit(), we do not ask to close window, but destroy the window // Unlike Quit(), we do not ask to close window, but destroy the window
// without asking. // without asking.
for (NativeWindow* window : *window_list) atom::WindowList::DestroyAllWindows();
window->CloseContents(nullptr); // e.g. Destroy()
} }
} }
} }

View file

@ -102,7 +102,7 @@ class Browser : public WindowListObserver {
std::vector<base::string16> args; std::vector<base::string16> args;
}; };
void SetLoginItemSettings(LoginItemSettings settings); void SetLoginItemSettings(LoginItemSettings settings);
LoginItemSettings GetLoginItemSettings(LoginItemSettings options); LoginItemSettings GetLoginItemSettings(const LoginItemSettings& options);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Hide the application. // Hide the application.

View file

@ -16,9 +16,7 @@ namespace atom {
void Browser::Focus() { void Browser::Focus() {
// Focus on the first visible window. // Focus on the first visible window.
WindowList* list = WindowList::GetInstance(); for (const auto& window : WindowList::GetWindows()) {
for (WindowList::iterator iter = list->begin(); iter != list->end(); ++iter) {
NativeWindow* window = *iter;
if (window->IsVisible()) { if (window->IsVisible()) {
window->Focus(true); window->Focus(true);
break; break;
@ -64,7 +62,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) {
} }
Browser::LoginItemSettings Browser::GetLoginItemSettings( Browser::LoginItemSettings Browser::GetLoginItemSettings(
LoginItemSettings options) { const LoginItemSettings& options) {
return LoginItemSettings(); return LoginItemSettings();
} }

View file

@ -64,8 +64,9 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
// On macOS, we can't query the default, but the handlers list seems to put // On macOS, we can't query the default, but the handlers list seems to put
// Apple's defaults first, so we'll use the first option that isn't our bundle // Apple's defaults first, so we'll use the first option that isn't our bundle
CFStringRef other = nil; CFStringRef other = nil;
for (CFIndex i = 0; i < CFArrayGetCount(bundleList); i++) { for (CFIndex i = 0; i < CFArrayGetCount(bundleList); ++i) {
other = (CFStringRef)CFArrayGetValueAtIndex(bundleList, i); other = base::mac::CFCast<CFStringRef>(CFArrayGetValueAtIndex(bundleList,
i));
if (![identifier isEqualToString: (__bridge NSString *)other]) { if (![identifier isEqualToString: (__bridge NSString *)other]) {
break; break;
} }
@ -152,7 +153,7 @@ bool Browser::ContinueUserActivity(const std::string& type,
} }
Browser::LoginItemSettings Browser::GetLoginItemSettings( Browser::LoginItemSettings Browser::GetLoginItemSettings(
LoginItemSettings options) { const LoginItemSettings& options) {
LoginItemSettings settings; LoginItemSettings settings;
settings.open_at_login = base::mac::CheckLoginItemStatus( settings.open_at_login = base::mac::CheckLoginItemStatus(
&settings.open_as_hidden); &settings.open_as_hidden);
@ -179,7 +180,7 @@ std::string Browser::GetExecutableFileProductName() const {
int Browser::DockBounce(BounceType type) { int Browser::DockBounce(BounceType type) {
return [[AtomApplication sharedApplication] return [[AtomApplication sharedApplication]
requestUserAttention:(NSRequestUserAttentionType)type]; requestUserAttention:static_cast<NSRequestUserAttentionType>(type)];
} }
void Browser::DockCancelBounce(int request_id) { void Browser::DockCancelBounce(int request_id) {
@ -203,9 +204,8 @@ std::string Browser::DockGetBadgeText() {
} }
void Browser::DockHide() { void Browser::DockHide() {
WindowList* list = WindowList::GetInstance(); for (const auto& window : WindowList::GetWindows())
for (WindowList::iterator it = list->begin(); it != list->end(); ++it) [window->GetNativeWindow() setCanHide:NO];
[(*it)->GetNativeWindow() setCanHide:NO];
ProcessSerialNumber psn = { 0, kCurrentProcess }; ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToUIElementApplication); TransformProcessType(&psn, kProcessTransformToUIElementApplication);

View file

@ -61,11 +61,11 @@ bool GetProtocolLaunchPath(mate::Arguments* args, base::string16* exe) {
// Read in optional args arg // Read in optional args arg
std::vector<base::string16> launch_args; std::vector<base::string16> launch_args;
if (args->GetNext(&launch_args) && !launch_args.empty()) if (args->GetNext(&launch_args) && !launch_args.empty())
*exe = base::StringPrintf(L"\"%s\" %s \"%%1\"", *exe = base::StringPrintf(L"\"%ls\" %ls \"%%1\"",
exe->c_str(), exe->c_str(),
base::JoinString(launch_args, L" ").c_str()); base::JoinString(launch_args, L" ").c_str());
else else
*exe = base::StringPrintf(L"\"%s\" \"%%1\"", exe->c_str()); *exe = base::StringPrintf(L"\"%ls\" \"%%1\"", exe->c_str());
return true; return true;
} }
@ -76,8 +76,7 @@ bool FormatCommandLineString(base::string16* exe,
} }
if (!launch_args.empty()) { if (!launch_args.empty()) {
base::string16 formatString = L"%s %s"; *exe = base::StringPrintf(L"%ls %ls",
*exe = base::StringPrintf(formatString.c_str(),
exe->c_str(), exe->c_str(),
base::JoinString(launch_args, L" ").c_str()); base::JoinString(launch_args, L" ").c_str());
} }
@ -287,7 +286,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) {
} }
Browser::LoginItemSettings Browser::GetLoginItemSettings( Browser::LoginItemSettings Browser::GetLoginItemSettings(
LoginItemSettings options) { const LoginItemSettings& options) {
LoginItemSettings settings; LoginItemSettings settings;
base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS); base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);

View file

@ -178,13 +178,23 @@ void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) {
void CommonWebContentsDelegate::SetOwnerWindow( void CommonWebContentsDelegate::SetOwnerWindow(
content::WebContents* web_contents, NativeWindow* owner_window) { content::WebContents* web_contents, NativeWindow* owner_window) {
owner_window_ = owner_window->GetWeakPtr(); owner_window_ = owner_window ? owner_window->GetWeakPtr() : nullptr;
NativeWindowRelay* relay = new NativeWindowRelay(owner_window_); NativeWindowRelay* relay = new NativeWindowRelay(owner_window_);
web_contents->SetUserData(relay->key, relay); if (owner_window) {
web_contents->SetUserData(relay->key, relay);
} else {
web_contents->RemoveUserData(relay->key);
delete relay;
}
} }
void CommonWebContentsDelegate::DestroyWebContents() { void CommonWebContentsDelegate::ResetManagedWebContents(bool async) {
web_contents_.reset(); if (async) {
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
web_contents_.release());
} else {
web_contents_.reset();
}
} }
content::WebContents* CommonWebContentsDelegate::GetWebContents() const { content::WebContents* CommonWebContentsDelegate::GetWebContents() const {
@ -294,10 +304,11 @@ void CommonWebContentsDelegate::DevToolsSaveToFile(
if (it != saved_files_.end() && !save_as) { if (it != saved_files_.end() && !save_as) {
path = it->second; path = it->second;
} else { } else {
file_dialog::Filters filters; file_dialog::DialogSettings settings;
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url)); settings.parent_window = owner_window();
if (!file_dialog::ShowSaveDialog(owner_window(), url, "", default_path, settings.title = url;
filters, &path)) { settings.default_path = base::FilePath::FromUTF8Unsafe(url);
if (!file_dialog::ShowSaveDialog(settings, &path)) {
base::StringValue url_value(url); base::StringValue url_value(url);
web_contents_->CallClientFunction( web_contents_->CallClientFunction(
"DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr); "DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr);
@ -337,7 +348,7 @@ void CommonWebContentsDelegate::DevToolsRequestFileSystems() {
} }
std::vector<FileSystem> file_systems; std::vector<FileSystem> file_systems;
for (auto file_system_path : file_system_paths) { for (const auto& file_system_path : file_system_paths) {
base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path); base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(), std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(),
path); path);
@ -358,12 +369,11 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem(
const base::FilePath& file_system_path) { const base::FilePath& file_system_path) {
base::FilePath path = file_system_path; base::FilePath path = file_system_path;
if (path.empty()) { if (path.empty()) {
file_dialog::Filters filters;
base::FilePath default_path;
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY; file_dialog::DialogSettings settings;
if (!file_dialog::ShowOpenDialog(owner_window(), "", "", default_path, settings.parent_window = owner_window();
filters, flag, &paths)) settings.properties = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
if (!file_dialog::ShowOpenDialog(settings, &paths))
return; return;
path = paths[0]; path = paths[0];

View file

@ -42,9 +42,6 @@ class CommonWebContentsDelegate
void SetOwnerWindow(content::WebContents* web_contents, void SetOwnerWindow(content::WebContents* web_contents,
NativeWindow* owner_window); NativeWindow* owner_window);
// Destroy the managed InspectableWebContents object.
void DestroyWebContents();
// Returns the WebContents managed by this delegate. // Returns the WebContents managed by this delegate.
content::WebContents* GetWebContents() const; content::WebContents* GetWebContents() const;
@ -114,6 +111,9 @@ class CommonWebContentsDelegate
std::string* name, std::string* class_name) override; std::string* name, std::string* class_name) override;
#endif #endif
// Destroy the managed InspectableWebContents object.
void ResetManagedWebContents(bool async);
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

@ -12,6 +12,8 @@
#include "gin/array_buffer.h" #include "gin/array_buffer.h"
#include "gin/v8_initializer.h" #include "gin/v8_initializer.h"
#include "atom/common/node_includes.h"
namespace atom { namespace atom {
JavascriptEnvironment::JavascriptEnvironment() JavascriptEnvironment::JavascriptEnvironment()
@ -46,4 +48,11 @@ bool JavascriptEnvironment::Initialize() {
return true; return true;
} }
NodeEnvironment::NodeEnvironment(node::Environment* env) : env_(env) {
}
NodeEnvironment::~NodeEnvironment() {
node::FreeEnvironment(env_);
}
} // namespace atom } // namespace atom

View file

@ -8,8 +8,13 @@
#include "base/macros.h" #include "base/macros.h"
#include "gin/public/isolate_holder.h" #include "gin/public/isolate_holder.h"
namespace node {
class Environment;
}
namespace atom { namespace atom {
// Manage the V8 isolate and context automatically.
class JavascriptEnvironment { class JavascriptEnvironment {
public: public:
JavascriptEnvironment(); JavascriptEnvironment();
@ -37,6 +42,18 @@ class JavascriptEnvironment {
DISALLOW_COPY_AND_ASSIGN(JavascriptEnvironment); DISALLOW_COPY_AND_ASSIGN(JavascriptEnvironment);
}; };
// Manage the Node Environment automatically.
class NodeEnvironment {
public:
explicit NodeEnvironment(node::Environment* env);
~NodeEnvironment();
private:
node::Environment* env_;
DISALLOW_COPY_AND_ASSIGN(NodeEnvironment);
};
} // namespace atom } // namespace atom
#endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_ #endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_

View file

@ -0,0 +1,26 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/loader/layered_resource_handler.h"
namespace atom {
LayeredResourceHandler::LayeredResourceHandler(
net::URLRequest* request,
std::unique_ptr<content::ResourceHandler> next_handler,
Delegate* delegate)
: content::LayeredResourceHandler(request, std::move(next_handler)),
delegate_(delegate) {}
LayeredResourceHandler::~LayeredResourceHandler() {}
bool LayeredResourceHandler::OnResponseStarted(
content::ResourceResponse* response,
bool* defer) {
if (delegate_)
delegate_->OnResponseStarted(response);
return next_handler_->OnResponseStarted(response, defer);
}
} // namespace atom

View file

@ -0,0 +1,40 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
#define ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
#include "content/browser/loader/layered_resource_handler.h"
namespace atom {
// Resource handler that notifies on various stages of a resource request.
class LayeredResourceHandler : public content::LayeredResourceHandler {
public:
class Delegate {
public:
Delegate() {}
virtual ~Delegate() {}
virtual void OnResponseStarted(content::ResourceResponse* response) = 0;
};
LayeredResourceHandler(net::URLRequest* request,
std::unique_ptr<content::ResourceHandler> next_handler,
Delegate* delegate);
~LayeredResourceHandler() override;
// content::LayeredResourceHandler:
bool OnResponseStarted(content::ResourceResponse* response,
bool* defer) override;
private:
Delegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(LayeredResourceHandler);
};
} // namespace atom
#endif // ATOM_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_

View file

@ -10,10 +10,6 @@
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/values.h" #include "base/values.h"
@interface NSWindow (SierraSDK)
@property(class) BOOL allowsAutomaticWindowTabbing;
@end
@implementation AtomApplicationDelegate @implementation AtomApplicationDelegate
- (void)setApplicationDockMenu:(atom::AtomMenuModel*)model { - (void)setApplicationDockMenu:(atom::AtomMenuModel*)model {
@ -25,10 +21,6 @@
// Don't add the "Enter Full Screen" menu item automatically. // Don't add the "Enter Full Screen" menu item automatically.
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
// Don't add the "Show Tab Bar" menu item.
if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)])
NSWindow.allowsAutomaticWindowTabbing = NO;
atom::Browser::Get()->WillFinishLaunching(); atom::Browser::Get()->WillFinishLaunching();
} }

View file

@ -0,0 +1,18 @@
// Copyright (c) 2017 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_browser_view.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
namespace atom {
NativeBrowserView::NativeBrowserView(
brightray::InspectableWebContentsView* web_contents_view)
: web_contents_view_(web_contents_view) {}
NativeBrowserView::~NativeBrowserView() {}
} // namespace atom

View file

@ -0,0 +1,57 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_
#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_
#include "base/macros.h"
#include "third_party/skia/include/core/SkColor.h"
namespace brightray {
class InspectableWebContentsView;
}
namespace gfx {
class Rect;
}
namespace atom {
namespace api {
class WebContents;
}
enum AutoResizeFlags {
kAutoResizeWidth = 0x1,
kAutoResizeHeight = 0x2,
};
class NativeBrowserView {
public:
virtual ~NativeBrowserView();
static NativeBrowserView* Create(
brightray::InspectableWebContentsView* web_contents_view);
brightray::InspectableWebContentsView* GetInspectableWebContentsView() {
return web_contents_view_;
}
virtual void SetAutoResizeFlags(uint8_t flags) = 0;
virtual void SetBounds(const gfx::Rect& bounds) = 0;
virtual void SetBackgroundColor(SkColor color) = 0;
protected:
explicit NativeBrowserView(
brightray::InspectableWebContentsView* web_contents_view);
brightray::InspectableWebContentsView* web_contents_view_;
private:
DISALLOW_COPY_AND_ASSIGN(NativeBrowserView);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_

View file

@ -0,0 +1,30 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_
#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_
#import <Cocoa/Cocoa.h>
#include "atom/browser/native_browser_view.h"
namespace atom {
class NativeBrowserViewMac : public NativeBrowserView {
public:
explicit NativeBrowserViewMac(
brightray::InspectableWebContentsView* web_contents_view);
~NativeBrowserViewMac() override;
void SetAutoResizeFlags(uint8_t flags) override;
void SetBounds(const gfx::Rect& bounds) override;
void SetBackgroundColor(SkColor color) override;
private:
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewMac);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_

View file

@ -0,0 +1,60 @@
// Copyright (c) 2017 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_browser_view_mac.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/gfx/geometry/rect.h"
// Match view::Views behavior where the view sticks to the top-left origin.
const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
NSViewMaxXMargin | NSViewMinYMargin;
namespace atom {
NativeBrowserViewMac::NativeBrowserViewMac(
brightray::InspectableWebContentsView* web_contents_view)
: NativeBrowserView(web_contents_view) {
auto* view = GetInspectableWebContentsView()->GetNativeView();
view.autoresizingMask = kDefaultAutoResizingMask;
}
NativeBrowserViewMac::~NativeBrowserViewMac() {}
void NativeBrowserViewMac::SetAutoResizeFlags(uint8_t flags) {
NSAutoresizingMaskOptions autoresizing_mask = kDefaultAutoResizingMask;
if (flags & kAutoResizeWidth) {
autoresizing_mask |= NSViewWidthSizable;
}
if (flags & kAutoResizeHeight) {
autoresizing_mask |= NSViewHeightSizable;
}
auto* view = GetInspectableWebContentsView()->GetNativeView();
view.autoresizingMask = autoresizing_mask;
}
void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) {
auto* view = GetInspectableWebContentsView()->GetNativeView();
auto* superview = view.superview;
const auto superview_height = superview ? superview.frame.size.height : 0;
view.frame =
NSMakeRect(bounds.x(), superview_height - bounds.y() - bounds.height(),
bounds.width(), bounds.height());
}
void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
auto* view = GetInspectableWebContentsView()->GetNativeView();
view.wantsLayer = YES;
view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color);
}
// static
NativeBrowserView* NativeBrowserView::Create(
brightray::InspectableWebContentsView* web_contents_view) {
return new NativeBrowserViewMac(web_contents_view);
}
} // namespace atom

View file

@ -0,0 +1,36 @@
// Copyright (c) 2017 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_browser_view_views.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/background.h"
#include "ui/views/view.h"
namespace atom {
NativeBrowserViewViews::NativeBrowserViewViews(
brightray::InspectableWebContentsView* web_contents_view)
: NativeBrowserView(web_contents_view) {}
NativeBrowserViewViews::~NativeBrowserViewViews() {}
void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) {
auto* view = GetInspectableWebContentsView()->GetView();
view->SetBoundsRect(bounds);
}
void NativeBrowserViewViews::SetBackgroundColor(SkColor color) {
auto* view = GetInspectableWebContentsView()->GetView();
view->set_background(views::Background::CreateSolidBackground(color));
}
// static
NativeBrowserView* NativeBrowserView::Create(
brightray::InspectableWebContentsView* web_contents_view) {
return new NativeBrowserViewViews(web_contents_view);
}
} // namespace atom

View file

@ -0,0 +1,33 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_
#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_
#include "atom/browser/native_browser_view.h"
namespace atom {
class NativeBrowserViewViews : public NativeBrowserView {
public:
explicit NativeBrowserViewViews(
brightray::InspectableWebContentsView* web_contents_view);
~NativeBrowserViewViews() override;
uint8_t GetAutoResizeFlags() { return auto_resize_flags_; }
void SetAutoResizeFlags(uint8_t flags) override {
auto_resize_flags_ = flags;
}
void SetBounds(const gfx::Rect& bounds) override;
void SetBackgroundColor(SkColor color) override;
private:
uint8_t auto_resize_flags_;
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews);
};
} // namespace atom
#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_

View file

@ -104,8 +104,7 @@ NativeWindow::~NativeWindow() {
// static // static
NativeWindow* NativeWindow::FromWebContents( NativeWindow* NativeWindow::FromWebContents(
content::WebContents* web_contents) { content::WebContents* web_contents) {
WindowList& window_list = *WindowList::GetInstance(); for (const auto& window : WindowList::GetWindows()) {
for (NativeWindow* window : window_list) {
if (window->web_contents() == web_contents) if (window->web_contents() == web_contents)
return window; return window;
} }
@ -340,6 +339,17 @@ void NativeWindow::SetAutoHideCursor(bool auto_hide) {
void NativeWindow::SetVibrancy(const std::string& filename) { void NativeWindow::SetVibrancy(const std::string& filename) {
} }
void NativeWindow::SetTouchBar(
const std::vector<mate::PersistentDictionary>& items) {
}
void NativeWindow::RefreshTouchBarItem(const std::string& item_id) {
}
void NativeWindow::SetEscapeTouchBarItem(
const mate::PersistentDictionary& item) {
}
void NativeWindow::FocusOnWebView() { void NativeWindow::FocusOnWebView() {
web_contents()->GetRenderViewHost()->GetWidget()->Focus(); web_contents()->GetRenderViewHost()->GetWidget()->Focus();
} }
@ -464,6 +474,11 @@ void NativeWindow::NotifyWindowClosed() {
observer.OnWindowClosed(); observer.OnWindowClosed();
} }
void NativeWindow::NotifyWindowEndSession() {
for (NativeWindowObserver& observer : observers_)
observer.OnWindowEndSession();
}
void NativeWindow::NotifyWindowBlur() { void NativeWindow::NotifyWindowBlur() {
for (NativeWindowObserver& observer : observers_) for (NativeWindowObserver& observer : observers_)
observer.OnWindowBlur(); observer.OnWindowBlur();
@ -531,7 +546,7 @@ void NativeWindow::NotifyWindowScrollTouchBegin() {
void NativeWindow::NotifyWindowScrollTouchEnd() { void NativeWindow::NotifyWindowScrollTouchEnd() {
for (NativeWindowObserver& observer : observers_) for (NativeWindowObserver& observer : observers_)
observer.OnWindowScrollTouchEdge(); observer.OnWindowScrollTouchEnd();
} }
void NativeWindow::NotifyWindowScrollTouchEdge() { void NativeWindow::NotifyWindowScrollTouchEdge() {
@ -544,6 +559,16 @@ void NativeWindow::NotifyWindowSwipe(const std::string& direction) {
observer.OnWindowSwipe(direction); observer.OnWindowSwipe(direction);
} }
void NativeWindow::NotifyWindowSheetBegin() {
for (NativeWindowObserver& observer : observers_)
observer.OnWindowSheetBegin();
}
void NativeWindow::NotifyWindowSheetEnd() {
for (NativeWindowObserver& observer : observers_)
observer.OnWindowSheetEnd();
}
void NativeWindow::NotifyWindowLeaveFullScreen() { void NativeWindow::NotifyWindowLeaveFullScreen() {
for (NativeWindowObserver& observer : observers_) for (NativeWindowObserver& observer : observers_)
observer.OnWindowLeaveFullScreen(); observer.OnWindowLeaveFullScreen();
@ -565,6 +590,13 @@ void NativeWindow::NotifyWindowExecuteWindowsCommand(
observer.OnExecuteWindowsCommand(command); observer.OnExecuteWindowsCommand(command);
} }
void NativeWindow::NotifyTouchBarItemInteraction(
const std::string& item_id,
const base::DictionaryValue& details) {
for (NativeWindowObserver& observer : observers_)
observer.OnTouchBarItemResult(item_id, details);
}
#if defined(OS_WIN) #if defined(OS_WIN)
void NativeWindow::NotifyWindowMessage( void NativeWindow::NotifyWindowMessage(
UINT message, WPARAM w_param, LPARAM l_param) { UINT message, WPARAM w_param, LPARAM l_param) {

View file

@ -21,6 +21,7 @@
#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 "extensions/browser/app_window/size_constraints.h"
#include "native_mate/persistent_dictionary.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"
@ -46,6 +47,8 @@ class Dictionary;
namespace atom { namespace atom {
class NativeBrowserView;
struct DraggableRegion; struct DraggableRegion;
class NativeWindow : public base::SupportsUserData, class NativeWindow : public base::SupportsUserData,
@ -124,6 +127,7 @@ class NativeWindow : public base::SupportsUserData,
std::string* error = nullptr) = 0; std::string* error = nullptr) = 0;
virtual bool IsAlwaysOnTop() = 0; virtual bool IsAlwaysOnTop() = 0;
virtual void Center() = 0; virtual void Center() = 0;
virtual void Invalidate() = 0;
virtual void SetTitle(const std::string& title) = 0; virtual void SetTitle(const std::string& title) = 0;
virtual std::string GetTitle() = 0; virtual std::string GetTitle() = 0;
virtual void FlashFrame(bool flash) = 0; virtual void FlashFrame(bool flash) = 0;
@ -142,6 +146,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void SetFocusable(bool focusable); virtual void SetFocusable(bool focusable);
virtual void SetMenu(AtomMenuModel* menu); virtual void SetMenu(AtomMenuModel* menu);
virtual void SetParentWindow(NativeWindow* parent); virtual void SetParentWindow(NativeWindow* parent);
virtual void SetBrowserView(NativeBrowserView* browser_view) = 0;
virtual gfx::NativeWindow GetNativeWindow() = 0; virtual gfx::NativeWindow GetNativeWindow() = 0;
virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
@ -168,6 +173,12 @@ class NativeWindow : public base::SupportsUserData,
// Vibrancy API // Vibrancy API
virtual void SetVibrancy(const std::string& type); virtual void SetVibrancy(const std::string& type);
// Touchbar API
virtual void SetTouchBar(
const std::vector<mate::PersistentDictionary>& items);
virtual void RefreshTouchBarItem(const std::string& item_id);
virtual void SetEscapeTouchBarItem(const mate::PersistentDictionary& item);
// Webview APIs. // Webview APIs.
virtual void FocusOnWebView(); virtual void FocusOnWebView();
virtual void BlurWebView(); virtual void BlurWebView();
@ -207,6 +218,7 @@ class NativeWindow : public base::SupportsUserData,
// Public API used by platform-dependent delegates and observers to send UI // Public API used by platform-dependent delegates and observers to send UI
// related notifications. // related notifications.
void NotifyWindowClosed(); void NotifyWindowClosed();
void NotifyWindowEndSession();
void NotifyWindowBlur(); void NotifyWindowBlur();
void NotifyWindowFocus(); void NotifyWindowFocus();
void NotifyWindowShow(); void NotifyWindowShow();
@ -222,11 +234,15 @@ class NativeWindow : public base::SupportsUserData,
void NotifyWindowScrollTouchEnd(); void NotifyWindowScrollTouchEnd();
void NotifyWindowScrollTouchEdge(); void NotifyWindowScrollTouchEdge();
void NotifyWindowSwipe(const std::string& direction); void NotifyWindowSwipe(const std::string& direction);
void NotifyWindowSheetBegin();
void NotifyWindowSheetEnd();
void NotifyWindowEnterFullScreen(); void NotifyWindowEnterFullScreen();
void NotifyWindowLeaveFullScreen(); void NotifyWindowLeaveFullScreen();
void NotifyWindowEnterHtmlFullScreen(); void NotifyWindowEnterHtmlFullScreen();
void NotifyWindowLeaveHtmlFullScreen(); void NotifyWindowLeaveHtmlFullScreen();
void NotifyWindowExecuteWindowsCommand(const std::string& command); void NotifyWindowExecuteWindowsCommand(const std::string& command);
void NotifyTouchBarItemInteraction(const std::string& item_id,
const base::DictionaryValue& details);
#if defined(OS_WIN) #if defined(OS_WIN)
void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param); void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param);

View file

@ -71,6 +71,7 @@ class NativeWindowMac : public NativeWindow,
int relativeLevel, std::string* error) override; int relativeLevel, std::string* error) override;
bool IsAlwaysOnTop() override; bool IsAlwaysOnTop() override;
void Center() override; void Center() override;
void Invalidate() override;
void SetTitle(const std::string& title) override; void SetTitle(const std::string& title) override;
std::string GetTitle() override; std::string GetTitle() override;
void FlashFrame(bool flash) override; void FlashFrame(bool flash) override;
@ -86,6 +87,7 @@ class NativeWindowMac : public NativeWindow,
bool IsDocumentEdited() override; bool IsDocumentEdited() override;
void SetIgnoreMouseEvents(bool ignore) override; void SetIgnoreMouseEvents(bool ignore) override;
void SetContentProtection(bool enable) override; void SetContentProtection(bool enable) override;
void SetBrowserView(NativeBrowserView* browser_view) override;
void SetParentWindow(NativeWindow* parent) override; void SetParentWindow(NativeWindow* parent) override;
gfx::NativeWindow GetNativeWindow() override; gfx::NativeWindow GetNativeWindow() override;
gfx::AcceleratedWidget GetAcceleratedWidget() override; gfx::AcceleratedWidget GetAcceleratedWidget() override;
@ -99,6 +101,10 @@ class NativeWindowMac : public NativeWindow,
void SetAutoHideCursor(bool auto_hide) override; void SetAutoHideCursor(bool auto_hide) override;
void SetVibrancy(const std::string& type) override; void SetVibrancy(const std::string& type) override;
void SetTouchBar(
const std::vector<mate::PersistentDictionary>& items) override;
void RefreshTouchBarItem(const std::string& item_id) override;
void SetEscapeTouchBarItem(const mate::PersistentDictionary& item) override;
// content::RenderWidgetHost::InputEventObserver: // content::RenderWidgetHost::InputEventObserver:
void OnInputEvent(const blink::WebInputEvent& event) override; void OnInputEvent(const blink::WebInputEvent& event) override;
@ -159,6 +165,8 @@ class NativeWindowMac : public NativeWindow,
// The view that will fill the whole frameless window. // The view that will fill the whole frameless window.
base::scoped_nsobject<FullSizeContentView> content_view_; base::scoped_nsobject<FullSizeContentView> content_view_;
NativeBrowserView* browser_view_;
std::vector<DraggableRegion> draggable_regions_; std::vector<DraggableRegion> draggable_regions_;
bool is_kiosk_; bool is_kiosk_;

View file

@ -7,6 +7,8 @@
#include <Quartz/Quartz.h> #include <Quartz/Quartz.h>
#include <string> #include <string>
#include "atom/browser/native_browser_view_mac.h"
#include "atom/browser/ui/cocoa/atom_touch_bar.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "atom/common/color_util.h" #include "atom/common/color_util.h"
#include "atom/common/draggable_region.h" #include "atom/common/draggable_region.h"
@ -18,9 +20,9 @@
#include "brightray/browser/inspectable_web_contents_view.h" #include "brightray/browser/inspectable_web_contents_view.h"
#include "brightray/browser/mac/event_dispatching_window.h" #include "brightray/browser/mac/event_dispatching_window.h"
#include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "skia/ext/skia_utils_mac.h" #include "skia/ext/skia_utils_mac.h"
#include "third_party/skia/include/core/SkRegion.h" #include "third_party/skia/include/core/SkRegion.h"
@ -228,7 +230,7 @@ bool ScopedDisableResize::disable_resize_ = false;
- (void)windowWillEnterFullScreen:(NSNotification*)notification { - (void)windowWillEnterFullScreen:(NSNotification*)notification {
// Hide the native toolbar before entering fullscreen, so there is no visual // Hide the native toolbar before entering fullscreen, so there is no visual
// artifacts. // artifacts.
if (base::mac::IsOS10_10() && if (base::mac::IsAtLeastOS10_10() &&
shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
NSWindow* window = shell_->GetNativeWindow(); NSWindow* window = shell_->GetNativeWindow();
[window setToolbar:nil]; [window setToolbar:nil];
@ -243,7 +245,7 @@ bool ScopedDisableResize::disable_resize_ = false;
// have to set one, because title bar is visible here. // have to set one, because title bar is visible here.
NSWindow* window = shell_->GetNativeWindow(); NSWindow* window = shell_->GetNativeWindow();
if ((shell_->transparent() || !shell_->has_frame()) && if ((shell_->transparent() || !shell_->has_frame()) &&
base::mac::IsOS10_10() && base::mac::IsAtLeastOS10_10() &&
// FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under // FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under
// fullscreen mode. // fullscreen mode.
shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) { shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) {
@ -252,7 +254,7 @@ bool ScopedDisableResize::disable_resize_ = false;
// Restore the native toolbar immediately after entering fullscreen, if we do // Restore the native toolbar immediately after entering fullscreen, if we do
// this before leaving fullscreen, traffic light buttons will be jumping. // this before leaving fullscreen, traffic light buttons will be jumping.
if (base::mac::IsOS10_10() && if (base::mac::IsAtLeastOS10_10() &&
shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
base::scoped_nsobject<NSToolbar> toolbar( base::scoped_nsobject<NSToolbar> toolbar(
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
@ -269,13 +271,13 @@ bool ScopedDisableResize::disable_resize_ = false;
// Restore the titlebar visibility. // Restore the titlebar visibility.
NSWindow* window = shell_->GetNativeWindow(); NSWindow* window = shell_->GetNativeWindow();
if ((shell_->transparent() || !shell_->has_frame()) && if ((shell_->transparent() || !shell_->has_frame()) &&
base::mac::IsOS10_10() && base::mac::IsAtLeastOS10_10() &&
shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) { shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) {
[window setTitleVisibility:NSWindowTitleHidden]; [window setTitleVisibility:NSWindowTitleHidden];
} }
// Turn off the style for toolbar. // Turn off the style for toolbar.
if (base::mac::IsOS10_10() && if (base::mac::IsAtLeastOS10_10() &&
shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask); shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask);
} }
@ -311,6 +313,14 @@ bool ScopedDisableResize::disable_resize_ = false;
return rect; return rect;
} }
- (void)windowWillBeginSheet:(NSNotification *)notification {
shell_->NotifyWindowSheetBegin();
}
- (void)windowDidEndSheet:(NSNotification *)notification {
shell_->NotifyWindowSheetEnd();
}
@end @end
@interface AtomPreviewItem : NSObject <QLPreviewItem> @interface AtomPreviewItem : NSObject <QLPreviewItem>
@ -335,10 +345,24 @@ bool ScopedDisableResize::disable_resize_ = false;
@end @end
@interface AtomNSWindow : EventDispatchingWindow<QLPreviewPanelDataSource, QLPreviewPanelDelegate> { #if !defined(MAC_OS_X_VERSION_10_12)
enum {
NSWindowTabbingModeDisallowed = 2
};
@interface NSWindow (SierraSDK)
- (void)setTabbingMode:(NSInteger)mode;
- (void)setTabbingIdentifier:(NSString*)identifier;
@end
#endif // MAC_OS_X_VERSION_10_12
@interface AtomNSWindow : EventDispatchingWindow<QLPreviewPanelDataSource, QLPreviewPanelDelegate, NSTouchBarDelegate> {
@private @private
atom::NativeWindowMac* shell_; atom::NativeWindowMac* shell_;
bool enable_larger_than_screen_; bool enable_larger_than_screen_;
base::scoped_nsobject<AtomTouchBar> atom_touch_bar_;
CGFloat windowButtonsInterButtonSpacing_; CGFloat windowButtonsInterButtonSpacing_;
} }
@property BOOL acceptsFirstMouse; @property BOOL acceptsFirstMouse;
@ -351,6 +375,10 @@ bool ScopedDisableResize::disable_resize_ = false;
- (void)setShell:(atom::NativeWindowMac*)shell; - (void)setShell:(atom::NativeWindowMac*)shell;
- (void)setEnableLargerThanScreen:(bool)enable; - (void)setEnableLargerThanScreen:(bool)enable;
- (void)enableWindowButtonsOffset; - (void)enableWindowButtonsOffset;
- (void)resetTouchBar:(const std::vector<mate::PersistentDictionary>&)settings;
- (void)refreshTouchBarItem:(const std::string&)item_id;
- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item;
@end @end
@implementation AtomNSWindow @implementation AtomNSWindow
@ -363,6 +391,40 @@ bool ScopedDisableResize::disable_resize_ = false;
enable_larger_than_screen_ = enable; enable_larger_than_screen_ = enable;
} }
- (void)resetTouchBar:(const std::vector<mate::PersistentDictionary>&)settings {
if (![self respondsToSelector:@selector(touchBar)]) return;
atom_touch_bar_.reset([[AtomTouchBar alloc] initWithDelegate:self
window:shell_
settings:settings]);
self.touchBar = nil;
}
- (void)refreshTouchBarItem:(const std::string&)item_id {
if (atom_touch_bar_ && self.touchBar)
[atom_touch_bar_ refreshTouchBarItem:self.touchBar id:item_id];
}
- (NSTouchBar*)makeTouchBar {
if (atom_touch_bar_)
return [atom_touch_bar_ makeTouchBar];
else
return nil;
}
- (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier {
if (touchBar && atom_touch_bar_)
return [atom_touch_bar_ makeItemForIdentifier:identifier];
else
return nil;
}
- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item {
if (atom_touch_bar_ && self.touchBar)
[atom_touch_bar_ setEscapeTouchBarItem:item forTouchBar:self.touchBar];
}
// NSWindow overrides. // NSWindow overrides.
- (void)swipeWithEvent:(NSEvent *)event { - (void)swipeWithEvent:(NSEvent *)event {
@ -618,6 +680,7 @@ NativeWindowMac::NativeWindowMac(
const mate::Dictionary& options, const mate::Dictionary& options,
NativeWindow* parent) NativeWindow* parent)
: NativeWindow(web_contents, options, parent), : NativeWindow(web_contents, options, parent),
browser_view_(nullptr),
is_kiosk_(false), is_kiosk_(false),
was_fullscreen_(false), was_fullscreen_(false),
zoom_to_page_width_(false), zoom_to_page_width_(false),
@ -648,6 +711,9 @@ NativeWindowMac::NativeWindowMac(
options.Get(options::kTitleBarStyle, &title_bar_style_); options.Get(options::kTitleBarStyle, &title_bar_style_);
std::string tabbingIdentifier;
options.Get(options::kTabbingIdentifier, &tabbingIdentifier);
std::string windowType; std::string windowType;
options.Get(options::kType, &windowType); options.Get(options::kType, &windowType);
@ -712,7 +778,7 @@ NativeWindowMac::NativeWindowMac(
[window_ setDisableKeyOrMainWindow:YES]; [window_ setDisableKeyOrMainWindow:YES];
if (transparent() || !has_frame()) { if (transparent() || !has_frame()) {
if (base::mac::IsOS10_10()) { if (base::mac::IsAtLeastOS10_10()) {
// Don't show title bar. // Don't show title bar.
[window_ setTitleVisibility:NSWindowTitleHidden]; [window_ setTitleVisibility:NSWindowTitleHidden];
} }
@ -720,12 +786,24 @@ NativeWindowMac::NativeWindowMac(
[window_ setOpaque:NO]; [window_ setOpaque:NO];
} }
// Create a tab only if tabbing identifier is specified and window has
// a native title bar.
if (tabbingIdentifier.empty() || transparent() || !has_frame()) {
if ([window_ respondsToSelector:@selector(tabbingMode)]) {
[window_ setTabbingMode:NSWindowTabbingModeDisallowed];
}
} else {
if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) {
[window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbingIdentifier)];
}
}
// We will manage window's lifetime ourselves. // We will manage window's lifetime ourselves.
[window_ setReleasedWhenClosed:NO]; [window_ setReleasedWhenClosed:NO];
// Hide the title bar. // Hide the title bar.
if (title_bar_style_ == HIDDEN_INSET) { if (title_bar_style_ == HIDDEN_INSET) {
if (base::mac::IsOS10_10()) { if (base::mac::IsAtLeastOS10_10()) {
[window_ setTitlebarAppearsTransparent:YES]; [window_ setTitlebarAppearsTransparent:YES];
base::scoped_nsobject<NSToolbar> toolbar( base::scoped_nsobject<NSToolbar> toolbar(
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
@ -1061,7 +1139,7 @@ void NativeWindowMac::SetAlwaysOnTop(bool top, const std::string& level,
int windowLevel = NSNormalWindowLevel; int windowLevel = NSNormalWindowLevel;
CGWindowLevel maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey); CGWindowLevel maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey);
CGWindowLevel minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey); CGWindowLevel minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey);
if (top) { if (top) {
if (level == "floating") { if (level == "floating") {
windowLevel = NSFloatingWindowLevel; windowLevel = NSFloatingWindowLevel;
@ -1101,10 +1179,15 @@ void NativeWindowMac::Center() {
[window_ center]; [window_ center];
} }
void NativeWindowMac::Invalidate() {
[window_ flushWindow];
[[window_ contentView] setNeedsDisplay:YES];
}
void NativeWindowMac::SetTitle(const std::string& title) { void NativeWindowMac::SetTitle(const std::string& title) {
// For macOS <= 10.9, the setTitleVisibility API is not available, we have // For macOS <= 10.9, the setTitleVisibility API is not available, we have
// to avoid calling setTitle for frameless window. // to avoid calling setTitle for frameless window.
if (!base::mac::IsOS10_10() && (transparent() || !has_frame())) if (!base::mac::IsAtLeastOS10_10() && (transparent() || !has_frame()))
return; return;
[window_ setTitle:base::SysUTF8ToNSString(title)]; [window_ setTitle:base::SysUTF8ToNSString(title)];
@ -1196,6 +1279,26 @@ void NativeWindowMac::SetContentProtection(bool enable) {
: NSWindowSharingReadOnly]; : NSWindowSharingReadOnly];
} }
void NativeWindowMac::SetBrowserView(NativeBrowserView* browser_view) {
if (browser_view_) {
[browser_view_->GetInspectableWebContentsView()->GetNativeView()
removeFromSuperview];
browser_view_ = nullptr;
}
if (!browser_view) {
return;
}
browser_view_ = browser_view;
auto* native_view =
browser_view->GetInspectableWebContentsView()->GetNativeView();
[[window_ contentView] addSubview:native_view
positioned:NSWindowAbove
relativeTo:nil];
native_view.hidden = NO;
}
void NativeWindowMac::SetParentWindow(NativeWindow* parent) { void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
if (is_modal()) if (is_modal())
return; return;
@ -1223,7 +1326,7 @@ void NativeWindowMac::SetProgressBar(double progress, const NativeWindow::Progre
NSDockTile* dock_tile = [NSApp dockTile]; NSDockTile* dock_tile = [NSApp dockTile];
// For the first time API invoked, we need to create a ContentView in DockTile. // For the first time API invoked, we need to create a ContentView in DockTile.
if (dock_tile.contentView == NULL) { if (dock_tile.contentView == nullptr) {
NSImageView* image_view = [[NSImageView alloc] init]; NSImageView* image_view = [[NSImageView alloc] init];
[image_view setImage:[NSApp applicationIconImage]]; [image_view setImage:[NSApp applicationIconImage]];
[dock_tile setContentView:image_view]; [dock_tile setContentView:image_view];
@ -1275,7 +1378,7 @@ void NativeWindowMac::SetAutoHideCursor(bool auto_hide) {
} }
void NativeWindowMac::SetVibrancy(const std::string& type) { void NativeWindowMac::SetVibrancy(const std::string& type) {
if (!base::mac::IsOS10_10()) return; if (!base::mac::IsAtLeastOS10_10()) return;
NSView* vibrant_view = [window_ vibrantView]; NSView* vibrant_view = [window_ vibrantView];
@ -1314,33 +1417,46 @@ void NativeWindowMac::SetVibrancy(const std::string& type) {
vibrancyType = NSVisualEffectMaterialTitlebar; vibrancyType = NSVisualEffectMaterialTitlebar;
} }
if (base::mac::IsOS10_11()) { if (base::mac::IsAtLeastOS10_11()) {
// TODO(kevinsawicki): Use NSVisualEffectMaterial* constants directly once // TODO(kevinsawicki): Use NSVisualEffectMaterial* constants directly once
// they are available in the minimum SDK version // they are available in the minimum SDK version
if (type == "selection") { if (type == "selection") {
// NSVisualEffectMaterialSelection // NSVisualEffectMaterialSelection
vibrancyType = (NSVisualEffectMaterial) 4; vibrancyType = static_cast<NSVisualEffectMaterial>(4);
} else if (type == "menu") { } else if (type == "menu") {
// NSVisualEffectMaterialMenu // NSVisualEffectMaterialMenu
vibrancyType = (NSVisualEffectMaterial) 5; vibrancyType = static_cast<NSVisualEffectMaterial>(5);
} else if (type == "popover") { } else if (type == "popover") {
// NSVisualEffectMaterialPopover // NSVisualEffectMaterialPopover
vibrancyType = (NSVisualEffectMaterial) 6; vibrancyType = static_cast<NSVisualEffectMaterial>(6);
} else if (type == "sidebar") { } else if (type == "sidebar") {
// NSVisualEffectMaterialSidebar // NSVisualEffectMaterialSidebar
vibrancyType = (NSVisualEffectMaterial) 7; vibrancyType = static_cast<NSVisualEffectMaterial>(7);
} else if (type == "medium-light") { } else if (type == "medium-light") {
// NSVisualEffectMaterialMediumLight // NSVisualEffectMaterialMediumLight
vibrancyType = (NSVisualEffectMaterial) 8; vibrancyType = static_cast<NSVisualEffectMaterial>(8);
} else if (type == "ultra-dark") { } else if (type == "ultra-dark") {
// NSVisualEffectMaterialUltraDark // NSVisualEffectMaterialUltraDark
vibrancyType = (NSVisualEffectMaterial) 9; vibrancyType = static_cast<NSVisualEffectMaterial>(9);
} }
} }
[effect_view setMaterial:vibrancyType]; [effect_view setMaterial:vibrancyType];
} }
void NativeWindowMac::SetTouchBar(
const std::vector<mate::PersistentDictionary>& items) {
[window_ resetTouchBar:items];
}
void NativeWindowMac::RefreshTouchBarItem(const std::string& item_id) {
[window_ refreshTouchBarItem:item_id];
}
void NativeWindowMac::SetEscapeTouchBarItem(const mate::PersistentDictionary& item) {
[window_ setEscapeTouchBarItem:item];
}
void NativeWindowMac::OnInputEvent(const blink::WebInputEvent& event) { void NativeWindowMac::OnInputEvent(const blink::WebInputEvent& event) {
switch (event.type) { switch (event.type) {
case blink::WebInputEvent::GestureScrollBegin: case blink::WebInputEvent::GestureScrollBegin:

View file

@ -8,6 +8,7 @@
#include <string> #include <string>
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/values.h"
#include "ui/base/window_open_disposition.h" #include "ui/base/window_open_disposition.h"
#include "url/gurl.h" #include "url/gurl.h"
@ -39,6 +40,9 @@ class NativeWindowObserver {
// Called when the window is closed. // Called when the window is closed.
virtual void OnWindowClosed() {} virtual void OnWindowClosed() {}
// Called when Windows sends WM_ENDSESSION message
virtual void OnWindowEndSession() {}
// Called when window loses focus. // Called when window loses focus.
virtual void OnWindowBlur() {} virtual void OnWindowBlur() {}
@ -66,10 +70,14 @@ class NativeWindowObserver {
virtual void OnWindowScrollTouchEnd() {} virtual void OnWindowScrollTouchEnd() {}
virtual void OnWindowScrollTouchEdge() {} virtual void OnWindowScrollTouchEdge() {}
virtual void OnWindowSwipe(const std::string& direction) {} virtual void OnWindowSwipe(const std::string& direction) {}
virtual void OnWindowSheetBegin() {}
virtual void OnWindowSheetEnd() {}
virtual void OnWindowEnterFullScreen() {} virtual void OnWindowEnterFullScreen() {}
virtual void OnWindowLeaveFullScreen() {} virtual void OnWindowLeaveFullScreen() {}
virtual void OnWindowEnterHtmlFullScreen() {} virtual void OnWindowEnterHtmlFullScreen() {}
virtual void OnWindowLeaveHtmlFullScreen() {} virtual void OnWindowLeaveHtmlFullScreen() {}
virtual void OnTouchBarItemResult(const std::string& item_id,
const base::DictionaryValue& details) {}
// Called when window message received // Called when window message received
#if defined(OS_WIN) #if defined(OS_WIN)

View file

@ -7,8 +7,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "atom/browser/native_browser_view_views.h"
#include "atom/browser/ui/views/menu_bar.h" #include "atom/browser/ui/views/menu_bar.h"
#include "atom/browser/ui/views/menu_layout.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "atom/common/color_util.h" #include "atom/common/color_util.h"
#include "atom/common/draggable_region.h" #include "atom/common/draggable_region.h"
@ -48,6 +48,7 @@
#include "ui/views/window/native_frame_view.h" #include "ui/views/window/native_frame_view.h"
#elif defined(OS_WIN) #elif defined(OS_WIN)
#include "atom/browser/ui/views/win_frame_view.h" #include "atom/browser/ui/views/win_frame_view.h"
#include "atom/browser/ui/win/atom_desktop_native_widget_aura.h"
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" #include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
#include "skia/ext/skia_utils_win.h" #include "skia/ext/skia_utils_win.h"
#include "ui/base/win/shell.h" #include "ui/base/win/shell.h"
@ -134,6 +135,7 @@ NativeWindowViews::NativeWindowViews(
: NativeWindow(web_contents, options, parent), : NativeWindow(web_contents, options, parent),
window_(new views::Widget), window_(new views::Widget),
web_view_(inspectable_web_contents()->GetView()->GetView()), web_view_(inspectable_web_contents()->GetView()->GetView()),
browser_view_(nullptr),
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),
@ -204,8 +206,7 @@ NativeWindowViews::NativeWindowViews(
if (parent) if (parent)
params.parent = parent->GetNativeWindow(); params.parent = parent->GetNativeWindow();
params.native_widget = params.native_widget = new AtomDesktopNativeWidgetAura(window_.get());
new views::DesktopNativeWidgetAura(window_.get());
atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin( atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin(
this, this,
window_.get(), window_.get(),
@ -274,9 +275,6 @@ NativeWindowViews::NativeWindowViews(
SetWindowType(GetAcceleratedWidget(), window_type); SetWindowType(GetAcceleratedWidget(), window_type);
#endif #endif
// Add web view.
SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
AddChildView(web_view_); AddChildView(web_view_);
#if defined(OS_WIN) #if defined(OS_WIN)
@ -695,6 +693,10 @@ void NativeWindowViews::Center() {
window_->CenterWindow(GetSize()); window_->CenterWindow(GetSize());
} }
void NativeWindowViews::Invalidate() {
window_->SchedulePaintInRect(gfx::Rect(GetBounds().size()));
}
void NativeWindowViews::SetTitle(const std::string& title) { void NativeWindowViews::SetTitle(const std::string& title) {
title_ = title; title_ = title;
window_->UpdateWindowTitle(); window_->UpdateWindowTitle();
@ -877,6 +879,24 @@ void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) {
Layout(); Layout();
} }
void NativeWindowViews::SetBrowserView(NativeBrowserView* browser_view) {
if (browser_view_) {
web_view_->RemoveChildView(
browser_view_->GetInspectableWebContentsView()->GetView());
browser_view_ = nullptr;
}
if (!browser_view) {
return;
}
// Add as child of the main web view to avoid (0, 0) origin from overlapping
// with menu bar.
browser_view_ = browser_view;
web_view_->AddChildView(
browser_view->GetInspectableWebContentsView()->GetView());
}
void NativeWindowViews::SetParentWindow(NativeWindow* parent) { void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
NativeWindow::SetParentWindow(parent); NativeWindow::SetParentWindow(parent);
@ -1244,6 +1264,43 @@ void NativeWindowViews::HandleKeyboardEvent(
} }
} }
void NativeWindowViews::Layout() {
const auto size = GetContentsBounds().size();
const auto menu_bar_bounds =
menu_bar_visible_ ? gfx::Rect(0, 0, size.width(), kMenuBarHeight)
: gfx::Rect();
if (menu_bar_) {
menu_bar_->SetBoundsRect(menu_bar_bounds);
}
const auto old_web_view_size = web_view_ ? web_view_->size() : gfx::Size();
if (web_view_) {
web_view_->SetBoundsRect(
gfx::Rect(0, menu_bar_bounds.height(), size.width(),
size.height() - menu_bar_bounds.height()));
}
const auto new_web_view_size = web_view_ ? web_view_->size() : gfx::Size();
if (browser_view_) {
const auto flags = static_cast<NativeBrowserViewViews*>(browser_view_)
->GetAutoResizeFlags();
int width_delta = 0;
int height_delta = 0;
if (flags & kAutoResizeWidth) {
width_delta = new_web_view_size.width() - old_web_view_size.width();
}
if (flags & kAutoResizeHeight) {
height_delta = new_web_view_size.height() - old_web_view_size.height();
}
auto* view = browser_view_->GetInspectableWebContentsView()->GetView();
auto new_view_size = view->size();
new_view_size.set_width(new_view_size.width() + width_delta);
new_view_size.set_height(new_view_size.height() + height_delta);
view->SetSize(new_view_size);
}
}
gfx::Size NativeWindowViews::GetMinimumSize() { gfx::Size NativeWindowViews::GetMinimumSize() {
return NativeWindow::GetMinimumSize(); return NativeWindow::GetMinimumSize();
} }

View file

@ -90,6 +90,7 @@ class NativeWindowViews : public NativeWindow,
int relativeLevel, std::string* error) override; int relativeLevel, std::string* error) override;
bool IsAlwaysOnTop() override; bool IsAlwaysOnTop() override;
void Center() override; void Center() override;
void Invalidate() override;
void SetTitle(const std::string& title) override; void SetTitle(const std::string& title) override;
std::string GetTitle() override; std::string GetTitle() override;
void FlashFrame(bool flash) override; void FlashFrame(bool flash) override;
@ -103,6 +104,7 @@ class NativeWindowViews : public NativeWindow,
void SetContentProtection(bool enable) override; void SetContentProtection(bool enable) override;
void SetFocusable(bool focusable) override; void SetFocusable(bool focusable) override;
void SetMenu(AtomMenuModel* menu_model) override; void SetMenu(AtomMenuModel* menu_model) override;
void SetBrowserView(NativeBrowserView* browser_view) override;
void SetParentWindow(NativeWindow* parent) override; void SetParentWindow(NativeWindow* parent) override;
gfx::NativeWindow GetNativeWindow() override; gfx::NativeWindow GetNativeWindow() override;
void SetOverlayIcon(const gfx::Image& overlay, void SetOverlayIcon(const gfx::Image& overlay,
@ -175,6 +177,7 @@ class NativeWindowViews : public NativeWindow,
const content::NativeWebKeyboardEvent& event) override; const content::NativeWebKeyboardEvent& event) override;
// views::View: // views::View:
void Layout() override;
gfx::Size GetMinimumSize() override; gfx::Size GetMinimumSize() override;
gfx::Size GetMaximumSize() override; gfx::Size GetMaximumSize() override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override; bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
@ -188,6 +191,8 @@ class NativeWindowViews : public NativeWindow,
std::unique_ptr<views::Widget> window_; std::unique_ptr<views::Widget> window_;
views::View* web_view_; // Managed by inspectable_web_contents_. views::View* web_view_; // Managed by inspectable_web_contents_.
NativeBrowserView* browser_view_;
std::unique_ptr<MenuBar> menu_bar_; std::unique_ptr<MenuBar> menu_bar_;
bool menu_bar_autohide_; bool menu_bar_autohide_;
bool menu_bar_visible_; bool menu_bar_visible_;

View file

@ -147,6 +147,11 @@ bool NativeWindowViews::PreHandleMSG(
} }
return false; return false;
} }
case WM_ENDSESSION: {
if (w_param) {
NotifyWindowEndSession();
}
}
default: default:
return false; return false;
} }

View file

@ -7,6 +7,9 @@
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/net/atom_ct_delegate.h" #include "atom/browser/net/atom_ct_delegate.h"
#include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/native_mate_converters/net_converter.h"
#include "base/containers/linked_list.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/cert/cert_verify_result.h" #include "net/cert/cert_verify_result.h"
@ -19,17 +22,130 @@ namespace atom {
namespace { namespace {
void OnResult( class Response : public base::LinkNode<Response> {
net::CertVerifyResult* verify_result, public:
const net::CompletionCallback& callback, Response(net::CertVerifyResult* verify_result,
bool result) { const net::CompletionCallback& callback)
BrowserThread::PostTask( : verify_result_(verify_result), callback_(callback) {}
BrowserThread::IO, FROM_HERE, net::CertVerifyResult* verify_result() { return verify_result_; }
base::Bind(callback, result ? net::OK : net::ERR_FAILED)); net::CompletionCallback callback() { return callback_; }
}
private:
net::CertVerifyResult* verify_result_;
net::CompletionCallback callback_;
DISALLOW_COPY_AND_ASSIGN(Response);
};
} // namespace } // namespace
class CertVerifierRequest : public AtomCertVerifier::Request {
public:
CertVerifierRequest(const AtomCertVerifier::RequestParams& params,
AtomCertVerifier* cert_verifier)
: params_(params),
cert_verifier_(cert_verifier),
error_(net::ERR_IO_PENDING),
custom_response_(net::ERR_IO_PENDING),
first_response_(true),
weak_ptr_factory_(this) {}
~CertVerifierRequest() override {
cert_verifier_->RemoveRequest(params_);
default_verifier_request_.reset();
while (!response_list_.empty() && !first_response_) {
base::LinkNode<Response>* response_node = response_list_.head();
response_node->RemoveFromList();
Response* response = response_node->value();
RunResponse(response);
}
cert_verifier_ = nullptr;
weak_ptr_factory_.InvalidateWeakPtrs();
}
void RunResponse(Response* response) {
if (custom_response_ == net::ERR_ABORTED) {
*(response->verify_result()) = result_;
response->callback().Run(error_);
} else {
response->verify_result()->Reset();
response->verify_result()->verified_cert = params_.certificate();
cert_verifier_->ct_delegate()->AddCTExcludedHost(params_.hostname());
response->callback().Run(custom_response_);
}
delete response;
}
void Start(net::CRLSet* crl_set,
const net::NetLogWithSource& net_log) {
int error = cert_verifier_->default_verifier()->Verify(
params_, crl_set, &result_,
base::Bind(&CertVerifierRequest::OnDefaultVerificationDone,
weak_ptr_factory_.GetWeakPtr()),
&default_verifier_request_, net_log);
if (error != net::ERR_IO_PENDING)
OnDefaultVerificationDone(error);
}
void OnDefaultVerificationDone(int error) {
error_ = error;
std::unique_ptr<VerifyRequestParams> request(new VerifyRequestParams());
request->hostname = params_.hostname();
request->default_result = net::ErrorToString(error);
request->certificate = params_.certificate();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&CertVerifierRequest::OnVerifyRequestInUI,
weak_ptr_factory_.GetWeakPtr(),
cert_verifier_->verify_proc(),
base::Passed(&request)));
}
void OnVerifyRequestInUI(const AtomCertVerifier::VerifyProc& verify_proc,
std::unique_ptr<VerifyRequestParams> request) {
verify_proc.Run(*(request.get()),
base::Bind(&CertVerifierRequest::OnResponseInUI,
weak_ptr_factory_.GetWeakPtr()));
}
void OnResponseInUI(int result) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&CertVerifierRequest::NotifyResponseInIO,
weak_ptr_factory_.GetWeakPtr(), result));
}
void NotifyResponseInIO(int result) {
custom_response_ = result;
first_response_ = false;
// Responding to first request in the list will initiate destruction of
// the class, respond to others in the list inside destructor.
base::LinkNode<Response>* response_node = response_list_.head();
response_node->RemoveFromList();
Response* response = response_node->value();
RunResponse(response);
}
void AddResponseListener(net::CertVerifyResult* verify_result,
const net::CompletionCallback& callback) {
response_list_.Append(new Response(verify_result, callback));
}
const AtomCertVerifier::RequestParams& params() const { return params_; }
private:
using ResponseList = base::LinkedList<Response>;
const AtomCertVerifier::RequestParams params_;
AtomCertVerifier* cert_verifier_;
int error_;
int custom_response_;
bool first_response_;
ResponseList response_list_;
net::CertVerifyResult result_;
std::unique_ptr<AtomCertVerifier::Request> default_verifier_request_;
base::WeakPtrFactory<CertVerifierRequest> weak_ptr_factory_;
};
AtomCertVerifier::AtomCertVerifier(AtomCTDelegate* ct_delegate) AtomCertVerifier::AtomCertVerifier(AtomCTDelegate* ct_delegate)
: default_cert_verifier_(net::CertVerifier::CreateDefault()), : default_cert_verifier_(net::CertVerifier::CreateDefault()),
ct_delegate_(ct_delegate) {} ct_delegate_(ct_delegate) {}
@ -51,23 +167,43 @@ int AtomCertVerifier::Verify(
if (verify_proc_.is_null()) { if (verify_proc_.is_null()) {
ct_delegate_->ClearCTExcludedHostsList(); ct_delegate_->ClearCTExcludedHostsList();
return default_cert_verifier_->Verify( return default_cert_verifier_->Verify(params, crl_set, verify_result,
params, crl_set, verify_result, callback, out_req, net_log); callback, out_req, net_log);
} else {
CertVerifierRequest* request = FindRequest(params);
if (!request) {
out_req->reset();
std::unique_ptr<CertVerifierRequest> new_request =
base::MakeUnique<CertVerifierRequest>(params, this);
new_request->Start(crl_set, net_log);
request = new_request.get();
*out_req = std::move(new_request);
inflight_requests_[params] = request;
}
request->AddResponseListener(verify_result, callback);
return net::ERR_IO_PENDING;
} }
verify_result->Reset();
verify_result->verified_cert = params.certificate();
ct_delegate_->AddCTExcludedHost(params.hostname());
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(verify_proc_, params.hostname(), params.certificate(),
base::Bind(OnResult, verify_result, callback)));
return net::ERR_IO_PENDING;
} }
bool AtomCertVerifier::SupportsOCSPStapling() { bool AtomCertVerifier::SupportsOCSPStapling() {
return true; if (verify_proc_.is_null())
return default_cert_verifier_->SupportsOCSPStapling();
return false;
}
void AtomCertVerifier::RemoveRequest(const RequestParams& params) {
auto it = inflight_requests_.find(params);
if (it != inflight_requests_.end())
inflight_requests_.erase(it);
}
CertVerifierRequest* AtomCertVerifier::FindRequest(
const RequestParams& params) {
auto it = inflight_requests_.find(params);
if (it != inflight_requests_.end())
return it->second;
return nullptr;
} }
} // namespace atom } // namespace atom

View file

@ -5,6 +5,7 @@
#ifndef ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_ #ifndef ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_
#define ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_ #define ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_
#include <map>
#include <memory> #include <memory>
#include <string> #include <string>
@ -13,19 +14,30 @@
namespace atom { namespace atom {
class AtomCTDelegate; class AtomCTDelegate;
class CertVerifierRequest;
struct VerifyRequestParams {
std::string hostname;
std::string default_result;
scoped_refptr<net::X509Certificate> certificate;
};
class AtomCertVerifier : public net::CertVerifier { class AtomCertVerifier : public net::CertVerifier {
public: public:
explicit AtomCertVerifier(AtomCTDelegate* ct_delegate); explicit AtomCertVerifier(AtomCTDelegate* ct_delegate);
virtual ~AtomCertVerifier(); virtual ~AtomCertVerifier();
using VerifyProc = using VerifyProc = base::Callback<void(const VerifyRequestParams& request,
base::Callback<void(const std::string& hostname, const net::CompletionCallback&)>;
scoped_refptr<net::X509Certificate>,
const base::Callback<void(bool)>&)>;
void SetVerifyProc(const VerifyProc& proc); void SetVerifyProc(const VerifyProc& proc);
const VerifyProc verify_proc() const { return verify_proc_; }
AtomCTDelegate* ct_delegate() const { return ct_delegate_; }
net::CertVerifier* default_verifier() const {
return default_cert_verifier_.get();
}
protected: protected:
// net::CertVerifier: // net::CertVerifier:
int Verify(const RequestParams& params, int Verify(const RequestParams& params,
@ -37,6 +49,12 @@ class AtomCertVerifier : public net::CertVerifier {
bool SupportsOCSPStapling() override; bool SupportsOCSPStapling() override;
private: private:
friend class CertVerifierRequest;
void RemoveRequest(const RequestParams& params);
CertVerifierRequest* FindRequest(const RequestParams& params);
std::map<RequestParams, CertVerifierRequest*> inflight_requests_;
VerifyProc verify_proc_; VerifyProc verify_proc_;
std::unique_ptr<net::CertVerifier> default_cert_verifier_; std::unique_ptr<net::CertVerifier> default_cert_verifier_;
AtomCTDelegate* ct_delegate_; AtomCTDelegate* ct_delegate_;

View file

@ -402,7 +402,7 @@ void AtomNetworkDelegate::OnListenerResultInIO(
if (!base::ContainsKey(callbacks_, id)) if (!base::ContainsKey(callbacks_, id))
return; return;
ReadFromResponseObject(*response.get(), out); ReadFromResponseObject(*response, out);
bool cancel = false; bool cancel = false;
response->GetBoolean("cancel", &cancel); response->GetBoolean("cancel", &cancel);

View file

@ -13,6 +13,7 @@
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/base/upload_bytes_element_reader.h" #include "net/base/upload_bytes_element_reader.h"
#include "net/url_request/redirect_info.h"
namespace { namespace {
const int kBufferSize = 4096; const int kBufferSize = 4096;
@ -58,6 +59,7 @@ scoped_refptr<AtomURLRequest> AtomURLRequest::Create(
AtomBrowserContext* browser_context, AtomBrowserContext* browser_context,
const std::string& method, const std::string& method,
const std::string& url, const std::string& url,
const std::string& redirect_policy,
api::URLRequest* delegate) { api::URLRequest* delegate) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@ -76,7 +78,7 @@ scoped_refptr<AtomURLRequest> AtomURLRequest::Create(
if (content::BrowserThread::PostTask( if (content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::Bind(&AtomURLRequest::DoInitialize, atom_url_request, base::Bind(&AtomURLRequest::DoInitialize, atom_url_request,
request_context_getter, method, url))) { request_context_getter, method, url, redirect_policy))) {
return atom_url_request; return atom_url_request;
} }
return nullptr; return nullptr;
@ -93,10 +95,12 @@ void AtomURLRequest::Terminate() {
void AtomURLRequest::DoInitialize( void AtomURLRequest::DoInitialize(
scoped_refptr<net::URLRequestContextGetter> request_context_getter, scoped_refptr<net::URLRequestContextGetter> request_context_getter,
const std::string& method, const std::string& method,
const std::string& url) { const std::string& url,
const std::string& redirect_policy) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(request_context_getter); DCHECK(request_context_getter);
redirect_policy_ = redirect_policy;
request_context_getter_ = request_context_getter; request_context_getter_ = request_context_getter;
request_context_getter_->AddObserver(this); request_context_getter_->AddObserver(this);
auto context = request_context_getter_->GetURLRequestContext(); auto context = request_context_getter_->GetURLRequestContext();
@ -150,6 +154,13 @@ void AtomURLRequest::Cancel() {
base::Bind(&AtomURLRequest::DoCancel, this)); base::Bind(&AtomURLRequest::DoCancel, this));
} }
void AtomURLRequest::FollowRedirect() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&AtomURLRequest::DoFollowRedirect, this));
}
void AtomURLRequest::SetExtraHeader(const std::string& name, void AtomURLRequest::SetExtraHeader(const std::string& name,
const std::string& value) const { const std::string& value) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@ -246,6 +257,13 @@ void AtomURLRequest::DoCancel() {
DoTerminate(); DoTerminate();
} }
void AtomURLRequest::DoFollowRedirect() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (request_ && request_->is_redirecting() && redirect_policy_ == "manual") {
request_->FollowDeferredRedirect();
}
}
void AtomURLRequest::DoSetExtraHeader(const std::string& name, void AtomURLRequest::DoSetExtraHeader(const std::string& name,
const std::string& value) const { const std::string& value) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@ -297,6 +315,29 @@ void AtomURLRequest::DoSetLoadFlags(int flags) const {
request_->SetLoadFlags(request_->load_flags() | flags); request_->SetLoadFlags(request_->load_flags() | flags);
} }
void AtomURLRequest::OnReceivedRedirect(net::URLRequest* request,
const net::RedirectInfo& info,
bool* defer_redirect) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!request_ || redirect_policy_ == "follow")
return;
if (redirect_policy_ == "error") {
request->Cancel();
DoCancelWithError(
"Request cannot follow redirect with the current redirect mode", true);
} else if (redirect_policy_ == "manual") {
*defer_redirect = true;
scoped_refptr<net::HttpResponseHeaders> response_headers =
request->response_headers();
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&AtomURLRequest::InformDelegateReceivedRedirect, this,
info.status_code, info.new_method, info.new_url,
response_headers));
}
}
void AtomURLRequest::OnAuthRequired(net::URLRequest* request, void AtomURLRequest::OnAuthRequired(net::URLRequest* request,
net::AuthChallengeInfo* auth_info) { net::AuthChallengeInfo* auth_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@ -348,6 +389,14 @@ void AtomURLRequest::OnReadCompleted(net::URLRequest* request, int bytes_read) {
DCHECK_EQ(request, request_.get()); DCHECK_EQ(request, request_.get());
const auto status = request_->status(); const auto status = request_->status();
if (status.error() == bytes_read &&
bytes_read == net::ERR_CONTENT_DECODING_INIT_FAILED) {
// When the request job is unable to create a source stream for the
// content encoding, we fail the request.
DoCancelWithError(net::ErrorToString(net::ERR_CONTENT_DECODING_INIT_FAILED),
true);
return;
}
bool response_error = false; bool response_error = false;
bool data_ended = false; bool data_ended = false;
@ -399,6 +448,16 @@ bool AtomURLRequest::CopyAndPostBuffer(int bytes_read) {
buffer_copy)); buffer_copy));
} }
void AtomURLRequest::InformDelegateReceivedRedirect(
int status_code,
const std::string& method,
const GURL& url,
scoped_refptr<net::HttpResponseHeaders> response_headers) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (delegate_)
delegate_->OnReceivedRedirect(status_code, method, url, response_headers);
}
void AtomURLRequest::InformDelegateAuthenticationRequired( void AtomURLRequest::InformDelegateAuthenticationRequired(
scoped_refptr<net::AuthChallengeInfo> auth_info) const { scoped_refptr<net::AuthChallengeInfo> auth_info) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

View file

@ -30,12 +30,14 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
AtomBrowserContext* browser_context, AtomBrowserContext* browser_context,
const std::string& method, const std::string& method,
const std::string& url, const std::string& url,
const std::string& redirect_policy,
api::URLRequest* delegate); api::URLRequest* delegate);
void Terminate(); void Terminate();
bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last); bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last);
void SetChunkedUpload(bool is_chunked_upload); void SetChunkedUpload(bool is_chunked_upload);
void Cancel(); void Cancel();
void FollowRedirect();
void SetExtraHeader(const std::string& name, const std::string& value) const; void SetExtraHeader(const std::string& name, const std::string& value) const;
void RemoveExtraHeader(const std::string& name) const; void RemoveExtraHeader(const std::string& name) const;
void PassLoginInformation(const base::string16& username, void PassLoginInformation(const base::string16& username,
@ -44,6 +46,9 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
protected: protected:
// Overrides of net::URLRequest::Delegate // Overrides of net::URLRequest::Delegate
void OnReceivedRedirect(net::URLRequest* request,
const net::RedirectInfo& info,
bool* defer_redirect) override;
void OnAuthRequired(net::URLRequest* request, void OnAuthRequired(net::URLRequest* request,
net::AuthChallengeInfo* auth_info) override; net::AuthChallengeInfo* auth_info) override;
void OnResponseStarted(net::URLRequest* request) override; void OnResponseStarted(net::URLRequest* request) override;
@ -60,11 +65,13 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
void DoInitialize(scoped_refptr<net::URLRequestContextGetter>, void DoInitialize(scoped_refptr<net::URLRequestContextGetter>,
const std::string& method, const std::string& method,
const std::string& url); const std::string& url,
const std::string& redirect_policy);
void DoTerminate(); void DoTerminate();
void DoWriteBuffer(scoped_refptr<const net::IOBufferWithSize> buffer, void DoWriteBuffer(scoped_refptr<const net::IOBufferWithSize> buffer,
bool is_last); bool is_last);
void DoCancel(); void DoCancel();
void DoFollowRedirect();
void DoSetExtraHeader(const std::string& name, void DoSetExtraHeader(const std::string& name,
const std::string& value) const; const std::string& value) const;
void DoRemoveExtraHeader(const std::string& name) const; void DoRemoveExtraHeader(const std::string& name) const;
@ -77,6 +84,11 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
void ReadResponse(); void ReadResponse();
bool CopyAndPostBuffer(int bytes_read); bool CopyAndPostBuffer(int bytes_read);
void InformDelegateReceivedRedirect(
int status_code,
const std::string& method,
const GURL& url,
scoped_refptr<net::HttpResponseHeaders> response_headers) const;
void InformDelegateAuthenticationRequired( void InformDelegateAuthenticationRequired(
scoped_refptr<net::AuthChallengeInfo> auth_info) const; scoped_refptr<net::AuthChallengeInfo> auth_info) const;
void InformDelegateResponseStarted( void InformDelegateResponseStarted(
@ -92,6 +104,7 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
scoped_refptr<net::URLRequestContextGetter> request_context_getter_; scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
bool is_chunked_upload_; bool is_chunked_upload_;
std::string redirect_policy_;
std::unique_ptr<net::ChunkedUploadDataStream> chunked_stream_; std::unique_ptr<net::ChunkedUploadDataStream> chunked_stream_;
std::unique_ptr<net::ChunkedUploadDataStream::Writer> chunked_stream_writer_; std::unique_ptr<net::ChunkedUploadDataStream::Writer> chunked_stream_writer_;
std::vector<std::unique_ptr<net::UploadElementReader>> std::vector<std::unique_ptr<net::UploadElementReader>>

View file

@ -164,7 +164,7 @@ void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket,
buffer_.append(data, len); buffer_.append(data, len);
do { do {
if (buffer_.size() == 0) if (buffer_.empty())
return; return;
// Read the "Content-Length" header. // Read the "Content-Length" header.

View file

@ -851,12 +851,12 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) {
GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval( GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval(
base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_)); base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_));
if (copy_frame_generator_.get()) { if (copy_frame_generator_) {
copy_frame_generator_->set_frame_rate_threshold_ms( copy_frame_generator_->set_frame_rate_threshold_ms(
frame_rate_threshold_ms_); frame_rate_threshold_ms_);
} }
if (begin_frame_timer_.get()) { if (begin_frame_timer_) {
begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_); begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_);
} else { } else {
begin_frame_timer_.reset(new AtomBeginFrameTimer( begin_frame_timer_.reset(new AtomBeginFrameTimer(
@ -871,7 +871,7 @@ void OffScreenRenderWidgetHostView::Invalidate() {
if (software_output_device_) { if (software_output_device_) {
software_output_device_->OnPaint(bounds_in_pixels); software_output_device_->OnPaint(bounds_in_pixels);
} else if (copy_frame_generator_.get()) { } else if (copy_frame_generator_) {
copy_frame_generator_->GenerateCopyFrame(true, bounds_in_pixels); copy_frame_generator_->GenerateCopyFrame(true, bounds_in_pixels);
} }
} }

View file

@ -145,4 +145,4 @@ OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const {
return browser_compositor_->GetDelegatedFrameHost(); return browser_compositor_->GetDelegatedFrameHost();
} }
} // namespace } // namespace atom

View file

@ -17,9 +17,9 @@
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>electron.icns</string> <string>electron.icns</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.5.1</string> <string>1.6.8</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.5.1</string> <string>1.6.8</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string> <string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>

View file

@ -32,7 +32,7 @@
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware> <dpiAware>true/pm</dpiAware>
<disableWindowFiltering xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">true</disableWindowFiltering> <disableWindowFiltering xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">true</disableWindowFiltering>
</asmv3:windowsSettings> </asmv3:windowsSettings>
</asmv3:application> </asmv3:application>

View file

@ -56,8 +56,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,5,1,0 FILEVERSION 1,6,8,0
PRODUCTVERSION 1,5,1,0 PRODUCTVERSION 1,6,8,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", "1.5.1" VALUE "FileVersion", "1.6.8"
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", "1.5.1" VALUE "ProductVersion", "1.6.8"
VALUE "SquirrelAwareVersion", "1" VALUE "SquirrelAwareVersion", "1"
END END
END END

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_UI_CERTIFICATE_TRUST_H_
#define ATOM_BROWSER_UI_CERTIFICATE_TRUST_H_
#include <string>
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "net/cert/x509_certificate.h"
namespace atom {
class NativeWindow;
} // namespace atom
namespace certificate_trust {
typedef base::Callback<void(void)> ShowTrustCallback;
void ShowCertificateTrust(atom::NativeWindow* parent_window,
const scoped_refptr<net::X509Certificate>& cert,
const std::string& message,
const ShowTrustCallback& callback);
} // namespace certificate_trust
#endif // ATOM_BROWSER_UI_CERTIFICATE_TRUST_H_

View file

@ -0,0 +1,112 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/certificate_trust.h"
#import <Cocoa/Cocoa.h>
#import <SecurityInterface/SFCertificateTrustPanel.h>
#include "atom/browser/native_window.h"
#include "base/strings/sys_string_conversions.h"
#include "net/cert/cert_database.h"
@interface TrustDelegate : NSObject {
@private
certificate_trust::ShowTrustCallback callback_;
SFCertificateTrustPanel* panel_;
scoped_refptr<net::X509Certificate> cert_;
SecTrustRef trust_;
CFArrayRef cert_chain_;
SecPolicyRef sec_policy_;
}
- (id)initWithCallback:(const certificate_trust::ShowTrustCallback&)callback
panel:(SFCertificateTrustPanel*)panel
cert:(const scoped_refptr<net::X509Certificate>&)cert
trust:(SecTrustRef)trust
certChain:(CFArrayRef)certChain
secPolicy:(SecPolicyRef)secPolicy;
- (void)panelDidEnd:(NSWindow*)sheet
returnCode:(int)returnCode
contextInfo:(void*)contextInfo;
@end
@implementation TrustDelegate
- (void)dealloc {
[panel_ release];
CFRelease(trust_);
CFRelease(cert_chain_);
CFRelease(sec_policy_);
[super dealloc];
}
- (id)initWithCallback:(const certificate_trust::ShowTrustCallback&)callback
panel:(SFCertificateTrustPanel*)panel
cert:(const scoped_refptr<net::X509Certificate>&)cert
trust:(SecTrustRef)trust
certChain:(CFArrayRef)certChain
secPolicy:(SecPolicyRef)secPolicy {
if ((self = [super init])) {
callback_ = callback;
panel_ = panel;
cert_ = cert;
trust_ = trust;
cert_chain_ = certChain;
sec_policy_ = secPolicy;
}
return self;
}
- (void)panelDidEnd:(NSWindow*)sheet
returnCode:(int)returnCode
contextInfo:(void*)contextInfo {
auto cert_db = net::CertDatabase::GetInstance();
// This forces Chromium to reload the certificate since it might be trusted
// now.
cert_db->NotifyObserversCertDBChanged(cert_.get());
callback_.Run();
[self autorelease];
}
@end
namespace certificate_trust {
void ShowCertificateTrust(atom::NativeWindow* parent_window,
const scoped_refptr<net::X509Certificate>& cert,
const std::string& message,
const ShowTrustCallback& callback) {
auto sec_policy = SecPolicyCreateBasicX509();
auto cert_chain = cert->CreateOSCertChainForCert();
SecTrustRef trust = nullptr;
SecTrustCreateWithCertificates(cert_chain, sec_policy, &trust);
NSWindow* window = parent_window ?
parent_window->GetNativeWindow() :
nil;
auto msg = base::SysUTF8ToNSString(message);
auto panel = [[SFCertificateTrustPanel alloc] init];
auto delegate = [[TrustDelegate alloc] initWithCallback:callback
panel:panel
cert:cert
trust:trust
certChain:cert_chain
secPolicy:sec_policy];
[panel beginSheetForWindow:window
modalDelegate:delegate
didEndSelector:@selector(panelDidEnd:returnCode:contextInfo:)
contextInfo:nil
trust:trust
message:msg];
}
} // namespace certificate_trust

View file

@ -0,0 +1,98 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/certificate_trust.h"
#include <wincrypt.h>
#include <windows.h>
#include "base/callback.h"
#include "net/cert/cert_database.h"
namespace certificate_trust {
// Add the provided certificate to the Trusted Root Certificate Authorities
// store for the current user.
//
// This requires prompting the user to confirm they trust the certificate.
BOOL AddToTrustedRootStore(const PCCERT_CONTEXT cert_context,
const scoped_refptr<net::X509Certificate>& cert) {
auto root_cert_store = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"Root");
if (root_cert_store == NULL) {
return false;
}
auto result = CertAddCertificateContextToStore(
root_cert_store,
cert_context,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL);
if (result) {
// force Chromium to reload it's database for this certificate
auto cert_db = net::CertDatabase::GetInstance();
cert_db->NotifyObserversCertDBChanged(cert.get());
}
CertCloseStore(root_cert_store, CERT_CLOSE_STORE_FORCE_FLAG);
return result;
}
CERT_CHAIN_PARA GetCertificateChainParameters() {
CERT_ENHKEY_USAGE enhkey_usage;
enhkey_usage.cUsageIdentifier = 0;
enhkey_usage.rgpszUsageIdentifier = NULL;
CERT_USAGE_MATCH cert_usage;
// ensure the rules are applied to the entire chain
cert_usage.dwType = USAGE_MATCH_TYPE_AND;
cert_usage.Usage = enhkey_usage;
CERT_CHAIN_PARA params = { sizeof(CERT_CHAIN_PARA) };
params.RequestedUsage = cert_usage;
return params;
}
void ShowCertificateTrust(atom::NativeWindow* parent_window,
const scoped_refptr<net::X509Certificate>& cert,
const std::string& message,
const ShowTrustCallback& callback) {
PCCERT_CHAIN_CONTEXT chain_context;
auto cert_context = cert->CreateOSCertChainForCert();
auto params = GetCertificateChainParameters();
if (CertGetCertificateChain(NULL,
cert_context,
NULL,
NULL,
&params,
NULL,
NULL,
&chain_context)) {
auto error_status = chain_context->TrustStatus.dwErrorStatus;
if (error_status == CERT_TRUST_IS_SELF_SIGNED ||
error_status == CERT_TRUST_IS_UNTRUSTED_ROOT) {
// these are the only scenarios we're interested in supporting
AddToTrustedRootStore(cert_context, cert);
}
CertFreeCertificateChain(chain_context);
}
CertFreeCertificateContext(cert_context);
callback.Run();
}
} // namespace certificate_trust

View file

@ -8,6 +8,7 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "base/callback.h"
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
@ -27,6 +28,7 @@ class AtomMenuModel;
base::scoped_nsobject<NSMenu> menu_; base::scoped_nsobject<NSMenu> menu_;
BOOL isMenuOpen_; BOOL isMenuOpen_;
BOOL useDefaultAccelerator_; BOOL useDefaultAccelerator_;
base::Callback<void()> closeCallback;
} }
@property(nonatomic, assign) atom::AtomMenuModel* model; @property(nonatomic, assign) atom::AtomMenuModel* model;
@ -35,6 +37,8 @@ class AtomMenuModel;
// to the contents of the model after calling this will not be noticed. // to the contents of the model after calling this will not be noticed.
- (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use; - (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use;
- (void)setCloseCallback:(const base::Callback<void()>&)callback;
// Populate current NSMenu with |model|. // Populate current NSMenu with |model|.
- (void)populateWithModel:(atom::AtomMenuModel*)model; - (void)populateWithModel:(atom::AtomMenuModel*)model;

View file

@ -12,9 +12,12 @@
#include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h" #include "ui/base/accelerators/platform_accelerator_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/l10n/l10n_util_mac.h"
#include "content/public/browser/browser_thread.h"
#include "ui/events/cocoa/cocoa_event_utils.h" #include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
using content::BrowserThread;
namespace { namespace {
struct Role { struct Role {
@ -67,10 +70,14 @@ Role kRolesMap[] = {
// while its context menu is still open. // while its context menu is still open.
[self cancel]; [self cancel];
model_ = NULL; model_ = nullptr;
[super dealloc]; [super dealloc];
} }
- (void)setCloseCallback:(const base::Callback<void()>&)callback {
closeCallback = callback;
}
- (void)populateWithModel:(atom::AtomMenuModel*)model { - (void)populateWithModel:(atom::AtomMenuModel*)model {
if (!menu_) if (!menu_)
return; return;
@ -265,8 +272,13 @@ Role kRolesMap[] = {
- (void)menuDidClose:(NSMenu*)menu { - (void)menuDidClose:(NSMenu*)menu {
if (isMenuOpen_) { if (isMenuOpen_) {
model_->MenuWillClose();
isMenuOpen_ = NO; isMenuOpen_ = NO;
model_->MenuWillClose();
// Post async task so that itemSelected runs before the close callback
// deletes the controller from the map which deallocates it
if (!closeCallback.is_null())
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, closeCallback);
} }
} }

View file

@ -0,0 +1,66 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_UI_COCOA_ATOM_TOUCH_BAR_H_
#define ATOM_BROWSER_UI_COCOA_ATOM_TOUCH_BAR_H_
#import <Cocoa/Cocoa.h>
#include <map>
#include <string>
#include <vector>
#include "atom/browser/native_window.h"
#include "atom/browser/ui/cocoa/touch_bar_forward_declarations.h"
#include "base/mac/scoped_nsobject.h"
#include "native_mate/constructor.h"
#include "native_mate/persistent_dictionary.h"
@interface AtomTouchBar : NSObject<NSScrubberDelegate, NSScrubberDataSource> {
@protected
std::vector<mate::PersistentDictionary> ordered_settings_;
std::map<std::string, mate::PersistentDictionary> settings_;
id<NSTouchBarDelegate> delegate_;
atom::NativeWindow* window_;
}
- (id)initWithDelegate:(id<NSTouchBarDelegate>)delegate window:(atom::NativeWindow*)window settings:(const std::vector<mate::PersistentDictionary>&)settings;
- (NSTouchBar*)makeTouchBar;
- (NSTouchBar*)touchBarFromItemIdentifiers:(NSMutableArray*)items;
- (NSMutableArray*)identifiersFromSettings:(const std::vector<mate::PersistentDictionary>&)settings;
- (void)refreshTouchBarItem:(NSTouchBar*)touchBar id:(const std::string&)item_id;
- (void)addNonDefaultTouchBarItems:(const std::vector<mate::PersistentDictionary>&)items;
- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item forTouchBar:(NSTouchBar*)touchBar;
- (NSString*)idFromIdentifier:(NSString*)identifier withPrefix:(NSString*)prefix;
- (NSTouchBarItemIdentifier)identifierFromID:(const std::string&)item_id type:(const std::string&)typere;
- (bool)hasItemWithID:(const std::string&)item_id;
- (NSColor*)colorFromHexColorString:(const std::string&)colorString;
// Selector actions
- (void)buttonAction:(id)sender;
- (void)colorPickerAction:(id)sender;
- (void)sliderAction:(id)sender;
// Helpers to create touch bar items
- (NSTouchBarItem*)makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier;
- (NSTouchBarItem*)makeButtonForID:(NSString*)id withIdentifier:(NSString*)identifier;
- (NSTouchBarItem*)makeLabelForID:(NSString*)id withIdentifier:(NSString*)identifier;
- (NSTouchBarItem*)makeColorPickerForID:(NSString*)id withIdentifier:(NSString*)identifier;
- (NSTouchBarItem*)makeSliderForID:(NSString*)id withIdentifier:(NSString*)identifier;
- (NSTouchBarItem*)makePopoverForID:(NSString*)id withIdentifier:(NSString*)identifier;
- (NSTouchBarItem*)makeGroupForID:(NSString*)id withIdentifier:(NSString*)identifier;
// Helpers to update touch bar items
- (void)updateButton:(NSCustomTouchBarItem*)item withSettings:(const mate::PersistentDictionary&)settings;
- (void)updateLabel:(NSCustomTouchBarItem*)item withSettings:(const mate::PersistentDictionary&)settings;
- (void)updateColorPicker:(NSColorPickerTouchBarItem*)item withSettings:(const mate::PersistentDictionary&)settings;
- (void)updateSlider:(NSSliderTouchBarItem*)item withSettings:(const mate::PersistentDictionary&)settings;
- (void)updatePopover:(NSPopoverTouchBarItem*)item withSettings:(const mate::PersistentDictionary&)settings;
@end
#endif // ATOM_BROWSER_UI_COCOA_ATOM_TOUCH_BAR_H_

View file

@ -0,0 +1,669 @@
// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#import "atom/browser/ui/cocoa/atom_touch_bar.h"
#include "atom/common/color_util.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "base/strings/sys_string_conversions.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/gfx/image/image.h"
@implementation AtomTouchBar
static NSTouchBarItemIdentifier ButtonIdentifier = @"com.electron.touchbar.button.";
static NSTouchBarItemIdentifier ColorPickerIdentifier = @"com.electron.touchbar.colorpicker.";
static NSTouchBarItemIdentifier GroupIdentifier = @"com.electron.touchbar.group.";
static NSTouchBarItemIdentifier LabelIdentifier = @"com.electron.touchbar.label.";
static NSTouchBarItemIdentifier PopoverIdentifier = @"com.electron.touchbar.popover.";
static NSTouchBarItemIdentifier SliderIdentifier = @"com.electron.touchbar.slider.";
static NSTouchBarItemIdentifier SegmentedControlIdentifier = @"com.electron.touchbar.segmentedcontrol.";
static NSTouchBarItemIdentifier ScrubberIdentifier = @"com.electron.touchbar.scrubber.";
static NSString* const TextScrubberItemIdentifier = @"scrubber.text.item";
static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
- (id)initWithDelegate:(id<NSTouchBarDelegate>)delegate
window:(atom::NativeWindow*)window
settings:(const std::vector<mate::PersistentDictionary>&)settings {
if ((self = [super init])) {
delegate_ = delegate;
window_ = window;
ordered_settings_ = settings;
}
return self;
}
- (NSTouchBar*)makeTouchBar {
NSMutableArray* identifiers = [self identifiersFromSettings:ordered_settings_];
return [self touchBarFromItemIdentifiers:identifiers];
}
- (NSTouchBar*)touchBarFromItemIdentifiers:(NSMutableArray*)items {
base::scoped_nsobject<NSTouchBar> bar(
[[NSClassFromString(@"NSTouchBar") alloc] init]);
[bar setDelegate:delegate_];
[bar setDefaultItemIdentifiers:items];
return bar.autorelease();
}
- (NSMutableArray*)identifiersFromSettings:(const std::vector<mate::PersistentDictionary>&)dicts {
NSMutableArray* identifiers = [NSMutableArray array];
for (const auto& item : dicts) {
std::string type;
std::string item_id;
if (item.Get("type", &type) && item.Get("id", &item_id)) {
NSTouchBarItemIdentifier identifier = nil;
if (type == "spacer") {
std::string size;
item.Get("size", &size);
if (size == "large") {
identifier = NSTouchBarItemIdentifierFixedSpaceLarge;
} else if (size == "flexible") {
identifier = NSTouchBarItemIdentifierFlexibleSpace;
} else {
identifier = NSTouchBarItemIdentifierFixedSpaceSmall;
}
} else {
identifier = [self identifierFromID:item_id type:type];
}
if (identifier) {
settings_[item_id] = item;
[identifiers addObject:identifier];
}
}
}
[identifiers addObject:NSTouchBarItemIdentifierOtherItemsProxy];
return identifiers;
}
- (NSTouchBarItem*)makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier {
NSString* item_id = nil;
if ([identifier hasPrefix:ButtonIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:ButtonIdentifier];
return [self makeButtonForID:item_id withIdentifier:identifier];
} else if ([identifier hasPrefix:LabelIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:LabelIdentifier];
return [self makeLabelForID:item_id withIdentifier:identifier];
} else if ([identifier hasPrefix:ColorPickerIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:ColorPickerIdentifier];
return [self makeColorPickerForID:item_id withIdentifier:identifier];
} else if ([identifier hasPrefix:SliderIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:SliderIdentifier];
return [self makeSliderForID:item_id withIdentifier:identifier];
} else if ([identifier hasPrefix:PopoverIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:PopoverIdentifier];
return [self makePopoverForID:item_id withIdentifier:identifier];
} else if ([identifier hasPrefix:GroupIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:GroupIdentifier];
return [self makeGroupForID:item_id withIdentifier:identifier];
} else if ([identifier hasPrefix:SegmentedControlIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:SegmentedControlIdentifier];
return [self makeSegmentedControlForID:item_id withIdentifier:identifier];
} else if ([identifier hasPrefix:ScrubberIdentifier]) {
item_id = [self idFromIdentifier:identifier withPrefix:ScrubberIdentifier];
return [self makeScrubberForID:item_id withIdentifier:identifier];
}
return nil;
}
- (void)refreshTouchBarItem:(NSTouchBar*)touchBar
id:(NSTouchBarItemIdentifier)identifier
withType:(const std::string&)item_type
withSettings:(const mate::PersistentDictionary&)settings {
NSTouchBarItem* item = [touchBar itemForIdentifier:identifier];
if (!item) return;
if (item_type == "button") {
[self updateButton:(NSCustomTouchBarItem*)item withSettings:settings];
} else if (item_type == "label") {
[self updateLabel:(NSCustomTouchBarItem*)item withSettings:settings];
} else if (item_type == "colorpicker") {
[self updateColorPicker:(NSColorPickerTouchBarItem*)item
withSettings:settings];
} else if (item_type == "slider") {
[self updateSlider:(NSSliderTouchBarItem*)item withSettings:settings];
} else if (item_type == "popover") {
[self updatePopover:(NSPopoverTouchBarItem*)item withSettings:settings];
} else if (item_type == "segmented_control") {
[self updateSegmentedControl:(NSCustomTouchBarItem*)item withSettings:settings];
} else if (item_type == "scrubber") {
[self updateScrubber:(NSCustomTouchBarItem*)item withSettings:settings];
}
}
- (void)addNonDefaultTouchBarItems:(const std::vector<mate::PersistentDictionary>&)items {
[self identifiersFromSettings:items];
}
- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item forTouchBar:(NSTouchBar*)touchBar {
std::string type;
std::string item_id;
NSTouchBarItemIdentifier identifier = nil;
if (item.Get("type", &type) && item.Get("id", &item_id)) {
identifier = [self identifierFromID:item_id type:type];
}
if (identifier) {
[self addNonDefaultTouchBarItems:{ item }];
touchBar.escapeKeyReplacementItemIdentifier = identifier;
} else {
touchBar.escapeKeyReplacementItemIdentifier = nil;
}
}
- (void)refreshTouchBarItem:(NSTouchBar*)touchBar
id:(const std::string&)item_id {
if (![self hasItemWithID:item_id]) return;
mate::PersistentDictionary settings = settings_[item_id];
std::string item_type;
settings.Get("type", &item_type);
auto identifier = [self identifierFromID:item_id type:item_type];
if (!identifier) return;
std::vector<std::string> popover_ids;
settings.Get("_popover", &popover_ids);
for (auto& popover_id : popover_ids) {
auto popoverIdentifier = [self identifierFromID:popover_id type:"popover"];
if (!popoverIdentifier) continue;
NSPopoverTouchBarItem* popoverItem =
[touchBar itemForIdentifier:popoverIdentifier];
[self refreshTouchBarItem:popoverItem.popoverTouchBar
id:identifier
withType:item_type
withSettings:settings];
}
[self refreshTouchBarItem:touchBar
id:identifier
withType:item_type
withSettings:settings];
}
- (void)buttonAction:(id)sender {
NSString* item_id = [NSString stringWithFormat:@"%ld", ((NSButton*)sender).tag];
window_->NotifyTouchBarItemInteraction([item_id UTF8String],
base::DictionaryValue());
}
- (void)colorPickerAction:(id)sender {
NSString* identifier = ((NSColorPickerTouchBarItem*)sender).identifier;
NSString* item_id = [self idFromIdentifier:identifier
withPrefix:ColorPickerIdentifier];
NSColor* color = ((NSColorPickerTouchBarItem*)sender).color;
std::string hex_color = atom::ToRGBHex(skia::NSDeviceColorToSkColor(color));
base::DictionaryValue details;
details.SetString("color", hex_color);
window_->NotifyTouchBarItemInteraction([item_id UTF8String], details);
}
- (void)sliderAction:(id)sender {
NSString* identifier = ((NSSliderTouchBarItem*)sender).identifier;
NSString* item_id = [self idFromIdentifier:identifier
withPrefix:SliderIdentifier];
base::DictionaryValue details;
details.SetInteger("value",
[((NSSliderTouchBarItem*)sender).slider intValue]);
window_->NotifyTouchBarItemInteraction([item_id UTF8String], details);
}
- (NSString*)idFromIdentifier:(NSString*)identifier
withPrefix:(NSString*)prefix {
return [identifier substringFromIndex:[prefix length]];
}
- (void)segmentedControlAction:(id)sender {
NSString* item_id = [NSString stringWithFormat:@"%ld", ((NSSegmentedControl*)sender).tag];
base::DictionaryValue details;
details.SetInteger("selectedIndex", ((NSSegmentedControl*)sender).selectedSegment);
details.SetBoolean("isSelected", [((NSSegmentedControl*)sender) isSelectedForSegment:((NSSegmentedControl*)sender).selectedSegment]);
window_->NotifyTouchBarItemInteraction([item_id UTF8String],
details);
}
- (void)scrubber:(NSScrubber*)scrubber didSelectItemAtIndex:(NSInteger)selectedIndex {
base::DictionaryValue details;
details.SetInteger("selectedIndex", selectedIndex);
details.SetString("type", "select");
window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String], details);
}
- (void)scrubber:(NSScrubber*)scrubber didHighlightItemAtIndex:(NSInteger)highlightedIndex {
base::DictionaryValue details;
details.SetInteger("highlightedIndex", highlightedIndex);
details.SetString("type", "highlight");
window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String], details);
}
- (NSTouchBarItemIdentifier)identifierFromID:(const std::string&)item_id
type:(const std::string&)type {
NSTouchBarItemIdentifier base_identifier = nil;
if (type == "button")
base_identifier = ButtonIdentifier;
else if (type == "label")
base_identifier = LabelIdentifier;
else if (type == "colorpicker")
base_identifier = ColorPickerIdentifier;
else if (type == "slider")
base_identifier = SliderIdentifier;
else if (type == "popover")
base_identifier = PopoverIdentifier;
else if (type == "group")
base_identifier = GroupIdentifier;
else if (type == "segmented_control")
base_identifier = SegmentedControlIdentifier;
else if (type == "scrubber")
base_identifier = ScrubberIdentifier;
if (base_identifier)
return [NSString stringWithFormat:@"%@%s", base_identifier, item_id.data()];
else
return nil;
}
- (bool)hasItemWithID:(const std::string&)item_id {
return settings_.find(item_id) != settings_.end();
}
- (NSColor*)colorFromHexColorString:(const std::string&)colorString {
SkColor color = atom::ParseHexColor(colorString);
return skia::SkColorToDeviceNSColor(color);
}
- (NSTouchBarItem*)makeButtonForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
NSButton* button = [NSButton buttonWithTitle:@""
target:self
action:@selector(buttonAction:)];
button.tag = [id floatValue];
[item setView:button];
[self updateButton:item withSettings:settings];
return item.autorelease();
}
- (void)updateButton:(NSCustomTouchBarItem*)item
withSettings:(const mate::PersistentDictionary&)settings {
NSButton* button = (NSButton*)item.view;
std::string backgroundColor;
if (settings.Get("backgroundColor", &backgroundColor)) {
button.bezelColor = [self colorFromHexColorString:backgroundColor];
}
std::string label;
settings.Get("label", &label);
button.title = base::SysUTF8ToNSString(label);
gfx::Image image;
if (settings.Get("icon", &image)) {
button.image = image.AsNSImage();
std::string iconPosition;
settings.Get("iconPosition", &iconPosition);
if (iconPosition == "left") {
button.imagePosition = NSImageLeft;
} else if (iconPosition == "right") {
button.imagePosition = NSImageRight;
} else {
button.imagePosition = NSImageOverlaps;
}
}
}
- (NSTouchBarItem*)makeLabelForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
[item setView:[NSTextField labelWithString:@""]];
[self updateLabel:item withSettings:settings];
return item.autorelease();
}
- (void)updateLabel:(NSCustomTouchBarItem*)item
withSettings:(const mate::PersistentDictionary&)settings {
NSTextField* text_field = (NSTextField*)item.view;
std::string label;
settings.Get("label", &label);
text_field.stringValue = base::SysUTF8ToNSString(label);
std::string textColor;
if (settings.Get("textColor", &textColor) && !textColor.empty()) {
text_field.textColor = [self colorFromHexColorString:textColor];
} else {
text_field.textColor = nil;
}
}
- (NSTouchBarItem*)makeColorPickerForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
base::scoped_nsobject<NSColorPickerTouchBarItem> item([[NSClassFromString(
@"NSColorPickerTouchBarItem") alloc] initWithIdentifier:identifier]);
[item setTarget:self];
[item setAction:@selector(colorPickerAction:)];
[self updateColorPicker:item withSettings:settings];
return item.autorelease();
}
- (void)updateColorPicker:(NSColorPickerTouchBarItem*)item
withSettings:(const mate::PersistentDictionary&)settings {
std::vector<std::string> colors;
if (settings.Get("availableColors", &colors) && !colors.empty()) {
NSColorList* color_list = [[[NSColorList alloc] initWithName:@""] autorelease];
for (size_t i = 0; i < colors.size(); ++i) {
[color_list insertColor:[self colorFromHexColorString:colors[i]]
key:base::SysUTF8ToNSString(colors[i])
atIndex:i];
}
item.colorList = color_list;
}
std::string selectedColor;
if (settings.Get("selectedColor", &selectedColor)) {
item.color = [self colorFromHexColorString:selectedColor];
}
}
- (NSTouchBarItem*)makeSliderForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
base::scoped_nsobject<NSSliderTouchBarItem> item([[NSClassFromString(
@"NSSliderTouchBarItem") alloc] initWithIdentifier:identifier]);
[item setTarget:self];
[item setAction:@selector(sliderAction:)];
[self updateSlider:item withSettings:settings];
return item.autorelease();
}
- (void)updateSlider:(NSSliderTouchBarItem*)item
withSettings:(const mate::PersistentDictionary&)settings {
std::string label;
settings.Get("label", &label);
item.label = base::SysUTF8ToNSString(label);
int maxValue = 100;
int minValue = 0;
int value = 50;
settings.Get("minValue", &minValue);
settings.Get("maxValue", &maxValue);
settings.Get("value", &value);
item.slider.minValue = minValue;
item.slider.maxValue = maxValue;
item.slider.doubleValue = value;
}
- (NSTouchBarItem*)makePopoverForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
base::scoped_nsobject<NSPopoverTouchBarItem> item([[NSClassFromString(
@"NSPopoverTouchBarItem") alloc] initWithIdentifier:identifier]);
[self updatePopover:item withSettings:settings];
return item.autorelease();
}
- (void)updatePopover:(NSPopoverTouchBarItem*)item
withSettings:(const mate::PersistentDictionary&)settings {
std::string label;
settings.Get("label", &label);
item.collapsedRepresentationLabel = base::SysUTF8ToNSString(label);
gfx::Image image;
if (settings.Get("icon", &image)) {
item.collapsedRepresentationImage = image.AsNSImage();
}
bool showCloseButton = true;
settings.Get("showCloseButton", &showCloseButton);
item.showsCloseButton = showCloseButton;
mate::PersistentDictionary child;
std::vector<mate::PersistentDictionary> items;
if (settings.Get("child", &child) && child.Get("ordereredItems", &items)) {
item.popoverTouchBar = [self touchBarFromItemIdentifiers:[self identifiersFromSettings:items]];
}
}
- (NSTouchBarItem*)makeGroupForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
mate::PersistentDictionary child;
if (!settings.Get("child", &child)) return nil;
std::vector<mate::PersistentDictionary> items;
if (!child.Get("ordereredItems", &items)) return nil;
NSMutableArray* generatedItems = [NSMutableArray array];
NSMutableArray* identifiers = [self identifiersFromSettings:items];
for (NSUInteger i = 0; i < [identifiers count]; ++i) {
if ([identifiers objectAtIndex:i] != NSTouchBarItemIdentifierOtherItemsProxy) {
NSTouchBarItem* generatedItem = [self makeItemForIdentifier:[identifiers objectAtIndex:i]];
if (generatedItem) {
[generatedItems addObject:generatedItem];
}
}
}
return [NSClassFromString(@"NSGroupTouchBarItem") groupItemWithIdentifier:identifier
items:generatedItems];
}
- (NSTouchBarItem*)makeSegmentedControlForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
NSSegmentedControl* control = [NSSegmentedControl segmentedControlWithLabels:[NSMutableArray array]
trackingMode:NSSegmentSwitchTrackingSelectOne
target:self
action:@selector(segmentedControlAction:)];
control.tag = [id floatValue];
[item setView:control];
[self updateSegmentedControl:item withSettings:settings];
return item.autorelease();
}
- (void)updateSegmentedControl:(NSCustomTouchBarItem*)item
withSettings:(const mate::PersistentDictionary&)settings {
NSSegmentedControl* control = item.view;
std::string segmentStyle;
settings.Get("segmentStyle", &segmentStyle);
if (segmentStyle == "rounded")
control.segmentStyle = NSSegmentStyleRounded;
else if (segmentStyle == "textured-rounded")
control.segmentStyle = NSSegmentStyleTexturedRounded;
else if (segmentStyle == "round-rect")
control.segmentStyle = NSSegmentStyleRoundRect;
else if (segmentStyle == "textured-square")
control.segmentStyle = NSSegmentStyleTexturedSquare;
else if (segmentStyle == "capsule")
control.segmentStyle = NSSegmentStyleCapsule;
else if (segmentStyle == "small-square")
control.segmentStyle = NSSegmentStyleSmallSquare;
else if (segmentStyle == "separated")
control.segmentStyle = NSSegmentStyleSeparated;
else
control.segmentStyle = NSSegmentStyleAutomatic;
std::string segmentMode;
settings.Get("mode", &segmentMode);
if (segmentMode == "multiple")
control.trackingMode = NSSegmentSwitchTrackingSelectAny;
else if (segmentMode == "buttons")
control.trackingMode = NSSegmentSwitchTrackingMomentary;
else
control.trackingMode = NSSegmentSwitchTrackingSelectOne;
std::vector<mate::Dictionary> segments;
settings.Get("segments", &segments);
control.segmentCount = segments.size();
for (size_t i = 0; i < segments.size(); ++i) {
std::string label;
gfx::Image image;
bool enabled = true;
segments[i].Get("enabled", &enabled);
if (segments[i].Get("label", &label)) {
[control setLabel:base::SysUTF8ToNSString(label) forSegment:i];
} else if (segments[i].Get("icon", &image)) {
[control setImage:image.AsNSImage() forSegment:i];
[control setImageScaling:NSImageScaleProportionallyUpOrDown forSegment:i];
}
[control setEnabled:enabled forSegment:i];
}
int selectedIndex = 0;
settings.Get("selectedIndex", &selectedIndex);
if (selectedIndex >= 0 && selectedIndex < control.segmentCount)
control.selectedSegment = selectedIndex;
}
- (NSTouchBarItem*)makeScrubberForID:(NSString*)id
withIdentifier:(NSString*)identifier {
std::string s_id([id UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
NSScrubber* scrubber = [[[NSClassFromString(@"NSScrubber") alloc] initWithFrame:NSZeroRect] autorelease];
[scrubber registerClass:NSClassFromString(@"NSScrubberTextItemView") forItemIdentifier:TextScrubberItemIdentifier];
[scrubber registerClass:NSClassFromString(@"NSScrubberImageItemView") forItemIdentifier:ImageScrubberItemIdentifier];
scrubber.delegate = self;
scrubber.dataSource = self;
scrubber.identifier = id;
[item setView:scrubber];
[self updateScrubber:item withSettings:settings];
return item.autorelease();
}
- (void)updateScrubber:(NSCustomTouchBarItem*)item
withSettings:(const mate::PersistentDictionary&)settings {
NSScrubber* scrubber = item.view;
bool showsArrowButtons = false;
settings.Get("showArrowButtons", &showsArrowButtons);
scrubber.showsArrowButtons = showsArrowButtons;
std::string selectedStyle;
std::string overlayStyle;
settings.Get("selectedStyle", &selectedStyle);
settings.Get("overlayStyle", &overlayStyle);
if (selectedStyle == "outline") {
scrubber.selectionBackgroundStyle = [NSClassFromString(@"NSScrubberSelectionStyle") outlineOverlayStyle];
} else if (selectedStyle == "background") {
scrubber.selectionBackgroundStyle = [NSClassFromString(@"NSScrubberSelectionStyle") roundedBackgroundStyle];
} else {
scrubber.selectionBackgroundStyle = nil;
}
if (overlayStyle == "outline") {
scrubber.selectionOverlayStyle = [NSClassFromString(@"NSScrubberSelectionStyle") outlineOverlayStyle];
} else if (overlayStyle == "background") {
scrubber.selectionOverlayStyle = [NSClassFromString(@"NSScrubberSelectionStyle") roundedBackgroundStyle];
} else {
scrubber.selectionOverlayStyle = nil;
}
std::string mode;
settings.Get("mode", &mode);
if (mode == "fixed") {
scrubber.mode = NSScrubberModeFixed;
} else {
scrubber.mode = NSScrubberModeFree;
}
bool continuous = true;
settings.Get("continuous", &continuous);
scrubber.continuous = continuous;
[scrubber reloadData];
}
- (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber {
std::string s_id([[scrubber identifier] UTF8String]);
if (![self hasItemWithID:s_id]) return 0;
mate::PersistentDictionary settings = settings_[s_id];
std::vector<mate::PersistentDictionary> items;
settings.Get("items", &items);
return items.size();
}
- (NSScrubberItemView*)scrubber:(NSScrubber*)scrubber
viewForItemAtIndex:(NSInteger)index {
std::string s_id([[scrubber identifier] UTF8String]);
if (![self hasItemWithID:s_id]) return nil;
mate::PersistentDictionary settings = settings_[s_id];
std::vector<mate::PersistentDictionary> items;
if (!settings.Get("items", &items)) return nil;
if (index >= static_cast<NSInteger>(items.size())) return nil;
mate::PersistentDictionary item = items[index];
NSScrubberItemView* itemView;
std::string title;
if (item.Get("label", &title)) {
NSScrubberTextItemView* view = [scrubber makeItemWithIdentifier:TextScrubberItemIdentifier
owner:self];
view.title = base::SysUTF8ToNSString(title);
itemView = view;
} else {
NSScrubberImageItemView* view = [scrubber makeItemWithIdentifier:ImageScrubberItemIdentifier
owner:self];
gfx::Image image;
if (item.Get("icon", &image)) {
view.image = image.AsNSImage();
}
itemView = view;
}
return itemView;
}
@end

View file

@ -0,0 +1,251 @@
// Copyright 2016 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 ATOM_BROWSER_UI_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_
#define ATOM_BROWSER_UI_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_
// Once Chrome no longer supports OSX 10.12.0, this file can be deleted.
#import <Foundation/Foundation.h>
#if !defined(MAC_OS_X_VERSION_10_12_1)
#pragma clang assume_nonnull begin
@class NSTouchBar, NSTouchBarItem;
@class NSScrubber, NSScrubberItemView, NSScrubberArrangedView, NSScrubberTextItemView, NSScrubberImageItemView, NSScrubberSelectionStyle;
@protocol NSTouchBarDelegate, NSScrubberDelegate, NSScrubberDataSource;
typedef float NSTouchBarItemPriority;
static const NSTouchBarItemPriority NSTouchBarItemPriorityHigh = 1000;
static const NSTouchBarItemPriority NSTouchBarItemPriorityNormal = 0;
static const NSTouchBarItemPriority NSTouchBarItemPriorityLow = -1000;
enum NSScrubberMode {
NSScrubberModeFixed = 0,
NSScrubberModeFree
};
typedef NSString* NSTouchBarItemIdentifier;
typedef NSString* NSTouchBarCustomizationIdentifier;
static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierFixedSpaceSmall =
@"NSTouchBarItemIdentifierFixedSpaceSmall";
static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierFixedSpaceLarge =
@"NSTouchBarItemIdentifierFixedSpaceLarge";
static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierFlexibleSpace =
@"NSTouchBarItemIdentifierFlexibleSpace";
static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierOtherItemsProxy =
@"NSTouchBarItemIdentifierOtherItemsProxy";
@interface NSTouchBar : NSObject<NSCoding>
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder*)aDecoder
NS_DESIGNATED_INITIALIZER;
@property(copy, nullable)
NSTouchBarCustomizationIdentifier customizationIdentifier;
@property(copy) NSArray* customizationAllowedItemIdentifiers;
@property(copy) NSArray* customizationRequiredItemIdentifiers;
@property(copy) NSArray* defaultItemIdentifiers;
@property(copy, readonly) NSArray* itemIdentifiers;
@property(copy, nullable) NSTouchBarItemIdentifier principalItemIdentifier;
@property(copy, nullable) NSTouchBarItemIdentifier escapeKeyReplacementItemIdentifier;
@property(copy) NSSet* templateItems;
@property(nullable, weak) id<NSTouchBarDelegate> delegate;
- (nullable __kindof NSTouchBarItem*)itemForIdentifier:
(NSTouchBarItemIdentifier)identifier;
@property(readonly, getter=isVisible) BOOL visible;
@end
@interface NSTouchBarItem : NSObject<NSCoding>
- (instancetype)initWithIdentifier:(NSTouchBarItemIdentifier)identifier
NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder*)coder
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@property(readonly, copy) NSTouchBarItemIdentifier identifier;
@property NSTouchBarItemPriority visibilityPriority;
@property(readonly, nullable) NSView* view;
@property(readonly, nullable) NSViewController* viewController;
@property(readwrite, copy) NSString* customizationLabel;
@property(readonly, getter=isVisible) BOOL visible;
@end
@interface NSGroupTouchBarItem : NSTouchBarItem
+ (NSGroupTouchBarItem*)groupItemWithIdentifier:
(NSTouchBarItemIdentifier)identifier
items:(NSArray*)items;
@property(strong) NSTouchBar* groupTouchBar;
@property(readwrite, copy, null_resettable) NSString* customizationLabel;
@end
@interface NSCustomTouchBarItem : NSTouchBarItem
@property(readwrite, strong) __kindof NSView* view;
@property(readwrite, strong, nullable)
__kindof NSViewController* viewController;
@property(readwrite, copy, null_resettable) NSString* customizationLabel;
@end
@interface NSColorPickerTouchBarItem : NSTouchBarItem
@property SEL action;
@property(weak) id target;
@property(copy) NSColor* color;
@property(strong) NSColorList* colorList;
@end
@interface NSPopoverTouchBarItem : NSTouchBarItem
@property BOOL showsCloseButton;
@property(strong) NSImage* collapsedRepresentationImage;
@property(strong) NSString* collapsedRepresentationLabel;
@property(strong) NSTouchBar* popoverTouchBar;
@end
@interface NSSliderTouchBarItem : NSTouchBarItem
@property SEL action;
@property(weak) id target;
@property(copy) NSString* label;
@property(strong) NSSlider* slider;
@end
@interface NSScrubber : NSView
@property(weak) id<NSScrubberDelegate> delegate;
@property(weak) id<NSScrubberDataSource> dataSource;
@property NSScrubberMode mode;
@property BOOL showsArrowButtons;
@property(getter=isContinuous) BOOL continuous;
@property(strong, nullable) NSScrubberSelectionStyle* selectionBackgroundStyle;
@property(strong, nullable) NSScrubberSelectionStyle* selectionOverlayStyle;
- (void)registerClass:(Class)itemViewClass
forItemIdentifier:(NSString*)itemIdentifier;
- (__kindof NSScrubberItemView*)makeItemWithIdentifier:(NSString*)itemIdentifier
owner:(id)owner;
- (void)reloadData;
@end
@interface NSScrubberSelectionStyle : NSObject<NSCoding>
@property(class, strong, readonly) NSScrubberSelectionStyle* outlineOverlayStyle;
@property(class, strong, readonly) NSScrubberSelectionStyle* roundedBackgroundStyle;
@end
@interface NSScrubberArrangedView : NSView
@end
@interface NSScrubberItemView : NSScrubberArrangedView
@end
@interface NSScrubberTextItemView : NSScrubberItemView
@property(copy) NSString* title;
@end
@interface NSScrubberImageItemView : NSScrubberItemView
@property(copy) NSImage* image;
@end
@interface NSWindow (TouchBarSDK)
@property(strong, readwrite, nullable) NSTouchBar* touchBar;
@end
@interface NSButton (TouchBarSDK)
@property(copy) NSColor* bezelColor;
+ (instancetype)buttonWithTitle:(NSString*)title
target:(id)target
action:(SEL)action;
@end
@interface NSTextField (TouchBarSDK)
+ (instancetype)labelWithString:(NSString*)stringValue;
@end
@interface NSSegmentedControl (TouchBarSDK)
+ (instancetype)segmentedControlWithLabels:(NSArray*)labels
trackingMode:(NSSegmentSwitchTracking)trackingMode
target:(id)target
action:(SEL)action;
@end
@protocol NSTouchBarDelegate<NSObject>
@optional
- (nullable NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier;
@end
@protocol NSScrubberDelegate<NSObject>
- (void)scrubber:(NSScrubber*)scrubber didHighlightItemAtIndex:(NSInteger)highlightedIndex;
- (void)scrubber:(NSScrubber*)scrubber didSelectItemAtIndex:(NSInteger)selectedIndex;
@end
@protocol NSScrubberDataSource<NSObject>
- (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber;
- (__kindof NSScrubberItemView*)scrubber:(NSScrubber*)scrubber
viewForItemAtIndex:(NSInteger)index;
@end
#pragma clang assume_nonnull end
#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1
// When compiling against the 10.12.1 SDK or later, just provide forward
// declarations to suppress the partial availability warnings.
@class NSCustomTouchBarItem;
@class NSGroupTouchBarItem;
@class NSTouchBar;
@protocol NSTouchBarDelegate;
@class NSTouchBarItem;
@interface NSWindow (TouchBarSDK)
@property(strong, readonly) NSTouchBar* touchBar;
@end
#endif // MAC_OS_X_VERSION_10_12_1
#endif // ATOM_BROWSER_UI_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_

View file

@ -23,12 +23,13 @@ typedef std::pair<std::string, std::vector<std::string> > Filter;
typedef std::vector<Filter> Filters; typedef std::vector<Filter> Filters;
enum FileDialogProperty { enum FileDialogProperty {
FILE_DIALOG_OPEN_FILE = 1 << 0, FILE_DIALOG_OPEN_FILE = 1 << 0,
FILE_DIALOG_OPEN_DIRECTORY = 1 << 1, FILE_DIALOG_OPEN_DIRECTORY = 1 << 1,
FILE_DIALOG_MULTI_SELECTIONS = 1 << 2, FILE_DIALOG_MULTI_SELECTIONS = 1 << 2,
FILE_DIALOG_CREATE_DIRECTORY = 1 << 3, FILE_DIALOG_CREATE_DIRECTORY = 1 << 3,
FILE_DIALOG_SHOW_HIDDEN_FILES = 1 << 4, FILE_DIALOG_SHOW_HIDDEN_FILES = 1 << 4,
FILE_DIALOG_PROMPT_TO_CREATE = 1 << 5, FILE_DIALOG_PROMPT_TO_CREATE = 1 << 5,
FILE_DIALOG_NO_RESOLVE_ALIASES = 1 << 6,
}; };
typedef base::Callback<void( typedef base::Callback<void(
@ -37,34 +38,28 @@ typedef base::Callback<void(
typedef base::Callback<void( typedef base::Callback<void(
bool result, const base::FilePath& path)> SaveDialogCallback; bool result, const base::FilePath& path)> SaveDialogCallback;
bool ShowOpenDialog(atom::NativeWindow* parent_window, struct DialogSettings {
const std::string& title, atom::NativeWindow* parent_window = nullptr;
const std::string& button_label, std::string title;
const base::FilePath& default_path, std::string message;
const Filters& filters, std::string button_label;
int properties, std::string name_field_label;
base::FilePath default_path;
Filters filters;
int properties = 0;
bool shows_tag_field = true;
};
bool ShowOpenDialog(const DialogSettings& settings,
std::vector<base::FilePath>* paths); std::vector<base::FilePath>* paths);
void ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& callback); const OpenDialogCallback& callback);
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
base::FilePath* path); base::FilePath* path);
void ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& callback); const SaveDialogCallback& callback);
} // namespace file_dialog } // namespace file_dialog

View file

@ -36,24 +36,20 @@ void OnFileFilterDataDestroyed(std::string* file_extension) {
class FileChooserDialog { class FileChooserDialog {
public: public:
FileChooserDialog(GtkFileChooserAction action, FileChooserDialog(GtkFileChooserAction action,
atom::NativeWindow* parent_window, const DialogSettings& settings)
const std::string& title, : parent_(static_cast<atom::NativeWindowViews*>(settings.parent_window)),
const std::string& button_label, filters_(settings.filters) {
const base::FilePath& default_path,
const Filters& filters)
: parent_(static_cast<atom::NativeWindowViews*>(parent_window)),
filters_(filters) {
const char* confirm_text = GTK_STOCK_OK; const char* confirm_text = GTK_STOCK_OK;
if (!button_label.empty()) if (!settings.button_label.empty())
confirm_text = button_label.c_str(); confirm_text = settings.button_label.c_str();
else if (action == GTK_FILE_CHOOSER_ACTION_SAVE) else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
confirm_text = GTK_STOCK_SAVE; confirm_text = GTK_STOCK_SAVE;
else if (action == GTK_FILE_CHOOSER_ACTION_OPEN) else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
confirm_text = GTK_STOCK_OPEN; confirm_text = GTK_STOCK_OPEN;
dialog_ = gtk_file_chooser_dialog_new( dialog_ = gtk_file_chooser_dialog_new(
title.c_str(), settings.title.c_str(),
NULL, NULL,
action, action,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
@ -71,20 +67,20 @@ class FileChooserDialog {
if (action != GTK_FILE_CHOOSER_ACTION_OPEN) if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE); gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE);
if (!default_path.empty()) { if (!settings.default_path.empty()) {
if (base::DirectoryExists(default_path)) { if (base::DirectoryExists(settings.default_path)) {
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_), gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_),
default_path.value().c_str()); settings.default_path.value().c_str());
} else { } else {
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_), gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_),
default_path.DirName().value().c_str()); settings.default_path.DirName().value().c_str());
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog_), gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog_),
default_path.BaseName().value().c_str()); settings.default_path.BaseName().value().c_str());
} }
} }
if (!filters.empty()) if (!settings.filters.empty())
AddFilters(filters); AddFilters(settings.filters);
} }
~FileChooserDialog() { ~FileChooserDialog() {
@ -230,19 +226,13 @@ base::FilePath FileChooserDialog::AddExtensionForFilename(
} // namespace } // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
std::vector<base::FilePath>* paths) { std::vector<base::FilePath>* paths) {
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
if (properties & FILE_DIALOG_OPEN_DIRECTORY) if (settings.properties & FILE_DIALOG_OPEN_DIRECTORY)
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
FileChooserDialog open_dialog(action, parent_window, title, button_label, FileChooserDialog open_dialog(action, settings);
default_path, filters); open_dialog.SetupProperties(settings.properties);
open_dialog.SetupProperties(properties);
gtk_widget_show_all(open_dialog.dialog()); gtk_widget_show_all(open_dialog.dialog());
int response = gtk_dialog_run(GTK_DIALOG(open_dialog.dialog())); int response = gtk_dialog_run(GTK_DIALOG(open_dialog.dialog()));
@ -254,30 +244,19 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
} }
} }
void ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& callback) { const OpenDialogCallback& callback) {
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
if (properties & FILE_DIALOG_OPEN_DIRECTORY) if (settings.properties & FILE_DIALOG_OPEN_DIRECTORY)
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
FileChooserDialog* open_dialog = new FileChooserDialog( FileChooserDialog* open_dialog = new FileChooserDialog(action, settings);
action, parent_window, title, button_label, default_path, filters); open_dialog->SetupProperties(settings.properties);
open_dialog->SetupProperties(properties);
open_dialog->RunOpenAsynchronous(callback); open_dialog->RunOpenAsynchronous(callback);
} }
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
base::FilePath* path) { base::FilePath* path) {
FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
title, button_label, default_path, filters);
gtk_widget_show_all(save_dialog.dialog()); gtk_widget_show_all(save_dialog.dialog());
int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog())); int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog()));
if (response == GTK_RESPONSE_ACCEPT) { if (response == GTK_RESPONSE_ACCEPT) {
@ -288,15 +267,10 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
} }
} }
void ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& callback) { const SaveDialogCallback& callback) {
FileChooserDialog* save_dialog = new FileChooserDialog( FileChooserDialog* save_dialog = new FileChooserDialog(
GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, button_label, GTK_FILE_CHOOSER_ACTION_SAVE, settings);
default_path, filters);
save_dialog->RunSaveAsynchronous(callback); save_dialog->RunSaveAsynchronous(callback);
} }

View file

@ -44,25 +44,31 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
} }
void SetupDialog(NSSavePanel* dialog, void SetupDialog(NSSavePanel* dialog,
const std::string& title, const DialogSettings& settings) {
const std::string& button_label, if (!settings.title.empty())
const base::FilePath& default_path, [dialog setTitle:base::SysUTF8ToNSString(settings.title)];
const Filters& filters) {
if (!title.empty())
[dialog setTitle:base::SysUTF8ToNSString(title)];
if (!button_label.empty()) if (!settings.button_label.empty())
[dialog setPrompt:base::SysUTF8ToNSString(button_label)]; [dialog setPrompt:base::SysUTF8ToNSString(settings.button_label)];
if (!settings.message.empty())
[dialog setMessage:base::SysUTF8ToNSString(settings.message)];
if (!settings.name_field_label.empty())
[dialog setNameFieldLabel:base::SysUTF8ToNSString(settings.name_field_label)];
[dialog setShowsTagField:settings.shows_tag_field];
NSString* default_dir = nil; NSString* default_dir = nil;
NSString* default_filename = nil; NSString* default_filename = nil;
if (!default_path.empty()) { if (!settings.default_path.empty()) {
if (base::DirectoryExists(default_path)) { if (base::DirectoryExists(settings.default_path)) {
default_dir = base::SysUTF8ToNSString(default_path.value()); default_dir = base::SysUTF8ToNSString(settings.default_path.value());
} else { } else {
default_dir = base::SysUTF8ToNSString(default_path.DirName().value()); default_dir =
base::SysUTF8ToNSString(settings.default_path.DirName().value());
default_filename = default_filename =
base::SysUTF8ToNSString(default_path.BaseName().value()); base::SysUTF8ToNSString(settings.default_path.BaseName().value());
} }
} }
@ -71,10 +77,10 @@ void SetupDialog(NSSavePanel* dialog,
if (default_filename) if (default_filename)
[dialog setNameFieldStringValue:default_filename]; [dialog setNameFieldStringValue:default_filename];
if (filters.empty()) if (settings.filters.empty())
[dialog setAllowsOtherFileTypes:YES]; [dialog setAllowsOtherFileTypes:YES];
else else
SetAllowedFileTypes(dialog, filters); SetAllowedFileTypes(dialog, settings.filters);
} }
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) { void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
@ -87,6 +93,8 @@ void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
[dialog setAllowsMultipleSelection:YES]; [dialog setAllowsMultipleSelection:YES];
if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES) if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES)
[dialog setShowsHiddenFiles:YES]; [dialog setShowsHiddenFiles:YES];
if (properties & FILE_DIALOG_NO_RESOLVE_ALIASES)
[dialog setResolvesAliases:NO];
} }
// Run modal dialog with parent window and return user's choice. // Run modal dialog with parent window and return user's choice.
@ -117,20 +125,15 @@ void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
} // namespace } // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
std::vector<base::FilePath>* paths) { std::vector<base::FilePath>* paths) {
DCHECK(paths); DCHECK(paths);
NSOpenPanel* dialog = [NSOpenPanel openPanel]; NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, button_label, default_path, filters); SetupDialog(dialog, settings);
SetupDialogForProperties(dialog, properties); SetupDialogForProperties(dialog, settings.properties);
int chosen = RunModalDialog(dialog, parent_window); int chosen = RunModalDialog(dialog, settings.parent_window);
if (chosen == NSFileHandlingPanelCancelButton) if (chosen == NSFileHandlingPanelCancelButton)
return false; return false;
@ -138,23 +141,20 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& c) { const OpenDialogCallback& c) {
NSOpenPanel* dialog = [NSOpenPanel openPanel]; NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, button_label, default_path, filters); SetupDialog(dialog, settings);
SetupDialogForProperties(dialog, properties); SetupDialogForProperties(dialog, settings.properties);
// Duplicate the callback object here since c is a reference and gcd would // Duplicate the callback object here since c is a reference and gcd would
// only store the pointer, by duplication we can force gcd to store a copy. // only store the pointer, by duplication we can force gcd to store a copy.
__block OpenDialogCallback callback = c; __block OpenDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL; NSWindow* window = settings.parent_window ?
settings.parent_window->GetNativeWindow() :
nullptr;
[dialog beginSheetModalForWindow:window [dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) { completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) { if (chosen == NSFileHandlingPanelCancelButton) {
@ -167,18 +167,14 @@ void ShowOpenDialog(atom::NativeWindow* parent_window,
}]; }];
} }
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
base::FilePath* path) { base::FilePath* path) {
DCHECK(path); DCHECK(path);
NSSavePanel* dialog = [NSSavePanel savePanel]; NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, button_label, default_path, filters); SetupDialog(dialog, settings);
int chosen = RunModalDialog(dialog, parent_window); int chosen = RunModalDialog(dialog, settings.parent_window);
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL]) if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
return false; return false;
@ -186,20 +182,18 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& c) { const SaveDialogCallback& c) {
NSSavePanel* dialog = [NSSavePanel savePanel]; NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, button_label, default_path, filters); SetupDialog(dialog, settings);
[dialog setCanSelectHiddenExtension:YES]; [dialog setCanSelectHiddenExtension:YES];
__block SaveDialogCallback callback = c; __block SaveDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL; NSWindow* window = settings.parent_window ?
settings.parent_window->GetNativeWindow() :
nullptr;
[dialog beginSheetModalForWindow:window [dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) { completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) { if (chosen == NSFileHandlingPanelCancelButton) {

View file

@ -66,26 +66,24 @@ void ConvertFilters(const Filters& filters,
template <typename T> template <typename T>
class FileDialog { class FileDialog {
public: public:
FileDialog(const base::FilePath& default_path, FileDialog(const DialogSettings& settings, int options) {
const std::string& title,
const std::string& button_label,
const Filters& filters, int options) {
std::wstring file_part; std::wstring file_part;
if (!IsDirectory(default_path)) if (!IsDirectory(settings.default_path))
file_part = default_path.BaseName().value(); file_part = settings.default_path.BaseName().value();
std::vector<std::wstring> buffer; std::vector<std::wstring> buffer;
std::vector<COMDLG_FILTERSPEC> filterspec; std::vector<COMDLG_FILTERSPEC> filterspec;
ConvertFilters(filters, &buffer, &filterspec); ConvertFilters(settings.filters, &buffer, &filterspec);
dialog_.reset(new T(file_part.c_str(), options, NULL, dialog_.reset(new T(file_part.c_str(), options, NULL,
filterspec.data(), filterspec.size())); filterspec.data(), filterspec.size()));
if (!title.empty()) if (!settings.title.empty())
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str()); GetPtr()->SetTitle(base::UTF8ToUTF16(settings.title).c_str());
if (!button_label.empty()) if (!settings.button_label.empty())
GetPtr()->SetOkButtonLabel(base::UTF8ToUTF16(button_label).c_str()); GetPtr()->SetOkButtonLabel(
base::UTF8ToUTF16(settings.button_label).c_str());
// By default, *.* will be added to the file name if file type is "*.*". In // By default, *.* will be added to the file name if file type is "*.*". In
// Electron, we disable it to make a better experience. // Electron, we disable it to make a better experience.
@ -107,7 +105,7 @@ class FileDialog {
} }
} }
SetDefaultFolder(default_path); SetDefaultFolder(settings.default_path);
} }
bool Show(atom::NativeWindow* parent_window) { bool Show(atom::NativeWindow* parent_window) {
@ -160,31 +158,20 @@ bool CreateDialogThread(RunState* run_state) {
} }
void RunOpenDialogInNewThread(const RunState& run_state, void RunOpenDialogInNewThread(const RunState& run_state,
atom::NativeWindow* parent, const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& callback) { const OpenDialogCallback& callback) {
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
bool result = ShowOpenDialog(parent, title, button_label, default_path, bool result = ShowOpenDialog(settings, &paths);
filters, properties, &paths);
run_state.ui_task_runner->PostTask(FROM_HERE, run_state.ui_task_runner->PostTask(FROM_HERE,
base::Bind(callback, result, paths)); base::Bind(callback, result, paths));
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread); run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
} }
void RunSaveDialogInNewThread(const RunState& run_state, void RunSaveDialogInNewThread(const RunState& run_state,
atom::NativeWindow* parent, const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& callback) { const SaveDialogCallback& callback) {
base::FilePath path; base::FilePath path;
bool result = ShowSaveDialog(parent, title, button_label, default_path, bool result = ShowSaveDialog(settings, &path);
filters, &path);
run_state.ui_task_runner->PostTask(FROM_HERE, run_state.ui_task_runner->PostTask(FROM_HERE,
base::Bind(callback, result, path)); base::Bind(callback, result, path));
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread); run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
@ -192,26 +179,20 @@ void RunSaveDialogInNewThread(const RunState& run_state,
} // namespace } // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
std::vector<base::FilePath>* paths) { std::vector<base::FilePath>* paths) {
int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST; int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
if (properties & FILE_DIALOG_OPEN_DIRECTORY) if (settings.properties & FILE_DIALOG_OPEN_DIRECTORY)
options |= FOS_PICKFOLDERS; options |= FOS_PICKFOLDERS;
if (properties & FILE_DIALOG_MULTI_SELECTIONS) if (settings.properties & FILE_DIALOG_MULTI_SELECTIONS)
options |= FOS_ALLOWMULTISELECT; options |= FOS_ALLOWMULTISELECT;
if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES) if (settings.properties & FILE_DIALOG_SHOW_HIDDEN_FILES)
options |= FOS_FORCESHOWHIDDEN; options |= FOS_FORCESHOWHIDDEN;
if (properties & FILE_DIALOG_PROMPT_TO_CREATE) if (settings.properties & FILE_DIALOG_PROMPT_TO_CREATE)
options |= FOS_CREATEPROMPT; options |= FOS_CREATEPROMPT;
FileDialog<CShellFileOpenDialog> open_dialog( FileDialog<CShellFileOpenDialog> open_dialog(settings, options);
default_path, title, button_label, filters, options); if (!open_dialog.Show(settings.parent_window))
if (!open_dialog.Show(parent_window))
return false; return false;
ATL::CComPtr<IShellItemArray> items; ATL::CComPtr<IShellItemArray> items;
@ -244,12 +225,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowOpenDialog(atom::NativeWindow* parent, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& callback) { const OpenDialogCallback& callback) {
RunState run_state; RunState run_state;
if (!CreateDialogThread(&run_state)) { if (!CreateDialogThread(&run_state)) {
@ -259,20 +235,14 @@ void ShowOpenDialog(atom::NativeWindow* parent,
run_state.dialog_thread->task_runner()->PostTask( run_state.dialog_thread->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&RunOpenDialogInNewThread, run_state, parent, title, base::Bind(&RunOpenDialogInNewThread, run_state, settings, callback));
button_label, default_path, filters, properties, callback));
} }
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
base::FilePath* path) { base::FilePath* path) {
FileDialog<CShellFileSaveDialog> save_dialog( FileDialog<CShellFileSaveDialog> save_dialog(
default_path, title, button_label, filters, settings, FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT);
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT); if (!save_dialog.Show(settings.parent_window))
if (!save_dialog.Show(parent_window))
return false; return false;
wchar_t buffer[MAX_PATH]; wchar_t buffer[MAX_PATH];
@ -284,11 +254,7 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowSaveDialog(atom::NativeWindow* parent, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& callback) { const SaveDialogCallback& callback) {
RunState run_state; RunState run_state;
if (!CreateDialogThread(&run_state)) { if (!CreateDialogThread(&run_state)) {
@ -298,8 +264,7 @@ void ShowSaveDialog(atom::NativeWindow* parent,
run_state.dialog_thread->task_runner()->PostTask( run_state.dialog_thread->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&RunSaveDialogInNewThread, run_state, parent, title, base::Bind(&RunSaveDialogInNewThread, run_state, settings, callback));
button_label, default_path, filters, callback));
} }
} // namespace file_dialog } // namespace file_dialog

View file

@ -32,7 +32,8 @@ enum MessageBoxOptions {
MESSAGE_BOX_NO_LINK = 1 << 0, MESSAGE_BOX_NO_LINK = 1 << 0,
}; };
typedef base::Callback<void(int code)> MessageBoxCallback; typedef base::Callback<void(int code, bool checkbox_checked)>
MessageBoxCallback;
int ShowMessageBox(NativeWindow* parent_window, int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
@ -54,6 +55,8 @@ void ShowMessageBox(NativeWindow* parent_window,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback); const MessageBoxCallback& callback);

View file

@ -36,8 +36,11 @@ class GtkMessageBox : public NativeWindowObserver {
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon) const gfx::ImageSkia& icon)
: cancel_id_(cancel_id), : cancel_id_(cancel_id),
checkbox_checked_(false),
parent_(static_cast<NativeWindowViews*>(parent_window)) { parent_(static_cast<NativeWindowViews*>(parent_window)) {
// Create dialog. // Create dialog.
dialog_ = gtk_message_dialog_new( dialog_ = gtk_message_dialog_new(
@ -68,6 +71,18 @@ class GtkMessageBox : public NativeWindowObserver {
g_object_unref(pixbuf); g_object_unref(pixbuf);
} }
if (!checkbox_label.empty()) {
GtkWidget* message_area =
gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog_));
GtkWidget* check_button =
gtk_check_button_new_with_label(checkbox_label.c_str());
g_signal_connect(check_button, "toggled",
G_CALLBACK(OnCheckboxToggledThunk), this);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
checkbox_checked);
gtk_container_add(GTK_CONTAINER(message_area), check_button);
}
// Add buttons. // Add buttons.
for (size_t i = 0; i < buttons.size(); ++i) { for (size_t i = 0; i < buttons.size(); ++i) {
GtkWidget* button = gtk_dialog_add_button( GtkWidget* button = gtk_dialog_add_button(
@ -154,6 +169,7 @@ class GtkMessageBox : public NativeWindowObserver {
} }
CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int); CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int);
CHROMEGTK_CALLBACK_0(GtkMessageBox, void, OnCheckboxToggled);
private: private:
atom::UnresponsiveSuppressor unresponsive_suppressor_; atom::UnresponsiveSuppressor unresponsive_suppressor_;
@ -161,6 +177,8 @@ class GtkMessageBox : public NativeWindowObserver {
// The id to return when the dialog is closed without pressing buttons. // The id to return when the dialog is closed without pressing buttons.
int cancel_id_; int cancel_id_;
bool checkbox_checked_;
NativeWindowViews* parent_; NativeWindowViews* parent_;
GtkWidget* dialog_; GtkWidget* dialog_;
MessageBoxCallback callback_; MessageBoxCallback callback_;
@ -172,12 +190,16 @@ void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) {
gtk_widget_hide(dialog_); gtk_widget_hide(dialog_);
if (response < 0) if (response < 0)
callback_.Run(cancel_id_); callback_.Run(cancel_id_, checkbox_checked_);
else else
callback_.Run(response); callback_.Run(response, checkbox_checked_);
delete this; delete this;
} }
void GtkMessageBox::OnCheckboxToggled(GtkWidget* widget) {
checkbox_checked_ = GTK_TOGGLE_BUTTON(widget)->active;
}
} // namespace } // namespace
int ShowMessageBox(NativeWindow* parent, int ShowMessageBox(NativeWindow* parent,
@ -190,8 +212,9 @@ int ShowMessageBox(NativeWindow* parent,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
return GtkMessageBox(parent, type, buttons, default_id, cancel_id, return GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
title, message, detail, icon).RunSynchronous(); message, detail, "", false, icon)
.RunSynchronous();
} }
void ShowMessageBox(NativeWindow* parent, void ShowMessageBox(NativeWindow* parent,
@ -203,18 +226,22 @@ void ShowMessageBox(NativeWindow* parent,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
(new GtkMessageBox(parent, type, buttons, default_id, cancel_id, (new GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
title, message, detail, icon))->RunAsynchronous(callback); message, detail, checkbox_label, checkbox_checked, icon))
->RunAsynchronous(callback);
} }
void ShowErrorBox(const base::string16& title, const base::string16& content) { void ShowErrorBox(const base::string16& title, const base::string16& content) {
if (Browser::Get()->is_ready()) { if (Browser::Get()->is_ready()) {
GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, -1, 0, "Error", GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, {"OK"}, -1, 0, "Error",
base::UTF16ToUTF8(title).c_str(), base::UTF16ToUTF8(title).c_str(),
base::UTF16ToUTF8(content).c_str(), base::UTF16ToUTF8(content).c_str(), "", false,
gfx::ImageSkia()).RunSynchronous(); gfx::ImageSkia())
.RunSynchronous();
} else { } else {
fprintf(stderr, fprintf(stderr,
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY

View file

@ -39,7 +39,7 @@
- (void)alertDidEnd:(NSAlert*)alert - (void)alertDidEnd:(NSAlert*)alert
returnCode:(NSInteger)returnCode returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo { contextInfo:(void*)contextInfo {
callback_.Run(returnCode); callback_.Run(returnCode, alert.suppressionButton.state == NSOnState);
[alert_ release]; [alert_ release];
[self release]; [self release];
@ -57,9 +57,12 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
const std::vector<std::string>& buttons, const std::vector<std::string>& buttons,
int default_id, int default_id,
int cancel_id,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
// Ignore the title; it's the window title on other platforms and ignorable. // Ignore the title; it's the window title on other platforms and ignorable.
NSAlert* alert = [[NSAlert alloc] init]; NSAlert* alert = [[NSAlert alloc] init];
@ -68,10 +71,14 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
switch (type) { switch (type) {
case MESSAGE_BOX_TYPE_INFORMATION: case MESSAGE_BOX_TYPE_INFORMATION:
[alert setAlertStyle:NSInformationalAlertStyle]; alert.alertStyle = NSInformationalAlertStyle;
break; break;
case MESSAGE_BOX_TYPE_WARNING: case MESSAGE_BOX_TYPE_WARNING:
[alert setAlertStyle:NSWarningAlertStyle]; case MESSAGE_BOX_TYPE_ERROR:
// NSWarningAlertStyle shows the app icon while NSCriticalAlertStyle
// shows a warning icon with an app icon badge. Since there is no
// error variant, lets just use NSCriticalAlertStyle.
alert.alertStyle = NSCriticalAlertStyle;
break; break;
default: default:
break; break;
@ -87,7 +94,14 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
} }
NSArray* ns_buttons = [alert buttons]; NSArray* ns_buttons = [alert buttons];
if (default_id >= 0 && default_id < static_cast<int>([ns_buttons count])) { int button_count = static_cast<int>([ns_buttons count]);
// Bind cancel id button to escape key if there is more than one button
if (button_count > 1 && cancel_id >= 0 && cancel_id < button_count) {
[[ns_buttons objectAtIndex:cancel_id] setKeyEquivalent:@"\e"];
}
if (default_id >= 0 && default_id < button_count) {
// Focus the button at default_id if the user opted to do so. // Focus the button at default_id if the user opted to do so.
// The first button added gets set as the default selected. // The first button added gets set as the default selected.
// So remove that default, and make the requested button the default. // So remove that default, and make the requested button the default.
@ -95,6 +109,12 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
[[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"]; [[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"];
} }
if (!checkbox_label.empty()) {
alert.showsSuppressionButton = YES;
alert.suppressionButton.title = base::SysUTF8ToNSString(checkbox_label);
alert.suppressionButton.state = checkbox_checked ? NSOnState : NSOffState;
}
if (!icon.isNull()) { if (!icon.isNull()) {
NSImage* image = skia::SkBitmapToNSImageWithColorSpace( NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
*icon.bitmap(), base::mac::GetGenericRGBColorSpace()); *icon.bitmap(), base::mac::GetGenericRGBColorSpace());
@ -104,7 +124,7 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
return alert; return alert;
} }
void SetReturnCode(int* ret_code, int result) { void SetReturnCode(int* ret_code, int result, bool checkbox_checked) {
*ret_code = result; *ret_code = result;
} }
@ -120,9 +140,9 @@ int ShowMessageBox(NativeWindow* parent_window,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
NSAlert* alert = CreateNSAlert( NSAlert* alert = CreateNSAlert(parent_window, type, buttons, default_id,
parent_window, type, buttons, default_id, title, message, cancel_id, title, message, detail, "", false,
detail, icon); icon);
// Use runModal for synchronous alert without parent, since we don't have a // Use runModal for synchronous alert without parent, since we don't have a
// window to wait for. // window to wait for.
@ -154,11 +174,13 @@ void ShowMessageBox(NativeWindow* parent_window,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
NSAlert* alert = CreateNSAlert( NSAlert* alert =
parent_window, type, buttons, default_id, title, message, CreateNSAlert(parent_window, type, buttons, default_id, cancel_id, title,
detail, icon); message, detail, checkbox_label, checkbox_checked, icon);
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
andAlert:alert andAlert:alert
callEndModal:false]; callEndModal:false];
@ -174,7 +196,7 @@ void ShowErrorBox(const base::string16& title, const base::string16& content) {
NSAlert* alert = [[NSAlert alloc] init]; NSAlert* alert = [[NSAlert alloc] init];
[alert setMessageText:base::SysUTF16ToNSString(title)]; [alert setMessageText:base::SysUTF16ToNSString(title)];
[alert setInformativeText:base::SysUTF16ToNSString(content)]; [alert setInformativeText:base::SysUTF16ToNSString(content)];
[alert setAlertStyle:NSWarningAlertStyle]; [alert setAlertStyle:NSCriticalAlertStyle];
[alert runModal]; [alert runModal];
[alert release]; [alert release];
} }

View file

@ -72,7 +72,7 @@ void MapToCommonID(const std::vector<base::string16>& buttons,
} }
} }
int ShowMessageBoxUTF16(HWND parent, int ShowTaskDialogUTF16(NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
const std::vector<base::string16>& buttons, const std::vector<base::string16>& buttons,
int default_id, int default_id,
@ -81,6 +81,8 @@ int ShowMessageBoxUTF16(HWND parent,
const base::string16& title, const base::string16& title,
const base::string16& message, const base::string16& message,
const base::string16& detail, const base::string16& detail,
const base::string16& checkbox_label,
bool* checkbox_checked,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
TASKDIALOG_FLAGS flags = TASKDIALOG_FLAGS flags =
TDF_SIZE_TO_CONTENT | // Show all content. TDF_SIZE_TO_CONTENT | // Show all content.
@ -88,10 +90,14 @@ int ShowMessageBoxUTF16(HWND parent,
TASKDIALOGCONFIG config = { 0 }; TASKDIALOGCONFIG config = { 0 };
config.cbSize = sizeof(config); config.cbSize = sizeof(config);
config.hwndParent = parent;
config.hInstance = GetModuleHandle(NULL); config.hInstance = GetModuleHandle(NULL);
config.dwFlags = flags; config.dwFlags = flags;
if (parent) {
config.hwndParent =
static_cast<atom::NativeWindowViews*>(parent)->GetAcceleratedWidget();
}
if (default_id > 0) if (default_id > 0)
config.nDefaultButton = kIDStart + default_id; config.nDefaultButton = kIDStart + default_id;
@ -132,6 +138,14 @@ int ShowMessageBoxUTF16(HWND parent,
config.pszContent = detail.c_str(); config.pszContent = detail.c_str();
} }
if (!checkbox_label.empty()) {
config.pszVerificationText = checkbox_label.c_str();
if (checkbox_checked && *checkbox_checked) {
config.dwFlags |= TDF_VERIFICATION_FLAG_CHECKED;
}
}
// Iterate through the buttons, put common buttons in dwCommonButtons // Iterate through the buttons, put common buttons in dwCommonButtons
// and custom buttons in pButtons. // and custom buttons in pButtons.
std::map<int, int> id_map; std::map<int, int> id_map;
@ -151,7 +165,12 @@ int ShowMessageBoxUTF16(HWND parent,
} }
int id = 0; int id = 0;
TaskDialogIndirect(&config, &id, NULL, NULL); BOOL verificationFlagChecked = FALSE;
TaskDialogIndirect(&config, &id, nullptr, &verificationFlagChecked);
if (checkbox_checked) {
*checkbox_checked = verificationFlagChecked;
}
if (id_map.find(id) != id_map.end()) // common button. if (id_map.find(id) != id_map.end()) // common button.
return id_map[id]; return id_map[id];
else if (id >= kIDStart) // custom button. else if (id >= kIDStart) // custom button.
@ -160,6 +179,29 @@ int ShowMessageBoxUTF16(HWND parent,
return cancel_id; return cancel_id;
} }
int ShowTaskDialogUTF8(NativeWindow* parent,
MessageBoxType type,
const std::vector<std::string>& buttons,
int default_id,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const std::string& checkbox_label,
bool* checkbox_checked,
const gfx::ImageSkia& icon) {
std::vector<base::string16> utf16_buttons;
for (const auto& button : buttons)
utf16_buttons.push_back(base::UTF8ToUTF16(button));
return ShowTaskDialogUTF16(
parent, type, utf16_buttons, default_id, cancel_id, options,
base::UTF8ToUTF16(title), base::UTF8ToUTF16(message),
base::UTF8ToUTF16(detail), base::UTF8ToUTF16(checkbox_label),
checkbox_checked, icon);
}
void RunMessageBoxInNewThread(base::Thread* thread, void RunMessageBoxInNewThread(base::Thread* thread,
NativeWindow* parent, NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
@ -170,12 +212,16 @@ void RunMessageBoxInNewThread(base::Thread* thread,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
int result = ShowMessageBox(parent, type, buttons, default_id, int result = ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
cancel_id, options, title, message, detail, icon); options, title, message, detail,
checkbox_label, &checkbox_checked, icon);
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result)); content::BrowserThread::UI, FROM_HERE,
base::Bind(callback, result, checkbox_checked));
content::BrowserThread::DeleteSoon( content::BrowserThread::DeleteSoon(
content::BrowserThread::UI, FROM_HERE, thread); content::BrowserThread::UI, FROM_HERE, thread);
} }
@ -192,25 +238,9 @@ int ShowMessageBox(NativeWindow* parent,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
std::vector<base::string16> utf16_buttons;
for (const auto& button : buttons)
utf16_buttons.push_back(base::UTF8ToUTF16(button));
HWND hwnd_parent = parent ?
static_cast<atom::NativeWindowViews*>(parent)->GetAcceleratedWidget() :
NULL;
atom::UnresponsiveSuppressor suppressor; atom::UnresponsiveSuppressor suppressor;
return ShowMessageBoxUTF16(hwnd_parent, return ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
type, options, title, message, detail, "", nullptr, icon);
utf16_buttons,
default_id,
cancel_id,
options,
base::UTF8ToUTF16(title),
base::UTF8ToUTF16(message),
base::UTF8ToUTF16(detail),
icon);
} }
void ShowMessageBox(NativeWindow* parent, void ShowMessageBox(NativeWindow* parent,
@ -222,13 +252,15 @@ void ShowMessageBox(NativeWindow* parent,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
std::unique_ptr<base::Thread> thread( std::unique_ptr<base::Thread> thread(
new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread")); new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread"));
thread->init_com_with_mta(false); thread->init_com_with_mta(false);
if (!thread->Start()) { if (!thread->Start()) {
callback.Run(cancel_id); callback.Run(cancel_id, checkbox_checked);
return; return;
} }
@ -237,13 +269,14 @@ void ShowMessageBox(NativeWindow* parent,
FROM_HERE, FROM_HERE,
base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained), base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained),
parent, type, buttons, default_id, cancel_id, options, title, parent, type, buttons, default_id, cancel_id, options, title,
message, detail, icon, callback)); message, detail, checkbox_label, checkbox_checked, icon,
callback));
} }
void ShowErrorBox(const base::string16& title, const base::string16& content) { void ShowErrorBox(const base::string16& title, const base::string16& content) {
atom::UnresponsiveSuppressor suppressor; atom::UnresponsiveSuppressor suppressor;
ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error", ShowTaskDialogUTF16(nullptr, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error",
title, content, gfx::ImageSkia()); title, content, L"", nullptr, gfx::ImageSkia());
} }
} // namespace atom } // namespace atom

View file

@ -1,91 +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/ui/views/menu_layout.h"
#if defined(OS_WIN)
#include "atom/browser/native_window_views.h"
#include "ui/display/win/screen_win.h"
#endif
namespace atom {
namespace {
#if defined(OS_WIN)
gfx::Rect SubtractBorderSize(gfx::Rect bounds) {
gfx::Point borderSize = gfx::Point(
GetSystemMetrics(SM_CXSIZEFRAME) - 1, // width
GetSystemMetrics(SM_CYSIZEFRAME) - 1); // height
gfx::Point dpiAdjustedSize =
display::win::ScreenWin::ScreenToDIPPoint(borderSize);
bounds.set_x(bounds.x() + dpiAdjustedSize.x());
bounds.set_y(bounds.y() + dpiAdjustedSize.y());
bounds.set_width(bounds.width() - 2 * dpiAdjustedSize.x());
bounds.set_height(bounds.height() - 2 * dpiAdjustedSize.y());
return bounds;
}
#endif
} // namespace
MenuLayout::MenuLayout(NativeWindowViews* window, int menu_height)
: window_(window),
menu_height_(menu_height) {
}
MenuLayout::~MenuLayout() {
}
void MenuLayout::Layout(views::View* host) {
#if defined(OS_WIN)
// Reserve border space for maximized frameless window so we won't have the
// content go outside of screen.
if (!window_->has_frame() && window_->IsMaximized()) {
gfx::Rect bounds = SubtractBorderSize(host->GetContentsBounds());
host->child_at(0)->SetBoundsRect(bounds);
return;
}
#endif
if (!HasMenu(host)) {
views::FillLayout::Layout(host);
return;
}
gfx::Size size = host->GetContentsBounds().size();
gfx::Rect menu_Bar_bounds = gfx::Rect(0, 0, size.width(), menu_height_);
gfx::Rect web_view_bounds = gfx::Rect(
0, menu_height_, size.width(), size.height() - menu_height_);
views::View* web_view = host->child_at(0);
views::View* menu_bar = host->child_at(1);
web_view->SetBoundsRect(web_view_bounds);
menu_bar->SetBoundsRect(menu_Bar_bounds);
}
gfx::Size MenuLayout::GetPreferredSize(const views::View* host) const {
gfx::Size size = views::FillLayout::GetPreferredSize(host);
if (!HasMenu(host))
return size;
size.set_height(size.height() + menu_height_);
return size;
}
int MenuLayout::GetPreferredHeightForWidth(
const views::View* host, int width) const {
int height = views::FillLayout::GetPreferredHeightForWidth(host, width);
if (!HasMenu(host))
return height;
return height + menu_height_;
}
bool MenuLayout::HasMenu(const views::View* host) const {
return host->child_count() == 2;
}
} // namespace atom

View file

@ -1,36 +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.
#ifndef ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_
#define ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_
#include "ui/views/layout/fill_layout.h"
namespace atom {
class NativeWindowViews;
class MenuLayout : public views::FillLayout {
public:
MenuLayout(NativeWindowViews* window, int menu_height);
virtual ~MenuLayout();
// views::LayoutManager:
void Layout(views::View* host) override;
gfx::Size GetPreferredSize(const views::View* host) const override;
int GetPreferredHeightForWidth(
const views::View* host, int width) const override;
private:
bool HasMenu(const views::View* host) const;
NativeWindowViews* window_;
int menu_height_;
DISALLOW_COPY_AND_ASSIGN(MenuLayout);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_

View file

@ -16,26 +16,15 @@
namespace atom { namespace atom {
namespace {
// Filter out the "&" in menu label.
base::string16 FilterAccelerator(const base::string16& label) {
base::string16 out;
base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out);
return out;
}
} // namespace
SubmenuButton::SubmenuButton(const base::string16& title, SubmenuButton::SubmenuButton(const base::string16& title,
views::MenuButtonListener* menu_button_listener, views::MenuButtonListener* menu_button_listener,
const SkColor& background_color) const SkColor& background_color)
: views::MenuButton(FilterAccelerator(title), : views::MenuButton(gfx::RemoveAcceleratorChar(title, '&', NULL, NULL),
menu_button_listener, false), menu_button_listener, false),
accelerator_(0), accelerator_(0),
show_underline_(false), show_underline_(false),
underline_start_(-1), underline_start_(0),
underline_end_(-1), underline_end_(0),
text_width_(0), text_width_(0),
text_height_(0), text_height_(0),
underline_color_(SK_ColorBLACK), underline_color_(SK_ColorBLACK),
@ -117,7 +106,7 @@ bool SubmenuButton::GetUnderlinePosition(const base::string16& text,
void SubmenuButton::GetCharacterPosition( void SubmenuButton::GetCharacterPosition(
const base::string16& text, int index, int* pos) { const base::string16& text, int index, int* pos) {
int height; int height = 0;
gfx::Canvas::SizeStringInt(text.substr(0, index), GetFontList(), pos, &height, gfx::Canvas::SizeStringInt(text.substr(0, index), GetFontList(), pos, &height,
0, 0); 0, 0);
} }

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