Merge remote-tracking branch 'ups/master'
This commit is contained in:
commit
cba5e96496
485 changed files with 17051 additions and 3798 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -22,3 +22,6 @@
|
|||
[submodule "vendor/boto"]
|
||||
path = vendor/boto
|
||||
url = https://github.com/boto/boto.git
|
||||
[submodule "vendor/pdf_viewer"]
|
||||
path = vendor/pdf_viewer
|
||||
url = https://github.com/electron/pdf-viewer.git
|
||||
|
|
|
@ -20,4 +20,16 @@ Thanks for opening an issue! A few things to keep in mind:
|
|||
|
||||
### 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 .
|
||||
|
||||
-->
|
||||
|
|
12
README.md
12
README.md
|
@ -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)
|
||||
[![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)
|
||||
[![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
|
||||
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
|
||||
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
|
||||
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)
|
||||
- [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)
|
||||
- [Thai](https://github.com/electron/electron/tree/master/docs-Translations/th-TH)
|
||||
- [Ukrainian](https://github.com/electron/electron/tree/master/docs-translations/uk-UA)
|
||||
- [Russian](https://github.com/electron/electron/tree/master/docs-translations/ru-RU)
|
||||
- [French](https://github.com/electron/electron/tree/master/docs-translations/fr-FR)
|
||||
|
@ -71,10 +72,11 @@ locations:
|
|||
forums
|
||||
- `#atom-shell` channel on Freenode
|
||||
- [`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-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
|
||||
- [`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)*
|
||||
|
||||
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
|
||||
|
|
9
SECURITY.md
Normal file
9
SECURITY.md
Normal 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).
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/chrome_version.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
|
@ -18,6 +19,7 @@
|
|||
#include "content/public/common/content_constants.h"
|
||||
#include "content/public/common/pepper_plugin_info.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
#include "pdf/pdf.h"
|
||||
#include "ppapi/shared_impl/ppapi_permissions.h"
|
||||
#include "third_party/widevine/cdm/stub/widevine_cdm_version.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(
|
||||
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");
|
||||
// |SplitString()| puts in an empty string given an empty string. :(
|
||||
else if (flash_version_numbers[0].empty())
|
||||
|
@ -108,6 +110,25 @@ content::PepperPluginInfo CreateWidevineCdmInfo(const base::FilePath& path,
|
|||
}
|
||||
#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,
|
||||
const char* separator,
|
||||
const char* cmd_switch) {
|
||||
|
@ -190,6 +211,7 @@ void AtomContentClient::AddPepperPlugins(
|
|||
#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_PEPPER_CDMS)
|
||||
AddWidevineCdmFromCommandLine(plugins);
|
||||
#endif
|
||||
ComputeBuiltInPlugins(plugins);
|
||||
}
|
||||
|
||||
void AtomContentClient::AddServiceWorkerSchemes(
|
||||
|
|
|
@ -102,6 +102,9 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||
#if defined(OS_WIN)
|
||||
// Ignore invalid parameter errors.
|
||||
_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
|
||||
|
||||
return brightray::MainDelegate::BasicStartupComplete(exit_code);
|
||||
|
|
|
@ -30,14 +30,16 @@
|
|||
#include "base/path_service.h"
|
||||
#include "base/strings/string_util.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 "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/gpu_data_manager.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "media/audio/audio_manager.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
@ -335,6 +337,26 @@ namespace api {
|
|||
|
||||
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.
|
||||
int GetPathConstant(const std::string& name) {
|
||||
if (name == "appData")
|
||||
|
@ -416,7 +438,7 @@ void OnClientCertificateSelected(
|
|||
|
||||
auto certs = net::X509Certificate::CreateCertificateListFromBytes(
|
||||
data.c_str(), data.length(), net::X509Certificate::FORMAT_AUTO);
|
||||
if (certs.size() > 0)
|
||||
if (!certs.empty())
|
||||
delegate->ContinueWithCertificate(certs[0].get());
|
||||
}
|
||||
|
||||
|
@ -462,6 +484,21 @@ int ImportIntoCertStore(
|
|||
}
|
||||
#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
|
||||
|
||||
App::App(v8::Isolate* isolate) {
|
||||
|
@ -494,7 +531,7 @@ void App::OnQuit() {
|
|||
int exitCode = AtomBrowserMainParts::Get()->GetExitCode();
|
||||
Emit("quit", exitCode);
|
||||
|
||||
if (process_singleton_.get()) {
|
||||
if (process_singleton_) {
|
||||
process_singleton_->Cleanup();
|
||||
process_singleton_.reset();
|
||||
}
|
||||
|
@ -629,6 +666,14 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) {
|
|||
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) {
|
||||
bool succeed = false;
|
||||
base::FilePath path;
|
||||
|
@ -669,7 +714,7 @@ std::string App::GetLocale() {
|
|||
|
||||
bool App::MakeSingleInstance(
|
||||
const ProcessSingleton::NotificationCallback& callback) {
|
||||
if (process_singleton_.get())
|
||||
if (process_singleton_)
|
||||
return false;
|
||||
|
||||
base::FilePath user_dir;
|
||||
|
@ -690,7 +735,7 @@ bool App::MakeSingleInstance(
|
|||
}
|
||||
|
||||
void App::ReleaseSingleInstance() {
|
||||
if (process_singleton_.get()) {
|
||||
if (process_singleton_) {
|
||||
process_singleton_->Cleanup();
|
||||
process_singleton_.reset();
|
||||
}
|
||||
|
@ -841,6 +886,84 @@ JumpListResult App::SetJumpList(v8::Local<v8::Value> val,
|
|||
}
|
||||
#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
|
||||
mate::Handle<App> App::Create(v8::Isolate* isolate) {
|
||||
return mate::CreateHandle(isolate, new App(isolate));
|
||||
|
@ -896,6 +1019,8 @@ void App::BuildPrototype(
|
|||
.SetMethod("isUnityRunning",
|
||||
base::Bind(&Browser::IsUnityRunning, browser))
|
||||
#endif
|
||||
.SetMethod("setAppPath", &App::SetAppPath)
|
||||
.SetMethod("getAppPath", &App::GetAppPath)
|
||||
.SetMethod("setPath", &App::SetPath)
|
||||
.SetMethod("getPath", &App::GetPath)
|
||||
.SetMethod("setDesktopName", &App::SetDesktopName)
|
||||
|
@ -909,7 +1034,9 @@ void App::BuildPrototype(
|
|||
.SetMethod("isAccessibilitySupportEnabled",
|
||||
&App::IsAccessibilitySupportEnabled)
|
||||
.SetMethod("disableHardwareAcceleration",
|
||||
&App::DisableHardwareAcceleration);
|
||||
&App::DisableHardwareAcceleration)
|
||||
.SetMethod("getFileIcon", &App::GetFileIcon)
|
||||
.SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -13,8 +13,12 @@
|
|||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/browser_observer.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 "content/public/browser/gpu_data_manager_observer.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/base/completion_callback.h"
|
||||
|
||||
|
@ -43,6 +47,9 @@ class App : public AtomBrowserClient::Delegate,
|
|||
public BrowserObserver,
|
||||
public content::GpuDataManagerObserver {
|
||||
public:
|
||||
using FileIconCallback = base::Callback<void(v8::Local<v8::Value>,
|
||||
const gfx::Image&)>;
|
||||
|
||||
static mate::Handle<App> Create(v8::Isolate* isolate);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
|
@ -65,6 +72,8 @@ class App : public AtomBrowserClient::Delegate,
|
|||
std::unique_ptr<CertificateManagerModel> model);
|
||||
#endif
|
||||
|
||||
base::FilePath GetAppPath() const;
|
||||
|
||||
protected:
|
||||
explicit App(v8::Isolate* isolate);
|
||||
~App() override;
|
||||
|
@ -110,6 +119,8 @@ class App : public AtomBrowserClient::Delegate,
|
|||
void OnGpuProcessCrashed(base::TerminationStatus status) override;
|
||||
|
||||
private:
|
||||
void SetAppPath(const base::FilePath& app_path);
|
||||
|
||||
// Get/Set the pre-defined path in PathService.
|
||||
base::FilePath GetPath(mate::Arguments* args, const std::string& name);
|
||||
void SetPath(mate::Arguments* args,
|
||||
|
@ -129,6 +140,10 @@ class App : public AtomBrowserClient::Delegate,
|
|||
void ImportCertificate(const base::DictionaryValue& options,
|
||||
const net::CompletionCallback& callback);
|
||||
#endif
|
||||
void GetFileIcon(const base::FilePath& path,
|
||||
mate::Arguments* args);
|
||||
|
||||
std::vector<mate::Dictionary> GetAppMemoryInfo(v8::Isolate* isolate);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Get the current Jump List settings.
|
||||
|
@ -144,6 +159,11 @@ class App : public AtomBrowserClient::Delegate,
|
|||
std::unique_ptr<CertificateManagerModel> certificate_manager_model_;
|
||||
#endif
|
||||
|
||||
// Tracks tasks requesting file icons.
|
||||
base::CancelableTaskTracker cancelable_task_tracker_;
|
||||
|
||||
base::FilePath app_path_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.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/node_includes.h"
|
||||
#include "base/time/time.h"
|
||||
|
@ -47,7 +48,9 @@ void AutoUpdater::OnError(const std::string& message) {
|
|||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
|
||||
EmitCustomEvent(
|
||||
mate::EmitEvent(
|
||||
isolate(),
|
||||
GetWrapper(),
|
||||
"error",
|
||||
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
|
||||
// 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() {
|
||||
// If we don't have any window then quitAndInstall immediately.
|
||||
WindowList* window_list = WindowList::GetInstance();
|
||||
if (window_list->size() == 0) {
|
||||
if (WindowList::IsEmpty()) {
|
||||
auto_updater::AutoUpdater::QuitAndInstall();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise do the restart after all windows have been closed.
|
||||
window_list->AddObserver(this);
|
||||
for (NativeWindow* window : *window_list)
|
||||
window->Close();
|
||||
WindowList::AddObserver(this);
|
||||
WindowList::CloseAllWindows();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
162
atom/browser/api/atom_api_browser_view.cc
Normal file
162
atom/browser/api/atom_api_browser_view.cc
Normal 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, ¶ms)) {
|
||||
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)
|
72
atom/browser/api/atom_api_browser_view.h
Normal file
72
atom/browser/api/atom_api_browser_view.h
Normal 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_
|
|
@ -179,6 +179,13 @@ void OnSetCookie(const Cookies::SetCallback& callback, bool success) {
|
|||
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.
|
||||
void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
std::unique_ptr<base::DictionaryValue> details,
|
||||
|
@ -265,6 +272,13 @@ void Cookies::Set(const base::DictionaryValue& details,
|
|||
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,
|
||||
bool removed,
|
||||
net::CookieStore::ChangeCause cause) {
|
||||
|
@ -286,7 +300,8 @@ void Cookies::BuildPrototype(v8::Isolate* isolate,
|
|||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.SetMethod("get", &Cookies::Get)
|
||||
.SetMethod("remove", &Cookies::Remove)
|
||||
.SetMethod("set", &Cookies::Set);
|
||||
.SetMethod("set", &Cookies::Set)
|
||||
.SetMethod("flushStore", &Cookies::FlushStore);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -53,6 +53,7 @@ class Cookies : public mate::TrackableObject<Cookies>,
|
|||
void Remove(const GURL& url, const std::string& name,
|
||||
const base::Closure& callback);
|
||||
void Set(const base::DictionaryValue& details, const SetCallback& callback);
|
||||
void FlushStore(const base::Closure& callback);
|
||||
|
||||
// AtomCookieDelegate::Observer:
|
||||
void OnCookieChanged(const net::CanonicalCookie& cookie,
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/json/json_reader.h"
|
||||
#include "base/json/json_writer.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
|
@ -45,12 +44,23 @@ void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host,
|
|||
const std::string& message) {
|
||||
DCHECK(agent_host == agent_host_.get());
|
||||
|
||||
std::unique_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
|
||||
if (!parsed_message->IsType(base::Value::TYPE_DICTIONARY))
|
||||
return;
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
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;
|
||||
if (!dict->GetInteger("id", &id)) {
|
||||
std::string method;
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
|
||||
#include "atom/browser/api/atom_api_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/message_box.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/net_converter.h"
|
||||
#include "native_mate/dictionary.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 {
|
||||
|
@ -47,6 +70,8 @@ void ShowMessageBox(int type,
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon,
|
||||
atom::NativeWindow* window,
|
||||
mate::Arguments* args) {
|
||||
|
@ -55,56 +80,44 @@ void ShowMessageBox(int type,
|
|||
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons,
|
||||
default_id, cancel_id, options, title,
|
||||
message, detail, icon, callback);
|
||||
atom::ShowMessageBox(window, static_cast<atom::MessageBoxType>(type),
|
||||
buttons, default_id, cancel_id, options, title,
|
||||
message, detail, checkbox_label, checkbox_checked,
|
||||
icon, callback);
|
||||
} else {
|
||||
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
|
||||
buttons, default_id, cancel_id,
|
||||
options, title, message, detail, icon);
|
||||
int chosen = atom::ShowMessageBox(
|
||||
window, static_cast<atom::MessageBoxType>(type), buttons, default_id,
|
||||
cancel_id, options, title, message, detail, icon);
|
||||
args->Return(chosen);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowOpenDialog(const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const file_dialog::Filters& filters,
|
||||
int properties,
|
||||
atom::NativeWindow* window,
|
||||
void ShowOpenDialog(const file_dialog::DialogSettings& settings,
|
||||
mate::Arguments* args) {
|
||||
v8::Local<v8::Value> peek = args->PeekNext();
|
||||
file_dialog::OpenDialogCallback callback;
|
||||
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
file_dialog::ShowOpenDialog(window, title, button_label, default_path,
|
||||
filters, properties, callback);
|
||||
file_dialog::ShowOpenDialog(settings, callback);
|
||||
} else {
|
||||
std::vector<base::FilePath> paths;
|
||||
if (file_dialog::ShowOpenDialog(window, title, button_label, default_path,
|
||||
filters, properties, &paths))
|
||||
if (file_dialog::ShowOpenDialog(settings, &paths))
|
||||
args->Return(paths);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowSaveDialog(const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const file_dialog::Filters& filters,
|
||||
atom::NativeWindow* window,
|
||||
void ShowSaveDialog(const file_dialog::DialogSettings& settings,
|
||||
mate::Arguments* args) {
|
||||
v8::Local<v8::Value> peek = args->PeekNext();
|
||||
file_dialog::SaveDialogCallback callback;
|
||||
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
file_dialog::ShowSaveDialog(window, title, button_label, default_path,
|
||||
filters, callback);
|
||||
file_dialog::ShowSaveDialog(settings, callback);
|
||||
} else {
|
||||
base::FilePath path;
|
||||
if (file_dialog::ShowSaveDialog(window, title, button_label, default_path,
|
||||
filters, &path))
|
||||
if (file_dialog::ShowSaveDialog(settings, &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("showOpenDialog", &ShowOpenDialog);
|
||||
dict.SetMethod("showSaveDialog", &ShowSaveDialog);
|
||||
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||
dict.SetMethod("showCertificateTrustDialog",
|
||||
&certificate_trust::ShowCertificateTrust);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -78,7 +78,6 @@ DownloadItem::~DownloadItem() {
|
|||
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
|
||||
if (download_item_->IsDone()) {
|
||||
Emit("done", item->GetState());
|
||||
|
||||
// Destroy the item once item is downloaded.
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, GetDestroyClosure());
|
||||
|
@ -111,7 +110,6 @@ bool DownloadItem::CanResume() const {
|
|||
|
||||
void DownloadItem::Cancel() {
|
||||
download_item_->Cancel(true);
|
||||
download_item_->Remove();
|
||||
}
|
||||
|
||||
int64_t DownloadItem::GetReceivedBytes() const {
|
||||
|
|
|
@ -176,7 +176,8 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
|
||||
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||
.SetMethod("popupAt", &Menu::PopupAt);
|
||||
.SetMethod("popupAt", &Menu::PopupAt)
|
||||
.SetMethod("closePopupAt", &Menu::ClosePopupAt);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -53,9 +53,9 @@ class Menu : public mate::TrackableObject<Menu>,
|
|||
void ExecuteCommand(int command_id, int event_flags) override;
|
||||
void MenuWillShow(ui::SimpleMenuModel* source) override;
|
||||
|
||||
virtual void PopupAt(Window* window,
|
||||
int x = -1, int y = -1,
|
||||
int positioning_item = 0) = 0;
|
||||
virtual void PopupAt(
|
||||
Window* window, int x, int y, int positioning_item, bool async) = 0;
|
||||
virtual void ClosePopupAt(int32_t window_id) = 0;
|
||||
|
||||
std::unique_ptr<AtomMenuModel> model_;
|
||||
Menu* parent_;
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#import "atom/browser/ui/cocoa/atom_menu_controller.h"
|
||||
|
||||
using base::scoped_nsobject;
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
@ -19,15 +22,25 @@ class MenuMac : public Menu {
|
|||
protected:
|
||||
MenuMac(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
|
||||
|
||||
void PopupAt(Window* window, int x, int y, int positioning_item) override;
|
||||
|
||||
base::scoped_nsobject<AtomMenuController> menu_controller_;
|
||||
void PopupAt(
|
||||
Window* window, int x, int y, int positioning_item, bool async) override;
|
||||
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:
|
||||
friend class Menu;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -6,35 +6,58 @@
|
|||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/unresponsive_suppressor.h"
|
||||
#include "base/mac/scoped_sending_event.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
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();
|
||||
if (!native_window)
|
||||
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 =
|
||||
native_window->inspectable_web_contents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
base::scoped_nsobject<AtomMenuController> menu_controller(
|
||||
[[AtomMenuController alloc] initWithModel:model_.get()
|
||||
auto close_callback = base::Bind(&MenuMac::ClosePopupAt,
|
||||
weak_factory_.GetWeakPtr(), window_id);
|
||||
popup_controllers_[window_id] = base::scoped_nsobject<AtomMenuController>(
|
||||
[[AtomMenuController alloc] initWithModel:model()
|
||||
useDefaultAccelerator:NO]);
|
||||
NSMenu* menu = [menu_controller menu];
|
||||
NSMenu* menu = [popup_controllers_[window_id] menu];
|
||||
NSView* view = web_contents->GetView()->GetNativeView();
|
||||
|
||||
// Which menu item to show.
|
||||
|
@ -69,11 +92,33 @@ void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) {
|
|||
if (rightmostMenuPoint > screenRight)
|
||||
position.x = position.x - [menu size].width;
|
||||
|
||||
// Don't emit unresponsive event when showing menu.
|
||||
atom::UnresponsiveSuppressor suppressor;
|
||||
|
||||
// Show the menu.
|
||||
[menu popUpMenuPositioningItem:item atLocation:position inView:view];
|
||||
if (async) {
|
||||
[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
|
||||
|
|
|
@ -8,17 +8,20 @@
|
|||
#include "atom/browser/unresponsive_suppressor.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/views/controls/menu/menu_runner.h"
|
||||
|
||||
using views::MenuRunner;
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
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());
|
||||
if (!native_window)
|
||||
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);
|
||||
}
|
||||
|
||||
int flags = MenuRunner::CONTEXT_MENU | MenuRunner::HAS_MNEMONICS;
|
||||
if (async)
|
||||
flags |= MenuRunner::ASYNC;
|
||||
|
||||
// Don't emit unresponsive event when showing menu.
|
||||
atom::UnresponsiveSuppressor suppressor;
|
||||
|
||||
// Show the menu.
|
||||
views::MenuRunner menu_runner(
|
||||
model(),
|
||||
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
|
||||
ignore_result(menu_runner.RunMenuAt(
|
||||
int32_t window_id = window->ID();
|
||||
auto close_callback = base::Bind(
|
||||
&MenuViews::ClosePopupAt, weak_factory_.GetWeakPtr(), window_id);
|
||||
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(),
|
||||
NULL,
|
||||
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));
|
||||
}
|
||||
|
||||
void MenuViews::ClosePopupAt(int32_t window_id) {
|
||||
menu_runners_.erase(window_id);
|
||||
}
|
||||
|
||||
// static
|
||||
mate::WrappableBase* Menu::New(mate::Arguments* args) {
|
||||
return new MenuViews(args->isolate(), args->GetThis());
|
||||
|
|
|
@ -5,8 +5,12 @@
|
|||
#ifndef 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 "base/memory/weak_ptr.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/views/controls/menu/menu_runner.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -17,9 +21,16 @@ class MenuViews : public Menu {
|
|||
MenuViews(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
|
||||
|
||||
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:
|
||||
// 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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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 atom {
|
||||
|
@ -221,7 +233,7 @@ class ResolveProxyHelper {
|
|||
public:
|
||||
ResolveProxyHelper(AtomBrowserContext* browser_context,
|
||||
const GURL& url,
|
||||
Session::ResolveProxyCallback callback)
|
||||
const Session::ResolveProxyCallback& callback)
|
||||
: callback_(callback),
|
||||
original_thread_(base::ThreadTaskRunnerHandle::Get()) {
|
||||
scoped_refptr<net::URLRequestContextGetter> context_getter =
|
||||
|
@ -738,7 +750,7 @@ void Session::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
|
||||
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
|
||||
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
|
||||
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
|
||||
.SetMethod("_setCertificateVerifyProc", &Session::SetCertVerifyProc)
|
||||
.SetMethod("setPermissionRequestHandler",
|
||||
&Session::SetPermissionRequestHandler)
|
||||
.SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "atom/browser/net/atom_url_request.h"
|
||||
#include "atom/common/api/event_emitter_caller.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/string16_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
|
@ -145,6 +146,8 @@ mate::WrappableBase* URLRequest::New(mate::Arguments* args) {
|
|||
dict.Get("method", &method);
|
||||
std::string url;
|
||||
dict.Get("url", &url);
|
||||
std::string redirect_policy;
|
||||
dict.Get("redirect", &redirect_policy);
|
||||
std::string partition;
|
||||
mate::Handle<api::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 api_url_request = new URLRequest(args->isolate(), args->GetThis());
|
||||
auto atom_url_request =
|
||||
AtomURLRequest::Create(browser_context, method, url, api_url_request);
|
||||
auto atom_url_request = AtomURLRequest::Create(
|
||||
browser_context, method, url, redirect_policy, api_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("removeExtraHeader", &URLRequest::RemoveExtraHeader)
|
||||
.SetMethod("setChunkedUpload", &URLRequest::SetChunkedUpload)
|
||||
.SetMethod("followRedirect", &URLRequest::FollowRedirect)
|
||||
.SetMethod("_setLoadFlags", &URLRequest::SetLoadFlags)
|
||||
.SetProperty("notStarted", &URLRequest::NotStarted)
|
||||
.SetProperty("finished", &URLRequest::Finished)
|
||||
|
@ -246,6 +250,17 @@ void URLRequest::Cancel() {
|
|||
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,
|
||||
const std::string& value) {
|
||||
// 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(
|
||||
scoped_refptr<const net::AuthChallengeInfo> auth_info) {
|
||||
if (request_state_.Canceled() || request_state_.Closed()) {
|
||||
|
|
|
@ -99,6 +99,11 @@ class URLRequest : public mate::EventEmitter<URLRequest> {
|
|||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
// 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(
|
||||
scoped_refptr<const net::AuthChallengeInfo> auth_info);
|
||||
void OnResponseStarted(
|
||||
|
@ -170,6 +175,7 @@ class URLRequest : public mate::EventEmitter<URLRequest> {
|
|||
bool Failed() const;
|
||||
bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last);
|
||||
void Cancel();
|
||||
void FollowRedirect();
|
||||
bool SetExtraHeader(const std::string& name, const std::string& value);
|
||||
void RemoveExtraHeader(const std::string& name);
|
||||
void SetChunkedUpload(bool is_chunked_upload);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "atom/browser/ui/drag_util.h"
|
||||
#include "atom/browser/web_contents_permission_helper.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/common/api/api_messages.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_view_manager_basic.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/web_contents/web_contents_impl.h"
|
||||
#include "content/common/view_messages.h"
|
||||
|
@ -54,6 +56,9 @@
|
|||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/navigation_entry.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/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
|
@ -201,6 +206,7 @@ struct Converter<atom::api::WebContents::Type> {
|
|||
switch (val) {
|
||||
case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
|
||||
case Type::BROWSER_WINDOW: type = "window"; break;
|
||||
case Type::BROWSER_VIEW: type = "browserView"; break;
|
||||
case Type::REMOTE: type = "remote"; break;
|
||||
case Type::WEB_VIEW: type = "webview"; break;
|
||||
case Type::OFF_SCREEN: type = "offscreen"; break;
|
||||
|
@ -215,10 +221,12 @@ struct Converter<atom::api::WebContents::Type> {
|
|||
std::string type;
|
||||
if (!ConvertFromV8(isolate, val, &type))
|
||||
return false;
|
||||
if (type == "webview") {
|
||||
*out = Type::WEB_VIEW;
|
||||
} else if (type == "backgroundPage") {
|
||||
if (type == "backgroundPage") {
|
||||
*out = Type::BACKGROUND_PAGE;
|
||||
} else if (type == "browserView") {
|
||||
*out = Type::BROWSER_VIEW;
|
||||
} else if (type == "webview") {
|
||||
*out = Type::WEB_VIEW;
|
||||
} else if (type == "offscreen") {
|
||||
*out = Type::OFF_SCREEN;
|
||||
} else {
|
||||
|
@ -253,12 +261,28 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
|
|||
}
|
||||
|
||||
// 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,
|
||||
content::ReadbackResponse response) {
|
||||
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
|
||||
|
||||
WebContents::WebContents(v8::Isolate* isolate,
|
||||
|
@ -266,11 +290,11 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
Type type)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
embedder_(nullptr),
|
||||
zoom_controller_(nullptr),
|
||||
type_(type),
|
||||
request_id_(0),
|
||||
background_throttling_(true),
|
||||
enable_devtools_(true) {
|
||||
|
||||
if (type == REMOTE) {
|
||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||
Init(isolate);
|
||||
|
@ -283,9 +307,9 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
}
|
||||
}
|
||||
|
||||
WebContents::WebContents(v8::Isolate* isolate,
|
||||
const mate::Dictionary& options)
|
||||
WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
|
||||
: embedder_(nullptr),
|
||||
zoom_controller_(nullptr),
|
||||
type_(BROWSER_WINDOW),
|
||||
request_id_(0),
|
||||
background_throttling_(true),
|
||||
|
@ -303,6 +327,8 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
type_ = WEB_VIEW;
|
||||
else if (options.Get("isBackgroundPage", &b) && b)
|
||||
type_ = BACKGROUND_PAGE;
|
||||
else if (options.Get("isBrowserView", &b) && b)
|
||||
type_ = BROWSER_VIEW;
|
||||
else if (options.Get("offscreen", &b) && b)
|
||||
type_ = OFF_SCREEN;
|
||||
|
||||
|
@ -355,7 +381,7 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
|
|||
content::WebContents *web_contents,
|
||||
mate::Handle<api::Session> session,
|
||||
const mate::Dictionary& options) {
|
||||
Observe(web_contents);
|
||||
content::WebContentsObserver::Observe(web_contents);
|
||||
InitWithWebContents(web_contents, session->browser_context());
|
||||
|
||||
managed_web_contents()->GetView()->SetDelegate(this);
|
||||
|
@ -363,10 +389,16 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
|
|||
// Save the preferences in C++.
|
||||
new WebContentsPreferences(web_contents, options);
|
||||
|
||||
// Intialize permission helper.
|
||||
// Initialize permission helper.
|
||||
WebContentsPermissionHelper::CreateForWebContents(web_contents);
|
||||
// Intialize security state client.
|
||||
// Initialize security state client.
|
||||
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());
|
||||
|
||||
|
@ -385,6 +417,11 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
|
|||
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);
|
||||
AttachAsUserData(web_contents);
|
||||
}
|
||||
|
@ -397,14 +434,31 @@ WebContents::~WebContents() {
|
|||
if (type_ == WEB_VIEW)
|
||||
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());
|
||||
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,
|
||||
int32_t level,
|
||||
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,
|
||||
initial_rect.x(), initial_rect.y(), initial_rect.width(),
|
||||
initial_rect.height())) {
|
||||
api_web_contents->DestroyWebContents();
|
||||
api_web_contents->DestroyWebContents(true /* async */);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -744,6 +798,30 @@ void WebContents::DidGetRedirectForResourceRequest(
|
|||
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(
|
||||
content::NavigationHandle* navigation_handle) {
|
||||
bool is_main_frame = navigation_handle->IsInMainFrame();
|
||||
|
@ -769,10 +847,8 @@ void WebContents::DidFinishNavigation(
|
|||
|
||||
void WebContents::TitleWasSet(content::NavigationEntry* entry,
|
||||
bool explicit_set) {
|
||||
if (entry)
|
||||
Emit("-page-title-updated", entry->GetTitle(), explicit_set);
|
||||
else
|
||||
Emit("-page-title-updated", "", explicit_set);
|
||||
auto title = entry ? entry->GetTitle() : base::string16();
|
||||
Emit("page-title-updated", title, explicit_set);
|
||||
}
|
||||
|
||||
void WebContents::DidUpdateFaviconURL(
|
||||
|
@ -788,6 +864,32 @@ void WebContents::DidUpdateFaviconURL(
|
|||
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() {
|
||||
Emit("devtools-reload-page");
|
||||
}
|
||||
|
@ -830,6 +932,10 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
|||
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
|
||||
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
|
||||
OnRendererMessageSync)
|
||||
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_SetTemporaryZoomLevel,
|
||||
OnSetTemporaryZoomLevel)
|
||||
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_GetZoomLevel,
|
||||
OnGetZoomLevel)
|
||||
IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
|
||||
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
|
||||
// we need to make sure the api::WebContents is also deleted.
|
||||
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.
|
||||
RemoveFromWeakMap();
|
||||
|
||||
|
@ -925,26 +1027,25 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
|
|||
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.should_clear_history_list = 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
|
||||
// created after loading a page.
|
||||
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);
|
||||
}
|
||||
}
|
||||
SetBackgroundColor(web_contents());
|
||||
}
|
||||
|
||||
void WebContents::DownloadURL(const GURL& url) {
|
||||
|
@ -1000,6 +1101,23 @@ void WebContents::GoToOffset(int 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 {
|
||||
return web_contents()->IsCrashed();
|
||||
}
|
||||
|
@ -1517,13 +1635,47 @@ int WebContents::GetFrameRate() const {
|
|||
}
|
||||
|
||||
void WebContents::Invalidate() {
|
||||
if (!IsOffScreen())
|
||||
return;
|
||||
|
||||
auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
|
||||
if (IsOffScreen()) {
|
||||
auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
|
||||
web_contents()->GetRenderWidgetHostView());
|
||||
if (osr_rwhv)
|
||||
osr_rwhv->Invalidate();
|
||||
if (osr_rwhv)
|
||||
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) {
|
||||
|
@ -1654,6 +1806,10 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setFrameRate", &WebContents::SetFrameRate)
|
||||
.SetMethod("getFrameRate", &WebContents::GetFrameRate)
|
||||
.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("getWebPreferences", &WebContents::GetWebPreferences)
|
||||
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
||||
|
@ -1671,6 +1827,10 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("copyImageAt", &WebContents::CopyImageAt)
|
||||
.SetMethod("capturePage", &WebContents::CapturePage)
|
||||
.SetMethod("setEmbedder", &WebContents::SetEmbedder)
|
||||
.SetMethod("setWebRTCIPHandlingPolicy",
|
||||
&WebContents::SetWebRTCIPHandlingPolicy)
|
||||
.SetMethod("getWebRTCIPHandlingPolicy",
|
||||
&WebContents::GetWebRTCIPHandlingPolicy)
|
||||
.SetProperty("id", &WebContents::ID)
|
||||
.SetProperty("session", &WebContents::Session)
|
||||
.SetProperty("hostWebContents", &WebContents::HostWebContents)
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/common_web_contents_delegate.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/common/favicon_url.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
@ -40,20 +42,23 @@ namespace atom {
|
|||
|
||||
struct SetSizeParams;
|
||||
class AtomBrowserContext;
|
||||
class WebContentsZoomController;
|
||||
class WebViewGuestDelegate;
|
||||
|
||||
namespace api {
|
||||
|
||||
class WebContents : public mate::TrackableObject<WebContents>,
|
||||
public CommonWebContentsDelegate,
|
||||
public content::WebContentsObserver {
|
||||
public content::WebContentsObserver,
|
||||
public content::NotificationObserver {
|
||||
public:
|
||||
enum Type {
|
||||
BACKGROUND_PAGE, // A DevTools extension background page.
|
||||
BROWSER_WINDOW, // Used by BrowserWindow.
|
||||
REMOTE, // Thin wrap around an existing WebContents.
|
||||
WEB_VIEW, // Used by <webview>.
|
||||
OFF_SCREEN, // Used for offscreen rendering
|
||||
BROWSER_WINDOW, // Used by BrowserWindow.
|
||||
BROWSER_VIEW, // Used by BrowserView.
|
||||
REMOTE, // Thin wrap around an existing WebContents.
|
||||
WEB_VIEW, // Used by <webview>.
|
||||
OFF_SCREEN, // Used for offscreen rendering
|
||||
};
|
||||
|
||||
// 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,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
// Notifies to destroy any guest web contents before destroying self.
|
||||
void DestroyWebContents(bool async);
|
||||
|
||||
int64_t GetID() const;
|
||||
int GetProcessID() const;
|
||||
Type GetType() const;
|
||||
|
@ -89,6 +97,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void GoBack();
|
||||
void GoForward();
|
||||
void GoToOffset(int offset);
|
||||
const std::string GetWebRTCIPHandlingPolicy() const;
|
||||
void SetWebRTCIPHandlingPolicy(const std::string& webrtc_ip_handling_policy);
|
||||
bool IsCrashed() const;
|
||||
void SetUserAgent(const std::string& user_agent, mate::Arguments* args);
|
||||
std::string GetUserAgent();
|
||||
|
@ -176,6 +186,12 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
int GetFrameRate() const;
|
||||
void Invalidate();
|
||||
|
||||
// Methods for zoom handling.
|
||||
void SetZoomLevel(double level);
|
||||
double GetZoomLevel();
|
||||
void SetZoomFactor(double factor);
|
||||
double GetZoomFactor();
|
||||
|
||||
// Callback triggered on permission response.
|
||||
void OnEnterFullscreenModeForTab(content::WebContents* source,
|
||||
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> Debugger(v8::Isolate* isolate);
|
||||
|
||||
WebContentsZoomController* GetZoomController() { return zoom_controller_; }
|
||||
|
||||
protected:
|
||||
WebContents(v8::Isolate* isolate,
|
||||
content::WebContents* web_contents,
|
||||
|
@ -301,6 +319,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
const content::ResourceRequestDetails& details) override;
|
||||
void DidGetRedirectForResourceRequest(
|
||||
const content::ResourceRedirectDetails& details) override;
|
||||
void DidStartNavigation(
|
||||
content::NavigationHandle* navigation_handle) override;
|
||||
void DidFinishNavigation(
|
||||
content::NavigationHandle* navigation_handle) override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
|
@ -318,6 +338,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
const MediaPlayerId& id) override;
|
||||
void DidChangeThemeColor(SkColor theme_color) override;
|
||||
|
||||
// content::NotificationObserver:
|
||||
void Observe(int type,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) override;
|
||||
|
||||
// brightray::InspectableWebContentsDelegate:
|
||||
void DevToolsReloadPage() override;
|
||||
|
||||
|
@ -327,6 +352,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void DevToolsClosed() override;
|
||||
|
||||
private:
|
||||
struct LoadURLParams {
|
||||
LoadURLParams() : params(GURL()), id(0) {}
|
||||
|
||||
content::NavigationController::LoadURLParams params;
|
||||
int id;
|
||||
};
|
||||
|
||||
AtomBrowserContext* GetBrowserContext() const;
|
||||
|
||||
uint32_t GetNextRequestId() {
|
||||
|
@ -345,6 +377,14 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
const base::ListValue& args,
|
||||
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> devtools_web_contents_;
|
||||
v8::Global<v8::Value> debugger_;
|
||||
|
@ -354,6 +394,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
// The host webcontents that may contain this webcontents.
|
||||
WebContents* embedder_;
|
||||
|
||||
// The zoom controller for this webContents.
|
||||
WebContentsZoomController* zoom_controller_;
|
||||
|
||||
// The type of current WebContents.
|
||||
Type type_;
|
||||
|
||||
|
@ -366,6 +409,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
// Whether to 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);
|
||||
};
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/web_contents_preferences.h"
|
||||
#include "atom/browser/web_contents_zoom_controller.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/common/native_mate_converters/content_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "content/public/browser/browser_context.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,
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "atom/browser/api/atom_api_window.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_web_contents.h"
|
||||
#include "atom/browser/browser.h"
|
||||
|
@ -172,7 +173,7 @@ void Window::WillDestroyNativeObject() {
|
|||
}
|
||||
|
||||
void Window::OnWindowClosed() {
|
||||
api_web_contents_->DestroyWebContents();
|
||||
api_web_contents_->DestroyWebContents(true /* async */);
|
||||
|
||||
RemoveFromWeakMap();
|
||||
window_->RemoveObserver(this);
|
||||
|
@ -190,6 +191,10 @@ void Window::OnWindowClosed() {
|
|||
FROM_HERE, GetDestroyClosure());
|
||||
}
|
||||
|
||||
void Window::OnWindowEndSession() {
|
||||
Emit("session-end");
|
||||
}
|
||||
|
||||
void Window::OnWindowBlur() {
|
||||
Emit("blur");
|
||||
}
|
||||
|
@ -262,6 +267,14 @@ void Window::OnWindowSwipe(const std::string& direction) {
|
|||
Emit("swipe", direction);
|
||||
}
|
||||
|
||||
void Window::OnWindowSheetBegin() {
|
||||
Emit("sheet-begin");
|
||||
}
|
||||
|
||||
void Window::OnWindowSheetEnd() {
|
||||
Emit("sheet-end");
|
||||
}
|
||||
|
||||
void Window::OnWindowEnterHtmlFullScreen() {
|
||||
Emit("enter-html-full-screen");
|
||||
}
|
||||
|
@ -282,6 +295,11 @@ void Window::OnExecuteWindowsCommand(const std::string& 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)
|
||||
void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {
|
||||
if (IsWindowMessageHooked(message)) {
|
||||
|
@ -811,6 +829,25 @@ std::vector<v8::Local<v8::Object>> Window::GetChildWindows() const {
|
|||
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 {
|
||||
return window_->is_modal();
|
||||
}
|
||||
|
@ -840,15 +877,28 @@ void Window::SetVibrancy(mate::Arguments* args) {
|
|||
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 {
|
||||
return weak_map_id();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
|
||||
if (web_contents_.IsEmpty())
|
||||
if (web_contents_.IsEmpty()) {
|
||||
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() {
|
||||
|
@ -893,6 +943,8 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
|||
#endif
|
||||
.SetMethod("getParentWindow", &Window::GetParentWindow)
|
||||
.SetMethod("getChildWindows", &Window::GetChildWindows)
|
||||
.SetMethod("getBrowserView", &Window::GetBrowserView)
|
||||
.SetMethod("setBrowserView", &Window::SetBrowserView)
|
||||
.SetMethod("isModal", &Window::IsModal)
|
||||
.SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle)
|
||||
.SetMethod("getBounds", &Window::GetBounds)
|
||||
|
@ -960,6 +1012,9 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setAutoHideCursor", &Window::SetAutoHideCursor)
|
||||
#endif
|
||||
.SetMethod("setVibrancy", &Window::SetVibrancy)
|
||||
.SetMethod("_setTouchBarItems", &Window::SetTouchBar)
|
||||
.SetMethod("_refreshTouchBarItem", &Window::RefreshTouchBarItem)
|
||||
.SetMethod("_setEscapeTouchBarItem", &Window::SetEscapeTouchBarItem)
|
||||
#if defined(OS_WIN)
|
||||
.SetMethod("hookWindowMessage", &Window::HookWindowMessage)
|
||||
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "atom/common/api/atom_api_native_image.h"
|
||||
#include "atom/common/key_weak_map.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "native_mate/persistent_dictionary.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
class GURL;
|
||||
|
@ -51,6 +52,8 @@ class Window : public mate::TrackableObject<Window>,
|
|||
|
||||
NativeWindow* window() const { return window_.get(); }
|
||||
|
||||
int32_t ID() const;
|
||||
|
||||
protected:
|
||||
Window(v8::Isolate* isolate, v8::Local<v8::Object> wrapper,
|
||||
const mate::Dictionary& options);
|
||||
|
@ -60,6 +63,7 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void WillCloseWindow(bool* prevent_default) override;
|
||||
void WillDestroyNativeObject() override;
|
||||
void OnWindowClosed() override;
|
||||
void OnWindowEndSession() override;
|
||||
void OnWindowBlur() override;
|
||||
void OnWindowFocus() override;
|
||||
void OnWindowShow() override;
|
||||
|
@ -76,6 +80,8 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void OnWindowScrollTouchEnd() override;
|
||||
void OnWindowScrollTouchEdge() override;
|
||||
void OnWindowSwipe(const std::string& direction) override;
|
||||
void OnWindowSheetBegin() override;
|
||||
void OnWindowSheetEnd() override;
|
||||
void OnWindowEnterFullScreen() override;
|
||||
void OnWindowLeaveFullScreen() override;
|
||||
void OnWindowEnterHtmlFullScreen() override;
|
||||
|
@ -83,6 +89,8 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void OnRendererUnresponsive() override;
|
||||
void OnRendererResponsive() 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)
|
||||
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);
|
||||
v8::Local<v8::Value> GetParentWindow() 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;
|
||||
v8::Local<v8::Value> GetNativeWindowHandle();
|
||||
|
||||
|
@ -201,8 +211,10 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void SetAutoHideCursor(bool auto_hide);
|
||||
|
||||
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);
|
||||
|
||||
// Remove this window from parent window's |child_windows_|.
|
||||
|
@ -213,6 +225,7 @@ class Window : public mate::TrackableObject<Window>,
|
|||
MessageCallbackMap messages_callback_map_;
|
||||
#endif
|
||||
|
||||
v8::Global<v8::Value> browser_view_;
|
||||
v8::Global<v8::Value> web_contents_;
|
||||
v8::Global<v8::Value> menu_;
|
||||
v8::Global<v8::Value> parent_window_;
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/common/google_api_key.h"
|
||||
#include "base/environment.h"
|
||||
#include "content/public/browser/browser_thread.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;
|
||||
|
||||
|
@ -19,51 +21,40 @@ namespace atom {
|
|||
|
||||
namespace internal {
|
||||
|
||||
// Loads access tokens and other necessary data on the UI thread, and
|
||||
// calls back to the originator on the originating thread.
|
||||
class TokenLoadingJob : public base::RefCountedThreadSafe<TokenLoadingJob> {
|
||||
class GeoURLRequestContextGetter : public net::URLRequestContextGetter {
|
||||
public:
|
||||
explicit TokenLoadingJob(
|
||||
const device::AccessTokenStore::LoadAccessTokensCallback& callback)
|
||||
: callback_(callback), request_context_getter_(nullptr) {}
|
||||
net::URLRequestContext* GetURLRequestContext() override {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
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) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
request_context_getter_ = browser_context->GetRequestContext();
|
||||
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));
|
||||
scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
|
||||
const override {
|
||||
return BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<TokenLoadingJob>;
|
||||
friend class atom::AtomAccessTokenStore;
|
||||
|
||||
~TokenLoadingJob() {}
|
||||
GeoURLRequestContextGetter() {}
|
||||
~GeoURLRequestContextGetter() override {}
|
||||
|
||||
void RespondOnIOThread() {
|
||||
// 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);
|
||||
|
||||
callback_.Run(access_token_map, request_context_getter_);
|
||||
}
|
||||
|
||||
device::AccessTokenStore::LoadAccessTokensCallback callback_;
|
||||
net::URLRequestContextGetter* request_context_getter_;
|
||||
std::string api_key_;
|
||||
std::unique_ptr<net::URLRequestContext> url_request_context_;
|
||||
DISALLOW_COPY_AND_ASSIGN(GeoURLRequestContextGetter);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
AtomAccessTokenStore::AtomAccessTokenStore() {
|
||||
browser_context_ = AtomBrowserContext::From("", false);
|
||||
AtomAccessTokenStore::AtomAccessTokenStore()
|
||||
: request_context_getter_(new internal::GeoURLRequestContextGetter) {
|
||||
device::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices();
|
||||
}
|
||||
|
||||
|
@ -72,16 +63,19 @@ AtomAccessTokenStore::~AtomAccessTokenStore() {
|
|||
|
||||
void AtomAccessTokenStore::LoadAccessTokens(
|
||||
const LoadAccessTokensCallback& callback) {
|
||||
scoped_refptr<internal::TokenLoadingJob> job(
|
||||
new internal::TokenLoadingJob(callback));
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&AtomAccessTokenStore::RunTokenLoadingJob,
|
||||
this, base::RetainedRef(job)));
|
||||
}
|
||||
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||
std::string api_key;
|
||||
if (!env->GetVar("GOOGLE_API_KEY", &api_key))
|
||||
api_key = GOOGLEAPIS_API_KEY;
|
||||
// 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(
|
||||
scoped_refptr<internal::TokenLoadingJob> job) {
|
||||
job->Run(browser_context_.get());
|
||||
callback.Run(access_token_map, request_context_getter_.get());
|
||||
}
|
||||
|
||||
void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url,
|
||||
|
|
|
@ -9,10 +9,8 @@
|
|||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
namespace internal {
|
||||
class TokenLoadingJob;
|
||||
class GeoURLRequestContextGetter;
|
||||
}
|
||||
|
||||
class AtomAccessTokenStore : public device::AccessTokenStore {
|
||||
|
@ -27,9 +25,7 @@ class AtomAccessTokenStore : public device::AccessTokenStore {
|
|||
const base::string16& access_token) override;
|
||||
|
||||
private:
|
||||
void RunTokenLoadingJob(scoped_refptr<internal::TokenLoadingJob> job);
|
||||
|
||||
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||
scoped_refptr<internal::GeoURLRequestContextGetter> request_context_getter_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore);
|
||||
};
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ std::string AtomBrowserClient::GetApplicationLocale() {
|
|||
}
|
||||
|
||||
void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
content::BrowserContext* browser_context,
|
||||
content::SiteInstance* current_instance,
|
||||
const GURL& url,
|
||||
|
@ -234,6 +235,11 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
|||
}
|
||||
#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);
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
|
|
@ -54,6 +54,7 @@ class AtomBrowserClient : public brightray::BrowserClient,
|
|||
content::WebPreferences* prefs) override;
|
||||
std::string GetApplicationLocale() override;
|
||||
void OverrideSiteInstanceForNavigation(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
content::BrowserContext* browser_context,
|
||||
content::SiteInstance* current_instance,
|
||||
const GURL& dest_url,
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
#include "atom/browser/atom_access_token_store.h"
|
||||
#include "atom/browser/atom_browser_client.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/browser.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/browser/node_debugger.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_includes.h"
|
||||
#include "base/command_line.h"
|
||||
|
@ -59,8 +61,8 @@ AtomBrowserMainParts::AtomBrowserMainParts()
|
|||
: fake_browser_process_(new BrowserProcess),
|
||||
exit_code_(nullptr),
|
||||
browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)),
|
||||
atom_bindings_(new AtomBindings),
|
||||
node_bindings_(NodeBindings::Create(NodeBindings::BROWSER)),
|
||||
atom_bindings_(new AtomBindings(uv_default_loop())),
|
||||
gc_timer_(true, true) {
|
||||
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
||||
self_ = this;
|
||||
|
@ -70,6 +72,7 @@ AtomBrowserMainParts::AtomBrowserMainParts()
|
|||
}
|
||||
|
||||
AtomBrowserMainParts::~AtomBrowserMainParts() {
|
||||
asar::ClearArchives();
|
||||
// Leak the JavascriptEnvironment on exit.
|
||||
// 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
|
||||
|
@ -132,6 +135,7 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
|
|||
// Create the global environment.
|
||||
node::Environment* env =
|
||||
node_bindings_->CreateEnvironment(js_env_->context());
|
||||
node_env_.reset(new NodeEnvironment(env));
|
||||
|
||||
// Make sure node can get correct environment when debugging.
|
||||
if (node_debugger_->IsRunning())
|
||||
|
@ -165,6 +169,9 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
|||
base::Bind(&v8::Isolate::LowMemoryNotification,
|
||||
base::Unretained(js_env_->isolate())));
|
||||
|
||||
content::WebUIControllerFactory::RegisterFactory(
|
||||
AtomWebUIControllerFactory::GetInstance());
|
||||
|
||||
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
||||
bridge_task_runner_->MessageLoopIsReady();
|
||||
bridge_task_runner_ = nullptr;
|
||||
|
|
|
@ -22,6 +22,7 @@ class Browser;
|
|||
class JavascriptEnvironment;
|
||||
class NodeBindings;
|
||||
class NodeDebugger;
|
||||
class NodeEnvironment;
|
||||
class BridgeTaskRunner;
|
||||
|
||||
class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
|
@ -81,6 +82,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
std::unique_ptr<JavascriptEnvironment> js_env_;
|
||||
std::unique_ptr<NodeBindings> node_bindings_;
|
||||
std::unique_ptr<AtomBindings> atom_bindings_;
|
||||
std::unique_ptr<NodeEnvironment> node_env_;
|
||||
std::unique_ptr<NodeDebugger> node_debugger_;
|
||||
|
||||
base::Timer gc_timer_;
|
||||
|
|
|
@ -90,10 +90,11 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
|||
base::FilePath path;
|
||||
GetItemSavePath(item, &path);
|
||||
// Show save dialog if save path was not set already on item
|
||||
if (path.empty() && file_dialog::ShowSaveDialog(window, item->GetURL().spec(),
|
||||
"", default_path,
|
||||
file_dialog::Filters(),
|
||||
&path)) {
|
||||
file_dialog::DialogSettings settings;
|
||||
settings.parent_window = window;
|
||||
settings.title = item->GetURL().spec();
|
||||
settings.default_path = default_path;
|
||||
if (path.empty() && file_dialog::ShowSaveDialog(settings, &path)) {
|
||||
// Remember the last selected download directory.
|
||||
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
|
|
|
@ -38,14 +38,9 @@ void AtomJavaScriptDialogManager::RunJavaScriptDialog(
|
|||
}
|
||||
|
||||
atom::ShowMessageBox(NativeWindow::FromWebContents(web_contents),
|
||||
atom::MessageBoxType::MESSAGE_BOX_TYPE_NONE,
|
||||
buttons,
|
||||
-1,
|
||||
0,
|
||||
atom::MessageBoxOptions::MESSAGE_BOX_NONE,
|
||||
"",
|
||||
base::UTF16ToUTF8(message_text),
|
||||
"",
|
||||
atom::MessageBoxType::MESSAGE_BOX_TYPE_NONE, buttons, -1,
|
||||
0, atom::MessageBoxOptions::MESSAGE_BOX_NONE, "",
|
||||
base::UTF16ToUTF8(message_text), "", "", false,
|
||||
gfx::ImageSkia(),
|
||||
base::Bind(&OnMessageBoxCallback, callback));
|
||||
}
|
||||
|
@ -66,7 +61,9 @@ void AtomJavaScriptDialogManager::CancelDialogs(
|
|||
|
||||
// static
|
||||
void AtomJavaScriptDialogManager::OnMessageBoxCallback(
|
||||
const DialogClosedCallback& callback, int code) {
|
||||
const DialogClosedCallback& callback,
|
||||
int code,
|
||||
bool checkbox_checked) {
|
||||
callback.Run(code == 0, base::string16());
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager {
|
|||
|
||||
private:
|
||||
static void OnMessageBoxCallback(const DialogClosedCallback& callback,
|
||||
int code);
|
||||
int code,
|
||||
bool checkbox_checked);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
|
||||
#include "atom/browser/login_handler.h"
|
||||
#include "atom/browser/web_contents_permission_helper.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "atom/common/platform_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/stream_info.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "net/ssl/client_cert_store.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
#if defined(USE_NSS_CERTS)
|
||||
|
@ -57,6 +61,23 @@ void HandleExternalProtocolInUI(
|
|||
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
|
||||
|
||||
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
|
||||
|
@ -95,4 +116,23 @@ AtomResourceDispatcherHostDelegate::CreateClientCertStore(
|
|||
#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
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#ifndef 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"
|
||||
|
||||
namespace atom {
|
||||
|
@ -22,6 +24,14 @@ class AtomResourceDispatcherHostDelegate
|
|||
net::URLRequest* request) override;
|
||||
std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
|
||||
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
|
||||
|
|
66
atom/browser/atom_web_ui_controller_factory.cc
Normal file
66
atom/browser/atom_web_ui_controller_factory.cc
Normal 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
|
40
atom/browser/atom_web_ui_controller_factory.h
Normal file
40
atom/browser/atom_web_ui_controller_factory.h
Normal 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_
|
|
@ -27,7 +27,7 @@ namespace {
|
|||
bool g_update_available = false;
|
||||
std::string update_url_ = "";
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string AutoUpdater::GetFeedURL() {
|
||||
return update_url_;
|
||||
|
|
|
@ -43,11 +43,10 @@ void Browser::Quit() {
|
|||
if (!is_quiting_)
|
||||
return;
|
||||
|
||||
atom::WindowList* window_list = atom::WindowList::GetInstance();
|
||||
if (window_list->size() == 0)
|
||||
if (atom::WindowList::IsEmpty())
|
||||
NotifyAndShutdown();
|
||||
|
||||
window_list->CloseAllWindows();
|
||||
else
|
||||
atom::WindowList::CloseAllWindows();
|
||||
}
|
||||
|
||||
void Browser::Exit(mate::Arguments* args) {
|
||||
|
@ -65,14 +64,12 @@ void Browser::Exit(mate::Arguments* args) {
|
|||
is_exiting_ = true;
|
||||
|
||||
// Must destroy windows before quitting, otherwise bad things can happen.
|
||||
atom::WindowList* window_list = atom::WindowList::GetInstance();
|
||||
if (window_list->size() == 0) {
|
||||
if (atom::WindowList::IsEmpty()) {
|
||||
Shutdown();
|
||||
} else {
|
||||
// Unlike Quit(), we do not ask to close window, but destroy the window
|
||||
// without asking.
|
||||
for (NativeWindow* window : *window_list)
|
||||
window->CloseContents(nullptr); // e.g. Destroy()
|
||||
atom::WindowList::DestroyAllWindows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ class Browser : public WindowListObserver {
|
|||
std::vector<base::string16> args;
|
||||
};
|
||||
void SetLoginItemSettings(LoginItemSettings settings);
|
||||
LoginItemSettings GetLoginItemSettings(LoginItemSettings options);
|
||||
LoginItemSettings GetLoginItemSettings(const LoginItemSettings& options);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Hide the application.
|
||||
|
|
|
@ -16,9 +16,7 @@ namespace atom {
|
|||
|
||||
void Browser::Focus() {
|
||||
// Focus on the first visible window.
|
||||
WindowList* list = WindowList::GetInstance();
|
||||
for (WindowList::iterator iter = list->begin(); iter != list->end(); ++iter) {
|
||||
NativeWindow* window = *iter;
|
||||
for (const auto& window : WindowList::GetWindows()) {
|
||||
if (window->IsVisible()) {
|
||||
window->Focus(true);
|
||||
break;
|
||||
|
@ -64,7 +62,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) {
|
|||
}
|
||||
|
||||
Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
LoginItemSettings options) {
|
||||
const LoginItemSettings& options) {
|
||||
return LoginItemSettings();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
// Apple's defaults first, so we'll use the first option that isn't our bundle
|
||||
CFStringRef other = nil;
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(bundleList); i++) {
|
||||
other = (CFStringRef)CFArrayGetValueAtIndex(bundleList, i);
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(bundleList); ++i) {
|
||||
other = base::mac::CFCast<CFStringRef>(CFArrayGetValueAtIndex(bundleList,
|
||||
i));
|
||||
if (![identifier isEqualToString: (__bridge NSString *)other]) {
|
||||
break;
|
||||
}
|
||||
|
@ -152,7 +153,7 @@ bool Browser::ContinueUserActivity(const std::string& type,
|
|||
}
|
||||
|
||||
Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
LoginItemSettings options) {
|
||||
const LoginItemSettings& options) {
|
||||
LoginItemSettings settings;
|
||||
settings.open_at_login = base::mac::CheckLoginItemStatus(
|
||||
&settings.open_as_hidden);
|
||||
|
@ -179,7 +180,7 @@ std::string Browser::GetExecutableFileProductName() const {
|
|||
|
||||
int Browser::DockBounce(BounceType type) {
|
||||
return [[AtomApplication sharedApplication]
|
||||
requestUserAttention:(NSRequestUserAttentionType)type];
|
||||
requestUserAttention:static_cast<NSRequestUserAttentionType>(type)];
|
||||
}
|
||||
|
||||
void Browser::DockCancelBounce(int request_id) {
|
||||
|
@ -203,9 +204,8 @@ std::string Browser::DockGetBadgeText() {
|
|||
}
|
||||
|
||||
void Browser::DockHide() {
|
||||
WindowList* list = WindowList::GetInstance();
|
||||
for (WindowList::iterator it = list->begin(); it != list->end(); ++it)
|
||||
[(*it)->GetNativeWindow() setCanHide:NO];
|
||||
for (const auto& window : WindowList::GetWindows())
|
||||
[window->GetNativeWindow() setCanHide:NO];
|
||||
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||
TransformProcessType(&psn, kProcessTransformToUIElementApplication);
|
||||
|
|
|
@ -61,11 +61,11 @@ bool GetProtocolLaunchPath(mate::Arguments* args, base::string16* exe) {
|
|||
// Read in optional args arg
|
||||
std::vector<base::string16> launch_args;
|
||||
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(),
|
||||
base::JoinString(launch_args, L" ").c_str());
|
||||
else
|
||||
*exe = base::StringPrintf(L"\"%s\" \"%%1\"", exe->c_str());
|
||||
*exe = base::StringPrintf(L"\"%ls\" \"%%1\"", exe->c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,7 @@ bool FormatCommandLineString(base::string16* exe,
|
|||
}
|
||||
|
||||
if (!launch_args.empty()) {
|
||||
base::string16 formatString = L"%s %s";
|
||||
*exe = base::StringPrintf(formatString.c_str(),
|
||||
*exe = base::StringPrintf(L"%ls %ls",
|
||||
exe->c_str(),
|
||||
base::JoinString(launch_args, L" ").c_str());
|
||||
}
|
||||
|
@ -287,7 +286,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) {
|
|||
}
|
||||
|
||||
Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
LoginItemSettings options) {
|
||||
const LoginItemSettings& options) {
|
||||
LoginItemSettings settings;
|
||||
base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
||||
base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
|
||||
|
|
|
@ -178,13 +178,23 @@ void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) {
|
|||
|
||||
void CommonWebContentsDelegate::SetOwnerWindow(
|
||||
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_);
|
||||
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() {
|
||||
web_contents_.reset();
|
||||
void CommonWebContentsDelegate::ResetManagedWebContents(bool async) {
|
||||
if (async) {
|
||||
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
|
||||
web_contents_.release());
|
||||
} else {
|
||||
web_contents_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
content::WebContents* CommonWebContentsDelegate::GetWebContents() const {
|
||||
|
@ -294,10 +304,11 @@ void CommonWebContentsDelegate::DevToolsSaveToFile(
|
|||
if (it != saved_files_.end() && !save_as) {
|
||||
path = it->second;
|
||||
} else {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url));
|
||||
if (!file_dialog::ShowSaveDialog(owner_window(), url, "", default_path,
|
||||
filters, &path)) {
|
||||
file_dialog::DialogSettings settings;
|
||||
settings.parent_window = owner_window();
|
||||
settings.title = url;
|
||||
settings.default_path = base::FilePath::FromUTF8Unsafe(url);
|
||||
if (!file_dialog::ShowSaveDialog(settings, &path)) {
|
||||
base::StringValue url_value(url);
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr);
|
||||
|
@ -337,7 +348,7 @@ void CommonWebContentsDelegate::DevToolsRequestFileSystems() {
|
|||
}
|
||||
|
||||
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);
|
||||
std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(),
|
||||
path);
|
||||
|
@ -358,12 +369,11 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem(
|
|||
const base::FilePath& file_system_path) {
|
||||
base::FilePath path = file_system_path;
|
||||
if (path.empty()) {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path;
|
||||
std::vector<base::FilePath> paths;
|
||||
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
|
||||
if (!file_dialog::ShowOpenDialog(owner_window(), "", "", default_path,
|
||||
filters, flag, &paths))
|
||||
file_dialog::DialogSettings settings;
|
||||
settings.parent_window = owner_window();
|
||||
settings.properties = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
|
||||
if (!file_dialog::ShowOpenDialog(settings, &paths))
|
||||
return;
|
||||
|
||||
path = paths[0];
|
||||
|
|
|
@ -42,9 +42,6 @@ class CommonWebContentsDelegate
|
|||
void SetOwnerWindow(content::WebContents* web_contents,
|
||||
NativeWindow* owner_window);
|
||||
|
||||
// Destroy the managed InspectableWebContents object.
|
||||
void DestroyWebContents();
|
||||
|
||||
// Returns the WebContents managed by this delegate.
|
||||
content::WebContents* GetWebContents() const;
|
||||
|
||||
|
@ -114,6 +111,9 @@ class CommonWebContentsDelegate
|
|||
std::string* name, std::string* class_name) override;
|
||||
#endif
|
||||
|
||||
// Destroy the managed InspectableWebContents object.
|
||||
void ResetManagedWebContents(bool async);
|
||||
|
||||
private:
|
||||
// Callback for when DevToolsSaveToFile has completed.
|
||||
void OnDevToolsSaveToFile(const std::string& url);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "gin/array_buffer.h"
|
||||
#include "gin/v8_initializer.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
JavascriptEnvironment::JavascriptEnvironment()
|
||||
|
@ -46,4 +48,11 @@ bool JavascriptEnvironment::Initialize() {
|
|||
return true;
|
||||
}
|
||||
|
||||
NodeEnvironment::NodeEnvironment(node::Environment* env) : env_(env) {
|
||||
}
|
||||
|
||||
NodeEnvironment::~NodeEnvironment() {
|
||||
node::FreeEnvironment(env_);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -8,8 +8,13 @@
|
|||
#include "base/macros.h"
|
||||
#include "gin/public/isolate_holder.h"
|
||||
|
||||
namespace node {
|
||||
class Environment;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Manage the V8 isolate and context automatically.
|
||||
class JavascriptEnvironment {
|
||||
public:
|
||||
JavascriptEnvironment();
|
||||
|
@ -37,6 +42,18 @@ class 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
|
||||
|
||||
#endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_
|
||||
|
|
26
atom/browser/loader/layered_resource_handler.cc
Normal file
26
atom/browser/loader/layered_resource_handler.cc
Normal 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
|
40
atom/browser/loader/layered_resource_handler.h
Normal file
40
atom/browser/loader/layered_resource_handler.h
Normal 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_
|
|
@ -10,10 +10,6 @@
|
|||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
|
||||
@interface NSWindow (SierraSDK)
|
||||
@property(class) BOOL allowsAutomaticWindowTabbing;
|
||||
@end
|
||||
|
||||
@implementation AtomApplicationDelegate
|
||||
|
||||
- (void)setApplicationDockMenu:(atom::AtomMenuModel*)model {
|
||||
|
@ -25,10 +21,6 @@
|
|||
// Don't add the "Enter Full Screen" menu item automatically.
|
||||
[[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();
|
||||
}
|
||||
|
||||
|
|
18
atom/browser/native_browser_view.cc
Normal file
18
atom/browser/native_browser_view.cc
Normal 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
|
57
atom/browser/native_browser_view.h
Normal file
57
atom/browser/native_browser_view.h
Normal 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_
|
30
atom/browser/native_browser_view_mac.h
Normal file
30
atom/browser/native_browser_view_mac.h
Normal 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_
|
60
atom/browser/native_browser_view_mac.mm
Normal file
60
atom/browser/native_browser_view_mac.mm
Normal 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
|
36
atom/browser/native_browser_view_views.cc
Normal file
36
atom/browser/native_browser_view_views.cc
Normal 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
|
33
atom/browser/native_browser_view_views.h
Normal file
33
atom/browser/native_browser_view_views.h
Normal 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_
|
|
@ -104,8 +104,7 @@ NativeWindow::~NativeWindow() {
|
|||
// static
|
||||
NativeWindow* NativeWindow::FromWebContents(
|
||||
content::WebContents* web_contents) {
|
||||
WindowList& window_list = *WindowList::GetInstance();
|
||||
for (NativeWindow* window : window_list) {
|
||||
for (const auto& window : WindowList::GetWindows()) {
|
||||
if (window->web_contents() == web_contents)
|
||||
return window;
|
||||
}
|
||||
|
@ -340,6 +339,17 @@ void NativeWindow::SetAutoHideCursor(bool auto_hide) {
|
|||
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() {
|
||||
web_contents()->GetRenderViewHost()->GetWidget()->Focus();
|
||||
}
|
||||
|
@ -464,6 +474,11 @@ void NativeWindow::NotifyWindowClosed() {
|
|||
observer.OnWindowClosed();
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowEndSession() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowEndSession();
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowBlur() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowBlur();
|
||||
|
@ -531,7 +546,7 @@ void NativeWindow::NotifyWindowScrollTouchBegin() {
|
|||
|
||||
void NativeWindow::NotifyWindowScrollTouchEnd() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowScrollTouchEdge();
|
||||
observer.OnWindowScrollTouchEnd();
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowScrollTouchEdge() {
|
||||
|
@ -544,6 +559,16 @@ void NativeWindow::NotifyWindowSwipe(const std::string& 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() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowLeaveFullScreen();
|
||||
|
@ -565,6 +590,13 @@ void NativeWindow::NotifyWindowExecuteWindowsCommand(
|
|||
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)
|
||||
void NativeWindow::NotifyWindowMessage(
|
||||
UINT message, WPARAM w_param, LPARAM l_param) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_contents_user_data.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_skia.h"
|
||||
|
||||
|
@ -46,6 +47,8 @@ class Dictionary;
|
|||
|
||||
namespace atom {
|
||||
|
||||
class NativeBrowserView;
|
||||
|
||||
struct DraggableRegion;
|
||||
|
||||
class NativeWindow : public base::SupportsUserData,
|
||||
|
@ -124,6 +127,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
std::string* error = nullptr) = 0;
|
||||
virtual bool IsAlwaysOnTop() = 0;
|
||||
virtual void Center() = 0;
|
||||
virtual void Invalidate() = 0;
|
||||
virtual void SetTitle(const std::string& title) = 0;
|
||||
virtual std::string GetTitle() = 0;
|
||||
virtual void FlashFrame(bool flash) = 0;
|
||||
|
@ -142,6 +146,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual void SetFocusable(bool focusable);
|
||||
virtual void SetMenu(AtomMenuModel* menu);
|
||||
virtual void SetParentWindow(NativeWindow* parent);
|
||||
virtual void SetBrowserView(NativeBrowserView* browser_view) = 0;
|
||||
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
||||
virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
|
||||
|
||||
|
@ -168,6 +173,12 @@ class NativeWindow : public base::SupportsUserData,
|
|||
// Vibrancy API
|
||||
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.
|
||||
virtual void FocusOnWebView();
|
||||
virtual void BlurWebView();
|
||||
|
@ -207,6 +218,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
// Public API used by platform-dependent delegates and observers to send UI
|
||||
// related notifications.
|
||||
void NotifyWindowClosed();
|
||||
void NotifyWindowEndSession();
|
||||
void NotifyWindowBlur();
|
||||
void NotifyWindowFocus();
|
||||
void NotifyWindowShow();
|
||||
|
@ -222,11 +234,15 @@ class NativeWindow : public base::SupportsUserData,
|
|||
void NotifyWindowScrollTouchEnd();
|
||||
void NotifyWindowScrollTouchEdge();
|
||||
void NotifyWindowSwipe(const std::string& direction);
|
||||
void NotifyWindowSheetBegin();
|
||||
void NotifyWindowSheetEnd();
|
||||
void NotifyWindowEnterFullScreen();
|
||||
void NotifyWindowLeaveFullScreen();
|
||||
void NotifyWindowEnterHtmlFullScreen();
|
||||
void NotifyWindowLeaveHtmlFullScreen();
|
||||
void NotifyWindowExecuteWindowsCommand(const std::string& command);
|
||||
void NotifyTouchBarItemInteraction(const std::string& item_id,
|
||||
const base::DictionaryValue& details);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param);
|
||||
|
|
|
@ -71,6 +71,7 @@ class NativeWindowMac : public NativeWindow,
|
|||
int relativeLevel, std::string* error) override;
|
||||
bool IsAlwaysOnTop() override;
|
||||
void Center() override;
|
||||
void Invalidate() override;
|
||||
void SetTitle(const std::string& title) override;
|
||||
std::string GetTitle() override;
|
||||
void FlashFrame(bool flash) override;
|
||||
|
@ -86,6 +87,7 @@ class NativeWindowMac : public NativeWindow,
|
|||
bool IsDocumentEdited() override;
|
||||
void SetIgnoreMouseEvents(bool ignore) override;
|
||||
void SetContentProtection(bool enable) override;
|
||||
void SetBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetParentWindow(NativeWindow* parent) override;
|
||||
gfx::NativeWindow GetNativeWindow() override;
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() override;
|
||||
|
@ -99,6 +101,10 @@ class NativeWindowMac : public NativeWindow,
|
|||
void SetAutoHideCursor(bool auto_hide) 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:
|
||||
void OnInputEvent(const blink::WebInputEvent& event) override;
|
||||
|
@ -159,6 +165,8 @@ class NativeWindowMac : public NativeWindow,
|
|||
// The view that will fill the whole frameless window.
|
||||
base::scoped_nsobject<FullSizeContentView> content_view_;
|
||||
|
||||
NativeBrowserView* browser_view_;
|
||||
|
||||
std::vector<DraggableRegion> draggable_regions_;
|
||||
|
||||
bool is_kiosk_;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <Quartz/Quartz.h>
|
||||
#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/common/color_util.h"
|
||||
#include "atom/common/draggable_region.h"
|
||||
|
@ -18,9 +20,9 @@
|
|||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "brightray/browser/mac/event_dispatching_window.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_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "skia/ext/skia_utils_mac.h"
|
||||
#include "third_party/skia/include/core/SkRegion.h"
|
||||
|
@ -228,7 +230,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
- (void)windowWillEnterFullScreen:(NSNotification*)notification {
|
||||
// Hide the native toolbar before entering fullscreen, so there is no visual
|
||||
// artifacts.
|
||||
if (base::mac::IsOS10_10() &&
|
||||
if (base::mac::IsAtLeastOS10_10() &&
|
||||
shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
|
||||
NSWindow* window = shell_->GetNativeWindow();
|
||||
[window setToolbar:nil];
|
||||
|
@ -243,7 +245,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
// have to set one, because title bar is visible here.
|
||||
NSWindow* window = shell_->GetNativeWindow();
|
||||
if ((shell_->transparent() || !shell_->has_frame()) &&
|
||||
base::mac::IsOS10_10() &&
|
||||
base::mac::IsAtLeastOS10_10() &&
|
||||
// FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under
|
||||
// fullscreen mode.
|
||||
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
|
||||
// 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) {
|
||||
base::scoped_nsobject<NSToolbar> toolbar(
|
||||
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
|
||||
|
@ -269,13 +271,13 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
// Restore the titlebar visibility.
|
||||
NSWindow* window = shell_->GetNativeWindow();
|
||||
if ((shell_->transparent() || !shell_->has_frame()) &&
|
||||
base::mac::IsOS10_10() &&
|
||||
base::mac::IsAtLeastOS10_10() &&
|
||||
shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) {
|
||||
[window setTitleVisibility:NSWindowTitleHidden];
|
||||
}
|
||||
|
||||
// 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_->SetStyleMask(false, NSFullSizeContentViewWindowMask);
|
||||
}
|
||||
|
@ -311,6 +313,14 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
return rect;
|
||||
}
|
||||
|
||||
- (void)windowWillBeginSheet:(NSNotification *)notification {
|
||||
shell_->NotifyWindowSheetBegin();
|
||||
}
|
||||
|
||||
- (void)windowDidEndSheet:(NSNotification *)notification {
|
||||
shell_->NotifyWindowSheetEnd();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface AtomPreviewItem : NSObject <QLPreviewItem>
|
||||
|
@ -335,10 +345,24 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
|
||||
@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
|
||||
atom::NativeWindowMac* shell_;
|
||||
bool enable_larger_than_screen_;
|
||||
base::scoped_nsobject<AtomTouchBar> atom_touch_bar_;
|
||||
CGFloat windowButtonsInterButtonSpacing_;
|
||||
}
|
||||
@property BOOL acceptsFirstMouse;
|
||||
|
@ -351,6 +375,10 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
- (void)setShell:(atom::NativeWindowMac*)shell;
|
||||
- (void)setEnableLargerThanScreen:(bool)enable;
|
||||
- (void)enableWindowButtonsOffset;
|
||||
- (void)resetTouchBar:(const std::vector<mate::PersistentDictionary>&)settings;
|
||||
- (void)refreshTouchBarItem:(const std::string&)item_id;
|
||||
- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AtomNSWindow
|
||||
|
@ -363,6 +391,40 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
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.
|
||||
|
||||
- (void)swipeWithEvent:(NSEvent *)event {
|
||||
|
@ -618,6 +680,7 @@ NativeWindowMac::NativeWindowMac(
|
|||
const mate::Dictionary& options,
|
||||
NativeWindow* parent)
|
||||
: NativeWindow(web_contents, options, parent),
|
||||
browser_view_(nullptr),
|
||||
is_kiosk_(false),
|
||||
was_fullscreen_(false),
|
||||
zoom_to_page_width_(false),
|
||||
|
@ -648,6 +711,9 @@ NativeWindowMac::NativeWindowMac(
|
|||
|
||||
options.Get(options::kTitleBarStyle, &title_bar_style_);
|
||||
|
||||
std::string tabbingIdentifier;
|
||||
options.Get(options::kTabbingIdentifier, &tabbingIdentifier);
|
||||
|
||||
std::string windowType;
|
||||
options.Get(options::kType, &windowType);
|
||||
|
||||
|
@ -712,7 +778,7 @@ NativeWindowMac::NativeWindowMac(
|
|||
[window_ setDisableKeyOrMainWindow:YES];
|
||||
|
||||
if (transparent() || !has_frame()) {
|
||||
if (base::mac::IsOS10_10()) {
|
||||
if (base::mac::IsAtLeastOS10_10()) {
|
||||
// Don't show title bar.
|
||||
[window_ setTitleVisibility:NSWindowTitleHidden];
|
||||
}
|
||||
|
@ -720,12 +786,24 @@ NativeWindowMac::NativeWindowMac(
|
|||
[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.
|
||||
[window_ setReleasedWhenClosed:NO];
|
||||
|
||||
// Hide the title bar.
|
||||
if (title_bar_style_ == HIDDEN_INSET) {
|
||||
if (base::mac::IsOS10_10()) {
|
||||
if (base::mac::IsAtLeastOS10_10()) {
|
||||
[window_ setTitlebarAppearsTransparent:YES];
|
||||
base::scoped_nsobject<NSToolbar> toolbar(
|
||||
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
|
||||
|
@ -1061,7 +1139,7 @@ void NativeWindowMac::SetAlwaysOnTop(bool top, const std::string& level,
|
|||
int windowLevel = NSNormalWindowLevel;
|
||||
CGWindowLevel maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey);
|
||||
CGWindowLevel minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey);
|
||||
|
||||
|
||||
if (top) {
|
||||
if (level == "floating") {
|
||||
windowLevel = NSFloatingWindowLevel;
|
||||
|
@ -1101,10 +1179,15 @@ void NativeWindowMac::Center() {
|
|||
[window_ center];
|
||||
}
|
||||
|
||||
void NativeWindowMac::Invalidate() {
|
||||
[window_ flushWindow];
|
||||
[[window_ contentView] setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetTitle(const std::string& title) {
|
||||
// For macOS <= 10.9, the setTitleVisibility API is not available, we have
|
||||
// to avoid calling setTitle for frameless window.
|
||||
if (!base::mac::IsOS10_10() && (transparent() || !has_frame()))
|
||||
if (!base::mac::IsAtLeastOS10_10() && (transparent() || !has_frame()))
|
||||
return;
|
||||
|
||||
[window_ setTitle:base::SysUTF8ToNSString(title)];
|
||||
|
@ -1196,6 +1279,26 @@ void NativeWindowMac::SetContentProtection(bool enable) {
|
|||
: 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) {
|
||||
if (is_modal())
|
||||
return;
|
||||
|
@ -1223,7 +1326,7 @@ void NativeWindowMac::SetProgressBar(double progress, const NativeWindow::Progre
|
|||
NSDockTile* dock_tile = [NSApp 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];
|
||||
[image_view setImage:[NSApp applicationIconImage]];
|
||||
[dock_tile setContentView:image_view];
|
||||
|
@ -1275,7 +1378,7 @@ void NativeWindowMac::SetAutoHideCursor(bool auto_hide) {
|
|||
}
|
||||
|
||||
void NativeWindowMac::SetVibrancy(const std::string& type) {
|
||||
if (!base::mac::IsOS10_10()) return;
|
||||
if (!base::mac::IsAtLeastOS10_10()) return;
|
||||
|
||||
NSView* vibrant_view = [window_ vibrantView];
|
||||
|
||||
|
@ -1314,33 +1417,46 @@ void NativeWindowMac::SetVibrancy(const std::string& type) {
|
|||
vibrancyType = NSVisualEffectMaterialTitlebar;
|
||||
}
|
||||
|
||||
if (base::mac::IsOS10_11()) {
|
||||
if (base::mac::IsAtLeastOS10_11()) {
|
||||
// TODO(kevinsawicki): Use NSVisualEffectMaterial* constants directly once
|
||||
// they are available in the minimum SDK version
|
||||
if (type == "selection") {
|
||||
// NSVisualEffectMaterialSelection
|
||||
vibrancyType = (NSVisualEffectMaterial) 4;
|
||||
vibrancyType = static_cast<NSVisualEffectMaterial>(4);
|
||||
} else if (type == "menu") {
|
||||
// NSVisualEffectMaterialMenu
|
||||
vibrancyType = (NSVisualEffectMaterial) 5;
|
||||
vibrancyType = static_cast<NSVisualEffectMaterial>(5);
|
||||
} else if (type == "popover") {
|
||||
// NSVisualEffectMaterialPopover
|
||||
vibrancyType = (NSVisualEffectMaterial) 6;
|
||||
vibrancyType = static_cast<NSVisualEffectMaterial>(6);
|
||||
} else if (type == "sidebar") {
|
||||
// NSVisualEffectMaterialSidebar
|
||||
vibrancyType = (NSVisualEffectMaterial) 7;
|
||||
vibrancyType = static_cast<NSVisualEffectMaterial>(7);
|
||||
} else if (type == "medium-light") {
|
||||
// NSVisualEffectMaterialMediumLight
|
||||
vibrancyType = (NSVisualEffectMaterial) 8;
|
||||
vibrancyType = static_cast<NSVisualEffectMaterial>(8);
|
||||
} else if (type == "ultra-dark") {
|
||||
// NSVisualEffectMaterialUltraDark
|
||||
vibrancyType = (NSVisualEffectMaterial) 9;
|
||||
vibrancyType = static_cast<NSVisualEffectMaterial>(9);
|
||||
}
|
||||
}
|
||||
|
||||
[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) {
|
||||
switch (event.type) {
|
||||
case blink::WebInputEvent::GestureScrollBegin:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/values.h"
|
||||
#include "ui/base/window_open_disposition.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
|
@ -39,6 +40,9 @@ class NativeWindowObserver {
|
|||
// Called when the window is closed.
|
||||
virtual void OnWindowClosed() {}
|
||||
|
||||
// Called when Windows sends WM_ENDSESSION message
|
||||
virtual void OnWindowEndSession() {}
|
||||
|
||||
// Called when window loses focus.
|
||||
virtual void OnWindowBlur() {}
|
||||
|
||||
|
@ -66,10 +70,14 @@ class NativeWindowObserver {
|
|||
virtual void OnWindowScrollTouchEnd() {}
|
||||
virtual void OnWindowScrollTouchEdge() {}
|
||||
virtual void OnWindowSwipe(const std::string& direction) {}
|
||||
virtual void OnWindowSheetBegin() {}
|
||||
virtual void OnWindowSheetEnd() {}
|
||||
virtual void OnWindowEnterFullScreen() {}
|
||||
virtual void OnWindowLeaveFullScreen() {}
|
||||
virtual void OnWindowEnterHtmlFullScreen() {}
|
||||
virtual void OnWindowLeaveHtmlFullScreen() {}
|
||||
virtual void OnTouchBarItemResult(const std::string& item_id,
|
||||
const base::DictionaryValue& details) {}
|
||||
|
||||
// Called when window message received
|
||||
#if defined(OS_WIN)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/native_browser_view_views.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/common/color_util.h"
|
||||
#include "atom/common/draggable_region.h"
|
||||
|
@ -48,6 +48,7 @@
|
|||
#include "ui/views/window/native_frame_view.h"
|
||||
#elif defined(OS_WIN)
|
||||
#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 "skia/ext/skia_utils_win.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
|
@ -134,6 +135,7 @@ NativeWindowViews::NativeWindowViews(
|
|||
: NativeWindow(web_contents, options, parent),
|
||||
window_(new views::Widget),
|
||||
web_view_(inspectable_web_contents()->GetView()->GetView()),
|
||||
browser_view_(nullptr),
|
||||
menu_bar_autohide_(false),
|
||||
menu_bar_visible_(false),
|
||||
menu_bar_alt_pressed_(false),
|
||||
|
@ -204,8 +206,7 @@ NativeWindowViews::NativeWindowViews(
|
|||
if (parent)
|
||||
params.parent = parent->GetNativeWindow();
|
||||
|
||||
params.native_widget =
|
||||
new views::DesktopNativeWidgetAura(window_.get());
|
||||
params.native_widget = new AtomDesktopNativeWidgetAura(window_.get());
|
||||
atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin(
|
||||
this,
|
||||
window_.get(),
|
||||
|
@ -274,9 +275,6 @@ NativeWindowViews::NativeWindowViews(
|
|||
SetWindowType(GetAcceleratedWidget(), window_type);
|
||||
#endif
|
||||
|
||||
// Add web view.
|
||||
SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
|
||||
|
||||
AddChildView(web_view_);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
@ -695,6 +693,10 @@ void NativeWindowViews::Center() {
|
|||
window_->CenterWindow(GetSize());
|
||||
}
|
||||
|
||||
void NativeWindowViews::Invalidate() {
|
||||
window_->SchedulePaintInRect(gfx::Rect(GetBounds().size()));
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetTitle(const std::string& title) {
|
||||
title_ = title;
|
||||
window_->UpdateWindowTitle();
|
||||
|
@ -877,6 +879,24 @@ void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) {
|
|||
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) {
|
||||
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() {
|
||||
return NativeWindow::GetMinimumSize();
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
int relativeLevel, std::string* error) override;
|
||||
bool IsAlwaysOnTop() override;
|
||||
void Center() override;
|
||||
void Invalidate() override;
|
||||
void SetTitle(const std::string& title) override;
|
||||
std::string GetTitle() override;
|
||||
void FlashFrame(bool flash) override;
|
||||
|
@ -103,6 +104,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
void SetContentProtection(bool enable) override;
|
||||
void SetFocusable(bool focusable) override;
|
||||
void SetMenu(AtomMenuModel* menu_model) override;
|
||||
void SetBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetParentWindow(NativeWindow* parent) override;
|
||||
gfx::NativeWindow GetNativeWindow() override;
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
|
@ -175,6 +177,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
const content::NativeWebKeyboardEvent& event) override;
|
||||
|
||||
// views::View:
|
||||
void Layout() override;
|
||||
gfx::Size GetMinimumSize() override;
|
||||
gfx::Size GetMaximumSize() override;
|
||||
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
|
||||
|
@ -188,6 +191,8 @@ class NativeWindowViews : public NativeWindow,
|
|||
std::unique_ptr<views::Widget> window_;
|
||||
views::View* web_view_; // Managed by inspectable_web_contents_.
|
||||
|
||||
NativeBrowserView* browser_view_;
|
||||
|
||||
std::unique_ptr<MenuBar> menu_bar_;
|
||||
bool menu_bar_autohide_;
|
||||
bool menu_bar_visible_;
|
||||
|
|
|
@ -147,6 +147,11 @@ bool NativeWindowViews::PreHandleMSG(
|
|||
}
|
||||
return false;
|
||||
}
|
||||
case WM_ENDSESSION: {
|
||||
if (w_param) {
|
||||
NotifyWindowEndSession();
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/net/atom_ct_delegate.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 "net/base/net_errors.h"
|
||||
#include "net/cert/cert_verify_result.h"
|
||||
|
@ -19,17 +22,130 @@ namespace atom {
|
|||
|
||||
namespace {
|
||||
|
||||
void OnResult(
|
||||
net::CertVerifyResult* verify_result,
|
||||
const net::CompletionCallback& callback,
|
||||
bool result) {
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(callback, result ? net::OK : net::ERR_FAILED));
|
||||
}
|
||||
class Response : public base::LinkNode<Response> {
|
||||
public:
|
||||
Response(net::CertVerifyResult* verify_result,
|
||||
const net::CompletionCallback& callback)
|
||||
: verify_result_(verify_result), callback_(callback) {}
|
||||
net::CertVerifyResult* verify_result() { return verify_result_; }
|
||||
net::CompletionCallback callback() { return callback_; }
|
||||
|
||||
private:
|
||||
net::CertVerifyResult* verify_result_;
|
||||
net::CompletionCallback callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Response);
|
||||
};
|
||||
|
||||
} // 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)
|
||||
: default_cert_verifier_(net::CertVerifier::CreateDefault()),
|
||||
ct_delegate_(ct_delegate) {}
|
||||
|
@ -51,23 +167,43 @@ int AtomCertVerifier::Verify(
|
|||
|
||||
if (verify_proc_.is_null()) {
|
||||
ct_delegate_->ClearCTExcludedHostsList();
|
||||
return default_cert_verifier_->Verify(
|
||||
params, crl_set, verify_result, callback, out_req, net_log);
|
||||
return default_cert_verifier_->Verify(params, crl_set, verify_result,
|
||||
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() {
|
||||
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
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_
|
||||
#define ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
@ -13,19 +14,30 @@
|
|||
namespace atom {
|
||||
|
||||
class AtomCTDelegate;
|
||||
class CertVerifierRequest;
|
||||
|
||||
struct VerifyRequestParams {
|
||||
std::string hostname;
|
||||
std::string default_result;
|
||||
scoped_refptr<net::X509Certificate> certificate;
|
||||
};
|
||||
|
||||
class AtomCertVerifier : public net::CertVerifier {
|
||||
public:
|
||||
explicit AtomCertVerifier(AtomCTDelegate* ct_delegate);
|
||||
virtual ~AtomCertVerifier();
|
||||
|
||||
using VerifyProc =
|
||||
base::Callback<void(const std::string& hostname,
|
||||
scoped_refptr<net::X509Certificate>,
|
||||
const base::Callback<void(bool)>&)>;
|
||||
using VerifyProc = base::Callback<void(const VerifyRequestParams& request,
|
||||
const net::CompletionCallback&)>;
|
||||
|
||||
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:
|
||||
// net::CertVerifier:
|
||||
int Verify(const RequestParams& params,
|
||||
|
@ -37,6 +49,12 @@ class AtomCertVerifier : public net::CertVerifier {
|
|||
bool SupportsOCSPStapling() override;
|
||||
|
||||
private:
|
||||
friend class CertVerifierRequest;
|
||||
|
||||
void RemoveRequest(const RequestParams& params);
|
||||
CertVerifierRequest* FindRequest(const RequestParams& params);
|
||||
|
||||
std::map<RequestParams, CertVerifierRequest*> inflight_requests_;
|
||||
VerifyProc verify_proc_;
|
||||
std::unique_ptr<net::CertVerifier> default_cert_verifier_;
|
||||
AtomCTDelegate* ct_delegate_;
|
||||
|
|
|
@ -402,7 +402,7 @@ void AtomNetworkDelegate::OnListenerResultInIO(
|
|||
if (!base::ContainsKey(callbacks_, id))
|
||||
return;
|
||||
|
||||
ReadFromResponseObject(*response.get(), out);
|
||||
ReadFromResponseObject(*response, out);
|
||||
|
||||
bool cancel = false;
|
||||
response->GetBoolean("cancel", &cancel);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/upload_bytes_element_reader.h"
|
||||
#include "net/url_request/redirect_info.h"
|
||||
|
||||
namespace {
|
||||
const int kBufferSize = 4096;
|
||||
|
@ -58,6 +59,7 @@ scoped_refptr<AtomURLRequest> AtomURLRequest::Create(
|
|||
AtomBrowserContext* browser_context,
|
||||
const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy,
|
||||
api::URLRequest* delegate) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
|
@ -76,7 +78,7 @@ scoped_refptr<AtomURLRequest> AtomURLRequest::Create(
|
|||
if (content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AtomURLRequest::DoInitialize, atom_url_request,
|
||||
request_context_getter, method, url))) {
|
||||
request_context_getter, method, url, redirect_policy))) {
|
||||
return atom_url_request;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -93,10 +95,12 @@ void AtomURLRequest::Terminate() {
|
|||
void AtomURLRequest::DoInitialize(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const std::string& method,
|
||||
const std::string& url) {
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
DCHECK(request_context_getter);
|
||||
|
||||
redirect_policy_ = redirect_policy;
|
||||
request_context_getter_ = request_context_getter;
|
||||
request_context_getter_->AddObserver(this);
|
||||
auto context = request_context_getter_->GetURLRequestContext();
|
||||
|
@ -150,6 +154,13 @@ void AtomURLRequest::Cancel() {
|
|||
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,
|
||||
const std::string& value) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
@ -246,6 +257,13 @@ void AtomURLRequest::DoCancel() {
|
|||
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,
|
||||
const std::string& value) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
@ -297,6 +315,29 @@ void AtomURLRequest::DoSetLoadFlags(int flags) const {
|
|||
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,
|
||||
net::AuthChallengeInfo* auth_info) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
@ -348,6 +389,14 @@ void AtomURLRequest::OnReadCompleted(net::URLRequest* request, int bytes_read) {
|
|||
DCHECK_EQ(request, request_.get());
|
||||
|
||||
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 data_ended = false;
|
||||
|
@ -399,6 +448,16 @@ bool AtomURLRequest::CopyAndPostBuffer(int bytes_read) {
|
|||
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(
|
||||
scoped_refptr<net::AuthChallengeInfo> auth_info) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
|
|
@ -30,12 +30,14 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
|||
AtomBrowserContext* browser_context,
|
||||
const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy,
|
||||
api::URLRequest* delegate);
|
||||
void Terminate();
|
||||
|
||||
bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last);
|
||||
void SetChunkedUpload(bool is_chunked_upload);
|
||||
void Cancel();
|
||||
void FollowRedirect();
|
||||
void SetExtraHeader(const std::string& name, const std::string& value) const;
|
||||
void RemoveExtraHeader(const std::string& name) const;
|
||||
void PassLoginInformation(const base::string16& username,
|
||||
|
@ -44,6 +46,9 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
|||
|
||||
protected:
|
||||
// Overrides of net::URLRequest::Delegate
|
||||
void OnReceivedRedirect(net::URLRequest* request,
|
||||
const net::RedirectInfo& info,
|
||||
bool* defer_redirect) override;
|
||||
void OnAuthRequired(net::URLRequest* request,
|
||||
net::AuthChallengeInfo* auth_info) override;
|
||||
void OnResponseStarted(net::URLRequest* request) override;
|
||||
|
@ -60,11 +65,13 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
|||
|
||||
void DoInitialize(scoped_refptr<net::URLRequestContextGetter>,
|
||||
const std::string& method,
|
||||
const std::string& url);
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy);
|
||||
void DoTerminate();
|
||||
void DoWriteBuffer(scoped_refptr<const net::IOBufferWithSize> buffer,
|
||||
bool is_last);
|
||||
void DoCancel();
|
||||
void DoFollowRedirect();
|
||||
void DoSetExtraHeader(const std::string& name,
|
||||
const std::string& value) const;
|
||||
void DoRemoveExtraHeader(const std::string& name) const;
|
||||
|
@ -77,6 +84,11 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
|||
void ReadResponse();
|
||||
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(
|
||||
scoped_refptr<net::AuthChallengeInfo> auth_info) const;
|
||||
void InformDelegateResponseStarted(
|
||||
|
@ -92,6 +104,7 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
|||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
|
||||
bool is_chunked_upload_;
|
||||
std::string redirect_policy_;
|
||||
std::unique_ptr<net::ChunkedUploadDataStream> chunked_stream_;
|
||||
std::unique_ptr<net::ChunkedUploadDataStream::Writer> chunked_stream_writer_;
|
||||
std::vector<std::unique_ptr<net::UploadElementReader>>
|
||||
|
|
|
@ -164,7 +164,7 @@ void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket,
|
|||
buffer_.append(data, len);
|
||||
|
||||
do {
|
||||
if (buffer_.size() == 0)
|
||||
if (buffer_.empty())
|
||||
return;
|
||||
|
||||
// Read the "Content-Length" header.
|
||||
|
|
|
@ -851,12 +851,12 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) {
|
|||
GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval(
|
||||
base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_));
|
||||
|
||||
if (copy_frame_generator_.get()) {
|
||||
if (copy_frame_generator_) {
|
||||
copy_frame_generator_->set_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_);
|
||||
} else {
|
||||
begin_frame_timer_.reset(new AtomBeginFrameTimer(
|
||||
|
@ -871,7 +871,7 @@ void OffScreenRenderWidgetHostView::Invalidate() {
|
|||
|
||||
if (software_output_device_) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,4 +145,4 @@ OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const {
|
|||
return browser_compositor_->GetDelegatedFrameHost();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace atom
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string>electron.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.5.1</string>
|
||||
<string>1.6.8</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.5.1</string>
|
||||
<string>1.6.8</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<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>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
|
|
|
@ -56,8 +56,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,5,1,0
|
||||
PRODUCTVERSION 1,5,1,0
|
||||
FILEVERSION 1,6,8,0
|
||||
PRODUCTVERSION 1,6,8,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -74,12 +74,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "1.5.1"
|
||||
VALUE "FileVersion", "1.6.8"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "1.5.1"
|
||||
VALUE "ProductVersion", "1.6.8"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
|
29
atom/browser/ui/certificate_trust.h
Normal file
29
atom/browser/ui/certificate_trust.h
Normal 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_
|
112
atom/browser/ui/certificate_trust_mac.mm
Normal file
112
atom/browser/ui/certificate_trust_mac.mm
Normal 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
|
98
atom/browser/ui/certificate_trust_win.cc
Normal file
98
atom/browser/ui/certificate_trust_win.cc
Normal 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,
|
||||
¶ms,
|
||||
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
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
|
@ -27,6 +28,7 @@ class AtomMenuModel;
|
|||
base::scoped_nsobject<NSMenu> menu_;
|
||||
BOOL isMenuOpen_;
|
||||
BOOL useDefaultAccelerator_;
|
||||
base::Callback<void()> closeCallback;
|
||||
}
|
||||
|
||||
@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.
|
||||
- (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use;
|
||||
|
||||
- (void)setCloseCallback:(const base::Callback<void()>&)callback;
|
||||
|
||||
// Populate current NSMenu with |model|.
|
||||
- (void)populateWithModel:(atom::AtomMenuModel*)model;
|
||||
|
||||
|
|
|
@ -12,9 +12,12 @@
|
|||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/base/accelerators/platform_accelerator_cocoa.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/gfx/image/image.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace {
|
||||
|
||||
struct Role {
|
||||
|
@ -67,10 +70,14 @@ Role kRolesMap[] = {
|
|||
// while its context menu is still open.
|
||||
[self cancel];
|
||||
|
||||
model_ = NULL;
|
||||
model_ = nullptr;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setCloseCallback:(const base::Callback<void()>&)callback {
|
||||
closeCallback = callback;
|
||||
}
|
||||
|
||||
- (void)populateWithModel:(atom::AtomMenuModel*)model {
|
||||
if (!menu_)
|
||||
return;
|
||||
|
@ -265,8 +272,13 @@ Role kRolesMap[] = {
|
|||
|
||||
- (void)menuDidClose:(NSMenu*)menu {
|
||||
if (isMenuOpen_) {
|
||||
model_->MenuWillClose();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
66
atom/browser/ui/cocoa/atom_touch_bar.h
Normal file
66
atom/browser/ui/cocoa/atom_touch_bar.h
Normal 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_
|
669
atom/browser/ui/cocoa/atom_touch_bar.mm
Normal file
669
atom/browser/ui/cocoa/atom_touch_bar.mm
Normal 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
|
251
atom/browser/ui/cocoa/touch_bar_forward_declarations.h
Normal file
251
atom/browser/ui/cocoa/touch_bar_forward_declarations.h
Normal 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_
|
|
@ -23,12 +23,13 @@ typedef std::pair<std::string, std::vector<std::string> > Filter;
|
|||
typedef std::vector<Filter> Filters;
|
||||
|
||||
enum FileDialogProperty {
|
||||
FILE_DIALOG_OPEN_FILE = 1 << 0,
|
||||
FILE_DIALOG_OPEN_DIRECTORY = 1 << 1,
|
||||
FILE_DIALOG_MULTI_SELECTIONS = 1 << 2,
|
||||
FILE_DIALOG_CREATE_DIRECTORY = 1 << 3,
|
||||
FILE_DIALOG_SHOW_HIDDEN_FILES = 1 << 4,
|
||||
FILE_DIALOG_PROMPT_TO_CREATE = 1 << 5,
|
||||
FILE_DIALOG_OPEN_FILE = 1 << 0,
|
||||
FILE_DIALOG_OPEN_DIRECTORY = 1 << 1,
|
||||
FILE_DIALOG_MULTI_SELECTIONS = 1 << 2,
|
||||
FILE_DIALOG_CREATE_DIRECTORY = 1 << 3,
|
||||
FILE_DIALOG_SHOW_HIDDEN_FILES = 1 << 4,
|
||||
FILE_DIALOG_PROMPT_TO_CREATE = 1 << 5,
|
||||
FILE_DIALOG_NO_RESOLVE_ALIASES = 1 << 6,
|
||||
};
|
||||
|
||||
typedef base::Callback<void(
|
||||
|
@ -37,34 +38,28 @@ typedef base::Callback<void(
|
|||
typedef base::Callback<void(
|
||||
bool result, const base::FilePath& path)> SaveDialogCallback;
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
struct DialogSettings {
|
||||
atom::NativeWindow* parent_window = nullptr;
|
||||
std::string title;
|
||||
std::string message;
|
||||
std::string button_label;
|
||||
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);
|
||||
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
void ShowOpenDialog(const DialogSettings& settings,
|
||||
const OpenDialogCallback& callback);
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
bool ShowSaveDialog(const DialogSettings& settings,
|
||||
base::FilePath* path);
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
void ShowSaveDialog(const DialogSettings& settings,
|
||||
const SaveDialogCallback& callback);
|
||||
|
||||
} // namespace file_dialog
|
||||
|
|
|
@ -36,24 +36,20 @@ void OnFileFilterDataDestroyed(std::string* file_extension) {
|
|||
class FileChooserDialog {
|
||||
public:
|
||||
FileChooserDialog(GtkFileChooserAction action,
|
||||
atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters)
|
||||
: parent_(static_cast<atom::NativeWindowViews*>(parent_window)),
|
||||
filters_(filters) {
|
||||
const DialogSettings& settings)
|
||||
: parent_(static_cast<atom::NativeWindowViews*>(settings.parent_window)),
|
||||
filters_(settings.filters) {
|
||||
const char* confirm_text = GTK_STOCK_OK;
|
||||
|
||||
if (!button_label.empty())
|
||||
confirm_text = button_label.c_str();
|
||||
if (!settings.button_label.empty())
|
||||
confirm_text = settings.button_label.c_str();
|
||||
else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
confirm_text = GTK_STOCK_SAVE;
|
||||
else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||
confirm_text = GTK_STOCK_OPEN;
|
||||
|
||||
dialog_ = gtk_file_chooser_dialog_new(
|
||||
title.c_str(),
|
||||
settings.title.c_str(),
|
||||
NULL,
|
||||
action,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
|
@ -71,20 +67,20 @@ class FileChooserDialog {
|
|||
if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE);
|
||||
|
||||
if (!default_path.empty()) {
|
||||
if (base::DirectoryExists(default_path)) {
|
||||
if (!settings.default_path.empty()) {
|
||||
if (base::DirectoryExists(settings.default_path)) {
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_),
|
||||
default_path.value().c_str());
|
||||
settings.default_path.value().c_str());
|
||||
} else {
|
||||
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_),
|
||||
default_path.BaseName().value().c_str());
|
||||
settings.default_path.BaseName().value().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!filters.empty())
|
||||
AddFilters(filters);
|
||||
if (!settings.filters.empty())
|
||||
AddFilters(settings.filters);
|
||||
}
|
||||
|
||||
~FileChooserDialog() {
|
||||
|
@ -230,19 +226,13 @@ base::FilePath FileChooserDialog::AddExtensionForFilename(
|
|||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
bool ShowOpenDialog(const DialogSettings& settings,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
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;
|
||||
FileChooserDialog open_dialog(action, parent_window, title, button_label,
|
||||
default_path, filters);
|
||||
open_dialog.SetupProperties(properties);
|
||||
FileChooserDialog open_dialog(action, settings);
|
||||
open_dialog.SetupProperties(settings.properties);
|
||||
|
||||
gtk_widget_show_all(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,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
void ShowOpenDialog(const DialogSettings& settings,
|
||||
const OpenDialogCallback& callback) {
|
||||
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;
|
||||
FileChooserDialog* open_dialog = new FileChooserDialog(
|
||||
action, parent_window, title, button_label, default_path, filters);
|
||||
open_dialog->SetupProperties(properties);
|
||||
FileChooserDialog* open_dialog = new FileChooserDialog(action, settings);
|
||||
open_dialog->SetupProperties(settings.properties);
|
||||
open_dialog->RunOpenAsynchronous(callback);
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
bool ShowSaveDialog(const DialogSettings& settings,
|
||||
base::FilePath* path) {
|
||||
FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, parent_window,
|
||||
title, button_label, default_path, filters);
|
||||
FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
|
||||
gtk_widget_show_all(save_dialog.dialog());
|
||||
int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog()));
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
|
@ -288,15 +267,10 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
|||
}
|
||||
}
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
void ShowSaveDialog(const DialogSettings& settings,
|
||||
const SaveDialogCallback& callback) {
|
||||
FileChooserDialog* save_dialog = new FileChooserDialog(
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, button_label,
|
||||
default_path, filters);
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE, settings);
|
||||
save_dialog->RunSaveAsynchronous(callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,25 +44,31 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
|
|||
}
|
||||
|
||||
void SetupDialog(NSSavePanel* dialog,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters) {
|
||||
if (!title.empty())
|
||||
[dialog setTitle:base::SysUTF8ToNSString(title)];
|
||||
const DialogSettings& settings) {
|
||||
if (!settings.title.empty())
|
||||
[dialog setTitle:base::SysUTF8ToNSString(settings.title)];
|
||||
|
||||
if (!button_label.empty())
|
||||
[dialog setPrompt:base::SysUTF8ToNSString(button_label)];
|
||||
if (!settings.button_label.empty())
|
||||
[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_filename = nil;
|
||||
if (!default_path.empty()) {
|
||||
if (base::DirectoryExists(default_path)) {
|
||||
default_dir = base::SysUTF8ToNSString(default_path.value());
|
||||
if (!settings.default_path.empty()) {
|
||||
if (base::DirectoryExists(settings.default_path)) {
|
||||
default_dir = base::SysUTF8ToNSString(settings.default_path.value());
|
||||
} else {
|
||||
default_dir = base::SysUTF8ToNSString(default_path.DirName().value());
|
||||
default_dir =
|
||||
base::SysUTF8ToNSString(settings.default_path.DirName().value());
|
||||
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)
|
||||
[dialog setNameFieldStringValue:default_filename];
|
||||
|
||||
if (filters.empty())
|
||||
if (settings.filters.empty())
|
||||
[dialog setAllowsOtherFileTypes:YES];
|
||||
else
|
||||
SetAllowedFileTypes(dialog, filters);
|
||||
SetAllowedFileTypes(dialog, settings.filters);
|
||||
}
|
||||
|
||||
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
||||
|
@ -87,6 +93,8 @@ void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
|||
[dialog setAllowsMultipleSelection:YES];
|
||||
if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES)
|
||||
[dialog setShowsHiddenFiles:YES];
|
||||
if (properties & FILE_DIALOG_NO_RESOLVE_ALIASES)
|
||||
[dialog setResolvesAliases:NO];
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
bool ShowOpenDialog(const DialogSettings& settings,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
DCHECK(paths);
|
||||
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||
|
||||
SetupDialog(dialog, title, button_label, default_path, filters);
|
||||
SetupDialogForProperties(dialog, properties);
|
||||
SetupDialog(dialog, settings);
|
||||
SetupDialogForProperties(dialog, settings.properties);
|
||||
|
||||
int chosen = RunModalDialog(dialog, parent_window);
|
||||
int chosen = RunModalDialog(dialog, settings.parent_window);
|
||||
if (chosen == NSFileHandlingPanelCancelButton)
|
||||
return false;
|
||||
|
||||
|
@ -138,23 +141,20 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
|||
return true;
|
||||
}
|
||||
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
void ShowOpenDialog(const DialogSettings& settings,
|
||||
const OpenDialogCallback& c) {
|
||||
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||
|
||||
SetupDialog(dialog, title, button_label, default_path, filters);
|
||||
SetupDialogForProperties(dialog, properties);
|
||||
SetupDialog(dialog, settings);
|
||||
SetupDialogForProperties(dialog, settings.properties);
|
||||
|
||||
// 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.
|
||||
__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
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
|
@ -167,18 +167,14 @@ void ShowOpenDialog(atom::NativeWindow* parent_window,
|
|||
}];
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
bool ShowSaveDialog(const DialogSettings& settings,
|
||||
base::FilePath* path) {
|
||||
DCHECK(path);
|
||||
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])
|
||||
return false;
|
||||
|
||||
|
@ -186,20 +182,18 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
|||
return true;
|
||||
}
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
void ShowSaveDialog(const DialogSettings& settings,
|
||||
const SaveDialogCallback& c) {
|
||||
NSSavePanel* dialog = [NSSavePanel savePanel];
|
||||
|
||||
SetupDialog(dialog, title, button_label, default_path, filters);
|
||||
SetupDialog(dialog, settings);
|
||||
[dialog setCanSelectHiddenExtension:YES];
|
||||
|
||||
__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
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
|
|
|
@ -66,26 +66,24 @@ void ConvertFilters(const Filters& filters,
|
|||
template <typename T>
|
||||
class FileDialog {
|
||||
public:
|
||||
FileDialog(const base::FilePath& default_path,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const Filters& filters, int options) {
|
||||
FileDialog(const DialogSettings& settings, int options) {
|
||||
std::wstring file_part;
|
||||
if (!IsDirectory(default_path))
|
||||
file_part = default_path.BaseName().value();
|
||||
if (!IsDirectory(settings.default_path))
|
||||
file_part = settings.default_path.BaseName().value();
|
||||
|
||||
std::vector<std::wstring> buffer;
|
||||
std::vector<COMDLG_FILTERSPEC> filterspec;
|
||||
ConvertFilters(filters, &buffer, &filterspec);
|
||||
ConvertFilters(settings.filters, &buffer, &filterspec);
|
||||
|
||||
dialog_.reset(new T(file_part.c_str(), options, NULL,
|
||||
filterspec.data(), filterspec.size()));
|
||||
|
||||
if (!title.empty())
|
||||
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
|
||||
if (!settings.title.empty())
|
||||
GetPtr()->SetTitle(base::UTF8ToUTF16(settings.title).c_str());
|
||||
|
||||
if (!button_label.empty())
|
||||
GetPtr()->SetOkButtonLabel(base::UTF8ToUTF16(button_label).c_str());
|
||||
if (!settings.button_label.empty())
|
||||
GetPtr()->SetOkButtonLabel(
|
||||
base::UTF8ToUTF16(settings.button_label).c_str());
|
||||
|
||||
// By default, *.* will be added to the file name if file type is "*.*". In
|
||||
// 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) {
|
||||
|
@ -160,31 +158,20 @@ bool CreateDialogThread(RunState* run_state) {
|
|||
}
|
||||
|
||||
void RunOpenDialogInNewThread(const RunState& run_state,
|
||||
atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
const DialogSettings& settings,
|
||||
const OpenDialogCallback& callback) {
|
||||
std::vector<base::FilePath> paths;
|
||||
bool result = ShowOpenDialog(parent, title, button_label, default_path,
|
||||
filters, properties, &paths);
|
||||
bool result = ShowOpenDialog(settings, &paths);
|
||||
run_state.ui_task_runner->PostTask(FROM_HERE,
|
||||
base::Bind(callback, result, paths));
|
||||
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
|
||||
}
|
||||
|
||||
void RunSaveDialogInNewThread(const RunState& run_state,
|
||||
atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
const DialogSettings& settings,
|
||||
const SaveDialogCallback& callback) {
|
||||
base::FilePath path;
|
||||
bool result = ShowSaveDialog(parent, title, button_label, default_path,
|
||||
filters, &path);
|
||||
bool result = ShowSaveDialog(settings, &path);
|
||||
run_state.ui_task_runner->PostTask(FROM_HERE,
|
||||
base::Bind(callback, result, path));
|
||||
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
|
||||
|
@ -192,26 +179,20 @@ void RunSaveDialogInNewThread(const RunState& run_state,
|
|||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
bool ShowOpenDialog(const DialogSettings& settings,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
if (settings.properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
options |= FOS_PICKFOLDERS;
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
if (settings.properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
options |= FOS_ALLOWMULTISELECT;
|
||||
if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES)
|
||||
if (settings.properties & FILE_DIALOG_SHOW_HIDDEN_FILES)
|
||||
options |= FOS_FORCESHOWHIDDEN;
|
||||
if (properties & FILE_DIALOG_PROMPT_TO_CREATE)
|
||||
if (settings.properties & FILE_DIALOG_PROMPT_TO_CREATE)
|
||||
options |= FOS_CREATEPROMPT;
|
||||
|
||||
FileDialog<CShellFileOpenDialog> open_dialog(
|
||||
default_path, title, button_label, filters, options);
|
||||
if (!open_dialog.Show(parent_window))
|
||||
FileDialog<CShellFileOpenDialog> open_dialog(settings, options);
|
||||
if (!open_dialog.Show(settings.parent_window))
|
||||
return false;
|
||||
|
||||
ATL::CComPtr<IShellItemArray> items;
|
||||
|
@ -244,12 +225,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
|||
return true;
|
||||
}
|
||||
|
||||
void ShowOpenDialog(atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
void ShowOpenDialog(const DialogSettings& settings,
|
||||
const OpenDialogCallback& callback) {
|
||||
RunState run_state;
|
||||
if (!CreateDialogThread(&run_state)) {
|
||||
|
@ -259,20 +235,14 @@ void ShowOpenDialog(atom::NativeWindow* parent,
|
|||
|
||||
run_state.dialog_thread->task_runner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&RunOpenDialogInNewThread, run_state, parent, title,
|
||||
button_label, default_path, filters, properties, callback));
|
||||
base::Bind(&RunOpenDialogInNewThread, run_state, settings, callback));
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
bool ShowSaveDialog(const DialogSettings& settings,
|
||||
base::FilePath* path) {
|
||||
FileDialog<CShellFileSaveDialog> save_dialog(
|
||||
default_path, title, button_label, filters,
|
||||
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT);
|
||||
if (!save_dialog.Show(parent_window))
|
||||
settings, FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT);
|
||||
if (!save_dialog.Show(settings.parent_window))
|
||||
return false;
|
||||
|
||||
wchar_t buffer[MAX_PATH];
|
||||
|
@ -284,11 +254,7 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
|||
return true;
|
||||
}
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const std::string& button_label,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
void ShowSaveDialog(const DialogSettings& settings,
|
||||
const SaveDialogCallback& callback) {
|
||||
RunState run_state;
|
||||
if (!CreateDialogThread(&run_state)) {
|
||||
|
@ -298,8 +264,7 @@ void ShowSaveDialog(atom::NativeWindow* parent,
|
|||
|
||||
run_state.dialog_thread->task_runner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&RunSaveDialogInNewThread, run_state, parent, title,
|
||||
button_label, default_path, filters, callback));
|
||||
base::Bind(&RunSaveDialogInNewThread, run_state, settings, callback));
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
|
|
|
@ -32,7 +32,8 @@ enum MessageBoxOptions {
|
|||
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,
|
||||
MessageBoxType type,
|
||||
|
@ -54,6 +55,8 @@ void ShowMessageBox(NativeWindow* parent_window,
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback);
|
||||
|
||||
|
|
|
@ -36,8 +36,11 @@ class GtkMessageBox : public NativeWindowObserver {
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon)
|
||||
: cancel_id_(cancel_id),
|
||||
checkbox_checked_(false),
|
||||
parent_(static_cast<NativeWindowViews*>(parent_window)) {
|
||||
// Create dialog.
|
||||
dialog_ = gtk_message_dialog_new(
|
||||
|
@ -68,6 +71,18 @@ class GtkMessageBox : public NativeWindowObserver {
|
|||
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.
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
GtkWidget* button = gtk_dialog_add_button(
|
||||
|
@ -154,6 +169,7 @@ class GtkMessageBox : public NativeWindowObserver {
|
|||
}
|
||||
|
||||
CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int);
|
||||
CHROMEGTK_CALLBACK_0(GtkMessageBox, void, OnCheckboxToggled);
|
||||
|
||||
private:
|
||||
atom::UnresponsiveSuppressor unresponsive_suppressor_;
|
||||
|
@ -161,6 +177,8 @@ class GtkMessageBox : public NativeWindowObserver {
|
|||
// The id to return when the dialog is closed without pressing buttons.
|
||||
int cancel_id_;
|
||||
|
||||
bool checkbox_checked_;
|
||||
|
||||
NativeWindowViews* parent_;
|
||||
GtkWidget* dialog_;
|
||||
MessageBoxCallback callback_;
|
||||
|
@ -172,12 +190,16 @@ void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) {
|
|||
gtk_widget_hide(dialog_);
|
||||
|
||||
if (response < 0)
|
||||
callback_.Run(cancel_id_);
|
||||
callback_.Run(cancel_id_, checkbox_checked_);
|
||||
else
|
||||
callback_.Run(response);
|
||||
callback_.Run(response, checkbox_checked_);
|
||||
delete this;
|
||||
}
|
||||
|
||||
void GtkMessageBox::OnCheckboxToggled(GtkWidget* widget) {
|
||||
checkbox_checked_ = GTK_TOGGLE_BUTTON(widget)->active;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent,
|
||||
|
@ -190,8 +212,9 @@ int ShowMessageBox(NativeWindow* parent,
|
|||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
return GtkMessageBox(parent, type, buttons, default_id, cancel_id,
|
||||
title, message, detail, icon).RunSynchronous();
|
||||
return GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
|
||||
message, detail, "", false, icon)
|
||||
.RunSynchronous();
|
||||
}
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent,
|
||||
|
@ -203,18 +226,22 @@ void ShowMessageBox(NativeWindow* parent,
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
(new GtkMessageBox(parent, type, buttons, default_id, cancel_id,
|
||||
title, message, detail, icon))->RunAsynchronous(callback);
|
||||
(new GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
|
||||
message, detail, checkbox_label, checkbox_checked, icon))
|
||||
->RunAsynchronous(callback);
|
||||
}
|
||||
|
||||
void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
||||
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(content).c_str(),
|
||||
gfx::ImageSkia()).RunSynchronous();
|
||||
base::UTF16ToUTF8(content).c_str(), "", false,
|
||||
gfx::ImageSkia())
|
||||
.RunSynchronous();
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
- (void)alertDidEnd:(NSAlert*)alert
|
||||
returnCode:(NSInteger)returnCode
|
||||
contextInfo:(void*)contextInfo {
|
||||
callback_.Run(returnCode);
|
||||
callback_.Run(returnCode, alert.suppressionButton.state == NSOnState);
|
||||
[alert_ release];
|
||||
[self release];
|
||||
|
||||
|
@ -57,9 +57,12 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
|||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int default_id,
|
||||
int cancel_id,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon) {
|
||||
// Ignore the title; it's the window title on other platforms and ignorable.
|
||||
NSAlert* alert = [[NSAlert alloc] init];
|
||||
|
@ -68,10 +71,14 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
|||
|
||||
switch (type) {
|
||||
case MESSAGE_BOX_TYPE_INFORMATION:
|
||||
[alert setAlertStyle:NSInformationalAlertStyle];
|
||||
alert.alertStyle = NSInformationalAlertStyle;
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
|
@ -87,7 +94,14 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
|||
}
|
||||
|
||||
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.
|
||||
// The first button added gets set as the default selected.
|
||||
// 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"];
|
||||
}
|
||||
|
||||
if (!checkbox_label.empty()) {
|
||||
alert.showsSuppressionButton = YES;
|
||||
alert.suppressionButton.title = base::SysUTF8ToNSString(checkbox_label);
|
||||
alert.suppressionButton.state = checkbox_checked ? NSOnState : NSOffState;
|
||||
}
|
||||
|
||||
if (!icon.isNull()) {
|
||||
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
|
||||
*icon.bitmap(), base::mac::GetGenericRGBColorSpace());
|
||||
|
@ -104,7 +124,7 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
|||
return alert;
|
||||
}
|
||||
|
||||
void SetReturnCode(int* ret_code, int result) {
|
||||
void SetReturnCode(int* ret_code, int result, bool checkbox_checked) {
|
||||
*ret_code = result;
|
||||
}
|
||||
|
||||
|
@ -120,9 +140,9 @@ int ShowMessageBox(NativeWindow* parent_window,
|
|||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
NSAlert* alert = CreateNSAlert(
|
||||
parent_window, type, buttons, default_id, title, message,
|
||||
detail, icon);
|
||||
NSAlert* alert = CreateNSAlert(parent_window, type, buttons, default_id,
|
||||
cancel_id, title, message, detail, "", false,
|
||||
icon);
|
||||
|
||||
// Use runModal for synchronous alert without parent, since we don't have a
|
||||
// window to wait for.
|
||||
|
@ -154,11 +174,13 @@ void ShowMessageBox(NativeWindow* parent_window,
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
NSAlert* alert = CreateNSAlert(
|
||||
parent_window, type, buttons, default_id, title, message,
|
||||
detail, icon);
|
||||
NSAlert* alert =
|
||||
CreateNSAlert(parent_window, type, buttons, default_id, cancel_id, title,
|
||||
message, detail, checkbox_label, checkbox_checked, icon);
|
||||
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
|
||||
andAlert:alert
|
||||
callEndModal:false];
|
||||
|
@ -174,7 +196,7 @@ void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
|||
NSAlert* alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:base::SysUTF16ToNSString(title)];
|
||||
[alert setInformativeText:base::SysUTF16ToNSString(content)];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert setAlertStyle:NSCriticalAlertStyle];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ void MapToCommonID(const std::vector<base::string16>& buttons,
|
|||
}
|
||||
}
|
||||
|
||||
int ShowMessageBoxUTF16(HWND parent,
|
||||
int ShowTaskDialogUTF16(NativeWindow* parent,
|
||||
MessageBoxType type,
|
||||
const std::vector<base::string16>& buttons,
|
||||
int default_id,
|
||||
|
@ -81,6 +81,8 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
const base::string16& title,
|
||||
const base::string16& message,
|
||||
const base::string16& detail,
|
||||
const base::string16& checkbox_label,
|
||||
bool* checkbox_checked,
|
||||
const gfx::ImageSkia& icon) {
|
||||
TASKDIALOG_FLAGS flags =
|
||||
TDF_SIZE_TO_CONTENT | // Show all content.
|
||||
|
@ -88,10 +90,14 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
|
||||
TASKDIALOGCONFIG config = { 0 };
|
||||
config.cbSize = sizeof(config);
|
||||
config.hwndParent = parent;
|
||||
config.hInstance = GetModuleHandle(NULL);
|
||||
config.dwFlags = flags;
|
||||
|
||||
if (parent) {
|
||||
config.hwndParent =
|
||||
static_cast<atom::NativeWindowViews*>(parent)->GetAcceleratedWidget();
|
||||
}
|
||||
|
||||
if (default_id > 0)
|
||||
config.nDefaultButton = kIDStart + default_id;
|
||||
|
||||
|
@ -132,6 +138,14 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
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
|
||||
// and custom buttons in pButtons.
|
||||
std::map<int, int> id_map;
|
||||
|
@ -151,7 +165,12 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
}
|
||||
|
||||
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.
|
||||
return id_map[id];
|
||||
else if (id >= kIDStart) // custom button.
|
||||
|
@ -160,6 +179,29 @@ int ShowMessageBoxUTF16(HWND parent,
|
|||
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,
|
||||
NativeWindow* parent,
|
||||
MessageBoxType type,
|
||||
|
@ -170,12 +212,16 @@ void RunMessageBoxInNewThread(base::Thread* thread,
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
int result = ShowMessageBox(parent, type, buttons, default_id,
|
||||
cancel_id, options, title, message, detail, icon);
|
||||
int result = ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
|
||||
options, title, message, detail,
|
||||
checkbox_label, &checkbox_checked, icon);
|
||||
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::UI, FROM_HERE, thread);
|
||||
}
|
||||
|
@ -192,25 +238,9 @@ int ShowMessageBox(NativeWindow* parent,
|
|||
const std::string& message,
|
||||
const std::string& detail,
|
||||
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;
|
||||
return ShowMessageBoxUTF16(hwnd_parent,
|
||||
type,
|
||||
utf16_buttons,
|
||||
default_id,
|
||||
cancel_id,
|
||||
options,
|
||||
base::UTF8ToUTF16(title),
|
||||
base::UTF8ToUTF16(message),
|
||||
base::UTF8ToUTF16(detail),
|
||||
icon);
|
||||
return ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
|
||||
options, title, message, detail, "", nullptr, icon);
|
||||
}
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent,
|
||||
|
@ -222,13 +252,15 @@ void ShowMessageBox(NativeWindow* parent,
|
|||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::string& checkbox_label,
|
||||
bool checkbox_checked,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
std::unique_ptr<base::Thread> thread(
|
||||
new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread"));
|
||||
thread->init_com_with_mta(false);
|
||||
if (!thread->Start()) {
|
||||
callback.Run(cancel_id);
|
||||
callback.Run(cancel_id, checkbox_checked);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -237,13 +269,14 @@ void ShowMessageBox(NativeWindow* parent,
|
|||
FROM_HERE,
|
||||
base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained),
|
||||
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) {
|
||||
atom::UnresponsiveSuppressor suppressor;
|
||||
ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error",
|
||||
title, content, gfx::ImageSkia());
|
||||
ShowTaskDialogUTF16(nullptr, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error",
|
||||
title, content, L"", nullptr, gfx::ImageSkia());
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -16,26 +16,15 @@
|
|||
|
||||
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,
|
||||
views::MenuButtonListener* menu_button_listener,
|
||||
const SkColor& background_color)
|
||||
: views::MenuButton(FilterAccelerator(title),
|
||||
: views::MenuButton(gfx::RemoveAcceleratorChar(title, '&', NULL, NULL),
|
||||
menu_button_listener, false),
|
||||
accelerator_(0),
|
||||
show_underline_(false),
|
||||
underline_start_(-1),
|
||||
underline_end_(-1),
|
||||
underline_start_(0),
|
||||
underline_end_(0),
|
||||
text_width_(0),
|
||||
text_height_(0),
|
||||
underline_color_(SK_ColorBLACK),
|
||||
|
@ -117,7 +106,7 @@ bool SubmenuButton::GetUnderlinePosition(const base::string16& text,
|
|||
|
||||
void SubmenuButton::GetCharacterPosition(
|
||||
const base::string16& text, int index, int* pos) {
|
||||
int height;
|
||||
int height = 0;
|
||||
gfx::Canvas::SizeStringInt(text.substr(0, index), GetFontList(), pos, &height,
|
||||
0, 0);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue