diff --git a/.gitmodules b/.gitmodules index c6e53ed39a69..6164ed8b9706 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,21 +1,21 @@ [submodule "vendor/brightray"] path = vendor/brightray - url = https://github.com/atom/brightray.git + url = https://github.com/electron/brightray.git [submodule "vendor/node"] path = vendor/node - url = https://github.com/atom/node.git + url = https://github.com/electron/node.git [submodule "vendor/depot_tools"] path = vendor/depot_tools url = https://chromium.googlesource.com/chromium/tools/depot_tools.git [submodule "vendor/breakpad"] path = vendor/breakpad - url = https://github.com/atom/chromium-breakpad.git + url = https://github.com/electron/chromium-breakpad.git [submodule "vendor/native_mate"] path = vendor/native_mate url = https://github.com/zcbenz/native-mate.git [submodule "vendor/crashpad"] path = vendor/crashpad - url = https://github.com/atom/crashpad.git + url = https://github.com/electron/crashpad.git [submodule "vendor/requests"] path = vendor/requests url = https://github.com/kennethreitz/requests diff --git a/.node-version b/.node-version index 346d9cae72c6..339cbf236a73 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -v5.1.1 +v5.10.0 diff --git a/CONTRIBUTING-ko.md b/CONTRIBUTING-ko.md index 52887c8d38a7..cb687f9227a5 100644 --- a/CONTRIBUTING-ko.md +++ b/CONTRIBUTING-ko.md @@ -1,10 +1,10 @@ # Electron에 기여하기 -:+1::tada: 먼저, 이 프로젝트에 기여해주셔서 감사합니다! :tada::+1: +:+1::tada: 먼저, 기여에 관심을 가져주셔서 감사합니다! :tada::+1: -이 프로젝트는 기여자 규약 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이 +이 프로젝트는 기여자 규약인 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이 프로젝트의 개발에 참여하려면 이 규약을 지켜야 합니다. 받아들일 수 없는 행위를 발견했을 -경우 atom@github.com로 보고 하십시오. +경우 atom@github.com로 보고하세요. 다음 항목들은 Electron에 기여하는 가이드라인을 제시합니다. 참고로 이 항목들은 그저 가이드라인에 불과하며 규칙이 아닙니다. 따라서 스스로의 적절한 @@ -12,7 +12,7 @@ ## 이슈 제출 -* [여기](https://github.com/atom/electron/issues/new)에서 새로운 이슈를 만들 수 +* [여기](https://github.com/electron/electron/issues/new)에서 새로운 이슈를 만들 수 있습니다. 하지만 이슈를 작성하기 전에 아래의 항목들을 숙지하고 가능한한 이슈 보고에 대해 최대한 많은 정보와 자세한 설명을 포함해야 합니다. 가능하다면 다음 항목을 포함해야 합니다: @@ -23,14 +23,14 @@ * 추가로 다음 사항을 준수하면 이슈를 해결하는데 큰 도움이 됩니다: * 스크린샷 또는 GIF 애니메이션 이미지들 * 터미널에 출력된 에러의 내용 또는 개발자 도구, 알림창에 뜬 내용 - * [Cursory search](https://github.com/atom/electron/issues?utf8=✓&q=is%3Aissue+)를 + * [Cursory search](https://github.com/electron/electron/issues?utf8=✓&q=is%3Aissue+)를 통해 이미 비슷한 내용의 이슈가 등록되어있는지 확인 ## Pull Request 하기 * 가능한한 스크린샷과 GIF 애니메이션 이미지를 pull request에 추가 -* CoffeeScript, JavaScript, C++과 Python등 -[참조문서에 정의된 코딩스타일](/docs-translations/ko-KR/development/coding-style.md)을 +* JavaScript, C++과 Python등 +[참조 문서에 정의된 코딩스타일](/docs-translations/ko-KR/development/coding-style.md)을 준수 * [문서 스타일 가이드](/docs-translations/ko-KR/styleguide.md)에 따라 문서를 [Markdown](https://daringfireball.net/projects/markdown) 형식으로 작성. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7c221863dcd..d6bc3cb2d67d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ propose changes to this document in a pull request. ## Submitting Issues -* You can create an issue [here](https://github.com/atom/electron/issues/new), +* You can create an issue [here](https://github.com/electron/electron/issues/new), but before doing that please read the notes below and include as many details as possible with your report. If you can, please include: * The version of Electron you are using @@ -22,7 +22,7 @@ possible with your report. If you can, please include: * Other things that will help resolve your issue: * Screenshots and animated GIFs * Error output that appears in your terminal, dev tools or as an alert - * Perform a [cursory search](https://github.com/atom/electron/issues?utf8=✓&q=is%3Aissue+) + * Perform a [cursory search](https://github.com/electron/electron/issues?utf8=✓&q=is%3Aissue+) to see if a similar issue has already been submitted ## Submitting Pull Requests diff --git a/README-ko.md b/README-ko.md index 5bef003966de..706a5556df9f 100644 --- a/README-ko.md +++ b/README-ko.md @@ -1,11 +1,11 @@ [![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/) -[![Build Status](https://travis-ci.org/atom/electron.svg?branch=master)](https://travis-ci.org/atom/electron) +[![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/qtmod45u0cc1ouov/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) -[![devDependency Status](https://david-dm.org/atom/electron/dev-status.svg)](https://david-dm.org/atom/electron#info=devDependencies) +[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron#info=devDependencies) [![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) -### [Electron](https://github.com/atom/electron/) 한국어 참조문서 +### [Electron](https://github.com/electron/electron/) 한국어 참조문서 :zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap: @@ -17,15 +17,15 @@ Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주 Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요. -이 프로젝트는 기여자 규약 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이 +이 프로젝트는 기여자 규약인 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이 프로젝트의 개발에 참여하려면 이 규약을 지켜야 합니다. 받아들일 수 없는 행위를 발견했을 -경우 atom@github.com로 보고 하십시오. +경우 atom@github.com로 보고하세요. ## 다운로드 Linux, Windows, OS X 용으로 미리 빌드된 Electron 바이너리와 디버그 심볼이 준비되어 -있습니다. [releases](https://github.com/atom/electron/releases) 페이지에서 받아 볼 -수 있습니다. +있습니다. [releases](https://github.com/electron/electron/releases) 페이지에서 +받아 볼 수 있습니다. 또한 [`npm`](https://docs.npmjs.com/)을 통해 미리 빌드된 Electron 바이너리를 설치할 수도 있습니다: @@ -44,25 +44,26 @@ npm install electron-prebuilt --save-dev ## 참조 문서 -[Docs](https://github.com/atom/electron/tree/master/docs/README.md)에 개발 지침과 -API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝트에 기여하는법 또한 문서에 -포함되어 있으니 참고하시기 바랍니다. +[Docs](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/README.md)에 +개발 지침과 API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝트에 기여하는법 +또한 문서에 포함되어 있으니 참고하시기 바랍니다. ## 참조 문서 (번역) -- [브라질 포르투갈어](https://github.com/atom/electron/tree/master/docs-translations/pt-BR) -- [한국어](https://github.com/atom/electron/tree/master/docs-translations/ko-KR) -- [일본어](https://github.com/atom/electron/tree/master/docs-translations/jp) -- [스페인어](https://github.com/atom/electron/tree/master/docs-translations/es) -- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) -- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW) -- [우크라이나어](https://github.com/atom/electron/tree/master/docs-translations/uk-UA) -- [러시아어](https://github.com/atom/electron/tree/master/docs-translations/ru-RU) -- [프랑스어](https://github.com/atom/electron/tree/master/docs-translations/fr-FR) +- [브라질 포르투갈어](https://github.com/electron/electron/tree/master/docs-translations/pt-BR) +- [한국어](https://github.com/electron/electron/tree/master/docs-translations/ko-KR) +- [일본어](https://github.com/electron/electron/tree/master/docs-translations/jp) +- [스페인어](https://github.com/electron/electron/tree/master/docs-translations/es) +- [중국어 간체](https://github.com/electron/electron/tree/master/docs-translations/zh-CN) +- [중국어 번체](https://github.com/electron/electron/tree/master/docs-translations/zh-TW) +- [터키의](https://github.com/electron/electron/tree/master/docs-translations/tr-TR) +- [우크라이나어](https://github.com/electron/electron/tree/master/docs-translations/uk-UA) +- [러시아어](https://github.com/electron/electron/tree/master/docs-translations/ru-RU) +- [프랑스어](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) ## 시작하기 -[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) +[`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) 저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다. ## 커뮤니티 diff --git a/README.md b/README.md index f7b5cb79000e..f8278f18586f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/) -[![Travis Build Status](https://travis-ci.org/atom/electron.svg?branch=master)](https://travis-ci.org/atom/electron) +[![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/qtmod45u0cc1ouov/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) -[![devDependency Status](https://david-dm.org/atom/electron/dev-status.svg)](https://david-dm.org/atom/electron#info=devDependencies) +[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron#info=devDependencies) [![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) :zap: *Formerly known as Atom Shell* :zap: @@ -22,7 +22,7 @@ behavior to atom@github.com. ## Downloads Prebuilt binaries and debug symbols of Electron for Linux, Windows and OS X can -be found on the [releases](https://github.com/atom/electron/releases) page. +be found on the [releases](https://github.com/electron/electron/releases) page. You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron binaries: @@ -42,24 +42,25 @@ npm install electron-prebuilt --save-dev ## Documentation Guides and the API reference are located in the -[docs](https://github.com/atom/electron/tree/master/docs) directory. It also +[docs](https://github.com/electron/electron/tree/master/docs) directory. It also contains documents describing how to build and contribute to Electron. ## Documentation Translations -- [Brazilian Portuguese](https://github.com/atom/electron/tree/master/docs-translations/pt-BR) -- [Korean](https://github.com/atom/electron/tree/master/docs-translations/ko-KR) -- [Japanese](https://github.com/atom/electron/tree/master/docs-translations/jp) -- [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es) -- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) -- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW) -- [Ukrainian](https://github.com/atom/electron/tree/master/docs-translations/uk-UA) -- [Russian](https://github.com/atom/electron/tree/master/docs-translations/ru-RU) -- [French](https://github.com/atom/electron/tree/master/docs-translations/fr-FR) +- [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR) +- [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR) +- [Japanese](https://github.com/electron/electron/tree/master/docs-translations/jp) +- [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es) +- [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) +- [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) ## Quick Start -Clone and run the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) +Clone and run the [`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) repository to see a minimal Electron app in action. ## Community diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index 221d59c1619c..0a298308ad0b 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -98,10 +98,6 @@ void AtomMainDelegate::PreSandboxStartup() { std::string process_type = command_line->GetSwitchValueASCII( switches::kProcessType); - if (process_type == switches::kUtilityProcess) { - AtomContentUtilityClient::PreSandboxStartup(); - } - // Only append arguments for browser process. if (!IsBrowserProcess(command_line)) return; diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 52d6ec3d338c..304e53a55540 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -15,15 +15,17 @@ #include "atom/browser/browser.h" #include "atom/browser/login_handler.h" #include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/image_converter.h" +#include "atom/common/native_mate_converters/net_converter.h" +#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_includes.h" #include "atom/common/options_switches.h" #include "base/command_line.h" #include "base/environment.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/path_service.h" #include "brightray/browser/brightray_paths.h" #include "chrome/common/chrome_paths.h" @@ -39,7 +41,6 @@ #if defined(OS_WIN) #include "base/strings/utf_string_conversions.h" -#include "ui/base/win/shell.h" #endif using atom::Browser; @@ -157,12 +158,46 @@ void PassLoginInformation(scoped_refptr login_handler, login_handler->CancelAuth(); } +#if defined(USE_NSS_CERTS) +int ImportIntoCertStore( + CertificateManagerModel* model, + const base::DictionaryValue& options) { + std::string file_data, cert_path; + base::string16 password; + net::CertificateList imported_certs; + int rv = -1; + options.GetString("certificate", &cert_path); + options.GetString("password", &password); + + if (!cert_path.empty()) { + if (base::ReadFileToString(base::FilePath(cert_path), &file_data)) { + auto module = model->cert_db()->GetPublicModule(); + rv = model->ImportFromPKCS12(module, + file_data, + password, + true, + &imported_certs); + if (imported_certs.size() > 1) { + auto it = imported_certs.begin(); + ++it; // skip first which would be the client certificate. + for (; it != imported_certs.end(); ++it) + rv &= model->SetCertTrust(it->get(), + net::CA_CERT, + net::NSSCertDatabase::TRUSTED_SSL); + } + } + } + return rv; +} +#endif + } // namespace -App::App() { +App::App(v8::Isolate* isolate) { static_cast(AtomBrowserClient::Get())->set_delegate(this); Browser::Get()->AddObserver(this); content::GpuDataManager::GetInstance()->AddObserver(this); + Init(isolate); } App::~App() { @@ -296,12 +331,6 @@ void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) { Emit("gpu-process-crashed"); } -#if defined(OS_MACOSX) -void App::OnPlatformThemeChanged() { - Emit("platform-theme-changed"); -} -#endif - base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) { bool succeed = false; base::FilePath path; @@ -316,10 +345,15 @@ base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) { void App::SetPath(mate::Arguments* args, const std::string& name, const base::FilePath& path) { + if (!path.IsAbsolute()) { + args->ThrowError("path must be absolute"); + return; + } + bool succeed = false; int key = GetPathConstant(name); if (key >= 0) - succeed = PathService::Override(key, path); + succeed = PathService::OverrideAndCreateIfNeeded(key, path, true, false); if (!succeed) args->ThrowError("Failed to set path"); } @@ -341,12 +375,6 @@ std::string App::GetLocale() { return l10n_util::GetApplicationLocale(""); } -#if defined(OS_WIN) -bool App::IsAeroGlassEnabled() { - return ui::win::IsAeroGlassEnabled(); -} -#endif - bool App::MakeSingleInstance( const ProcessSingleton::NotificationCallback& callback) { if (process_singleton_.get()) @@ -369,10 +397,46 @@ bool App::MakeSingleInstance( } } -mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( - v8::Isolate* isolate) { +#if defined(USE_NSS_CERTS) +void App::ImportCertificate( + const base::DictionaryValue& options, + const net::CompletionCallback& callback) { + auto browser_context = AtomBrowserMainParts::Get()->browser_context(); + if (!certificate_manager_model_) { + scoped_ptr copy = options.CreateDeepCopy(); + CertificateManagerModel::Create(browser_context, + base::Bind(&App::OnCertificateManagerModelCreated, + base::Unretained(this), + base::Passed(©), + callback)); + return; + } + + int rv = ImportIntoCertStore(certificate_manager_model_.get(), options); + callback.Run(rv); +} + +void App::OnCertificateManagerModelCreated( + scoped_ptr options, + const net::CompletionCallback& callback, + scoped_ptr model) { + certificate_manager_model_ = std::move(model); + int rv = ImportIntoCertStore(certificate_manager_model_.get(), + *(options.get())); + callback.Run(rv); +} +#endif + +// static +mate::Handle App::Create(v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new App(isolate)); +} + +// static +void App::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { auto browser = base::Unretained(Browser::Get()); - return mate::ObjectTemplateBuilder(isolate) + mate::ObjectTemplateBuilder(isolate, prototype) .SetMethod("quit", base::Bind(&Browser::Quit, browser)) .SetMethod("exit", base::Bind(&Browser::Exit, browser)) .SetMethod("focus", base::Bind(&Browser::Focus, browser)) @@ -387,6 +451,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( base::Bind(&Browser::ClearRecentDocuments, browser)) .SetMethod("setAppUserModelId", base::Bind(&Browser::SetAppUserModelID, browser)) + .SetMethod("isDefaultProtocolClient", + base::Bind(&Browser::IsDefaultProtocolClient, browser)) .SetMethod("setAsDefaultProtocolClient", base::Bind(&Browser::SetAsDefaultProtocolClient, browser)) .SetMethod("removeAsDefaultProtocolClient", @@ -394,13 +460,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( #if defined(OS_MACOSX) .SetMethod("hide", base::Bind(&Browser::Hide, browser)) .SetMethod("show", base::Bind(&Browser::Show, browser)) - .SetMethod("isDarkMode", - base::Bind(&Browser::IsDarkMode, browser)) #endif #if defined(OS_WIN) .SetMethod("setUserTasks", base::Bind(&Browser::SetUserTasks, browser)) - .SetMethod("isAeroGlassEnabled", &App::IsAeroGlassEnabled) #endif .SetMethod("setPath", &App::SetPath) .SetMethod("getPath", &App::GetPath) @@ -408,14 +471,12 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( .SetMethod("allowNTLMCredentialsForAllDomains", &App::AllowNTLMCredentialsForAllDomains) .SetMethod("getLocale", &App::GetLocale) +#if defined(USE_NSS_CERTS) + .SetMethod("importCertificate", &App::ImportCertificate) +#endif .SetMethod("makeSingleInstance", &App::MakeSingleInstance); } -// static -mate::Handle App::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new App); -} - } // namespace api } // namespace atom @@ -427,7 +488,6 @@ void AppendSwitch(const std::string& switch_string, mate::Arguments* args) { auto command_line = base::CommandLine::ForCurrentProcess(); if (switch_string == atom::switches::kPpapiFlashPath || - switch_string == atom::switches::kClientCertificate || switch_string == switches::kLogNetLog) { base::FilePath path; args->GetNext(&path); diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 5025a3869dd4..c99d5df77937 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -14,6 +14,11 @@ #include "chrome/browser/process_singleton.h" #include "content/public/browser/gpu_data_manager_observer.h" #include "native_mate/handle.h" +#include "net/base/completion_callback.h" + +#if defined(USE_NSS_CERTS) +#include "chrome/browser/certificate_manager_model.h" +#endif namespace base { class FilePath; @@ -28,12 +33,15 @@ namespace atom { namespace api { class App : public AtomBrowserClient::Delegate, - public mate::EventEmitter, + public mate::EventEmitter, public BrowserObserver, public content::GpuDataManagerObserver { public: static mate::Handle Create(v8::Isolate* isolate); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + // Called when window with disposition needs to be created. void OnCreateWindow(const GURL& target_url, const std::string& frame_name, @@ -41,9 +49,16 @@ class App : public AtomBrowserClient::Delegate, int render_process_id, int render_frame_id); +#if defined(USE_NSS_CERTS) + void OnCertificateManagerModelCreated( + scoped_ptr options, + const net::CompletionCallback& callback, + scoped_ptr model); +#endif + protected: - App(); - virtual ~App(); + explicit App(v8::Isolate* isolate); + ~App() override; // BrowserObserver: void OnBeforeQuit(bool* prevent_default) override; @@ -77,14 +92,6 @@ class App : public AtomBrowserClient::Delegate, // content::GpuDataManagerObserver: void OnGpuProcessCrashed(base::TerminationStatus exit_code) override; -#if defined(OS_MACOSX) - void OnPlatformThemeChanged() override; -#endif - - // mate::Wrappable: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; - private: // Get/Set the pre-defined path in PathService. base::FilePath GetPath(mate::Arguments* args, const std::string& name); @@ -98,12 +105,17 @@ class App : public AtomBrowserClient::Delegate, const ProcessSingleton::NotificationCallback& callback); std::string GetLocale(); -#if defined(OS_WIN) - bool IsAeroGlassEnabled(); +#if defined(USE_NSS_CERTS) + void ImportCertificate(const base::DictionaryValue& options, + const net::CompletionCallback& callback); #endif scoped_ptr process_singleton_; +#if defined(USE_NSS_CERTS) + scoped_ptr certificate_manager_model_; +#endif + DISALLOW_COPY_AND_ASSIGN(App); }; diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index 1a02a54d4533..cdf3406ae788 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -34,8 +34,9 @@ namespace atom { namespace api { -AutoUpdater::AutoUpdater() { +AutoUpdater::AutoUpdater(v8::Isolate* isolate) { auto_updater::AutoUpdater::SetDelegate(this); + Init(isolate); } AutoUpdater::~AutoUpdater() { @@ -78,14 +79,6 @@ void AutoUpdater::OnWindowAllClosed() { QuitAndInstall(); } -mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return mate::ObjectTemplateBuilder(isolate) - .SetMethod("setFeedURL", &auto_updater::AutoUpdater::SetFeedURL) - .SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates) - .SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall); -} - void AutoUpdater::QuitAndInstall() { // If we don't have any window then quitAndInstall immediately. WindowList* window_list = WindowList::GetInstance(); @@ -102,7 +95,16 @@ void AutoUpdater::QuitAndInstall() { // static mate::Handle AutoUpdater::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new AutoUpdater); + return mate::CreateHandle(isolate, new AutoUpdater(isolate)); +} + +// static +void AutoUpdater::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("setFeedURL", &auto_updater::AutoUpdater::SetFeedURL) + .SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates) + .SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall); } } // namespace api diff --git a/atom/browser/api/atom_api_auto_updater.h b/atom/browser/api/atom_api_auto_updater.h index 95b91041e9e3..857647258adf 100644 --- a/atom/browser/api/atom_api_auto_updater.h +++ b/atom/browser/api/atom_api_auto_updater.h @@ -16,15 +16,18 @@ namespace atom { namespace api { -class AutoUpdater : public mate::EventEmitter, +class AutoUpdater : public mate::EventEmitter, public auto_updater::Delegate, public WindowListObserver { public: static mate::Handle Create(v8::Isolate* isolate); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + protected: - AutoUpdater(); - virtual ~AutoUpdater(); + explicit AutoUpdater(v8::Isolate* isolate); + ~AutoUpdater() override; // Delegate implementations. void OnError(const std::string& error) override; @@ -39,10 +42,6 @@ class AutoUpdater : public mate::EventEmitter, // WindowListObserver: void OnWindowAllClosed() override; - // mate::Wrappable implementations: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; - private: void QuitAndInstall(); diff --git a/atom/browser/api/atom_api_cookies.cc b/atom/browser/api/atom_api_cookies.cc index e49a2ee2f676..8698b43485bf 100644 --- a/atom/browser/api/atom_api_cookies.cc +++ b/atom/browser/api/atom_api_cookies.cc @@ -186,8 +186,10 @@ void SetCookieOnIO(scoped_refptr getter, } // namespace -Cookies::Cookies(content::BrowserContext* browser_context) - : request_context_getter_(browser_context->GetRequestContext()) { +Cookies::Cookies(v8::Isolate* isolate, + content::BrowserContext* browser_context) + : request_context_getter_(browser_context->GetRequestContext()) { + Init(isolate); } Cookies::~Cookies() { @@ -223,7 +225,7 @@ void Cookies::Set(const base::DictionaryValue& details, mate::Handle Cookies::Create( v8::Isolate* isolate, content::BrowserContext* browser_context) { - return mate::CreateHandle(isolate, new Cookies(browser_context)); + return mate::CreateHandle(isolate, new Cookies(isolate, browser_context)); } // static diff --git a/atom/browser/api/atom_api_cookies.h b/atom/browser/api/atom_api_cookies.h index 302fd1b25110..33fee56960f4 100644 --- a/atom/browser/api/atom_api_cookies.h +++ b/atom/browser/api/atom_api_cookies.h @@ -46,8 +46,8 @@ class Cookies : public mate::TrackableObject { v8::Local prototype); protected: - explicit Cookies(content::BrowserContext* browser_context); - ~Cookies(); + Cookies(v8::Isolate* isolate, content::BrowserContext* browser_context); + ~Cookies() override; void Get(const base::DictionaryValue& filter, const GetCallback& callback); void Remove(const GURL& url, const std::string& name, diff --git a/atom/browser/api/atom_api_debugger.cc b/atom/browser/api/atom_api_debugger.cc index eab60311f3dd..03490360133a 100644 --- a/atom/browser/api/atom_api_debugger.cc +++ b/atom/browser/api/atom_api_debugger.cc @@ -31,9 +31,10 @@ WrapDebuggerCallback g_wrap_debugger; } // namespace -Debugger::Debugger(content::WebContents* web_contents) +Debugger::Debugger(v8::Isolate* isolate, content::WebContents* web_contents) : web_contents_(web_contents), previous_request_id_(0) { + Init(isolate); } Debugger::~Debugger() { @@ -150,7 +151,8 @@ void Debugger::SendCommand(mate::Arguments* args) { mate::Handle Debugger::Create( v8::Isolate* isolate, content::WebContents* web_contents) { - auto handle = mate::CreateHandle(isolate, new Debugger(web_contents)); + auto handle = mate::CreateHandle( + isolate, new Debugger(isolate, web_contents)); g_wrap_debugger.Run(handle.ToV8()); return handle; } @@ -165,16 +167,8 @@ void Debugger::BuildPrototype(v8::Isolate* isolate, .SetMethod("sendCommand", &Debugger::SendCommand); } -void ClearWrapDebugger() { - g_wrap_debugger.Reset(); -} - void SetWrapDebugger(const WrapDebuggerCallback& callback) { g_wrap_debugger = callback; - - // Cleanup the wrapper on exit. - atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback( - base::Bind(ClearWrapDebugger)); } } // namespace api diff --git a/atom/browser/api/atom_api_debugger.h b/atom/browser/api/atom_api_debugger.h index 5454108e8b09..1e97fa89abd0 100644 --- a/atom/browser/api/atom_api_debugger.h +++ b/atom/browser/api/atom_api_debugger.h @@ -42,8 +42,8 @@ class Debugger: public mate::TrackableObject, v8::Local prototype); protected: - explicit Debugger(content::WebContents* web_contents); - ~Debugger(); + Debugger(v8::Isolate* isolate, content::WebContents* web_contents); + ~Debugger() override; // content::DevToolsAgentHostClient: void AgentHostClosed(content::DevToolsAgentHost* agent_host, diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index cdae6f0c44cd..9200a89224c2 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -38,7 +38,8 @@ namespace atom { namespace api { -DesktopCapturer::DesktopCapturer() { +DesktopCapturer::DesktopCapturer(v8::Isolate* isolate) { + Init(isolate); } DesktopCapturer::~DesktopCapturer() { @@ -88,19 +89,19 @@ void DesktopCapturer::OnSourceThumbnailChanged(int index) { bool DesktopCapturer::OnRefreshFinished() { Emit("finished", media_list_->GetSources()); - media_list_.reset(); return false; } -mate::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return mate::ObjectTemplateBuilder(isolate) - .SetMethod("startHandling", &DesktopCapturer::StartHandling); -} - // static mate::Handle DesktopCapturer::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new DesktopCapturer); + return mate::CreateHandle(isolate, new DesktopCapturer(isolate)); +} + +// static +void DesktopCapturer::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("startHandling", &DesktopCapturer::StartHandling); } } // namespace api diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index c22c8a44835f..e71141fa5218 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -14,18 +14,21 @@ namespace atom { namespace api { -class DesktopCapturer: public mate::EventEmitter, +class DesktopCapturer: public mate::EventEmitter, public DesktopMediaListObserver { public: static mate::Handle Create(v8::Isolate* isolate); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + void StartHandling(bool capture_window, bool capture_screen, const gfx::Size& thumbnail_size); protected: - DesktopCapturer(); - ~DesktopCapturer(); + explicit DesktopCapturer(v8::Isolate* isolate); + ~DesktopCapturer() override; // DesktopMediaListObserver overrides. void OnSourceAdded(int index) override; @@ -36,10 +39,6 @@ class DesktopCapturer: public mate::EventEmitter, bool OnRefreshFinished() override; private: - // mate::Wrappable: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; - scoped_ptr media_list_; DISALLOW_COPY_AND_ASSIGN(DesktopCapturer); diff --git a/atom/browser/api/atom_api_download_item.cc b/atom/browser/api/atom_api_download_item.cc index 3edd5f9c2549..96826a250f57 100644 --- a/atom/browser/api/atom_api_download_item.cc +++ b/atom/browser/api/atom_api_download_item.cc @@ -57,9 +57,11 @@ std::map>> g_download_item_objects; } // namespace -DownloadItem::DownloadItem(content::DownloadItem* download_item) +DownloadItem::DownloadItem(v8::Isolate* isolate, + content::DownloadItem* download_item) : download_item_(download_item) { download_item_->AddObserver(this); + Init(isolate); AttachAsUserData(download_item); } @@ -173,7 +175,7 @@ mate::Handle DownloadItem::Create( if (existing) return mate::CreateHandle(isolate, static_cast(existing)); - auto handle = mate::CreateHandle(isolate, new DownloadItem(item)); + auto handle = mate::CreateHandle(isolate, new DownloadItem(isolate, item)); g_wrap_download_item.Run(handle.ToV8()); // Reference this object in case it got garbage collected. @@ -182,16 +184,8 @@ mate::Handle DownloadItem::Create( return handle; } -void ClearWrapDownloadItem() { - g_wrap_download_item.Reset(); -} - void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) { g_wrap_download_item = callback; - - // Cleanup the wrapper on exit. - atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback( - base::Bind(ClearWrapDownloadItem)); } } // namespace api diff --git a/atom/browser/api/atom_api_download_item.h b/atom/browser/api/atom_api_download_item.h index 64469b9b34d1..bc7ddd821bb9 100644 --- a/atom/browser/api/atom_api_download_item.h +++ b/atom/browser/api/atom_api_download_item.h @@ -23,7 +23,6 @@ class DownloadItem : public mate::TrackableObject, static mate::Handle Create(v8::Isolate* isolate, content::DownloadItem* item); - // mate::TrackableObject: static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); @@ -41,7 +40,7 @@ class DownloadItem : public mate::TrackableObject, base::FilePath GetSavePath() const; protected: - explicit DownloadItem(content::DownloadItem* download_item); + DownloadItem(v8::Isolate* isolate, content::DownloadItem* download_item); ~DownloadItem(); // Override content::DownloadItem::Observer methods diff --git a/atom/browser/api/atom_api_global_shortcut.cc b/atom/browser/api/atom_api_global_shortcut.cc index f5a03e4abf90..2b1e5d6591a0 100644 --- a/atom/browser/api/atom_api_global_shortcut.cc +++ b/atom/browser/api/atom_api_global_shortcut.cc @@ -19,7 +19,8 @@ namespace atom { namespace api { -GlobalShortcut::GlobalShortcut() { +GlobalShortcut::GlobalShortcut(v8::Isolate* isolate) { + Init(isolate); } GlobalShortcut::~GlobalShortcut() { @@ -66,20 +67,21 @@ void GlobalShortcut::UnregisterAll() { GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this); } -mate::ObjectTemplateBuilder GlobalShortcut::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return mate::ObjectTemplateBuilder(isolate) +// static +mate::Handle GlobalShortcut::Create(v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new GlobalShortcut(isolate)); +} + +// static +void GlobalShortcut::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) .SetMethod("register", &GlobalShortcut::Register) .SetMethod("isRegistered", &GlobalShortcut::IsRegistered) .SetMethod("unregister", &GlobalShortcut::Unregister) .SetMethod("unregisterAll", &GlobalShortcut::UnregisterAll); } -// static -mate::Handle GlobalShortcut::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new GlobalShortcut); -} - } // namespace api } // namespace atom diff --git a/atom/browser/api/atom_api_global_shortcut.h b/atom/browser/api/atom_api_global_shortcut.h index d7057b000320..41eb42f85569 100644 --- a/atom/browser/api/atom_api_global_shortcut.h +++ b/atom/browser/api/atom_api_global_shortcut.h @@ -23,13 +23,12 @@ class GlobalShortcut : public extensions::GlobalShortcutListener::Observer, public: static mate::Handle Create(v8::Isolate* isolate); - protected: - GlobalShortcut(); - ~GlobalShortcut() override; + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); - // mate::Wrappable implementations: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; + protected: + explicit GlobalShortcut(v8::Isolate* isolate); + ~GlobalShortcut() override; private: typedef std::map AcceleratorCallbackMap; diff --git a/atom/browser/api/atom_api_menu.cc b/atom/browser/api/atom_api_menu.cc index e40ba17f464f..996c71739bc4 100644 --- a/atom/browser/api/atom_api_menu.cc +++ b/atom/browser/api/atom_api_menu.cc @@ -19,7 +19,7 @@ namespace atom { namespace api { -Menu::Menu() +Menu::Menu(v8::Isolate* isolate) : model_(new AtomMenuModel(this)), parent_(NULL) { } @@ -28,7 +28,7 @@ Menu::~Menu() { } void Menu::AfterInit(v8::Isolate* isolate) { - mate::Dictionary wrappable(isolate, GetWrapper(isolate)); + mate::Dictionary wrappable(isolate, GetWrapper()); mate::Dictionary delegate; if (!wrappable.Get("delegate", &delegate)) return; diff --git a/atom/browser/api/atom_api_menu.h b/atom/browser/api/atom_api_menu.h index 1ae708863a73..5701985ab101 100644 --- a/atom/browser/api/atom_api_menu.h +++ b/atom/browser/api/atom_api_menu.h @@ -20,7 +20,7 @@ namespace api { class Menu : public mate::TrackableObject, public AtomMenuModel::Delegate { public: - static mate::Wrappable* Create(); + static mate::WrappableBase* Create(v8::Isolate* isolate); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); @@ -36,7 +36,7 @@ class Menu : public mate::TrackableObject, AtomMenuModel* model() const { return model_.get(); } protected: - Menu(); + explicit Menu(v8::Isolate* isolate); ~Menu() override; // mate::Wrappable: diff --git a/atom/browser/api/atom_api_menu_mac.h b/atom/browser/api/atom_api_menu_mac.h index 85227fa2a9d9..293e8ec4edae 100644 --- a/atom/browser/api/atom_api_menu_mac.h +++ b/atom/browser/api/atom_api_menu_mac.h @@ -17,7 +17,7 @@ namespace api { class MenuMac : public Menu { protected: - MenuMac(); + explicit MenuMac(v8::Isolate* isolate); void PopupAt(Window* window, int x, int y, int positioning_item = 0) override; diff --git a/atom/browser/api/atom_api_menu_mac.mm b/atom/browser/api/atom_api_menu_mac.mm index 71c677b0476e..d8ee089c1cba 100644 --- a/atom/browser/api/atom_api_menu_mac.mm +++ b/atom/browser/api/atom_api_menu_mac.mm @@ -15,7 +15,7 @@ namespace atom { namespace api { -MenuMac::MenuMac() { +MenuMac::MenuMac(v8::Isolate* isolate) : Menu(isolate) { } void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) { @@ -68,8 +68,8 @@ void Menu::SendActionToFirstResponder(const std::string& action) { } // static -mate::Wrappable* Menu::Create() { - return new MenuMac(); +mate::WrappableBase* Menu::Create(v8::Isolate* isolate) { + return new MenuMac(isolate); } } // namespace api diff --git a/atom/browser/api/atom_api_menu_views.cc b/atom/browser/api/atom_api_menu_views.cc index 4a3a97dd906e..4d1c902e1755 100644 --- a/atom/browser/api/atom_api_menu_views.cc +++ b/atom/browser/api/atom_api_menu_views.cc @@ -13,7 +13,7 @@ namespace atom { namespace api { -MenuViews::MenuViews() { +MenuViews::MenuViews(v8::Isolate* isolate) : Menu(isolate) { } void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) { @@ -49,8 +49,8 @@ void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) { } // static -mate::Wrappable* Menu::Create() { - return new MenuViews(); +mate::WrappableBase* Menu::Create(v8::Isolate* isolate) { + return new MenuViews(isolate); } } // namespace api diff --git a/atom/browser/api/atom_api_menu_views.h b/atom/browser/api/atom_api_menu_views.h index e4d17c77ca65..e1daa4904028 100644 --- a/atom/browser/api/atom_api_menu_views.h +++ b/atom/browser/api/atom_api_menu_views.h @@ -14,7 +14,7 @@ namespace api { class MenuViews : public Menu { public: - MenuViews(); + explicit MenuViews(v8::Isolate* isolate); protected: void PopupAt(Window* window, int x, int y, int positioning_item = 0) override; diff --git a/atom/browser/api/atom_api_power_monitor.cc b/atom/browser/api/atom_api_power_monitor.cc index 31b35e10cea8..32c50c696c7f 100644 --- a/atom/browser/api/atom_api_power_monitor.cc +++ b/atom/browser/api/atom_api_power_monitor.cc @@ -14,8 +14,9 @@ namespace atom { namespace api { -PowerMonitor::PowerMonitor() { +PowerMonitor::PowerMonitor(v8::Isolate* isolate) { base::PowerMonitor::Get()->AddObserver(this); + Init(isolate); } PowerMonitor::~PowerMonitor() { @@ -46,7 +47,13 @@ v8::Local PowerMonitor::Create(v8::Isolate* isolate) { return v8::Null(isolate); } - return CreateHandle(isolate, new PowerMonitor).ToV8(); + return mate::CreateHandle(isolate, new PowerMonitor(isolate)).ToV8(); +} + +// static +void PowerMonitor::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype); } } // namespace api diff --git a/atom/browser/api/atom_api_power_monitor.h b/atom/browser/api/atom_api_power_monitor.h index 8fb52eeec95e..50d4bb466ca9 100644 --- a/atom/browser/api/atom_api_power_monitor.h +++ b/atom/browser/api/atom_api_power_monitor.h @@ -19,8 +19,11 @@ class PowerMonitor : public mate::TrackableObject, public: static v8::Local Create(v8::Isolate* isolate); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + protected: - PowerMonitor(); + explicit PowerMonitor(v8::Isolate* isolate); ~PowerMonitor() override; // base::PowerObserver implementations: diff --git a/atom/browser/api/atom_api_power_save_blocker.cc b/atom/browser/api/atom_api_power_save_blocker.cc index 58983e6c846a..b8adcb776e56 100644 --- a/atom/browser/api/atom_api_power_save_blocker.cc +++ b/atom/browser/api/atom_api_power_save_blocker.cc @@ -37,9 +37,10 @@ namespace atom { namespace api { -PowerSaveBlocker::PowerSaveBlocker() +PowerSaveBlocker::PowerSaveBlocker(v8::Isolate* isolate) : current_blocker_type_( - content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension) { + content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension) { + Init(isolate); } PowerSaveBlocker::~PowerSaveBlocker() { @@ -97,17 +98,18 @@ bool PowerSaveBlocker::IsStarted(int id) { return power_save_blocker_types_.find(id) != power_save_blocker_types_.end(); } -mate::ObjectTemplateBuilder PowerSaveBlocker::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return mate::ObjectTemplateBuilder(isolate) - .SetMethod("start", &PowerSaveBlocker::Start) - .SetMethod("stop", &PowerSaveBlocker::Stop) - .SetMethod("isStarted", &PowerSaveBlocker::IsStarted); +// static +mate::Handle PowerSaveBlocker::Create(v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new PowerSaveBlocker(isolate)); } // static -mate::Handle PowerSaveBlocker::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new PowerSaveBlocker); +void PowerSaveBlocker::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("start", &PowerSaveBlocker::Start) + .SetMethod("stop", &PowerSaveBlocker::Stop) + .SetMethod("isStarted", &PowerSaveBlocker::IsStarted); } } // namespace api diff --git a/atom/browser/api/atom_api_power_save_blocker.h b/atom/browser/api/atom_api_power_save_blocker.h index a698d746ceb0..c24ae0aa4b66 100644 --- a/atom/browser/api/atom_api_power_save_blocker.h +++ b/atom/browser/api/atom_api_power_save_blocker.h @@ -24,13 +24,12 @@ class PowerSaveBlocker : public mate::TrackableObject { public: static mate::Handle Create(v8::Isolate* isolate); - protected: - PowerSaveBlocker(); - ~PowerSaveBlocker() override; + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); - // mate::Wrappable implementations: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; + protected: + explicit PowerSaveBlocker(v8::Isolate* isolate); + ~PowerSaveBlocker() override; private: void UpdatePowerSaveBlocker(); diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 09da9c71cadb..3835fac62d7a 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -22,37 +22,11 @@ namespace atom { namespace api { -Protocol::Protocol(AtomBrowserContext* browser_context) +Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context) : request_context_getter_(browser_context->GetRequestContext()), job_factory_(browser_context->job_factory()) { CHECK(job_factory_); -} - -mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return mate::ObjectTemplateBuilder(isolate) - .SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes) - .SetMethod("registerServiceWorkerSchemes", - &Protocol::RegisterServiceWorkerSchemes) - .SetMethod("registerStringProtocol", - &Protocol::RegisterProtocol) - .SetMethod("registerBufferProtocol", - &Protocol::RegisterProtocol) - .SetMethod("registerFileProtocol", - &Protocol::RegisterProtocol) - .SetMethod("registerHttpProtocol", - &Protocol::RegisterProtocol) - .SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol) - .SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled) - .SetMethod("interceptStringProtocol", - &Protocol::InterceptProtocol) - .SetMethod("interceptBufferProtocol", - &Protocol::InterceptProtocol) - .SetMethod("interceptFileProtocol", - &Protocol::InterceptProtocol) - .SetMethod("interceptHttpProtocol", - &Protocol::InterceptProtocol) - .SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol); + Init(isolate); } void Protocol::RegisterStandardSchemes( @@ -150,7 +124,35 @@ std::string Protocol::ErrorCodeToString(ProtocolError error) { // static mate::Handle Protocol::Create( v8::Isolate* isolate, AtomBrowserContext* browser_context) { - return mate::CreateHandle(isolate, new Protocol(browser_context)); + return mate::CreateHandle(isolate, new Protocol(isolate, browser_context)); +} + +// static +void Protocol::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes) + .SetMethod("registerServiceWorkerSchemes", + &Protocol::RegisterServiceWorkerSchemes) + .SetMethod("registerStringProtocol", + &Protocol::RegisterProtocol) + .SetMethod("registerBufferProtocol", + &Protocol::RegisterProtocol) + .SetMethod("registerFileProtocol", + &Protocol::RegisterProtocol) + .SetMethod("registerHttpProtocol", + &Protocol::RegisterProtocol) + .SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol) + .SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled) + .SetMethod("interceptStringProtocol", + &Protocol::InterceptProtocol) + .SetMethod("interceptBufferProtocol", + &Protocol::InterceptProtocol) + .SetMethod("interceptFileProtocol", + &Protocol::InterceptProtocol) + .SetMethod("interceptHttpProtocol", + &Protocol::InterceptProtocol) + .SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol); } } // namespace api diff --git a/atom/browser/api/atom_api_protocol.h b/atom/browser/api/atom_api_protocol.h index 107fbf1ce712..d7fa7f5211f8 100644 --- a/atom/browser/api/atom_api_protocol.h +++ b/atom/browser/api/atom_api_protocol.h @@ -30,7 +30,7 @@ class AtomURLRequestJobFactory; namespace api { -class Protocol : public mate::Wrappable { +class Protocol : public mate::Wrappable { public: using Handler = base::Callback)>; @@ -40,12 +40,11 @@ class Protocol : public mate::Wrappable { static mate::Handle Create( v8::Isolate* isolate, AtomBrowserContext* browser_context); - protected: - explicit Protocol(AtomBrowserContext* browser_context); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); - // mate::Wrappable implementations: - virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate); + protected: + Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context); private: // Possible errors. diff --git a/atom/browser/api/atom_api_screen.cc b/atom/browser/api/atom_api_screen.cc index 407a71f0cc41..9d845e390e31 100644 --- a/atom/browser/api/atom_api_screen.cc +++ b/atom/browser/api/atom_api_screen.cc @@ -47,9 +47,10 @@ std::vector MetricsToArray(uint32_t metrics) { } // namespace -Screen::Screen(gfx::Screen* screen) : screen_(screen) { - displays_ = screen_->GetAllDisplays(); +Screen::Screen(v8::Isolate* isolate, gfx::Screen* screen) + : screen_(screen) { screen_->AddObserver(this); + Init(isolate); } Screen::~Screen() { @@ -65,7 +66,7 @@ gfx::Display Screen::GetPrimaryDisplay() { } std::vector Screen::GetAllDisplays() { - return displays_; + return screen_->GetAllDisplays(); } gfx::Display Screen::GetDisplayNearestPoint(const gfx::Point& point) { @@ -77,39 +78,18 @@ gfx::Display Screen::GetDisplayMatching(const gfx::Rect& match_rect) { } void Screen::OnDisplayAdded(const gfx::Display& new_display) { - displays_.push_back(new_display); Emit("display-added", new_display); } void Screen::OnDisplayRemoved(const gfx::Display& old_display) { - auto iter = FindById(&displays_, old_display.id()); - if (iter == displays_.end()) - return; - - displays_.erase(iter); Emit("display-removed", old_display); } void Screen::OnDisplayMetricsChanged(const gfx::Display& display, uint32_t changed_metrics) { - auto iter = FindById(&displays_, display.id()); - if (iter == displays_.end()) - return; - - *iter = display; Emit("display-metrics-changed", display, MetricsToArray(changed_metrics)); } -mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return mate::ObjectTemplateBuilder(isolate) - .SetMethod("getCursorScreenPoint", &Screen::GetCursorScreenPoint) - .SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay) - .SetMethod("getAllDisplays", &Screen::GetAllDisplays) - .SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint) - .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching); -} - // static v8::Local Screen::Create(v8::Isolate* isolate) { if (!Browser::Get()->is_ready()) { @@ -126,7 +106,18 @@ v8::Local Screen::Create(v8::Isolate* isolate) { return v8::Null(isolate); } - return mate::CreateHandle(isolate, new Screen(screen)).ToV8(); + return mate::CreateHandle(isolate, new Screen(isolate, screen)).ToV8(); +} + +// static +void Screen::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("getCursorScreenPoint", &Screen::GetCursorScreenPoint) + .SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay) + .SetMethod("getAllDisplays", &Screen::GetAllDisplays) + .SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint) + .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching); } } // namespace api diff --git a/atom/browser/api/atom_api_screen.h b/atom/browser/api/atom_api_screen.h index f724130fa7fc..c17b61288525 100644 --- a/atom/browser/api/atom_api_screen.h +++ b/atom/browser/api/atom_api_screen.h @@ -21,14 +21,17 @@ namespace atom { namespace api { -class Screen : public mate::EventEmitter, +class Screen : public mate::EventEmitter, public gfx::DisplayObserver { public: static v8::Local Create(v8::Isolate* isolate); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + protected: - explicit Screen(gfx::Screen* screen); - virtual ~Screen(); + Screen(v8::Isolate* isolate, gfx::Screen* screen); + ~Screen() override; gfx::Point GetCursorScreenPoint(); gfx::Display GetPrimaryDisplay(); @@ -42,13 +45,8 @@ class Screen : public mate::EventEmitter, void OnDisplayMetricsChanged(const gfx::Display& display, uint32_t changed_metrics) override; - // mate::Wrappable: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; - private: gfx::Screen* screen_; - std::vector displays_; DISALLOW_COPY_AND_ASSIGN(Screen); }; diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 0f104c760724..39c435b723ea 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -9,9 +9,7 @@ #include "atom/browser/api/atom_api_cookies.h" #include "atom/browser/api/atom_api_download_item.h" -#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_request.h" -#include "atom/browser/api/save_page_handler.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_permission_manager.h" @@ -23,12 +21,13 @@ #include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/node_includes.h" #include "base/files/file_path.h" +#include "base/guid.h" #include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/thread_task_runner_handle.h" #include "brightray/browser/net/devtools_network_conditions.h" -#include "brightray/browser/net/devtools_network_controller.h" +#include "brightray/browser/net/devtools_network_controller_handle.h" #include "chrome/common/pref_names.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" @@ -287,13 +286,15 @@ void ClearHostResolverCacheInIO( } // namespace -Session::Session(AtomBrowserContext* browser_context) - : browser_context_(browser_context) { - AttachAsUserData(browser_context); - +Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context) + : devtools_network_emulation_client_id_(base::GenerateGUID()), + browser_context_(browser_context) { // Observe DownloadManger to get download notifications. content::BrowserContext::GetDownloadManager(browser_context)-> AddObserver(this); + + Init(isolate); + AttachAsUserData(browser_context); } Session::~Session() { @@ -303,13 +304,15 @@ Session::~Session() { void Session::OnDownloadCreated(content::DownloadManager* manager, content::DownloadItem* item) { - auto web_contents = item->GetWebContents(); - if (SavePageHandler::IsSavePageTypes(item->GetMimeType())) + if (item->IsSavePackageDownload()) return; + + v8::Locker locker(isolate()); + v8::HandleScope handle_scope(isolate()); bool prevent_default = Emit( "will-download", DownloadItem::Create(isolate(), item), - api::WebContents::CreateFrom(isolate(), web_contents)); + item->GetWebContents()); if (prevent_default) { item->Cancel(true); item->Remove(); @@ -381,25 +384,19 @@ void Session::EnableNetworkEmulation(const mate::Dictionary& options) { download_throughput, upload_throughput)); } - auto controller = browser_context_->GetDevToolsNetworkController(); - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&brightray::DevToolsNetworkController::SetNetworkState, - base::Unretained(controller), - std::string(), - base::Passed(&conditions))); + browser_context_->network_controller_handle()->SetNetworkState( + devtools_network_emulation_client_id_, std::move(conditions)); + browser_context_->network_delegate()->SetDevToolsNetworkEmulationClientId( + devtools_network_emulation_client_id_); } void Session::DisableNetworkEmulation() { - scoped_ptr conditions( - new brightray::DevToolsNetworkConditions(false)); - auto controller = browser_context_->GetDevToolsNetworkController(); - - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&brightray::DevToolsNetworkController::SetNetworkState, - base::Unretained(controller), - std::string(), - base::Passed(&conditions))); + scoped_ptr conditions; + browser_context_->network_controller_handle()->SetNetworkState( + devtools_network_emulation_client_id_, std::move(conditions)); + browser_context_->network_delegate()->SetDevToolsNetworkEmulationClientId( + std::string()); } void Session::SetCertVerifyProc(v8::Local val, @@ -458,7 +455,8 @@ mate::Handle Session::CreateFrom( if (existing) return mate::CreateHandle(isolate, static_cast(existing)); - auto handle = mate::CreateHandle(isolate, new Session(browser_context)); + auto handle = mate::CreateHandle( + isolate, new Session(isolate, browser_context)); g_wrap_session.Run(handle.ToV8()); return handle; } @@ -493,16 +491,8 @@ void Session::BuildPrototype(v8::Isolate* isolate, .SetProperty("webRequest", &Session::WebRequest); } -void ClearWrapSession() { - g_wrap_session.Reset(); -} - void SetWrapSession(const WrapSessionCallback& callback) { g_wrap_session = callback; - - // Cleanup the wrapper on exit. - atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback( - base::Bind(ClearWrapSession)); } } // namespace api diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index 02d8ba5cdec0..5e08a85aa7d1 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -58,7 +58,7 @@ class Session: public mate::TrackableObject, v8::Local prototype); protected: - explicit Session(AtomBrowserContext* browser_context); + Session(v8::Isolate* isolate, AtomBrowserContext* browser_context); ~Session(); // content::DownloadManager::Observer: @@ -86,6 +86,9 @@ class Session: public mate::TrackableObject, v8::Global cookies_; v8::Global web_request_; + // The X-DevTools-Emulate-Network-Conditions-Client-Id. + std::string devtools_network_emulation_client_id_; + scoped_refptr browser_context_; DISALLOW_COPY_AND_ASSIGN(Session); diff --git a/atom/browser/api/atom_api_system_preferences.cc b/atom/browser/api/atom_api_system_preferences.cc new file mode 100644 index 000000000000..b8c665456ade --- /dev/null +++ b/atom/browser/api/atom_api_system_preferences.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2016 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_system_preferences.h" + +#include "atom/common/native_mate_converters/callback.h" +#include "atom/common/node_includes.h" +#include "native_mate/dictionary.h" + +#if defined(OS_WIN) +#include "ui/base/win/shell.h" +#endif + +namespace atom { + +namespace api { + +SystemPreferences::SystemPreferences(v8::Isolate* isolate) { + Init(isolate); +} + +SystemPreferences::~SystemPreferences() { +} + +#if defined(OS_WIN) +bool SystemPreferences::IsAeroGlassEnabled() { + return ui::win::IsAeroGlassEnabled(); +} +#endif + +#if !defined(OS_MACOSX) +bool SystemPreferences::IsDarkMode() { + return false; +} +#endif + +// static +mate::Handle SystemPreferences::Create( + v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new SystemPreferences(isolate)); +} + +// static +void SystemPreferences::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) +#if defined(OS_WIN) + .SetMethod("isAeroGlassEnabled", &SystemPreferences::IsAeroGlassEnabled) +#elif defined(OS_MACOSX) + .SetMethod("subscribeNotification", + &SystemPreferences::SubscribeNotification) + .SetMethod("unsubscribeNotification", + &SystemPreferences::UnsubscribeNotification) + .SetMethod("getUserDefault", &SystemPreferences::GetUserDefault) +#endif + .SetMethod("isDarkMode", &SystemPreferences::IsDarkMode); +} + +} // namespace api + +} // namespace atom + +namespace { + +void Initialize(v8::Local exports, v8::Local unused, + v8::Local context, void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + mate::Dictionary dict(isolate, exports); + dict.Set("systemPreferences", atom::api::SystemPreferences::Create(isolate)); +} + +} // namespace + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_system_preferences, Initialize); diff --git a/atom/browser/api/atom_api_system_preferences.h b/atom/browser/api/atom_api_system_preferences.h new file mode 100644 index 000000000000..fed1c52247b7 --- /dev/null +++ b/atom/browser/api/atom_api_system_preferences.h @@ -0,0 +1,48 @@ +// Copyright (c) 2016 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_SYSTEM_PREFERENCES_H_ +#define ATOM_BROWSER_API_ATOM_API_SYSTEM_PREFERENCES_H_ + +#include + +#include "atom/browser/api/event_emitter.h" +#include "base/callback.h" +#include "native_mate/handle.h" + +namespace atom { + +namespace api { + +class SystemPreferences : public mate::EventEmitter { + public: + static mate::Handle Create(v8::Isolate* isolate); + + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + +#if defined(OS_WIN) + bool IsAeroGlassEnabled(); +#elif defined(OS_MACOSX) + int SubscribeNotification(const std::string& name, + const base::Closure& callback); + void UnsubscribeNotification(int id); + v8::Local GetUserDefault(const std::string& name, + const std::string& type); +#endif + bool IsDarkMode(); + + protected: + explicit SystemPreferences(v8::Isolate* isolate); + ~SystemPreferences() override; + + private: + DISALLOW_COPY_AND_ASSIGN(SystemPreferences); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_SYSTEM_PREFERENCES_H_ diff --git a/atom/browser/api/atom_api_system_preferences_mac.mm b/atom/browser/api/atom_api_system_preferences_mac.mm new file mode 100644 index 000000000000..2d12b278ae92 --- /dev/null +++ b/atom/browser/api/atom_api_system_preferences_mac.mm @@ -0,0 +1,83 @@ +// Copyright (c) 2016 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_system_preferences.h" + +#include + +#import + +#include "atom/common/native_mate_converters/gurl_converter.h" +#include "base/strings/sys_string_conversions.h" +#include "net/base/mac/url_conversions.h" + +namespace atom { + +namespace api { + +namespace { + +int g_next_id = 0; + +// The map to convert |id| to |int|. +std::map g_id_map; + +} // namespace + +int SystemPreferences::SubscribeNotification(const std::string& name, + const base::Closure& callback) { + int request_id = g_next_id++; + __block base::Closure copied_callback = callback; + g_id_map[request_id] = [[NSDistributedNotificationCenter defaultCenter] + addObserverForName:base::SysUTF8ToNSString(name) + object:nil + queue:nil + usingBlock:^(NSNotification* notification) { + copied_callback.Run(); + } + ]; + return request_id; +} + +void SystemPreferences::UnsubscribeNotification(int request_id) { + auto iter = g_id_map.find(request_id); + if (iter != g_id_map.end()) { + id observer = iter->second; + [[NSDistributedNotificationCenter defaultCenter] removeObserver:observer]; + g_id_map.erase(iter); + } +} + +v8::Local SystemPreferences::GetUserDefault( + const std::string& name, const std::string& type) { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + NSString* key = base::SysUTF8ToNSString(name); + if (type == "string") { + return mate::StringToV8( + isolate(), base::SysNSStringToUTF8([defaults stringForKey:key])); + } else if (type == "boolean") { + return v8::Boolean::New(isolate(), [defaults boolForKey:key]); + } else if (type == "float") { + return v8::Number::New(isolate(), [defaults floatForKey:key]); + } else if (type == "integer") { + return v8::Integer::New(isolate(), [defaults integerForKey:key]); + } else if (type == "double") { + return v8::Number::New(isolate(), [defaults doubleForKey:key]); + } else if (type == "url") { + return mate::ConvertToV8( + isolate(), net::GURLWithNSURL([defaults URLForKey:key])); + } else { + return v8::Undefined(isolate()); + } +} + +bool SystemPreferences::IsDarkMode() { + NSString* mode = [[NSUserDefaults standardUserDefaults] + stringForKey:@"AppleInterfaceStyle"]; + return [mode isEqualToString:@"Dark"]; +} + +} // namespace api + +} // namespace atom diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index 5f351f485049..34fe81b92b22 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -22,7 +22,7 @@ namespace atom { namespace api { -Tray::Tray(const gfx::Image& image) +Tray::Tray(v8::Isolate* isolate, const gfx::Image& image) : tray_icon_(TrayIcon::Create()) { tray_icon_->SetImage(image); tray_icon_->AddObserver(this); @@ -32,13 +32,13 @@ Tray::~Tray() { } // static -mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) { +mate::WrappableBase* Tray::New(v8::Isolate* isolate, const gfx::Image& image) { if (!Browser::Get()->is_ready()) { isolate->ThrowException(v8::Exception::Error(mate::StringToV8( isolate, "Cannot create Tray before app is ready"))); return nullptr; } - return new Tray(image); + return new Tray(isolate, image); } void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) { diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h index 0e0d153ad0d3..84e68220dba8 100644 --- a/atom/browser/api/atom_api_tray.h +++ b/atom/browser/api/atom_api_tray.h @@ -32,13 +32,14 @@ class Menu; class Tray : public mate::TrackableObject, public TrayIconObserver { public: - static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image); + static mate::WrappableBase* New( + v8::Isolate* isolate, const gfx::Image& image); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); protected: - explicit Tray(const gfx::Image& image); + Tray(v8::Isolate* isolate, const gfx::Image& image); ~Tray() override; // TrayIconObserver: diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 8c0f7d571f35..a48277490b00 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -13,12 +13,16 @@ #include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" +#include "atom/browser/atom_security_state_model_client.h" #include "atom/browser/native_window.h" +#include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/web_contents_permission_helper.h" #include "atom/browser/web_contents_preferences.h" #include "atom/browser/web_view_guest_delegate.h" #include "atom/common/api/api_messages.h" #include "atom/common/api/event_emitter_caller.h" +#include "atom/common/color_util.h" +#include "atom/common/mouse_util.h" #include "atom/common/native_mate_converters/blink_converter.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/content_converter.h" @@ -28,13 +32,14 @@ #include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/mouse_util.h" +#include "atom/common/options_switches.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents_view.h" #include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_preview_message_handler.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/common/view_messages.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/native_web_keyboard_event.h" @@ -210,17 +215,27 @@ content::ServiceWorkerContext* GetServiceWorkerContext( } // namespace -WebContents::WebContents(content::WebContents* web_contents) +WebContents::WebContents(v8::Isolate* isolate, + content::WebContents* web_contents) : content::WebContentsObserver(web_contents), - type_(REMOTE) { - AttachAsUserData(web_contents); + embedder_(nullptr), + type_(REMOTE), + request_id_(0), + background_throttling_(true) { web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); + + Init(isolate); + AttachAsUserData(web_contents); } WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options) : embedder_(nullptr), - request_id_(0) { + request_id_(0), + background_throttling_(true) { + // Read options. + options.Get("backgroundThrottling", &background_throttling_); + // Whether it is a guest WebContents. bool is_guest = false; options.Get("isGuest", &is_guest); @@ -258,7 +273,6 @@ WebContents::WebContents(v8::Isolate* isolate, } Observe(web_contents); - AttachAsUserData(web_contents); InitWithWebContents(web_contents); managed_web_contents()->GetView()->SetDelegate(this); @@ -268,6 +282,8 @@ WebContents::WebContents(v8::Isolate* isolate, // Intialize permission helper. WebContentsPermissionHelper::CreateForWebContents(web_contents); + // Intialize security state client. + AtomSecurityStateModelClient::CreateForWebContents(web_contents); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); @@ -285,6 +301,9 @@ WebContents::WebContents(v8::Isolate* isolate, if (owner_window) SetOwnerWindow(owner_window); } + + Init(isolate); + AttachAsUserData(web_contents); } WebContents::~WebContents() { @@ -538,18 +557,21 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host, void WebContents::DidFailProvisionalLoad( content::RenderFrameHost* render_frame_host, const GURL& url, - int error_code, - const base::string16& error_description, + int code, + const base::string16& description, bool was_ignored_by_handler) { - Emit("did-fail-provisional-load", error_code, error_description, url); + bool is_main_frame = !render_frame_host->GetParent(); + Emit("did-fail-provisional-load", code, description, url, is_main_frame); + Emit("did-fail-load", code, description, url, is_main_frame); } void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url, + const GURL& url, int error_code, const base::string16& error_description, bool was_ignored_by_handler) { - Emit("did-fail-load", error_code, error_description, validated_url); + bool is_main_frame = !render_frame_host->GetParent(); + Emit("did-fail-load", error_code, error_description, url, is_main_frame); } void WebContents::DidStartLoading() { @@ -569,7 +591,8 @@ void WebContents::DidGetResourceResponseStart( details.http_response_code, details.method, details.referrer, - details.headers.get()); + details.headers.get(), + ResourceTypeToString(details.resource_type)); } void WebContents::DidGetRedirectForResourceRequest( @@ -615,6 +638,10 @@ void WebContents::DidUpdateFaviconURL( Emit("page-favicon-updated", unique_urls); } +void WebContents::DevToolsReloadPage() { + Emit("devtools-reload-page"); +} + void WebContents::DevToolsFocused() { Emit("devtools-focused"); } @@ -705,7 +732,8 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) { Emit("did-fail-load", static_cast(net::ERR_INVALID_URL), net::ErrorToShortString(net::ERR_INVALID_URL), - url.possibly_invalid_spec()); + url.possibly_invalid_spec(), + true); return; } @@ -728,6 +756,25 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) { 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. + // We have to call it right after LoadURL because the RenderViewHost is only + // created after loading a page. + const auto view = web_contents()->GetRenderWidgetHostView(); + 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); + } + + // For the same reason we can only disable hidden here. + const auto host = static_cast( + view->GetRenderWidgetHost()); + host->disable_hidden_ = !background_throttling_; } void WebContents::DownloadURL(const GURL& url) { @@ -751,6 +798,14 @@ bool WebContents::IsLoading() const { return web_contents()->IsLoading(); } +bool WebContents::IsLoadingMainFrame() const { + // Comparing site instances works because Electron always creates a new site + // instance when navigating, regardless of origin. See AtomBrowserClient. + return (web_contents()->GetLastCommittedURL().is_empty() || + web_contents()->GetSiteInstance() != + web_contents()->GetPendingSiteInstance()) && IsLoading(); +} + bool WebContents::IsWaitingForResponse() const { return web_contents()->IsWaitingForResponse(); } @@ -807,14 +862,20 @@ void WebContents::OpenDevTools(mate::Arguments* args) { if (type_ == REMOTE) return; - bool detach = false; + std::string state; if (type_ == WEB_VIEW) { - detach = true; + state = "detach"; } else if (args && args->Length() == 1) { + bool detach = false; mate::Dictionary options; - args->GetNext(&options) && options.Get("detach", &detach); + if (args->GetNext(&options)) { + options.Get("mode", &state); + options.Get("detach", &detach); + if (state.empty() && detach) + state = "detach"; + } } - managed_web_contents()->SetCanDock(!detach); + managed_web_contents()->SetDockState(state); managed_web_contents()->ShowDevTools(); } @@ -1147,6 +1208,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate, .SetMethod("_getURL", &WebContents::GetURL) .SetMethod("getTitle", &WebContents::GetTitle) .SetMethod("isLoading", &WebContents::IsLoading) + .SetMethod("isLoadingMainFrame", &WebContents::IsLoadingMainFrame) .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse) .SetMethod("_stop", &WebContents::Stop) .SetMethod("_goBack", &WebContents::GoBack) @@ -1233,7 +1295,8 @@ mate::Handle WebContents::CreateFrom( return mate::CreateHandle(isolate, static_cast(existing)); // Otherwise create a new WebContents wrapper object. - auto handle = mate::CreateHandle(isolate, new WebContents(web_contents)); + auto handle = mate::CreateHandle( + isolate, new WebContents(isolate, web_contents)); g_wrap_web_contents.Run(handle.ToV8()); return handle; } @@ -1246,16 +1309,8 @@ mate::Handle WebContents::Create( return handle; } -void ClearWrapWebContents() { - g_wrap_web_contents.Reset(); -} - void SetWrapWebContents(const WrapWebContentsCallback& callback) { g_wrap_web_contents = callback; - - // Cleanup the wrapper on exit. - atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback( - base::Bind(ClearWrapWebContents)); } } // namespace api diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 5fb1947f5795..9deb1696c411 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -55,6 +55,9 @@ class WebContents : public mate::TrackableObject, static mate::Handle Create( v8::Isolate* isolate, const mate::Dictionary& options); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + int GetID() const; bool Equal(const WebContents* web_contents) const; void LoadURL(const GURL& url, const mate::Dictionary& options); @@ -62,6 +65,7 @@ class WebContents : public mate::TrackableObject, GURL GetURL() const; base::string16 GetTitle() const; bool IsLoading() const; + bool IsLoadingMainFrame() const; bool IsWaitingForResponse() const; void Stop(); void ReloadIgnoringCache(); @@ -155,12 +159,8 @@ class WebContents : public mate::TrackableObject, v8::Local DevToolsWebContents(v8::Isolate* isolate); v8::Local Debugger(v8::Isolate* isolate); - // mate::TrackableObject: - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - protected: - explicit WebContents(content::WebContents* web_contents); + WebContents(v8::Isolate* isolate, content::WebContents* web_contents); WebContents(v8::Isolate* isolate, const mate::Dictionary& options); ~WebContents(); @@ -251,6 +251,9 @@ class WebContents : public mate::TrackableObject, void MediaStoppedPlaying(const MediaPlayerId& id) override; void DidChangeThemeColor(SkColor theme_color) override; + // brightray::InspectableWebContentsDelegate: + void DevToolsReloadPage() override; + // brightray::InspectableWebContentsViewDelegate: void DevToolsFocused() override; void DevToolsOpened() override; @@ -296,6 +299,9 @@ class WebContents : public mate::TrackableObject, // Request id used for findInPage request. uint32_t request_id_; + // Whether background throttling is disabled. + bool background_throttling_; + DISALLOW_COPY_AND_ASSIGN(WebContents); }; diff --git a/atom/browser/api/atom_api_web_request.cc b/atom/browser/api/atom_api_web_request.cc index a987369ed82d..867901df065b 100644 --- a/atom/browser/api/atom_api_web_request.cc +++ b/atom/browser/api/atom_api_web_request.cc @@ -36,8 +36,10 @@ namespace atom { namespace api { -WebRequest::WebRequest(AtomBrowserContext* browser_context) +WebRequest::WebRequest(v8::Isolate* isolate, + AtomBrowserContext* browser_context) : browser_context_(browser_context) { + Init(isolate); } WebRequest::~WebRequest() { @@ -81,7 +83,7 @@ void WebRequest::SetListener(Method method, Event type, mate::Arguments* args) { mate::Handle WebRequest::Create( v8::Isolate* isolate, AtomBrowserContext* browser_context) { - return mate::CreateHandle(isolate, new WebRequest(browser_context)); + return mate::CreateHandle(isolate, new WebRequest(isolate, browser_context)); } // static diff --git a/atom/browser/api/atom_api_web_request.h b/atom/browser/api/atom_api_web_request.h index 9a6e17a04605..edcdcc5339e3 100644 --- a/atom/browser/api/atom_api_web_request.h +++ b/atom/browser/api/atom_api_web_request.h @@ -21,13 +21,12 @@ class WebRequest : public mate::TrackableObject { static mate::Handle Create(v8::Isolate* isolate, AtomBrowserContext* browser_context); - // mate::TrackableObject: static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); protected: - explicit WebRequest(AtomBrowserContext* browser_context); - ~WebRequest(); + WebRequest(v8::Isolate* isolate, AtomBrowserContext* browser_context); + ~WebRequest() override; // C++ can not distinguish overloaded member function. template diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc index e57c5ffb6bb4..f06c1105526e 100644 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ b/atom/browser/api/atom_api_web_view_manager.cc @@ -2,9 +2,9 @@ // 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_web_contents.h" #include "atom/browser/web_contents_preferences.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 "content/public/browser/browser_context.h" @@ -12,22 +12,6 @@ using atom::WebContentsPreferences; -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - content::WebContents** out) { - atom::api::WebContents* contents; - if (!Converter::FromV8(isolate, val, &contents)) - return false; - *out = contents->web_contents(); - return true; - } -}; - -} // namespace mate - namespace { atom::WebViewManager* GetWebViewManager(content::WebContents* web_contents) { diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index a10f46fe75e7..ae5eec64cf93 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -141,13 +141,17 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { if (options.Get(options::kZoomFactor, &value)) web_preferences.Set(options::kZoomFactor, value); + // Copy the backgroundColor to webContents. + if (options.Get(options::kBackgroundColor, &value)) + web_preferences.Set(options::kBackgroundColor, value); + // Creates the WebContents used by BrowserWindow. auto web_contents = WebContents::Create(isolate, web_preferences); web_contents_.Reset(isolate, web_contents.ToV8()); api_web_contents_ = web_contents.get(); // Keep a copy of the options for later use. - mate::Dictionary(isolate, web_contents->GetWrapper(isolate)).Set( + mate::Dictionary(isolate, web_contents->GetWrapper()).Set( "browserWindowOptions", options); // Creates BrowserWindow. @@ -283,7 +287,7 @@ void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) { #endif // static -mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Arguments* args) { +mate::WrappableBase* Window::New(v8::Isolate* isolate, mate::Arguments* args) { if (!Browser::Get()->is_ready()) { isolate->ThrowException(v8::Exception::Error(mate::StringToV8( isolate, "Cannot create BrowserWindow before app is ready"))); @@ -436,6 +440,10 @@ std::vector Window::GetMaximumSize() { return result; } +void Window::SetSheetOffset(double offset) { + window_->SetSheetOffset(offset); +} + void Window::SetResizable(bool resizable) { window_->SetResizable(resizable); } @@ -742,6 +750,7 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("getMinimumSize", &Window::GetMinimumSize) .SetMethod("setMaximumSize", &Window::SetMaximumSize) .SetMethod("getMaximumSize", &Window::GetMaximumSize) + .SetMethod("setSheetOffset", &Window::SetSheetOffset) .SetMethod("setResizable", &Window::SetResizable) .SetMethod("isResizable", &Window::IsResizable) .SetMethod("setMovable", &Window::SetMovable) @@ -808,7 +817,7 @@ v8::Local Window::From(v8::Isolate* isolate, NativeWindow* native_window) { auto existing = TrackableObject::FromWrappedClass(isolate, native_window); if (existing) - return existing->GetWrapper(isolate); + return existing->GetWrapper(); else return v8::Null(isolate); } diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index d26ff5b36748..a00e063d99f8 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -38,7 +38,7 @@ class WebContents; class Window : public mate::TrackableObject, public NativeWindowObserver { public: - static mate::Wrappable* New(v8::Isolate* isolate, mate::Arguments* args); + static mate::WrappableBase* New(v8::Isolate* isolate, mate::Arguments* args); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); @@ -51,7 +51,7 @@ class Window : public mate::TrackableObject, protected: Window(v8::Isolate* isolate, const mate::Dictionary& options); - virtual ~Window(); + ~Window() override; // NativeWindowObserver: void WillCloseWindow(bool* prevent_default) override; @@ -110,6 +110,7 @@ class Window : public mate::TrackableObject, std::vector GetMinimumSize(); void SetMaximumSize(int width, int height); std::vector GetMaximumSize(); + void SetSheetOffset(double offset); void SetResizable(bool resizable); bool IsResizable(); void SetMovable(bool movable); diff --git a/atom/browser/api/event.cc b/atom/browser/api/event.cc index 5c87292ea52e..f456cf2758bb 100644 --- a/atom/browser/api/event.cc +++ b/atom/browser/api/event.cc @@ -11,31 +11,15 @@ namespace mate { -namespace { - -v8::Persistent template_; - -} // namespace - -Event::Event() +Event::Event(v8::Isolate* isolate) : sender_(NULL), message_(NULL) { + Init(isolate); } Event::~Event() { } -ObjectTemplateBuilder Event::GetObjectTemplateBuilder(v8::Isolate* isolate) { - if (template_.IsEmpty()) - template_.Reset(isolate, ObjectTemplateBuilder(isolate) - .SetMethod("preventDefault", &Event::PreventDefault) - .SetMethod("sendReply", &Event::SendReply) - .Build()); - - return ObjectTemplateBuilder( - isolate, v8::Local::New(isolate, template_)); -} - void Event::SetSenderAndMessage(content::WebContents* sender, IPC::Message* message) { DCHECK(!sender_); @@ -52,7 +36,7 @@ void Event::WebContentsDestroyed() { } void Event::PreventDefault(v8::Isolate* isolate) { - GetWrapper(isolate)->Set(StringToV8(isolate, "defaultPrevented"), + GetWrapper()->Set(StringToV8(isolate, "defaultPrevented"), v8::True(isolate)); } @@ -66,7 +50,15 @@ bool Event::SendReply(const base::string16& json) { // static Handle Event::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new Event); + return mate::CreateHandle(isolate, new Event(isolate)); +} + +// static +void Event::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("preventDefault", &Event::PreventDefault) + .SetMethod("sendReply", &Event::SendReply); } } // namespace mate diff --git a/atom/browser/api/event.h b/atom/browser/api/event.h index 5cdc08324b72..81db638a0dc2 100644 --- a/atom/browser/api/event.h +++ b/atom/browser/api/event.h @@ -15,11 +15,14 @@ class Message; namespace mate { -class Event : public Wrappable, +class Event : public Wrappable, public content::WebContentsObserver { public: static Handle Create(v8::Isolate* isolate); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + // Pass the sender and message to be replied. void SetSenderAndMessage(content::WebContents* sender, IPC::Message* message); @@ -30,11 +33,8 @@ class Event : public Wrappable, bool SendReply(const base::string16& json); protected: - Event(); - virtual ~Event(); - - // Wrappable implementations: - ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) override; + explicit Event(v8::Isolate* isolate); + ~Event() override; // content::WebContentsObserver implementations: void WebContentsDestroyed() override; diff --git a/atom/browser/api/event_emitter.cc b/atom/browser/api/event_emitter.cc index be7018dafa44..7e392fddee34 100644 --- a/atom/browser/api/event_emitter.cc +++ b/atom/browser/api/event_emitter.cc @@ -34,11 +34,13 @@ v8::Local CreateEventObject(v8::Isolate* isolate) { } // namespace -EventEmitter::EventEmitter() { -} +namespace internal { -v8::Local EventEmitter::CreateJSEvent( - v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) { +v8::Local CreateJSEvent( + v8::Isolate* isolate, + v8::Local object, + content::WebContents* sender, + IPC::Message* message) { v8::Local event; bool use_native_event = sender && message; @@ -49,16 +51,20 @@ v8::Local EventEmitter::CreateJSEvent( } else { event = CreateEventObject(isolate); } - mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate)); + mate::Dictionary(isolate, event).Set("sender", object); return event; } -v8::Local EventEmitter::CreateCustomEvent( - v8::Isolate* isolate, v8::Local custom_event) { +v8::Local CreateCustomEvent( + v8::Isolate* isolate, + v8::Local object, + v8::Local custom_event) { v8::Local event = CreateEventObject(isolate); (void)event->SetPrototype(custom_event->CreationContext(), custom_event); - mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate)); + mate::Dictionary(isolate, event).Set("sender", object); return event; } +} // namespace internal + } // namespace mate diff --git a/atom/browser/api/event_emitter.h b/atom/browser/api/event_emitter.h index 42816d42a45b..99f6ed46e48f 100644 --- a/atom/browser/api/event_emitter.h +++ b/atom/browser/api/event_emitter.h @@ -20,17 +20,38 @@ class Message; namespace mate { +namespace internal { + +v8::Local CreateJSEvent(v8::Isolate* isolate, + v8::Local object, + content::WebContents* sender, + IPC::Message* message); +v8::Local CreateCustomEvent( + v8::Isolate* isolate, + v8::Local object, + v8::Local event); + +} // namespace internal + // Provide helperers to emit event in JavaScript. -class EventEmitter : public Wrappable { +template +class EventEmitter : public Wrappable { public: typedef std::vector> ValueArray; + // Make the convinient methods visible: + // https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members + v8::Local GetWrapper() { return Wrappable::GetWrapper(); } + v8::Isolate* isolate() const { return Wrappable::isolate(); } + // this.emit(name, event, args...); template bool EmitCustomEvent(const base::StringPiece& name, v8::Local event, const Args&... args) { - return EmitWithEvent(name, CreateCustomEvent(isolate(), event), args...); + return EmitWithEvent( + name, + internal::CreateCustomEvent(isolate(), GetWrapper(), event), args...); } // this.emit(name, new Event(), args...); @@ -47,12 +68,13 @@ class EventEmitter : public Wrappable { const Args&... args) { v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - v8::Local event = CreateJSEvent(isolate(), sender, message); + v8::Local event = internal::CreateJSEvent( + isolate(), GetWrapper(), sender, message); return EmitWithEvent(name, event, args...); } protected: - EventEmitter(); + EventEmitter() {} private: // this.emit(name, event, args...); @@ -62,17 +84,11 @@ class EventEmitter : public Wrappable { const Args&... args) { v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...); + EmitEvent(isolate(), GetWrapper(), name, event, args...); return event->Get( StringToV8(isolate(), "defaultPrevented"))->BooleanValue(); } - v8::Local CreateJSEvent(v8::Isolate* isolate, - content::WebContents* sender, - IPC::Message* message); - v8::Local CreateCustomEvent( - v8::Isolate* isolate, v8::Local event); - DISALLOW_COPY_AND_ASSIGN(EventEmitter); }; diff --git a/atom/browser/api/save_page_handler.cc b/atom/browser/api/save_page_handler.cc index 1e5bc094cf63..e07ec3ac0abb 100644 --- a/atom/browser/api/save_page_handler.cc +++ b/atom/browser/api/save_page_handler.cc @@ -73,11 +73,6 @@ void SavePageHandler::Destroy(content::DownloadItem* item) { delete this; } -// static -bool SavePageHandler::IsSavePageTypes(const std::string& type) { - return type == "multipart/related" || type == "text/html"; -} - } // namespace api } // namespace atom diff --git a/atom/browser/api/save_page_handler.h b/atom/browser/api/save_page_handler.h index dd1692a8badc..951a9414e03f 100644 --- a/atom/browser/api/save_page_handler.h +++ b/atom/browser/api/save_page_handler.h @@ -37,8 +37,6 @@ class SavePageHandler : public content::DownloadManager::Observer, bool Handle(const base::FilePath& full_path, const content::SavePageType& save_type); - static bool IsSavePageTypes(const std::string& type); - private: void Destroy(content::DownloadItem* item); diff --git a/atom/browser/api/trackable_object.cc b/atom/browser/api/trackable_object.cc index 77a936cde02c..5148df627c8d 100644 --- a/atom/browser/api/trackable_object.cc +++ b/atom/browser/api/trackable_object.cc @@ -37,15 +37,6 @@ TrackableObjectBase::~TrackableObjectBase() { cleanup_.Run(); } -void TrackableObjectBase::AfterInit(v8::Isolate* isolate) { - if (wrapped_) - AttachAsUserData(wrapped_); -} - -void TrackableObjectBase::MarkDestroyed() { - GetWrapper(isolate())->SetAlignedPointerInInternalField(0, nullptr); -} - base::Closure TrackableObjectBase::GetDestroyClosure() { return base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr()); } diff --git a/atom/browser/api/trackable_object.h b/atom/browser/api/trackable_object.h index 7c4ed03fe052..1c71d84e42c9 100644 --- a/atom/browser/api/trackable_object.h +++ b/atom/browser/api/trackable_object.h @@ -21,7 +21,7 @@ class SupportsUserData; namespace mate { // Users should use TrackableObject instead. -class TrackableObjectBase : public mate::EventEmitter { +class TrackableObjectBase { public: TrackableObjectBase(); @@ -32,13 +32,7 @@ class TrackableObjectBase : public mate::EventEmitter { void AttachAsUserData(base::SupportsUserData* wrapped); protected: - ~TrackableObjectBase() override; - - // mate::Wrappable: - void AfterInit(v8::Isolate* isolate) override; - - // Mark the JS object as destroyed. - void MarkDestroyed(); + virtual ~TrackableObjectBase(); // Returns a closure that can destroy the native class. base::Closure GetDestroyClosure(); @@ -65,8 +59,14 @@ class TrackableObjectBase : public mate::EventEmitter { // All instances of TrackableObject will be kept in a weak map and can be got // from its ID. template -class TrackableObject : public TrackableObjectBase { +class TrackableObject : public TrackableObjectBase, + public mate::EventEmitter { public: + // Mark the JS object as destroyed. + void MarkDestroyed() { + Wrappable::GetWrapper()->SetAlignedPointerInInternalField(0, nullptr); + } + // Finds out the TrackableObject from its ID in weak map. static T* FromWeakMapID(v8::Isolate* isolate, int32_t id) { if (!weak_map_) @@ -106,6 +106,7 @@ class TrackableObject : public TrackableObjectBase { protected: TrackableObject() {} + ~TrackableObject() override { RemoveFromWeakMap(); } @@ -113,41 +114,18 @@ class TrackableObject : public TrackableObjectBase { void AfterInit(v8::Isolate* isolate) override { if (!weak_map_) { weak_map_.reset(new atom::IDWeakMap); - RegisterDestructionCallback( - base::Bind(&TrackableObject::ReleaseAllWeakReferences)); } - weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate)); - TrackableObjectBase::AfterInit(isolate); + weak_map_id_ = weak_map_->Add(isolate, Wrappable::GetWrapper()); + if (wrapped_) + AttachAsUserData(wrapped_); } private: - // mate::Wrappable: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override { - if (template_.IsEmpty()) { - auto templ = v8::ObjectTemplate::New(isolate); - T::BuildPrototype(isolate, templ); - template_.Reset(isolate, templ); - } - - return ObjectTemplateBuilder( - isolate, v8::Local::New(isolate, template_)); - } - - // Releases all weak references in weak map, called when app is terminating. - static void ReleaseAllWeakReferences() { - weak_map_.reset(); - } - - static v8::Persistent template_; static scoped_ptr weak_map_; DISALLOW_COPY_AND_ASSIGN(TrackableObject); }; -template -v8::Persistent TrackableObject::template_; - template scoped_ptr TrackableObject::weak_map_; diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 9a59c3f9d412..f4add58e3a89 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -37,7 +37,6 @@ #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/common/web_preferences.h" -#include "net/cert/x509_certificate.h" #include "net/ssl/ssl_cert_request_info.h" #include "ppapi/host/ppapi_host.h" #include "ui/base/l10n/l10n_util.h" @@ -55,26 +54,6 @@ std::string g_custom_schemes = ""; // Custom schemes to be registered to handle service worker. std::string g_custom_service_worker_schemes = ""; -scoped_refptr ImportCertFromFile( - const base::FilePath& path) { - if (path.empty()) - return nullptr; - - std::string cert_data; - if (!base::ReadFileToString(path, &cert_data)) - return nullptr; - - net::CertificateList certs = - net::X509Certificate::CreateCertificateListFromBytes( - cert_data.data(), cert_data.size(), - net::X509Certificate::FORMAT_AUTO); - - if (certs.empty()) - return nullptr; - - return certs[0]; -} - } // namespace // static @@ -242,16 +221,6 @@ void AtomBrowserClient::SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, scoped_ptr delegate) { - // --client-certificate=`path` - auto cmd = base::CommandLine::ForCurrentProcess(); - if (cmd->HasSwitch(switches::kClientCertificate)) { - auto cert_path = cmd->GetSwitchValuePath(switches::kClientCertificate); - auto certificate = ImportCertFromFile(cert_path); - if (certificate.get()) - delegate->ContinueWithCertificate(certificate.get()); - return; - } - if (!cert_request_info->client_certs.empty() && delegate_) { delegate_->SelectClientCertificate( web_contents, cert_request_info, std::move(delegate)); diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index d6724ff53384..b06c6278f53f 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -65,7 +65,7 @@ std::string RemoveWhitespace(const std::string& str) { AtomBrowserContext::AtomBrowserContext(const std::string& partition, bool in_memory) : brightray::BrowserContext(partition, in_memory), - cert_verifier_(nullptr), + cert_verifier_(new AtomCertVerifier), job_factory_(new AtomURLRequestJobFactory), network_delegate_(new AtomNetworkDelegate), allow_ntlm_everywhere_(false) { @@ -178,8 +178,6 @@ content::PermissionManager* AtomBrowserContext::GetPermissionManager() { } scoped_ptr AtomBrowserContext::CreateCertVerifier() { - DCHECK(!cert_verifier_); - cert_verifier_ = new AtomCertVerifier; return make_scoped_ptr(cert_verifier_); } diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index f45f6492a849..335e0576fcbc 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -49,7 +49,7 @@ AtomBrowserMainParts::~AtomBrowserMainParts() { // 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 - // about this can be found at https://github.com/atom/electron/issues/4767. + // about this can be found at https://github.com/electron/electron/issues/4767. // On the other handle there is actually no need to gracefully shutdown V8 // on exit in the main process, we already ensured all necessary resources get // cleaned up, and it would make quitting faster. @@ -136,9 +136,8 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() { // Start idle gc. gc_timer_.Start( FROM_HERE, base::TimeDelta::FromMinutes(1), - base::Bind(base::IgnoreResult(&v8::Isolate::IdleNotification), - base::Unretained(js_env_->isolate()), - 1000)); + base::Bind(&v8::Isolate::LowMemoryNotification, + base::Unretained(js_env_->isolate()))); brightray::BrowserMainParts::PreMainMessageLoopRun(); bridge_task_runner_->MessageLoopIsReady(); diff --git a/atom/browser/atom_download_manager_delegate.cc b/atom/browser/atom_download_manager_delegate.cc index 16c0cf708b85..295747a33c4e 100644 --- a/atom/browser/atom_download_manager_delegate.cc +++ b/atom/browser/atom_download_manager_delegate.cc @@ -70,7 +70,9 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated( return; NativeWindow* window = nullptr; - auto relay = NativeWindowRelay::FromWebContents(item->GetWebContents()); + content::WebContents* web_contents = item->GetWebContents(); + auto relay = web_contents ? NativeWindowRelay::FromWebContents(web_contents) + : nullptr; if (relay) window = relay->window.get(); diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc index 68576a52f248..59ac258ea13a 100644 --- a/atom/browser/atom_resource_dispatcher_host_delegate.cc +++ b/atom/browser/atom_resource_dispatcher_host_delegate.cc @@ -5,6 +5,7 @@ #include "atom/browser/atom_resource_dispatcher_host_delegate.h" #include "atom/browser/login_handler.h" +#include "atom/browser/web_contents_permission_helper.h" #include "atom/common/platform_util.h" #include "content/public/browser/browser_thread.h" #include "net/base/escape.h" @@ -14,20 +15,46 @@ using content::BrowserThread; namespace atom { +namespace { + +void OnOpenExternal(const GURL& escaped_url, + bool allowed) { + if (allowed) + platform_util::OpenExternal(escaped_url, true); +} + +void HandleExternalProtocolInUI( + const GURL& url, + const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, + bool has_user_gesture) { + content::WebContents* web_contents = web_contents_getter.Run(); + if (!web_contents) + return; + + GURL escaped_url(net::EscapeExternalHandlerValue(url.spec())); + auto callback = base::Bind(&OnOpenExternal, escaped_url); + auto permission_helper = + WebContentsPermissionHelper::FromWebContents(web_contents); + permission_helper->RequestOpenExternalPermission(callback, has_user_gesture); +} + +} // namespace + AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() { } bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol( const GURL& url, int child_id, - const content::ResourceRequestInfo::WebContentsGetter&, + const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, bool is_main_frame, ui::PageTransition transition, bool has_user_gesture) { - GURL escaped_url(net::EscapeExternalHandlerValue(url.spec())); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind( - base::IgnoreResult(platform_util::OpenExternal), escaped_url, true)); + base::Bind(&HandleExternalProtocolInUI, + url, + web_contents_getter, + has_user_gesture)); return true; } diff --git a/atom/browser/atom_security_state_model_client.cc b/atom/browser/atom_security_state_model_client.cc new file mode 100644 index 000000000000..911849c5c2d1 --- /dev/null +++ b/atom/browser/atom_security_state_model_client.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2016 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_security_state_model_client.h" + +#include "content/public/browser/cert_store.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/origin_util.h" +#include "content/public/common/ssl_status.h" +#include "net/cert/x509_certificate.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::AtomSecurityStateModelClient); + +using security_state::SecurityStateModel; + +namespace atom { + +namespace { + +SecurityStateModel::SecurityLevel GetSecurityLevelForSecurityStyle( + content::SecurityStyle style) { + switch (style) { + case content::SECURITY_STYLE_UNKNOWN: + return SecurityStateModel::NONE; + case content::SECURITY_STYLE_UNAUTHENTICATED: + return SecurityStateModel::NONE; + case content::SECURITY_STYLE_AUTHENTICATION_BROKEN: + return SecurityStateModel::SECURITY_ERROR; + case content::SECURITY_STYLE_WARNING: + return SecurityStateModel::SECURITY_WARNING; + case content::SECURITY_STYLE_AUTHENTICATED: + return SecurityStateModel::SECURE; + } + return SecurityStateModel::NONE; +} + +} // namespace + +AtomSecurityStateModelClient::AtomSecurityStateModelClient( + content::WebContents* web_contents) + : web_contents_(web_contents), + security_state_model_(new SecurityStateModel()) { + security_state_model_->SetClient(this); +} + +AtomSecurityStateModelClient::~AtomSecurityStateModelClient() { +} + +const SecurityStateModel::SecurityInfo& +AtomSecurityStateModelClient::GetSecurityInfo() const { + return security_state_model_->GetSecurityInfo(); +} + +bool AtomSecurityStateModelClient::RetrieveCert( + scoped_refptr* cert) { + content::NavigationEntry* entry = + web_contents_->GetController().GetVisibleEntry(); + if (!entry) + return false; + return content::CertStore::GetInstance()->RetrieveCert( + entry->GetSSL().cert_id, cert); +} + +bool AtomSecurityStateModelClient::UsedPolicyInstalledCertificate() { + return false; +} + +bool AtomSecurityStateModelClient::IsOriginSecure(const GURL& url) { + return content::IsOriginSecure(url); +} + +void AtomSecurityStateModelClient::GetVisibleSecurityState( + SecurityStateModel::VisibleSecurityState* state) { + content::NavigationEntry* entry = + web_contents_->GetController().GetVisibleEntry(); + if (!entry || + entry->GetSSL().security_style == content::SECURITY_STYLE_UNKNOWN) { + *state = SecurityStateModel::VisibleSecurityState(); + return; + } + + state->initialized = true; + state->url = entry->GetURL(); + const content::SSLStatus& ssl = entry->GetSSL(); + state->initial_security_level = + GetSecurityLevelForSecurityStyle(ssl.security_style); + state->cert_id = ssl.cert_id; + state->cert_status = ssl.cert_status; + state->connection_status = ssl.connection_status; + state->security_bits = ssl.security_bits; + state->sct_verify_statuses.clear(); + for (const auto& sct : ssl.signed_certificate_timestamp_ids) + state->sct_verify_statuses.push_back(sct.status); + state->displayed_mixed_content = + (ssl.content_status & content::SSLStatus::DISPLAYED_INSECURE_CONTENT) + ? true + : false; + state->ran_mixed_content = + (ssl.content_status & content::SSLStatus::RAN_INSECURE_CONTENT) ? true + : false; +} + +} // namespace atom diff --git a/atom/browser/atom_security_state_model_client.h b/atom/browser/atom_security_state_model_client.h new file mode 100644 index 000000000000..cc943eb7f949 --- /dev/null +++ b/atom/browser/atom_security_state_model_client.h @@ -0,0 +1,42 @@ +// Copyright (c) 2016 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_SECURITY_STATE_MODEL_CLIENT_H_ +#define ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ + +#include "components/security_state/security_state_model.h" +#include "components/security_state/security_state_model_client.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace atom { + +class AtomSecurityStateModelClient + : public security_state::SecurityStateModelClient, + public content::WebContentsUserData { + public: + ~AtomSecurityStateModelClient() override; + + const security_state::SecurityStateModel::SecurityInfo& + GetSecurityInfo() const; + + // security_state::SecurityStateModelClient: + void GetVisibleSecurityState( + security_state::SecurityStateModel::VisibleSecurityState* state) override; + bool RetrieveCert(scoped_refptr* cert) override; + bool UsedPolicyInstalledCertificate() override; + bool IsOriginSecure(const GURL& url) override; + + private: + explicit AtomSecurityStateModelClient(content::WebContents* web_contents); + friend class content::WebContentsUserData; + + content::WebContents* web_contents_; + scoped_ptr security_state_model_; + + DISALLOW_COPY_AND_ASSIGN(AtomSecurityStateModelClient); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ diff --git a/atom/browser/auto_updater_mac.mm b/atom/browser/auto_updater_mac.mm index a55cdd281265..9af920f59299 100644 --- a/atom/browser/auto_updater_mac.mm +++ b/atom/browser/auto_updater_mac.mm @@ -22,6 +22,12 @@ SQRLUpdater* g_updater = nil; } // namespace +namespace { + +bool g_update_available = false; + +} + // static void AutoUpdater::SetFeedURL(const std::string& feed) { if (g_updater == nil) { @@ -69,6 +75,7 @@ void AutoUpdater::CheckForUpdates() { take:1] subscribeNext:^(SQRLDownloadedUpdate *downloadedUpdate) { if (downloadedUpdate) { + g_update_available = true; SQRLUpdate* update = downloadedUpdate.update; // There is a new update that has been downloaded. delegate->OnUpdateDownloaded( @@ -77,6 +84,7 @@ void AutoUpdater::CheckForUpdates() { base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970), base::SysNSStringToUTF8(update.updateURL.absoluteString)); } else { + g_update_available = false; // When the completed event is sent with no update, then we know there // is no update available. delegate->OnUpdateNotAvailable(); @@ -89,11 +97,16 @@ void AutoUpdater::CheckForUpdates() { } void AutoUpdater::QuitAndInstall() { - [[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) { - Delegate* delegate = AutoUpdater::GetDelegate(); + Delegate* delegate = AutoUpdater::GetDelegate(); + if (g_update_available) { + [[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) { + if (delegate) + delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription)); + }]; + } else { if (delegate) - delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription)); - }]; + delegate->OnError("No update available, can't quit and install"); + } } } // namespace auto_updater diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index e89f52283b3c..093209ef7c47 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -9,12 +9,16 @@ #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/native_window.h" #include "atom/browser/window_list.h" +#include "base/files/file_util.h" #include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "brightray/browser/brightray_paths.h" namespace atom { Browser::Browser() : is_quiting_(false), + is_exiting_(false), is_ready_(false), is_shutdown_(false) { WindowList::AddObserver(this); @@ -49,9 +53,12 @@ void Browser::Exit(int code) { // Message loop is not ready, quit directly. exit(code); } else { - // Prepare to quit when all windows have been closed.. + // Prepare to quit when all windows have been closed. is_quiting_ = true; + // Remember this caller so that we don't emit unrelated events. + 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) { @@ -135,6 +142,11 @@ void Browser::WillFinishLaunching() { } void Browser::DidFinishLaunching() { + // Make sure the userData directory is created. + base::FilePath user_data; + if (PathService::Get(brightray::DIR_USER_DATA, &user_data)) + base::CreateDirectoryAndGetError(user_data, nullptr); + is_ready_ = true; FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching()); } @@ -175,14 +187,12 @@ void Browser::OnWindowCloseCancelled(NativeWindow* window) { } void Browser::OnWindowAllClosed() { - if (is_quiting_) + if (is_exiting_) + Shutdown(); + else if (is_quiting_) NotifyAndShutdown(); else FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWindowAllClosed()); } -void Browser::PlatformThemeChanged() { - FOR_EACH_OBSERVER(BrowserObserver, observers_, OnPlatformThemeChanged()); -} - } // namespace atom diff --git a/atom/browser/browser.h b/atom/browser/browser.h index 634e14e60262..8329b14bc2c4 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -82,6 +82,9 @@ class Browser : public WindowListObserver { // Set as default handler for a protocol. bool SetAsDefaultProtocolClient(const std::string& protocol); + // Query the current state of default handler for a protocol. + bool IsDefaultProtocolClient(const std::string& protocol); + #if defined(OS_MACOSX) // Hide the application. void Hide(); @@ -89,9 +92,6 @@ class Browser : public WindowListObserver { // Show the application. void Show(); - // Check if the system is in Dark Mode. - bool IsDarkMode(); - // Bounce the dock icon. enum BounceType { BOUNCE_CRITICAL = 0, @@ -151,9 +151,6 @@ class Browser : public WindowListObserver { // Request basic auth login. void RequestLogin(LoginHandler* login_handler); - // Tell the application that plaform's theme changed. - void PlatformThemeChanged(); - void AddObserver(BrowserObserver* obs) { observers_.AddObserver(obs); } @@ -189,10 +186,13 @@ class Browser : public WindowListObserver { // Observers of the browser. base::ObserverList observers_; + // Whether `app.exit()` has been called + bool is_exiting_; + // Whether "ready" event has been emitted. bool is_ready_; - // The browse is being shutdown. + // The browser is being shutdown. bool is_shutdown_; std::string version_override_; diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc index 6c7d4abaf645..d994bb4109bb 100644 --- a/atom/browser/browser_linux.cc +++ b/atom/browser/browser_linux.cc @@ -42,6 +42,10 @@ bool Browser::SetAsDefaultProtocolClient(const std::string& protocol) { return false; } +bool Browser::IsDefaultProtocolClient(const std::string& protocol) { + return false; +} + std::string Browser::GetExecutableFileVersion() const { return brightray::GetApplicationVersion(); } diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 0294894fcd61..c10369a2e7af 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -27,11 +27,6 @@ void Browser::Show() { [[AtomApplication sharedApplication] unhide:nil]; } -bool Browser::IsDarkMode() { - NSString *mode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"]; - return [mode isEqualToString: @"Dark"]; -} - void Browser::AddRecentDocument(const base::FilePath& path) { NSString* path_string = base::mac::FilePathToNSString(path); if (!path_string) @@ -65,6 +60,30 @@ bool Browser::SetAsDefaultProtocolClient(const std::string& protocol) { return return_code == noErr; } +bool Browser::IsDefaultProtocolClient(const std::string& protocol) { + if (protocol.empty()) + return false; + + NSString* identifier = [base::mac::MainBundle() bundleIdentifier]; + if (!identifier) + return false; + + NSString* protocol_ns = [NSString stringWithUTF8String:protocol.c_str()]; + + CFStringRef bundle = + LSCopyDefaultHandlerForURLScheme(base::mac::NSToCFCast(protocol_ns)); + NSString* bundleId = static_cast( + base::mac::CFTypeRefToNSObjectAutorelease(bundle)); + if (!bundleId) + return false; + + // Ensure the comparison is case-insensitive + // as LS does not persist the case of the bundle id. + NSComparisonResult result = + [bundleId caseInsensitiveCompare:identifier]; + return result == NSOrderedSame; +} + void Browser::SetAppUserModelID(const base::string16& name) { } diff --git a/atom/browser/browser_observer.h b/atom/browser/browser_observer.h index da327eb90a02..f6d76bc13fb3 100644 --- a/atom/browser/browser_observer.h +++ b/atom/browser/browser_observer.h @@ -45,8 +45,6 @@ class BrowserObserver { // The browser requests HTTP login. virtual void OnLogin(LoginHandler* login_handler) {} - virtual void OnPlatformThemeChanged() {} - protected: virtual ~BrowserObserver() {} }; diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 9531406f8cd4..7b1402ba2d2c 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -225,6 +225,50 @@ bool Browser::SetAsDefaultProtocolClient(const std::string& protocol) { return true; } +bool Browser::IsDefaultProtocolClient(const std::string& protocol) { + if (protocol.empty()) + return false; + + base::FilePath path; + if (!PathService::Get(base::FILE_EXE, &path)) { + LOG(ERROR) << "Error getting app exe path"; + return false; + } + + // Main Registry Key + HKEY root = HKEY_CURRENT_USER; + std::string keyPathStr = "Software\\Classes\\" + protocol; + std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end()); + + // Command Key + std::string cmdPathStr = keyPathStr + "\\shell\\open\\command"; + std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end()); + + base::win::RegKey key; + base::win::RegKey commandKey; + if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS))) + // Key doesn't exist, we can confirm that it is not set + return false; + + if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS))) + // Key doesn't exist, we can confirm that it is not set + return false; + + std::wstring keyVal; + if (FAILED(commandKey.ReadValue(L"", &keyVal))) + // Default value not set, we can confirm that it is not set + return false; + + std::wstring exePath(path.value()); + std::wstring exe = L"\"" + exePath + L"\" \"%1\""; + if (keyVal == exe) { + // Default value is the same as current file path + return true; + } else { + return false; + } +} + PCWSTR Browser::GetAppUserModelID() { if (app_user_model_id_.empty()) { SetAppUserModelID(base::ReplaceStringPlaceholders( diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 62e854ac5655..4bebf7480b89 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -10,9 +10,11 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_javascript_dialog_manager.h" +#include "atom/browser/atom_security_state_model_client.h" #include "atom/browser/native_window.h" #include "atom/browser/ui/file_dialog.h" #include "atom/browser/web_dialog_helper.h" +#include "atom/common/atom_constants.h" #include "base/files/file_util.h" #include "base/prefs/pref_service.h" #include "base/prefs/scoped_user_pref_update.h" @@ -25,6 +27,8 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" +#include "content/public/browser/security_style_explanation.h" +#include "content/public/browser/security_style_explanations.h" #include "storage/browser/fileapi/isolated_context.h" #if defined(TOOLKIT_VIEWS) @@ -36,6 +40,7 @@ #endif using content::BrowserThread; +using security_state::SecurityStateModel; namespace atom { @@ -140,6 +145,24 @@ std::set GetAddedFileSystemPaths( return result; } +content::SecurityStyle SecurityLevelToSecurityStyle( + SecurityStateModel::SecurityLevel security_level) { + switch (security_level) { + case SecurityStateModel::NONE: + return content::SECURITY_STYLE_UNAUTHENTICATED; + case SecurityStateModel::SECURITY_WARNING: + case SecurityStateModel::SECURITY_POLICY_WARNING: + return content::SECURITY_STYLE_WARNING; + case SecurityStateModel::EV_SECURE: + case SecurityStateModel::SECURE: + return content::SECURITY_STYLE_AUTHENTICATED; + case SecurityStateModel::SECURITY_ERROR: + return content::SECURITY_STYLE_AUTHENTICATION_BROKEN; + } + + return content::SECURITY_STYLE_UNKNOWN; +} + } // namespace CommonWebContentsDelegate::CommonWebContentsDelegate() @@ -265,6 +288,90 @@ bool CommonWebContentsDelegate::IsFullscreenForTabOrPending( return html_fullscreen_; } +content::SecurityStyle CommonWebContentsDelegate::GetSecurityStyle( + content::WebContents* web_contents, + content::SecurityStyleExplanations* explanations) { + auto model_client = + AtomSecurityStateModelClient::FromWebContents(web_contents); + + const SecurityStateModel::SecurityInfo& security_info = + model_client->GetSecurityInfo(); + + const content::SecurityStyle security_style = + SecurityLevelToSecurityStyle(security_info.security_level); + + explanations->ran_insecure_content_style = + SecurityLevelToSecurityStyle( + SecurityStateModel::kRanInsecureContentLevel); + explanations->displayed_insecure_content_style = + SecurityLevelToSecurityStyle( + SecurityStateModel::kDisplayedInsecureContentLevel); + + explanations->scheme_is_cryptographic = security_info.scheme_is_cryptographic; + if (!security_info.scheme_is_cryptographic) + return security_style; + + if (security_info.sha1_deprecation_status == + SecurityStateModel::DEPRECATED_SHA1_MAJOR) { + explanations->broken_explanations.push_back( + content::SecurityStyleExplanation( + kSHA1Certificate, + kSHA1MajorDescription, + security_info.cert_id)); + } else if (security_info.sha1_deprecation_status == + SecurityStateModel::DEPRECATED_SHA1_MINOR) { + explanations->unauthenticated_explanations.push_back( + content::SecurityStyleExplanation( + kSHA1Certificate, + kSHA1MinorDescription, + security_info.cert_id)); + } + + explanations->ran_insecure_content = + security_info.mixed_content_status == + SecurityStateModel::RAN_MIXED_CONTENT || + security_info.mixed_content_status == + SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT; + explanations->displayed_insecure_content = + security_info.mixed_content_status == + SecurityStateModel::DISPLAYED_MIXED_CONTENT || + security_info.mixed_content_status == + SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT; + + if (net::IsCertStatusError(security_info.cert_status)) { + std::string error_string = net::ErrorToString( + net::MapCertStatusToNetError(security_info.cert_status)); + + content::SecurityStyleExplanation explanation( + kCertificateError, + "There are issues with the site's certificate chain " + error_string, + security_info.cert_id); + + if (net::IsCertStatusMinorError(security_info.cert_status)) + explanations->unauthenticated_explanations.push_back(explanation); + else + explanations->broken_explanations.push_back(explanation); + } else { + if (security_info.sha1_deprecation_status == + SecurityStateModel::NO_DEPRECATED_SHA1) { + explanations->secure_explanations.push_back( + content::SecurityStyleExplanation( + kValidCertificate, + kValidCertificateDescription, + security_info.cert_id)); + } + } + + if (security_info.is_secure_protocol_and_ciphersuite) { + explanations->secure_explanations.push_back( + content::SecurityStyleExplanation( + kSecureProtocol, + kSecureProtocolDescription)); + } + + return security_style; +} + void CommonWebContentsDelegate::DevToolsSaveToFile( const std::string& url, const std::string& content, bool save_as) { base::FilePath path; diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h index 61ff63793df5..699d00e18bce 100644 --- a/atom/browser/common_web_contents_delegate.h +++ b/atom/browser/common_web_contents_delegate.h @@ -76,6 +76,9 @@ class CommonWebContentsDelegate void ExitFullscreenModeForTab(content::WebContents* source) override; bool IsFullscreenForTabOrPending( const content::WebContents* source) const override; + content::SecurityStyle GetSecurityStyle( + content::WebContents* web_contents, + content::SecurityStyleExplanations* explanations) override; // brightray::InspectableWebContentsDelegate: void DevToolsSaveToFile(const std::string& url, diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index f4db929bf575..7662162ab618 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -24,9 +24,6 @@ // Don't add the "Enter Full Screen" menu item automatically. [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; - // Add observer to monitor the system's Dark Mode theme. - [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(platformThemeChanged:) name:@"AppleInterfaceThemeChangedNotification" object:nil]; - atom::Browser::Get()->WillFinishLaunching(); } @@ -62,8 +59,4 @@ return flag; } -- (void)platformThemeChanged:(NSNotification *)notify { - atom::Browser::Get()->PlatformThemeChanged(); -} - @end diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 2627c704d21f..2379bdd053c5 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -54,6 +54,7 @@ NativeWindow::NativeWindow( enable_larger_than_screen_(false), is_closed_(false), has_dialog_attached_(false), + sheet_offset_(0.0), aspect_ratio_(0.0), inspectable_web_contents_(inspectable_web_contents), weak_factory_(this) { @@ -162,6 +163,9 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { std::string color; if (options.Get(options::kBackgroundColor, &color)) { SetBackgroundColor(color); + } else if (!transparent()) { + // For normal window, use white as default background. + SetBackgroundColor("#FFFF"); } std::string title("Electron"); options.Get(options::kTitle, &title); @@ -251,6 +255,14 @@ gfx::Size NativeWindow::GetMaximumSize() { return GetSizeConstraints().GetMaximumSize(); } +void NativeWindow::SetSheetOffset(const double offset) { + sheet_offset_ = offset; +} + +double NativeWindow::GetSheetOffset() { + return sheet_offset_; +} + void NativeWindow::SetRepresentedFilename(const std::string& filename) { } @@ -594,27 +606,4 @@ void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback, callback.Run(bitmap); } -SkColor NativeWindow::ParseHexColor(const std::string& name) { - auto color = name.substr(1); - unsigned length = color.size(); - SkColor result = (length != 8 ? 0xFF000000 : 0x00000000); - unsigned value = 0; - if (length != 3 && length != 6 && length != 8) - return result; - for (unsigned i = 0; i < length; ++i) { - if (!base::IsHexDigit(color[i])) - return result; - value <<= 4; - value |= (color[i] < 'A' ? color[i] - '0' : (color[i] - 'A' + 10) & 0xF); - } - if (length == 6 || length == 8) { - result |= value; - return result; - } - result |= (value & 0xF00) << 12 | (value & 0xF00) << 8 - | (value & 0xF0) << 8 | (value & 0xF0) << 4 - | (value & 0xF) << 4 | (value & 0xF); - return result; -} - } // namespace atom diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 49e1e71d5df6..f3acf6222314 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -123,6 +123,8 @@ class NativeWindow : public base::SupportsUserData, virtual gfx::Size GetMinimumSize(); virtual void SetMaximumSize(const gfx::Size& size); virtual gfx::Size GetMaximumSize(); + virtual void SetSheetOffset(const double offset); + virtual double GetSheetOffset(); virtual void SetResizable(bool resizable) = 0; virtual bool IsResizable() = 0; virtual void SetMovable(bool movable) = 0; @@ -282,9 +284,6 @@ class NativeWindow : public base::SupportsUserData, void BeforeUnloadDialogCancelled() override; bool OnMessageReceived(const IPC::Message& message) override; - // Parse hex color like "#FFF" or "#EFEFEF" - SkColor ParseHexColor(const std::string& name); - private: // Schedule a notification unresponsive event. void ScheduleUnresponsiveEvent(int ms); @@ -329,6 +328,9 @@ class NativeWindow : public base::SupportsUserData, // it should be cancelled when we can prove that the window is responsive. base::CancelableClosure window_unresposive_closure_; + // Used to display sheets at the appropriate vertical offset + double sheet_offset_; + // Used to maintain the aspect ratio of a view which is inside of the // content view. double aspect_ratio_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 2044ee7d7189..04569d8f50f9 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -6,9 +6,11 @@ #include +#include "atom/common/color_util.h" #include "atom/common/draggable_region.h" #include "atom/common/options_switches.h" #include "base/mac/mac_util.h" +#include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents_view.h" @@ -18,6 +20,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "native_mate/dictionary.h" +#include "skia/ext/skia_utils_mac.h" #include "ui/gfx/skia_util.h" namespace { @@ -240,6 +243,13 @@ bool ScopedDisableResize::disable_resize_ = false; return NO; } +- (NSRect)window:(NSWindow*)window + willPositionSheet:(NSWindow*)sheet usingRect:(NSRect)rect { + NSView* view = window.contentView; + rect.origin.y = view.frame.size.height - shell_->GetSheetOffset(); + return rect; +} + @end @interface AtomNSWindow : NSWindow { @@ -592,10 +602,16 @@ bool NativeWindowMac::IsVisible() { } void NativeWindowMac::Maximize() { + if (IsMaximized()) + return; + [window_ zoom:nil]; } void NativeWindowMac::Unmaximize() { + if (!IsMaximized()) + return; + [window_ zoom:nil]; } @@ -804,12 +820,14 @@ bool NativeWindowMac::IsKiosk() { } void NativeWindowMac::SetBackgroundColor(const std::string& color_name) { - SkColor background_color = NativeWindow::ParseHexColor(color_name); - NSColor *color = [NSColor colorWithCalibratedRed:SkColorGetR(background_color) - green:SkColorGetG(background_color) - blue:SkColorGetB(background_color) - alpha:SkColorGetA(background_color)/255.0f]; - [window_ setBackgroundColor:color]; + SkColor color = ParseHexColor(color_name); + base::ScopedCFTypeRef cgcolor = + skia::CGColorCreateFromSkColor(color); + [[[window_ contentView] layer] setBackgroundColor:cgcolor]; + + const auto view = web_contents()->GetRenderWidgetHostView(); + if (view) + view->SetBackgroundColor(color); } void NativeWindowMac::SetHasShadow(bool has_shadow) { diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 15f2046364bb..93e43661302e 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -9,11 +9,13 @@ #include "atom/browser/ui/views/menu_bar.h" #include "atom/browser/ui/views/menu_layout.h" +#include "atom/common/color_util.h" #include "atom/common/draggable_region.h" #include "atom/common/options_switches.h" #include "base/strings/utf_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/native_web_keyboard_event.h" #include "native_mate/dictionary.h" #include "ui/aura/window_tree_host.h" @@ -614,7 +616,7 @@ bool NativeWindowViews::IsKiosk() { void NativeWindowViews::SetBackgroundColor(const std::string& color_name) { // web views' background color. - SkColor background_color = NativeWindow::ParseHexColor(color_name); + SkColor background_color = ParseHexColor(color_name); set_background(views::Background::CreateSolidBackground(background_color)); #if defined(OS_WIN) @@ -779,10 +781,12 @@ void NativeWindowViews::OnWidgetActivationChanged( if (widget != window_.get()) return; - if (active) - NotifyWindowFocus(); - else - NotifyWindowBlur(); + // Post the notification to next tick. + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::Bind(active ? &NativeWindow::NotifyWindowFocus : + &NativeWindow::NotifyWindowBlur, + GetWeakPtr())); if (active && inspectable_web_contents() && !inspectable_web_contents()->IsDevToolsViewShowing()) diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 862cd5458bb6..bcf3ca8bd16f 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -199,6 +199,10 @@ class NativeWindowViews : public NativeWindow, // In charge of running taskbar related APIs. TaskbarHost taskbar_host_; + + // If true we have enabled a11y + bool enabled_a11y_support_; + #endif // Handles unhandled keyboard messages coming back from the renderer process. diff --git a/atom/browser/native_window_views_win.cc b/atom/browser/native_window_views_win.cc index e5ed1975f80f..038ab105222d 100644 --- a/atom/browser/native_window_views_win.cc +++ b/atom/browser/native_window_views_win.cc @@ -84,6 +84,25 @@ bool NativeWindowViews::PreHandleMSG( NotifyWindowMessage(message, w_param, l_param); switch (message) { + // Screen readers send WM_GETOBJECT in order to get the accessibility + // object, so take this opportunity to push Chromium into accessible + // mode if it isn't already, always say we didn't handle the message + // because we still want Chromium to handle returning the actual + // accessibility object. + case WM_GETOBJECT: { + const DWORD obj_id = static_cast(l_param); + if (enabled_a11y_support_) return false; + + if (obj_id == OBJID_CLIENT) { + const auto axState = content::BrowserAccessibilityState::GetInstance(); + if (axState && !axState->IsAccessibleBrowser()) { + axState->OnScreenReaderDetected(); + enabled_a11y_support_ = true; + } + } + + return false; + } case WM_COMMAND: // Handle thumbar button click message. if (HIWORD(w_param) == THBN_CLICKED) diff --git a/atom/browser/net/atom_network_delegate.cc b/atom/browser/net/atom_network_delegate.cc index 91b63fada359..3143cd3b2575 100644 --- a/atom/browser/net/atom_network_delegate.cc +++ b/atom/browser/net/atom_network_delegate.cc @@ -4,21 +4,20 @@ #include "atom/browser/net/atom_network_delegate.h" -#include +#include #include "atom/common/native_mate_converters/net_converter.h" #include "base/stl_util.h" #include "base/strings/string_util.h" +#include "brightray/browser/net/devtools_network_transaction.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/resource_request_info.h" #include "net/url_request/url_request.h" +using brightray::DevToolsNetworkTransaction; using content::BrowserThread; namespace atom { -namespace { - const char* ResourceTypeToString(content::ResourceType type) { switch (type) { case content::RESOURCE_TYPE_MAIN_FRAME: @@ -40,6 +39,11 @@ const char* ResourceTypeToString(content::ResourceType type) { } } +namespace { + +using ResponseHeadersContainer = + std::pair*, const std::string&>; + void RunSimpleListener(const AtomNetworkDelegate::SimpleListener& listener, scoped_ptr details) { return listener.Run(*(details.get())); @@ -170,10 +174,15 @@ void ReadFromResponseObject(const base::DictionaryValue& response, } void ReadFromResponseObject(const base::DictionaryValue& response, - scoped_refptr* headers) { + const ResponseHeadersContainer& container) { const base::DictionaryValue* dict; + std::string status_line; + if (!response.GetString("statusLine", &status_line)) + status_line = container.second; if (response.GetDictionary("responseHeaders", &dict)) { + auto headers = container.first; *headers = new net::HttpResponseHeaders(""); + (*headers)->ReplaceStatusLine(status_line); for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { @@ -218,6 +227,12 @@ void AtomNetworkDelegate::SetResponseListenerInIO( response_listeners_[type] = { patterns, callback }; } +void AtomNetworkDelegate::SetDevToolsNetworkEmulationClientId( + const std::string& client_id) { + base::AutoLock auto_lock(lock_); + client_id_ = client_id; +} + int AtomNetworkDelegate::OnBeforeURLRequest( net::URLRequest* request, const net::CompletionCallback& callback, @@ -233,6 +248,16 @@ int AtomNetworkDelegate::OnBeforeSendHeaders( net::URLRequest* request, const net::CompletionCallback& callback, net::HttpRequestHeaders* headers) { + std::string client_id; + { + base::AutoLock auto_lock(lock_); + client_id = client_id_; + } + + if (!client_id.empty()) + headers->SetHeader( + DevToolsNetworkTransaction::kDevToolsEmulateNetworkConditionsClientId, + client_id); if (!ContainsKey(response_listeners_, kOnBeforeSendHeaders)) return brightray::NetworkDelegate::OnBeforeSendHeaders( request, callback, headers); @@ -263,7 +288,8 @@ int AtomNetworkDelegate::OnHeadersReceived( request, callback, original, override, allowed); return HandleResponseEvent( - kOnHeadersReceived, request, callback, override, original); + kOnHeadersReceived, request, callback, + std::make_pair(override, original->GetStatusLine()), original); } void AtomNetworkDelegate::OnBeforeRedirect(net::URLRequest* request, diff --git a/atom/browser/net/atom_network_delegate.h b/atom/browser/net/atom_network_delegate.h index 4f55f7c09863..701a953c265e 100644 --- a/atom/browser/net/atom_network_delegate.h +++ b/atom/browser/net/atom_network_delegate.h @@ -7,14 +7,17 @@ #include #include +#include #include "brightray/browser/network_delegate.h" #include "base/callback.h" +#include "base/synchronization/lock.h" #include "base/values.h" #include "extensions/common/url_pattern.h" #include "net/base/net_errors.h" #include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" +#include "content/public/browser/resource_request_info.h" namespace extensions { class URLPattern; @@ -24,6 +27,8 @@ namespace atom { using URLPatterns = std::set; +const char* ResourceTypeToString(content::ResourceType type); + class AtomNetworkDelegate : public brightray::NetworkDelegate { public: using ResponseCallback = base::Callback; @@ -65,6 +70,8 @@ class AtomNetworkDelegate : public brightray::NetworkDelegate { const URLPatterns& patterns, const ResponseListener& callback); + void SetDevToolsNetworkEmulationClientId(const std::string& client_id); + protected: // net::NetworkDelegate: int OnBeforeURLRequest(net::URLRequest* request, @@ -113,6 +120,11 @@ class AtomNetworkDelegate : public brightray::NetworkDelegate { std::map response_listeners_; std::map callbacks_; + base::Lock lock_; + + // Client id for devtools network emulation. + std::string client_id_; + DISALLOW_COPY_AND_ASSIGN(AtomNetworkDelegate); }; diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index e2afa33f7df6..9d04617b2098 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 0.37.3 + 0.37.8 CFBundleShortVersionString - 0.37.3 + 0.37.8 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 152523466694..9f74c14d4461 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,37,3,0 - PRODUCTVERSION 0,37,3,0 + FILEVERSION 0,37,8,0 + PRODUCTVERSION 0,37,8,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "0.37.3" + VALUE "FileVersion", "0.37.8" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "0.37.3" + VALUE "ProductVersion", "0.37.8" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/browser/ui/accelerator_util_mac.mm b/atom/browser/ui/accelerator_util_mac.mm index be631b021249..d3395884c97f 100644 --- a/atom/browser/ui/accelerator_util_mac.mm +++ b/atom/browser/ui/accelerator_util_mac.mm @@ -13,12 +13,6 @@ namespace accelerator_util { void SetPlatformAccelerator(ui::Accelerator* accelerator) { unichar character; unichar characterIgnoringModifiers; - ui::MacKeyCodeForWindowsKeyCode(accelerator->key_code(), - 0, - &character, - &characterIgnoringModifiers); - NSString* characters = - [[[NSString alloc] initWithCharacters:&character length:1] autorelease]; NSUInteger modifiers = (accelerator->IsCtrlDown() ? NSControlKeyMask : 0) | @@ -26,6 +20,18 @@ void SetPlatformAccelerator(ui::Accelerator* accelerator) { (accelerator->IsAltDown() ? NSAlternateKeyMask : 0) | (accelerator->IsShiftDown() ? NSShiftKeyMask : 0); + ui::MacKeyCodeForWindowsKeyCode(accelerator->key_code(), + modifiers, + &character, + &characterIgnoringModifiers); + + if (character != characterIgnoringModifiers) { + modifiers ^= NSShiftKeyMask; + } + + NSString* characters = + [[[NSString alloc] initWithCharacters:&character length:1] autorelease]; + scoped_ptr platform_accelerator( new ui::PlatformAcceleratorCocoa(characters, modifiers)); accelerator->set_platform_accelerator(std::move(platform_accelerator)); diff --git a/atom/browser/ui/tray_icon_cocoa.mm b/atom/browser/ui/tray_icon_cocoa.mm index d2a2fe83460e..c3fa3f3b9272 100644 --- a/atom/browser/ui/tray_icon_cocoa.mm +++ b/atom/browser/ui/tray_icon_cocoa.mm @@ -27,7 +27,6 @@ const CGFloat kVerticalTitleMargin = 2; BOOL inMouseEventSequence_; base::scoped_nsobject image_; base::scoped_nsobject alternateImage_; - base::scoped_nsobject image_view_; base::scoped_nsobject title_; base::scoped_nsobject statusItem_; } @@ -44,15 +43,6 @@ const CGFloat kVerticalTitleMargin = 2; inMouseEventSequence_ = NO; if ((self = [super initWithFrame: CGRectZero])) { - // Setup the image view. - image_view_.reset([[NSImageView alloc] initWithFrame: CGRectZero]); - [image_view_ setImageScaling:NSImageScaleNone]; - [image_view_ setImageAlignment:NSImageAlignCenter]; - [self addSubview:image_view_]; - - // Unregister image_view_ as a dragged destination, allows its parent view - // (StatusItemView) handle dragging events. - [image_view_ unregisterDraggedTypes]; [self registerForDraggedTypes: @[NSFilenamesPboardType]]; // Create the status item. @@ -69,7 +59,6 @@ const CGFloat kVerticalTitleMargin = 2; - (void)updateDimensions { NSStatusBar * bar = [NSStatusBar systemStatusBar]; - [image_view_ setFrame: NSMakeRect(0, 0, [self iconWidth], [bar thickness])]; [self setFrame: NSMakeRect(0, 0, [self fullWidth], [bar thickness])]; [self setNeedsDisplay:YES]; } @@ -85,28 +74,44 @@ const CGFloat kVerticalTitleMargin = 2; // | icon | title | /// ---------------- - // Draw background. BOOL highlight = [self shouldHighlight]; + BOOL highlightContent = highlight | [self isDarkMode]; CGFloat thickness = [[statusItem_ statusBar] thickness]; + + // Draw the system bar background. [statusItem_ drawStatusBarBackgroundInRect:self.bounds withHighlight:highlight]; - // Make use of NSImageView to draw the image, which can correctly draw - // template image under dark menu bar. - if (inMouseEventSequence_ && alternateImage_ && - [image_view_ image] != alternateImage_.get()) { - [image_view_ setImage:alternateImage_]; - } else if ([image_view_ image] != image_.get()) { - [image_view_ setImage:image_]; + // Determine which image to use. + NSImage* image = image_.get(); + if (inMouseEventSequence_ && alternateImage_) { + image = alternateImage_.get(); + } + // Apply the higlight color if the image is a template image. When this moves + // to using the new [NSStatusItem button] API, this should work automagically. + if ([image isTemplate] == YES) { + NSImage* imageWithColor = [[image copy] autorelease]; + [imageWithColor lockFocus]; + [[self colorWithHighlight: highlightContent] set]; + CGRect imageBounds = CGRectMake(0,0, image.size.width, image.size.height); + NSRectFillUsingOperation(imageBounds, NSCompositeSourceAtop); + [imageWithColor unlockFocus]; + image = imageWithColor; } + // Draw the image + [image drawInRect: CGRectMake( + roundf(([self iconWidth] - image.size.width) / 2), + roundf((thickness - image.size.height) / 2), + image.size.width, + image.size.height + )]; + if (title_) { - // Highlight the text when icon is highlighted or in dark mode. - highlight |= [self isDarkMode]; // Draw title. NSRect titleDrawRect = NSMakeRect( [self iconWidth], -kVerticalTitleMargin, [self titleWidth], thickness); [title_ drawInRect:titleDrawRect - withAttributes:[self titleAttributesWithHighlight:highlight]]; + withAttributes:[self titleAttributesWithHighlight:highlightContent]]; } } @@ -157,14 +162,16 @@ const CGFloat kVerticalTitleMargin = 2; return [attributes size].width; } -- (NSDictionary*)titleAttributesWithHighlight:(BOOL)highlight { - NSFont* font = [NSFont menuBarFontOfSize:0]; - NSColor* foregroundColor = highlight ? +- (NSColor*)colorWithHighlight:(BOOL)highlight { + return highlight ? [NSColor whiteColor] : [NSColor colorWithRed:0.265625 green:0.25390625 blue:0.234375 alpha:1.0]; +} + +- (NSDictionary*)titleAttributesWithHighlight:(BOOL)highlight { return @{ - NSFontAttributeName: font, - NSForegroundColorAttributeName: foregroundColor + NSFontAttributeName:[NSFont menuBarFontOfSize:0], + NSForegroundColorAttributeName:[self colorWithHighlight: highlight] }; } diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc index d018e1d09dbc..7c944832d88d 100644 --- a/atom/browser/web_contents_permission_helper.cc +++ b/atom/browser/web_contents_permission_helper.cc @@ -91,4 +91,12 @@ void WebContentsPermissionHelper::RequestPointerLockPermission( user_gesture); } +void WebContentsPermissionHelper::RequestOpenExternalPermission( + const base::Callback& callback, + bool user_gesture) { + RequestPermission((content::PermissionType)(PermissionType::OPEN_EXTERNAL), + callback, + user_gesture); +} + } // namespace atom diff --git a/atom/browser/web_contents_permission_helper.h b/atom/browser/web_contents_permission_helper.h index 90ae6dff56f5..89da64b75833 100644 --- a/atom/browser/web_contents_permission_helper.h +++ b/atom/browser/web_contents_permission_helper.h @@ -19,7 +19,8 @@ class WebContentsPermissionHelper enum class PermissionType { POINTER_LOCK = static_cast(content::PermissionType::NUM) + 1, - FULLSCREEN + FULLSCREEN, + OPEN_EXTERNAL, }; void RequestFullscreenPermission( @@ -30,6 +31,9 @@ class WebContentsPermissionHelper void RequestWebNotificationPermission( const base::Callback& callback); void RequestPointerLockPermission(bool user_gesture); + void RequestOpenExternalPermission( + const base::Callback& callback, + bool user_gesture); private: explicit WebContentsPermissionHelper(content::WebContents* web_contents); diff --git a/atom/browser/web_contents_preferences.cc b/atom/browser/web_contents_preferences.cc index bcdbd736676a..05286a2d3ba4 100644 --- a/atom/browser/web_contents_preferences.cc +++ b/atom/browser/web_contents_preferences.cc @@ -8,6 +8,7 @@ #include #include +#include "atom/browser/native_window.h" #include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/options_switches.h" #include "base/command_line.h" @@ -116,6 +117,11 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches( LOG(ERROR) << "preload url must be file:// protocol."; } + // --background-color. + std::string color; + if (web_preferences.GetString(options::kBackgroundColor, &color)) + command_line->AppendSwitchASCII(switches::kBackgroundColor, color); + // The zoom factor. double zoom_factor = 1.0; if (web_preferences.GetDouble(options::kZoomFactor, &zoom_factor) && @@ -126,20 +132,28 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches( // --guest-instance-id, which is used to identify guest WebContents. int guest_instance_id; if (web_preferences.GetInteger(options::kGuestInstanceID, &guest_instance_id)) - command_line->AppendSwitchASCII(switches::kGuestInstanceID, - base::IntToString(guest_instance_id)); + command_line->AppendSwitchASCII(switches::kGuestInstanceID, + base::IntToString(guest_instance_id)); // Pass the opener's window id. int opener_id; if (web_preferences.GetInteger(options::kOpenerID, &opener_id)) - command_line->AppendSwitchASCII(switches::kOpenerID, - base::IntToString(opener_id)); + command_line->AppendSwitchASCII(switches::kOpenerID, + base::IntToString(opener_id)); // Enable blink features. std::string blink_features; if (web_preferences.GetString(options::kBlinkFeatures, &blink_features)) - command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures, - blink_features); + command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures, + blink_features); + + // The initial visibility state. + NativeWindow* window = NativeWindow::FromWebContents(web_contents); + if (window) { + bool visible = window->IsVisible() && !window->IsMinimized(); + if (!visible) // Default state is visible. + command_line->AppendSwitch("hidden-page"); + } } // static diff --git a/atom/common/api/atom_api_asar.cc b/atom/common/api/atom_api_asar.cc index 4bfb0ed4c1be..1b0ea799e7d7 100644 --- a/atom/common/api/atom_api_asar.cc +++ b/atom/common/api/atom_api_asar.cc @@ -18,21 +18,39 @@ namespace { -v8::Persistent template_; - -class Archive : public mate::Wrappable { +class Archive : public mate::Wrappable { public: static v8::Local Create(v8::Isolate* isolate, const base::FilePath& path) { scoped_ptr archive(new asar::Archive(path)); if (!archive->Init()) return v8::False(isolate); - return (new Archive(std::move(archive)))->GetWrapper(isolate); + return (new Archive(isolate, std::move(archive)))->GetWrapper(); + } + + static void BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetProperty("path", &Archive::GetPath) + .SetMethod("getFileInfo", &Archive::GetFileInfo) + .SetMethod("stat", &Archive::Stat) + .SetMethod("readdir", &Archive::Readdir) + .SetMethod("realpath", &Archive::Realpath) + .SetMethod("copyFileOut", &Archive::CopyFileOut) + .SetMethod("getFd", &Archive::GetFD) + .SetMethod("destroy", &Archive::Destroy); } protected: - explicit Archive(scoped_ptr archive) - : archive_(std::move(archive)) {} + Archive(v8::Isolate* isolate, scoped_ptr archive) + : archive_(std::move(archive)) { + Init(isolate); + } + + // Returns the path of the file. + base::FilePath GetPath() { + return archive_->path(); + } // Reads the offset and size of file. v8::Local GetFileInfo(v8::Isolate* isolate, @@ -101,24 +119,6 @@ class Archive : public mate::Wrappable { archive_.reset(); } - // mate::Wrappable: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) { - if (template_.IsEmpty()) - template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate) - .SetValue("path", archive_->path()) - .SetMethod("getFileInfo", &Archive::GetFileInfo) - .SetMethod("stat", &Archive::Stat) - .SetMethod("readdir", &Archive::Readdir) - .SetMethod("realpath", &Archive::Realpath) - .SetMethod("copyFileOut", &Archive::CopyFileOut) - .SetMethod("getFd", &Archive::GetFD) - .SetMethod("destroy", &Archive::Destroy) - .Build()); - - return mate::ObjectTemplateBuilder( - isolate, v8::Local::New(isolate, template_)); - } - private: scoped_ptr archive_; diff --git a/atom/common/api/atom_api_id_weak_map.cc b/atom/common/api/atom_api_id_weak_map.cc index f32e33682dff..0d3ddae3cc09 100644 --- a/atom/common/api/atom_api_id_weak_map.cc +++ b/atom/common/api/atom_api_id_weak_map.cc @@ -12,7 +12,7 @@ namespace atom { namespace api { -IDWeakMap::IDWeakMap() { +IDWeakMap::IDWeakMap(v8::Isolate* isolate) { } IDWeakMap::~IDWeakMap() { @@ -52,8 +52,8 @@ void IDWeakMap::BuildPrototype(v8::Isolate* isolate, } // static -mate::Wrappable* IDWeakMap::Create(v8::Isolate* isolate) { - return new IDWeakMap; +mate::WrappableBase* IDWeakMap::Create(v8::Isolate* isolate) { + return new IDWeakMap(isolate); } } // namespace api diff --git a/atom/common/api/atom_api_id_weak_map.h b/atom/common/api/atom_api_id_weak_map.h index 0cf656f455bc..616112ffe6f4 100644 --- a/atom/common/api/atom_api_id_weak_map.h +++ b/atom/common/api/atom_api_id_weak_map.h @@ -13,15 +13,15 @@ namespace atom { namespace api { -class IDWeakMap : public mate::Wrappable { +class IDWeakMap : public mate::Wrappable { public: - static mate::Wrappable* Create(v8::Isolate* isolate); + static mate::WrappableBase* Create(v8::Isolate* isolate); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); protected: - IDWeakMap(); + explicit IDWeakMap(v8::Isolate* isolate); ~IDWeakMap(); private: diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 3dda326f59fd..1c90fe7080fb 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -168,35 +168,15 @@ bool ReadImageSkiaFromICO(gfx::ImageSkia* image, const base::FilePath& path) { } #endif -v8::Persistent template_; - } // namespace -NativeImage::NativeImage() {} - -NativeImage::NativeImage(const gfx::Image& image) : image_(image) {} +NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image) + : image_(image) { + Init(isolate); +} NativeImage::~NativeImage() {} -mate::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - if (template_.IsEmpty()) - template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate) - .SetMethod("toPng", &NativeImage::ToPNG) - .SetMethod("toJpeg", &NativeImage::ToJPEG) - .SetMethod("getNativeHandle", &NativeImage::GetNativeHandle) - .SetMethod("toDataURL", &NativeImage::ToDataURL) - .SetMethod("toDataUrl", &NativeImage::ToDataURL) // deprecated. - .SetMethod("isEmpty", &NativeImage::IsEmpty) - .SetMethod("getSize", &NativeImage::GetSize) - .SetMethod("setTemplateImage", &NativeImage::SetTemplateImage) - .SetMethod("isTemplateImage", &NativeImage::IsTemplateImage) - .Build()); - - return mate::ObjectTemplateBuilder( - isolate, v8::Local::New(isolate, template_)); -} - v8::Local NativeImage::ToPNG(v8::Isolate* isolate) { scoped_refptr png = image_.As1xPNGBytes(); return node::Buffer::Copy(isolate, @@ -255,13 +235,13 @@ bool NativeImage::IsTemplateImage() { // static mate::Handle NativeImage::CreateEmpty(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new NativeImage); + return mate::CreateHandle(isolate, new NativeImage(isolate, gfx::Image())); } // static mate::Handle NativeImage::Create( v8::Isolate* isolate, const gfx::Image& image) { - return mate::CreateHandle(isolate, new NativeImage(image)); + return mate::CreateHandle(isolate, new NativeImage(isolate, image)); } // static @@ -330,6 +310,21 @@ mate::Handle NativeImage::CreateFromDataURL( return CreateEmpty(isolate); } +// static +void NativeImage::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) + .SetMethod("toPng", &NativeImage::ToPNG) + .SetMethod("toJpeg", &NativeImage::ToJPEG) + .SetMethod("getNativeHandle", &NativeImage::GetNativeHandle) + .SetMethod("toDataURL", &NativeImage::ToDataURL) + .SetMethod("toDataUrl", &NativeImage::ToDataURL) // deprecated. + .SetMethod("isEmpty", &NativeImage::IsEmpty) + .SetMethod("getSize", &NativeImage::GetSize) + .SetMethod("setTemplateImage", &NativeImage::SetTemplateImage) + .SetMethod("isTemplateImage", &NativeImage::IsTemplateImage); +} + } // namespace api } // namespace atom diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index 145f5ff1dcdc..79844604706c 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -29,7 +29,7 @@ namespace atom { namespace api { -class NativeImage : public mate::Wrappable { +class NativeImage : public mate::Wrappable { public: static mate::Handle CreateEmpty(v8::Isolate* isolate); static mate::Handle Create( @@ -45,18 +45,14 @@ class NativeImage : public mate::Wrappable { static mate::Handle CreateFromDataURL( v8::Isolate* isolate, const GURL& url); - // The default constructor should only be used by image_converter.cc. - NativeImage(); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); const gfx::Image& image() const { return image_; } protected: - explicit NativeImage(const gfx::Image& image); - virtual ~NativeImage(); - - // mate::Wrappable: - mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; + NativeImage(v8::Isolate* isolate, const gfx::Image& image); + ~NativeImage() override; private: v8::Local ToPNG(v8::Isolate* isolate); diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc index 0ebd939398f1..109f9f0f36c2 100644 --- a/atom/common/api/atom_api_v8_util.cc +++ b/atom/common/api/atom_api_v8_util.cc @@ -4,7 +4,9 @@ #include -#include "atom/common/api/object_life_monitor.h" +#include "atom/common/api/remote_callback_freer.h" +#include "atom/common/api/remote_object_freer.h" +#include "atom/common/native_mate_converters/content_converter.h" #include "atom/common/node_includes.h" #include "native_mate/dictionary.h" #include "v8/include/v8-profiler.h" @@ -51,12 +53,6 @@ int32_t GetObjectHash(v8::Local object) { return object->GetIdentityHash(); } -void SetDestructor(v8::Isolate* isolate, - v8::Local object, - v8::Local callback) { - atom::ObjectLifeMonitor::BindTo(isolate, object, callback); -} - void TakeHeapSnapshot(v8::Isolate* isolate) { isolate->GetHeapProfiler()->TakeHeapSnapshot(); } @@ -68,8 +64,9 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("setHiddenValue", &SetHiddenValue); dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue); dict.SetMethod("getObjectHash", &GetObjectHash); - dict.SetMethod("setDestructor", &SetDestructor); dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot); + dict.SetMethod("setRemoteCallbackFreer", &atom::RemoteCallbackFreer::BindTo); + dict.SetMethod("setRemoteObjectFreer", &atom::RemoteObjectFreer::BindTo); } } // namespace diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc index fe53d8793f2a..f518caf5c503 100644 --- a/atom/common/api/atom_bindings.cc +++ b/atom/common/api/atom_bindings.cc @@ -98,8 +98,17 @@ void AtomBindings::OnCallNextTick(uv_async_t* handle) { self->pending_next_ticks_.begin(); it != self->pending_next_ticks_.end(); ++it) { node::Environment* env = *it; + // KickNextTick, copied from node.cc: node::Environment::AsyncCallbackScope callback_scope(env); - env->KickNextTick(&callback_scope); + if (callback_scope.in_makecallback()) + continue; + node::Environment::TickInfo* tick_info = env->tick_info(); + if (tick_info->length() == 0) + env->isolate()->RunMicrotasks(); + v8::Local process = env->process_object(); + if (tick_info->length() == 0) + tick_info->set_index(0); + env->tick_callback_function()->Call(process, 0, nullptr).IsEmpty(); } self->pending_next_ticks_.clear(); diff --git a/atom/common/api/object_life_monitor.cc b/atom/common/api/object_life_monitor.cc index 916ad8a5177a..ffcc0d718420 100644 --- a/atom/common/api/object_life_monitor.cc +++ b/atom/common/api/object_life_monitor.cc @@ -10,30 +10,28 @@ namespace atom { -// static -void ObjectLifeMonitor::BindTo(v8::Isolate* isolate, - v8::Local target, - v8::Local destructor) { - new ObjectLifeMonitor(isolate, target, destructor); -} - ObjectLifeMonitor::ObjectLifeMonitor(v8::Isolate* isolate, - v8::Local target, - v8::Local destructor) + v8::Local target) : isolate_(isolate), context_(isolate, isolate->GetCurrentContext()), target_(isolate, target), - destructor_(isolate, destructor), weak_ptr_factory_(this) { target_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter); } +ObjectLifeMonitor::~ObjectLifeMonitor() { + if (target_.IsEmpty()) + return; + target_.ClearWeak(); + target_.Reset(); +} + // static void ObjectLifeMonitor::OnObjectGC( const v8::WeakCallbackInfo& data) { ObjectLifeMonitor* self = data.GetParameter(); self->target_.Reset(); - self->RunCallback(); + self->RunDestructor(); data.SetSecondPassCallback(Free); } @@ -43,13 +41,4 @@ void ObjectLifeMonitor::Free( delete data.GetParameter(); } -void ObjectLifeMonitor::RunCallback() { - v8::HandleScope handle_scope(isolate_); - v8::Local context = v8::Local::New( - isolate_, context_); - v8::Context::Scope context_scope(context); - v8::Local::New(isolate_, destructor_)->Call( - context->Global(), 0, nullptr); -} - } // namespace atom diff --git a/atom/common/api/object_life_monitor.h b/atom/common/api/object_life_monitor.h index 82d923fcedb7..59d5fdb5cffd 100644 --- a/atom/common/api/object_life_monitor.h +++ b/atom/common/api/object_life_monitor.h @@ -12,25 +12,19 @@ namespace atom { class ObjectLifeMonitor { - public: - static void BindTo(v8::Isolate* isolate, - v8::Local target, - v8::Local destructor); + protected: + ObjectLifeMonitor(v8::Isolate* isolate, v8::Local target); + virtual ~ObjectLifeMonitor(); + + virtual void RunDestructor() = 0; private: - ObjectLifeMonitor(v8::Isolate* isolate, - v8::Local target, - v8::Local destructor); - static void OnObjectGC(const v8::WeakCallbackInfo& data); static void Free(const v8::WeakCallbackInfo& data); - void RunCallback(); - v8::Isolate* isolate_; v8::Global context_; v8::Global target_; - v8::Global destructor_; base::WeakPtrFactory weak_ptr_factory_; diff --git a/atom/common/api/remote_callback_freer.cc b/atom/common/api/remote_callback_freer.cc new file mode 100644 index 000000000000..7bc377efc5e7 --- /dev/null +++ b/atom/common/api/remote_callback_freer.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/common/api/remote_callback_freer.h" + +#include "atom/common/api/api_messages.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" + +namespace atom { + +// static +void RemoteCallbackFreer::BindTo(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_contents) { + new RemoteCallbackFreer(isolate, target, object_id, web_contents); +} + +RemoteCallbackFreer::RemoteCallbackFreer(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_contents) + : ObjectLifeMonitor(isolate, target), + content::WebContentsObserver(web_contents), + object_id_(object_id) { +} + +RemoteCallbackFreer::~RemoteCallbackFreer() { +} + +void RemoteCallbackFreer::RunDestructor() { + base::string16 channel = + base::ASCIIToUTF16("ELECTRON_RENDERER_RELEASE_CALLBACK"); + base::ListValue args; + args.AppendInteger(object_id_); + Send(new AtomViewMsg_Message(routing_id(), channel, args)); + + Observe(nullptr); +} + +void RemoteCallbackFreer::RenderViewDeleted(content::RenderViewHost*) { + delete this; +} + +} // namespace atom diff --git a/atom/common/api/remote_callback_freer.h b/atom/common/api/remote_callback_freer.h new file mode 100644 index 000000000000..8fe80c8d4774 --- /dev/null +++ b/atom/common/api/remote_callback_freer.h @@ -0,0 +1,40 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ +#define ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ +#include "atom/common/api/object_life_monitor.h" +#include "content/public/browser/web_contents_observer.h" + +namespace atom { + +class RemoteCallbackFreer : public ObjectLifeMonitor, + public content::WebContentsObserver { + public: + static void BindTo(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_conents); + + protected: + RemoteCallbackFreer(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_conents); + ~RemoteCallbackFreer() override; + + void RunDestructor() override; + + // content::WebContentsObserver: + void RenderViewDeleted(content::RenderViewHost*) override; + + private: + int object_id_; + + DISALLOW_COPY_AND_ASSIGN(RemoteCallbackFreer); +}; + +} // namespace atom + +#endif // ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ diff --git a/atom/common/api/remote_object_freer.cc b/atom/common/api/remote_object_freer.cc new file mode 100644 index 000000000000..1762f1d1e068 --- /dev/null +++ b/atom/common/api/remote_object_freer.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/common/api/remote_object_freer.h" + +#include "atom/common/api/api_messages.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "content/public/renderer/render_view.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebView.h" + +using blink::WebLocalFrame; +using blink::WebView; + +namespace atom { + +namespace { + +content::RenderView* GetCurrentRenderView() { + WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext(); + if (!frame) + return nullptr; + + WebView* view = frame->view(); + if (!view) + return nullptr; // can happen during closing. + + return content::RenderView::FromWebView(view); +} + +} // namespace + +// static +void RemoteObjectFreer::BindTo( + v8::Isolate* isolate, v8::Local target, int object_id) { + new RemoteObjectFreer(isolate, target, object_id); +} + +RemoteObjectFreer::RemoteObjectFreer( + v8::Isolate* isolate, v8::Local target, int object_id) + : ObjectLifeMonitor(isolate, target), + object_id_(object_id) { +} + +RemoteObjectFreer::~RemoteObjectFreer() { +} + +void RemoteObjectFreer::RunDestructor() { + content::RenderView* render_view = GetCurrentRenderView(); + if (!render_view) + return; + + base::string16 channel = base::ASCIIToUTF16("ipc-message"); + base::ListValue args; + args.AppendString("ELECTRON_BROWSER_DEREFERENCE"); + args.AppendInteger(object_id_); + render_view->Send( + new AtomViewHostMsg_Message(render_view->GetRoutingID(), channel, args)); +} + +} // namespace atom diff --git a/atom/common/api/remote_object_freer.h b/atom/common/api/remote_object_freer.h new file mode 100644 index 000000000000..c2b5d8b7d30b --- /dev/null +++ b/atom/common/api/remote_object_freer.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_ +#define ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_ + +#include "atom/common/api/object_life_monitor.h" + +namespace atom { + +class RemoteObjectFreer : public ObjectLifeMonitor { + public: + static void BindTo( + v8::Isolate* isolate, v8::Local target, int object_id); + + protected: + RemoteObjectFreer( + v8::Isolate* isolate, v8::Local target, int object_id); + ~RemoteObjectFreer() override; + + void RunDestructor() override; + + private: + int object_id_; + + DISALLOW_COPY_AND_ASSIGN(RemoteObjectFreer); +}; + +} // namespace atom + +#endif // ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_ diff --git a/atom/common/atom_constants.cc b/atom/common/atom_constants.cc index dacda3c816c8..f66c947aa24c 100644 --- a/atom/common/atom_constants.cc +++ b/atom/common/atom_constants.cc @@ -6,6 +6,22 @@ namespace atom { -const char* kCORSHeader = "Access-Control-Allow-Origin: *"; +const char kCORSHeader[] = "Access-Control-Allow-Origin: *"; + +const char kSHA1Certificate[] = "SHA-1 Certificate"; +const char kSHA1MajorDescription[] = + "The certificate for this site expires in 2017 or later, " + "and the certificate chain contains a certificate signed using SHA-1."; +const char kSHA1MinorDescription[] = + "The certificate for this site expires in 2016, " + "and the certificate chain contains a certificate signed using SHA-1."; +const char kCertificateError[] = "Certificate Error"; +const char kValidCertificate[] = "Valid Certificate"; +const char kValidCertificateDescription[] = + "The connection to this site is using a valid, trusted server certificate."; +const char kSecureProtocol[] = "Secure TLS connection"; +const char kSecureProtocolDescription[] = + "The connection to this site is using a strong protocol version " + "and cipher suite."; } // namespace atom diff --git a/atom/common/atom_constants.h b/atom/common/atom_constants.h index e0d42e83eef9..b67b7b2e4ae5 100644 --- a/atom/common/atom_constants.h +++ b/atom/common/atom_constants.h @@ -8,7 +8,17 @@ namespace atom { // Header to ignore CORS. -extern const char* kCORSHeader; +extern const char kCORSHeader[]; + +// Strings describing Chrome security policy for DevTools security panel. +extern const char kSHA1Certificate[]; +extern const char kSHA1MajorDescription[]; +extern const char kSHA1MinorDescription[]; +extern const char kCertificateError[]; +extern const char kValidCertificate[]; +extern const char kValidCertificateDescription[]; +extern const char kSecureProtocol[]; +extern const char kSecureProtocolDescription[]; } // namespace atom diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index cb4705293404..4ce73bc0aeec 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 0 #define ATOM_MINOR_VERSION 37 -#define ATOM_PATCH_VERSION 3 +#define ATOM_PATCH_VERSION 8 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/atom/common/color_util.cc b/atom/common/color_util.cc new file mode 100644 index 000000000000..a6640d9e08b6 --- /dev/null +++ b/atom/common/color_util.cc @@ -0,0 +1,48 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/common/color_util.h" + +#include + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" + +namespace atom { + +SkColor ParseHexColor(const std::string& color_string) { + // Check the string for incorrect formatting. + if (color_string.empty() || color_string[0] != '#') + return SK_ColorWHITE; + + // Prepend FF if alpha channel is not specified. + std::string source = color_string.substr(1); + if (source.size() == 3) + source.insert(0, "F"); + else if (source.size() == 6) + source.insert(0, "FF"); + + // Convert the string from #FFF format to #FFFFFF format. + std::string formatted_color; + if (source.size() == 4) { + for (size_t i = 0; i < 4; ++i) { + formatted_color += source[i]; + formatted_color += source[i]; + } + } else if (source.size() == 8) { + formatted_color = source; + } else { + return SK_ColorWHITE; + } + + // Convert the string to an integer and make sure it is in the correct value + // range. + std::vector bytes; + if (!base::HexStringToBytes(formatted_color, &bytes)) + return SK_ColorWHITE; + + return SkColorSetARGB(bytes[0], bytes[1], bytes[2], bytes[3]); +} + +} // namespace atom diff --git a/atom/common/color_util.h b/atom/common/color_util.h new file mode 100644 index 000000000000..0f2bb9633a73 --- /dev/null +++ b/atom/common/color_util.h @@ -0,0 +1,19 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_COLOR_UTIL_H_ +#define ATOM_COMMON_COLOR_UTIL_H_ + +#include + +#include "third_party/skia/include/core/SkColor.h" + +namespace atom { + +// Parse hex color like "#FFF" or "#EFEFEF" +SkColor ParseHexColor(const std::string& name); + +} // namespace atom + +#endif // ATOM_COMMON_COLOR_UTIL_H_ diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index f5d81d085bc1..154dcf88ce37 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -145,6 +145,8 @@ v8::Local Converter::ToV8( return StringToV8(isolate, "pointerLock"); else if (val == (content::PermissionType)(PermissionType::FULLSCREEN)) return StringToV8(isolate, "fullscreen"); + else if (val == (content::PermissionType)(PermissionType::OPEN_EXTERNAL)) + return StringToV8(isolate, "openExternal"); return StringToV8(isolate, "unknown"); } @@ -178,4 +180,17 @@ v8::Local Converter::ToV8( return atom::api::WebContents::CreateFrom(isolate, val).ToV8(); } +// static +bool Converter::FromV8( + v8::Isolate* isolate, + v8::Local val, + content::WebContents** out) { + atom::api::WebContents* web_contents = nullptr; + if (!ConvertFromV8(isolate, val, &web_contents) || !web_contents) + return false; + + *out = web_contents->web_contents(); + return true; +} + } // namespace mate diff --git a/atom/common/native_mate_converters/content_converter.h b/atom/common/native_mate_converters/content_converter.h index b1a42b6897ca..f2e7211ce5d1 100644 --- a/atom/common/native_mate_converters/content_converter.h +++ b/atom/common/native_mate_converters/content_converter.h @@ -57,6 +57,8 @@ template<> struct Converter { static v8::Local ToV8(v8::Isolate* isolate, content::WebContents* val); + static bool FromV8(v8::Isolate* isolate, v8::Local val, + content::WebContents** out); }; } // namespace mate diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index ce3b9a708152..31105886eb7c 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -44,6 +44,7 @@ REFERENCE_MODULE(atom_browser_power_save_blocker); REFERENCE_MODULE(atom_browser_protocol); REFERENCE_MODULE(atom_browser_global_shortcut); REFERENCE_MODULE(atom_browser_session); +REFERENCE_MODULE(atom_browser_system_preferences); REFERENCE_MODULE(atom_browser_tray); REFERENCE_MODULE(atom_browser_web_contents); REFERENCE_MODULE(atom_browser_web_view_manager); @@ -175,6 +176,9 @@ node::Environment* NodeBindings::CreateEnvironment( mate::Dictionary process(context->GetIsolate(), env->process_object()); process.Set("type", process_type); process.Set("resourcesPath", resources_path); + // Do not set DOM globals for renderer process. + if (!is_browser_) + process.Set("_noBrowserGlobals", resources_path); // The path to helper app. base::FilePath helper_exec_path; PathService::Get(content::CHILD_PROCESS_EXE, &helper_exec_path); diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index ac63ea1b7276..562171d51f25 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -119,9 +119,6 @@ const char kPpapiFlashPath[] = "ppapi-flash-path"; // Ppapi Flash version. const char kPpapiFlashVersion[] = "ppapi-flash-version"; -// Path to client certificate. -const char kClientCertificate[] = "client-certificate"; - // Disable HTTP cache. const char kDisableHttpCache[] = "disable-http-cache"; @@ -142,12 +139,13 @@ const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist"; const char kAppUserModelId[] = "app-user-model-id"; // The command line switch versions of the options. -const char kZoomFactor[] = "zoom-factor"; -const char kPreloadScript[] = "preload"; -const char kPreloadURL[] = "preload-url"; -const char kNodeIntegration[] = "node-integration"; -const char kGuestInstanceID[] = "guest-instance-id"; -const char kOpenerID[] = "opener-id"; +const char kBackgroundColor[] = "background-color"; +const char kZoomFactor[] = "zoom-factor"; +const char kPreloadScript[] = "preload"; +const char kPreloadURL[] = "preload-url"; +const char kNodeIntegration[] = "node-integration"; +const char kGuestInstanceID[] = "guest-instance-id"; +const char kOpenerID[] = "opener-id"; // Widevine options // Path to Widevine CDM binaries. diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 3c198555a5c3..5746a7bbfe54 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -68,7 +68,6 @@ namespace switches { extern const char kEnablePlugins[]; extern const char kPpapiFlashPath[]; extern const char kPpapiFlashVersion[]; -extern const char kClientCertificate[]; extern const char kDisableHttpCache[]; extern const char kRegisterStandardSchemes[]; extern const char kRegisterServiceWorkerSchemes[]; @@ -76,6 +75,7 @@ extern const char kSSLVersionFallbackMin[]; extern const char kCipherSuiteBlacklist[]; extern const char kAppUserModelId[]; +extern const char kBackgroundColor[]; extern const char kZoomFactor[]; extern const char kPreloadScript[]; extern const char kPreloadURL[]; diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index 1e437b866cc0..9811c8760d06 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -13,7 +13,9 @@ namespace { -bool XDGUtil(const std::string& util, const std::string& arg) { +bool XDGUtil(const std::string& util, + const std::string& arg, + const bool wait_for_exit) { std::vector argv; argv.push_back(util); argv.push_back(arg); @@ -30,6 +32,11 @@ bool XDGUtil(const std::string& util, const std::string& arg) { if (!process.IsValid()) return false; + if (!wait_for_exit) { + base::EnsureProcessGetsReaped(process.Pid()); + return true; + } + int exit_code = -1; if (!process.WaitForExit(&exit_code)) return false; @@ -37,12 +44,12 @@ bool XDGUtil(const std::string& util, const std::string& arg) { return (exit_code == 0); } -bool XDGOpen(const std::string& path) { - return XDGUtil("xdg-open", path); +bool XDGOpen(const std::string& path, const bool wait_for_exit) { + return XDGUtil("xdg-open", path, wait_for_exit); } -bool XDGEmail(const std::string& email) { - return XDGUtil("xdg-email", email); +bool XDGEmail(const std::string& email, const bool wait_for_exit) { + return XDGUtil("xdg-email", email, wait_for_exit); } } // namespace @@ -57,22 +64,24 @@ void ShowItemInFolder(const base::FilePath& full_path) { if (!base::DirectoryExists(dir)) return; - XDGOpen(dir.value()); + XDGOpen(dir.value(), true); } void OpenItem(const base::FilePath& full_path) { - XDGOpen(full_path.value()); + XDGOpen(full_path.value(), true); } bool OpenExternal(const GURL& url, bool activate) { + // Don't wait for exit, since we don't want to wait for the browser/email + // client window to close before returning if (url.SchemeIs("mailto")) - return XDGEmail(url.spec()); + return XDGEmail(url.spec(), false); else - return XDGOpen(url.spec()); + return XDGOpen(url.spec(), false); } bool MoveItemToTrash(const base::FilePath& full_path) { - return XDGUtil("gvfs-trash", full_path.value()); + return XDGUtil("gvfs-trash", full_path.value(), true); } void Beep() { diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index e00b901bfff6..0eebc94fc141 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -54,8 +54,9 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { } // namespace -WebFrame::WebFrame() +WebFrame::WebFrame(v8::Isolate* isolate) : web_frame_(blink::WebLocalFrame::frameForCurrentContext()) { + Init(isolate); } WebFrame::~WebFrame() { @@ -67,7 +68,7 @@ void WebFrame::SetName(const std::string& name) { double WebFrame::SetZoomLevel(double level) { double ret = web_frame_->view()->setZoomLevel(level); - mate::EmitEvent(isolate(), GetWrapper(isolate()), "zoom-level-changed", ret); + mate::EmitEvent(isolate(), GetWrapper(), "zoom-level-changed", ret); return ret; } @@ -162,9 +163,15 @@ void WebFrame::ExecuteJavaScript(const base::string16& code, callback.release()); } -mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return mate::ObjectTemplateBuilder(isolate) +// static +mate::Handle WebFrame::Create(v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new WebFrame(isolate)); +} + +// static +void WebFrame::BuildPrototype( + v8::Isolate* isolate, v8::Local prototype) { + mate::ObjectTemplateBuilder(isolate, prototype) .SetMethod("setName", &WebFrame::SetName) .SetMethod("setZoomLevel", &WebFrame::SetZoomLevel) .SetMethod("getZoomLevel", &WebFrame::GetZoomLevel) @@ -187,11 +194,6 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( .SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript); } -// static -mate::Handle WebFrame::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new WebFrame); -} - } // namespace api } // namespace atom diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index d55b24fd25ea..e1eeb224930b 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -26,13 +26,16 @@ namespace api { class SpellCheckClient; -class WebFrame : public mate::Wrappable { +class WebFrame : public mate::Wrappable { public: static mate::Handle Create(v8::Isolate* isolate); + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + private: - WebFrame(); - virtual ~WebFrame(); + explicit WebFrame(v8::Isolate* isolate); + ~WebFrame() override; void SetName(const std::string& name); @@ -66,10 +69,6 @@ class WebFrame : public mate::Wrappable { // Excecuting scripts. void ExecuteJavaScript(const base::string16& code, mate::Arguments* args); - // mate::Wrappable: - virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate); - scoped_ptr spell_check_client_; blink::WebLocalFrame* web_frame_; diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc index bbaea351378b..96dffbd512a6 100644 --- a/atom/renderer/atom_render_view_observer.cc +++ b/atom/renderer/atom_render_view_observer.cc @@ -27,6 +27,7 @@ #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebView.h" #include "ui/base/resource/resource_bundle.h" #include "native_mate/dictionary.h" @@ -88,6 +89,9 @@ void AtomRenderViewObserver::DidCreateDocumentElement( blink::WebLocalFrame* frame) { document_created_ = true; + // Make sure every page will get a script context created. + frame->executeScript(blink::WebScriptSource("void 0")); + // Read --zoom-factor from command line. std::string zoom_factor_str = base::CommandLine::ForCurrentProcess()-> GetSwitchValueASCII(switches::kZoomFactor); diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 7746ce123e4f..4bb3cd2168c8 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -10,6 +10,7 @@ #include "atom/common/api/api_messages.h" #include "atom/common/api/atom_bindings.h" #include "atom/common/api/event_emitter_caller.h" +#include "atom/common/color_util.h" #include "atom/common/node_bindings.h" #include "atom/common/node_includes.h" #include "atom/common/options_switches.h" @@ -120,8 +121,17 @@ void AtomRendererClient::RenderFrameCreated( } void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { - // Set default UA-dependent background as transparent. - render_view->GetWebView()->setBaseBackgroundColor(SK_ColorTRANSPARENT); + base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); + if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview. + // Set transparent background. + render_view->GetWebView()->setBaseBackgroundColor(SK_ColorTRANSPARENT); + } else { // normal window. + // If backgroundColor is specified then use it. + std::string name = cmd->GetSwitchValueASCII(switches::kBackgroundColor); + // Otherwise use white background. + SkColor color = name.empty() ? SK_ColorWHITE : ParseHexColor(name); + render_view->GetWebView()->setBaseBackgroundColor(color); + } new printing::PrintWebViewHelper(render_view); new AtomRenderViewObserver(render_view, this); diff --git a/atom/utility/atom_content_utility_client.cc b/atom/utility/atom_content_utility_client.cc index 2e591f2c6a8d..aff567fbcaab 100644 --- a/atom/utility/atom_content_utility_client.cc +++ b/atom/utility/atom_content_utility_client.cc @@ -37,7 +37,7 @@ int64_t AtomContentUtilityClient::max_ipc_message_size_ = AtomContentUtilityClient::AtomContentUtilityClient() : filter_messages_(false) { #if defined(OS_WIN) - handlers_.push_back(new PrintingHandlerWin()); + handlers_.push_back(new printing::PrintingHandlerWin()); #endif } @@ -71,11 +71,4 @@ void AtomContentUtilityClient::OnStartupPing() { // Don't release the process, we assume further messages are on the way. } -// static -void AtomContentUtilityClient::PreSandboxStartup() { -#if defined(OS_WIN) - PrintingHandlerWin::PreSandboxStartup(); -#endif -} - } // namespace atom diff --git a/atom/utility/atom_content_utility_client.h b/atom/utility/atom_content_utility_client.h index 229ae3f91765..ba0fef471a11 100644 --- a/atom/utility/atom_content_utility_client.h +++ b/atom/utility/atom_content_utility_client.h @@ -31,8 +31,6 @@ class AtomContentUtilityClient : public content::ContentUtilityClient { void UtilityThreadStarted() override; bool OnMessageReceived(const IPC::Message& message) override; - static void PreSandboxStartup(); - static void set_max_ipc_message_size_for_test(int64_t max_message_size) { max_ipc_message_size_ = max_message_size; } diff --git a/chromium_src/chrome/browser/certificate_manager_model.cc b/chromium_src/chrome/browser/certificate_manager_model.cc new file mode 100644 index 000000000000..b0db6edc357c --- /dev/null +++ b/chromium_src/chrome/browser/certificate_manager_model.cc @@ -0,0 +1,173 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/certificate_manager_model.h" + +#include + +#include "base/bind.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/resource_context.h" +#include "crypto/nss_util.h" +#include "crypto/nss_util_internal.h" +#include "net/base/crypto_module.h" +#include "net/base/net_errors.h" +#include "net/cert/nss_cert_database.h" +#include "net/cert/x509_certificate.h" + +using content::BrowserThread; + +namespace { + +net::NSSCertDatabase* g_nss_cert_database = nullptr; + +net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext( + content::ResourceContext* context, + const base::Callback& callback) { + // This initialization is not thread safe. This CHECK ensures that this code + // is only run on a single thread. + CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + if (!g_nss_cert_database) { + // Linux has only a single persistent slot compared to ChromeOS's separate + // public and private slot. + // Redirect any slot usage to this persistent slot on Linux. + g_nss_cert_database = new net::NSSCertDatabase( + crypto::ScopedPK11Slot( + crypto::GetPersistentNSSKeySlot()) /* public slot */, + crypto::ScopedPK11Slot( + crypto::GetPersistentNSSKeySlot()) /* private slot */); + } + return g_nss_cert_database; +} + +} // namespace + +// CertificateManagerModel is created on the UI thread. It needs a +// NSSCertDatabase handle (and on ChromeOS it needs to get the TPM status) which +// needs to be done on the IO thread. +// +// The initialization flow is roughly: +// +// UI thread IO Thread +// +// CertificateManagerModel::Create +// \--------------------------------------v +// CertificateManagerModel::GetCertDBOnIOThread +// | +// GetNSSCertDatabaseForResourceContext +// | +// CertificateManagerModel::DidGetCertDBOnIOThread +// v--------------------------------------/ +// CertificateManagerModel::DidGetCertDBOnUIThread +// | +// new CertificateManagerModel +// | +// callback + +// static +void CertificateManagerModel::Create( + content::BrowserContext* browser_context, + const CreationCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&CertificateManagerModel::GetCertDBOnIOThread, + browser_context->GetResourceContext(), + callback)); +} + +CertificateManagerModel::CertificateManagerModel( + net::NSSCertDatabase* nss_cert_database, + bool is_user_db_available) + : cert_db_(nss_cert_database), + is_user_db_available_(is_user_db_available) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +} + +CertificateManagerModel::~CertificateManagerModel() { +} + +int CertificateManagerModel::ImportFromPKCS12(net::CryptoModule* module, + const std::string& data, + const base::string16& password, + bool is_extractable, + net::CertificateList* imported_certs) { + return cert_db_->ImportFromPKCS12(module, data, password, + is_extractable, imported_certs); +} + +int CertificateManagerModel::ImportUserCert(const std::string& data) { + return cert_db_->ImportUserCert(data); +} + +bool CertificateManagerModel::ImportCACerts( + const net::CertificateList& certificates, + net::NSSCertDatabase::TrustBits trust_bits, + net::NSSCertDatabase::ImportCertFailureList* not_imported) { + return cert_db_->ImportCACerts(certificates, trust_bits, not_imported); +} + +bool CertificateManagerModel::ImportServerCert( + const net::CertificateList& certificates, + net::NSSCertDatabase::TrustBits trust_bits, + net::NSSCertDatabase::ImportCertFailureList* not_imported) { + return cert_db_->ImportServerCert(certificates, trust_bits, + not_imported); +} + +bool CertificateManagerModel::SetCertTrust( + const net::X509Certificate* cert, + net::CertType type, + net::NSSCertDatabase::TrustBits trust_bits) { + return cert_db_->SetCertTrust(cert, type, trust_bits); +} + +bool CertificateManagerModel::Delete(net::X509Certificate* cert) { + return cert_db_->DeleteCertAndKey(cert); +} + +// static +void CertificateManagerModel::DidGetCertDBOnUIThread( + net::NSSCertDatabase* cert_db, + bool is_user_db_available, + const CreationCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + scoped_ptr model(new CertificateManagerModel( + cert_db, is_user_db_available)); + callback.Run(std::move(model)); +} + +// static +void CertificateManagerModel::DidGetCertDBOnIOThread( + const CreationCallback& callback, + net::NSSCertDatabase* cert_db) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + bool is_user_db_available = !!cert_db->GetPublicSlot(); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&CertificateManagerModel::DidGetCertDBOnUIThread, + cert_db, + is_user_db_available, + callback)); +} + +// static +void CertificateManagerModel::GetCertDBOnIOThread( + content::ResourceContext* context, + const CreationCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext( + context, + base::Bind(&CertificateManagerModel::DidGetCertDBOnIOThread, + callback)); + if (cert_db) + DidGetCertDBOnIOThread(callback, cert_db); +} diff --git a/chromium_src/chrome/browser/certificate_manager_model.h b/chromium_src/chrome/browser/certificate_manager_model.h new file mode 100644 index 000000000000..1eb350876803 --- /dev/null +++ b/chromium_src/chrome/browser/certificate_manager_model.h @@ -0,0 +1,119 @@ +// Copyright (c) 2012 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 CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ +#define CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ + +#include +#include + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string16.h" +#include "net/cert/nss_cert_database.h" + +namespace content { +class BrowserContext; +class ResourceContext; +} // namespace content + +// CertificateManagerModel provides the data to be displayed in the certificate +// manager dialog, and processes changes from the view. +class CertificateManagerModel { + public: + typedef base::Callback)> + CreationCallback; + + // Creates a CertificateManagerModel. The model will be passed to the callback + // when it is ready. The caller must ensure the model does not outlive the + // |browser_context|. + static void Create(content::BrowserContext* browser_context, + const CreationCallback& callback); + + ~CertificateManagerModel(); + + bool is_user_db_available() const { return is_user_db_available_; } + + // Accessor for read-only access to the underlying NSSCertDatabase. + const net::NSSCertDatabase* cert_db() const { return cert_db_; } + + // Import private keys and certificates from PKCS #12 encoded + // |data|, using the given |password|. If |is_extractable| is false, + // mark the private key as unextractable from the module. + // Returns a net error code on failure. + int ImportFromPKCS12(net::CryptoModule* module, + const std::string& data, + const base::string16& password, + bool is_extractable, + net::CertificateList* imported_certs); + + // Import user certificate from DER encoded |data|. + // Returns a net error code on failure. + int ImportUserCert(const std::string& data); + + // Import CA certificates. + // Tries to import all the certificates given. The root will be trusted + // according to |trust_bits|. Any certificates that could not be imported + // will be listed in |not_imported|. + // |trust_bits| should be a bit field of TRUST* values from NSSCertDatabase. + // Returns false if there is an internal error, otherwise true is returned and + // |not_imported| should be checked for any certificates that were not + // imported. + bool ImportCACerts(const net::CertificateList& certificates, + net::NSSCertDatabase::TrustBits trust_bits, + net::NSSCertDatabase::ImportCertFailureList* not_imported); + + // Import server certificate. The first cert should be the server cert. Any + // additional certs should be intermediate/CA certs and will be imported but + // not given any trust. + // Any certificates that could not be imported will be listed in + // |not_imported|. + // |trust_bits| can be set to explicitly trust or distrust the certificate, or + // use TRUST_DEFAULT to inherit trust as normal. + // Returns false if there is an internal error, otherwise true is returned and + // |not_imported| should be checked for any certificates that were not + // imported. + bool ImportServerCert( + const net::CertificateList& certificates, + net::NSSCertDatabase::TrustBits trust_bits, + net::NSSCertDatabase::ImportCertFailureList* not_imported); + + // Set trust values for certificate. + // |trust_bits| should be a bit field of TRUST* values from NSSCertDatabase. + // Returns true on success or false on failure. + bool SetCertTrust(const net::X509Certificate* cert, + net::CertType type, + net::NSSCertDatabase::TrustBits trust_bits); + + // Delete the cert. Returns true on success. |cert| is still valid when this + // function returns. + bool Delete(net::X509Certificate* cert); + + private: + CertificateManagerModel(net::NSSCertDatabase* nss_cert_database, + bool is_user_db_available); + + // Methods used during initialization, see the comment at the top of the .cc + // file for details. + static void DidGetCertDBOnUIThread( + net::NSSCertDatabase* cert_db, + bool is_user_db_available, + const CreationCallback& callback); + static void DidGetCertDBOnIOThread( + const CreationCallback& callback, + net::NSSCertDatabase* cert_db); + static void GetCertDBOnIOThread(content::ResourceContext* context, + const CreationCallback& callback); + + net::NSSCertDatabase* cert_db_; + // Whether the certificate database has a public slot associated with the + // profile. If not set, importing certificates is not allowed with this model. + bool is_user_db_available_; + + DISALLOW_COPY_AND_ASSIGN(CertificateManagerModel); +}; + +#endif // CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ diff --git a/chromium_src/chrome/browser/process_singleton_posix.cc b/chromium_src/chrome/browser/process_singleton_posix.cc index 7e54d9b5d370..5c26d7b6157a 100644 --- a/chromium_src/chrome/browser/process_singleton_posix.cc +++ b/chromium_src/chrome/browser/process_singleton_posix.cc @@ -111,7 +111,7 @@ const base::FilePath::CharType kSingletonCookieFilename[] = const base::FilePath::CharType kSingletonLockFilename[] = FILE_PATH_LITERAL("SingletonLock"); const base::FilePath::CharType kSingletonSocketFilename[] = - FILE_PATH_LITERAL("SingletonSocket"); + FILE_PATH_LITERAL("SS"); // Set the close-on-exec bit on a file descriptor. // Returns 0 on success, -1 on failure. @@ -717,6 +717,9 @@ ProcessSingleton::ProcessSingleton( const NotificationCallback& notification_callback) : notification_callback_(notification_callback), current_pid_(base::GetCurrentProcId()) { + // The user_data_dir may have not been created yet. + base::CreateDirectoryAndGetError(user_data_dir, nullptr); + socket_path_ = user_data_dir.Append(kSingletonSocketFilename); lock_path_ = user_data_dir.Append(kSingletonLockFilename); cookie_path_ = user_data_dir.Append(kSingletonCookieFilename); @@ -943,6 +946,19 @@ bool ProcessSingleton::Create() { #endif } +#if defined(MAS_BUILD) + // For Mac App Store build, the tmp dir could be too long to fit + // addr->sun_path, so we need to make it as short as possible. + base::FilePath tmp_dir; + if (!base::GetTempDir(&tmp_dir)) { + LOG(ERROR) << "Failed to get temporary directory."; + return false; + } + if (!socket_dir_.Set(tmp_dir.Append("S"))) { + LOG(ERROR) << "Failed to set socket directory."; + return false; + } +#else // Create the socket file somewhere in /tmp which is usually mounted as a // normal filesystem. Some network filesystems (notably AFS) are screwy and // do not support Unix domain sockets. @@ -950,6 +966,7 @@ bool ProcessSingleton::Create() { LOG(ERROR) << "Failed to create socket directory."; return false; } +#endif // Check that the directory was created with the correct permissions. int dir_mode = 0; diff --git a/chromium_src/chrome/browser/process_singleton_win.cc b/chromium_src/chrome/browser/process_singleton_win.cc index fd4c22e7405c..b488ad457674 100644 --- a/chromium_src/chrome/browser/process_singleton_win.cc +++ b/chromium_src/chrome/browser/process_singleton_win.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/process/process.h" #include "base/process/process_info.h" #include "base/strings/string_number_conversions.h" @@ -190,6 +191,8 @@ ProcessSingleton::ProcessSingleton( user_data_dir_(user_data_dir), should_kill_remote_process_callback_( base::Bind(&TerminateAppWithError)) { + // The user_data_dir may have not been created yet. + base::CreateDirectoryAndGetError(user_data_dir, nullptr); } ProcessSingleton::~ProcessSingleton() { diff --git a/chromium_src/chrome/utility/printing_handler_win.cc b/chromium_src/chrome/utility/printing_handler_win.cc index 805cd6e343c8..b0bbac523671 100644 --- a/chromium_src/chrome/utility/printing_handler_win.cc +++ b/chromium_src/chrome/utility/printing_handler_win.cc @@ -10,11 +10,14 @@ #include "base/scoped_native_library.h" #include "chrome/common/print_messages.h" #include "content/public/utility/utility_thread.h" +#include "pdf/pdf.h" #include "printing/emf_win.h" #include "printing/page_range.h" #include "printing/pdf_render_settings.h" #include "ui/gfx/gdi_util.h" +namespace printing { + namespace { bool Send(IPC::Message* message) { @@ -25,114 +28,12 @@ void ReleaseProcessIfNeeded() { content::UtilityThread::Get()->ReleaseProcessIfNeeded(); } -class PdfFunctions { - public: - PdfFunctions() : get_pdf_doc_info_func_(NULL), - render_pdf_to_dc_func_(NULL) {} - - bool Init() { - base::FilePath module_path; - if (!PathService::Get(base::DIR_MODULE, &module_path)) - return false; - base::FilePath::StringType name(FILE_PATH_LITERAL("pdf.dll")); - pdf_lib_.Reset(base::LoadNativeLibrary(module_path.Append(name), NULL)); - if (!pdf_lib_.is_valid()) { - LOG(WARNING) << "Couldn't load PDF plugin"; - return false; - } - - get_pdf_doc_info_func_ = - reinterpret_cast( - pdf_lib_.GetFunctionPointer("GetPDFDocInfo")); - LOG_IF(WARNING, !get_pdf_doc_info_func_) << "Missing GetPDFDocInfo"; - - render_pdf_to_dc_func_ = - reinterpret_cast( - pdf_lib_.GetFunctionPointer("RenderPDFPageToDC")); - LOG_IF(WARNING, !render_pdf_to_dc_func_) << "Missing RenderPDFPageToDC"; - - if (!get_pdf_doc_info_func_ || !render_pdf_to_dc_func_) { - Reset(); - } - - return IsValid(); - } - - bool IsValid() const { - return pdf_lib_.is_valid(); - } - - void Reset() { - pdf_lib_.Reset(NULL); - } - - bool GetPDFDocInfo(const void* pdf_buffer, - int buffer_size, - int* page_count, - double* max_page_width) { - if (!get_pdf_doc_info_func_) - return false; - return get_pdf_doc_info_func_(pdf_buffer, buffer_size, page_count, - max_page_width); - } - - bool RenderPDFPageToDC(const void* pdf_buffer, - int buffer_size, - int page_number, - HDC dc, - int dpi, - int bounds_origin_x, - int bounds_origin_y, - int bounds_width, - int bounds_height, - bool fit_to_bounds, - bool stretch_to_bounds, - bool keep_aspect_ratio, - bool center_in_bounds, - bool autorotate) { - if (!render_pdf_to_dc_func_) - return false; - return render_pdf_to_dc_func_(pdf_buffer, buffer_size, page_number, - dc, dpi, bounds_origin_x, - bounds_origin_y, bounds_width, bounds_height, - fit_to_bounds, stretch_to_bounds, - keep_aspect_ratio, center_in_bounds, - autorotate); - } - - private: - // Exported by PDF plugin. - typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer, - int buffer_size, int* page_count, - double* max_page_width); - typedef bool (*RenderPDFPageToDCProc)( - const void* pdf_buffer, int buffer_size, int page_number, HDC dc, - int dpi, int bounds_origin_x, int bounds_origin_y, - int bounds_width, int bounds_height, bool fit_to_bounds, - bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds, - bool autorotate); - - RenderPDFPageToDCProc render_pdf_to_dc_func_; - GetPDFDocInfoProc get_pdf_doc_info_func_; - - base::ScopedNativeLibrary pdf_lib_; - - DISALLOW_COPY_AND_ASSIGN(PdfFunctions); -}; - -base::LazyInstance g_pdf_lib = LAZY_INSTANCE_INITIALIZER; - } // namespace PrintingHandlerWin::PrintingHandlerWin() {} PrintingHandlerWin::~PrintingHandlerWin() {} -// static -void PrintingHandlerWin::PreSandboxStartup() { - g_pdf_lib.Get().Init(); -} - bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintingHandlerWin, message) @@ -149,7 +50,7 @@ bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) { void PrintingHandlerWin::OnRenderPDFPagesToMetafile( IPC::PlatformFileForTransit pdf_transit, - const printing::PdfRenderSettings& settings) { + const PdfRenderSettings& settings) { pdf_rendering_settings_ = settings; base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit); int page_count = LoadPDF(pdf_file.Pass()); @@ -174,9 +75,6 @@ void PrintingHandlerWin::OnRenderPDFPagesToMetafileStop() { } int PrintingHandlerWin::LoadPDF(base::File pdf_file) { - if (!g_pdf_lib.Get().IsValid()) - return 0; - int64_t length64 = pdf_file.GetLength(); if (length64 <= 0 || length64 > std::numeric_limits::max()) return 0; @@ -187,8 +85,8 @@ int PrintingHandlerWin::LoadPDF(base::File pdf_file) { return 0; int total_page_count = 0; - if (!g_pdf_lib.Get().GetPDFDocInfo( - &pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) { + if (!chrome_pdf::GetPDFDocInfo(&pdf_data_.front(), pdf_data_.size(), + &total_page_count, nullptr)) { return 0; } return total_page_count; @@ -197,7 +95,7 @@ int PrintingHandlerWin::LoadPDF(base::File pdf_file) { bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number, base::File output_file, float* scale_factor) { - printing::Emf metafile; + Emf metafile; metafile.Init(); // We need to scale down DC to fit an entire page into DC available area. @@ -216,7 +114,7 @@ bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number, // The underlying metafile is of type Emf and ignores the arguments passed // to StartPage. metafile.StartPage(gfx::Size(), gfx::Rect(), 1); - if (!g_pdf_lib.Get().RenderPDFPageToDC( + if (!chrome_pdf::RenderPDFPageToDC( &pdf_data_.front(), pdf_data_.size(), page_number, @@ -237,3 +135,5 @@ bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number, metafile.FinishDocument(); return metafile.SaveTo(&output_file); } + +} // printing diff --git a/chromium_src/chrome/utility/printing_handler_win.h b/chromium_src/chrome/utility/printing_handler_win.h index 5b8c5e970f15..e7fcc5bed158 100644 --- a/chromium_src/chrome/utility/printing_handler_win.h +++ b/chromium_src/chrome/utility/printing_handler_win.h @@ -12,10 +12,10 @@ #include "printing/pdf_render_settings.h" namespace printing { + class PdfRenderSettings; struct PwgRasterSettings; struct PageRange; -} // Dispatches IPCs for printing. class PrintingHandlerWin : public UtilityMessageHandler { @@ -26,12 +26,10 @@ class PrintingHandlerWin : public UtilityMessageHandler { // IPC::Listener: bool OnMessageReceived(const IPC::Message& message) override; - static void PrintingHandlerWin::PreSandboxStartup(); - private: // IPC message handlers. void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit, - const printing::PdfRenderSettings& settings); + const PdfRenderSettings& settings); void OnRenderPDFPagesToMetafileGetPage( int page_number, IPC::PlatformFileForTransit output_file); @@ -43,9 +41,11 @@ class PrintingHandlerWin : public UtilityMessageHandler { float* scale_factor); std::vector pdf_data_; - printing::PdfRenderSettings pdf_rendering_settings_; + PdfRenderSettings pdf_rendering_settings_; DISALLOW_COPY_AND_ASSIGN(PrintingHandlerWin); }; +} // namespace printing + #endif // CHROME_UTILITY_PRINTING_HANDLER_WIN_H_ diff --git a/common.gypi b/common.gypi index a9f067bcc54e..1088beb1b7b8 100644 --- a/common.gypi +++ b/common.gypi @@ -15,7 +15,7 @@ 'openssl_fips': '', 'openssl_no_asm': 1, 'node_release_urlbase': 'https://atom.io/download/atom-shell', - 'node_byteorder': 'Electron @@ -89,11 +132,29 @@ }; -

- -

+
+ + + + Electron + + + + + +
+ Docs + Repository + Blog +
+
@@ -112,13 +173,13 @@

You can read the guide in Electron's to learn how to write one. diff --git a/default_app/main.js b/default_app/main.js index 43c8d7298046..cf71277c19d5 100644 --- a/default_app/main.js +++ b/default_app/main.js @@ -147,7 +147,7 @@ app.once('ready', function () { label: 'Documentation', click: function () { shell.openExternal( - `https://github.com/atom/electron/tree/v${process.versions.electron}/docs#readme` + `https://github.com/electron/electron/tree/v${process.versions.electron}/docs#readme` ) } }, @@ -160,7 +160,7 @@ app.once('ready', function () { { label: 'Search Issues', click: function () { - shell.openExternal('https://github.com/atom/electron/issues') + shell.openExternal('https://github.com/electron/electron/issues') } } ] @@ -257,7 +257,7 @@ function loadApplicationPackage (packagePath) { dialog.showErrorBox( 'Error opening app', 'The app provided is not a valid Electron app, please read the docs on how to write one:\n' + - `https://github.com/atom/electron/tree/v${process.versions.electron}/docs + `https://github.com/electron/electron/tree/v${process.versions.electron}/docs ${e.toString()}` ) diff --git a/docs-translations/es/README.md b/docs-translations/es/README.md index e69e76b1c4c7..c2358bbb0161 100644 --- a/docs-translations/es/README.md +++ b/docs-translations/es/README.md @@ -35,7 +35,7 @@ * [content-tracing](../../docs/api/content-tracing.md) * [dialog](../../docs/api/dialog.md) * [global-shortcut](../../docs/api/global-shortcut.md) -* [ipc (proceso principal)](../../docs/api/ipc-main-process.md) +* [ipc (proceso principal)](../../docs/api/ipc-main.md) * [menu](../../docs/api/menu.md) * [menu-item](../../docs/api/menu-item.md) * [power-monitor](../../docs/api/power-monitor.md) @@ -66,6 +66,6 @@ * [Diferencias Técnicas con NW.js (anteriormente conocido como node-webkit)](development/atom-shell-vs-node-webkit.md) * [Repaso del Sistema de Compilación](development/build-system-overview.md) * [Instrucciones de Compilación (Mac)](development/build-instructions-osx.md) -* [Instrucciones de Compilación (Windows)](../../development/build-instructions-windows.md) +* [Instrucciones de Compilación (Windows)](development/build-instructions-windows.md) * [Instrucciones de Compilación (Linux)](development/build-instructions-linux.md) -* [Configurando un Servidor de Símbolos en el depurador](../../development/setting-up-symbol-server.md) +* [Configurando un Servidor de Símbolos en el depurador](development/setting-up-symbol-server.md) diff --git a/docs-translations/es/api/synopsis.md b/docs-translations/es/api/synopsis.md index 534fafcf2f7c..54c264a1aa74 100644 --- a/docs-translations/es/api/synopsis.md +++ b/docs-translations/es/api/synopsis.md @@ -1,4 +1,4 @@ -# Synopsis +# Sinopsis Todos los [Módulos integrados de Node.js](http://nodejs.org/api/) se encuentran disponibles en Electron y módulos de terceros son támbien totalmente compatibles diff --git a/docs-translations/es/development/atom-shell-vs-node-webkit.md b/docs-translations/es/development/atom-shell-vs-node-webkit.md index 434e67658074..8d0170673294 100644 --- a/docs-translations/es/development/atom-shell-vs-node-webkit.md +++ b/docs-translations/es/development/atom-shell-vs-node-webkit.md @@ -31,4 +31,4 @@ Si usted es un usuario experimentado NW.js, usted debe estar familiarizado con e Mediante el uso de la característica [multi-contexto](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/) de Node, Electron no introduce un nuevo contexto JavaScript en páginas web.Resultados de búsqueda -[node-bindings]: https://github.com/atom/electron/tree/master/atom/common +[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs-translations/es/development/build-instructions-linux.md b/docs-translations/es/development/build-instructions-linux.md index 28ad828fa709..58beef4ecf04 100644 --- a/docs-translations/es/development/build-instructions-linux.md +++ b/docs-translations/es/development/build-instructions-linux.md @@ -29,7 +29,7 @@ Si usted planea construir Electron en una máquina virtual, necesitará un disp #Obteniendo el codigo -`$ git clone https://github.com/atom/electron.git` +`$ git clone https://github.com/electron/electron.git` #Bootstrapping (Arranque) diff --git a/docs-translations/es/development/build-instructions-osx.md b/docs-translations/es/development/build-instructions-osx.md index 6e2d7b7f392e..2ac3641e8361 100644 --- a/docs-translations/es/development/build-instructions-osx.md +++ b/docs-translations/es/development/build-instructions-osx.md @@ -13,7 +13,7 @@ Si está utilizando Python descargado de Homebrew, también es necesario instal #Obtener el Código -`$ git clone https://github.com/atom/electron.git` +`$ git clone https://github.com/electron/electron.git` #Bootstrapping (arranque) diff --git a/docs-translations/es/development/coding-style.md b/docs-translations/es/development/coding-style.md index de02a33a86d3..e2f364d8b9c2 100644 --- a/docs-translations/es/development/coding-style.md +++ b/docs-translations/es/development/coding-style.md @@ -34,4 +34,4 @@ siguientes reglas: Al crear una nueva API, nosotros deberíamos preferir usar metodos `get` y `set` en vez de usar el estilo de jQuery que utiliza una sola función. Por ejemplo, se prefiere `.getText()` y `.setText()` por sobre `.text([text])`. Hay una -[discusión](https://github.com/atom/electron/issues/46) sobre esto. +[discusión](https://github.com/electron/electron/issues/46) sobre esto. diff --git a/docs-translations/es/styleguide.md b/docs-translations/es/styleguide.md index 4948035ffffe..18fa1aa3bb3a 100644 --- a/docs-translations/es/styleguide.md +++ b/docs-translations/es/styleguide.md @@ -43,7 +43,7 @@ Para agregar otro set (o un set parcial): - Actualizar el `README.md` dentro del subdirectorio del lenguaje apuntando a los archivos que has traducido. - Agregar un enlace al folder de tu traducción en la sección principal Electron -[README](https://github.com/atom/electron#documentation-translations). +[README](https://github.com/electron/electron#documentation-translations). ## Leyendo la Documentación de Electron diff --git a/docs-translations/es/tutorial/application-packaging.md b/docs-translations/es/tutorial/application-packaging.md index c0cca7ecd916..0e46a44d2b48 100644 --- a/docs-translations/es/tutorial/application-packaging.md +++ b/docs-translations/es/tutorial/application-packaging.md @@ -24,8 +24,8 @@ $ asar pack your-app app.asar ## Utilizando los paquetes `asar` -En Electron existen dos tipos de APIs: las APIs de Node, proveídas por Node.js, -y las APIs Web, proveídas por Chromium. Ambas APIs soportan la lecutra de paquetes `asar`. +En Electron existen dos tipos de APIs: las APIs de Node, provistas por Node.js, +y las APIs Web, provistas por Chromium. Ambas APIs soportan la lectura de paquetes `asar`. ### API Node @@ -92,7 +92,7 @@ $.get('file:///path/to/example.asar/file.txt', function(data) { ### Utilizando un paquete `asar` como un archivo normal En algunas situaciones necesitaremos acceder al paquete `asar` como archivo, por ejemplo, -si necesitaramos verificar la integridad del archivo con un checksum. +si necesitáramos verificar la integridad del archivo con un checksum. Para casos así es posible utilizar el módulo `original-fs`, que provee la API `fs` original: ```javascript @@ -105,7 +105,7 @@ originalFs.readFileSync('/path/to/example.asar'); A pesar de que hemos intentado que los paquetes `asar` funcionen como directorios de la mejor forma posible, aún existen limitaciones debido a la naturaleza de bajo nivel de la API Node. -### Los paquetes son de sólo lecutra +### Los paquetes son de sólo lectura Los paquetes `asar` no pueden ser modificados, por lo cual todas las funciones que modifiquen archivos no funcionarán. @@ -127,12 +127,12 @@ Las APIs que requieren el desempaquetamiento adicional son: * `child_process.execFile` * `fs.open` * `fs.openSync` -* `process.dlopen` - Utilizado po `require` en los módulos nativos +* `process.dlopen` - Utilizado por `require` en los módulos nativos ### Información falsa en `fs.stat` El objeto `Stats` retornado por `fs.stat` y otras funciones relacionadas, -no es preciso, ya que los archivos del paquete `asar` no existen el sistema de archivos. +no es preciso, ya que los archivos del paquete `asar` no existen en el sistema de archivos. La utilización del objeto `Stats` sólo es recomendable para obtener el tamaño del archivo y/o comprobar el tipo de archivo. @@ -143,8 +143,8 @@ Como se menciona arriba, algunas APIs de Node desempaquetarán archivos cuando e que los referencie, además de los problemas de rendimiento que esto podría ocasionar, también podría accionar alertas falsas en software antivirus. -Para lidiar con esto, puedes desempaquetar algunos archivos utilizando la opción `--unpack`, -a continuación un ejemplo que excluye las librerías compartidas de los módulos nativos: +Para lidiar con esto, puedes desempaquetar algunos archivos utilizando la opción `--unpack`. +A continuación, un ejemplo que excluye las librerías compartidas de los módulos nativos: ```bash $ asar pack app app.asar --unpack *.node diff --git a/docs-translations/es/tutorial/devtools-extension.md b/docs-translations/es/tutorial/devtools-extension.md index f54c3e0eaa83..495f56058d5f 100644 --- a/docs-translations/es/tutorial/devtools-extension.md +++ b/docs-translations/es/tutorial/devtools-extension.md @@ -1,13 +1,13 @@ # Extensión DevTools -Para facilitar la depuración, Electron provee un soporte básico para la extensión -[Chrome DevTools Extension][devtools-extension]. +Para facilitar la depuración, Electron provee un soporte básico para la extensión +[Chrome DevTools][devtools-extension]. Para la mayoría de las extensiones devtools, simplemente puedes descargar el código fuente y utilizar `BrowserWindow.addDevToolsExtension` para cargarlas, las extensiones cargadas serán recordadas para que no sea necesario llamar a la función cada vez que creas una ventana. -Por ejemplo, para usar la extensión [React DevTools Extension](https://github.com/facebook/react-devtools), primero debes descargar el código fuente: +Por ejemplo, para usar la extensión [React DevTools](https://github.com/facebook/react-devtools), primero debes descargar el código fuente: ```bash $ cd /some-directory diff --git a/docs-translations/es/tutorial/quick-start.md b/docs-translations/es/tutorial/quick-start.md index b038f7cb08d6..a760fccad2c8 100644 --- a/docs-translations/es/tutorial/quick-start.md +++ b/docs-translations/es/tutorial/quick-start.md @@ -1,8 +1,6 @@ -# Intro - ## Introducción -Electron permite la creación de aplicaciones de escritorio utilizando JavaScript puro, a través de un runtime con APIs nativas. Puedes verlo como una variante de io.js, enfocado en aplicaciones de escritorio, en vez de servidores web. +Electron permite la creación de aplicaciones de escritorio utilizando JavaScript puro, a través de un runtime con APIs nativas. Puedes verlo como una variante de io.js, enfocado a aplicaciones de escritorio, en vez de servidores web. Esto no significa que Electron sea un binding de librerías GUI para JavaScript. Electron utiliza páginas web como su GUI, por lo cual puedes verlo como un navegador Chromium mínimo, @@ -147,4 +145,4 @@ En OS X: $ ./Electron.app/Contents/MacOS/Electron your-app/ ``` -`Electron.app` es parte del paquete de release de Electron, puedes descargarlo [aquí](https://github.com/atom/electron/releases). +`Electron.app` es parte del paquete de release de Electron, puedes descargarlo [aquí](https://github.com/electron/electron/releases). diff --git a/docs-translations/es/tutorial/using-selenium-and-webdriver.md b/docs-translations/es/tutorial/using-selenium-and-webdriver.md index 7d9989057056..919a889d38dd 100644 --- a/docs-translations/es/tutorial/using-selenium-and-webdriver.md +++ b/docs-translations/es/tutorial/using-selenium-and-webdriver.md @@ -8,7 +8,7 @@ De [ChromeDriver - WebDriver for Chrome][chrome-driver]: > el protocolo de WebDriver para Chromium. Se encuentra en desarrollo por los miembros de > Chromium y WebDriver. -En la página de [lanzamientos](https://github.com/atom/electron/releases) de Electron encontrarás paquetes de `chromedriver`. +En la página de [lanzamientos](https://github.com/electron/electron/releases) de Electron encontrarás paquetes de `chromedriver`. ## Ajustando parámetros con WebDriverJs @@ -65,7 +65,7 @@ driver.quit(); ## Workflow -Para probar tu aplicación sin recompilar Electron, simplemente [copia](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md) las fuentes de tu aplicación en el directorio de recursos de Electron. +Para probar tu aplicación sin recompilar Electron, simplemente [copia](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md) las fuentes de tu aplicación en el directorio de recursos de Electron. [chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ diff --git a/docs-translations/fr-FR/styleguide.md b/docs-translations/fr-FR/styleguide.md index 5fe781773c12..b683ee68aad7 100644 --- a/docs-translations/fr-FR/styleguide.md +++ b/docs-translations/fr-FR/styleguide.md @@ -43,7 +43,7 @@ Pour ajouter une nouvelle langue (ou commencer) : - Traduire les fichiers. - Mettre à jour le `README.md` à l'intérieur du dossier de langue en mettant les liens vers les fichiers traduits. -- Ajouter un lien vers le nouveau dossier de langue dans le [README](https://github.com/atom/electron#documentation-translations) +- Ajouter un lien vers le nouveau dossier de langue dans le [README](https://github.com/electron/electron#documentation-translations) principal d'Electron. ## Lire la documentation d'Electron diff --git a/docs-translations/jp/api/frameless-window.md b/docs-translations/jp/api/frameless-window.md index 0b1e055602f8..4478387877e1 100644 --- a/docs-translations/jp/api/frameless-window.md +++ b/docs-translations/jp/api/frameless-window.md @@ -29,7 +29,7 @@ var win = new BrowserWindow({ transparent: true, frame: false }); ### 制限 -* 透明領域をクリックすることはできません。この問題を解決するためにウィンドウの輪郭を設定するAPIを導入しようとしています。詳細は、[our issue](https://github.com/atom/electron/issues/1335) を参照してください。 +* 透明領域をクリックすることはできません。この問題を解決するためにウィンドウの輪郭を設定するAPIを導入しようとしています。詳細は、[our issue](https://github.com/electron/electron/issues/1335) を参照してください。 * 透明なウィンドウはサイズ変更できません。いくつかのプラットフォーム上では、`resizable`の`true`設定は、いくつかのプラットフォーム上で、動作を停止する透明ウィンドウを作成するかもしれません。 * `blur`フィルターはウェブページのみに適用され、ウィンドウの下のコンテンツ(例えば、ユーザーのシステム上でほかのアプリケーションを開く)に、ぼやける効果を適用する方法はありません。 * Windows オペレーティングシステム上では、DMMが無効のとき透明なウィンドウは動作しません。 diff --git a/docs-translations/jp/api/synopsis.md b/docs-translations/jp/api/synopsis.md index 683f5611eb12..89d8973a14ba 100644 --- a/docs-translations/jp/api/synopsis.md +++ b/docs-translations/jp/api/synopsis.md @@ -65,4 +65,4 @@ require('electron').hideInternalModules() [gui]: https://en.wikipedia.org/wiki/Graphical_user_interface [desctructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment -[issue-387]: https://github.com/atom/electron/issues/387 +[issue-387]: https://github.com/electron/electron/issues/387 diff --git a/docs-translations/jp/tutorial/devtools-extension.md b/docs-translations/jp/tutorial/devtools-extension.md index 85eff391a43b..2c8816a666f8 100644 --- a/docs-translations/jp/tutorial/devtools-extension.md +++ b/docs-translations/jp/tutorial/devtools-extension.md @@ -4,7 +4,7 @@ DevToolsエクステンションのために、ソースコードをダウンローし、`BrowserWindow.addDevToolsExtension` APIを使って読み込みます。読み込んだエクステンションは維持されているので、ウィンドウを作成するとき、毎回APIをコールする必要はありません。 -** NOTE: React DevTools は動作しません。issue https://github.com/atom/electron/issues/915 でフォローしています** +** NOTE: React DevTools は動作しません。issue https://github.com/electron/electron/issues/915 でフォローしています** 例えば、[React DevTools Extension](https://github.com/facebook/react-devtools)を使うために、最初にソースコードをダウンロードする必要があります。 diff --git a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md index 47d7a76b925b..c4bbf0706eba 100644 --- a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md +++ b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md @@ -140,5 +140,5 @@ ERNの同意を取得するには、 [How to legally submit an app to Apple’s [create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html [submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html [app-sandboxing]: https://developer.apple.com/app-sandboxing/ -[issue-3871]: https://github.com/atom/electron/issues/3871 +[issue-3871]: https://github.com/electron/electron/issues/3871 [ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ diff --git a/docs-translations/jp/tutorial/quick-start.md b/docs-translations/jp/tutorial/quick-start.md index 4f2e5c9a52ef..4a4a7f1692d5 100644 --- a/docs-translations/jp/tutorial/quick-start.md +++ b/docs-translations/jp/tutorial/quick-start.md @@ -151,7 +151,7 @@ $ ./electron/electron your-app/ $ ./Electron.app/Contents/MacOS/Electron your-app/ ``` -`Electron.app` は Electron のリリースパッケージの一部で、[ここ](https://github.com/atom/electron/releases) からダウンロードできます。 +`Electron.app` は Electron のリリースパッケージの一部で、[ここ](https://github.com/electron/electron/releases) からダウンロードできます。 ### Run as a distribution @@ -159,13 +159,13 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/ ### 試してみよう -このチュートリアルのコードは [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) リポジトリから clone して実行できます。 +このチュートリアルのコードは [`atom/electron-quick-start`](https://github.com/electron/electron-quick-start) リポジトリから clone して実行できます。 **注記**:例を試すには、[Git](https://git-scm.com) と [Node.js](https://nodejs.org/en/download/) ([npm](https://npmjs.org) もこれに含まれています) が必要です。 ```bash # Clone the repository -$ git clone https://github.com/atom/electron-quick-start +$ git clone https://github.com/electron/electron-quick-start # Go into the repository $ cd electron-quick-start # Install dependencies and run the app diff --git a/docs-translations/jp/tutorial/using-native-node-modules.md b/docs-translations/jp/tutorial/using-native-node-modules.md index c0bce4fab8d8..eced3d36a2b6 100644 --- a/docs-translations/jp/tutorial/using-native-node-modules.md +++ b/docs-translations/jp/tutorial/using-native-node-modules.md @@ -4,7 +4,7 @@ Electronは、ネイティブのNodeモジュールをサポートしていま ## ネイティブNodeモジュールとの互換性 -Nodeが新しいV8バージョンを使用し始めた時、Nativeモジュールは動作しなくなるかもしれません。ElectronでNativeモジュールが動作するかどうかを確認するために、Electronで使用する内部のNodeバージョンがサポートしているかを確認すべきです。ElectronでNodeが使用しているバージョンを確認するには、[releases](https://github.com/atom/electron/releases)ページを見るか、`process.version` (例えば [Quick Start](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md)を見てください)を使用してください。 +Nodeが新しいV8バージョンを使用し始めた時、Nativeモジュールは動作しなくなるかもしれません。ElectronでNativeモジュールが動作するかどうかを確認するために、Electronで使用する内部のNodeバージョンがサポートしているかを確認すべきです。ElectronでNodeが使用しているバージョンを確認するには、[releases](https://github.com/electron/electron/releases)ページを見るか、`process.version` (例えば [Quick Start](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md)を見てください)を使用してください。 Nodeの複数バージョンを簡単にサポートできるので、あなたのモジュールに [NAN](https://github.com/nodejs/nan/) を使うことを検討してください。古いバージョンからElectronで動作するNodeの新しいバージョンへ移植するのに役立ちます。 diff --git a/docs-translations/jp/tutorial/using-selenium-and-webdriver.md b/docs-translations/jp/tutorial/using-selenium-and-webdriver.md index a1fd0f21d7f9..0250436844b2 100644 --- a/docs-translations/jp/tutorial/using-selenium-and-webdriver.md +++ b/docs-translations/jp/tutorial/using-selenium-and-webdriver.md @@ -112,7 +112,7 @@ client ## ワークフロー -Electronはリビルドせずにアプリケーションをテストするために、単純にElectronのリソースディレクトリでアプリのソースを[配置します](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md)。 +Electronはリビルドせずにアプリケーションをテストするために、単純にElectronのリソースディレクトリでアプリのソースを[配置します](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md)。 もしくは、アプリのフォルダーを引数にしてElectronバイナリを実行します。これは、Electronのリソースディレクトリにアプリをコピー&ペーストする必要性を除きます。 diff --git a/docs-translations/ko-KR/README.md b/docs-translations/ko-KR/README.md index 8c5912f604b0..717bfd5ef30b 100644 --- a/docs-translations/ko-KR/README.md +++ b/docs-translations/ko-KR/README.md @@ -69,7 +69,7 @@ Electron에 대해 자주 묻는 질문이 있습니다. 이슈를 생성하기 * [webContents](api/web-contents.md) * [Tray](api/tray.md) -### 랜더러 프로세스에서 사용할 수 있는 모듈 (웹 페이지): +### 렌더러 프로세스에서 사용할 수 있는 모듈 (웹 페이지): * [desktopCapturer](api/desktop-capturer.md) * [ipcRenderer](api/ipc-renderer.md) @@ -93,4 +93,5 @@ Electron에 대해 자주 묻는 질문이 있습니다. 이슈를 생성하기 * [빌드 설명서 (OS X)](development/build-instructions-osx.md) * [빌드 설명서 (Windows)](development/build-instructions-windows.md) * [빌드 설명서 (Linux)](development/build-instructions-linux.md) -* [디버거에서 디버그 심볼 서버 설정](development/setting-up-symbol-server.md) +* [디버그 설명서 (Windows)](development/debug-instructions-windows.md) +* [디버거 심볼 서버 설정](development/setting-up-symbol-server.md) diff --git a/docs-translations/ko-KR/api/accelerator.md b/docs-translations/ko-KR/api/accelerator.md index 90adf414dc39..a0eb55e87025 100644 --- a/docs-translations/ko-KR/api/accelerator.md +++ b/docs-translations/ko-KR/api/accelerator.md @@ -5,8 +5,8 @@ Accelerator는 키보드 단축키를 표현하는 문자열입니다, 여러 예제: -* `Command+A` -* `Ctrl+Shift+Z` +* `CommandOrControl+A` +* `CommandOrControl+Shift+Z` ## 플랫폼에 관련하여 주의할 점 @@ -14,6 +14,9 @@ Linux와 Windows에서는 `Command`키가 없으므로 작동하지 않습니다 `CommandOrControl`을 사용하면 OS X의 `Command`와 Linux, Windows의 `Control` 모두 지원할 수 있습니다. +`Option` 대신 `Alt`을 사용하는게 좋습니다. `Option` 키는 OS X에만 있으므로 +모든 플랫폼에서 사용할 수 있는 `Alt` 키를 권장합니다. + `Super`키는 Windows와 Linux 에서는 `윈도우`키를, OS X에서는 `Cmd`키로 맵핑됩니다. ## 사용 가능한 혼합키 diff --git a/docs-translations/ko-KR/api/app.md b/docs-translations/ko-KR/api/app.md index ff4269ea8295..ff6b4640ad2f 100644 --- a/docs-translations/ko-KR/api/app.md +++ b/docs-translations/ko-KR/api/app.md @@ -353,6 +353,10 @@ npm 모듈 규칙에 따라 대부분의 경우 `package.json`의 `name` 필드 현재 어플리케이션의 [로케일](https://ko.wikipedia.org/wiki/%EB%A1%9C%EC%BC%80%EC%9D%BC)을 반환합니다. +**참고:** 패키징된 앱을 배포할 때, `locales` 폴더도 같이 배포해야 합니다. + +**참고:** Windows에선 `ready` 이벤트가 발생한 이후에 이 메서드를 사용해야 합니다. + ### `app.addRecentDocument(path)` _OS X_ _Windows_ * `path` String @@ -517,6 +521,19 @@ if (browserOptions.transparent) { 이 메서드는 시스템이 다크 모드 상태인 경우 `true`를 반환하고 아닐 경우 `false`를 반환합니다. +### `app.importCertificate(options, callback)` _LINUX_ + +* `options` Object + * `certificate` String - pkcs12 파일의 위치. + * `password` String - 인증서의 암호. +* `callback` Function + * `result` Integer - 가져오기의 결과. + +pkcs12 형식으로된 인증서를 플랫폼 인증서 저장소로 가져옵니다. `callback`은 가져오기의 +결과를 포함하는 `result` 객체를 포함하여 호출됩니다. 값이 `0` 일 경우 성공을 의미하며 +다른 값은 모두 Chrominum의 [net_error_list](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h)에 +따라 실패를 의미합니다. + ### `app.commandLine.appendSwitch(switch[, value])` Chrominum의 명령줄에 스위치를 추가합니다. `value`는 추가적인 값을 뜻하며 옵션입니다. diff --git a/docs-translations/ko-KR/api/auto-updater.md b/docs-translations/ko-KR/api/auto-updater.md index e5121d0f9b1d..e699108a649c 100644 --- a/docs-translations/ko-KR/api/auto-updater.md +++ b/docs-translations/ko-KR/api/auto-updater.md @@ -2,8 +2,14 @@ 이 모듈은 `Squirrel` 자동 업데이트 프레임워크의 인터페이스를 제공합니다. -[electron-release-server](https://github.com/ArekSredzki/electron-release-server)를 -포크하면 어플리케이션을 배포하기 위한 멀티 플랫폼 릴리즈 서버를 손쉽게 구축할 수 있습니다. +다음 프로젝트 중 하나를 택하여 사용하면, 어플리케이션을 배포하기 위한 멀티 플랫폼 +릴리즈 서버를 손쉽게 구축할 수 있습니다: + +- [electron-release-server][electron-release-server]: *완벽하게 모든 기능을 +지원하는 electron 어플리케이션을 위한 자가 호스트 릴리즈 서버입니다. auto-updater와 +호환됩니다* +- [squirrel-updates-server][squirrel-updates-server]: *GitHub 릴리즈를 사용하는 +Squirrel.Mac 와 Squirrel.Windows를 위한 간단한 node.js 기반 서버입니다* ## 플랫폼별 참고 사항 @@ -16,6 +22,9 @@ OS X에선 `auto-updater` 모듈이 [Squirrel.Mac][squirrel-mac]를 기반으로 따라서 이 모듈을 작동시키기 위해 특별히 준비해야 할 작업은 없습니다. 서버 사이드 요구 사항은 [서버 지원][server-support]을 참고하세요. +**참고:** Mac OS X에서 자동 업데이트를 지원하려면 반드시 사인이 되어있어야 합니다. +이것은 `Squirrel.Mac`의 요구사항입니다. + ### Windows Windows에선 `auto-updater` 모듈을 사용하기 전에 어플리케이션을 사용자의 장치에 @@ -95,5 +104,7 @@ Returns: [squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac [server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support [squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows -[installer]: https://github.com/atom/grunt-electron-installer +[installer]: https://github.com/electron/grunt-electron-installer [app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx +[electron-release-server]: https://github.com/ArekSredzki/electron-release-server +[squirrel-updates-server]: https://github.com/Aluxian/squirrel-updates-server diff --git a/docs-translations/ko-KR/api/browser-window.md b/docs-translations/ko-KR/api/browser-window.md index 06e31e9fba56..9ba61bea57f2 100644 --- a/docs-translations/ko-KR/api/browser-window.md +++ b/docs-translations/ko-KR/api/browser-window.md @@ -8,7 +8,7 @@ // 메인 프로세스에서 const BrowserWindow = require('electron').BrowserWindow; -// 또는 랜더러 프로세스에서 +// 또는 렌더러 프로세스에서 const BrowserWindow = require('electron').remote.BrowserWindow; var win = new BrowserWindow({ width: 800, height: 600, show: false }); @@ -81,8 +81,7 @@ win.show(); * `enableLargerThanScreen` Boolean - 윈도우 크기가 화면 크기보다 크게 재조정 될 수 있는지 여부. 기본값은 `false`입니다. * `backgroundColor` String - `#66CD00` 와 `#FFF`, `#80FFFFFF` (알파 지원됨) 같이 - 16진수로 표현된 윈도우의 배경 색. 기본값은 Linux와 Windows에선 `#000` (검정)이며, - Mac에선 `#FFF` (또는, transparent(투명)일 경우 clear(색 없음)로 설정) + 16진수로 표현된 윈도우의 배경 색. 기본값은 `#FFF` (white). * `hasShadow` Boolean - 윈도우가 그림자를 가질지 여부를 지정합니다. 이 속성은 OS X에서만 구현되어 있습니다. 기본값은 `true`입니다. * `darkTheme` Boolean - 설정에 상관 없이 무조건 어두운 윈도우 테마를 사용합니다. @@ -160,7 +159,7 @@ win.show(); 기본값은 `false`입니다. * `experimentalCanvasFeatures` Boolean - Chrome의 실험적인 캔버스(canvas) 기능을 활성화합니다. 기본값은 `false`입니다. -* `directWrite` Boolean - Windows에서 폰트 랜더링을 위해 DirectWrite를 +* `directWrite` Boolean - Windows에서 폰트 렌더링을 위해 DirectWrite를 사용하는지를 지정합니다. 기본값은 `true`입니다. * `blinkFeatures` String - `CSSVariables,KeyboardEventKey`같은 `,`로 구분된 기능 문자열들의 리스트입니다. 지원하는 전체 기능 문자열들은 @@ -174,6 +173,8 @@ win.show(); * `defaultMonospaceFontSize` Integer - 기본값 `13`. * `minimumFontSize` Integer - 기본값 `0`. * `defaultEncoding` String - 기본값 `ISO-8859-1`. +* `backgroundThrottling` Boolean - 페이지가 백그라운드 상태에 진입할 때 애니메이션과 + 타이머에 스로틀을 적용할지 여부입니다. 기본값은 `true`입니다. ## Events @@ -296,11 +297,20 @@ __참고__: OS X에선 이 이벤트가 그저 `moved` 이벤트의 별칭(alias ### Event: 'app-command' _Windows_ +Returns: + +* `event` Event +* `command` String + [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx)가 호출됐을 때 발생하는 이벤트입니다. 이 이벤트는 일반적으로 키보드 미디어 키 또는 브라우저 커맨드(기본 동작 키)에 관련되어 있습니다. 예를 들어 Windows에서 작동하는 몇몇 마우스는 "뒤로가기" 같은 동작을 포함하고 있습니다. +반환되는 커맨드들은 모두 소문자화되며 언더스코어(`_`)는 하이픈(`-`)으로 변경되며 +`APPCOMMAND_` 접두어는 제거됩니다. +e.g. `APPCOMMAND_BROWSER_BACKWARD` 는 `browser-backward`와 같이 반환됩니다. + ```javascript someWindow.on('app-command', function(e, cmd) { // 마우스의 뒤로가기 버튼을 눌렀을 때 뒤로가기 탐색을 실행합니다 @@ -660,6 +670,17 @@ var win = new BrowserWindow({ width: 800, height: 600 }); **참고:** 웹 페이지의 제목과 네이티브 윈도우의 제목은 서로 다를 수 있습니다. +### `win.setSheetOffset(offset)` _OS X_ + +Mac OS X에서 시트를 부착할 위치를 지정합니다. 기본적으로 시트는 윈도우의 프레임 바로 +아래의 위치에 부착됩니다. 아마도 이 기능은 보통 다음과 같이 HTML 렌더링된 툴바 밑에 +표시하기 위해 사용할 것입니다: + +```javascript +var toolbarRect = document.getElementById('toolbar').getBoundingClientRect(); +win.setSheetOffset(toolbarRect.height); +``` + ### `win.flashFrame(flag)` * `flag` Boolean @@ -890,4 +911,4 @@ Linux 플랫폼에선 Unity 데스크톱 환경만 지원합니다. 그리고 윈도우에서 일어나는 모든 마우스 이벤트를 무시합니다. -[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 +[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=576 diff --git a/docs-translations/ko-KR/api/chrome-command-line-switches.md b/docs-translations/ko-KR/api/chrome-command-line-switches.md index defa1e04841b..babddd327559 100644 --- a/docs-translations/ko-KR/api/chrome-command-line-switches.md +++ b/docs-translations/ko-KR/api/chrome-command-line-switches.md @@ -15,10 +15,6 @@ app.on('ready', function() { }); ``` -## --client-certificate=`path` - -`path`를 클라이언트 인증서로 설정합니다. - ## --ignore-connections-limit=`domains` `domains` 리스트(`,`로 구분)의 연결 제한을 무시합니다. @@ -121,9 +117,9 @@ SSL 암호화를 비활성화할 대상 목록을 지정합니다. (`,`로 구 ## --disable-renderer-backgrounding -Chromium이 랜더러 프로세스의 보이지 않는 페이지의 우선순위를 낮추는 것을 방지합니다. +Chromium이 렌더러 프로세스의 보이지 않는 페이지의 우선순위를 낮추는 것을 방지합니다. -이 플래그는 전역적이며 모든 랜더러 프로세스에 적용됩니다. 만약 하나의 윈도우창에만 +이 플래그는 전역적이며 모든 렌더러 프로세스에 적용됩니다. 만약 하나의 윈도우창에만 스로틀링을 비활성화하고 싶다면 [조용한 오디오를 재생하는][play-silent-audio] 핵을 사용할 수 있습니다. diff --git a/docs-translations/ko-KR/api/crash-reporter.md b/docs-translations/ko-KR/api/crash-reporter.md index c1437571d3f2..2269742bcbff 100644 --- a/docs-translations/ko-KR/api/crash-reporter.md +++ b/docs-translations/ko-KR/api/crash-reporter.md @@ -20,7 +20,7 @@ crashReporter.start({ 있습니다: * [socorro](https://github.com/mozilla/socorro) -* [mini-breakpad-server](https://github.com/atom/mini-breakpad-server) +* [mini-breakpad-server](https://github.com/electron/mini-breakpad-server) ## Methods @@ -42,8 +42,8 @@ crashReporter.start({ **참고:** OS X에선 Windows와 Linux의 `breakpad`와 달리 새로운 `crashpad` 클라이언트를 사용합니다. 오류 수집 기능을 활성화 시키려면 오류를 수집하고 싶은 메인 -프로세스나 랜더러 프로세스에서 `crashReporter.start` 메서드를 호출하여 `crashpad`를 -초기화 해야합니다. +프로세스나 렌더러 프로세스에서 `crashReporter.start` 메서드를 호출하여 `crashpad`를 +초기화해야 합니다. ### `crashReporter.getLastCrashReport()` diff --git a/docs-translations/ko-KR/api/desktop-capturer.md b/docs-translations/ko-KR/api/desktop-capturer.md index 5a531bf44ab5..3b4f8c719832 100644 --- a/docs-translations/ko-KR/api/desktop-capturer.md +++ b/docs-translations/ko-KR/api/desktop-capturer.md @@ -65,13 +65,14 @@ function getUserMediaError(e) { `sources`는 `Source` 객체의 배열입니다. 각 `Source`는 캡쳐된 화면과 독립적인 윈도우를 표현합니다. 그리고 다음과 같은 속성을 가지고 있습니다: + * `id` String - `navigator.webkitGetUserMedia` API에서 사용할 수 있는 캡쳐된 윈도우 또는 화면의 id입니다. 포맷은 `window:XX` 또는 `screen:XX`로 표현되며 `XX` 는 무작위로 생성된 숫자입니다. * `name` String - 캡쳐된 화면과 윈도우에 대해 묘사된 이름입니다. 만약 소스가 화면이라면, `Entire Screen` 또는 `Screen `가 될 것이고 소스가 윈도우라면, 해당 윈도우의 제목이 반환됩니다. -* `thumbnail` [NativeImage](NativeImage.md) - 섬네일 이미지. +* `thumbnail` [NativeImage](native-image.md) - 섬네일 네이티브 이미지. **참고:** `source.thumbnail`의 크기는 언제나 `options`의 `thumnbailSize`와 같다고 보장할 수 없습니다. 섬네일의 크기는 화면과 윈도우의 크기에 의존하여 조정됩니다. diff --git a/docs-translations/ko-KR/api/dialog.md b/docs-translations/ko-KR/api/dialog.md index 9147f1c5bdca..cbb1afc71ae4 100644 --- a/docs-translations/ko-KR/api/dialog.md +++ b/docs-translations/ko-KR/api/dialog.md @@ -12,8 +12,12 @@ const dialog = require('electron').dialog; console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', 'multiSelections' ]})); ``` -**OS X 참고**: 대화 상자를 시트처럼 보여지게 하려면 `browserWindow` 인자에 -`BrowserWindow` 객체의 참조를 제공하면 됩니다. +대화 상자는 Electron의 메인 스레드에서 열립니다. 만약 렌더러 프로세스에서 대화 상자 +객체를 사용하고 싶다면, `remote`를 통해 접근하는 방법을 고려해야 합니다: + +```javascript +const dialog = require('electron').remote.dialog; +``` ## Methods @@ -109,7 +113,7 @@ console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', ' 대화 상자를 표시합니다. `browserWindow`를 지정하면 대화 상자가 완전히 닫힐 때까지 지정한 창을 사용할 수 없습니다. 완료 시 유저가 선택한 버튼의 인덱스를 반환합니다. -역주: 부정을 표현하는 "아니오", "취소"와 같은 한글 단어는 지원되지 않습니다. 만약 +**역주:** 부정을 표현하는 "아니오", "취소"와 같은 한글 단어는 지원되지 않습니다. 만약 OS X 또는 Windows에서 "확인", "취소"와 같은 순서로 버튼을 지정하게 될 때 Alt + f4로 해당 대화 상자를 끄게 되면 "확인"을 누른 것으로 판단되어 버립니다. 이를 해결하려면 "Cancel"을 대신 사용하거나 BrowserWindow API를 사용하여 대화 상자를 직접 구현해야 @@ -123,4 +127,15 @@ OS X 또는 Windows에서 "확인", "취소"와 같은 순서로 버튼을 지 에러 메시지를 보여주는 대화 상자를 표시합니다. 이 API는 `app` 모듈의 `ready` 이벤트가 발생하기 전에 사용할 수 있습니다. 이 메서드는 -보통 어플리케이션이 시작되기 전에 특정한 에러를 표시하기 위해 사용됩니다. +보통 어플리케이션이 시작되기 전에 특정한 에러를 표시하기 위해 사용됩니다. 만약 +Linux에서 `ready` 이벤트가 호출되기 이전에 이 API를 호출할 경우, 메시지는 stderr를 +통해서 표시되며 GUI 대화 상자는 표시되지 않습니다. + +## Sheets + +Mac OS X에선, `browserWindow` 인자에 `BrowserWindow` 객체 참조를 전달하면 대화 +상자가 해당 윈도우에 시트처럼 표시되도록 표현할 수 있습니다. 윈도우의 객체 참조가 +제공되지 않으면 모달 형태로 표시됩니다. + +`BrowserWindow.getCurrentWindow().setSheetOffset(offset)`을 통해 윈도우에 부착될 +시트의 위치를 조정할 수 있습니다. diff --git a/docs-translations/ko-KR/api/download-item.md b/docs-translations/ko-KR/api/download-item.md index a367d0e000bd..0356030d8fb9 100644 --- a/docs-translations/ko-KR/api/download-item.md +++ b/docs-translations/ko-KR/api/download-item.md @@ -22,6 +22,7 @@ win.webContents.session.on('will-download', function(event, item, webContents) { console.log("Download is cancelled or interrupted that can't be resumed"); } }); +}); ``` ## Events diff --git a/docs-translations/ko-KR/api/frameless-window.md b/docs-translations/ko-KR/api/frameless-window.md index 94c87ca9a649..7bcdeb4a60bc 100644 --- a/docs-translations/ko-KR/api/frameless-window.md +++ b/docs-translations/ko-KR/api/frameless-window.md @@ -1,6 +1,6 @@ # Frameless Window -Frameless Window는 [창 테두리](https://developer.mozilla.org/en-US/docs/Glossary/Chrome)가 +Frameless Window는 [창 테두리](https://developer.mozilla.org/ko/docs/Glossary/Chrome)가 없는 윈도우를 말합니다. 이 기능은 윈도우의 일부분인 툴바와 같이 웹 페이지의 일부분이 아닌 부분을 보이지 않도록 합니다. [`BrowserWindow`](browser-window.md) 클래스의 옵션에서 설정할 수 있습니다. @@ -39,7 +39,7 @@ var win = new BrowserWindow({ transparent: true, frame: false }); * 투명한 영역을 통과하여 클릭할 수 없습니다. 우리는 이 문제를 해결하기 위해 API를 제공할 예정이며 자세한 내용은 - [이슈](https://github.com/atom/electron/issues/1335)를 참고하세요. + [이슈](https://github.com/electron/electron/issues/1335)를 참고하세요. * 투명한 창은 크기를 조절할 수 없습니다. `resizable` 속성을 `true`로 할 경우 몇몇 플랫폼에선 크래시가 일어납니다. * `blur` 필터는 웹 페이지에서만 적용됩니다. 윈도우 아래 컨텐츠에는 블러 효과를 적용할 diff --git a/docs-translations/ko-KR/api/global-shortcut.md b/docs-translations/ko-KR/api/global-shortcut.md index 658f723692a6..6c01368a392e 100644 --- a/docs-translations/ko-KR/api/global-shortcut.md +++ b/docs-translations/ko-KR/api/global-shortcut.md @@ -14,9 +14,9 @@ const app = electron.app; const globalShortcut = electron.globalShortcut; app.on('ready', function() { - // 'ctrl+x' 단축키를 리스너에 등록합니다. - var ret = globalShortcut.register('ctrl+x', function() { - console.log('ctrl+x is pressed'); + // 'CommandOrControl+X' 단축키를 리스너에 등록합니다. + var ret = globalShortcut.register('CommandOrControl+X', function() { + console.log('CommandOrControl+X is pressed'); }); if (!ret) { @@ -24,12 +24,12 @@ app.on('ready', function() { } // 단축키가 등록되었는지 확인합니다. - console.log(globalShortcut.isRegistered('ctrl+x')); + console.log(globalShortcut.isRegistered('CommandOrControl+X')); }); app.on('will-quit', function() { // 단축키의 등록을 해제합니다. - globalShortcut.unregister('ctrl+x'); + globalShortcut.unregister('CommandOrControl+X'); // 모든 단축키의 등록을 해제합니다. globalShortcut.unregisterAll(); diff --git a/docs-translations/ko-KR/api/ipc-main.md b/docs-translations/ko-KR/api/ipc-main.md index 30b10247f9dc..dcbaa1396737 100644 --- a/docs-translations/ko-KR/api/ipc-main.md +++ b/docs-translations/ko-KR/api/ipc-main.md @@ -1,20 +1,20 @@ # ipcMain `ipcMain` 모듈은 [EventEmitter](https://nodejs.org/api/events.html) 클래스의 -인스턴스입니다. 메인 프로세스에서 사용하면, 랜더러 프로세스(웹 페이지)에서 전달된 -동기, 비동기 메시지를 주고 받는 방법을 제공합니다. 랜더러 프로세스에서 메시지를 전달하면 +인스턴스입니다. 메인 프로세스에서 사용하면, 렌더러 프로세스(웹 페이지)에서 전달된 +동기, 비동기 메시지를 주고 받는 방법을 제공합니다. 렌더러 프로세스에서 메시지를 전달하면 이 모듈을 통해 메시지를 받을 수 있습니다. ## 메시지 전송 -물론 메시지를 받는 것 말고도 메인 프로세스에서 랜더러 프로세스로 보내는 것도 가능합니다. +물론 메시지를 받는 것 말고도 메인 프로세스에서 렌더러 프로세스로 보내는 것도 가능합니다. 자세한 내용은 [webContents.send][web-contents-send]를 참고하세요. * 메시지를 전송할 때 이벤트 이름은 `channel`이 됩니다. * 메시지에 동기로 응답할 땐 반드시 `event.returnValue`를 설정해야 합니다. * 메시지를 비동기로 응답할 땐 `event.sender.send(...)` 메서드를 사용할 수 있습니다. -다음 예제는 랜더러 프로세스와 메인 프로세스간에 메시지를 전달하고 받는 예제입니다: +다음 예제는 렌더러 프로세스와 메인 프로세스간에 메시지를 전달하고 받는 예제입니다: ```javascript // 메인 프로세스 @@ -31,7 +31,7 @@ ipcMain.on('synchronous-message', function(event, arg) { ``` ```javascript -// 랜더러 프로세스 (웹 페이지) +// 렌더러 프로세스 (웹 페이지) const ipcRenderer = require('electron').ipcRenderer; console.log(ipc.sendSync('synchronous-message', 'ping')); // "pong" 출력 diff --git a/docs-translations/ko-KR/api/ipc-renderer.md b/docs-translations/ko-KR/api/ipc-renderer.md index 0d43b157d165..f46809a52d27 100644 --- a/docs-translations/ko-KR/api/ipc-renderer.md +++ b/docs-translations/ko-KR/api/ipc-renderer.md @@ -1,7 +1,7 @@ # ipcRenderer `ipcRenderer` 모듈은 [EventEmitter](https://nodejs.org/api/events.html) 클래스의 -인스턴스입니다. 랜더러 프로세스에서 메인 프로세스로 동기/비동기 메시지를 주고 받는 +인스턴스입니다. 렌더러 프로세스에서 메인 프로세스로 동기/비동기 메시지를 주고 받는 방법을 제공합니다. 또한 메인 프로세스로부터 받은 메시지에 응답할 수도 있습니다. [ipcMain](ipc-main.md)에서 코드 예제를 확인할 수 있습니다. @@ -71,7 +71,7 @@ 메인 프로세스는 `ipcMain` 모듈을 통해 `channel` 이벤트를 리스닝 할 수 있고, `event.returnValue`로 회신 할 수 있습니다. -__참고:__ 동기 메서드는 모든 랜더러 프로세스의 작업을 일시 중단시킵니다. 사용 목적이 +**참고:** 동기 메서드는 모든 렌더러 프로세스의 작업을 일시 중단시킵니다. 사용 목적이 확실하지 않다면 사용하지 않는 것이 좋습니다. ### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])` diff --git a/docs-translations/ko-KR/api/menu-item.md b/docs-translations/ko-KR/api/menu-item.md index 0e723fc657d3..3ee5a2ff5075 100644 --- a/docs-translations/ko-KR/api/menu-item.md +++ b/docs-translations/ko-KR/api/menu-item.md @@ -14,7 +14,7 @@ * `options` Object * `click` Function - 메뉴 아이템이 클릭될 때 `click(menuItem, browserWindow)` 형태로 호출 되는 콜백 함수 - * `role` String - 메뉴 아이템의 액션을 정의합니다. 이 속성을 지정하면 `click` + * `role` String - 메뉴 아이템의 액션을 정의합니다; 이 속성을 지정하면 `click` 속성이 무시됩니다. * `type` String - `MenuItem`의 타입 `normal`, `separator`, `submenu`, `checkbox` 또는 `radio`를 사용할 수 있습니다. 만약 값이 `Menu`가 아니면 @@ -23,18 +23,22 @@ * `sublabel` String * `accelerator` [Accelerator](accelerator.md) * `icon` [NativeImage](native-image.md) - * `enabled` Boolean - * `visible` Boolean - * `checked` Boolean - * `submenu` Menu - 보조메뉴를 설정합니다. `type`이 `submenu`일 경우 반드시 - 설정해야 합니다. 일반 메뉴 아이템일 경우 생략할 수 있습니다. + * `enabled` Boolean - 만약 `false`로 설정되면, 메뉴 아이템이 회색으로 변하며 + 클릭할 수 없게 됩니다. + * `visible` Boolean - 만약 `false`로 설정되면, 메뉴 아이템이 완전히 숨겨집니다. + * `checked` Boolean - 반드시 `checkbox` 또는 `radio` 타입의 메뉴 아이템에만 + 지정해야 합니다. + * `submenu` Menu - 반드시 `submenu` 타입의 메뉴 아이템에만 지정해야 합니다. 만약 + `submenu`가 지정되면 `type: 'submenu'`는 생략될 수 있습니다. 만약 값이 `Menu`가 + 아닐 경우 `Menu.buildFromTemplate`을 통해 자동적으로 변환됩니다. * `id` String - 현재 메뉴 아이템에 대해 유일키를 지정합니다. 이 키는 이후 `position` 옵션에서 사용할 수 있습니다. * `position` String - 미리 지정한 `id`를 이용하여 메뉴 아이템의 위치를 세밀하게 조정합니다. -메뉴 아이템을 생성할 때, 다음 목록과 일치하는 표준 동작은 수동으로 직접 구현하는 대신 -`role` 속성을 지정하여 고유 OS 경험을 최대한 살릴 수 있습니다. +어떠한 메뉴 아이템이 표준 롤에 일치한다면, `role`을 지정하는 것이 동작을 `click` +함수로 일일이 구현하려 시도하는 것 보다 더 좋을 수 있습니다. 빌트-인 `role` 동작은 +더 좋은 네이티브 경험을 제공할 것입니다. `role` 속성은 다음 값을 가질 수 있습니다: @@ -57,3 +61,24 @@ OS X에서의 `role`은 다음 값을 추가로 가질 수 있습니다: * `window` - 부 메뉴를 가지는 "Window" 메뉴 * `help` - 부 메뉴를 가지는 "Help" 메뉴 * `services` - 부 메뉴를 가지는 "Services" 메뉴 + +OS X에서는 `role`을 지정할 때, `label`과 `accelerator`만 MenuItem에 효과가 +적용되도록 변경되며, 다른 옵션들은 모두 무시됩니다. + +## Instance Properties + +다음 속성들은 존재하는 `MenuItem`에서 계속 변경될 수 있습니다: + + * `enabled` Boolean + * `visible` Boolean + * `checked` Boolean + +이 속성들의 의미는 위 옵션에서 설명한 것과 같습니다. + +`checkbox` 메뉴 아이템은 선택될 때 해당 아이템의 `checked` 속성을 통해 활성화 그리고 +비활성화 상태인지를 표시합니다. 또한 `click` 함수를 지정하여 추가적인 작업을 할 수도 +있습니다. + +`radio` 메뉴 아이템은 클릭되었을 때 `checked` 속성을 활성화 합니다. 그리고 같은 +메뉴의 인접한 모든 다른 아이템은 비활성화됩니다. 또한 `click` 함수를 지정하여 추가적인 +작업을 할 수도 있습니다. diff --git a/docs-translations/ko-KR/api/menu.md b/docs-translations/ko-KR/api/menu.md index 44fe461bcc21..c0de2ec2ab00 100644 --- a/docs-translations/ko-KR/api/menu.md +++ b/docs-translations/ko-KR/api/menu.md @@ -1,7 +1,7 @@ # Menu -`menu` 클래스는 어플리케이션 메뉴와 [컨텍스트 메뉴](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/PopupGuide/ContextMenus)를 -만들 때 사용됩니다. 이 모듈은 메인 프로세스용 모듈이지만 `remote` 모듈을 통해 랜더러 +`menu` 클래스는 어플리케이션 메뉴와 [컨텍스트 메뉴](https://developer.mozilla.org/ko/docs/Mozilla/Tech/XUL/PopupGuide/ContextMenus)를 +만들 때 사용됩니다. 이 모듈은 메인 프로세스용 모듈이지만 `remote` 모듈을 통해 렌더러 프로세스에서도 사용할 수 있습니다. 각 메뉴는 여러 개의 [메뉴 아이템](menu-item.md)으로 구성되고 서브 메뉴를 가질 수도 있습니다. @@ -29,7 +29,7 @@ window.addEventListener('contextmenu', function (e) { ``` -또 하나의 예를 들자면 다음 예제는 랜더러 프로세스에서 template API를 사용하여 +또 하나의 예를 들자면 다음 예제는 렌더러 프로세스에서 template API를 사용하여 어플리케이션 메뉴를 만듭니다: ```javascript @@ -106,7 +106,7 @@ var template = [ })(), click: function(item, focusedWindow) { if (focusedWindow) - focusedWindow.toggleDevTools(); + focusedWindow.webContents.toggleDevTools(); } }, ] @@ -382,4 +382,4 @@ OS X에선 지정한 어플리케이션 메뉴에 상관없이 메뉴의 첫번 ``` [AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html -[setMenu]: https://github.com/atom/electron/blob/master/docs-translations/ko-KR/api/browser-window.md#winsetmenumenu-linux-windows +[setMenu]: ./browser-window.md#winsetmenumenu-linux-windows diff --git a/docs-translations/ko-KR/api/process.md b/docs-translations/ko-KR/api/process.md index de24b5ac174e..3cdc10dd78cf 100644 --- a/docs-translations/ko-KR/api/process.md +++ b/docs-translations/ko-KR/api/process.md @@ -9,6 +9,8 @@ Electron의 `process` 객체는 기존의 node와는 달리 약간의 차이점 * `process.resourcesPath` String - JavaScript 소스 코드의 경로. * `process.mas` Boolean - Mac 앱 스토어용 빌드일 때 `true`로 지정됩니다. 다른 빌드일 땐 `undefined`로 지정됩니다. +* `process.windowsStore` Boolean - 만약 앱이 Windows Store 앱 (appx)으로 작동하고 + 있다면, 이 값이 `true`로 지정되며 다른 빌드인 경우엔 `undefined`로 지정됩니다. ## Events diff --git a/docs-translations/ko-KR/api/remote.md b/docs-translations/ko-KR/api/remote.md index 3a09084acdef..3265a795a070 100644 --- a/docs-translations/ko-KR/api/remote.md +++ b/docs-translations/ko-KR/api/remote.md @@ -1,15 +1,15 @@ # remote -`remote` 모듈은 메인 프로세스와 랜더러 프로세스(웹 페이지) 사이의 inter-process +`remote` 모듈은 메인 프로세스와 렌더러 프로세스(웹 페이지) 사이의 inter-process (IPC) 통신을 간단하게 추상화 한 모듈입니다. Electron의 메인 프로세스에선 GUI와 관련 있는(`dialog`, `menu`등) 모듈만 사용할 수 -있습니다. 랜더러 프로세스에서 이러한 모듈들을 사용하려면 `ipc` 모듈을 통해 메인 -프로세스와 inter-process 통신을 해야합니다. 또한, `remote` 모듈을 사용하면 +있습니다. 렌더러 프로세스에서 이러한 모듈들을 사용하려면 `ipc` 모듈을 통해 메인 +프로세스와 inter-process 통신을 해야 합니다. 또한, `remote` 모듈을 사용하면 inter-process 통신을 하지 않고도 간단한 API를 통해 직접 메인 프로세스의 모듈과 메서드를 사용할 수 있습니다. 이 개념은 Java의 [RMI][rmi]와 비슷합니다. -다음 예제는 랜더러 프로세스에서 브라우저 창을 만드는 예제입니다: +다음 예제는 렌더러 프로세스에서 브라우저 창을 만드는 예제입니다: ```javascript const remote = require('electron').remote; @@ -19,7 +19,7 @@ var win = new BrowserWindow({ width: 800, height: 600 }); win.loadURL('https://github.com'); ``` -**참고:** 반대로 메인 프로세스에서 랜더러 프로세스에 접근 하려면 [webContents.executeJavascript](web-contents.md#webcontentsexecutejavascriptcode-usergesture) +**참고:** 반대로 메인 프로세스에서 렌더러 프로세스에 접근 하려면 [webContents.executeJavascript](web-contents.md#webcontentsexecutejavascriptcode-usergesture) 메서드를 사용하면 됩니다. ## Remote 객체 @@ -30,20 +30,20 @@ win.loadURL('https://github.com'); 동기형 inter-process 메시지를 보냅니다. 위의 예제에서 사용한 두 `BrowserWindow`와 `win`은 remote 객체입니다. 그리고 -`new BrowserWindow`이 생성하는 `BrowserWindow` 객체는 랜더러 프로세스에서 생성되지 -않습니다. 대신에 이 `BrowserWindow` 객체는 메인 프로세스에서 생성되며 랜더러 +`new BrowserWindow`이 생성하는 `BrowserWindow` 객체는 렌더러 프로세스에서 생성되지 +않습니다. 대신에 이 `BrowserWindow` 객체는 메인 프로세스에서 생성되며 렌더러 프로세스에 `win` 객체와 같이 이에 대응하는 remote 객체를 반환합니다. -참고로 remote를 통해선 [enumerable 속성](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)을 +참고로 remote를 통해선 [enumerable 속성](https://developer.mozilla.org/ko/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)을 가진 프로퍼티에만 접근할 수 있습니다. ## Remote 객체의 생명 주기 -Electron은 랜더러 프로세스의 remote 객체가 살아있는 한(다시 말해서 GC(garbage +Electron은 렌더러 프로세스의 remote 객체가 살아있는 한(다시 말해서 GC(garbage collection)가 일어나지 않습니다) 대응하는 메인 프로세스의 객체는 릴리즈되지 않습니다. Remote 객체가 GC 되려면 대응하는 메인 프로세스 내부 객체의 참조가 해제되어야만 합니다. -만약 remote 객체가 랜더러 프로세스에서 누수가 생겼다면 (예시: 맵에 저장하고 할당 +만약 remote 객체가 렌더러 프로세스에서 누수가 생겼다면 (예시: 맵에 저장하고 할당 해제하지 않음) 대응하는 메인 프로세스의 객체도 누수가 생깁니다. 그래서 remote 객체를 사용할 땐 메모리 누수가 생기지 않도록 매우 주의해서 사용해야 합니다. @@ -51,14 +51,14 @@ Remote 객체가 GC 되려면 대응하는 메인 프로세스 내부 객체의 ## 메인 프로세스로 콜백 넘기기 -메인 프로세스의 코드는 `remote` 모듈을 통해 랜더러 프로세스가 전달하는 콜백 함수를 +메인 프로세스의 코드는 `remote` 모듈을 통해 렌더러 프로세스가 전달하는 콜백 함수를 받을 수 있습니다. 하지만 이 작업은 반드시 주의를 기울여 사용해야 합니다. 첫째, 데드락을 피하기 위해 메인 프로세스로 전달된 콜백들은 비동기로 호출됩니다. 이러한 이유로 메인 프로세스로 전달된 콜백들의 반환 값을 내부 함수에서 언제나 정상적으로 받을 것이라고 예측해선 안됩니다. -예를 들어 메인 프로세스에서 `Array.map` 같은 메서드를 사용할 때 랜더러 프로세스에서 +예를 들어 메인 프로세스에서 `Array.map` 같은 메서드를 사용할 때 렌더러 프로세스에서 전달된 함수를 사용해선 안됩니다: ```javascript @@ -75,7 +75,7 @@ exports.withLocalCallback = function() { ``` ```javascript -// 랜더러 프로세스 +// 렌더러 프로세스 var mapNumbers = require("remote").require("./mapNumbers"); var withRendererCb = mapNumbers.withRendererCallback(function(x) { @@ -87,7 +87,7 @@ var withLocalCb = mapNumbers.withLocalCallback() console.log(withRendererCb, withLocalCb) // [true, true, true], [2, 3, 4] ``` -보다시피 랜더러 콜백의 동기 반환 값은 예상되지 않은 처리입니다. +보다시피 렌더러 콜백의 동기 반환 값은 예상되지 않은 처리입니다. 그리고 메인 프로세스에서 처리한 함수의 반환 값과 일치하지 않습니다. 둘째, 콜백들은 메인 프로세스로 전달, 호출된 이후에도 자동으로 함수의 참조가 릴리즈 되지 @@ -113,9 +113,9 @@ remote.getCurrentWindow().on('close', function() { 설상가상으로 이전에 설치된 콜백의 콘텍스트가 릴리즈 되고 난 후(예: 페이지 새로고침) `close` 이벤트가 발생하면 예외가 발생하고 메인 프로세스가 작동 중지됩니다. -이러한 문제를 피하려면 랜더러 프로세스에서 메인 프로세스로 넘긴 함수의 참조를 사용 후 +이러한 문제를 피하려면 렌더러 프로세스에서 메인 프로세스로 넘긴 함수의 참조를 사용 후 확실하게 제거해야 합니다. 작업 후 이벤트 콜백을 포함하여 책임 있게 함수의 참조를 -제거하거나 메인 프로세스에서 랜더러 프로세스가 종료될 때 내부적으로 함수 참조를 +제거하거나 메인 프로세스에서 렌더러 프로세스가 종료될 때 내부적으로 함수 참조를 제거하도록 설계해야 합니다. ## 메인 프로세스의 빌트인 모듈에 접근 diff --git a/docs-translations/ko-KR/api/screen.md b/docs-translations/ko-KR/api/screen.md index 6cc6535235b6..db832852f3d2 100644 --- a/docs-translations/ko-KR/api/screen.md +++ b/docs-translations/ko-KR/api/screen.md @@ -1,12 +1,13 @@ # screen `screen` 모듈은 화면 크기, 디스플레이, 커서 위치 등등의 다양한 정보를 가져옵니다. -이 모듈은 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 사용할 수 없습니다. +이 모듈은 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 사용할 수 없습니다. (호출 또는 +모듈 포함) `screen`은 [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)를 상속 받았습니다. -**참고:** 랜더러 / DevTools에선 이미 DOM 속성이 `window.screen`을 가지고 있으므로 +**참고:** 렌더러 / DevTools에선 이미 DOM 속성이 `window.screen`을 가지고 있으므로 `screen = require('screen')` 형식으로 모듈을 사용할 수 없습니다. 아래의 예제와 같이 `electronScreen` 같은 이름으로 모듈 이름을 대체하여 사용해야 합니다. diff --git a/docs-translations/ko-KR/api/session.md b/docs-translations/ko-KR/api/session.md index 5bb4867eda0e..76a3fc9ea837 100644 --- a/docs-translations/ko-KR/api/session.md +++ b/docs-translations/ko-KR/api/session.md @@ -293,9 +293,9 @@ myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, c * `handler` Function * `webContents` Object - [WebContents](web-contents.md) 권한을 요청. - * `permission` String - 'media', 'geolocation', 'notifications', - 'midiSysex', 'pointerLock', 'fullscreen'의 나열. - * `callback` Function - 권한 허용 및 거부. + * `permission` String - 'media', 'geolocation', 'notifications', + 'midiSysex', 'pointerLock', 'fullscreen', 'openExternal'의 나열. + * `callback` Function - 권한 허용 및 거부. `session`의 권한 요청에 응답을 하는데 사용하는 핸들러를 설정합니다. `callback(true)`를 호출하면 권한 제공을 허용하고 `callback(false)`를 @@ -419,7 +419,7 @@ HTTP 요청을 보내기 전 요청 헤더를 사용할 수 있을 때 `listener * `timestamp` Double * `requestHeaders` Object -#### `ses.webRequest.onHeadersReceived([filter,] listener)` +#### `ses.webRequest.onHeadersReceived([filter, ]listener)` * `filter` Object * `listener` Function @@ -444,6 +444,9 @@ HTTP 요청을 보내기 전 요청 헤더를 사용할 수 있을 때 `listener * `cancel` Boolean * `responseHeaders` Object (optional) - 이 속성이 제공되면 서버는 이 헤더와 함께 응답합니다. + * `statusLine` String (optional) - `responseHeaders`를 덮어쓸 땐, 헤더의 상태를 + 변경하기 위해 반드시 지정되어야 합니다. 그렇지 않은 경우, 기존의 응답 헤더의 상태가 + 사용됩니다. #### `ses.webRequest.onResponseStarted([filter, ]listener)` diff --git a/docs-translations/ko-KR/api/shell.md b/docs-translations/ko-KR/api/shell.md index c4831092f3cf..6e9b0f25d5a4 100644 --- a/docs-translations/ko-KR/api/shell.md +++ b/docs-translations/ko-KR/api/shell.md @@ -36,14 +36,12 @@ shell.openExternal('https://github.com'); mailto: URL은 유저의 기본 이메일 에이전트로 URL을 엽니다.) 어플리케이션이 해당 URL을 열 수 있을 때 `true`를 반환합니다. 아니라면 `false`를 반환합니다. -역주: 폴더는 'file:\\\\C:\\'와 같이 지정하여 열 수 있습니다. (Windows의 경우) +**역주:** 탐색기로 폴더만 표시하려면 `'file://경로'`와 같이 지정하여 열 수 있습니다. ### `shell.moveItemToTrash(fullPath)` * `fullPath` String -Move the given file to trash and returns boolean status for the operation. - 지정한 파일을 휴지통으로 이동합니다. 작업의 성공여부를 boolean 형으로 리턴합니다. ### `shell.beep()` diff --git a/docs-translations/ko-KR/api/synopsis.md b/docs-translations/ko-KR/api/synopsis.md index 8f59d12c1ce5..3493223cceb6 100644 --- a/docs-translations/ko-KR/api/synopsis.md +++ b/docs-translations/ko-KR/api/synopsis.md @@ -5,12 +5,12 @@ node 모듈을 완벽하게 지원합니다. ([네이티브 모듈](../tutorial/ 포함) 또한 Electron은 네이티브 데스크톱 어플리케이션을 개발 할 수 있도록 추가적인 built-in -모듈을 제공합니다. 몇몇 모듈은 메인 프로세스에서만 사용할 수 있고 어떤 모듈은 랜더러 +모듈을 제공합니다. 몇몇 모듈은 메인 프로세스에서만 사용할 수 있고 어떤 모듈은 렌더러 프로세스(웹 페이지)에서만 사용할 수 있습니다. 또한 두 프로세스 모두 사용할 수 있는 모듈도 있습니다. 기본적인 규칙으로 [GUI][gui]와 저 수준 시스템에 관련된 모듈들은 오직 메인 -프로세스에서만 사용할 수 있습니다. [메인 프로세스 vs. 랜더러 프로세스](../tutorial/quick-start.md#메인-프로세스) +프로세스에서만 사용할 수 있습니다. [메인 프로세스 vs. 렌더러 프로세스](../tutorial/quick-start.md#메인-프로세스) 컨셉에 익숙해야 모듈을 다루기 쉬우므로 관련 문서를 읽어 보는 것을 권장합니다. 메인 프로세스 스크립트는 일반 Node.js 스크립트와 비슷합니다: @@ -28,7 +28,7 @@ app.on('ready', function() { }); ``` -랜더러 프로세스도 예외적인 node module들을 사용할 수 있다는 점을 제외하면 일반 웹 +렌더러 프로세스도 예외적인 node module들을 사용할 수 있다는 점을 제외하면 일반 웹 페이지와 크게 다를게 없습니다: ```html @@ -78,5 +78,5 @@ require('electron').hideInternalModules() ``` [gui]: https://en.wikipedia.org/wiki/Graphical_user_interface -[destructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment -[issue-387]: https://github.com/atom/electron/issues/387 +[destructuring-assignment]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment +[issue-387]: https://github.com/electron/electron/issues/387 diff --git a/docs-translations/ko-KR/api/tray.md b/docs-translations/ko-KR/api/tray.md index d82b0a9d7e40..b0293d40fcb3 100644 --- a/docs-translations/ko-KR/api/tray.md +++ b/docs-translations/ko-KR/api/tray.md @@ -11,7 +11,7 @@ const Tray = electron.Tray; var appIcon = null; app.on('ready', function(){ - appIcon = new Tray('/path/to/my/icon'); // 현재 어플리케이션 디렉터리를 기준으로 하려면 `__dirname + '/images/tray.png'` 형식으로 입력해야합니다. + appIcon = new Tray('/path/to/my/icon'); // 현재 어플리케이션 디렉터리를 기준으로 하려면 `__dirname + '/images/tray.png'` 형식으로 입력해야 합니다. var contextMenu = Menu.buildFromTemplate([ { label: 'Item1', type: 'radio' }, { label: 'Item2', type: 'radio' }, @@ -74,7 +74,7 @@ appIcon.setContextMenu(contextMenu); 트레이 아이콘이 클릭될 때 발생하는 이벤트입니다. -__주의:__ `bounds`는 OS X 와 Windows에서만 작동합니다. +**참고:** `bounds`는 OS X 와 Windows에서만 작동합니다. ### Event: 'right-click' _OS X_ _Windows_ diff --git a/docs-translations/ko-KR/api/web-contents.md b/docs-translations/ko-KR/api/web-contents.md index 1cda4a3af5ed..48798f79b6cc 100644 --- a/docs-translations/ko-KR/api/web-contents.md +++ b/docs-translations/ko-KR/api/web-contents.md @@ -31,6 +31,7 @@ Returns: * `errorCode` Integer * `errorDescription` String * `validatedURL` String +* `isMainFrame` Boolean 이 이벤트는 `did-finish-load`와 비슷하나, 로드가 실패했거나 취소되었을 때 발생합니다. 예를 들면 `window.stop()`이 실행되었을 때 발생합니다. 발생할 수 있는 전체 에러 코드의 @@ -66,6 +67,7 @@ Returns: * `requestMethod` String * `referrer` String * `headers` Object +* `resourceType` String 요청한 리소스에 관련된 자세한 정보를 사용할 수 있을 때 발생하는 이벤트입니다. `status`는 리소스를 다운로드하기 위한 소켓 연결을 나타냅니다. @@ -348,6 +350,10 @@ var currentURL = win.webContents.getURL(); 현재 웹 페이지가 리소스를 로드중인지 여부를 반환합니다. +### `webContents.isLoadingMainFrame()` + +메인 프레임이 여전히 로딩중인지 여부를 반환합니다. (내부 iframe 또는 frame 포함) + ### `webContents.isWaitingForResponse()` 현재 웹 페이지가 페이지의 메인 리소스로부터 첫 응답을 기다리고있는지 여부를 반환합니다. @@ -638,6 +644,9 @@ mainWindow.webContents.on('devtools-opened', function() { * `options` Object (optional) * `detach` Boolean - 새 창에서 개발자 도구를 엽니다. + * `mode` String - 개발자 도구 표시 상태를 지정합니다. 옵션은 "right", "bottom", + "undocked", "detach" 중 한 가지가 될 수 있습니다. 기본값은 마지막 표시 상태를 + 사용합니다. 개발자 도구를 엽니다. diff --git a/docs-translations/ko-KR/api/web-frame.md b/docs-translations/ko-KR/api/web-frame.md index f77ed68f9073..292f7d81420d 100644 --- a/docs-translations/ko-KR/api/web-frame.md +++ b/docs-translations/ko-KR/api/web-frame.md @@ -1,6 +1,6 @@ # webFrame -`web-frame` 모듈은 현재 웹 페이지의 랜더링 상태를 설정 할 수 있도록 관련 유틸리티를 +`web-frame` 모듈은 현재 웹 페이지의 렌더링 상태를 설정 할 수 있도록 관련 유틸리티를 제공하는 모듈입니다. 다음 예제는 현재 페이지를 200% 줌 합니다: diff --git a/docs-translations/ko-KR/api/web-view-tag.md b/docs-translations/ko-KR/api/web-view-tag.md index 69fa0c5a7679..b04398e8e5d6 100644 --- a/docs-translations/ko-KR/api/web-view-tag.md +++ b/docs-translations/ko-KR/api/web-view-tag.md @@ -17,7 +17,7 @@ 수 있습니다: ```html - + ``` 게스트 컨텐츠를 조작하기 위해 자바스크립트로 `webview` 태그의 이벤트를 리스닝 하여 @@ -43,6 +43,36 @@ ``` +## CSS 스타일링 참고 + +주의할 점은 `webview` 태그의 스타일은 전통적인 flexbox 레이아웃을 사용했을 때 자식 +`object` 요소가 해당 `webview` 컨테이너의 전체 높이와 넓이를 확실히 채우도록 +내부적으로 `display:flex;`를 사용합니다. (v0.36.11 부터) 따라서 인라인 레이아웃을 +위해 `display:inline-flex;`를 쓰지 않는 한, 기본 `display:flex;` CSS 속성을 +덮어쓰지 않도록 주의해야 합니다. + +`webview`는 `hidden` 또는 `display: none;` 속성을 사용할 때 발생하는 문제를 한 가지 +가지고 있습니다. 자식 `browserplugin` 객체 내에서 비정상적인 랜더링 동작을 발생시킬 수 +있으며 웹 페이지가 로드되었을 때, `webview`가 숨겨지지 않았을 때, 반대로 그냥 바로 +다시 보이게 됩니다. `webview`를 숨기는 방법으로 가장 권장되는 방법은 `width` & +`height`를 0으로 지정하는 CSS를 사용하는 것이며 `flex`를 통해 0px로 요소를 수축할 수 +있도록 합니다. + +```html + +``` + ## 태그 속성 `webview` 태그는 다음과 같은 속성을 가지고 있습니다: @@ -80,6 +110,9 @@ "on"으로 지정하면 `webview` 페이지 내에서 `require`와 `process 객체`같은 node.js API를 사용할 수 있습니다. 이를 지정하면 내부에서 로우레벨 리소스에 접근할 수 있습니다. +**참고:** Node 통합 기능은 `webview`에서 부모 윈도우가 해당 옵션이 비활성화되어있는 +경우 항상 비활성화됩니다. + ### `plugins` ```html @@ -140,7 +173,7 @@ API를 사용할 수 있습니다. 이를 지정하면 내부에서 로우레벨 동일한 세션을 공유할 수 있도록 할 수 있습니다. 만약 `partition`이 지정되지 않으면 앱의 기본 세션을 사용합니다. -이 값은 첫 탐색 이전에만 지정할 수 있습니다. 즉. 작동중인 랜더러 프로세스의 세션은 +이 값은 첫 탐색 이전에만 지정할 수 있습니다. 즉. 작동중인 렌더러 프로세스의 세션은 변경할 수 없습니다. 이후 이 값을 바꾸려고 시도하면 DOM 예외를 발생시킵니다. ### `allowpopups` @@ -254,7 +287,7 @@ Webview에 웹 페이지 `url`을 로드합니다. `url`은 `http://`, `file://` ### `.isCrashed()` -랜더러 프로세스가 크래시 됬는지 확인합니다. +렌더러 프로세스가 크래시 됬는지 확인합니다. ### `.setUserAgent(userAgent)` @@ -285,7 +318,7 @@ Webview에 웹 페이지 `url`을 로드합니다. `url`은 `http://`, `file://` 이 옵션을 활성화 시키면 `requestFullScreen`와 같은 HTML API에서 유저의 승인을 무시하고 개발자가 API를 바로 사용할 수 있도록 허용합니다. -역주: 기본적으로 브라우저에선 전체화면, 웹캠, 파일 열기등의 API를 사용하려면 유저의 +**역주:** 기본적으로 브라우저에선 전체화면, 웹캠, 파일 열기등의 API를 사용하려면 유저의 승인(이벤트)이 필요합니다. ### `.openDevTools()` @@ -414,8 +447,8 @@ Webview 페이지를 PDF 형식으로 인쇄합니다. * `channel` String * `args` (optional) -`channel`을 통해 랜더러 프로세스로 비동기 메시지를 보냅니다. 또한 `args`를 지정하여 -임의의 인자를 보낼 수도 있습니다. 랜더러 프로세스는 `ipcRenderer` 모듈의 `channel` +`channel`을 통해 렌더러 프로세스로 비동기 메시지를 보냅니다. 또한 `args`를 지정하여 +임의의 인자를 보낼 수도 있습니다. 렌더러 프로세스는 `ipcRenderer` 모듈의 `channel` 이벤트로 이 메시지를 받아 처리할 수 있습니다. 예제는 [webContents.send](web-contents.md#webcontentssendchannel-args)를 참고하세요. @@ -460,9 +493,10 @@ Returns: * `errorCode` Integer * `errorDescription` String * `validatedURL` String +* `isMainFrame` Boolean -`did-finish-load`와 비슷합니다. 하지만 이 이벤트는 `window.stop()`과 같은 무언가로 -인해 로드에 실패했을 때 발생하는 이벤트입니다. +`did-finish-load`와 비슷합니다. 하지만 이 이벤트는 `window.stop()`과 같이 취소 +함수가 호출되었거나 로드에 실패했을 때 발생하는 이벤트입니다. ### Event: 'did-frame-finish-load' @@ -492,6 +526,7 @@ Returns: * `requestMethod` String * `referrer` String * `headers` Object +* `resourceType` String 요청한 리소스에 관해 자세한 내용을 알 수 있을 때 발생하는 이벤트입니다. `status`는 리소스를 다운로드할 소켓 커낵션을 나타냅니다. @@ -595,7 +630,10 @@ Returns: ```javascript webview.addEventListener('new-window', function(e) { - require('electron').shell.openExternal(e.url); + var protocol = require('url').parse(e.url).protocol; + if (protocol === 'http:' || protocol === 'https:') { + require('electron').shell.openExternal(e.url); + } }); ``` @@ -683,7 +721,7 @@ ipcRenderer.on('ping', function() { ### Event: 'crashed' -랜더러 프로세스가 크래시 되었을 때 발생하는 이벤트입니다. +렌더러 프로세스가 크래시 되었을 때 발생하는 이벤트입니다. ### Event: 'gpu-crashed' @@ -712,6 +750,10 @@ WebContents가 파괴될 때 발생하는 이벤트입니다. ### Event: 'did-change-theme-color' +Returns: + +* `themeColor` String + 페이지의 테마 색이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 보통 meta 태그에 의해서 발생합니다: diff --git a/docs-translations/ko-KR/api/window-open.md b/docs-translations/ko-KR/api/window-open.md index f81c6b65be87..8969160c9ac5 100644 --- a/docs-translations/ko-KR/api/window-open.md +++ b/docs-translations/ko-KR/api/window-open.md @@ -22,6 +22,9 @@ `features` 문자열은 표준 브라우저의 포맷을 따르고 있지만, 각 기능은 `BrowserWindow`의 옵션이어야 합니다. +**참고:** Node 통합 기능은 열린 `window`에서 부모 윈도우가 해당 옵션이 +비활성화되어있는 경우 항상 비활성화됩니다. + ### `window.opener.postMessage(message, targetOrigin)` * `message` String diff --git a/docs-translations/ko-KR/development/atom-shell-vs-node-webkit.md b/docs-translations/ko-KR/development/atom-shell-vs-node-webkit.md index 22e8e3756469..21972d2f38ae 100644 --- a/docs-translations/ko-KR/development/atom-shell-vs-node-webkit.md +++ b/docs-translations/ko-KR/development/atom-shell-vs-node-webkit.md @@ -16,7 +16,7 @@ main 필드에 메인 웹 페이지(index.html) URL을 지정하면 어플리케 Electron에선 JavaScript를 엔트리 포인트로 사용합니다. URL을 직접 제공하는 대신 API를 사용하여 직접 브라우저 창과 HTML 파일을 로드할 수 있습니다. 또한 윈도우의 종료시기를 -결정하는 이벤트를 리스닝해야합니다. +결정하는 이벤트를 리스닝해야 합니다. Electron은 Node.js 런타임과 비슷하게 작동합니다. Electron의 API는 저수준이기에 브라우저 테스팅을 위해 [PhantomJS](http://phantomjs.org/)를 사용할 수도 있습니다. @@ -44,4 +44,4 @@ __4. 다중 컨텍스트__ Node의 [다중 컨텍스트](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/)를 사용하기 때문에 Electron은 웹 페이지의 새로운 JavaScript 컨텍스트를 생성하지 않습니다. -[node-bindings]: https://github.com/atom/electron/tree/master/atom/common +[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs-translations/ko-KR/development/build-instructions-linux.md b/docs-translations/ko-KR/development/build-instructions-linux.md index 377a7977a852..e5712fcac99e 100644 --- a/docs-translations/ko-KR/development/build-instructions-linux.md +++ b/docs-translations/ko-KR/development/build-instructions-linux.md @@ -44,7 +44,7 @@ $ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring- ## 코드 가져오기 ```bash -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## 부트 스트랩 diff --git a/docs-translations/ko-KR/development/build-instructions-osx.md b/docs-translations/ko-KR/development/build-instructions-osx.md index 142cdaca4dfe..1a1a13a4576c 100644 --- a/docs-translations/ko-KR/development/build-instructions-osx.md +++ b/docs-translations/ko-KR/development/build-instructions-osx.md @@ -15,7 +15,7 @@ ## 코드 가져오기 ```bash -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## 부트 스트랩 diff --git a/docs-translations/ko-KR/development/build-instructions-windows.md b/docs-translations/ko-KR/development/build-instructions-windows.md index 3c7932479ecd..4d1c57a33b49 100644 --- a/docs-translations/ko-KR/development/build-instructions-windows.md +++ b/docs-translations/ko-KR/development/build-instructions-windows.md @@ -27,7 +27,7 @@ Studio를 사용할 수 없습니다. 하지만 여전히 Electron을 개발할 ## 코드 가져오기 ```powershell -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## 부트 스트랩 diff --git a/docs-translations/ko-KR/development/coding-style.md b/docs-translations/ko-KR/development/coding-style.md index dd64e724517f..ff162575d72c 100644 --- a/docs-translations/ko-KR/development/coding-style.md +++ b/docs-translations/ko-KR/development/coding-style.md @@ -23,26 +23,35 @@ C++ 코드는 많은 Chromium의 추상화와 타입을 사용합니다. 따라 ## JavaScript -* 하드 탭(hard tabs) 대신 소프트 탭(2 spaces) 들여쓰기를 사용합니다. -* 항상 구문의 끝은 `;`으로 마쳐야 합니다. +* [표준](http://npm.im/standard) JavaScript 코딩 스타일을 사용합니다. * Google의 코딩 스타일에도 맞추기 위해 파일의 끝에는 **절대** 개행을 삽입해선 안됩니다. * 파일 이름의 공백은 `_`대신에 `-`을 사용하여야 합니다. 예를 들어 -`file_name.js`를 `file-name.js`로 고쳐야합니다. 왜냐하면 +`file_name.js`를 `file-name.js`로 고쳐야 합니다. 왜냐하면 [github/atom](https://github.com/github/atom)에서 사용되는 모듈의 이름은 보통 `module-name` 형식이기 때문입니다. 이 규칙은 '.js' 파일에만 적용됩니다. * 적절한 곳에 새로운 ES6/ES2015 문법을 사용해도 됩니다. - * [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) + * [`const`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/const) 는 requires와 다른 상수에 사용합니다 - * [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) + * [`let`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let) 은 변수를 정의할 때 사용합니다 - * [Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) + * [Arrow functions](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 는 `function () { }` 표현 대신에 사용합니다 - * [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) + * [Template literals](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals) 는 `+`로 문자열을 합치는 대신 사용합니다. -## API 이름 +## 이름 짓기 -새로운 API를 만들 땐 getter, setter스타일 대신 jQuery의 one-function 스타일을 -사용해야 합니다. 예를 들어 `.getText()`와 `.setText(text)`대신에 `.text([text])` -형식으로 설계하면 됩니다. 포럼에 이 문제에 대한 [논의](https://github.com/atom/electron/issues/46)가 +Electron API는 Node.js와 비슷한 명명법을 사용합니다: + +- `BrowserWindow`와 같은 모듈 자체를 뜻하는 이름은, `CamelCase`를 사용합니다. +- `globalShortcut`과 같은 API의 세트일 땐, `mixedCase`를 사용합니다. +- API가 객체의 속성일 경우, 그리고 `win.webContents`와 같이 충분히 복잡하고 분리된 + 부분일 경우, `mixedCase`를 사용합니다. +- 다른 모듈이 아닌 API를 구현할 땐, ` Tag` 또는 `Process Object`와 같이 + 단순하고 자연스러운 제목을 사용합니다. + +새로운 API를 만들 땐 jQuery의 one-function 스타일 대신 getter, setter스타일을 +사용해야 합니다. 예를 들어 `.text([text])` 대신 `.getText()`와 `.setText(text)` +형식으로 함수를 설계하면 됩니다. 포럼에서 이 문제에 대한 +[논의](https://github.com/electron/electron/issues/46)가 진행되고 있습니다. diff --git a/docs-translations/ko-KR/development/debug-instructions-windows.md b/docs-translations/ko-KR/development/debug-instructions-windows.md new file mode 100644 index 000000000000..a0d50e475c76 --- /dev/null +++ b/docs-translations/ko-KR/development/debug-instructions-windows.md @@ -0,0 +1,87 @@ +# Windows에서 Electron 디버깅하기 + +만약 작성한 Javascript 어플리케이션이 아닌 Electron 자체의 크래시나 문제를 경험하고 +있다면, 네이티브/C++ 디버깅에 익숙하지 않은 개발자는 디버깅이 약간 까다로울 수 +있습니다. 그렇다 해도, Visual Studio, GitHub의 Electron이 호스팅하는 심볼 서버, +Electron 소스 코드가 중단점을 통해 순차적으로 쉽게 디버깅할 수 있는 환경을 제공합니다. + +## 요구 사항 + +* **Electron의 디버그 빌드**: 가장 쉬운 방법은 보통 + [Windows용 빌드 설명서](build-instructions-windows.md)에 명시된 요구사항과 툴을 + 사용하여 스스로 빌드하는 것입니다. 물론 직접 다운로드 받은 Electron 바이너리에도 + 디버거 연결 및 디버깅을 사용할 수 있지만, 실질적으로 디버깅이 까다롭게 고도의 + 최적화가 되어있음을 발견하게 될 것입니다: 인라인화, 꼬리 호출, 이외 여러 가지 + 생소한 최적화가 적용되어 디버거가 모든 변수와 실행 경로를 정상적으로 표시할 수 + 없습니다. + +* **Visual Studio와 C++ 툴**: Visual Studio 2013과 Visual Studio 2015 두 가지 + 커뮤니티 에디션 모두 잘 작동합니다. 설치가 완료되면, + [Visual Studio가 GitHub의 Electron 심볼 서버를 사용하도록](setting-up-symbol-server.md) + 설정해야 합니다. 이 작업은 Visual Studio가 Electron에서 무슨일이 일어나는지 더 잘 + 이해할 수 있도록 하며 변수를 사람이 읽기 좋은 포맷으로 쉽게 표현할 수 있도록 합니다. + +* **ProcMon**: 이 무료 [SysInternals][sys-internals] 툴은 프로세스 인자, 파일 + 핸들러 그리고 레지스트리 작업을 탐색할 수 있게 도와줍니다. + +## Electron에 디버거 연결하고 디버깅하기 + +디버깅 작업을 시작하려면, PowerShell/CMD 중 한 가지를 열고 디버그 빌드 상태의 +Electron에 인자로 어플리케이션을 전달하여 실행합니다: + +```powershell +$ ./out/D/electron.exe ~/my-electron-app/ +``` + +### 중단점 설정 + +그리고, Visual Studio를 엽니다. Electron은 Visual Studio로 만들어지지 않았으며 +이러한 이유로 인해 프로젝트 파일을 가지고 있지 않습니다. 하지만 "파일로 열기"를 통해 +소스 코드 파일들을 열 수 있습니다. Visual Studio가 각각의 파일을 따로 연다는 것입니다. +여전히 중단점을 설정할 수 있습니다. Visual Studio는 현재 소스 코드와 일치하는 작동 +중인 프로세스와 중단점을 자동으로 찾아냅니다. + +관련된 코드 파일들은 `./atom/`에서 찾을 수 있으며 또한 Brightray 안 +`./vendor/brightray/browser`와 `./vendor/brightray/common`에서도 찾을 수 있습니다. +만약 하드코어를 좋아한다면, Chromium을 직접 디버깅할 수도 있습니다. 확실히 +`chromium_src` 안에서 찾을 수 있습니다. + +### 디버거 연결 + +로컬에서 작동 중인 프로세스 또는 원격 컴퓨터에 Visual Studio 디버거를 적용시킬 수 +있습니다. 프로세스의 실행이 끝난 후, 디버그 / 프로세스에 연결을 (또는 `Ctrl+Alt+P` +입력) 클릭하면 "프로세스에 연결" 대화 상자가 열립니다. 이 도구를 통해 로컬 또는 +원격에서 작동 중인 어플리케이션을 디버깅할 수 있으며 여러 프로세스를 동시에 디버깅할 +수도 있습니다. + +만약 Electron이 서로 다른 유저 계정에서 실행 중이라면, `모든 사용자의 프로세스 +보이기`를 선택하면 됩니다. 참고로 이는 `BrowserWindow`가 열린 개수에 따라 달라질 수 +있으며 아마 다수의 프로세스를 발견할 수 있을 것입니다. 전형적인 one-window +어플리케이션은 Visual Studio에서 두 개의 `Electron.exe` 항목으로 표시됩니다. 하나는 +메인 프로세스이며 다른 하나는 렌더러 프로세스입니다. 리스트는 단지 이름 하나만 제공하기 +때문에 현재까지는 다른 적절한 프로세스 판별법이 없습니다. + +### 어떤 프로세스에 디버거를 적용해야 하나요? + +코드는 메인 프로세스 내에서 실행되며 (이는 코드를 안에서 찾을 수 있거나, 결국 메인 +Javascript 파일에 의해 실행) remote (`require('electron').remote`)를 사용하여 +코드를 실행하는 것 또한 메인 프로세스 내에서 실행됩니다. 다른 코드는 각각의 렌더러 +프로세스 내에서 실행됩니다. + +디버깅할 때 여러 프로그램에 디버거를 적용할 수 있지만, 언제나 한 개의 프로그램만 +디버거에서 활성화되어야 합니다. `디버그 경로` 툴바 또는 `프로세스 창`에서 활성화 +프로그램을 설정할 수 있습니다. + +## 프로세스를 관찰하기 위해 ProcMon 사용 + +Visual Studio는 특정 코드 경로를 탐색하는것에 대해 환상적인 기능을 제공하고 ProcMon은 +어플리케이션이 운영체제와 하는 일의 모든 것을 관찰하는데 강력한 기능을 가지고 있습니다. +이 툴은 프로세스의 파일, 레지스트리, 네트워킹, 프로세스, 프로파일링 상세를 포착할 수 +있으며 강력하게 **모든** 이벤트의 발생을 로깅을 시도합니다. 만약 어플리케이션이 +운영체제에 대해 무슨 일을 하고 있는지 이해하고 싶다면 이는 좋은 자원이 될 것입니다. + +ProcMon의 기본적인 디버깅 기능을 알아보고 싶다면 Microsoft에서 제공하는 +[동영상 강좌][procmon-instructions]를 참고하세요. + +[sys-internals]: https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx +[procmon-instructions]: https://channel9.msdn.com/shows/defrag-tools/defrag-tools-4-process-monitor diff --git a/docs-translations/ko-KR/development/setting-up-symbol-server.md b/docs-translations/ko-KR/development/setting-up-symbol-server.md index 014f383ab29e..abfda6851bfc 100644 --- a/docs-translations/ko-KR/development/setting-up-symbol-server.md +++ b/docs-translations/ko-KR/development/setting-up-symbol-server.md @@ -14,14 +14,14 @@ 공식적인 Electron의 심볼 서버의 URL은 http://54.249.141.255:8086/atom-shell/symbols 입니다. 일단 이 URL에 직접적으로 -접근할 수는 없습니다: 디버깅 툴에 심볼의 경로를 추가해야합니다. 아래의 예제를 참고하면 +접근할 수는 없습니다: 디버깅 툴에 심볼의 경로를 추가해야 합니다. 아래의 예제를 참고하면 로컬 캐시 디렉터리는 서버로부터 중복되지 않게 PDB를 가져오는데 사용됩니다. `c:\code\symbols` 캐시 디렉터리를 사용중인 OS에 맞춰 적당한 경로로 변경하세요. ## Windbg에서 심볼 서버 사용하기 Windbg 심볼 경로는 구분자와 `*` 문자로 설정되어 있습니다. Electron 심볼 서버만 -사용하려면 심볼 경로의 엔트리를 추가해야 합니다. (__참고:__ `c:\code\symbols` +사용하려면 심볼 경로의 엔트리를 추가해야 합니다. (**참고:** `c:\code\symbols` 디렉터리 경로를 PC가 원하는 경로로 수정할 수 있습니다): ``` @@ -30,7 +30,7 @@ SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols Windbg 메뉴 또는 `.sympath` 커맨드를 이용하여 환경에 `_NT_SYMBOL_PATH` 문자열을 설정합니다. 만약 Microsoft의 심볼서버로부터 심볼을 받아오려면 다음과 같이 리스팅을 -먼저 해야합니다: +먼저해야 합니다: ``` SRV*c:\code\symbols\*http://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols diff --git a/docs-translations/ko-KR/development/source-code-directory-structure.md b/docs-translations/ko-KR/development/source-code-directory-structure.md index 7450b3b3e9ed..98a3fd2a1de0 100644 --- a/docs-translations/ko-KR/development/source-code-directory-structure.md +++ b/docs-translations/ko-KR/development/source-code-directory-structure.md @@ -13,7 +13,7 @@ Electron ├── atom - C++ 소스 코드. | ├── app - 시스템 엔트리 코드. | ├── browser - 주 윈도우를 포함한 프론트엔드, UI, 그리고 메인 프로세스에 관련된 -| | 코드와 랜더러 및 웹 페이지 관리 관련 코드. +| | 코드와 렌더러 및 웹 페이지 관리 관련 코드. | | ├── ui - 서로 다른 플랫폼에 대한 UI 관련 구현 코드. | | | ├── cocoa - Cocoa 특정 소스 코드. | | | ├── gtk - GTK+ 특정 소스 코드. @@ -22,9 +22,9 @@ Electron | | ├── net - 네트워킹 관련 코드. | | ├── mac - Mac 특정 Objective-C 소스 코드. | | └── resources - 아이콘들, 플랫폼 종속성 파일들, 기타 등등.. -| ├── renderer - 랜더러 프로세스에서 작동하는 코드. -| | └── api - 랜더러 프로세스 API의 구현. -| └── common - 메인과 랜더러 프로세스에서 모두 사용하는 코드, 몇가지 유틸리티 +| ├── renderer - 렌더러 프로세스에서 작동하는 코드. +| | └── api - 렌더러 프로세스 API의 구현. +| └── common - 메인과 렌더러 프로세스에서 모두 사용하는 코드, 몇가지 유틸리티 | 함수들이 포함되어 있고 node의 메시지 루프와 Chromium의 메시지 루프를 통합. | └── api - 공통 API 구현들, 기초 Electron 빌트-인 모듈들. ├── chromium_src - Chromium에서 복사하여 가져온 소스코드. @@ -33,9 +33,9 @@ Electron ├── lib - JavaScript 소스 코드. | ├── browser - Javascript 메인 프로세스 초기화 코드. | | └── api - Javascript API 구현 코드. -| ├── common - 메인과 랜더러 프로세스에서 모두 사용하는 JavaScript +| ├── common - 메인과 렌더러 프로세스에서 모두 사용하는 JavaScript | | └── api - Javascript API 구현 코드. -| └── renderer - Javascript 랜더러 프로세스 초기화 코드. +| └── renderer - Javascript 렌더러 프로세스 초기화 코드. | └── api - Javascript API 구현 코드. ├── spec - 자동화 테스트. ├── atom.gyp - Electron의 빌드 규칙. @@ -57,3 +57,30 @@ Electron 스크립트로부터 만들어지는 임시 디렉터리. * **external_binaries** - `gyp` 빌드를 지원하지 않아 따로 다운로드된 서드파티 프레임워크 바이너리들. + +## Git 서브 모듈 최신 버전으로 유지 + +Electron 저장소는 몇 가지 외부 벤더 종속성을 가지고 있으며 [/vendor](/vendor) +디렉터리에서 확인할 수 있습니다. 때때로 `git status`를 실행했을 때 아마 다음과 같은 +메시지를 흔히 목격할 것입니다: + +```sh +$ git status + + modified: vendor/brightray (new commits) + modified: vendor/node (new commits) +``` + +이 외부 종속성 모듈들을 업데이트 하려면, 다음 커맨드를 실행합니다: + +```sh +git submodule update --init --recursive +``` + +만약 자기 자신이 너무 이 커맨드를 자주 사용하는 것 같다면, `~/.gitconfig` 파일을 +생성하여 편하게 업데이트할 수 있습니다: + +``` +[alias] + su = submodule update --init --recursive +``` diff --git a/docs-translations/ko-KR/faq/electron-faq.md b/docs-translations/ko-KR/faq/electron-faq.md index 40d10f293f42..a038142c5ae3 100644 --- a/docs-translations/ko-KR/faq/electron-faq.md +++ b/docs-translations/ko-KR/faq/electron-faq.md @@ -20,13 +20,13 @@ Node.js의 새로운 기능은 보통 V8 업그레이드에서 가져옵니다. ## 어떻게 웹 페이지 간에 데이터를 공유할 수 있나요? -두 웹페이지 간에 (랜더러 프로세스) 데이터를 공유하려면 간단히 이미 모든 브라우저에서 +두 웹페이지 간에 (렌더러 프로세스) 데이터를 공유하려면 간단히 이미 모든 브라우저에서 사용할 수 있는 HTML5 API들을 사용하면 됩니다. 가장 좋은 후보는 [Storage API][storage], [`localStorage`][local-storage], [`sessionStorage`][session-storage], 그리고 [IndexedDB][indexed-db]가 있습니다. 또는 Electron에서만 사용할 수 있는 IPC 시스템을 사용하여 메인 프로세스의 global -변수에 데이터를 저장한 후 다음과 같이 랜더러 프로세스에서 `remote` 모듈을 사용하여 +변수에 데이터를 저장한 후 다음과 같이 렌더러 프로세스에서 `remote` 모듈을 사용하여 접근할 수 있습니다: ```javascript @@ -141,26 +141,13 @@ npm uninstall -g electron 그런데 여전히 빌트인 모듈이 계속해서 문제를 발생시키는 경우, 아마 모듈을 잘못 사용하고 있을 가능성이 큽니다. 예를 들면 `electron.app`은 메인 프로세스에서만 사용할 수 있는 -모듈이며, 반면 `electron.webFrame` 모듈은 랜더러 프로세스에서만 사용할 수 있는 +모듈이며, 반면 `electron.webFrame` 모듈은 렌더러 프로세스에서만 사용할 수 있는 모듈입니다. -## 왜 저의 앱 배경이 투명하죠? - -Electron `0.37.3` 부터, 기본 클라이언트 배경색이 `투명색`으로 변경되었습니다. -간단히 HTML에서 배경색을 지정합니다: - -```html - -``` - [memory-management]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management [variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx [electron-module]: https://www.npmjs.com/package/electron -[storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage -[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage -[session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage -[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API +[storage]: https://developer.mozilla.org/ko/docs/Web/API/Storage +[local-storage]: https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage +[session-storage]: https://developer.mozilla.org/ko/docs/Web/API/Window/sessionStorage +[indexed-db]: https://developer.mozilla.org/ko/docs/Web/API/IndexedDB_API diff --git a/docs-translations/ko-KR/styleguide.md b/docs-translations/ko-KR/styleguide.md index 8327cd3c1dd7..ec57970e513e 100644 --- a/docs-translations/ko-KR/styleguide.md +++ b/docs-translations/ko-KR/styleguide.md @@ -18,7 +18,7 @@ Electron 문서를 작성하는 규칙은 다음과 같습니다. 추가합니다. - 메서드 헤더는 `code backtick` 으로 표시합니다. - 이벤트 헤더는 한 '따옴표'로 표시합니다. -- 리스트를 2 단계 이상 중첩하지 않습니다. (안타깝게도 markdown 랜더러가 이를 지원하지 +- 리스트를 2 단계 이상 중첩하지 않습니다. (안타깝게도 markdown 렌더러가 이를 지원하지 않습니다) - 섹션에 대한 제목을 추가합니다. Events, Class 메서드 그리고 인스턴스 메서드 등 - 어떤 '것'의 사용 결과를 설명할 때 '될 것입니다' 형식을 사용하여 설명합니다. @@ -41,7 +41,7 @@ Electron 문서를 작성하는 규칙은 다음과 같습니다. 유지합니다. - 문서를 번역합니다. - 언어 디렉터리 내의 `README.md`에 번역한 문서의 링크를 추가합니다. -- 메인(upstream) Electron의 [README](https://github.com/atom/electron#documentation-translations)에 +- 메인(upstream) Electron의 [README](https://github.com/electron/electron#documentation-translations)에 번역된 언어 디렉터리의 링크를 추가합니다. ## Electron 문서 읽기 @@ -50,7 +50,7 @@ Electron 문서 구조를 이해하는 데 참고할 수 있는 유용한 도움 ### Methods -[Method](https://developer.mozilla.org/en-US/docs/Glossary/Method) 문서의 +[Method](https://developer.mozilla.org/ko/docs/Glossary/Method) 문서의 예제입니다: --- @@ -66,16 +66,16 @@ Electron 문서 구조를 이해하는 데 참고할 수 있는 유용한 도움 묶어 이 인수가 다른 인수뒤에서 선택적으로 사용될 수 있다는 것을 표시합니다. 메서드 이름 하단에선 각 인수에 대해 자세한 설명을 합니다. 인수의 타입은: -[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), -[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), -[`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), -[`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) +[`String`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String), +[`Number`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Number), +[`Object`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object), +[`Array`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array) 와 같은 일반적으로 쓰이는 타입 중 하나를 받거나 Electron의 [`webContent`](api/web-content.md) 같은 커스텀 타입을 받습니다. ### Events -[Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) 문서의 예제입니다: +[Event](https://developer.mozilla.org/ko/docs/Web/API/Event) 문서의 예제입니다: --- diff --git a/docs-translations/ko-KR/tutorial/application-distribution.md b/docs-translations/ko-KR/tutorial/application-distribution.md index 7072d7c4d952..445a9dda21d4 100644 --- a/docs-translations/ko-KR/tutorial/application-distribution.md +++ b/docs-translations/ko-KR/tutorial/application-distribution.md @@ -30,7 +30,7 @@ electron/resources/app ## asar로 앱 패키징 하기 -소스파일 전체를 복사해서 배포하는 것과는 별개로 [asar](https://github.com/atom/asar) +소스파일 전체를 복사해서 배포하는 것과는 별개로 [asar](https://github.com/electron/asar) 아카이브를 통해 어플리케이션의 소스코드가 사용자에게 노출되는 것을 방지할 수 있습니다. `asar` 아카이브를 사용할 땐 단순히 `app` 폴더 대신에 어플리케이션을 패키징한 diff --git a/docs-translations/ko-KR/tutorial/application-packaging.md b/docs-translations/ko-KR/tutorial/application-packaging.md index 9183f0eafe96..a33e2eef96cf 100644 --- a/docs-translations/ko-KR/tutorial/application-packaging.md +++ b/docs-translations/ko-KR/tutorial/application-packaging.md @@ -179,4 +179,4 @@ $ asar pack app app.asar --unpack *.node 포함되어 있습니다. 사용자에게 어플리케이션을 배포할 때 반드시 해당 폴더도 같이 배포해야 합니다. -[asar]: https://github.com/atom/asar +[asar]: https://github.com/electron/asar diff --git a/docs-translations/ko-KR/tutorial/debugging-main-process.md b/docs-translations/ko-KR/tutorial/debugging-main-process.md index 43b24c79b3a2..339c28daab7a 100644 --- a/docs-translations/ko-KR/tutorial/debugging-main-process.md +++ b/docs-translations/ko-KR/tutorial/debugging-main-process.md @@ -1,6 +1,6 @@ # 메인 프로세스 디버깅하기 -브라우저 창의 개발자 도구는 웹 페이지 같은 랜더러 프로세스의 스크립트만 디버깅이 +브라우저 창의 개발자 도구는 웹 페이지 같은 렌더러 프로세스의 스크립트만 디버깅이 가능합니다. 대신 Electron은 메인 프로세스의 디버깅을 위해 `--debug` 과 `--debug-brk` 스위치들을 제공합니다. @@ -19,7 +19,7 @@ ## node-inspector로 디버깅 하기 -__참고:__ Electron은 현재 node-inspector 유틸리티와 호환성 문제가 있습니다. 따라서 +**참고:** Electron은 현재 node-inspector 유틸리티와 호환성 문제가 있습니다. 따라서 node-inspector 콘솔 내에서 메인 프로세스의 `process` 객체를 탐색할 경우 크래시가 발생할 수 있습니다. diff --git a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md b/docs-translations/ko-KR/tutorial/desktop-environment-integration.md index ddeadc04e916..961bfc83076f 100644 --- a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md +++ b/docs-translations/ko-KR/tutorial/desktop-environment-integration.md @@ -14,7 +14,7 @@ Windows, Linux, OS X 운영체제 모두 기본적으로 어플리케이션에 통해 개발자가 편리하게 데스크톱 알림을 사용할 수 있는 기능을 제공합니다. 데스크톱 알림은 운영체제의 네이티브 알림 API를 사용하여 표시합니다. -__참고:__ 이 API는 HTML5 API이기 때문에 랜더러 프로세스에서만 사용할 수 있습니다. +**참고:** 이 API는 HTML5 API이기 때문에 렌더러 프로세스에서만 사용할 수 있습니다. ```javascript var myNotification = new Notification('Title', { diff --git a/docs-translations/ko-KR/tutorial/devtools-extension.md b/docs-translations/ko-KR/tutorial/devtools-extension.md index 655c6ed7d5c2..b45f88892d81 100644 --- a/docs-translations/ko-KR/tutorial/devtools-extension.md +++ b/docs-translations/ko-KR/tutorial/devtools-extension.md @@ -8,7 +8,7 @@ 한가지 주의할 점은 확장 기능 사용시 창이 생성될 때 마다 일일이 해당 API를 호출할 필요는 없습니다. -**주의: 현재 React DevTools은 작동하지 않습니다. https://github.com/atom/electron/issues/915 이슈를 참고하세요!** +**주의: 현재 React DevTools은 작동하지 않습니다. https://github.com/electron/electron/issues/915 이슈를 참고하세요!** 다음 예제는 [React DevTools Extension](https://github.com/facebook/react-devtools)을 사용합니다. diff --git a/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md b/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md index c319f344b638..45342f14de28 100644 --- a/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md +++ b/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md @@ -4,11 +4,7 @@ Electron은 v0.34.0 버전부터 앱 패키지를 Mac App Store(MAS)에 제출 되었습니다. 이 가이드는 어플리케이션을 앱 스토어에 등록하는 방법과 빌드의 한계에 대한 설명을 제공합니다. -__참고:__ v0.36.0 버전부터 어플리케이션이 샌드박스화 된 상태로 실행되면 GPU 작동을 -방지하는 버그가 있었습니다. 따라서 이 버그가 고쳐지기 전까진 v0.35.x 버전을 사용하는 -것을 권장합니다. 이 버그에 관한 자세한 사항은 [issue #3871][issue-3871]를 참고하세요. - -__참고:__ Mac App Store에 어플리케이션을 등록하려면 +**참고:** Mac App Store에 어플리케이션을 등록하려면 [Apple Developer Program][developer-program]에 등록되어 있어야 하며 비용이 발생할 수 있습니다. @@ -17,7 +13,7 @@ __참고:__ Mac App Store에 어플리케이션을 등록하려면 다음 몇 가지 간단한 절차에 따라 앱 스토어에 어플리케이션을 등록하는 방법을 알아봅니다. 한가지, 이 절차는 제출한 앱이 Apple로부터 승인되는 것을 보장하지 않습니다. 따라서 여전히 Apple의 [Submitting Your App][submitting-your-app] 가이드를 숙지하고 있어야 -하며 앱 스토어 제출 요구 사항을 확실히 인지하고 있어야합니다. +하며 앱 스토어 제출 요구 사항을 확실히 인지하고 있어야 합니다. ### 인증서 취득 @@ -56,6 +52,8 @@ Apple로부터 인증서를 취득했다면, [어플리케이션 배포](applica com.apple.security.app-sandbox + com.apple.security.temporary-exception.sbpl + (allow mach-lookup (global-name-regex #"^org.chromium.Chromium.rohitfork.[0-9]+$")) ``` @@ -77,17 +75,18 @@ INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" -if [ -d "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" ]; then - # non-MAS 빌드 서명 - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Mantle.framework/Versions/A" - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/ReactiveCocoa.framework/Versions/A" - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" -fi -codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$APP_PATH/Contents/MacOS/$APP" +codesign -s "$APP_KEY" -f --entitlements parent.plist "$APP_PATH" productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" ``` @@ -96,11 +95,31 @@ productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RES 문서를 참고하여 기본적인 개념을 이해해야 합니다. 그리고 자격(plist) 파일에 어플리케이션에서 요구하는 권한의 키를 추가합니다. -### 어플리케이션을 업로드하고 심사용 앱으로 제출 +### 어플리케이션 업로드 어플리케이션 서명을 완료한 후 iTunes Connect에 업로드하기 위해 Application Loader를 사용할 수 있습니다. 참고로 업로드하기 전에 [레코드][create-record]를 만들었는지 -확인해야 합니다. 그리고 [심사를 위해 앱을 제출][submit-for-review]할 수 있습니다. +확인해야 합니다. + +### `temporary-exception`의 사용처 설명 + +어플리케이션을 샌드박싱할 때 `temporary-exception` 엔트리가 자격에 추가되며 +[어플리케이션 샌드박스 임시 예외 적용][temporary-exception] 문서에 따라 +왜 이 엔트리가 필요한지 설명해야 합니다: + +> Note: If you request a temporary-exception entitlement, be sure to follow the +guidance regarding entitlements provided on the iTunes Connect website. In +particular, identify the entitlement and corresponding issue number in the App +Sandbox Entitlement Usage Information section in iTunes Connect and explain why +your app needs the exception. + +아마 제출하려는 어플리케이션이 Chromium 브라우저를 기반으로 만들어졌고, 또한 +멀티-프로세스 구조를 위해 Mach 포트를 사용하는 것도 설명해야 할 수 있습니다. 하지만 +여전히 이러한 문제 때문에 어플리케이션 심사에 실패할 수 있습니다. + +### 어플리케이션을 심사에 제출 + +위 과정을 마치면 [어플리케이션을 심사를 위해 제출][submit-for-review]할 수 있습니다. ## MAS 빌드의 한계 @@ -117,7 +136,7 @@ productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RES * 어플리케이션이 DNS의 변경을 감지하지 못할 수 있습니다. 또한 어플리케이션 샌드박스 개념으로 인해 어플리케이션에서 접근할 수 있는 리소스는 -엄격하게 제한되어 있습니다. 자세한 내용은 [App Sandboxing][app-sandboxing] 문서를 +엄격하게 제한되어 있습니다. 자세한 내용은 [앱 샌드박싱][app-sandboxing] 문서를 참고하세요. ## Electron에서 사용하는 암호화 알고리즘 @@ -164,5 +183,5 @@ ERN의 승인을 얻는 방법은, 다음 글을 참고하는 것이 좋습니 [create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html [submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html [app-sandboxing]: https://developer.apple.com/app-sandboxing/ -[issue-3871]: https://github.com/atom/electron/issues/3871 [ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ +[temporary-exception]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html diff --git a/docs-translations/ko-KR/tutorial/online-offline-events.md b/docs-translations/ko-KR/tutorial/online-offline-events.md index f66e2e2bbb59..5b91fc61bd55 100644 --- a/docs-translations/ko-KR/tutorial/online-offline-events.md +++ b/docs-translations/ko-KR/tutorial/online-offline-events.md @@ -1,6 +1,6 @@ # 온라인/오프라인 이벤트 감지 -온라인/오프라인 이벤트는 다음 예제와 같이 랜더러 프로세스에서 표준 HTML5 API를 이용하여 +온라인/오프라인 이벤트는 다음 예제와 같이 렌더러 프로세스에서 표준 HTML5 API를 이용하여 구현할 수 있습니다. _main.js_ diff --git a/docs-translations/ko-KR/tutorial/quick-start.md b/docs-translations/ko-KR/tutorial/quick-start.md index 82d359e0de5f..eb95232a06fc 100644 --- a/docs-translations/ko-KR/tutorial/quick-start.md +++ b/docs-translations/ko-KR/tutorial/quick-start.md @@ -16,23 +16,23 @@ Electron은 실행될 때 __메인 프로세스__ 로 불리는 `package.json` 호출합니다. 이 스크립트는 메인 프로세스에서 작동합니다. GUI 컴포넌트를 조작하거나 웹 페이지 창을 생성할 수 있습니다. -### 랜더러 프로세스 +### 렌더러 프로세스 Electron이 웹페이지를 보여줄 때 Chromium의 multi-processes 구조도 같이 사용됩니다. -Electron 프로세스 내에서 작동하는 웹 페이지를 __랜더러 프로세스__ 라고 불립니다. +Electron 프로세스 내에서 작동하는 웹 페이지를 __렌더러 프로세스__ 라고 불립니다. 보통 일반 브라우저의 웹 페이지들은 샌드박스가 적용된 환경에서 작동하며 네이티브 리소스에는 접근할 수 없도록 되어 있습니다. 하지만 Electron은 웹 페이지 내에서 Node.js API를 사용하여 low-level 수준으로 운영체제와 상호작용할 수 있습니다. -### 메인 프로세스와 랜더러 프로세스의 차이점 +### 메인 프로세스와 렌더러 프로세스의 차이점 메인 프로세스는 `BrowserWindow` Class를 사용하여 새로운 창을 만들 수 있습니다. -`BrowserWindow` 인스턴스는 따로 분리된 프로세스에서 랜더링 되며 이 프로세스를 랜더러 -프로세스라고 합니다. `BrowserWindow` 인스턴스가 소멸할 때 그 창의 랜더러 프로세스도 +`BrowserWindow` 인스턴스는 따로 분리된 프로세스에서 렌더링 되며 이 프로세스를 렌더러 +프로세스라고 합니다. `BrowserWindow` 인스턴스가 소멸할 때 그 창의 렌더러 프로세스도 같이 소멸합니다. -메인 프로세스는 모든 웹 페이지와 랜더러 프로세스를 관리하며 랜더러 프로세스는 각각의 +메인 프로세스는 모든 웹 페이지와 렌더러 프로세스를 관리하며 렌더러 프로세스는 각각의 프로세스에 고립되며 웹 페이지의 작동에만 영향을 끼칩니다. 웹 페이지 내에선 기본적으로 네이티브 GUI와 관련된 API를 호출할 수 없도록 설계 되어 @@ -40,7 +40,7 @@ API를 사용하여 low-level 수준으로 운영체제와 상호작용할 수 리소스를 누수시킬 수 있기 때문입니다. 꼭 웹 페이지 내에서 API를 사용해야 한다면 메인 프로세스에서 그 작업을 처리할 수 있도록 메인 프로세스와 통신을 해야 합니다. -Electron에는 메인 프로세스와 랜더러 프로세스 사이에 통신을 할 수 있도록 +Electron에는 메인 프로세스와 렌더러 프로세스 사이에 통신을 할 수 있도록 [ipc](../api/ipc-renderer.md) 모듈을 제공하고 있습니다. 또는 [remote](../api/remote.md) 모듈을 사용하여 RPC 스타일로 통신할 수도 있습니다. 또한 FAQ에서 [다양한 객체를 공유하는 방법](share-data)도 소개하고 있습니다. @@ -186,7 +186,7 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/ ``` 어플리케이션 실행파일은 `Electron`의 release 패키지에 포함되어 있습니다. -[여기](https://github.com/atom/electron/releases)에서 다운로드 받을 수 있습니다. +[여기](https://github.com/electron/electron/releases)에서 다운로드 받을 수 있습니다. ### 배포용 실행 파일 만들기 @@ -195,7 +195,7 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/ ### 미리 작성된 앱 실행하기 -[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) +[`atom/electron-quick-start`](https://github.com/electron/electron-quick-start) 저장소를 클론하면 이 문서에서 작성한 예제 앱을 바로 실행해 볼 수 있습니다. **참고**: 이 예제를 실행시키려면 [Git](https://git-scm.com)과 @@ -206,7 +206,7 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/ ```bash # 저장소를 클론합니다 -$ git clone https://github.com/atom/electron-quick-start +$ git clone https://github.com/electron/electron-quick-start # 저장소 안으로 들어갑니다 $ cd electron-quick-start # 어플리케이션의 종속성 모듈을 설치한 후 실행합니다 diff --git a/docs-translations/ko-KR/tutorial/supported-platforms.md b/docs-translations/ko-KR/tutorial/supported-platforms.md index 656d31308e07..d71951cd3d8e 100644 --- a/docs-translations/ko-KR/tutorial/supported-platforms.md +++ b/docs-translations/ko-KR/tutorial/supported-platforms.md @@ -12,7 +12,7 @@ Windows 7 이후 버전만 지원됩니다. Windows Vista에서도 작동할 수 테스트가 완료되지 않았습니다. 윈도우용 바이너리는 `x86`과 `x64` 모두 제공됩니다. 그리고 `ARM` 버전 윈도우는 아직 -지원하지 않습니다. (역주: 추후 지원할 가능성이 있습니다) +지원하지 않습니다. ### Linux diff --git a/docs-translations/ko-KR/tutorial/testing-on-headless-ci.md b/docs-translations/ko-KR/tutorial/testing-on-headless-ci.md index be88be1cec6d..4fec05e15056 100644 --- a/docs-translations/ko-KR/tutorial/testing-on-headless-ci.md +++ b/docs-translations/ko-KR/tutorial/testing-on-headless-ci.md @@ -16,9 +16,9 @@ Electron 기반 어플리케이션을 Travis, Circle, Jenkins 또는 유사한 그리고, 가상 xvfb 스크린을 생성하고 DISPLAY라고 불리우는 환경 변수를 지정합니다. Electron의 Chromium은 자동적으로 `$DISPLAY` 변수를 찾습니다. 따라서 앱의 추가적인 다른 설정이 필요하지 않습니다. 이러한 작업은 Paul Betts의 -[xfvb-maybe](https://github.com/paulcbetts/xvfb-maybe)를 통해 자동화 할 수 -있습니다: `xfvb-maybe`를 테스트 커맨드 앞에 추가하고 현재 시스템에서 요구하면 -이 작은 툴이 자동적으로 xfvb를 설정합니다. Windows와 Mac OS X에선 간단히 아무 작업도 +[xvfb-maybe](https://github.com/paulcbetts/xvfb-maybe)를 통해 자동화 할 수 +있습니다: `xvfb-maybe`를 테스트 커맨드 앞에 추가하고 현재 시스템에서 요구하면 +이 작은 툴이 자동적으로 xvfb를 설정합니다. Windows와 Mac OS X에선 간단히 아무 작업도 하지 않습니다. ``` @@ -45,7 +45,7 @@ install: ### Jenkins -Jenkins는 [Xfvb 플러그인이 존재합니다](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). +Jenkins는 [Xvfb 플러그인이 존재합니다](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). ### Circle CI diff --git a/docs-translations/ko-KR/tutorial/using-native-node-modules.md b/docs-translations/ko-KR/tutorial/using-native-node-modules.md index d1c3aa167ad6..e153b265b634 100644 --- a/docs-translations/ko-KR/tutorial/using-native-node-modules.md +++ b/docs-translations/ko-KR/tutorial/using-native-node-modules.md @@ -9,9 +9,9 @@ Electron의 V8 버전에 맞춰 네이티브 모듈을 다시 빌드하고 헤 네이티브 모듈은 node.js가 새로운 V8 버전을 사용함으로 인해 작동하지 않을 수 있습니다. 사용하는 네이티브 모듈이 Electron에 맞춰 작동할 수 있도록 하려면 Electron에서 사용하는 node.js의 버전을 확인할 필요가 있습니다. Electron에서 사용하는 node 버전은 -[releases](https://github.com/atom/electron/releases)에서 확인할 수 있으며 +[releases](https://github.com/electron/electron/releases)에서 확인할 수 있으며 `process.version`을 출력하여 버전을 확인할 수도 있습니다. -([시작하기](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md)의 +([시작하기](./quick-start.md)의 예제를 참고하세요) 혹시 직접 만든 네이티브 모듈이 있다면 [NAN](https://github.com/nodejs/nan/) 모듈을 diff --git a/docs-translations/ko-KR/tutorial/using-pepper-flash-plugin.md b/docs-translations/ko-KR/tutorial/using-pepper-flash-plugin.md index 2f15a3532eea..1437bbde92c9 100644 --- a/docs-translations/ko-KR/tutorial/using-pepper-flash-plugin.md +++ b/docs-translations/ko-KR/tutorial/using-pepper-flash-plugin.md @@ -13,7 +13,7 @@ Pepper 플래시 플러그인을 사용하려면 Pepper 플래시 플러그인 플러그인을 사용하려면 Electron 커맨드 라인에 `--ppapi-flash-path` 와 `ppapi-flash-version` 플래그를 app의 ready 이벤트가 호출되기 전에 추가해야 합니다. -그리고 `browser-window`에 `plugins` 스위치도 추가해야합니다. +그리고 `browser-window`에 `plugins` 스위치도 추가해야 합니다. ```javascript // 플래시 플러그인의 위치를 설정합니다. diff --git a/docs-translations/ko-KR/tutorial/using-widevine-cdm-plugin.md b/docs-translations/ko-KR/tutorial/using-widevine-cdm-plugin.md index b9fec886769d..698503df484f 100644 --- a/docs-translations/ko-KR/tutorial/using-widevine-cdm-plugin.md +++ b/docs-translations/ko-KR/tutorial/using-widevine-cdm-plugin.md @@ -8,7 +8,7 @@ Electron은 라이센스상의 문제로 Widevine CDM 플러그인을 직접 제 따라서 플러그인을 얻으려면 먼저 사용할 Electron 빌드의 아키텍쳐와 버전에 맞춰 공식 Chrome 브라우저를 설치해야 합니다. -__참고:__ Chrome 브라우저의 메이저 버전은 Electron에서 사용하는 Chrome 버전과 +**참고:** Chrome 브라우저의 메이저 버전은 Electron에서 사용하는 Chrome 버전과 같습니다, 만약 그렇지 않다면 `navigator.plugins`가 로드됐더라도 정상적으로 작동하지 않습니다. @@ -42,7 +42,7 @@ Linux에선 플러그인 바이너리들이 Chrome 브라우저와 함께 제공 `widevinecdmadapter`의 위치를 전달하고 플러그인의 버전을 `--widevine-cdm-version` 스위치에 전달해야 합니다. -__참고:__ `widevinecdmadapter` 바이너리가 Electron으로 전달되어도, `widevinecdm` +**참고:** `widevinecdmadapter` 바이너리가 Electron으로 전달되어도, `widevinecdm` 바이너리는 옆에 같이 두어야 합니다. 커맨드 라인 스위치들은 `app` 모듈의 `ready` 이벤트가 발생하기 전에 전달되어야 합니다. diff --git a/docs-translations/pt-BR/development/build-instructions-linux.md b/docs-translations/pt-BR/development/build-instructions-linux.md index 532892a40833..5e8ffe447804 100644 --- a/docs-translations/pt-BR/development/build-instructions-linux.md +++ b/docs-translations/pt-BR/development/build-instructions-linux.md @@ -43,7 +43,7 @@ de um container de tamanho fixo de pelo menos 25 gigabytes. ## Baixando o Código ```bash -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## Bootstrapping diff --git a/docs-translations/pt-BR/development/coding-style.md b/docs-translations/pt-BR/development/coding-style.md index b0068d568924..acfdf7e3dbd7 100644 --- a/docs-translations/pt-BR/development/coding-style.md +++ b/docs-translations/pt-BR/development/coding-style.md @@ -23,4 +23,4 @@ Para CoffeeScript, seguimos o [Guia de Estilo] (https://github.com/styleguide/ja Ao criar uma nova API, devemos preferencialmente utilizar métodos getters e setters em vez do estilo de uma função única do jQuery. Por exemplo, `.getText()` e `.setText(text)` são preferenciais a `.text([text])`. Existe uma -[discussão](https://github.com/atom/electron/issues/46) sobre este assunto. +[discussão](https://github.com/electron/electron/issues/46) sobre este assunto. diff --git a/docs-translations/pt-BR/tutorial/quick-start.md b/docs-translations/pt-BR/tutorial/quick-start.md index 1b1d6942379d..76b128df5d04 100644 --- a/docs-translations/pt-BR/tutorial/quick-start.md +++ b/docs-translations/pt-BR/tutorial/quick-start.md @@ -180,7 +180,7 @@ $ ./Electron.app/Contents/MacOS/Electron seu-app/ ``` `Electron.app` aqui é uma parte do pacote de lançamento do Electron, você pode baixa-lo -[aqui](https://github.com/atom/electron/releases). +[aqui](https://github.com/electron/electron/releases). ### Executar como uma distribuição diff --git a/docs-translations/pt-BR/tutorial/using-native-node-modules.md b/docs-translations/pt-BR/tutorial/using-native-node-modules.md index c5e9eeddd61e..8cc883046eb9 100644 --- a/docs-translations/pt-BR/tutorial/using-native-node-modules.md +++ b/docs-translations/pt-BR/tutorial/using-native-node-modules.md @@ -12,8 +12,8 @@ Para ter certeza que o módulo que você está interessado em trabalhar com o Electron, você deve checar se a versão do Node utilizada é compatível com a usada pelo Electron. Você pode verificar qual versão do Node foi utilizada no Electron olhando na -página [releases](https://github.com/atom/electron/releases) ou usando -`process.version` (veja [Quick Start](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md) +página [releases](https://github.com/electron/electron/releases) ou usando +`process.version` (veja [Quick Start](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md) por exemplo). Considere usar [NAN](https://github.com/nodejs/nan/) para seus próprios diff --git a/docs-translations/tr-TR/README.md b/docs-translations/tr-TR/README.md new file mode 100644 index 000000000000..b055e63f5af1 --- /dev/null +++ b/docs-translations/tr-TR/README.md @@ -0,0 +1,86 @@ +Lütfen kullandığınız dokümanın Electron versiyonunuzla aynı olduğundan emin olun. +Versiyon numarası okuduğunuz dokümanın URL'sindekiyle aynı olmalı. Eğer aynı değilse, muhtemelen geliştirme aşamasındaki API değişikliklerini içerebilecek dokümantasyonudur. +Eğer öyleyse, atom.io üzerinden [mevcut sürümler](http://electron.atom.io/docs/)e göz atabilirsiniz ya da eğer GitHub arayüzünü kullanıyorsanız "Switch branches/tags" açılır menüsünden versiyonunuza uygun olanı seçebilirsiniz. + +## SSS(Sıkça Sorulan Sorular) + +Bir problem(issue) bildirmeden önce sıkça sorulan sorulara göz atın: +* [Electron SSS](https://github.com/electron/electron/tree/master/docs/faq/electron-faq.md) + +## Klavuzlar + +* [Desteklenen Platformlar ](https://github.com/electron/electron/tree/master/docs/tutorial/supported-platforms.md) +* [Uygulama Dağıtımı](https://github.com/electron/electron/tree/master/docs/tutorial/application-distribution.md) +* [Mac Uygulama Mağazası Başvuru Klavuzu](https://github.com/electron/electron/tree/master/docs/tutorial/mac-app-store-submission-guide.md) +* [Uygulama Paketleme](https://github.com/electron/electron/tree/master/docs/tutorial/application-packaging.md) +* [Native Node Modüllerini Kullanma](https://github.com/electron/electron/tree/master/docs/tutorial/using-native-node-modules.md) +* [Ana Süreç(Main Process) Hata ayıklama](https://github.com/electron/electron/tree/master/docs/tutorial/debugging-main-process.md) +* [Selenium ve WebDriver kullanımı](https://github.com/electron/electron/tree/master/docs/tutorial/using-selenium-and-webdriver.md) +* [DevTools Eklentisi](https://github.com/electron/electron/tree/master/docs/tutorial/devtools-extension.md) +* [Pepper Flash Kullanımı](https://github.com/electron/electron/tree/master/docs/tutorial/using-pepper-flash-plugin.md) +* [Widevine CDM Kullanımı](https://github.com/electron/electron/tree/master/docs/tutorial/using-widevine-cdm-plugin.md) +* [CI Sistem Testleri (Travis, Jenkins)](https://github.com/electron/electron/tree/master/docs/tutorial/testing-on-headless-ci.md) + +## Eğitimler + +* [Quick Start](https://github.com/electron/electron/tree/master/docs/tutorial/quick-start.md) +* [Desktop Environment Integration](https://github.com/electron/electron/tree/master/docs/tutorial/desktop-environment-integration.md) +* [Online/Offline Event Detection](https://github.com/electron/electron/tree/master/docs/tutorial/online-offline-events.md) + +## API Kaynakları + +* [Synopsis](https://github.com/electron/electron/tree/master/docs/api/synopsis.md) +* [Process Object](https://github.com/electron/electron/tree/master/docs/api/process.md) +* [Desteklenen Chrome Komut Satırı Anahtarları](https://github.com/electron/electron/tree/master/docs/api/chrome-command-line-switches.md) +* [Environment Değişkenleri](https://github.com/electron/electron/tree/master/docs/api/environment-variables.md) + +### Özel DOM Elementleri: + +* [`File` Nesnesi](api/file-object.md) +* [`` Etiketi](https://github.com/electron/electron/tree/master/docs/api/web-view-tag.md) +* [`window.open` Fonksiyonu](https://github.com/electron/electron/tree/master/docs/api/window-open.md) + +### Ana Süreç(Main Process) Modülleri: + +* [app](https://github.com/electron/electron/tree/master/docs/api/app.md) +* [autoUpdater](https://github.com/electron/electron/tree/master/docs/api/auto-updater.md) +* [BrowserWindow](https://github.com/electron/electron/tree/master/docs/api/browser-window.md) +* [contentTracing](https://github.com/electron/electron/tree/master/docs/api/content-tracing.md) +* [dialog](https://github.com/electron/electron/tree/master/docs/api/dialog.md) +* [globalShortcut](https://github.com/electron/electron/tree/master/docs/api/global-shortcut.md) +* [ipcMain](https://github.com/electron/electron/tree/master/docs/api/ipc-main.md) +* [Menu](https://github.com/electron/electron/tree/master/docs/api/menu.md) +* [MenuItem](https://github.com/electron/electron/tree/master/docs/api/menu-item.md) +* [powerMonitor](https://github.com/electron/electron/tree/master/docs/api/power-monitor.md) +* [powerSaveBlocker](https://github.com/electron/electron/tree/master/docs/api/power-save-blocker.md) +* [protocol](https://github.com/electron/electron/tree/master/docs/api/protocol.md) +* [session](https://github.com/electron/electron/tree/master/docs/api/session.md) +* [webContents](https://github.com/electron/electron/tree/master/docs/api/web-contents.md) +* [Tray](https://github.com/electron/electron/tree/master/docs/api/tray.md) + +### Renderer Process Modülelri (Web Page): + +* [desktopCapturer](https://github.com/electron/electron/tree/master/docs/api/desktop-capturer.md) +* [ipcRenderer](https://github.com/electron/electron/tree/master/docs/api/ipc-renderer.md) +* [remote](https://github.com/electron/electron/tree/master/docs/api/remote.md) +* [webFrame](https://github.com/electron/electron/tree/master/docs/api/web-frame.md) + +### Her İki Süreç İçin Geçerli Modüller: + +* [clipboard](https://github.com/electron/electron/tree/master/docs/api/clipboard.md) +* [crashReporter](https://github.com/electron/electron/tree/master/docs/api/crash-reporter.md) +* [nativeImage](https://github.com/electron/electron/tree/master/docs/api/native-image.md) +* [screen](https://github.com/electron/electron/tree/master/docs/api/screen.md) +* [shell](https://github.com/electron/electron/tree/master/docs/api/shell.md) + +## Geliştirme + +* [Kodlama Stili](https://github.com/electron/electron/tree/master/docs/development/coding-style.md) +* [Kaynak Kod Dizin Yapısı](https://github.com/electron/electron/tree/master/docs/development/source-code-directory-structure.md) +* [NW.js(node-webkit adıyla bilinen) İle Arasındaki Teknik Farklılıklar](https://github.com/electron/electron/tree/master/docs/development/atom-shell-vs-node-webkit.md) +* [Build Sisyem Genel Bakış](https://github.com/electron/electron/tree/master/docs/development/build-system-overview.md) +* [(OS X) Build Komutları](https://github.com/electron/electron/tree/master/docs/development/build-instructions-osx.md) +* [(Windows) Build Komutları](https://github.com/electron/electron/tree/master/docs/development/build-instructions-windows.md) +* [(Linux) Build Komutları](https://github.com/electron/electron/tree/master/docs/development/build-instructions-linux.md) +* [(Windows) Hata Ayıklama Komutları](https://github.com/electron/electron/tree/master/docs/development/debug-instructions-windows.md) +* [Simge Sunucusu(Symbol Server) Hata Ayıklama Kurulumu](https://github.com/electron/electron/tree/master/docs/development/setting-up-symbol-server.md) diff --git a/docs-translations/tr-TR/api/accelerator.md b/docs-translations/tr-TR/api/accelerator.md new file mode 100644 index 000000000000..9105e5c6e460 --- /dev/null +++ b/docs-translations/tr-TR/api/accelerator.md @@ -0,0 +1,49 @@ +# Hızlandırıcı + +> Kısayol Tanımlama. + +Hızlandırıcılar `+` karakteriyle birden fazla niteleyici ile kombinlenebilir. + +Örnek: + +* `CommandOrControl+A` +* `CommandOrControl+Shift+Z` + +## Platform bilgileri + +Linux ve Windows'ta `Command` tuşu herhangi bir etki göstermez. Bunun yerine +`CommandOrControl` niteleyicisini kullanın. Bu işlem OS X'te `Command`, +Linux ve Windows'ta `Control` tuşunun işlevini sağlar. `Alt` ise tüm platformlarda mevcuttur. + +`Super` tuşu Windows ve Linux'te `Windows` tuşuna, OS X'te ise `Cmd` tuşuna eşleştirilmiştir. + +## Mevcut düzenleyiciler + +* `Command` (ya da kısa tanım için `Cmd`) +* `Control` (ya da kısa tanım için `Ctrl`) +* `CommandOrControl` (ya da kısa tanım için `CmdOrCtrl`) +* `Alt` +* `Option` +* `AltGr` +* `Shift` +* `Super` + +## Mevcut tuş kodları + +* `0`dan `9`a +* `A`dan `Z`ye +* `F1`dan `F24`e +* Noktalama işaretleri `~`, `!`, `@`, `#`, `$`, vb. +* `Plus` +* `Space` +* `Backspace` +* `Delete` +* `Insert` +* `Return` (ya da `Enter`) +* `Up`, `Down`, `Left` ve `Right` +* `Home` ve `End` +* `PageUp` ve `PageDown` +* `Escape` (ya da kısa tanım için `Esc`) +* `VolumeUp`, `VolumeDown` ve `VolumeMute` +* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` ve `MediaPlayPause` +* `PrintScreen` diff --git a/docs-translations/tr-TR/api/file-object.md b/docs-translations/tr-TR/api/file-object.md new file mode 100644 index 000000000000..a99bdb329c5d --- /dev/null +++ b/docs-translations/tr-TR/api/file-object.md @@ -0,0 +1,29 @@ +# `File` nesnesi + +> Dosya ve dosya sistemlerinde HTML5 `File` nesnesini native olarak çalışır. + +DOM Dosya arayüzü HTML5 dosya API'sini kullanarak kullanıcılara doğrudan native dosyalar üzerinde çalışmasına olanak sağlar. Electron'da `File` arayüzü için `path` özelliğini eklemiştir. + +`dragged-onto-the-app`'dan tam dosya yolu alma örneği: + +```html +

+ Dosyalarınızı buraya sürükleyin +
+ + +``` diff --git a/docs-translations/tr-TR/styleguide.md b/docs-translations/tr-TR/styleguide.md new file mode 100644 index 000000000000..5e8f75240721 --- /dev/null +++ b/docs-translations/tr-TR/styleguide.md @@ -0,0 +1,95 @@ +# Electron Dokümantasyonu Stil Rehberi + +Size uygun bölümü bulun: [Electron Dokümantasyonunu okumak](#reading-electron-documentation) +ya da [Electron Dokümantasyonunu yazmak](#writing-electron-documentation). + +## Electron Dokümantasyonunu Yazmak + +Electron Dokümantasyonunu geliştirmek için aşağıdaki yöntemleri takip edin. + +- Her sayfada en fazla bir tane `h1` etiketi olmalıdır. +- Kod bloklarında `cmd` yerine `bash` kullanın.(syntax highlighter için). +- `h1` Başlığı nesne ismiyle eşleşmeli (ör. `browser-window` → + `BrowserWindow`). + - Hyphen separated filenames, however, are fine. +- No headers following headers, add at least a one-sentence description. +- Methods headers are wrapped in `code` ticks. +- Event headers are wrapped in single 'quotation' marks. +- No nesting lists more than 2 levels (unfortunately because of markdown + renderer). +- Add section titles: Events, Class Methods and Instance Methods. +- Use 'will' over 'would' when describing outcomes. +- Events and methods are `h3` headers. +- Optional arguments written as `function (required[, optional])`. +- Optional arguments are denoted when called out in list. +- Line length is 80-column wrapped. +- Platform specific methods are noted in italics following method header. + - ```### `method(foo, bar)` _OS X_``` +- Prefer 'in the ___ process' over 'on' + +### Dokümantasyon Çevirisi + +Electron Dokümantasyonunun çevirileri `docs-translations` klasörü içerisindedir. + +To add another set (or partial set): + +- Create a subdirectory named by language abbreviation. +- Within that subdirectory, duplicate the `docs` directory, keeping the + names of directories and files same. +- Translate the files. +- Update the `README.md` within your language directory to link to the files + you have translated. +- Add a link to your translation directory on the main Electron [README](https://github.com/electron/electron#documentation-translations). + +## Electron Dokümantasyonunu Okumak + +Electron Dokümantasyon sözdizimini(syntax) anlayabileceğiniz bir kaç ipucu: + +### Metodlar + +[Method](https://developer.mozilla.org/en-US/docs/Glossary/Method) dokümantasyonunun bir örneği: + +--- + +`methodName(required[, optional]))` + +* `require` String (**required**) +* `optional` Integer + +--- + +The method name is followed by the arguments it takes. Optional arguments are +notated by brackets surrounding the optional argument as well as the comma +required if this optional argument follows another argument. + +Below the method is more detailed information on each of the arguments. The type +of argument is notated by either the common types: +[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), +[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), +[`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), +[`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) +or a custom type like Electron's [`webContent`](https://github.com/electron/electron/tree/master/docs/api/web-content.md). + +### Events + +[event](https://developer.mozilla.org/en-US/docs/Web/API/Event) Dokümantasyonunun bir örneği: + +--- + +Event: 'wake-up' + +Returns: + +* `time` String + +--- + +The event is a string that is used after a `.on` listener method. If it returns +a value it and its type is noted below. If you were to listen and respond to +this event it might look something like this: + +```javascript +Alarm.on('wake-up', function(time) { + console.log(time) +}) +``` diff --git a/docs-translations/uk-UA/styleguide.md b/docs-translations/uk-UA/styleguide.md index 041596700017..2a5907ec4eaf 100644 --- a/docs-translations/uk-UA/styleguide.md +++ b/docs-translations/uk-UA/styleguide.md @@ -39,7 +39,7 @@ or [writing Electron documentation](#writing-electron-documentation). - Translate the files. - Update the `README.md` within your language directory to link to the files you have translated. -- Add a link to your translation directory on the main Electron [README](https://github.com/atom/electron#documentation-translations). +- Add a link to your translation directory on the main Electron [README](https://github.com/electron/electron#documentation-translations). ## Читання документації Electron diff --git a/docs-translations/zh-CN/api/browser-window.md b/docs-translations/zh-CN/api/browser-window.md index 6e486406d63c..aedc5f06a2c9 100644 --- a/docs-translations/zh-CN/api/browser-window.md +++ b/docs-translations/zh-CN/api/browser-window.md @@ -99,7 +99,7 @@ win.show(); * `zoomFactor` Number - 界面默认缩放值, `3.0` 表示 `300%`. 默认 `1.0`. * `javascript` Boolean - 开启javascript支持. 默认为`true`. -* `webSecurity` Boolean - 当设置为 `false`, 它将禁用相同地方的规则 (通常测试服), 并且如果有2个非用户设置的参数,就设置 +* `webSecurity` Boolean - 当设置为 `false`, 它将禁用同源策略 (通常用来测试网站), 并且如果有2个非用户设置的参数,就设置 `allowDisplayingInsecureContent` 和 `allowRunningInsecureContent` 的值为 `true`. 默认为 `true`. * `allowDisplayingInsecureContent` Boolean -允许一个使用 https的界面来展示由 http URLs 传过来的资源. 默认`false`. @@ -758,4 +758,4 @@ windows上句柄类型为 `HWND` ,OS X `NSView*` , Linux `Window`. 忽略窗口的所有鼠标事件. -[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 \ No newline at end of file +[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 diff --git a/docs-translations/zh-CN/api/download-item.md b/docs-translations/zh-CN/api/download-item.md new file mode 100644 index 000000000000..e869e8f30570 --- /dev/null +++ b/docs-translations/zh-CN/api/download-item.md @@ -0,0 +1,96 @@ +# DownloadItem + +`DownloadItem`(下载项)是一个在Electron中展示下载项的 +[EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)。 +它被用于`Session`模块中的`will-download`事件,允许用户去控制下载项。 + +```javascript +// In the main process. +win.webContents.session.on('will-download', function(event, item, webContents) { + // Set the save path, making Electron not to prompt a save dialog. + item.setSavePath('/tmp/save.pdf'); + console.log(item.getMimeType()); + console.log(item.getFilename()); + console.log(item.getTotalBytes()); + item.on('updated', function() { + console.log('Received bytes: ' + item.getReceivedBytes()); + }); + item.on('done', function(e, state) { + if (state == "completed") { + console.log("Download successfully"); + } else { + console.log("Download is cancelled or interrupted that can't be resumed"); + } + }); +``` + +## 事件 + +### 事件: 'updated' + +当`downloadItem`获得更新时发射。 + +### 事件: 'done' + +* `event` Event +* `state` String + * `completed` - 下载成功完成。 + * `cancelled` - 下载被取消。 + * `interrupted` - 与文件服务器错误的中断连接。 + +当下载处于一个终止状态时发射。这包括了一个完成的下载,一个被取消的下载(via `downloadItem.cancel()`), +和一个被意外中断的下载(无法恢复)。 + +## 方法 + +`downloadItem`对象有以下一些方法: + +### `downloadItem.setSavePath(path)` + +* `path` String - 设置下载项的保存文件路径. + +这个API仅仅在`session`的`will-download`回调函数中可用。 +如果用户没有这个API去设置保存路径,Electron会用原始程序去确定保存路径(通常提示一个保存对话框)。 + +### `downloadItem.pause()` + +暂停下载。 + +### `downloadItem.resume()` + +恢复被暂停的下载。 + +### `downloadItem.cancel()` + +取消下载操作。 + +### `downloadItem.getURL()` + +以`String`形式返回一个该下载项的下载源url。 + +### `downloadItem.getMimeType()` + +返回一个表示mime类型的`String`。 + +### `downloadItem.hasUserGesture()` + +返回一个`Boolean`表示下载是否有用户动作。 + +### `downloadItem.getFilename()` + +返回一个表示下载项文件名的`String`。 + +**Note:** 此文件名不一定总是保存在本地硬盘上的实际文件名。 +如果用户在下载保存对话框中修改了文件名,保存的文件的实际名称会与`downloadItem.getFilename()`方法返回的文件名不同。 + +### `downloadItem.getTotalBytes()` + +返回一个表示下载项总字节数大小的`Integer`。如果大小未知,返回0。 + +### `downloadItem.getReceivedBytes()` + +返回一个表示下载项已经接收的字节数大小的`Integer`。 + +### `downloadItem.getContentDisposition()` + +以`String`形式返回响应头(response header)中的`Content-Disposition`域。 diff --git a/docs-translations/zh-CN/api/frameless-window.md b/docs-translations/zh-CN/api/frameless-window.md new file mode 100644 index 000000000000..833f070ad27c --- /dev/null +++ b/docs-translations/zh-CN/api/frameless-window.md @@ -0,0 +1,87 @@ +# Frameless Window + +无边框窗口指的是不包含除页面本身以外任何其它可视部分的窗口([chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome))。 +像工具栏,是窗口的一部分,但并不属于页面。这些是[`BrowserWindow`](browser-window.md) 类的选项。 + +## 创建无边框窗口 + +为了创建一个无边框窗口,你需要设置[BrowserWindow](browser-window.md)的`frame`为`false`: + + + +```javascript +const BrowserWindow = require('electron').BrowserWindow; +var win = new BrowserWindow({ width: 800, height: 600, frame: false }); +``` + +### OS X上的替代方案 + +在Mac OS X 10.10 Yosemite或者更新的版本中,有一个替代方案去生成一个无边框窗口。 +不同于设置`frame`为`false`会隐藏标题栏以及失去对窗口的控制,你可能想隐藏标题栏使你的页面内容显示在整个窗口上 +,同时又想保持对窗口的控制("traffic lights")。你可以通过指定`titleBarStyle`这一新选项达到目标: + +```javascript +var win = new BrowserWindow({ 'titleBarStyle': 'hidden' }); +``` + +## 透明窗口 + +通过设置`transparent` 选项为 `true`,你能使无边框窗口透明: + +```javascript +var win = new BrowserWindow({ transparent: true, frame: false }); +``` + +### 限制 + +* 你无法点击透明的区域。我们正在采用一个新的API去设置窗口的外形以解决这个问题, + 详见[our issue](https://github.com/electron/electron/issues/1335)。 +* 透明窗口是不可调整大小的。在某些平台上,设置`resizable`为`true`也许会造成这个透明窗口停止工作。 +* `blur`滤光器器只适用于网页,所以没法将模糊效果用于窗口之下(i.e. 其它在用户的系统中打开的应用)。 +* 在Windows系统中,当DWM被禁用时透明窗口不会工作。 +* Linux用户需要在命令行中输入`--enable-transparent-visuals --disable-gpu` + 去禁用GPU以及允许ARGB去渲染透明窗口,这是由于一个Linux上的上游bug[alpha channel doesn't work on some + NVidia drivers](https://code.google.com/p/chromium/issues/detail?id=369209)造成的 +* 在Mac上,透明窗口的阴影不会显示出来. + +## 可拖动区域 + +默认情况下,无边框窗口是不可拖动的。应用在CSS中设置`-webkit-app-region: drag` +告诉Electron哪个区域是可拖动的(比如系统标准的标题栏),应用也可以设置`-webkit-app-region: no-drag` +在可拖动区域中排除不可拖动的区域。需要注意的是,目前只支持矩形区域。 + +为了让整个窗口可拖动,你可以在`body`的样式中添加`-webkit-app-region: drag`: + +```html + + +``` + +另外需要注意的是,如果你设置了整个窗口可拖动,你必须标记按钮为不可拖动的(non-draggable), +否则用户不能点击它们: + +```css +button { + -webkit-app-region: no-drag; +} +``` + +如果你设置一个自定义的标题栏可拖动,你同样需要设置标题栏中所有的按钮为不可拖动(non-draggable)。 + +## 文本选择 + +在一个无边框窗口中,拖动动作会与文本选择发生冲突。比如,当你拖动标题栏,偶尔会选中标题栏上的文本。 +为了防止这种情况发生,你需要向下面这样在一个可拖动区域中禁用文本选择: + +```css +.titlebar { + -webkit-user-select: none; + -webkit-app-region: drag; +} +``` + +## 上下文菜单 + +在一些平台上,可拖动区域会被认为是非客户端框架(non-client frame),所有当你点击右键时,一个系统菜单会弹出。 +为了保证上下文菜单在所有平台下正确的显示,你不应该在可拖动区域使用自定义上下文菜单。 + diff --git a/docs-translations/zh-CN/api/menu.md b/docs-translations/zh-CN/api/menu.md index d0cfeeb33eb0..1997a293d248 100644 --- a/docs-translations/zh-CN/api/menu.md +++ b/docs-translations/zh-CN/api/menu.md @@ -352,4 +352,4 @@ Property List Files][AboutInformationPropertyListFiles] . [AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html [setMenu]: -https://github.com/atom/electron/blob/master/docs/api/browser-window.md#winsetmenumenu-linux-windows \ No newline at end of file +https://github.com/electron/electron/blob/master/docs/api/browser-window.md#winsetmenumenu-linux-windows \ No newline at end of file diff --git a/docs-translations/zh-CN/api/process.md b/docs-translations/zh-CN/api/process.md index d07741247aa5..7e8173dfb3b3 100644 --- a/docs-translations/zh-CN/api/process.md +++ b/docs-translations/zh-CN/api/process.md @@ -31,7 +31,7 @@ process.once('loaded', function() { ### `process.noAsar` -设置它为 `true` 可以使 `asar` 文件在node的内置模块中实效. +设置它为 `true` 可以使 `asar` 文件在node的内置模块中失效. ## 方法 @@ -45,4 +45,4 @@ process.once('loaded', function() { * `maxDescriptors` Integer -设置文件描述符软限制于 `maxDescriptors` 或硬限制与os, 无论它是否低于当前进程. \ No newline at end of file +设置文件描述符软限制于 `maxDescriptors` 或硬限制与os, 无论它是否低于当前进程. diff --git a/docs-translations/zh-CN/api/screen.md b/docs-translations/zh-CN/api/screen.md index 0de4c975afbd..3919ebabb779 100644 --- a/docs-translations/zh-CN/api/screen.md +++ b/docs-translations/zh-CN/api/screen.md @@ -23,7 +23,7 @@ app.on('ready', function() { }); ``` -另一个例子,在次页外创建一个窗口: +另一个例子,在此页外创建一个窗口: ```javascript const electron = require('electron'); @@ -54,7 +54,7 @@ app.on('ready', function() { ## `Display` 对象 -`Display` 对象表示了物力方式连接系统. 一个伪造的 `Display` 或许存在于一个无头系统中,或者一个 `Display` 相当于一个远程的、虚拟的 display. +`Display` 对象表示一个连接到系统的物理显示. 一个虚设的 `Display` 或许存在于一个无头系统(headless system)中,或者一个 `Display` 对应一个远程的、虚拟的display. * `display` object * `id` Integer - 与display 相关的唯一性标志. @@ -132,4 +132,4 @@ app.on('ready', function() { * `width` Integer * `height` Integer -返回与提供的边界范围最密切相关的 display. \ No newline at end of file +返回与提供的边界范围最密切相关的 display. diff --git a/docs-translations/zh-CN/api/synopsis.md b/docs-translations/zh-CN/api/synopsis.md index a1a2a6d01222..014d5893c73a 100644 --- a/docs-translations/zh-CN/api/synopsis.md +++ b/docs-translations/zh-CN/api/synopsis.md @@ -68,4 +68,4 @@ require('electron').hideInternalModules() [2]:https://github.com/heyunjiang/electron/blob/master/docs/tutorial/using-native-node-modules.md [3]:https://github.com/heyunjiang/electron/blob/master/docs/tutorial/quick-start.md#the-main-process [4]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment - [5]:https://github.com/atom/electron/issues/387 \ No newline at end of file + [5]:https://github.com/electron/electron/issues/387 \ No newline at end of file diff --git a/docs-translations/zh-CN/api/web-contents.md b/docs-translations/zh-CN/api/web-contents.md index f168849863af..54b9c56dcc6c 100644 --- a/docs-translations/zh-CN/api/web-contents.md +++ b/docs-translations/zh-CN/api/web-contents.md @@ -30,6 +30,7 @@ var webContents = win.webContents; * `errorCode` Integer * `errorDescription` String * `validatedURL` String +* `isMainFrame` Boolean 这个事件类似 `did-finish-load` ,但是是在加载失败或取消加载时发出, 例如, `window.stop()` 请求结束.错误代码的完整列表和它们的含义都可以在 [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) 找到. @@ -62,6 +63,7 @@ var webContents = win.webContents; * `requestMethod` String * `referrer` String * `headers` Object +* `resourceType` String 当有关请求资源的详细信息可用的时候发出事件. `status` 标识了 socket链接来下载资源. diff --git a/docs-translations/zh-CN/api/web-view-tag.md b/docs-translations/zh-CN/api/web-view-tag.md index e1e31f6f5a02..a1348c4d5882 100644 --- a/docs-translations/zh-CN/api/web-view-tag.md +++ b/docs-translations/zh-CN/api/web-view-tag.md @@ -457,6 +457,7 @@ Returns: * `requestMethod` String * `referrer` String * `headers` Object +* `resourceType` String 当获得返回详情的时候触发. diff --git a/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md b/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md index beea91e3ff16..68fddb11d237 100644 --- a/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md +++ b/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md @@ -28,4 +28,4 @@ __4. 多上下文__ 通过使用 Node 的[多上下文](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/)特性,Electron不需要在网页中引入新的 JavaScript 上下文。 -[node-bindings]: https://github.com/atom/electron/tree/master/atom/common +[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs-translations/zh-CN/development/build-instructions-linux.md b/docs-translations/zh-CN/development/build-instructions-linux.md index 0f76e78b9a5d..9815aeb03e5f 100644 --- a/docs-translations/zh-CN/development/build-instructions-linux.md +++ b/docs-translations/zh-CN/development/build-instructions-linux.md @@ -36,7 +36,7 @@ $ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring- ## 获取代码 ```bash -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## Bootstrapping diff --git a/docs-translations/zh-CN/development/build-instructions-osx.md b/docs-translations/zh-CN/development/build-instructions-osx.md index 15485e57acc0..98f6648a3598 100644 --- a/docs-translations/zh-CN/development/build-instructions-osx.md +++ b/docs-translations/zh-CN/development/build-instructions-osx.md @@ -15,7 +15,7 @@ ## 获取代码 ```bash -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## Bootstrapping diff --git a/docs-translations/zh-CN/development/build-instructions-windows.md b/docs-translations/zh-CN/development/build-instructions-windows.md index 7b11dc7f57f3..2e2ee38638bf 100644 --- a/docs-translations/zh-CN/development/build-instructions-windows.md +++ b/docs-translations/zh-CN/development/build-instructions-windows.md @@ -25,7 +25,7 @@ ## 获取代码 ```powershell -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## Bootstrapping @@ -76,7 +76,7 @@ $ python script\cpplint.py ```powershell $ python script\test.py ``` -在构建 debug 时为 Tests包含原生模块 (例如 `runas`) 将不会执行(详情 [#2558](https://github.com/atom/electron/issues/2558)), 但是它们在构建 release 会起效. +在构建 debug 时为 Tests包含原生模块 (例如 `runas`) 将不会执行(详情 [#2558](https://github.com/electron/electron/issues/2558)), 但是它们在构建 release 会起效. 运行 release 构建使用 : diff --git a/docs-translations/zh-CN/development/coding-style.md b/docs-translations/zh-CN/development/coding-style.md index 6652466b9703..4136ae4805b1 100644 --- a/docs-translations/zh-CN/development/coding-style.md +++ b/docs-translations/zh-CN/development/coding-style.md @@ -20,4 +20,4 @@ C++ 代码中用到了许多 Chromium 中的接口和数据类型,所以希望 ## API 命名 当新建一个 API 时,我们倾向于使用 getters 和 setters 而不是 jQuery 单函数的命名方式,比如 `.getText()` 和 `.setText(text)` - 而不是 `.text([text])`。这里有关于该规则的[讨论记录](https://github.com/atom/electron/issues/46)。 + 而不是 `.text([text])`。这里有关于该规则的[讨论记录](https://github.com/electron/electron/issues/46)。 diff --git a/docs-translations/zh-CN/tutorial/application-distribution.md b/docs-translations/zh-CN/tutorial/application-distribution.md index f3cf3692b5db..2dca19342ad5 100644 --- a/docs-translations/zh-CN/tutorial/application-distribution.md +++ b/docs-translations/zh-CN/tutorial/application-distribution.md @@ -27,7 +27,7 @@ electron/resources/app ## 将你的应用程序打包成一个文件 -除了通过拷贝所有的资源文件来分发你的应用程序之外,你可以可以通过打包你的应用程序为一个 [asar](https://github.com/atom/asar) 库文件以避免暴露你的源代码。 +除了通过拷贝所有的资源文件来分发你的应用程序之外,你可以通过打包你的应用程序为一个 [asar](https://github.com/atom/asar) 库文件以避免暴露你的源代码。 为了使用一个 `asar` 库文件代替 `app` 文件夹,你需要修改这个库文件的名字为 `app.asar` , 然后将其放到 Electron 的资源文件夹下,然后 Electron 就会试图读取这个库文件并从中启动。 diff --git a/docs-translations/zh-CN/tutorial/desktop-environment-integration.md b/docs-translations/zh-CN/tutorial/desktop-environment-integration.md index 614aeed708f6..3f946da34e1c 100644 --- a/docs-translations/zh-CN/tutorial/desktop-environment-integration.md +++ b/docs-translations/zh-CN/tutorial/desktop-environment-integration.md @@ -3,6 +3,47 @@ 本章将会说明怎样使用 Electron APIs 把你的应用和桌面环境集成到一块。 +## Notifications (Windows, Linux, OS X) + +这三个操作系统都为用户提供了发送通知的方法。Electron让开发人员通过 +[HTML5 Notification API](https://notifications.spec.whatwg.org/) +便利的去发送通知,用操作系统自带的通知APIs去显示。 + +**Note:** 因为这是一个HTML5API,所以只在渲染进程中起作用 + +```javascript +var myNotification = new Notification('Title', { + body: 'Lorem Ipsum Dolor Sit Amet' +}); + +myNotification.onclick = function () { + console.log('Notification clicked') +} +``` + +尽管代码和用户体验在不同的操作系统中基本相同,但还是有一些差异。 + +### Windows + +* 在Windows 10上, 通知"可以工作". +* 在Windows 8.1和Windows 8系统下,你需要将你的应用通过一个[Application User +Model ID][app-user-model-id]安装到开始屏幕上。需要注意的是,这不是将你的应用固定到开始屏幕。 +* 在Windows 7以及更低的版本中,通知不被支持。不过你可以使用[Tray API][tray-balloon]发送一个"气泡通知"。 + +此外,通知支持的最大字符长队为250。Windows团队建议通知应该保持在200个字符以下。 + +### Linux + +通知使用`libnotify`发送,它能在任何支持[Desktop Notifications +Specification][notification-spec]的桌面环境中显示,包括 Cinnamon, Enlightenment, Unity, +GNOME, KDE。 + +### OS X + +在OS X系统中,通知是直接转发的,你应该了解[Apple's Human Interface guidelines regarding notifications](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html)。 + +注意通知被限制在256个字节以内,如果超出,则会被截断。 + ## 最近文档 (Windows & OS X) Windows 和 OS X 提供获取最近文档列表的便捷方式,那就是打开跳转列表或者鱼眼菜单。 @@ -149,19 +190,33 @@ window.setDocumentEdited(true); [1]:https://camo.githubusercontent.com/3310597e01f138b1d687e07aa618c50908a88dec/687474703a2f2f692e6d73646e2e6d6963726f736f66742e636f6d2f64796e696d672f49433432303533382e706e67 [2]: https://cloud.githubusercontent.com/assets/639601/5069610/2aa80758-6e97-11e4-8cfb-c1a414a10774.png - [3]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/app.md - [4]: https://github.com/atom/electron/blob/master/docs/tutorial/clearrecentdocuments + [3]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/app.md + [4]: https://github.com/electron/electron/blob/master/docs/tutorial/clearrecentdocuments [5]: https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121%28v=vs.85%29.aspx [6]: https://cloud.githubusercontent.com/assets/639601/5069962/6032658a-6e9c-11e4-9953-aa84006bdfff.png [7]: https://camo.githubusercontent.com/30154e0cc36acfc968ac9ae076a8f0d6600dd736/687474703a2f2f692e6d73646e2e6d6963726f736f66742e636f6d2f64796e696d672f49433432303533392e706e67 - [8]: https://github.com/atom/electron/blob/master/docs/api/app.md#appsetusertaskstasks + [8]: https://github.com/electron/electron/blob/master/docs/api/app.md#appsetusertaskstasks [9]: https://camo.githubusercontent.com/098cb0f52f27084a80ec6429e51a195df3d8c333/68747470733a2f2f692d6d73646e2e7365632e732d6d7366742e636f6d2f64796e696d672f49433432303534302e706e67 - [10]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/browser-window.md + [10]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md [11]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher [12]: https://camo.githubusercontent.com/b6f54e2bc3206ebf8e08dd029529af9ec84d58ae/68747470733a2f2f68656c702e7562756e74752e636f6d2f636f6d6d756e6974792f556e6974794c61756e6368657273416e644465736b746f7046696c65733f616374696f6e3d41747461636846696c6526646f3d676574267461726765743d73686f7274637574732e706e67 [13]: https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png [14]: https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png - [15]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/browser-window.md + [15]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md [16]: https://cloud.githubusercontent.com/assets/639601/5082061/670a949a-6f14-11e4-987a-9aaa04b23c1d.png - [17]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/browser-window.md - [18]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/browser-window.md + [17]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md + [18]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md + +[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows +[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows +[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows +[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress +[setoverlayicon]: ../api/browser-window.md#winsetoverlayiconoverlay-description-windows-7 +[setrepresentedfilename]: ../api/browser-window.md#winsetrepresentedfilenamefilename-os-x +[setdocumentedited]: ../api/browser-window.md#winsetdocumenteditededited-os-x +[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx +[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher +[setthumbarbuttons]: ../api/browser-window.md#winsetthumbarbuttonsbuttons-windows-7 +[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows +[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx +[notification-spec]: https://developer.gnome.org/notification-spec/ diff --git a/docs-translations/zh-CN/tutorial/devtools-extension.md b/docs-translations/zh-CN/tutorial/devtools-extension.md index 0270eae29550..e35a971e1c76 100644 --- a/docs-translations/zh-CN/tutorial/devtools-extension.md +++ b/docs-translations/zh-CN/tutorial/devtools-extension.md @@ -4,7 +4,7 @@ 对于大多数DevTools的扩展,你可以直接下载源码,然后通过 `BrowserWindow.addDevToolsExtension` API 加载它们。Electron会记住已经加载了哪些扩展,所以你不需要每次创建一个新window时都调用 `BrowserWindow.addDevToolsExtension` API。 -** 注:React DevTools目前不能直接工作,详情留意 [https://github.com/atom/electron/issues/915](https://github.com/atom/electron/issues/915) ** +** 注:React DevTools目前不能直接工作,详情留意 [https://github.com/electron/electron/issues/915](https://github.com/electron/electron/issues/915) ** 例如,要用[React DevTools Extension](https://github.com/facebook/react-devtools),你得先下载他的源码: diff --git a/docs-translations/zh-CN/tutorial/mac-app-store-submission-guide.md b/docs-translations/zh-CN/tutorial/mac-app-store-submission-guide.md index 45cff454a961..e7c7af817aa9 100644 --- a/docs-translations/zh-CN/tutorial/mac-app-store-submission-guide.md +++ b/docs-translations/zh-CN/tutorial/mac-app-store-submission-guide.md @@ -143,5 +143,5 @@ ERN)][ern-tutorial]. [create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html [submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html [app-sandboxing]: https://developer.apple.com/app-sandboxing/ -[issue-3871]: https://github.com/atom/electron/issues/3871 +[issue-3871]: https://github.com/electron/electron/issues/3871 [ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ \ No newline at end of file diff --git a/docs-translations/zh-CN/tutorial/online-offline-events.md b/docs-translations/zh-CN/tutorial/online-offline-events.md index 7389afa4c9e5..d61f7378b967 100644 --- a/docs-translations/zh-CN/tutorial/online-offline-events.md +++ b/docs-translations/zh-CN/tutorial/online-offline-events.md @@ -3,10 +3,11 @@ *main.js* ```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; +const electron = require('electron'); +const app = electron.app; +const BrowserWindow = electron.BrowserWindow; +var onlineStatusWindow; app.on('ready', function() { onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); @@ -36,17 +37,18 @@ app.on('ready', function() { *main.js* ```javascript -var app = require('app'); -var ipc = require('ipc'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; +const electron = require('electron'); +const app = electron.app; +const ipcMain = electron.ipcMain; +const BrowserWindow = electron.BrowserWindow; +var onlineStatusWindow; app.on('ready', function() { onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); }); -ipc.on('online-status-changed', function(event, status) { +ipcMain.on('online-status-changed', function(event, status) { console.log(status); }); ``` @@ -57,9 +59,9 @@ ipc.on('online-status-changed', function(event, status) { ``` +## CSS Styling Notes + +Please note that the `webview` tag's style uses `display:flex;` internally to +ensure the child `object` element fills the full height and width of its `webview` +container when used with traditional and flexbox layouts (since v0.36.11). Please +do not overwrite the default `display:flex;` CSS property, unless specifying +`display:inline-flex;` for inline layout. + +`webview` has issues being hidden using the `hidden` attribute or using `display: none;`. +It can cause unusual rendering behaviour within its child `browserplugin` object +and the web page is reloaded, when the `webview` is un-hidden, as opposed to just +becoming visible again. The recommended approach is to hide the `webview` using +CSS by zeroing the `width` & `height` and allowing the element to shrink to the 0px +dimensions via `flex`. + +```html + +``` + ## Tag Attributes The `webview` tag has the following attributes: @@ -474,6 +506,7 @@ Returns: * `errorCode` Integer * `errorDescription` String * `validatedURL` String +* `isMainFrame` Boolean This event is like `did-finish-load`, but fired when the load failed or was cancelled, e.g. `window.stop()` is invoked. @@ -505,6 +538,7 @@ Returns: * `requestMethod` String * `referrer` String * `headers` Object +* `resourceType` String Fired when details regarding a requested resource is available. `status` indicates socket connection to download the resource. @@ -731,6 +765,10 @@ Emitted when media is paused or done playing. ### Event: 'did-change-theme-color' +Returns: + +* `themeColor` String + Emitted when a page's theme color changes. This is usually due to encountering a meta tag: ```html diff --git a/docs/api/window-open.md b/docs/api/window-open.md index 46e74327741f..abb0760f121e 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -1,5 +1,7 @@ # The `window.open` function +> Open a new window and load a URL. + When `window.open` is called to create a new window in a web page, a new instance of `BrowserWindow` will be created for the `url` and a proxy will be returned to `window.open` to let the page have limited control over it. diff --git a/docs/development/atom-shell-vs-node-webkit.md b/docs/development/atom-shell-vs-node-webkit.md index 76fa5d57d289..3ec11b78b7d1 100644 --- a/docs/development/atom-shell-vs-node-webkit.md +++ b/docs/development/atom-shell-vs-node-webkit.md @@ -47,4 +47,4 @@ By using the [multi-context](http://strongloop.com/strongblog/whats-new-node-js- feature of Node, Electron doesn't introduce a new JavaScript context in web pages. -[node-bindings]: https://github.com/atom/electron/tree/master/atom/common +[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs/development/build-instructions-linux.md b/docs/development/build-instructions-linux.md index df0943050f7b..79fbc5014896 100644 --- a/docs/development/build-instructions-linux.md +++ b/docs/development/build-instructions-linux.md @@ -41,7 +41,7 @@ device container of at least 25 gigabytes in size. ## Getting the Code ```bash -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## Bootstrapping diff --git a/docs/development/build-instructions-osx.md b/docs/development/build-instructions-osx.md index 598aa01c4406..b703a75897d9 100644 --- a/docs/development/build-instructions-osx.md +++ b/docs/development/build-instructions-osx.md @@ -16,14 +16,14 @@ following python modules: ## Getting the Code ```bash -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## Bootstrapping The bootstrap script will download all necessary build dependencies and create -the build project files. Notice that we're using [ninja](https://ninja-build.org/) to build Electron so -there is no Xcode project generated. +the build project files. Notice that we're using [ninja](https://ninja-build.org/) +to build Electron so there is no Xcode project generated. ```bash $ cd electron diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 06ce696a9e3c..3f94a18393cf 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -11,7 +11,8 @@ Follow the guidelines below for building Electron on Windows. * [Node.js](http://nodejs.org/download/) * [Git](http://git-scm.com) -If you don't currently have a Windows installation, [modern.ie](https://www.modern.ie/en-us/virtualization-tools#downloads) +If you don't currently have a Windows installation, +[modern.ie](https://www.modern.ie/en-us/virtualization-tools#downloads) has timebombed versions of Windows that you can use to build Electron. Building Electron is done entirely with command-line scripts and cannot be done @@ -27,7 +28,7 @@ building with Visual Studio will come in the future. ## Getting the Code ```powershell -$ git clone https://github.com/atom/electron.git +$ git clone https://github.com/electron/electron.git ``` ## Bootstrapping @@ -84,7 +85,7 @@ $ python script\test.py ``` Tests that include native modules (e.g. `runas`) can't be executed with the -debug build (see [#2558](https://github.com/atom/electron/issues/2558) for +debug build (see [#2558](https://github.com/electron/electron/issues/2558) for details), but they will work with the release build. To run the tests with the release build use: diff --git a/docs/development/build-system-overview.md b/docs/development/build-system-overview.md index 61b88e14078c..bc27c1932fa6 100644 --- a/docs/development/build-system-overview.md +++ b/docs/development/build-system-overview.md @@ -1,7 +1,8 @@ # Build System Overview -Electron uses [gyp](https://gyp.gsrc.io/) for project generation and [ninja](https://ninja-build.org/) for building. Project -configurations can be found in the `.gyp` and `.gypi` files. +Electron uses [gyp](https://gyp.gsrc.io/) for project generation and +[ninja](https://ninja-build.org/) for building. Project configurations can +be found in the `.gyp` and `.gypi` files. ## Gyp Files diff --git a/docs/development/coding-style.md b/docs/development/coding-style.md index 422a4226df60..1840700f5237 100644 --- a/docs/development/coding-style.md +++ b/docs/development/coding-style.md @@ -39,9 +39,18 @@ etc. * [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) instead of string concatenation using `+` -## API Names +## Naming Things -When creating a new API, we should prefer getters and setters instead of +Electron APIs uses the same capitalization scheme as Node.js: + +- When the module itself is a class like `BrowserWindow`, use `CamelCase`. +- When the module is a set of APIs, like `globalShortcut`, use `mixedCase`. +- When the API is a property of object, and it is complex enough to be in a + separate chapter like `win.webContents`, use `mixedCase`. +- For other non-module APIs, use natural titles, like ` Tag` or + `Process Object`. + +When creating a new API, it is preferred to use getters and setters instead of jQuery's one-function style. For example, `.getText()` and `.setText(text)` are preferred to `.text([text])`. There is a -[discussion](https://github.com/atom/electron/issues/46) on this. +[discussion](https://github.com/electron/electron/issues/46) on this. diff --git a/docs/development/debug-instructions-windows.md b/docs/development/debug-instructions-windows.md new file mode 100644 index 000000000000..3a1a05e11030 --- /dev/null +++ b/docs/development/debug-instructions-windows.md @@ -0,0 +1,93 @@ +# Debugging Electron in Windows + +If you experience crashes or issues in Electron that you believe are not caused +by your JavaScript application, but instead by Electron itself, debugging can +be a little bit tricky, especially for developers not used to native/C++ +debugging. However, using Visual Studio, GitHub's hosted Electron Symbol Server, +and the Electron source code, it is fairly easy to enable step-through debugging +with breakpoints inside Electron's source code. + +## Requirements + +* **A debug build of Electron**: The easiest way is usually building it + yourself, using the tools and prerequisites listed in the + [build instructions for Windows](build-instructions-osx.md). While you can + easily attach to and debug Electron as you can download it directly, you will + find that it is heavily optimized, making debugging substantially more + difficult: The debugger will not be able to show you the content of all + variables and the execution path can seem strange because of inlining, + tail calls, and other compiler optimizations. + +* **Visual Studio with C++ Tools**: The free community editions of Visual + Studio 2013 and Visual Studio 2015 both work. Once installed, + [configure Visual Studio to use GitHub's Electron Symbol server](setting-up-symbol-server.md). + It will enable Visual Studio to gain a better understanding of what happens + inside Electron, making it easier to present variables in a human-readable + format. + +* **ProcMon**: The [free SysInternals tool][sys-internals] allows you to inspect + a processes parameters, file handles, and registry operations. + +## Attaching to and Debugging Electron + +To start a debugging session, open up PowerShell/CMD and execute your debug +build of Electron, using the application to open as a parameter. + +```powershell +$ ./out/D/electron.exe ~/my-electron-app/ +``` + +### Setting Breakpoints + +Then, open up Visual Studio. Electron is not built with Visual Studio and hence +does not contain a project file - you can however open up the source code files +"As File", meaning that Visual Studio will open them up by themselves. You can +still set breakpoints - Visual Studio will automatically figure out that the +source code matches the code running in the attached process and break +accordingly. + +Relevant code files can be found in `./atom/` as well as in Brightray, found in +`./vendor/brightray/browser` and `./vendor/brightray/common`. If you're hardcore, +you can also debug Chromium directly, which is obviously found in `chromium_src`. + +### Attaching + +You can attach the Visual Studio debugger to a running process on a local or +remote computer. After the process is running, click Debug / Attach to Process +(or press `CTRL+ALT+P`) to open the "Attach to Process" dialog box. You can use +this capability to debug apps that are running on a local or remote computer, +debug multiple processes simultaneously. + +If Electron is running under a different user account, select the +`Show processes from all users` check box. Notice that depending on how many +BrowserWindows your app opened, you will see multiple processes. A typical +one-window app will result in Visual Studio presenting you with two +`Electron.exe` entries - one for the main process and one for the renderer +process. Since the list only gives you names, there's currently no reliable +way of figuring out which is which. + +### Which Process Should I Attach to? + +Code executed within the main process (that is, code found in or eventually run +by your main JavaScript file) as well as code called using the remote +(`require('electron').remote`) will run inside the main process, while other +code will execute inside its respective renderer process. + +You can be attached to multiple programs when you are debugging, but only one +program is active in the debugger at any time. You can set the active program +in the `Debug Location` toolbar or the `Processes window`. + +## Using ProcMon to Observe a Process + +While Visual Studio is fantastic for inspecting specific code paths, ProcMon's +strength is really in observing everything your application is doing with the +operating system - it captures File, Registry, Network, Process, and Profiling +details of processes. It attempts to log **all** events occurring and can be +quite overwhelming, but if you seek to understand what and how your application +is doing to the operating system, it can be a valuable resource. + +For an introduction to ProcMon's basic and advanced debugging features, go check +out [this video tutorial][procmon-instructions] provided by Microsoft. + +[sys-internals]: https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx +[procmon-instructions]: https://channel9.msdn.com/shows/defrag-tools/defrag-tools-4-process-monitor diff --git a/docs/development/source-code-directory-structure.md b/docs/development/source-code-directory-structure.md index 998280a37054..27cf36b9d4e7 100644 --- a/docs/development/source-code-directory-structure.md +++ b/docs/development/source-code-directory-structure.md @@ -34,7 +34,7 @@ Electron ├── default_app - The default page to show when Electron is started without | providing an app. ├── docs - Documentations. -├── lib - JavaScript source code. +├── lib - JavaScript source code. | ├── browser - Javascript main process initialization code. | | └── api - Javascript API implementation. | ├── common - JavaScript used by both the main and renderer processes @@ -62,3 +62,30 @@ Electron when creating a distribution. * **external_binaries** - Downloaded binaries of third-party frameworks which do not support building with `gyp`. + +## Keeping Git Submodules Up to Date + +The Electron repository has a few vendored dependencies, found in the +[/vendor](/vendor) directory. Occasionally you might see a message like this +when running `git status`: + +```sh +$ git status + + modified: vendor/brightray (new commits) + modified: vendor/node (new commits) +``` + +To update these vendored dependencies, run the following command: + +```sh +git submodule update --init --recursive +``` + +If you find yourself running this command often, you can create an alias for it +in your `~/.gitconfig` file: + +``` +[alias] + su = submodule update --init --recursive +``` diff --git a/docs/faq/electron-faq.md b/docs/faq/electron-faq.md index 1782d3873108..02d72744e657 100644 --- a/docs/faq/electron-faq.md +++ b/docs/faq/electron-faq.md @@ -77,8 +77,8 @@ app.on('ready', function() { ## I can not use jQuery/RequireJS/Meteor/AngularJS in Electron. Due to the Node.js integration of Electron, there are some extra symbols -inserted into the DOM like `module`, `exports`, `require`. This causes problems for -some libraries since they want to insert the symbols with the same names. +inserted into the DOM like `module`, `exports`, `require`. This causes problems +for some libraries since they want to insert the symbols with the same names. To solve this, you can turn off node integration in Electron: @@ -144,19 +144,6 @@ is very likely you are using the module in the wrong process. For example `electron.app` can only be used in the main process, while `electron.webFrame` is only available in renderer processes. -## Why is my app's background transparent? - -Since Electron `0.37.3`, the default user-agent background color is `transparent`. -Simply specify a background color in HTML: - -```html - -``` - [memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management [variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx [electron-module]: https://www.npmjs.com/package/electron diff --git a/docs/styleguide.md b/docs/styleguide.md index 6b745b988b36..28ebaa18b660 100644 --- a/docs/styleguide.md +++ b/docs/styleguide.md @@ -40,7 +40,7 @@ To add another set (or partial set): - Translate the files. - Update the `README.md` within your language directory to link to the files you have translated. -- Add a link to your translation directory on the main Electron [README](https://github.com/atom/electron#documentation-translations). +- Add a link to your translation directory on the main Electron [README](https://github.com/electron/electron#documentation-translations). ## Reading Electron Documentation diff --git a/docs/tutorial/debugging-main-process.md b/docs/tutorial/debugging-main-process.md index ee7fc4c5fa47..714b7100cf47 100644 --- a/docs/tutorial/debugging-main-process.md +++ b/docs/tutorial/debugging-main-process.md @@ -68,9 +68,10 @@ $ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin ### 7. Load the debugger UI -Open http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 in the Chrome browser. You may have to click pause if starting with debug-brk to see the entry line. +Open http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 in the Chrome +browser. You may have to click pause if starting with debug-brk to see the +entry line. [node-inspector]: https://github.com/node-inspector/node-inspector [node-gyp-required-tools]: https://github.com/nodejs/node-gyp#installation [how-to-install-native-modules]: using-native-node-modules.md#how-to-install-native-modules - diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 1186918799b9..110d2917ab47 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -53,8 +53,7 @@ GNOME, KDE. ### OS X Notifications are straight-forward on OS X, you should however be aware of -[Apple's Human Interface guidelines regarding -notifications](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html). +[Apple's Human Interface guidelines regarding notifications](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html). Note that notifications are limited to 256 bytes in size - and will be truncated if you exceed that limit. diff --git a/docs/tutorial/devtools-extension.md b/docs/tutorial/devtools-extension.md index 7c7ea7d64a24..1791c0459207 100644 --- a/docs/tutorial/devtools-extension.md +++ b/docs/tutorial/devtools-extension.md @@ -8,7 +8,7 @@ the `BrowserWindow.addDevToolsExtension` API to load them. The loaded extensions will be remembered so you don't need to call the API every time when creating a window. -** NOTE: React DevTools does not work, follow the issue here https://github.com/atom/electron/issues/915 ** +** NOTE: React DevTools does not work, follow the issue here https://github.com/electron/electron/issues/915 ** For example, to use the [React DevTools Extension](https://github.com/facebook/react-devtools) , first you need to download its source code: diff --git a/docs/tutorial/mac-app-store-submission-guide.md b/docs/tutorial/mac-app-store-submission-guide.md index 91a10d40eb1e..404dcb80efbf 100644 --- a/docs/tutorial/mac-app-store-submission-guide.md +++ b/docs/tutorial/mac-app-store-submission-guide.md @@ -4,10 +4,6 @@ Since v0.34.0, Electron allows submitting packaged apps to the Mac App Store (MAS). This guide provides information on: how to submit your app and the limitations of the MAS build. -**Note:** From v0.36.0 there was a bug preventing GPU process to start after -the app being sandboxed, so it is recommended to use v0.35.x before this bug -gets fixed. You can find more about this in [issue #3871][issue-3871]. - **Note:** Submitting an app to Mac App Store requires enrolling [Apple Developer Program][developer-program], which costs money. @@ -56,6 +52,8 @@ First, you need to prepare two entitlements files. com.apple.security.app-sandbox + com.apple.security.temporary-exception.sbpl + (allow mach-lookup (global-name-regex #"^org.chromium.Chromium.rohitfork.[0-9]+$")) ``` @@ -77,17 +75,18 @@ INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" -if [ -d "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" ]; then - # Signing a non-MAS build. - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Mantle.framework/Versions/A" - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/ReactiveCocoa.framework/Versions/A" - codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" -fi -codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" +codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" +codesign -s "$APP_KEY" -f --entitlements child.plist "$APP_PATH/Contents/MacOS/$APP" +codesign -s "$APP_KEY" -f --entitlements parent.plist "$APP_PATH" productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" ``` @@ -96,11 +95,32 @@ If you are new to app sandboxing under OS X, you should also read through Apple's [Enabling App Sandbox][enable-app-sandbox] to have a basic idea, then add keys for the permissions needed by your app to the entitlements files. -### Upload Your App and Submit for Review +### Upload Your App After signing your app, you can use Application Loader to upload it to iTunes Connect for processing, making sure you have [created a record][create-record] -before uploading. Then you can [submit your app for review][submit-for-review]. +before uploading. + +### Explain the Usages of `temporary-exception` + +When sandboxing your app there was a `temporary-exception` entry added to the +entitlements, according to the [App Sandbox Temporary Exception +Entitlements][temporary-exception] documentation, you have to explain why this +entry is needed: + +> Note: If you request a temporary-exception entitlement, be sure to follow the +guidance regarding entitlements provided on the iTunes Connect website. In +particular, identify the entitlement and corresponding issue number in the App +Sandbox Entitlement Usage Information section in iTunes Connect and explain why +your app needs the exception. + +You may explain that your app is built upon Chromium browser, which uses Mach +port for its multi-process architecture. But there is still probability that +your app failed the review because of this. + +### Submit Your App for Review + +After these steps, you can [submit your app for review][submit-for-review]. ## Limitations of MAS Build @@ -163,5 +183,5 @@ ERN)][ern-tutorial]. [create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html [submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html [app-sandboxing]: https://developer.apple.com/app-sandboxing/ -[issue-3871]: https://github.com/atom/electron/issues/3871 [ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ +[temporary-exception]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index 684c72c6669e..ddbda3782449 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -147,8 +147,8 @@ working as expected. ### electron-prebuilt -If you've installed `electron-prebuilt` globally with `npm`, then you will only need -to run the following in your app's source directory: +If you've installed `electron-prebuilt` globally with `npm`, then you will only +need to run the following in your app's source directory: ```bash electron . @@ -184,7 +184,7 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/ ``` `Electron.app` here is part of the Electron's release package, you can download -it from [here](https://github.com/atom/electron/releases). +it from [here](https://github.com/electron/electron/releases). ### Run as a distribution @@ -194,14 +194,14 @@ and then executing the packaged app. ### Try this Example -Clone and run the code in this tutorial by using the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) +Clone and run the code in this tutorial by using the [`atom/electron-quick-start`](https://github.com/electron/electron-quick-start) repository. **Note**: Running this requires [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which includes [npm](https://npmjs.org)) on your system. ```bash # Clone the repository -$ git clone https://github.com/atom/electron-quick-start +$ git clone https://github.com/electron/electron-quick-start # Go into the repository $ cd electron-quick-start # Install dependencies and run the app diff --git a/docs/tutorial/testing-on-headless-ci.md b/docs/tutorial/testing-on-headless-ci.md index ec1f4635c906..f9090a6cbd79 100644 --- a/docs/tutorial/testing-on-headless-ci.md +++ b/docs/tutorial/testing-on-headless-ci.md @@ -18,9 +18,9 @@ Then, create a virtual xvfb screen and export an environment variable called DISPLAY that points to it. Chromium in Electron will automatically look for `$DISPLAY`, so no further configuration of your app is required. This step can be automated with Paul Betts's -[xfvb-maybe](https://github.com/paulcbetts/xvfb-maybe): Prepend your test -commands with `xfvb-maybe` and the little tool will automatically configure -xfvb, if required by the current system. On Windows or Mac OS X, it will simply +[xvfb-maybe](https://github.com/paulcbetts/xvfb-maybe): Prepend your test +commands with `xvfb-maybe` and the little tool will automatically configure +xvfb, if required by the current system. On Windows or Mac OS X, it will simply do nothing. ``` @@ -47,7 +47,7 @@ install: ### Jenkins -For Jenkins, a [Xfvb plugin is available](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). +For Jenkins, a [Xvfb plugin is available](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). ### Circle CI diff --git a/docs/tutorial/using-native-node-modules.md b/docs/tutorial/using-native-node-modules.md index 2defedd74183..f73c1cde1f02 100644 --- a/docs/tutorial/using-native-node-modules.md +++ b/docs/tutorial/using-native-node-modules.md @@ -10,8 +10,8 @@ Native modules might break when Node starts using a new version of V8. To make sure the module you're interested in will work with Electron, you should check if it supports the internal Node version used by Electron. You can check what version of Node is used in Electron by looking it up in -the [releases](https://github.com/atom/electron/releases) page or by using -`process.version` (see [Quick Start](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md) +the [releases](https://github.com/electron/electron/releases) page or by using +`process.version` (see [Quick Start](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md) for example). Consider using [NAN](https://github.com/nodejs/nan/) for your own modules, since diff --git a/docs/tutorial/using-pepper-flash-plugin.md b/docs/tutorial/using-pepper-flash-plugin.md index a9918b220ac0..de7c7001cf36 100644 --- a/docs/tutorial/using-pepper-flash-plugin.md +++ b/docs/tutorial/using-pepper-flash-plugin.md @@ -1,6 +1,6 @@ # Using Pepper Flash Plugin -Electron now supports the Pepper Flash plugin. To use the Pepper Flash plugin in +Electron supports the Pepper Flash plugin. To use the Pepper Flash plugin in Electron, you should manually specify the location of the Pepper Flash plugin and then enable it in your application. @@ -15,25 +15,25 @@ location. You can directly add `--ppapi-flash-path` and `ppapi-flash-version` to the Electron command line or by using the `app.commandLine.appendSwitch` method -before the app ready event. Also, add the `plugins` switch of `browser-window`. +before the app ready event. Also, turn on `plugins` option of `BrowserWindow`. For example: ```javascript // Specify flash path. -// On Windows, it might be /path/to/pepflashplayer.dll +// On Windows, it might be /path/to/pepflashplayer.dll or just pepflashplayer.dll if it resides main.js // On OS X, /path/to/PepperFlashPlayer.plugin // On Linux, /path/to/libpepflashplayer.so app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so'); -// Specify flash version, for example, v17.0.0.169 +// Optional: Specify flash version, for example, v17.0.0.169 app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169'); app.on('ready', function() { mainWindow = new BrowserWindow({ - 'width': 800, - 'height': 600, - 'web-preferences': { - 'plugins': true + width: 800, + height: 600, + webPreferences: { + plugins: true } }); mainWindow.loadURL('file://' + __dirname + '/index.html'); @@ -48,3 +48,13 @@ Add `plugins` attribute to `` tag. ```html ``` + +## Troubleshooting + +You can check if Pepper Flash plugin was loaded by inspecting +`navigator.plugins` in the console of devtools (although you can't know if the +plugin's path is correct). + +The architecture of Pepper Flash plugin has to match Electron's one. On Windows, +a common error is to use 32bit version of Flash plugin against 64bit version of +Electron. diff --git a/docs/tutorial/using-selenium-and-webdriver.md b/docs/tutorial/using-selenium-and-webdriver.md index 2d296548dd9c..32a96cd84b74 100644 --- a/docs/tutorial/using-selenium-and-webdriver.md +++ b/docs/tutorial/using-selenium-and-webdriver.md @@ -122,7 +122,7 @@ client ## Workflow To test your application without rebuilding Electron, simply -[place](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md) +[place](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md) your app source into Electron's resource directory. Alternatively, pass an argument to run with your electron binary that points to diff --git a/electron.gyp b/electron.gyp index 9652bd662c73..66ff2fd5baf8 100644 --- a/electron.gyp +++ b/electron.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '0.37.3', + 'version%': '0.37.8', }, 'includes': [ 'filenames.gypi', @@ -310,6 +310,9 @@ ], }], # OS=="mac" and mas_build==1 ['OS=="linux"', { + 'sources': [ + '<@(lib_sources_nss)', + ], 'link_settings': { 'ldflags': [ # Make binary search for libraries under current directory, so we diff --git a/filenames.gypi b/filenames.gypi index 2c39a8dccef1..1c2139497567 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -28,6 +28,7 @@ 'lib/browser/api/protocol.js', 'lib/browser/api/session.js', 'lib/browser/api/screen.js', + 'lib/browser/api/system-preferences.js', 'lib/browser/api/tray.js', 'lib/browser/api/web-contents.js', 'lib/browser/chrome-extension.js', @@ -115,6 +116,9 @@ 'atom/browser/api/atom_api_screen.h', 'atom/browser/api/atom_api_session.cc', 'atom/browser/api/atom_api_session.h', + 'atom/browser/api/atom_api_system_preferences.cc', + 'atom/browser/api/atom_api_system_preferences.h', + 'atom/browser/api/atom_api_system_preferences_mac.mm', 'atom/browser/api/atom_api_tray.cc', 'atom/browser/api/atom_api_tray.h', 'atom/browser/api/atom_api_web_contents.cc', @@ -157,6 +161,8 @@ 'atom/browser/atom_quota_permission_context.h', 'atom/browser/atom_resource_dispatcher_host_delegate.cc', 'atom/browser/atom_resource_dispatcher_host_delegate.h', + 'atom/browser/atom_security_state_model_client.cc', + 'atom/browser/atom_security_state_model_client.h', 'atom/browser/atom_speech_recognition_manager_delegate.cc', 'atom/browser/atom_speech_recognition_manager_delegate.h', 'atom/browser/bridge_task_runner.cc', @@ -297,6 +303,10 @@ 'atom/common/api/locker.h', 'atom/common/api/object_life_monitor.cc', 'atom/common/api/object_life_monitor.h', + 'atom/common/api/remote_callback_freer.cc', + 'atom/common/api/remote_callback_freer.h', + 'atom/common/api/remote_object_freer.cc', + 'atom/common/api/remote_object_freer.h', 'atom/common/asar/archive.cc', 'atom/common/asar/archive.h', 'atom/common/asar/asar_util.cc', @@ -307,6 +317,8 @@ 'atom/common/atom_command_line.h', 'atom/common/atom_constants.cc', 'atom/common/atom_constants.h', + 'atom/common/color_util.cc', + 'atom/common/color_util.h', 'atom/common/common_message_generator.cc', 'atom/common/common_message_generator.h', 'atom/common/crash_reporter/crash_reporter.cc', @@ -513,6 +525,10 @@ '<@(native_mate_files)', '<(SHARED_INTERMEDIATE_DIR)/atom_natives.h', ], + 'lib_sources_nss': [ + 'chromium_src/chrome/browser/certificate_manager_model.cc', + 'chromium_src/chrome/browser/certificate_manager_model.h', + ], 'lib_sources_win': [ 'chromium_src/chrome/browser/ui/views/color_chooser_dialog.cc', 'chromium_src/chrome/browser/ui/views/color_chooser_dialog.h', diff --git a/lib/browser/api/app.js b/lib/browser/api/app.js index 48a27cfc648d..0487270ce7b3 100644 --- a/lib/browser/api/app.js +++ b/lib/browser/api/app.js @@ -1,8 +1,7 @@ 'use strict' -const deprecate = require('electron').deprecate -const session = require('electron').session -const Menu = require('electron').Menu +const electron = require('electron') +const {deprecate, session, Menu} = electron const EventEmitter = require('events').EventEmitter const bindings = process.atomBinding('app') @@ -65,39 +64,49 @@ for (i = 0, len = ref1.length; i < len; i++) { } // Deprecated. - app.getHomeDir = deprecate('app.getHomeDir', 'app.getPath', function () { return this.getPath('home') }) - app.getDataPath = deprecate('app.getDataPath', 'app.getPath', function () { return this.getPath('userData') }) - app.setDataPath = deprecate('app.setDataPath', 'app.setPath', function (path) { return this.setPath('userData', path) }) - app.resolveProxy = deprecate('app.resolveProxy', 'session.defaultSession.resolveProxy', function (url, callback) { return session.defaultSession.resolveProxy(url, callback) }) - deprecate.rename(app, 'terminate', 'quit') - deprecate.event(app, 'finish-launching', 'ready', function () { // give default app a chance to setup default menu. setImmediate(() => { this.emit('finish-launching') }) }) - deprecate.event(app, 'activate-with-no-open-windows', 'activate', function (event, hasVisibleWindows) { if (!hasVisibleWindows) { return this.emit('activate-with-no-open-windows', event) } }) - deprecate.event(app, 'select-certificate', 'select-client-certificate') +if (process.platform === 'win32') { + app.isAeroGlassEnabled = deprecate('app.isAeroGlassEnabled', 'systemPreferences.isAeroGlassEnabled', function () { + return electron.systemPreferences.isAeroGlassEnabled() + }) +} else if (process.platform === 'darwin') { + app.isDarkMode = deprecate('app.isDarkMode', 'systemPreferences.isDarkMode', function () { + return electron.systemPreferences.isDarkMode() + }) + app.on = app.addListener = function (event, listener) { + if (event === 'platform-theme-changed') { + deprecate.warn('platform-theme-changed event', "systemPreferences.subscribeNotification('AppleInterfaceThemeChangedNotification', callback)") + electron.systemPreferences.subscribeNotification('AppleInterfaceThemeChangedNotification', function () { + app.emit('platform-theme-changed') + }) + } + EventEmitter.prototype.addListener.call(app, event, listener) + } +} // Wrappers for native classes. var wrapDownloadItem = function (downloadItem) { diff --git a/lib/browser/api/auto-updater/auto-updater-win.js b/lib/browser/api/auto-updater/auto-updater-win.js index 896b9ffce9d2..5b1127027e9d 100644 --- a/lib/browser/api/auto-updater/auto-updater-win.js +++ b/lib/browser/api/auto-updater/auto-updater-win.js @@ -12,6 +12,9 @@ function AutoUpdater () { util.inherits(AutoUpdater, EventEmitter) AutoUpdater.prototype.quitAndInstall = function () { + if (!this.updateAvailable) { + return this.emitError('No update available, can\'t quit and install') + } squirrelUpdate.processStart() return app.quit() } @@ -33,8 +36,10 @@ AutoUpdater.prototype.checkForUpdates = function () { return this.emitError(error) } if (update == null) { + this.updateAvailable = false return this.emit('update-not-available') } + this.updateAvailable = true this.emit('update-available') squirrelUpdate.update(this.updateURL, (error) => { var date, releaseNotes, version diff --git a/lib/browser/api/auto-updater/squirrel-update-win.js b/lib/browser/api/auto-updater/squirrel-update-win.js index da27e02aab65..0910c5f4efbb 100644 --- a/lib/browser/api/auto-updater/squirrel-update-win.js +++ b/lib/browser/api/auto-updater/squirrel-update-win.js @@ -7,17 +7,34 @@ const appFolder = path.dirname(process.execPath) // i.e. my-app/Update.exe const updateExe = path.resolve(appFolder, '..', 'Update.exe') - const exeName = path.basename(process.execPath) +var spawnedArgs = [] +var spawnedProcess + +var isSameArgs = function (args) { + return (args.length === spawnedArgs.length) && args.every(function (e, i) { + return e === spawnedArgs[i] + }) +} // Spawn a command and invoke the callback when it completes with an error // and the output from standard out. var spawnUpdate = function (args, detached, callback) { - var error, errorEmitted, spawnedProcess, stderr, stdout + var error, errorEmitted, stderr, stdout + try { - spawnedProcess = spawn(updateExe, args, { - detached: detached - }) + // Ensure we don't spawn multiple squirrel processes + // Process spawned, same args: Attach events to alread running process + // Process spawned, different args: Return with error + // No process spawned: Spawn new process + if (spawnedProcess && !isSameArgs(args)) { + return callback('AutoUpdater process with arugments ' + args + ' is already running') + } else if (!spawnedProcess) { + spawnedProcess = spawn(updateExe, args, { + detached: detached + }) + spawnedArgs = args || [] + } } catch (error1) { error = error1 @@ -41,6 +58,9 @@ var spawnUpdate = function (args, detached, callback) { return callback(error) }) return spawnedProcess.on('exit', function (code, signal) { + spawnedProcess = undefined + spawnedArgs = [] + // We may have already emitted an error. if (errorEmitted) { return diff --git a/lib/browser/api/browser-window.js b/lib/browser/api/browser-window.js index 33aea5da4d0c..c9d63278f974 100644 --- a/lib/browser/api/browser-window.js +++ b/lib/browser/api/browser-window.js @@ -28,7 +28,7 @@ BrowserWindow.prototype._init = function () { width: 800, height: 600 } - return ipcMain.emit('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, disposition, options) + return ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, disposition, options) }) // window.resizeTo(...) @@ -78,19 +78,20 @@ BrowserWindow.prototype._init = function () { app.emit('browser-window-focus', event, this) }) - // Evented visibilityState changes - this.on('show', () => { - this.webContents.send('ATOM_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized()) - }) - this.on('hide', () => { - this.webContents.send('ATOM_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized()) - }) - this.on('minimize', () => { - this.webContents.send('ATOM_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized()) - }) - this.on('restore', () => { - this.webContents.send('ATOM_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized()) - }) + // Subscribe to visibilityState changes and pass to renderer process. + let isVisible = this.isVisible() && !this.isMinimized() + let visibilityChanged = () => { + let newState = this.isVisible() && !this.isMinimized() + if (isVisible !== newState) { + isVisible = newState + this.webContents.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', isVisible ? 'visible' : 'hidden') + } + } + this.on('show', visibilityChanged) + this.on('hide', visibilityChanged) + this.on('minimize', visibilityChanged) + this.on('restore', visibilityChanged) + this.on('maximize', visibilityChanged) // Notify the creation of the window. app.emit('browser-window-created', {}, this) @@ -105,6 +106,7 @@ BrowserWindow.prototype._init = function () { this.webContents.on('devtools-closed', () => { this.emit('devtools-closed') }) + Object.defineProperty(this, 'devToolsWebContents', { enumerable: true, configurable: false, @@ -195,37 +197,21 @@ BrowserWindow.prototype.inspectServiceWorker = function () { } // Deprecated. - deprecate.member(BrowserWindow, 'undo', 'webContents') - deprecate.member(BrowserWindow, 'redo', 'webContents') - deprecate.member(BrowserWindow, 'cut', 'webContents') - deprecate.member(BrowserWindow, 'copy', 'webContents') - deprecate.member(BrowserWindow, 'paste', 'webContents') - deprecate.member(BrowserWindow, 'selectAll', 'webContents') - deprecate.member(BrowserWindow, 'reloadIgnoringCache', 'webContents') - deprecate.member(BrowserWindow, 'isLoading', 'webContents') - deprecate.member(BrowserWindow, 'isWaitingForResponse', 'webContents') - deprecate.member(BrowserWindow, 'stop', 'webContents') - deprecate.member(BrowserWindow, 'isCrashed', 'webContents') - deprecate.member(BrowserWindow, 'print', 'webContents') - deprecate.member(BrowserWindow, 'printToPDF', 'webContents') - deprecate.rename(BrowserWindow, 'restart', 'reload') - deprecate.rename(BrowserWindow, 'loadUrl', 'loadURL') - deprecate.rename(BrowserWindow, 'getUrl', 'getURL') BrowserWindow.prototype.executeJavaScriptInDevTools = deprecate('executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', function (code) { diff --git a/lib/browser/api/exports/electron.js b/lib/browser/api/exports/electron.js index bd8285401c79..9d873663029c 100644 --- a/lib/browser/api/exports/electron.js +++ b/lib/browser/api/exports/electron.js @@ -89,6 +89,12 @@ Object.defineProperties(exports, { return require('../session') } }, + systemPreferences: { + enumerable: true, + get: function () { + return require('../system-preferences') + } + }, Tray: { enumerable: true, get: function () { diff --git a/lib/browser/api/navigation-controller.js b/lib/browser/api/navigation-controller.js index d9dedc91e343..c7aa7f4e92aa 100644 --- a/lib/browser/api/navigation-controller.js +++ b/lib/browser/api/navigation-controller.js @@ -3,12 +3,12 @@ const ipcMain = require('electron').ipcMain // The history operation in renderer is redirected to browser. -ipcMain.on('ATOM_SHELL_NAVIGATION_CONTROLLER', function (event, method, ...args) { +ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER', function (event, method, ...args) { var ref (ref = event.sender)[method].apply(ref, args) }) -ipcMain.on('ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', function (event, method, ...args) { +ipcMain.on('ELECTRON_SYNC_NAVIGATION_CONTROLLER', function (event, method, ...args) { var ref event.returnValue = (ref = event.sender)[method].apply(ref, args) }) diff --git a/lib/browser/api/system-preferences.js b/lib/browser/api/system-preferences.js new file mode 100644 index 000000000000..6ba1750507c0 --- /dev/null +++ b/lib/browser/api/system-preferences.js @@ -0,0 +1,6 @@ +const {EventEmitter} = require('events') +const {systemPreferences} = process.atomBinding('system_preferences') + +Object.setPrototypeOf(systemPreferences, EventEmitter.prototype) + +module.exports = systemPreferences diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 2ec7c14bae11..823351ebe116 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -116,10 +116,12 @@ let wrapWebContents = function (webContents) { callback = hasUserGesture hasUserGesture = false } - if (this.getURL() && !this.isLoading()) { - return asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture) + if (this.getURL() && !this.isLoadingMainFrame()) { + asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture) } else { - return this.once('did-finish-load', asyncWebFrameMethods.bind(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)) + this.once('did-finish-load', () => { + asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture) + }) } } @@ -146,13 +148,9 @@ let wrapWebContents = function (webContents) { return menu.popup(params.x, params.y) }) - // This error occurs when host could not be found. - webContents.on('did-fail-provisional-load', function (...args) { - // Calling loadURL during this event might cause crash, so delay the event - // until next tick. - setImmediate(() => { - this.emit.apply(this, ['did-fail-load'].concat(args)) - }) + // The devtools requests the webContents to reload. + webContents.on('devtools-reload-page', function () { + webContents.reload() }) // Delays the page-title-updated event to next tick. @@ -168,6 +166,7 @@ let wrapWebContents = function (webContents) { deprecate.event(webContents, 'page-title-set', 'page-title-updated', function (...args) { return this.emit.apply(this, ['page-title-set'].concat(args)) }) + webContents.printToPDF = function (options, callback) { var printingSetting printingSetting = { diff --git a/lib/browser/desktop-capturer.js b/lib/browser/desktop-capturer.js index 5ba64fcddb14..5e8ad3e7328c 100644 --- a/lib/browser/desktop-capturer.js +++ b/lib/browser/desktop-capturer.js @@ -10,7 +10,7 @@ var deepEqual = function (opt1, opt2) { // A queue for holding all requests from renderer process. var requestsQueue = [] -ipcMain.on('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, captureWindow, captureScreen, thumbnailSize, id) { +ipcMain.on('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, captureWindow, captureScreen, thumbnailSize, id) { var request request = { id: id, @@ -51,7 +51,7 @@ desktopCapturer.emit = function (event, name, sources) { return results })() if ((ref = handledRequest.webContents) != null) { - ref.send('ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_' + handledRequest.id, result) + ref.send('ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_' + handledRequest.id, result) } // Check the queue to see whether there is other same request. If has, handle @@ -61,7 +61,7 @@ desktopCapturer.emit = function (event, name, sources) { request = requestsQueue[i] if (deepEqual(handledRequest.options, request.options)) { if ((ref1 = request.webContents) != null) { - ref1.send('ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_' + request.id, result) + ref1.send('ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_' + request.id, result) } } else { unhandledRequestsQueue.push(request) diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js index ee633cf29019..58775669c2f4 100644 --- a/lib/browser/guest-view-manager.js +++ b/lib/browser/guest-view-manager.js @@ -137,7 +137,7 @@ var createGuest = function (embedder, params) { // Dispatch events to embedder. fn = function (event) { return guest.on(event, function (_, ...args) { - return embedder.send.apply(embedder, ['ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + guest.viewInstanceId, event].concat(args)) + return embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + guest.viewInstanceId, event].concat(args)) }) } for (j = 0, len1 = supportedWebViewEvents.length; j < len1; j++) { @@ -147,12 +147,12 @@ var createGuest = function (embedder, params) { // Dispatch guest's IPC messages to embedder. guest.on('ipc-message-host', function (_, [channel, ...args]) { - return embedder.send.apply(embedder, ['ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + guest.viewInstanceId, channel].concat(args)) + return embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + guest.viewInstanceId, channel].concat(args)) }) // Autosize. guest.on('size-changed', function (_, ...args) { - return embedder.send.apply(embedder, ['ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + guest.viewInstanceId].concat(args)) + return embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + guest.viewInstanceId].concat(args)) }) return id } @@ -182,6 +182,11 @@ var attachGuest = function (embedder, elementInstanceId, guestInstanceId, params webSecurity: !params.disablewebsecurity, blinkFeatures: params.blinkfeatures } + + if (embedder.getWebPreferences().nodeIntegration === false) { + webPreferences.nodeIntegration = false + } + if (params.preload) { webPreferences.preloadURL = params.preload } @@ -204,19 +209,19 @@ var destroyGuest = function (embedder, id) { } } -ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params, requestId) { - return event.sender.send('ATOM_SHELL_RESPONSE_' + requestId, createGuest(event.sender, params)) +ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params, requestId) { + return event.sender.send('ELECTRON_RESPONSE_' + requestId, createGuest(event.sender, params)) }) -ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, elementInstanceId, guestInstanceId, params) { +ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, elementInstanceId, guestInstanceId, params) { return attachGuest(event.sender, elementInstanceId, guestInstanceId, params) }) -ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', function (event, id) { +ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', function (event, id) { return destroyGuest(event.sender, id) }) -ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', function (event, id, params) { +ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_SET_SIZE', function (event, id, params) { var ref1 return (ref1 = guestInstances[id]) != null ? ref1.guest.setSize(params) : void 0 }) diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index 7508b6f16a2e..c5189bee60ce 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -70,7 +70,7 @@ var createGuest = function (embedder, url, frameName, options) { return guest.destroy() } closedByUser = function () { - embedder.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId) + embedder.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId) return embedder.removeListener('render-view-deleted', closedByEmbedder) } embedder.once('render-view-deleted', closedByEmbedder) @@ -86,7 +86,7 @@ var createGuest = function (embedder, url, frameName, options) { } // Routed window.open messages. -ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, frameName, disposition, options) { +ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, frameName, disposition, options) { options = mergeBrowserWindowOptions(event.sender, options) event.sender.emit('new-window', event, url, frameName, disposition, options) if ((event.sender.isGuest() && !event.sender.allowPopups) || event.defaultPrevented) { @@ -96,17 +96,17 @@ ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, } }) -ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestId) { +ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestId) { var ref1 return (ref1 = BrowserWindow.fromId(guestId)) != null ? ref1.destroy() : void 0 }) -ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) { +ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) { var ref1 event.returnValue = (ref1 = BrowserWindow.fromId(guestId)) != null ? ref1[method].apply(ref1, args) : void 0 }) -ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, guestId, message, targetOrigin, sourceOrigin) { +ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, guestId, message, targetOrigin, sourceOrigin) { var guestContents, ref1, ref2, sourceId sourceId = (ref1 = BrowserWindow.fromWebContents(event.sender)) != null ? ref1.id : void 0 if (sourceId == null) { @@ -114,11 +114,11 @@ ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event } guestContents = (ref2 = BrowserWindow.fromId(guestId)) != null ? ref2.webContents : void 0 if ((guestContents != null ? guestContents.getURL().indexOf(targetOrigin) : void 0) === 0 || targetOrigin === '*') { - return guestContents != null ? guestContents.send('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) : void 0 + return guestContents != null ? guestContents.send('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) : void 0 } }) -ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) { +ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) { var ref1, ref2 return (ref1 = BrowserWindow.fromId(guestId)) != null ? (ref2 = ref1.webContents) != null ? ref2[method].apply(ref2, args) : void 0 : void 0 }) diff --git a/lib/browser/objects-registry.js b/lib/browser/objects-registry.js index b8aa480a6dba..adbf6835554c 100644 --- a/lib/browser/objects-registry.js +++ b/lib/browser/objects-registry.js @@ -50,7 +50,10 @@ class ObjectsRegistry { this.dereference(id) // Also remove the reference in owner. - this.owners[webContentsId].delete(id) + let owner = this.owners[webContentsId] + if (owner) { + owner.delete(id) + } } // Clear all references to objects refrenced by the WebContents. diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 79a52b132626..1dff5fdb8ade 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -12,8 +12,19 @@ const FUNCTION_PROPERTIES = [ ] // The remote functions in renderer processes. -// (webContentsId) => {id: Function} -let rendererFunctions = {} +// id => Function +let rendererFunctions = new IDWeakMap() + +// Merge two IDs together. +let mergeIds = function (webContentsId, metaId) { + const PADDING_BITS = 20 + if ((webContentsId << PADDING_BITS) < 0) { + throw new Error(`webContents ID is too large: ${webContentsId}`) + } else if (metaId > (1 << PADDING_BITS)) { + throw new Error(`Object ID is too large: ${metaId}`) + } + return (webContentsId << PADDING_BITS) + metaId +} // Return the description of object's members: let getObjectMembers = function (object) { @@ -50,50 +61,37 @@ let getObjectPrototype = function (object) { } // Convert a real value into meta data. -var valueToMeta = function (sender, value, optimizeSimpleObject) { - var el, i, len, meta - if (optimizeSimpleObject == null) { - optimizeSimpleObject = false - } - meta = { - type: typeof value - } - if (Buffer.isBuffer(value)) { - meta.type = 'buffer' - } - if (value === null) { - meta.type = 'value' - } - if (Array.isArray(value)) { - meta.type = 'array' - } - if (value instanceof Error) { - meta.type = 'error' - } - if (value instanceof Date) { - meta.type = 'date' - } - if ((value != null ? value.constructor.name : void 0) === 'Promise') { - meta.type = 'promise' - } - - // Treat simple objects as value. - if (optimizeSimpleObject && meta.type === 'object' && v8Util.getHiddenValue(value, 'simple')) { - meta.type = 'value' - } - - // Treat the arguments object as array. - if (meta.type === 'object' && (value.hasOwnProperty('callee')) && (value.length != null)) { - meta.type = 'array' - } - if (meta.type === 'array') { - meta.members = [] - for (i = 0, len = value.length; i < len; i++) { - el = value[i] - meta.members.push(valueToMeta(sender, el)) +let valueToMeta = function (sender, value, optimizeSimpleObject = false) { + // Determine the type of value. + let meta = { type: typeof value } + if (meta.type === 'object') { + // Recognize certain types of objects. + if (value === null) { + meta.type = 'value' + } else if (Buffer.isBuffer(value)) { + meta.type = 'buffer' + } else if (Array.isArray(value)) { + meta.type = 'array' + } else if (value instanceof Error) { + meta.type = 'error' + } else if (value instanceof Date) { + meta.type = 'date' + } else if (value.constructor != null && value.constructor.name === 'Promise') { + meta.type = 'promise' + } else if (value.hasOwnProperty('callee') && value.length != null) { + // Treat the arguments object as array. + meta.type = 'array' + } else if (optimizeSimpleObject && v8Util.getHiddenValue(value, 'simple')) { + // Treat simple objects as value. + meta.type = 'value' } + } + + // Fill the meta object according to value's type. + if (meta.type === 'array') { + meta.members = value.map((el) => valueToMeta(sender, el)) } else if (meta.type === 'object' || meta.type === 'function') { - meta.name = value.constructor.name + meta.name = value.constructor ? value.constructor.name : '' // Reference the original value if it's an object, because when it's // passed to renderer we would assume the renderer keeps a reference of @@ -178,32 +176,26 @@ var unwrapArgs = function (sender, args) { return returnValue } case 'function': { + // Merge webContentsId and meta.id, since meta.id can be the same in + // different webContents. + const webContentsId = sender.getId() + const objectId = mergeIds(webContentsId, meta.id) + // Cache the callbacks in renderer. - let webContentsId = sender.getId() - let callbacks = rendererFunctions[webContentsId] - if (!callbacks) { - callbacks = rendererFunctions[webContentsId] = new IDWeakMap() - sender.once('render-view-deleted', function (event, id) { - callbacks.clear() - delete rendererFunctions[id] - }) + if (rendererFunctions.has(objectId)) { + return rendererFunctions.get(objectId) } - if (callbacks.has(meta.id)) return callbacks.get(meta.id) - let callIntoRenderer = function (...args) { - if ((webContentsId in rendererFunctions) && !sender.isDestroyed()) { - sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args)) + if (!sender.isDestroyed() && webContentsId === sender.getId()) { + sender.send('ELECTRON_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args)) } else { throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`) } } - v8Util.setDestructor(callIntoRenderer, function () { - if ((webContentsId in rendererFunctions) && !sender.isDestroyed()) { - sender.send('ATOM_RENDERER_RELEASE_CALLBACK', meta.id) - } - }) - callbacks.set(meta.id, callIntoRenderer) + + v8Util.setRemoteCallbackFreer(callIntoRenderer, meta.id, sender) + rendererFunctions.set(objectId, callIntoRenderer) return callIntoRenderer } default: @@ -238,7 +230,7 @@ var callFunction = function (event, func, caller, args) { } } -ipcMain.on('ATOM_BROWSER_REQUIRE', function (event, module) { +ipcMain.on('ELECTRON_BROWSER_REQUIRE', function (event, module) { try { event.returnValue = valueToMeta(event.sender, process.mainModule.require(module)) } catch (error) { @@ -246,7 +238,7 @@ ipcMain.on('ATOM_BROWSER_REQUIRE', function (event, module) { } }) -ipcMain.on('ATOM_BROWSER_GET_BUILTIN', function (event, module) { +ipcMain.on('ELECTRON_BROWSER_GET_BUILTIN', function (event, module) { try { event.returnValue = valueToMeta(event.sender, electron[module]) } catch (error) { @@ -254,7 +246,7 @@ ipcMain.on('ATOM_BROWSER_GET_BUILTIN', function (event, module) { } }) -ipcMain.on('ATOM_BROWSER_GLOBAL', function (event, name) { +ipcMain.on('ELECTRON_BROWSER_GLOBAL', function (event, name) { try { event.returnValue = valueToMeta(event.sender, global[name]) } catch (error) { @@ -262,7 +254,7 @@ ipcMain.on('ATOM_BROWSER_GLOBAL', function (event, name) { } }) -ipcMain.on('ATOM_BROWSER_CURRENT_WINDOW', function (event) { +ipcMain.on('ELECTRON_BROWSER_CURRENT_WINDOW', function (event) { try { event.returnValue = valueToMeta(event.sender, event.sender.getOwnerBrowserWindow()) } catch (error) { @@ -270,11 +262,11 @@ ipcMain.on('ATOM_BROWSER_CURRENT_WINDOW', function (event) { } }) -ipcMain.on('ATOM_BROWSER_CURRENT_WEB_CONTENTS', function (event) { +ipcMain.on('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event) { event.returnValue = valueToMeta(event.sender, event.sender) }) -ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function (event, id, args) { +ipcMain.on('ELECTRON_BROWSER_CONSTRUCTOR', function (event, id, args) { try { args = unwrapArgs(event.sender, args) let constructor = objectsRegistry.get(id) @@ -288,7 +280,7 @@ ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function (event, id, args) { } }) -ipcMain.on('ATOM_BROWSER_FUNCTION_CALL', function (event, id, args) { +ipcMain.on('ELECTRON_BROWSER_FUNCTION_CALL', function (event, id, args) { try { args = unwrapArgs(event.sender, args) let func = objectsRegistry.get(id) @@ -298,7 +290,7 @@ ipcMain.on('ATOM_BROWSER_FUNCTION_CALL', function (event, id, args) { } }) -ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function (event, id, method, args) { +ipcMain.on('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, id, method, args) { try { args = unwrapArgs(event.sender, args) let constructor = objectsRegistry.get(id)[method] @@ -311,7 +303,7 @@ ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function (event, id, method, args) } }) -ipcMain.on('ATOM_BROWSER_MEMBER_CALL', function (event, id, method, args) { +ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, id, method, args) { try { args = unwrapArgs(event.sender, args) let obj = objectsRegistry.get(id) @@ -321,7 +313,7 @@ ipcMain.on('ATOM_BROWSER_MEMBER_CALL', function (event, id, method, args) { } }) -ipcMain.on('ATOM_BROWSER_MEMBER_SET', function (event, id, name, value) { +ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, id, name, value) { try { let obj = objectsRegistry.get(id) obj[name] = value @@ -331,7 +323,7 @@ ipcMain.on('ATOM_BROWSER_MEMBER_SET', function (event, id, name, value) { } }) -ipcMain.on('ATOM_BROWSER_MEMBER_GET', function (event, id, name) { +ipcMain.on('ELECTRON_BROWSER_MEMBER_GET', function (event, id, name) { try { let obj = objectsRegistry.get(id) event.returnValue = valueToMeta(event.sender, obj[name]) @@ -340,11 +332,11 @@ ipcMain.on('ATOM_BROWSER_MEMBER_GET', function (event, id, name) { } }) -ipcMain.on('ATOM_BROWSER_DEREFERENCE', function (event, id) { +ipcMain.on('ELECTRON_BROWSER_DEREFERENCE', function (event, id) { return objectsRegistry.remove(event.sender.getId(), id) }) -ipcMain.on('ATOM_BROWSER_GUEST_WEB_CONTENTS', function (event, guestInstanceId) { +ipcMain.on('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, guestInstanceId) { try { let guestViewManager = require('./guest-view-manager') event.returnValue = valueToMeta(event.sender, guestViewManager.getGuest(guestInstanceId)) @@ -353,13 +345,13 @@ ipcMain.on('ATOM_BROWSER_GUEST_WEB_CONTENTS', function (event, guestInstanceId) } }) -ipcMain.on('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function (event, requestId, guestInstanceId, method, ...args) { +ipcMain.on('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function (event, requestId, guestInstanceId, method, ...args) { try { let guestViewManager = require('./guest-view-manager') let guest = guestViewManager.getGuest(guestInstanceId) if (requestId) { const responseCallback = function (result) { - event.sender.send(`ATOM_RENDERER_ASYNC_CALL_TO_GUEST_VIEW_RESPONSE_${requestId}`, result) + event.sender.send(`ELECTRON_RENDERER_ASYNC_CALL_TO_GUEST_VIEW_RESPONSE_${requestId}`, result) } args.push(responseCallback) } diff --git a/lib/common/asar_init.js b/lib/common/asar_init.js index 0f728200880d..13ee449a42c0 100644 --- a/lib/common/asar_init.js +++ b/lib/common/asar_init.js @@ -1,10 +1,10 @@ ;(function () { return function (process, require, asarSource) { // Make asar.coffee accessible via "require". - process.binding('natives').ATOM_SHELL_ASAR = asarSource + process.binding('natives').ELECTRON_ASAR = asarSource // Monkey-patch the fs module. - require('ATOM_SHELL_ASAR').wrapFsWithAsar(require('fs')) + require('ELECTRON_ASAR').wrapFsWithAsar(require('fs')) // Make graceful-fs work with asar. var source = process.binding('natives') @@ -13,7 +13,7 @@ var nativeModule = new process.NativeModule('original-fs') nativeModule.cache() nativeModule.compile() -var asar = require('ATOM_SHELL_ASAR') +var asar = require('ELECTRON_ASAR') asar.wrapFsWithAsar(nativeModule.exports) module.exports = nativeModule.exports` } diff --git a/lib/common/init.js b/lib/common/init.js index 221febb0c37a..11c098d3ce5c 100644 --- a/lib/common/init.js +++ b/lib/common/init.js @@ -44,3 +44,12 @@ if (process.type === 'browser') { global.setTimeout = wrapWithActivateUvLoop(timers.setTimeout) global.setInterval = wrapWithActivateUvLoop(timers.setInterval) } + +// If we're running as a Windows Store app, __dirname will be set +// to C:/Program Files/WindowsApps. +// +// Nobody else get's to install there, changing the path is forbidden +// We can therefore say that we're running as appx +if (process.platform === 'win32' && __dirname.indexOf('\\Program Files\\WindowsApps\\') === 2) { + process.windowsStore = true +} diff --git a/lib/renderer/api/desktop-capturer.js b/lib/renderer/api/desktop-capturer.js index 5683e9cff250..32f78f7a6a37 100644 --- a/lib/renderer/api/desktop-capturer.js +++ b/lib/renderer/api/desktop-capturer.js @@ -27,8 +27,8 @@ exports.getSources = function (options, callback) { } } id = getNextId() - ipcRenderer.send('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id) - return ipcRenderer.once('ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_' + id, function (event, sources) { + ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id) + return ipcRenderer.once('ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_' + id, function (event, sources) { var source return callback(null, (function () { var i, len, results diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index 30b66983a7d9..6631ea22575a 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -45,17 +45,19 @@ var wrapArgs = function (args, visited) { type: 'date', value: value.getTime() } - } else if ((value != null ? value.constructor.name : void 0) === 'Promise') { - return { - type: 'promise', - then: valueToMeta(function (v) { value.then(v) }) - } - } else if ((value != null) && typeof value === 'object' && v8Util.getHiddenValue(value, 'atomId')) { - return { - type: 'remote-object', - id: v8Util.getHiddenValue(value, 'atomId') - } } else if ((value != null) && typeof value === 'object') { + if (value.constructor != null && value.constructor.name === 'Promise') { + return { + type: 'promise', + then: valueToMeta(function (v) { value.then(v) }) + } + } else if (v8Util.getHiddenValue(value, 'atomId')) { + return { + type: 'remote-object', + id: v8Util.getHiddenValue(value, 'atomId') + } + } + ret = { type: 'object', name: value.constructor.name, @@ -102,11 +104,11 @@ let setObjectMembers = function (ref, object, metaId, members) { let remoteMemberFunction = function () { if (this && this.constructor === remoteMemberFunction) { // Constructor call. - let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments)) + let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments)) return metaToValue(ret) } else { // Call member function. - let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments)) + let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments)) return metaToValue(ret) } } @@ -122,13 +124,13 @@ let setObjectMembers = function (ref, object, metaId, members) { descriptor.configurable = true } else if (member.type === 'get') { descriptor.get = function () { - return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, member.name)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_GET', metaId, member.name)) } // Only set setter when it is writable. if (member.writable) { descriptor.set = function (value) { - ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_SET', metaId, member.name, value) + ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, value) return value } } @@ -182,14 +184,14 @@ let metaToValue = function (meta) { let remoteFunction = function () { if (this && this.constructor === remoteFunction) { // Constructor call. - let obj = ipcRenderer.sendSync('ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)) + let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)) // Returning object in constructor will replace constructed object // with the returned object. // http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this return metaToValue(obj) } else { // Function call. - let obj = ipcRenderer.sendSync('ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)) + let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)) return metaToValue(obj) } } @@ -208,9 +210,7 @@ let metaToValue = function (meta) { // Track delegate object's life time, and tell the browser to clean up // when the object is GCed. - v8Util.setDestructor(ret, function () { - ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id) - }) + v8Util.setRemoteObjectFreer(ret, meta.id) // Remember object's id. v8Util.setHiddenValue(ret, 'atomId', meta.id) @@ -239,12 +239,12 @@ var metaToPlainObject = function (meta) { } // Browser calls a callback in renderer. -ipcRenderer.on('ATOM_RENDERER_CALLBACK', function (event, id, args) { +ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', function (event, id, args) { return callbacksRegistry.apply(id, metaToValue(args)) }) // A callback in browser is released. -ipcRenderer.on('ATOM_RENDERER_RELEASE_CALLBACK', function (event, id) { +ipcRenderer.on('ELECTRON_RENDERER_RELEASE_CALLBACK', function (event, id) { return callbacksRegistry.remove(id) }) @@ -265,27 +265,27 @@ for (var name in browserModules) { // Get remote module. exports.require = function (module) { - return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_REQUIRE', module)) } // Alias to remote.require('electron').xxx. exports.getBuiltin = function (module) { - return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GET_BUILTIN', module)) } // Get current BrowserWindow. exports.getCurrentWindow = function () { - return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW')) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WINDOW')) } // Get current WebContents object. exports.getCurrentWebContents = function () { - return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS')) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS')) } // Get a global object in browser. exports.getGlobal = function (name) { - return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GLOBAL', name)) } // Get the process object in browser. @@ -306,6 +306,6 @@ exports.createFunctionWithReturnValue = function (returnValue) { // Get the guest WebContents from guestInstanceId. exports.getGuestWebContents = function (guestInstanceId) { var meta - meta = ipcRenderer.sendSync('ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId) + meta = ipcRenderer.sendSync('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId) return metaToValue(meta) } diff --git a/lib/renderer/init.js b/lib/renderer/init.js index 02ac36c28e1b..a9f4acc5cbfe 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -47,11 +47,7 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (ev // Process command line arguments. var nodeIntegration = 'false' var preloadScript = null - -var ref = process.argv -var i, len, arg -for (i = 0, len = ref.length; i < len; i++) { - arg = ref[i] +for (let arg of process.argv) { if (arg.indexOf('--guest-instance-id=') === 0) { // This is a guest web view. process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1)) diff --git a/lib/renderer/override.js b/lib/renderer/override.js index 20c993d0bc5b..db56eadd3484 100644 --- a/lib/renderer/override.js +++ b/lib/renderer/override.js @@ -3,20 +3,8 @@ const ipcRenderer = require('electron').ipcRenderer const remote = require('electron').remote -// Cache browser window visibility -var _isVisible = true -var _isMinimized = false -var initWindow = function initWindow () { - var currentWindow - currentWindow = remote.getCurrentWindow() - _isVisible = currentWindow.isVisible() - _isMinimized = currentWindow.isMinimized() -} -initWindow() - // Helper function to resolve relative url. var a = window.top.document.createElement('a') - var resolveURL = function (url) { a.href = url return a.href @@ -38,30 +26,30 @@ var BrowserWindowProxy = (function () { function BrowserWindowProxy (guestId1) { this.guestId = guestId1 this.closed = false - ipcRenderer.once('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + this.guestId, () => { + ipcRenderer.once('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + this.guestId, () => { BrowserWindowProxy.remove(this.guestId) this.closed = true }) } BrowserWindowProxy.prototype.close = function () { - return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', this.guestId) + return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', this.guestId) } BrowserWindowProxy.prototype.focus = function () { - return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'focus') + return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'focus') } BrowserWindowProxy.prototype.blur = function () { - return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur') + return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur') } Object.defineProperty(BrowserWindowProxy.prototype, 'location', { get: function () { - return ipcRenderer.sendSync('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'getURL') + return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'getURL') }, set: function (url) { - return ipcRenderer.sendSync('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'loadURL', url) + return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'loadURL', url) } }) @@ -69,11 +57,11 @@ var BrowserWindowProxy = (function () { if (targetOrigin == null) { targetOrigin = '*' } - return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, targetOrigin, window.location.origin) + return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, targetOrigin, window.location.origin) } BrowserWindowProxy.prototype['eval'] = function (...args) { - return ipcRenderer.send.apply(ipcRenderer, ['ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript'].concat(args)) + return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript'].concat(args)) } return BrowserWindowProxy @@ -147,7 +135,7 @@ window.open = function (url, frameName, features) { options[name] = parseInt(options[name], 10) } } - guestId = ipcRenderer.sendSync('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, disposition, options) + guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, disposition, options) if (guestId) { return BrowserWindowProxy.getOrCreate(guestId) } else { @@ -171,8 +159,6 @@ window.alert = function (message, title) { title: title, buttons: buttons }) - -// Alert should always return undefined. } // And the confirm(). @@ -200,18 +186,7 @@ if (process.openerId != null) { window.opener = BrowserWindowProxy.getOrCreate(process.openerId) } -ipcRenderer.on('ATOM_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, isVisible, isMinimized) { - var hasChanged = _isVisible !== isVisible || _isMinimized !== isMinimized - - if (hasChanged) { - _isVisible = isVisible - _isMinimized = isMinimized - - document.dispatchEvent(new Event('visibilitychange')) - } -}) - -ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) { +ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) { // Manually dispatch event instead of using postMessage because we also need to // set event.source. event = document.createEvent('Event') @@ -224,11 +199,11 @@ ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, // Forward history operations to browser. var sendHistoryOperation = function (...args) { - return ipcRenderer.send.apply(ipcRenderer, ['ATOM_SHELL_NAVIGATION_CONTROLLER'].concat(args)) + return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_NAVIGATION_CONTROLLER'].concat(args)) } var getHistoryOperation = function (...args) { - return ipcRenderer.sendSync.apply(ipcRenderer, ['ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER'].concat(args)) + return ipcRenderer.sendSync.apply(ipcRenderer, ['ELECTRON_SYNC_NAVIGATION_CONTROLLER'].concat(args)) } window.history.back = function () { @@ -249,19 +224,26 @@ Object.defineProperty(window.history, 'length', { } }) +// The initial visibilityState. +let cachedVisibilityState = process.argv.includes('--hidden-page') ? 'hidden' : 'visible' + +// Subscribe to visibilityState changes. +ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, visibilityState) { + if (cachedVisibilityState !== visibilityState) { + cachedVisibilityState = visibilityState + document.dispatchEvent(new Event('visibilitychange')) + } +}) + // Make document.hidden and document.visibilityState return the correct value. Object.defineProperty(document, 'hidden', { get: function () { - return _isMinimized || !_isVisible + return cachedVisibilityState !== 'visible' } }) Object.defineProperty(document, 'visibilityState', { get: function () { - if (_isVisible && !_isMinimized) { - return 'visible' - } else { - return 'hidden' - } + return cachedVisibilityState } }) diff --git a/lib/renderer/web-view/guest-view-internal.js b/lib/renderer/web-view/guest-view-internal.js index f4023d22701a..4f920707d1be 100644 --- a/lib/renderer/web-view/guest-view-internal.js +++ b/lib/renderer/web-view/guest-view-internal.js @@ -8,11 +8,11 @@ var requestId = 0 var WEB_VIEW_EVENTS = { 'load-commit': ['url', 'isMainFrame'], 'did-finish-load': [], - 'did-fail-load': ['errorCode', 'errorDescription', 'validatedURL'], + 'did-fail-load': ['errorCode', 'errorDescription', 'validatedURL', 'isMainFrame'], 'did-frame-finish-load': ['isMainFrame'], 'did-start-loading': [], 'did-stop-loading': [], - 'did-get-response-details': ['status', 'newURL', 'originalURL', 'httpResponseCode', 'requestMethod', 'referrer', 'headers'], + 'did-get-response-details': ['status', 'newURL', 'originalURL', 'httpResponseCode', 'requestMethod', 'referrer', 'headers', 'resourceType'], 'did-get-redirect-request': ['oldURL', 'newURL', 'isMainFrame'], 'dom-ready': [], 'console-message': ['level', 'message', 'line', 'sourceId'], @@ -61,18 +61,18 @@ var dispatchEvent = function (webView, eventName, eventKey, ...args) { module.exports = { registerEvents: function (webView, viewInstanceId) { - ipcRenderer.on('ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId, function (event, eventName, ...args) { + ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId, function (event, eventName, ...args) { return dispatchEvent.apply(null, [webView, eventName, eventName].concat(args)) }) - ipcRenderer.on('ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId, function (event, channel, ...args) { + ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId, function (event, channel, ...args) { var domEvent = new Event('ipc-message') domEvent.channel = channel domEvent.args = args return webView.dispatchEvent(domEvent) }) - return ipcRenderer.on('ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + viewInstanceId, function (event, ...args) { + return ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + viewInstanceId, function (event, ...args) { var domEvent, f, i, j, len, ref1 domEvent = new Event('size-changed') ref1 = ['oldWidth', 'oldHeight', 'newWidth', 'newHeight'] @@ -84,23 +84,23 @@ module.exports = { }) }, deregisterEvents: function (viewInstanceId) { - ipcRenderer.removeAllListeners('ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId) - ipcRenderer.removeAllListeners('ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId) - return ipcRenderer.removeAllListeners('ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + viewInstanceId) + ipcRenderer.removeAllListeners('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId) + ipcRenderer.removeAllListeners('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId) + return ipcRenderer.removeAllListeners('ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + viewInstanceId) }, createGuest: function (params, callback) { requestId++ - ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', params, requestId) - return ipcRenderer.once('ATOM_SHELL_RESPONSE_' + requestId, callback) + ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', params, requestId) + return ipcRenderer.once('ELECTRON_RESPONSE_' + requestId, callback) }, attachGuest: function (elementInstanceId, guestInstanceId, params) { - ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params) + ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params) return webFrame.attachGuest(elementInstanceId) }, destroyGuest: function (guestInstanceId) { - return ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId) + return ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId) }, setSize: function (guestInstanceId, params) { - return ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', guestInstanceId, params) + return ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_SET_SIZE', guestInstanceId, params) } } diff --git a/lib/renderer/web-view/web-view.js b/lib/renderer/web-view/web-view.js index 0e96d0c06433..20f5f07465b5 100644 --- a/lib/renderer/web-view/web-view.js +++ b/lib/renderer/web-view/web-view.js @@ -335,6 +335,7 @@ var registerWebViewElement = function () { 'loadURL', 'getTitle', 'isLoading', + 'isLoadingMainFrame', 'isWaitingForResponse', 'stop', 'reload', @@ -404,7 +405,7 @@ var registerWebViewElement = function () { createNonBlockHandler = function (m) { return function (...args) { const internal = v8Util.getHiddenValue(this, 'internal') - return ipcRenderer.send.apply(ipcRenderer, ['ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m].concat(args)) + return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m].concat(args)) } } for (j = 0, len1 = nonblockMethods.length; j < len1; j++) { @@ -419,8 +420,8 @@ var registerWebViewElement = function () { hasUserGesture = false } let requestId = getNextId() - ipcRenderer.send('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', requestId, internal.guestInstanceId, 'executeJavaScript', code, hasUserGesture) - ipcRenderer.once(`ATOM_RENDERER_ASYNC_CALL_TO_GUEST_VIEW_RESPONSE_${requestId}`, function (event, result) { + ipcRenderer.send('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', requestId, internal.guestInstanceId, 'executeJavaScript', code, hasUserGesture) + ipcRenderer.once(`ELECTRON_RENDERER_ASYNC_CALL_TO_GUEST_VIEW_RESPONSE_${requestId}`, function (event, result) { if (callback) callback(result) }) } diff --git a/package.json b/package.json index c12f3d37c42c..7d40098f099a 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "electron", - "version": "0.37.3", + "version": "0.37.8", "devDependencies": { - "asar": "^0.10.0", + "asar": "^0.11.0", "request": "*", "standard": "^6.0.8" }, diff --git a/script/bootstrap.py b/script/bootstrap.py index 1efea3c28973..54f59c68f90f 100755 --- a/script/bootstrap.py +++ b/script/bootstrap.py @@ -168,7 +168,8 @@ def download_sysroot(target_arch): target_arch = 'i386' if target_arch == 'x64': target_arch = 'amd64' - execute_stdout([os.path.join(SOURCE_ROOT, 'script', 'install-sysroot.py'), + execute_stdout([sys.executable, + os.path.join(SOURCE_ROOT, 'script', 'install-sysroot.py'), '--arch', target_arch]) def create_chrome_version_h(): diff --git a/script/cibuild b/script/cibuild index 54cfa508910a..59437837aa16 100755 --- a/script/cibuild +++ b/script/cibuild @@ -32,6 +32,9 @@ LINUX_DEPS_ARM = [ def main(): os.environ['CI'] = '1' + if os.environ.has_key('JANKY_SHA1'): + setup_nodenv() + target_arch = 'x64' if os.environ.has_key('TARGET_ARCH'): target_arch = os.environ['TARGET_ARCH'] @@ -50,12 +53,12 @@ def main(): if PLATFORM == 'linux': os.environ['DISPLAY'] = ':99.0' - run_script('clean.py') - # CI's npm is not reliable. npm = 'npm.cmd' if PLATFORM == 'win32' else 'npm' execute([npm, 'install', 'npm@2.12.1']) + log_versions() + is_release = os.environ.has_key('ELECTRON_RELEASE') args = ['--target_arch=' + target_arch] if not is_release: @@ -76,8 +79,6 @@ def main(): if PLATFORM != 'win32' and target_arch == 'x64': run_script('test.py', ['--ci']) - run_script('clean.py') - def run_script(script, args=[]): sys.stderr.write('\nRunning ' + script +'\n') @@ -86,5 +87,23 @@ def run_script(script, args=[]): subprocess.check_call([sys.executable, script] + args) +def log_versions(): + sys.stderr.write('\nnode --version\n') + sys.stderr.flush() + subprocess.call(['node', '--version']) + + sys.stderr.write('\nnpm --version\n') + sys.stderr.flush() + npm = 'npm.cmd' if PLATFORM == 'win32' else 'npm' + subprocess.call([npm, '--version']) + + +def setup_nodenv(): + if os.path.isdir('/usr/local/share/nodenv'): + os.environ['NODENV_ROOT'] = '/usr/local/share/nodenv' + os.environ['PATH'] = '/usr/local/share/nodenv/bin:/usr/local/share/nodenv/shims:' + os.environ['PATH'] + os.environ['NODENV_VERSION'] = 'v0.10.21' + + if __name__ == '__main__': sys.exit(main()) diff --git a/script/lib/config.py b/script/lib/config.py index 83960e68e2cd..4b3f4ba6fb34 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = 'd41c1e48f428257d99abcf29fd9f26928e9fc53e' +LIBCHROMIUMCONTENT_COMMIT = '1a4c5e51a670633ff3ecd4448ad01ba21b440542' PLATFORM = { 'cygwin': 'win32', diff --git a/script/upload.py b/script/upload.py index d23bc554c3cc..fd795172a679 100755 --- a/script/upload.py +++ b/script/upload.py @@ -14,7 +14,7 @@ from lib.util import atom_gyp, execute, get_atom_shell_version, parse_version, \ from lib.github import GitHub -ATOM_SHELL_REPO = 'atom/electron' +ATOM_SHELL_REPO = 'electron/electron' ATOM_SHELL_VERSION = get_atom_shell_version() PROJECT_NAME = atom_gyp()['project_name%'] diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index c237ef17238e..1c20ef8e4523 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -1,5 +1,7 @@ const assert = require('assert') const ChildProcess = require('child_process') +const https = require('https') +const fs = require('fs') const path = require('path') const remote = require('electron').remote @@ -87,6 +89,70 @@ describe('app module', function () { }) }) + describe('app.importCertificate', function () { + if (process.platform !== 'linux') + return + + this.timeout(5000) + + var w = null + var certPath = path.join(__dirname, 'fixtures', 'certificates') + var options = { + key: fs.readFileSync(path.join(certPath, 'server.key')), + cert: fs.readFileSync(path.join(certPath, 'server.pem')), + ca: [ + fs.readFileSync(path.join(certPath, 'rootCA.pem')), + fs.readFileSync(path.join(certPath, 'intermediateCA.pem')) + ], + requestCert: true, + rejectUnauthorized: false + } + + var server = https.createServer(options, function (req, res) { + if (req.client.authorized) { + res.writeHead(200); + res.end('authorized'); + } + }) + + afterEach(function () { + if (w != null) { + w.destroy() + } + w = null + }) + + it('can import certificate into platform cert store', function (done) { + let options = { + certificate: path.join(certPath, 'client.p12'), + password: 'electron' + } + + w = new BrowserWindow({ + show: false + }) + + w.webContents.on('did-finish-load', function () { + server.close() + done() + }) + + app.on('select-client-certificate', function (event, webContents, url, list, callback) { + assert.equal(list.length, 1) + assert.equal(list[0].issuerName, 'Intermediate CA') + callback(list[0]) + }) + + app.importCertificate(options, function (result) { + assert(!result) + server.listen(0, '127.0.0.1', function () { + var port = server.address().port + w.loadURL(`https://127.0.0.1:${port}`) + }) + }) + }) + }) + describe('BrowserWindow events', function () { var w = null diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 468586eb7bb8..c364b916c3a4 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -4,6 +4,7 @@ const assert = require('assert') const fs = require('fs') const path = require('path') const os = require('os') +const http = require('http') const remote = require('electron').remote const screen = require('electron').screen @@ -18,6 +19,23 @@ const isCI = remote.getGlobal('isCi') describe('browser-window module', function () { var fixtures = path.resolve(__dirname, 'fixtures') var w = null + var server + + before(function (done) { + server = http.createServer(function (req, res) { + function respond() { res.end(''); } + setTimeout(respond, req.url.includes('slow') ? 200 : 0) + }); + server.listen(0, '127.0.0.1', function () { + server.url = 'http://127.0.0.1:' + server.address().port + done() + }) + }) + + after(function () { + server.close() + server = null + }) beforeEach(function () { if (w != null) { @@ -101,22 +119,66 @@ describe('browser-window module', function () { w.loadURL('about:blank') }) + it('should emit did-get-response-details event', function (done) { + // expected {fileName: resourceType} pairs + var expectedResources = { + 'did-get-response-details.html': 'mainFrame', + 'logo.png': 'image' + } + var responses = 0; + w.webContents.on('did-get-response-details', function (event, status, newUrl, oldUrl, responseCode, method, referrer, headers, resourceType) { + responses++ + var fileName = newUrl.slice(newUrl.lastIndexOf('/') + 1) + var expectedType = expectedResources[fileName] + assert(!!expectedType, `Unexpected response details for ${newUrl}`) + assert(typeof status === 'boolean', 'status should be boolean') + assert.equal(responseCode, 200) + assert.equal(method, 'GET') + assert(typeof referrer === 'string', 'referrer should be string') + assert(!!headers, 'headers should be present') + assert(typeof headers === 'object', 'headers should be object') + assert.equal(resourceType, expectedType, 'Incorrect resourceType') + if (responses === Object.keys(expectedResources).length) { + done() + } + }) + w.loadURL('file://' + path.join(fixtures, 'pages', 'did-get-response-details.html')) + }) + it('should emit did-fail-load event for files that do not exist', function (done) { - w.webContents.on('did-fail-load', function (event, code) { + w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { assert.equal(code, -6) + assert.equal(isMainFrame, true) done() }) w.loadURL('file://a.txt') }) it('should emit did-fail-load event for invalid URL', function (done) { - w.webContents.on('did-fail-load', function (event, code, desc) { + w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { assert.equal(desc, 'ERR_INVALID_URL') assert.equal(code, -300) + assert.equal(isMainFrame, true) done() }) w.loadURL('http://example:port') }) + + it('should set `mainFrame = false` on did-fail-load events in iframes', function (done) { + w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { + assert.equal(isMainFrame, false) + done() + }) + w.loadURL('file://' + path.join(fixtures, 'api', 'did-fail-load-iframe.html')) + }) + + it('does not crash in did-fail-provisional-load handler', function (done) { + w.webContents.once('did-fail-provisional-load', function () { + w.loadURL('http://localhost:11111') + done() + }) + w.loadURL('http://localhost:11111') + }) }) describe('BrowserWindow.show()', function () { @@ -590,6 +652,44 @@ describe('browser-window module', function () { assert.equal(w.isResizable(), true) }) }) + + describe('loading main frame state', function () { + it('is true when the main frame is loading', function (done) { + w.webContents.on('did-start-loading', function() { + assert.equal(w.webContents.isLoadingMainFrame(), true) + done() + }) + w.webContents.loadURL(server.url) + }) + + it('is false when only a subframe is loading', function (done) { + w.webContents.once('did-finish-load', function() { + assert.equal(w.webContents.isLoadingMainFrame(), false) + w.webContents.on('did-start-loading', function() { + assert.equal(w.webContents.isLoadingMainFrame(), false) + done() + }) + w.webContents.executeJavaScript(` + var iframe = document.createElement('iframe') + iframe.src = '${server.url}/page2' + document.body.appendChild(iframe) + `) + }) + w.webContents.loadURL(server.url) + }) + + it('is true when navigating to pages from the same origin', function (done) { + w.webContents.once('did-finish-load', function() { + assert.equal(w.webContents.isLoadingMainFrame(), false) + w.webContents.on('did-start-loading', function() { + assert.equal(w.webContents.isLoadingMainFrame(), true) + done() + }) + w.webContents.loadURL(`${server.url}/page2`) + }) + w.webContents.loadURL(server.url) + }) + }) }) describe('window states (excluding Linux)', function () { @@ -754,6 +854,30 @@ describe('browser-window module', function () { done() }) }) + + it('works after page load and during subframe load', function (done) { + w.webContents.once('did-finish-load', function() { + // initiate a sub-frame load, then try and execute script during it + w.webContents.executeJavaScript(` + var iframe = document.createElement('iframe') + iframe.src = '${server.url}/slow' + document.body.appendChild(iframe) + `, function() { + w.webContents.executeJavaScript(`console.log('hello')`, function() { + done() + }) + }) + }) + w.loadURL(server.url) + }) + + it('executes after page load', function (done) { + w.webContents.executeJavaScript(code, function(result) { + assert.equal(result, expected) + done() + }) + w.loadURL(server.url) + }) }) describe('deprecated options', function () { diff --git a/spec/api-desktop-capturer-spec.js b/spec/api-desktop-capturer-spec.js index 9e85a48fbcc5..68ab2463087d 100644 --- a/spec/api-desktop-capturer-spec.js +++ b/spec/api-desktop-capturer-spec.js @@ -24,4 +24,16 @@ describe('desktopCapturer', function () { desktopCapturer.getSources({types: ['window', 'screen']}, callback) desktopCapturer.getSources({types: ['window', 'screen']}, callback) }) + + it('responds to subsequest calls of different options', function (done) { + var callCount = 0 + var callback = function (error, sources) { + callCount++ + assert.equal(error, null) + if (callCount === 2) done() + } + + desktopCapturer.getSources({types: ['window']}, callback) + desktopCapturer.getSources({types: ['screen']}, callback) + }) }) diff --git a/spec/api-web-request-spec.js b/spec/api-web-request-spec.js index abc4f9568cd3..211c69a14765 100644 --- a/spec/api-web-request-spec.js +++ b/spec/api-web-request-spec.js @@ -7,12 +7,18 @@ const session = remote.session describe('webRequest module', function () { var ses = session.defaultSession var server = http.createServer(function (req, res) { - res.setHeader('Custom', ['Header']) - var content = req.url - if (req.headers.accept === '*/*;test/header') { - content += 'header/received' + if (req.url == '/serverRedirect') { + res.statusCode = 301 + res.setHeader('Location', 'http://' + req.rawHeaders[1]) + res.end() + } else { + res.setHeader('Custom', ['Header']) + var content = req.url + if (req.headers.accept === '*/*;test/header') { + content += 'header/received' + } + res.end(content) } - res.end(content) }) var defaultURL = null @@ -297,6 +303,44 @@ describe('webRequest module', function () { } }) }) + + it('follows server redirect', function (done) { + ses.webRequest.onHeadersReceived(function (details, callback) { + var responseHeaders = details.responseHeaders + callback({ + responseHeaders: responseHeaders, + }) + }) + $.ajax({ + url: defaultURL + 'serverRedirect', + success: function (data, status, xhr) { + assert.equal(xhr.getResponseHeader('Custom'), 'Header') + done() + }, + error: function (xhr, errorType) { + done(errorType) + } + }) + }) + + it('can change the header status', function (done) { + ses.webRequest.onHeadersReceived(function (details, callback) { + var responseHeaders = details.responseHeaders + callback({ + responseHeaders: responseHeaders, + statusLine: "HTTP/1.1 404 Not Found" + }) + }) + $.ajax({ + url: defaultURL, + success: function (data, status, xhr) { + }, + error: function (xhr, errorType) { + assert.equal(xhr.getResponseHeader('Custom'), 'Header') + done() + } + }) + }) }) describe('webRequest.onResponseStarted', function () { diff --git a/spec/fixtures/api/did-fail-load-iframe.html b/spec/fixtures/api/did-fail-load-iframe.html new file mode 100644 index 000000000000..293041b65ecb --- /dev/null +++ b/spec/fixtures/api/did-fail-load-iframe.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/fixtures/certificates/certs.cnf b/spec/fixtures/certificates/certs.cnf new file mode 100644 index 000000000000..76ef8d073f9d --- /dev/null +++ b/spec/fixtures/certificates/certs.cnf @@ -0,0 +1,68 @@ +ID=1 +CA_DIR=out + +[ca] +default_ca = ca_settings + +[ca_settings] +dir = ${ENV::CA_DIR} +database = $dir/${ENV::ID}-index.txt +new_certs_dir = $dir +serial = $dir/${ENV::ID}-serial +certificate = $dir/${ENV::ID}.pem +private_key = $dir/${ENV::ID}.key +RANDFILE = $dir/rand +default_md = sha256 +default_days = 3650 +policy = policy_anything +preserve = no + +[policy_anything] +# Default signing policy +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[req] +default_bits = 2048 +default_md = sha256 +string_mask = utf8only +distinguished_name = req_env_dn +prompt = no + +[user_cert] +basicConstraints = CA:FALSE +nsCertType = client +nsComment = "OpenSSL Generated Client Certificate" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth, emailProtection + +[server_cert] +basicConstraints = CA:FALSE +nsCertType = server +nsComment = "OpenSSL Generated Server Certificate" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth + +[ca_cert] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true +keyUsage = critical, digitalSignature, cRLSign, keyCertSign + +[ca_intermediate_cert] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true, pathlen:0 +keyUsage = critical, digitalSignature, cRLSign, keyCertSign + +[req_env_dn] +commonName = ${ENV::COMMON_NAME} diff --git a/spec/fixtures/certificates/client.p12 b/spec/fixtures/certificates/client.p12 new file mode 100644 index 000000000000..7543c7d38904 Binary files /dev/null and b/spec/fixtures/certificates/client.p12 differ diff --git a/spec/fixtures/certificates/generate_certs.sh b/spec/fixtures/certificates/generate_certs.sh new file mode 100755 index 000000000000..c8e6217e66fd --- /dev/null +++ b/spec/fixtures/certificates/generate_certs.sh @@ -0,0 +1,127 @@ +#!/bin/bash +# This script generates certificates that can be used to test SSL client +# authentication. +# +# 1. A (end-entity) -> B -> C (self-signed root) +# 2. D (end-entity) -> B -> C (self-signed root) + +try () { + echo "$@" + "$@" || exit 1 +} + +try mkdir out + +echo Create the serial number files and indices. +serial=1000 +for i in B C +do + try /bin/sh -c "echo $serial > out/$i-serial" + serial=$(expr $serial + 1) + touch out/$i-index.txt + touch out/$i-index.txt.attr +done + +echo Generate the keys. +for i in A B C D +do + try openssl genrsa -out out/$i.key 2048 +done + +echo Generate the C CSR +COMMON_NAME="Root CA" \ + CA_DIR=out \ + ID=C \ + try openssl req \ + -new \ + -key out/C.key \ + -out out/C.csr \ + -config certs.cnf + +echo C signs itself. +COMMON_NAME="Root CA" \ + CA_DIR=out \ + ID=C \ + try openssl x509 \ + -req -days 3650 \ + -in out/C.csr \ + -extensions ca_cert \ + -extfile certs.cnf \ + -signkey out/C.key \ + -out out/C.pem + +echo Generate the intermediates +COMMON_NAME="Intermediate CA" \ + CA_DIR=out \ + ID=B \ + try openssl req \ + -new \ + -key out/B.key \ + -out out/B.csr \ + -config certs.cnf + +COMMON_NAME="Root CA" \ + CA_DIR=out \ + ID=C \ + try openssl ca \ + -batch \ + -extensions ca_intermediate_cert \ + -in out/B.csr \ + -out out/B.pem \ + -config certs.cnf + +echo Generate the leaf certs +COMMON_NAME="Client Cert" \ + ID=A \ + try openssl req \ + -new \ + -key out/A.key \ + -out out/A.csr \ + -config certs.cnf + +echo B signs A +COMMON_NAME="Intermediate CA" \ + CA_DIR=out \ + ID=B \ + try openssl ca \ + -batch \ + -extensions user_cert \ + -in out/A.csr \ + -out out/A.pem \ + -config certs.cnf + +COMMON_NAME="localhost" \ + ID=D \ + try openssl req \ + -new \ + -key out/D.key \ + -out out/D.csr \ + -config certs.cnf + +echo B signs D +COMMON_NAME="Intermediate CA" \ + CA_DIR=out \ + ID=B \ + try openssl ca \ + -batch \ + -extensions server_cert \ + -in out/D.csr \ + -out out/D.pem \ + -config certs.cnf + +echo Package the client cert and private key into PKCS12 file +try /bin/sh -c "cat out/A.pem out/A.key out/B.pem out/C.pem > out/A-chain.pem" + +try openssl pkcs12 \ + -in out/A-chain.pem \ + -out client.p12 \ + -export \ + -passout pass:electron + +echo Package the certs +try cp out/C.pem rootCA.pem +try cp out/B.pem intermediateCA.pem +try cp out/D.key server.key +try cp out/D.pem server.pem + +try rm -rf out diff --git a/spec/fixtures/certificates/intermediateCA.pem b/spec/fixtures/certificates/intermediateCA.pem new file mode 100644 index 000000000000..58293f76da0b --- /dev/null +++ b/spec/fixtures/certificates/intermediateCA.pem @@ -0,0 +1,78 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4097 (0x1001) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Root CA + Validity + Not Before: Apr 18 16:14:29 2016 GMT + Not After : Apr 16 16:14:29 2026 GMT + Subject: CN=Intermediate CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b6:42:02:13:25:40:13:a6:05:99:69:da:0c:c9: + a8:bf:86:3b:fc:c6:51:ba:64:65:7e:33:11:31:d5: + 03:45:30:4c:ca:49:d2:96:42:52:2f:f9:e6:6c:9a: + 50:1c:fe:fa:e2:e8:63:36:14:47:f7:49:9f:78:28: + 5e:1f:0b:9d:9e:f8:d3:33:77:06:4d:6d:14:c0:57: + 01:83:2b:ef:99:06:48:21:ec:c1:d7:05:48:2c:ea: + 83:06:6a:20:df:73:ce:8a:a5:e4:81:00:41:84:cf: + 89:81:78:2e:3a:bd:1b:fd:3e:96:08:8d:44:1b:00: + c8:d6:4e:7a:6a:75:c0:9b:3c:e0:fa:aa:3a:82:5b: + 3c:39:32:ca:4a:ba:82:bc:60:47:6f:e4:4a:fd:dc: + a0:72:8a:1b:fe:cd:2e:10:f4:27:4c:08:4e:d1:ed: + dc:08:b0:f8:1f:e4:fc:45:72:43:58:6e:dd:05:37: + 8c:04:a1:fb:64:f4:3f:90:bb:85:f2:4c:97:46:fd: + 1f:29:e5:19:d0:0f:24:fd:d1:00:c5:b6:be:da:84: + 62:77:be:db:67:f6:ec:98:5d:97:f5:df:0a:bd:b8: + 07:7f:0a:d5:92:29:1f:c4:b0:97:4f:e4:87:d7:a9: + 00:c9:61:d5:6c:cd:6a:fc:56:c3:f3:b7:ca:53:70: + 02:3f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + A9:75:99:CF:9C:92:54:A4:4B:65:CD:3D:FC:93:98:8D:9E:09:1F:47 + X509v3 Authority Key Identifier: + keyid:E3:51:87:E3:CD:7A:B3:26:9F:8F:EC:62:D1:0E:15:0C:39:36:47:4F + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 55:69:d6:1d:33:ad:ab:40:46:fd:34:02:c1:43:50:7b:90:ea: + f3:5f:4f:b6:2c:28:aa:72:e0:4b:36:2e:8f:44:93:15:52:14: + f6:61:b3:50:e0:ba:43:91:ba:a9:5d:ac:43:b7:52:ca:91:a3: + d7:0e:ac:a7:9e:ee:28:7f:2d:0f:93:b5:d9:23:35:68:54:29: + 2a:e7:3a:4c:41:24:d0:5e:2d:f3:1e:b9:52:f1:3e:16:76:93: + 89:6d:a1:4c:63:f5:4a:cc:08:36:61:29:0a:29:5f:f4:5a:55: + 98:10:b3:de:b3:90:f9:03:e5:bd:1b:61:01:a7:22:03:ae:0f: + 77:c4:a8:bf:31:b4:af:c8:c7:e3:25:a1:2b:b9:43:37:3b:08: + ea:c4:46:60:b8:5f:ee:2a:0d:ce:18:75:63:ba:32:28:84:f4: + 56:95:1b:c5:f9:46:7e:14:2e:83:5e:a9:ff:b2:80:ca:25:fd: + 22:90:b5:de:bd:e6:f1:0c:ee:7e:09:71:0d:82:6a:ca:2f:9c: + 96:45:73:3a:65:bc:d8:9d:e0:61:01:5d:a8:de:de:61:8c:82: + 52:0c:ef:97:39:b3:13:c6:7d:d0:c0:f5:6d:c8:70:5b:96:e8: + 99:31:d8:75:3a:21:58:ab:01:21:9e:38:8e:53:ff:f8:48:a7: + af:01:9a:93 +-----BEGIN CERTIFICATE----- +MIIDDjCCAfagAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v +dCBDQTAeFw0xNjA0MTgxNjE0MjlaFw0yNjA0MTYxNjE0MjlaMBoxGDAWBgNVBAMM +D0ludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALZCAhMlQBOmBZlp2gzJqL+GO/zGUbpkZX4zETHVA0UwTMpJ0pZCUi/55myaUBz+ ++uLoYzYUR/dJn3goXh8LnZ740zN3Bk1tFMBXAYMr75kGSCHswdcFSCzqgwZqIN9z +zoql5IEAQYTPiYF4Ljq9G/0+lgiNRBsAyNZOemp1wJs84PqqOoJbPDkyykq6grxg +R2/kSv3coHKKG/7NLhD0J0wITtHt3Aiw+B/k/EVyQ1hu3QU3jASh+2T0P5C7hfJM +l0b9HynlGdAPJP3RAMW2vtqEYne+22f27Jhdl/XfCr24B38K1ZIpH8Swl0/kh9ep +AMlh1WzNavxWw/O3ylNwAj8CAwEAAaNmMGQwHQYDVR0OBBYEFKl1mc+cklSkS2XN +PfyTmI2eCR9HMB8GA1UdIwQYMBaAFONRh+PNerMmn4/sYtEOFQw5NkdPMBIGA1Ud +EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB +AQBVadYdM62rQEb9NALBQ1B7kOrzX0+2LCiqcuBLNi6PRJMVUhT2YbNQ4LpDkbqp +XaxDt1LKkaPXDqynnu4ofy0Pk7XZIzVoVCkq5zpMQSTQXi3zHrlS8T4WdpOJbaFM +Y/VKzAg2YSkKKV/0WlWYELPes5D5A+W9G2EBpyIDrg93xKi/MbSvyMfjJaEruUM3 +OwjqxEZguF/uKg3OGHVjujIohPRWlRvF+UZ+FC6DXqn/soDKJf0ikLXevebxDO5+ +CXENgmrKL5yWRXM6ZbzYneBhAV2o3t5hjIJSDO+XObMTxn3QwPVtyHBbluiZMdh1 +OiFYqwEhnjiOU//4SKevAZqT +-----END CERTIFICATE----- diff --git a/spec/fixtures/certificates/rootCA.pem b/spec/fixtures/certificates/rootCA.pem new file mode 100644 index 000000000000..5c77fe61cd0f --- /dev/null +++ b/spec/fixtures/certificates/rootCA.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCjCCAfKgAwIBAgIJAOcWbv0WHll0MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV +BAMMB1Jvb3QgQ0EwHhcNMTYwNDE4MTYxNDI5WhcNMjYwNDE2MTYxNDI5WjASMRAw +DgYDVQQDDAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +0iZvelv6MjxqdmQsAmKqIfc5gvQjYB3CqWlEH3g5czPFBMMtmOI9czlk+0jc1VEf +t1SKst7zwe1rpxFArgudV45NBHQH3ZlzkLeO7Ol2kPzlyMHNJ70vT3CBitKnLl4B +bg7xf6kDQQlC3/QeWxvbR5cvp131uwcpXKdJ9k4dwpfS2BKiRb5Uk46DgX5kGaka +q/tQ2F7b6AlAoTq608tZBuOInkg2tTbGe9PDWSL8oMZRwCSbF543SAR45zjWBa0k +ymY31VvlYbEd/3lfE5Mrn/JwZQpTKOfcOI//kUkcClJVpSMObh4eiy1oNjqcJ4KR +/4hkY7oTQCA7zWD34jQpkQIDAQABo2MwYTAdBgNVHQ4EFgQU41GH4816syafj+xi +0Q4VDDk2R08wHwYDVR0jBBgwFoAU41GH4816syafj+xi0Q4VDDk2R08wDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggEBADrt +1bSbOYxDmB1x9KaHNFVSzs0XsipsbZW/XTqtNMPMFXh+I57NVptVanCwcfU5zmOF +AjL+R8v0NkPU9+6nSM2PYqWxEavf0f6pkxIj+ThFwtVwXEKocPG9RFUvZNZv+rSH +yAnzuAzFI71EsT9VgJGHI0pgPjrGbSlNfb0OJFOlwtbGWGofmg+N6hHcx5nVKlgL +ZWLtYT+/mT2pSGuIpJtdnuUv0vcrRa4mxAa8NPF4+Qpi6yErkfogE+T4RYf2L4rp +CaRIFicLoNUmwK0nCerJaPFLwGkiNGNX81CHnw3+xLisSPvxze2ZRA0DhUWUGInq +grjWDMO9P1hPWu5jmbo= +-----END CERTIFICATE----- diff --git a/spec/fixtures/certificates/server.key b/spec/fixtures/certificates/server.key new file mode 100644 index 000000000000..719bfc8797df --- /dev/null +++ b/spec/fixtures/certificates/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAuByk7Ib6anz0xOFRqyogGsTTEAAGduquIckVFajDHrk7vdq+ +TflkDp+UhbISqu1rj0OuaqODxiPSSw5fHClqNKpjhHS1ry86knS847BGwrByY0oa +zBdN0UgtWiXOK+iCuSI9p0KSIORJ3Y70pUZmm12EHRwb0tANv4ogYxjAxwnyqYgn +PnrDsoyCh/Cb4Fu8XucrnepYbInXi6yOdwTuivTx9qy7tlQzvYJ2LLEUIJdBtCUZ +dZkxky9CJUbfu5rm6PFvbLII5YCSlpXLxg9bumZCR1z9IXE6rLYcJIp3HIquR2cN +tAs9M8OHuR5V6vhUG51bP3aTkg3asJVdUe10dwIDAQABAoIBAQCJGINSwZv86blW +VbX7r+2iIUhNVMd7i3tJGzQBId7RpPswf49P/tIb9YaiG5y8/PgoAS0CqWn5hDkW +vMfj747vUqWyPzn/DjseTaFOJrg6RyuWddsIeJ3wpj9nLlmc5pFZDH8+alrn9TZv +rgDMhWTocjVre7/YNibWpyNAx3DdhG5DzNVLnu1R68d5k3JutQVqm01xCAV9ne9n +xE1RB5Z1xLvpQfW2qLYT0yFB7Xxw8awGyzVesPhGW1aa5F4urQjdCt2baa06Xolu +T3wXJ6wA9BuF2KOCi8DxELDaXoB//+82HafgWbOWIhJFOzEZaMNqZkfS/GbCgpEr +mE2r8zGBAoGBAOHNcUPgnIIeGdgFZZvL3Ge3Hp5mi2Vd2KBkAPNCjVSXeCu57yRC +SetlYuZlIhd7o+wdxUmWtg73DU19eDXJsOjXgNAoJfT9Zsyi4RClmJ0FRcSzvFU/ +m/TKrBbnFFAI+1pKwDnQ7envuRiTECFSsvKqdr8hddx0cPCgDtbe+75BAoGBANC7 +4ozkgsUTtdojz0DYBYBwUjN1gUETIhl91tt+48hmmEedROWDQDCT9gJfpAVFe1I6 +RyKKJnBcgNDJ7mqPUB1f5xb5rtaZS1owPNYTi3GrdVVg3lAf0j5ch8XoRJn/plnL +M0Sj5lLMviHJjyk8CPHbnE2k2vERAW4/SgzfA3S3AoGAHx55Jamm6CfN1/+maTpH +PeP2zE3FmEq+uBwQJXZek/HsFdqiIpUgKtjmMGpvsFzR0pCnx+SFYrqZkrxf/Mm3 +H9/TWNyvnnvt1vX7npez2LAJVXqP0g/aJnpoDR/7pKwYN/FlXJJ2t27aS5C5AF6t +WtQzWVP7Mk654e+tG9/PQgECgYEAiTCT7EpccK9NvLwAgfv5UbuBK3U1qNGsfdip +mMZDa/mSaK9DEx462DLHZDP8F8LdFORc0KTAMuV5fMDbxInA/C2GMyGT+lPypKpD +sehSpDku+xiZxUvE4VvrmPXZ8OWILkhRv/GBdjY/WPGi+FUPA/d1Ocr6Y6rrp8xN +HTyOhu0CgYBKxTSH6RCQsm8Q8uqmcP7cwe6fciTC0c2CRRqlzuXeseG72MBRDk/8 +P1jtOIlIsax/8NwNm5ReAiLgVn/h6/YgN4fpMkV1XIaH4j7HiGf5CWgOTWxS9jWA +cV09H22BaNkT0fZ71IlXQI11cVRodX0g4cJXeuyTxY9OkMd6cGs8+A== +-----END RSA PRIVATE KEY----- diff --git a/spec/fixtures/certificates/server.pem b/spec/fixtures/certificates/server.pem new file mode 100644 index 000000000000..117be807e528 --- /dev/null +++ b/spec/fixtures/certificates/server.pem @@ -0,0 +1,88 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4097 (0x1001) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Intermediate CA + Validity + Not Before: Apr 18 16:14:29 2016 GMT + Not After : Apr 16 16:14:29 2026 GMT + Subject: CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b8:1c:a4:ec:86:fa:6a:7c:f4:c4:e1:51:ab:2a: + 20:1a:c4:d3:10:00:06:76:ea:ae:21:c9:15:15:a8: + c3:1e:b9:3b:bd:da:be:4d:f9:64:0e:9f:94:85:b2: + 12:aa:ed:6b:8f:43:ae:6a:a3:83:c6:23:d2:4b:0e: + 5f:1c:29:6a:34:aa:63:84:74:b5:af:2f:3a:92:74: + bc:e3:b0:46:c2:b0:72:63:4a:1a:cc:17:4d:d1:48: + 2d:5a:25:ce:2b:e8:82:b9:22:3d:a7:42:92:20:e4: + 49:dd:8e:f4:a5:46:66:9b:5d:84:1d:1c:1b:d2:d0: + 0d:bf:8a:20:63:18:c0:c7:09:f2:a9:88:27:3e:7a: + c3:b2:8c:82:87:f0:9b:e0:5b:bc:5e:e7:2b:9d:ea: + 58:6c:89:d7:8b:ac:8e:77:04:ee:8a:f4:f1:f6:ac: + bb:b6:54:33:bd:82:76:2c:b1:14:20:97:41:b4:25: + 19:75:99:31:93:2f:42:25:46:df:bb:9a:e6:e8:f1: + 6f:6c:b2:08:e5:80:92:96:95:cb:c6:0f:5b:ba:66: + 42:47:5c:fd:21:71:3a:ac:b6:1c:24:8a:77:1c:8a: + ae:47:67:0d:b4:0b:3d:33:c3:87:b9:1e:55:ea:f8: + 54:1b:9d:5b:3f:76:93:92:0d:da:b0:95:5d:51:ed: + 74:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Cert Type: + SSL Server + Netscape Comment: + OpenSSL Generated Server Certificate + X509v3 Subject Key Identifier: + 1D:60:82:FA:3A:EC:27:91:BA:8D:F5:ED:B2:E3:85:0B:22:5A:8E:38 + X509v3 Authority Key Identifier: + keyid:A9:75:99:CF:9C:92:54:A4:4B:65:CD:3D:FC:93:98:8D:9E:09:1F:47 + DirName:/CN=Root CA + serial:10:01 + + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication + Signature Algorithm: sha256WithRSAEncryption + 89:90:3d:2c:b8:0d:36:63:68:9a:cd:f9:14:56:94:d9:18:11: + b5:08:35:af:f9:34:cd:70:db:7d:66:06:e3:57:9b:06:8f:11: + d6:ea:ac:a6:07:db:ae:a2:c0:66:69:84:d8:2d:3c:cc:d7:4d: + 3c:75:60:4f:98:fc:56:df:30:39:c6:55:2c:73:92:9e:0c:b5: + 7c:75:40:5d:21:aa:01:c1:8a:03:86:eb:d7:02:7d:f5:7b:12: + cc:18:90:23:ad:8f:d7:05:18:6d:f0:11:a8:6b:27:fd:4c:07: + 07:53:f5:7f:f7:a2:e5:18:1e:4e:90:1b:10:5f:f3:5c:cb:c7: + 37:63:d0:d5:1d:3a:65:66:24:ee:0e:ce:7f:b1:fb:ee:17:d0: + b5:4d:64:2f:5a:9c:bc:7a:1c:c0:b4:0f:32:c9:a9:5c:cb:57: + 26:fd:49:39:8d:f2:89:54:c4:92:b5:35:ec:fe:cf:87:07:a6: + 84:01:98:00:e4:2a:44:26:b7:48:00:11:d3:e4:5a:c1:ad:46: + 36:53:f9:28:b7:e4:c5:bb:66:88:ab:8e:cc:30:d0:96:aa:3e: + c1:12:6a:8f:fa:6d:19:15:f4:90:66:54:62:84:97:06:2d:5c: + b9:18:71:90:f4:ca:4c:8c:a5:8b:32:14:93:89:f1:93:f4:00: + bd:1d:42:4f +-----BEGIN CERTIFICATE----- +MIIDgjCCAmqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwGjEYMBYGA1UEAwwPSW50 +ZXJtZWRpYXRlIENBMB4XDTE2MDQxODE2MTQyOVoXDTI2MDQxNjE2MTQyOVowFDES +MBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAuByk7Ib6anz0xOFRqyogGsTTEAAGduquIckVFajDHrk7vdq+TflkDp+UhbIS +qu1rj0OuaqODxiPSSw5fHClqNKpjhHS1ry86knS847BGwrByY0oazBdN0UgtWiXO +K+iCuSI9p0KSIORJ3Y70pUZmm12EHRwb0tANv4ogYxjAxwnyqYgnPnrDsoyCh/Cb +4Fu8XucrnepYbInXi6yOdwTuivTx9qy7tlQzvYJ2LLEUIJdBtCUZdZkxky9CJUbf +u5rm6PFvbLII5YCSlpXLxg9bumZCR1z9IXE6rLYcJIp3HIquR2cNtAs9M8OHuR5V +6vhUG51bP3aTkg3asJVdUe10dwIDAQABo4HXMIHUMAkGA1UdEwQCMAAwEQYJYIZI +AYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBT +ZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFB1ggvo67CeRuo317bLjhQsiWo44 +MDsGA1UdIwQ0MDKAFKl1mc+cklSkS2XNPfyTmI2eCR9HoRakFDASMRAwDgYDVQQD +DAdSb290IENBggIQATAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH +AwEwDQYJKoZIhvcNAQELBQADggEBAImQPSy4DTZjaJrN+RRWlNkYEbUINa/5NM1w +231mBuNXmwaPEdbqrKYH266iwGZphNgtPMzXTTx1YE+Y/FbfMDnGVSxzkp4MtXx1 +QF0hqgHBigOG69cCffV7EswYkCOtj9cFGG3wEahrJ/1MBwdT9X/3ouUYHk6QGxBf +81zLxzdj0NUdOmVmJO4Ozn+x++4X0LVNZC9anLx6HMC0DzLJqVzLVyb9STmN8olU +xJK1Nez+z4cHpoQBmADkKkQmt0gAEdPkWsGtRjZT+Si35MW7Zoirjsww0JaqPsES +ao/6bRkV9JBmVGKElwYtXLkYcZD0ykyMpYsyFJOJ8ZP0AL0dQk8= +-----END CERTIFICATE----- diff --git a/spec/fixtures/module/answer.js b/spec/fixtures/module/answer.js new file mode 100644 index 000000000000..d592d6cda214 --- /dev/null +++ b/spec/fixtures/module/answer.js @@ -0,0 +1,4 @@ +var ipcRenderer = require('electron').ipcRenderer +window.answer = function (answer) { + ipcRenderer.send('answer', answer) +} diff --git a/spec/fixtures/pages/did-get-response-details.html b/spec/fixtures/pages/did-get-response-details.html new file mode 100644 index 000000000000..c98458c8ffaa --- /dev/null +++ b/spec/fixtures/pages/did-get-response-details.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/fixtures/pages/ping.html b/spec/fixtures/pages/ping.html new file mode 100644 index 000000000000..5bd6a8772a95 --- /dev/null +++ b/spec/fixtures/pages/ping.html @@ -0,0 +1,7 @@ + + + + + diff --git a/spec/fixtures/pages/web-view-log-process.html b/spec/fixtures/pages/web-view-log-process.html new file mode 100644 index 000000000000..9e75edb393e2 --- /dev/null +++ b/spec/fixtures/pages/web-view-log-process.html @@ -0,0 +1,13 @@ + + + + + test + + + + test? + + diff --git a/spec/fixtures/pages/webview-no-node-integration-on-window.html b/spec/fixtures/pages/webview-no-node-integration-on-window.html new file mode 100644 index 000000000000..0af03cf1c497 --- /dev/null +++ b/spec/fixtures/pages/webview-no-node-integration-on-window.html @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/spec/fixtures/pages/webview-no-script.html b/spec/fixtures/pages/webview-no-script.html new file mode 100644 index 000000000000..00b8f21bde70 --- /dev/null +++ b/spec/fixtures/pages/webview-no-script.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/node-spec.js b/spec/node-spec.js index 286c4d6f9161..0ab98aa67ab9 100644 --- a/spec/node-spec.js +++ b/spec/node-spec.js @@ -196,6 +196,11 @@ describe('node feature', function () { assert.equal(b.toString(), 'Jøhänñéß') assert.equal(Buffer.byteLength(p.innerText), 13) }) + + it('does not crash when creating large Buffers', function () { + new Buffer(new Array(4096).join(' ')); + new Buffer(new Array(4097).join(' ')); + }) }) describe('process.stdout', function () { @@ -212,6 +217,12 @@ describe('node feature', function () { }) }) + describe('process.version', function () { + it('should not have -pre', function () { + assert(!process.version.endsWith('-pre')) + }) + }) + describe('vm.createContext', function () { it('should not crash', function () { require('vm').runInNewContext('') diff --git a/spec/static/index.html b/spec/static/index.html index 3c57f94d144d..e31fcffebb89 100644 --- a/spec/static/index.html +++ b/spec/static/index.html @@ -3,11 +3,6 @@ - diff --git a/spec/static/main.js b/spec/static/main.js index 2707f6a686de..84e9ba3da55d 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -83,7 +83,7 @@ app.on('ready', function () { width: 800, height: 600, webPreferences: { - javascript: true // Test whether web preferences crashes. + backgroundThrottling: false, } }) window.loadURL(url.format({ diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 0d32138906e3..d2c37c857df1 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -2,7 +2,7 @@ const assert = require('assert') const path = require('path') const http = require('http') const url = require('url') -const {app, session} = require('electron').remote +const {app, session, ipcMain, BrowserWindow} = require('electron').remote describe(' tag', function () { this.timeout(10000) @@ -20,6 +20,15 @@ describe(' tag', function () { } }) + it('works without script tag in page', function (done) { + let w = new BrowserWindow({show: false}) + ipcMain.once('pong', function () { + w.destroy() + done() + }) + w.loadURL('file://' + fixtures + '/pages/webview-no-script.html') + }) + describe('src attribute', function () { it('specifies the page to load', function (done) { webview.addEventListener('console-message', function (e) { @@ -75,6 +84,39 @@ describe(' tag', function () { document.body.appendChild(webview) }) + it('disables node integration when disabled on the parent BrowserWindow', function (done) { + var b = undefined + + ipcMain.once('answer', function (event, typeofProcess) { + try { + assert.equal(typeofProcess, 'undefined') + done() + } finally { + b.close() + } + }) + + var windowUrl = require('url').format({ + pathname: `${fixtures}/pages/webview-no-node-integration-on-window.html`, + protocol: 'file', + query: { + p: `${fixtures}/pages/web-view-log-process.html` + }, + slashes: true + }) + var preload = path.join(fixtures, 'module', 'answer.js') + + b = new BrowserWindow({ + height: 400, + width: 400, + show: false, + webPreferences: { + preload: preload, + nodeIntegration: false, + } + }) + b.loadURL(windowUrl) + }) it('disables node integration on child windows when it is disabled on the webview', function (done) { app.once('browser-window-created', function (event, window) { @@ -155,6 +197,18 @@ describe(' tag', function () { webview.src = 'file://' + fixtures + '/pages/e.html' document.body.appendChild(webview) }) + + it('works without script tag in page', function (done) { + var listener = function (e) { + assert.equal(e.message, 'function object object') + webview.removeEventListener('console-message', listener) + done() + } + webview.addEventListener('console-message', listener) + webview.setAttribute('preload', fixtures + '/module/preload.js') + webview.src = 'file://' + fixtures + '/pages/base-page.html' + document.body.appendChild(webview) + }) }) describe('httpreferrer attribute', function () { @@ -701,11 +755,13 @@ describe(' tag', function () { }) describe('permission-request event', function () { - function setUpRequestHandler (webview, requested_permission) { + function setUpRequestHandler (webview, requested_permission, completed) { var listener = function (webContents, permission, callback) { if (webContents.getId() === webview.getId()) { assert.equal(permission, requested_permission) callback(false) + if (completed) + completed() } } session.fromPartition(webview.partition).setPermissionRequestHandler(listener) @@ -749,6 +805,13 @@ describe(' tag', function () { setUpRequestHandler(webview, 'midiSysex') document.body.appendChild(webview) }) + + it('emits when accessing external protocol', function (done) { + webview.src = 'magnet:test' + webview.partition = 'permissionTest' + setUpRequestHandler(webview, 'openExternal', done) + document.body.appendChild(webview) + }) }) describe('.getWebContents', function () { @@ -763,4 +826,33 @@ describe(' tag', function () { document.body.appendChild(webview) }) }) + + describe('did-get-response-details event', function () { + it('emits for the page and its resources', function (done) { + // expected {fileName: resourceType} pairs + var expectedResources = { + 'did-get-response-details.html': 'mainFrame', + 'logo.png': 'image' + } + var responses = 0; + webview.addEventListener('did-get-response-details', function (event) { + responses++ + var fileName = event.newURL.slice(event.newURL.lastIndexOf('/') + 1) + var expectedType = expectedResources[fileName] + assert(!!expectedType, `Unexpected response details for ${event.newURL}`) + assert(typeof event.status === 'boolean', 'status should be boolean') + assert.equal(event.httpResponseCode, 200) + assert.equal(event.requestMethod, 'GET') + assert(typeof event.referrer === 'string', 'referrer should be string') + assert(!!event.headers, 'headers should be present') + assert(typeof event.headers === 'object', 'headers should be object') + assert.equal(event.resourceType, expectedType, 'Incorrect resourceType') + if (responses === Object.keys(expectedResources).length) { + done() + } + }) + webview.src = 'file://' + path.join(fixtures, 'pages', 'did-get-response-details.html') + document.body.appendChild(webview) + }) + }) }) diff --git a/toolchain.gypi b/toolchain.gypi index 7c3cd0d05833..11da28f70233 100644 --- a/toolchain.gypi +++ b/toolchain.gypi @@ -16,7 +16,7 @@ 'arm_neon%': 1, # Abosulte path to source root. - 'source_root%': '