From 19d7f0733e77a57a5bf5743917c7d6f9abc10b50 Mon Sep 17 00:00:00 2001 From: Catalin Ionut Fratila Date: Fri, 10 Feb 2017 14:26:53 +0100 Subject: [PATCH 001/337] create-dist: Adding argument to supress api docs generation. --- script/create-dist.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/script/create-dist.py b/script/create-dist.py index 4aa67eacd676..f9d590259c1e 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import argparse import glob import os import re @@ -86,7 +87,9 @@ def main(): copy_chrome_binary('mksnapshot') copy_license() - if PLATFORM != 'win32': + args = parse_args() + + if PLATFORM != 'win32' and not args.no_api_docs: create_api_json_schema() if PLATFORM == 'linux': @@ -241,5 +244,13 @@ def create_symbols_zip(): make_zip(os.path.join(DIST_DIR, pdb_name), pdbs + licenses, []) +def parse_args(): + parser = argparse.ArgumentParser(description='Create Electron Distribution') + parser.add_argument('--no_api_docs', + action='store_true', + help='Skip generating the Electron API Documentation!') + return parser.parse_args() + + if __name__ == '__main__': sys.exit(main()) From 8aba64025038e79f043793b29871e77dd88bc118 Mon Sep 17 00:00:00 2001 From: mst128256 Date: Thu, 9 Mar 2017 16:01:33 +0100 Subject: [PATCH 002/337] added default menu items for 'Edit' and 'Window' #2814 --- docs/api/menu-item.md | 3 ++ lib/browser/api/menu-item-roles.js | 81 ++++++++++++++++++++++++++++++ lib/browser/api/menu-item.js | 2 +- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 1c12d9fdacd1..76fcae1129f3 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -64,6 +64,9 @@ The `role` property can have following values: * `zoomin` - Zoom in the focused page by 10% * `zoomout` - Zoom out the focused page by 10% +* `menuEdit` - Whole default "Edit" menu (Undo,Copy, etc.) +* `menuWindow` - Whole default "Window" menu (Minimize, Close, etc.) + On macOS `role` can also have following additional values: * `about` - Map to the `orderFrontStandardAboutPanel` action diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 8a78670267ae..254283b86be8 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -154,6 +154,73 @@ const roles = { webContents.setZoomLevel(zoomLevel - 0.5) }) } + }, + // submenu Edit (should fit both Mac & Windows) + menuEdit: { + label: 'Edit', + submenu: [ + { + role: 'undo' + }, + { + role: 'redo' + }, + { + type: 'separator' + }, + { + role: 'cut' + }, + { + role: 'copy' + }, + { + role: 'paste' + }, + + process.platform === 'darwin' ? + { + role: 'pasteandmatchstyle' + } : {}, + + { + role: 'delete' + }, + + process.platform === 'win32' ? + { + type: 'separator' + } : {}, + + { + role: 'selectall' + } + ] + }, + + // submenu Window should be used for Mac only + menuWindow: { + label: 'Window', + submenu: [ + { + role: 'minimize' + }, + { + role: 'close' + }, + + process.platform === 'darwin' ? + { + type: 'separator' + } : {}, + + process.platform === 'darwin' ? + { + label: 'Bring All to Front', + role: 'front' + } : {} + + ] } } @@ -176,6 +243,20 @@ exports.getDefaultAccelerator = (role) => { if (roles.hasOwnProperty(role)) return roles[role].accelerator } +exports.getDefaultSubmenu = (role) => { + if (roles.hasOwnProperty(role)) { + submenu = roles[role].submenu + + // remove empty objects from within the submenu + if (Array.isArray(submenu)) + submenu = submenu.filter(function(n){ + return n.constructor !== Object || Object.keys(n).length > 0 + }) + + return submenu + } +} + exports.execute = (role, focusedWindow, focusedWebContents) => { if (!canExecuteRole(role)) return false diff --git a/lib/browser/api/menu-item.js b/lib/browser/api/menu-item.js index 98b8e9980e28..e95226d3b364 100644 --- a/lib/browser/api/menu-item.js +++ b/lib/browser/api/menu-item.js @@ -11,7 +11,7 @@ const MenuItem = function (options) { for (let key in options) { if (!(key in this)) this[key] = options[key] } - + this.submenu = this.submenu || roles.getDefaultSubmenu(this.role) if (this.submenu != null && this.submenu.constructor !== Menu) { this.submenu = Menu.buildFromTemplate(this.submenu) } From 7fefb75de5dd6cb4e4c8501d02e419d8fd5b206a Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Fri, 10 Mar 2017 08:08:23 -0800 Subject: [PATCH 003/337] update versioning doc --- docs/tutorial/electron-versioning.md | 60 +++++++++++++++++++++------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/docs/tutorial/electron-versioning.md b/docs/tutorial/electron-versioning.md index cae99344a657..b1812d84b4c4 100644 --- a/docs/tutorial/electron-versioning.md +++ b/docs/tutorial/electron-versioning.md @@ -1,21 +1,51 @@ # Electron Versioning -If you are a seasoned Node developer, you are surely aware of `semver` - and -might be used to giving your dependency management systems only rough guidelines -rather than fixed version numbers. Due to the hard dependency on Node and -Chromium, Electron is in a slightly more difficult position and does not follow -semver. You should therefore always reference a specific version of Electron. +If you've been using Node and npm for a while, you are probably aware of [Semantic Versioning], or SemVer for short. It's a convention for specifying version numbers for software that helps communicate intentions to the users of your software. -Version numbers are bumped using the following rules: +## Overview of Semantic Versioning -* Major: For breaking changes in Electron's API - if you upgrade from `0.37.0` - to `1.0.0`, you will have to update your app. -* Minor: For major Chrome and minor Node upgrades; or significant Electron - changes - if you upgrade from `1.0.0` to `1.1.0`, your app is supposed to +Semantic versions are always made up of three numbers: + +``` +major.minor.patch +``` + +Semantic version numbers are bumped (incremented) using the following rules: + +* **Major** is for changes that break backwards compatibility. +* **Minor** is for new features that don't break backwards compatibility. +* **Patch** is for bug fixes and other minor changes. + +A simple mnemonic for remembering this scheme is as follows: + +``` +breaking.feature.fix +``` + +## Electron Versioning + +Due to its dependency on Node and Chromium, it is not possible for the Electron +project to adhere to a SemVer policy. **You should therefore always +reference a specific version of Electron.** + +Electron version numbers are bumped using the following rules: + +* **Major** is for breaking changes in Electron's API. If you upgrade from `0.37.0` + to `1.0.0`, you will have to make changes to your app. +* **Minor** is for major Chrome and minor Node upgrades, or significant Electron + changes. If you upgrade from `1.5.0` to `1.6.0`, your app is supposed to still work, but you might have to work around small changes. -* Patch: For new features and bug fixes - if you upgrade from `1.0.0` to - `1.0.1`, your app will continue to work as-is. +* **Patch** is for new features and bug fixes. If you upgrade from `1.6.2` to + `1.6.3`, your app will continue to work as-is. -If you are using `electron` or `electron-prebuilt`, we recommend that you set a fixed version -number (`1.1.0` instead of `^1.1.0`) to ensure that all upgrades of Electron are -a manual operation made by you, the developer. +We recommend that you set a fixed version when installing Electron from npm: + +```sh +npm install electron --save-exact --save-dev +``` + +The `--save-exact` flag will add `electron` to your `package.json` file without +using a `^` or `~`, e.g. `1.6.2` instead of `^1.6.2`. This practice ensures that +all upgrades of Electron are a manual operation made by you, the developer. + +[Semantic Versioning](http://semver.org) From 582662e40fc96801e5d2be9dd4d9bc8b9981de78 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Fri, 10 Mar 2017 09:03:04 -0800 Subject: [PATCH 004/337] fix markdown link --- docs/tutorial/electron-versioning.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/electron-versioning.md b/docs/tutorial/electron-versioning.md index b1812d84b4c4..eccd9459f881 100644 --- a/docs/tutorial/electron-versioning.md +++ b/docs/tutorial/electron-versioning.md @@ -48,4 +48,4 @@ The `--save-exact` flag will add `electron` to your `package.json` file without using a `^` or `~`, e.g. `1.6.2` instead of `^1.6.2`. This practice ensures that all upgrades of Electron are a manual operation made by you, the developer. -[Semantic Versioning](http://semver.org) +[Semantic Versioning]: http://semver.org From 76ee7fda2b2ec83de0755555604c80442f9882b3 Mon Sep 17 00:00:00 2001 From: mst128256 Date: Mon, 13 Mar 2017 14:26:34 +0100 Subject: [PATCH 005/337] Fixed linting --- lib/browser/api/menu-item-roles.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 254283b86be8..8919b8d10ec7 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -178,8 +178,7 @@ const roles = { role: 'paste' }, - process.platform === 'darwin' ? - { + process.platform === 'darwin' ? { role: 'pasteandmatchstyle' } : {}, @@ -187,9 +186,8 @@ const roles = { role: 'delete' }, - process.platform === 'win32' ? - { - type: 'separator' + process.platform === 'win32' ? { + type: 'separator' } : {}, { @@ -209,13 +207,11 @@ const roles = { role: 'close' }, - process.platform === 'darwin' ? - { + process.platform === 'darwin' ? { type: 'separator' } : {}, - process.platform === 'darwin' ? - { + process.platform === 'darwin' ? { label: 'Bring All to Front', role: 'front' } : {} @@ -245,13 +241,14 @@ exports.getDefaultAccelerator = (role) => { exports.getDefaultSubmenu = (role) => { if (roles.hasOwnProperty(role)) { - submenu = roles[role].submenu + let submenu = roles[role].submenu // remove empty objects from within the submenu - if (Array.isArray(submenu)) - submenu = submenu.filter(function(n){ + if (Array.isArray(submenu)) { + submenu = submenu.filter(function (n) { return n.constructor !== Object || Object.keys(n).length > 0 }) + } return submenu } From 46af3cefec37e13fa03d4b52c155fcb555dcbf40 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 15:42:26 -0700 Subject: [PATCH 006/337] Clarify remote require of relative modules The docs for the `remote.require(module)` method were a little too terse for me to understand the behavior of relative module loading for `remote.require` and I had to run an experiment to understand the behavior (e.g. is the relative path relative to caller of `remote.require` or relative to some other path in the project related to the main process?). I think this is correct but someone please double check my understanding. Adding an example and additional explanation should help clarify this. Feel free to edit the copy as needed. --- docs/api/remote.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 0bed3ad9b511..7f1c7f09292c 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -140,7 +140,26 @@ The `remote` module has the following methods: * `module` String -Returns `any` - The object returned by `require(module)` in the main process. +Returns `any` - The object returned by `require(module)` in the main process. Modules specified by their relative path will resolve relative to the entrypoint of the main process. + +e.g. + +```js +// main process: main/index.js +const { app, ipcMain } = require('electron') +app.on('ready', () => { +//... +``` + +```js +// some relative module: main/foo.js +module.exports = 'bar' +``` + +```js +// renderer process: renderer/index.js +const foo = require('electron').remote.require('./foo') // bar +``` ### `remote.getCurrentWindow()` From f82590b9ab0288409d817e948332a3ab122d4eb3 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 15:48:42 -0700 Subject: [PATCH 007/337] Wrap at 80 --- docs/api/remote.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 7f1c7f09292c..ccbfbf3fb14f 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -140,7 +140,9 @@ The `remote` module has the following methods: * `module` String -Returns `any` - The object returned by `require(module)` in the main process. Modules specified by their relative path will resolve relative to the entrypoint of the main process. +Returns `any` - The object returned by `require(module)` in the main process. +Modules specified by their relative path will resolve relative to the entrypoint +of the main process. e.g. From 2276357f723ada06b31c9595e7bd76a3898e7562 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 17:18:23 -0700 Subject: [PATCH 008/337] update with a tree --- docs/api/remote.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index ccbfbf3fb14f..36b38b835408 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -146,11 +146,24 @@ of the main process. e.g. +``` +project/ +├── main +│   ├── foo.js +│   └── index.js +├── package.json +└── renderer + └── index.js +``` + ```js // main process: main/index.js -const { app, ipcMain } = require('electron') +const { app } = require('electron') app.on('ready', () => { -//... + +// ... + +}) ``` ```js From 85c48a23368317bc134c938876d5515abab17349 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Mon, 13 Mar 2017 17:20:11 -0700 Subject: [PATCH 009/337] make main process example shorter --- docs/api/remote.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 36b38b835408..4da19daaa34f 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -159,11 +159,7 @@ project/ ```js // main process: main/index.js const { app } = require('electron') -app.on('ready', () => { - -// ... - -}) +app.on('ready', () => {/* ... */}) ``` ```js From b67c81226c05856b09cef9b5066a0d74e23ff424 Mon Sep 17 00:00:00 2001 From: Bret Comnes Date: Tue, 14 Mar 2017 10:48:44 -0700 Subject: [PATCH 010/337] fix linting --- docs/api/remote.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 4da19daaa34f..2db8d17c9992 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -159,7 +159,7 @@ project/ ```js // main process: main/index.js const { app } = require('electron') -app.on('ready', () => {/* ... */}) +app.on('ready', () => { /* ... */ }) ``` ```js From 16f97544459abab741eeeffe8d0a51e260c4fa33 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 14 Mar 2017 21:08:10 +0530 Subject: [PATCH 011/337] Create separate request context for geolocation service. * Geolocation service cannot hold reference to browser context, since it is destroyed at the end of everything and this will confuse the shutdown path of browser context. * Geolocation service run on its own thread. --- atom/browser/atom_access_token_store.cc | 82 ++++++++++++------------- atom/browser/atom_access_token_store.h | 8 +-- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/atom/browser/atom_access_token_store.cc b/atom/browser/atom_access_token_store.cc index aef54dfa0ebc..6a5597ca7780 100644 --- a/atom/browser/atom_access_token_store.cc +++ b/atom/browser/atom_access_token_store.cc @@ -7,11 +7,13 @@ #include #include -#include "atom/browser/atom_browser_context.h" #include "atom/common/google_api_key.h" #include "base/environment.h" #include "content/public/browser/browser_thread.h" #include "device/geolocation/geolocation_provider.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_builder.h" +#include "net/url_request/url_request_context_getter.h" using content::BrowserThread; @@ -19,51 +21,40 @@ namespace atom { namespace internal { -// Loads access tokens and other necessary data on the UI thread, and -// calls back to the originator on the originating thread. -class TokenLoadingJob : public base::RefCountedThreadSafe { +class GeoURLRequestContextGetter : public net::URLRequestContextGetter { public: - explicit TokenLoadingJob( - const device::AccessTokenStore::LoadAccessTokensCallback& callback) - : callback_(callback), request_context_getter_(nullptr) {} + net::URLRequestContext* GetURLRequestContext() override { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!url_request_context_.get()) { + net::URLRequestContextBuilder builder; + builder.set_proxy_config_service( + net::ProxyService::CreateSystemProxyConfigService( + BrowserThread::GetTaskRunnerForThread(BrowserThread::IO), + BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE))); + url_request_context_ = builder.Build(); + } + return url_request_context_.get(); + } - void Run(AtomBrowserContext* browser_context) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - request_context_getter_ = browser_context->GetRequestContext(); - std::unique_ptr env(base::Environment::Create()); - if (!env->GetVar("GOOGLE_API_KEY", &api_key_)) - api_key_ = GOOGLEAPIS_API_KEY; - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&TokenLoadingJob::RespondOnIOThread, this)); + scoped_refptr GetNetworkTaskRunner() + const override { + return BrowserThread::GetTaskRunnerForThread(BrowserThread::IO); } private: - friend class base::RefCountedThreadSafe; + friend class atom::AtomAccessTokenStore; - ~TokenLoadingJob() {} + GeoURLRequestContextGetter() {} + ~GeoURLRequestContextGetter() override {} - void RespondOnIOThread() { - // Equivalent to access_token_map[kGeolocationProviderURL]. - // Somehow base::string16 is causing compilation errors when used in a pair - // of std::map on Linux, this can work around it. - device::AccessTokenStore::AccessTokenMap access_token_map; - std::pair token_pair; - token_pair.first = GURL(GOOGLEAPIS_ENDPOINT + api_key_); - access_token_map.insert(token_pair); - - callback_.Run(access_token_map, request_context_getter_); - } - - device::AccessTokenStore::LoadAccessTokensCallback callback_; - net::URLRequestContextGetter* request_context_getter_; - std::string api_key_; + std::unique_ptr url_request_context_; + DISALLOW_COPY_AND_ASSIGN(GeoURLRequestContextGetter); }; } // namespace internal -AtomAccessTokenStore::AtomAccessTokenStore() { - browser_context_ = AtomBrowserContext::From("", false); +AtomAccessTokenStore::AtomAccessTokenStore() + : request_context_getter_(new internal::GeoURLRequestContextGetter) { device::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); } @@ -72,16 +63,19 @@ AtomAccessTokenStore::~AtomAccessTokenStore() { void AtomAccessTokenStore::LoadAccessTokens( const LoadAccessTokensCallback& callback) { - scoped_refptr job( - new internal::TokenLoadingJob(callback)); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&AtomAccessTokenStore::RunTokenLoadingJob, - this, base::RetainedRef(job))); -} + std::unique_ptr env(base::Environment::Create()); + std::string api_key; + if (!env->GetVar("GOOGLE_API_KEY", &api_key)) + api_key = GOOGLEAPIS_API_KEY; + // Equivalent to access_token_map[kGeolocationProviderURL]. + // Somehow base::string16 is causing compilation errors when used in a pair + // of std::map on Linux, this can work around it. + device::AccessTokenStore::AccessTokenMap access_token_map; + std::pair token_pair; + token_pair.first = GURL(GOOGLEAPIS_ENDPOINT + api_key); + access_token_map.insert(token_pair); -void AtomAccessTokenStore::RunTokenLoadingJob( - scoped_refptr job) { - job->Run(browser_context_.get()); + callback.Run(access_token_map, request_context_getter_.get()); } void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url, diff --git a/atom/browser/atom_access_token_store.h b/atom/browser/atom_access_token_store.h index 07884e58d60a..820ceddce4fd 100644 --- a/atom/browser/atom_access_token_store.h +++ b/atom/browser/atom_access_token_store.h @@ -9,10 +9,8 @@ namespace atom { -class AtomBrowserContext; - namespace internal { -class TokenLoadingJob; +class GeoURLRequestContextGetter; } class AtomAccessTokenStore : public device::AccessTokenStore { @@ -27,9 +25,7 @@ class AtomAccessTokenStore : public device::AccessTokenStore { const base::string16& access_token) override; private: - void RunTokenLoadingJob(scoped_refptr job); - - scoped_refptr browser_context_; + scoped_refptr request_context_getter_; DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore); }; From 72adbf7a2fef7aaef83fb56db9d3e9ddacc99b3a Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sun, 19 Mar 2017 01:10:30 +0530 Subject: [PATCH 012/337] destroy guest webcontents before embedder --- atom/browser/api/atom_api_web_contents.cc | 16 ++++++++-------- atom/browser/api/atom_api_web_contents.h | 3 +++ vendor/brightray | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 6ba23b3c9afc..0f188d0d222e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -411,14 +411,18 @@ WebContents::~WebContents() { if (type_ == WEB_VIEW) guest_delegate_->Destroy(); - // The WebContentsDestroyed will not be called automatically because we - // unsubscribe from webContents before destroying it. So we have to manually - // call it here to make sure "destroyed" event is emitted. RenderViewDeleted(web_contents()->GetRenderViewHost()); - WebContentsDestroyed(); + DestroyWebContents(); } } +void WebContents::DestroyWebContents() { + // This event is only for internal use, which is emitted when WebContents is + // being destroyed. + Emit("will-destroy"); + CommonWebContentsDelegate::DestroyWebContents(); +} + bool WebContents::DidAddMessageToConsole(content::WebContents* source, int32_t level, const base::string16& message, @@ -919,10 +923,6 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { // be destroyed on close, and WebContentsDestroyed would be called for it, so // we need to make sure the api::WebContents is also deleted. void WebContents::WebContentsDestroyed() { - // This event is only for internal use, which is emitted when WebContents is - // being destroyed. - Emit("will-destroy"); - // Cleanup relationships with other parts. RemoveFromWeakMap(); diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 2513dc7722a8..c289503b43c9 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -76,6 +76,9 @@ class WebContents : public mate::TrackableObject, static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); + // Notifies to destroy any guest web contents before destroying self. + void DestroyWebContents(); + int64_t GetID() const; int GetProcessID() const; Type GetType() const; diff --git a/vendor/brightray b/vendor/brightray index d0144ba2c902..53aa2cfc8a40 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit d0144ba2c9024d65cdf260abf5c03c742afff3fd +Subproject commit 53aa2cfc8a40627d62bf5be757ff9dea444f80bd From 4ab2c9241896fc96ef3ba7f158897b92a90aa463 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 22 Mar 2017 07:30:36 +0530 Subject: [PATCH 013/337] CommonWebContentsDelegate::DestroyWebContents => ResetManagedWebContents --- atom/browser/api/atom_api_web_contents.cc | 2 +- atom/browser/common_web_contents_delegate.cc | 2 +- atom/browser/common_web_contents_delegate.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 0f188d0d222e..a0100fd65c6e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -420,7 +420,7 @@ void WebContents::DestroyWebContents() { // This event is only for internal use, which is emitted when WebContents is // being destroyed. Emit("will-destroy"); - CommonWebContentsDelegate::DestroyWebContents(); + ResetManagedWebContents(); } bool WebContents::DidAddMessageToConsole(content::WebContents* source, diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 89c1e372558c..59ffc7dcbc08 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -183,7 +183,7 @@ void CommonWebContentsDelegate::SetOwnerWindow( web_contents->SetUserData(relay->key, relay); } -void CommonWebContentsDelegate::DestroyWebContents() { +void CommonWebContentsDelegate::ResetManagedWebContents() { web_contents_.reset(); } diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h index c08f8d246cee..27209411c72b 100644 --- a/atom/browser/common_web_contents_delegate.h +++ b/atom/browser/common_web_contents_delegate.h @@ -42,9 +42,6 @@ class CommonWebContentsDelegate void SetOwnerWindow(content::WebContents* web_contents, NativeWindow* owner_window); - // Destroy the managed InspectableWebContents object. - void DestroyWebContents(); - // Returns the WebContents managed by this delegate. content::WebContents* GetWebContents() const; @@ -114,6 +111,9 @@ class CommonWebContentsDelegate std::string* name, std::string* class_name) override; #endif + // Destroy the managed InspectableWebContents object. + void ResetManagedWebContents(); + private: // Callback for when DevToolsSaveToFile has completed. void OnDevToolsSaveToFile(const std::string& url); From 426563a8439adef225af5335a87901ca83902ce6 Mon Sep 17 00:00:00 2001 From: Hansen Zhang Date: Wed, 22 Mar 2017 11:52:25 -0400 Subject: [PATCH 014/337] #8881 - Display '&' in MenuItem label --- atom/browser/ui/views/submenu_button.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/atom/browser/ui/views/submenu_button.cc b/atom/browser/ui/views/submenu_button.cc index b398d84deec8..92f2a791cd09 100644 --- a/atom/browser/ui/views/submenu_button.cc +++ b/atom/browser/ui/views/submenu_button.cc @@ -16,21 +16,10 @@ namespace atom { -namespace { - -// Filter out the "&" in menu label. -base::string16 FilterAccelerator(const base::string16& label) { - base::string16 out; - base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out); - return out; -} - -} // namespace - SubmenuButton::SubmenuButton(const base::string16& title, views::MenuButtonListener* menu_button_listener, const SkColor& background_color) - : views::MenuButton(FilterAccelerator(title), + : views::MenuButton(gfx::RemoveAcceleratorChar(title, '&', NULL, NULL), menu_button_listener, false), accelerator_(0), show_underline_(false), From d22910f554f5527826deb02d925e55719787a444 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Wed, 22 Mar 2017 16:13:24 -0700 Subject: [PATCH 015/337] mention tilde --- docs/tutorial/electron-versioning.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/tutorial/electron-versioning.md b/docs/tutorial/electron-versioning.md index eccd9459f881..3f6c9ef90d43 100644 --- a/docs/tutorial/electron-versioning.md +++ b/docs/tutorial/electron-versioning.md @@ -48,4 +48,8 @@ The `--save-exact` flag will add `electron` to your `package.json` file without using a `^` or `~`, e.g. `1.6.2` instead of `^1.6.2`. This practice ensures that all upgrades of Electron are a manual operation made by you, the developer. +Alternatively, you can use the `~` prefix in your SemVer range, like `~1.6.2`. +This will lock your major and minor version, but allow new patch versions to +be installed. + [Semantic Versioning]: http://semver.org From 360d2b45f40b2312ad5d2907c3265204d70f564a Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Wed, 22 Mar 2017 22:59:11 -0700 Subject: [PATCH 016/337] document resources for tracking chromium development --- docs/README.md | 2 ++ docs/development/chromium-development.md | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 docs/development/chromium-development.md diff --git a/docs/README.md b/docs/README.md index 56a423f491de..2df14cc5c1ac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -103,3 +103,5 @@ an issue: * [Debug Instructions (Windows)](development/debug-instructions-windows.md) * [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md) * [Documentation Styleguide](styleguide.md) +* [Updating Chrome](development/updating-chrome.md) +* [Chromium Development](development/chromium-development.md) diff --git a/docs/development/chromium-development.md b/docs/development/chromium-development.md new file mode 100644 index 000000000000..a692714482e4 --- /dev/null +++ b/docs/development/chromium-development.md @@ -0,0 +1,12 @@ +# Chromium Development + +> A collection of resources for learning about Chromium and tracking its development + +- [chromiumdev](https://chromiumdev-slack.herokuapp.com) on Slack +- [@ChromiumDev](https://twitter.com/ChromiumDev) on Twitter +- [@googlechrome](https://twitter.com/googlechrome) on Twitter +- [Blog](https://blog.chromium.org) +- [Code Search](https://cs.chromium.org/) +- [Source Code](https://cs.chromium.org/chromium/src/) +- [Development Calendar and Release Info](https://www.chromium.org/developers/calendar) +- [Discussion Groups](http://www.chromium.org/developers/discussion-groups) From e1aebef57c00bd254b64c813e388eaeea53c6e5f Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:41:23 -0300 Subject: [PATCH 017/337] Make sandbox APIs more compatible with normal renderers - Expose remote shortcuts for the `fs`, `os` and `child_process` modules. - Expose the `url` and `timers` modules(the browserify versions) - Add `process.crash` and `process.platform` --- .../atom_sandboxed_renderer_client.cc | 2 ++ electron.gyp | 8 +++++- .../api/exports/child_process.js | 1 + lib/sandboxed_renderer/api/exports/fs.js | 1 + lib/sandboxed_renderer/api/exports/os.js | 1 + lib/sandboxed_renderer/init.js | 27 ++++++++++--------- 6 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 lib/sandboxed_renderer/api/exports/child_process.js create mode 100644 lib/sandboxed_renderer/api/exports/fs.js create mode 100644 lib/sandboxed_renderer/api/exports/os.js diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index 7d0dfde8c5ab..cb0dfd6db1fa 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -9,6 +9,7 @@ #include "atom_natives.h" // NOLINT: This file is generated with js2c #include "atom/common/api/api_messages.h" +#include "atom/common/api/atom_bindings.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/v8_value_converter.h" #include "atom/common/native_mate_converters/value_converter.h" @@ -85,6 +86,7 @@ void InitializeBindings(v8::Local binding, auto isolate = context->GetIsolate(); mate::Dictionary b(isolate, binding); b.SetMethod("get", GetBinding); + b.SetMethod("crash", AtomBindings::Crash); } class AtomSandboxedRenderFrameObserver : public content::RenderFrameObserver { diff --git a/electron.gyp b/electron.gyp index 15336a4e6bf3..78eed743cc36 100644 --- a/electron.gyp +++ b/electron.gyp @@ -441,7 +441,13 @@ 'sandbox_args': [ './lib/sandboxed_renderer/init.js', '-r', - './lib/sandboxed_renderer/api/exports/electron.js:electron' + './lib/sandboxed_renderer/api/exports/electron.js:electron', + '-r', + './lib/sandboxed_renderer/api/exports/fs.js:fs', + '-r', + './lib/sandboxed_renderer/api/exports/os.js:os', + '-r', + './lib/sandboxed_renderer/api/exports/child_process.js:child_process' ], 'isolated_args': [ 'lib/isolated_renderer/init.js', diff --git a/lib/sandboxed_renderer/api/exports/child_process.js b/lib/sandboxed_renderer/api/exports/child_process.js new file mode 100644 index 000000000000..ff39e96a120e --- /dev/null +++ b/lib/sandboxed_renderer/api/exports/child_process.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.require('child_process') diff --git a/lib/sandboxed_renderer/api/exports/fs.js b/lib/sandboxed_renderer/api/exports/fs.js new file mode 100644 index 000000000000..7342908e59a9 --- /dev/null +++ b/lib/sandboxed_renderer/api/exports/fs.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.require('fs') diff --git a/lib/sandboxed_renderer/api/exports/os.js b/lib/sandboxed_renderer/api/exports/os.js new file mode 100644 index 000000000000..ecd0d38a63a6 --- /dev/null +++ b/lib/sandboxed_renderer/api/exports/os.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.require('os') diff --git a/lib/sandboxed_renderer/init.js b/lib/sandboxed_renderer/init.js index 7f2d252865a8..46b74ee7b042 100644 --- a/lib/sandboxed_renderer/init.js +++ b/lib/sandboxed_renderer/init.js @@ -21,23 +21,23 @@ for (let prop of Object.keys(events.EventEmitter.prototype)) { Object.setPrototypeOf(process, events.EventEmitter.prototype) const electron = require('electron') +const fs = require('fs') const preloadModules = new Map([ - ['electron', electron] + ['child_process', require('child_process')], + ['electron', electron], + ['fs', fs], + ['os', require('os')], + ['url', require('url')], + ['timers', require('timers')] ]) -const extraModules = [ - 'fs' -] -for (let extraModule of extraModules) { - preloadModules.set(extraModule, electron.remote.require(extraModule)) -} - -// Fetch the preload script using the "fs" module proxy. -let preloadSrc = preloadModules.get('fs').readFileSync(preloadPath).toString() +const preloadSrc = fs.readFileSync(preloadPath).toString() // Pass different process object to the preload script(which should not have // access to things like `process.atomBinding`). const preloadProcess = new events.EventEmitter() +preloadProcess.platform = electron.remote.process.platform +preloadProcess.crash = () => binding.crash() process.on('exit', () => preloadProcess.emit('exit')) // This is the `require` function that will be visible to the preload script @@ -67,12 +67,13 @@ function preloadRequire (module) { // and any `require('electron')` calls in `preload.js` will work as expected // since browserify won't try to include `electron` in the bundle, falling back // to the `preloadRequire` function above. -let preloadWrapperSrc = `(function(require, process, Buffer, global) { +const preloadWrapperSrc = `(function(require, process, Buffer, global, setImmediate) { ${preloadSrc} })` // eval in window scope: // http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.2 const geval = eval -let preloadFn = geval(preloadWrapperSrc) -preloadFn(preloadRequire, preloadProcess, Buffer, global) +const preloadFn = geval(preloadWrapperSrc) +const {setImmediate} = require('timers') +preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate) From bf756e3c00c79f4f7886dd7ea4d3c27eb5fbfcb0 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:45:40 -0300 Subject: [PATCH 018/337] Prevent browserify from leaking the require function Define a "require" argument in the wrapper functions that runs browserify bundles, which will prevent browserify from leaking the require function. Note that this doesn't affect the isolated renderer script, only when `-r` flag is passed to browserify command it will export a require function. It is still added to isolated renderer script to prevent future mistakes(doesn't hurt defining a "require" local). --- atom/renderer/atom_renderer_client.cc | 2 +- atom/renderer/atom_sandboxed_renderer_client.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 8dd8e04e1ac2..eb1bdccbe34c 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -115,7 +115,7 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { // an argument. std::string bundle(node::isolated_bundle_data, node::isolated_bundle_data + sizeof(node::isolated_bundle_data)); - std::string wrapper = "(function (binding) {\n" + bundle + "\n})"; + std::string wrapper = "(function (binding, require) {\n" + bundle + "\n})"; auto script = v8::Script::Compile( mate::ConvertToV8(isolate, wrapper)->ToString()); auto func = v8::Handle::Cast( diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index cb0dfd6db1fa..bf9ea6fd9ef8 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -206,7 +206,7 @@ void AtomSandboxedRendererClient::DidCreateScriptContext( std::string preload_bundle_native(node::preload_bundle_data, node::preload_bundle_data + sizeof(node::preload_bundle_data)); std::stringstream ss; - ss << "(function(binding, preloadPath) {\n"; + ss << "(function(binding, preloadPath, require) {\n"; ss << preload_bundle_native << "\n"; ss << "})"; std::string preload_wrapper = ss.str(); From 3a97cfc359e009caf1a42b00d7a7df27439849a6 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:47:18 -0300 Subject: [PATCH 019/337] Expose `crashReporter` to sandbox --- lib/sandboxed_renderer/api/exports/electron.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/sandboxed_renderer/api/exports/electron.js b/lib/sandboxed_renderer/api/exports/electron.js index 2a1d34123116..02f23be3966d 100644 --- a/lib/sandboxed_renderer/api/exports/electron.js +++ b/lib/sandboxed_renderer/api/exports/electron.js @@ -11,6 +11,12 @@ Object.defineProperties(exports, { return require('../../../renderer/api/remote') } }, + crashReporter: { + enumerable: true, + get: function () { + return require('../../../common/api/crash-reporter') + } + }, CallbacksRegistry: { get: function () { return require('../../../common/api/callbacks-registry') From 5ee6205c0a5eac585d10d878b8200e40f7c79168 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:48:36 -0300 Subject: [PATCH 020/337] Run the crash reporter specs with sandbox option. - Create a function that accepts BrowserWindow options and generates a suite that contains the renderer-specific tests. - Run the function twice to execute the tests with and without sandbox option. --- spec/api-crash-reporter-spec.js | 23 +++++++++++++++++------ spec/fixtures/module/preload-sandbox.js | 2 ++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index c269cfe1324b..41910d6228a8 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,15 +11,20 @@ const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') describe('crashReporter module', function () { + if (process.mas) { + return + } var fixtures = path.resolve(__dirname, 'fixtures') + const generateSpecs = (description, browserWindowOpts) => { + describe(description, function () { var w = null var originalTempDirectory = null var tempDirectory = null beforeEach(function () { - w = new BrowserWindow({ + w = new BrowserWindow(Object.assign({ show: false - }) + }, browserWindowOpts)) tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') originalTempDirectory = app.getPath('temp') app.setPath('temp', tempDirectory) @@ -30,10 +35,6 @@ describe('crashReporter module', function () { return closeWindow(w).then(function () { w = null }) }) - if (process.mas) { - return - } - it('should send minidump when renderer crashes', function (done) { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() @@ -91,6 +92,16 @@ describe('crashReporter module', function () { done: done }) }) + }) + } + + generateSpecs('without sandbox', {}) + generateSpecs('with sandbox ', { + webPreferences: { + sandbox: true, + preload: path.join(fixtures, 'module', 'preload-sandbox.js') + } + }) describe('.start(options)', function () { it('requires that the companyName and submitURL options be specified', function () { diff --git a/spec/fixtures/module/preload-sandbox.js b/spec/fixtures/module/preload-sandbox.js index 39a8704e1329..15d6e06a862c 100644 --- a/spec/fixtures/module/preload-sandbox.js +++ b/spec/fixtures/module/preload-sandbox.js @@ -1,6 +1,8 @@ (function () { + const {setImmediate} = require('timers') const {ipcRenderer} = require('electron') window.ipcRenderer = ipcRenderer + window.setImmediate = setImmediate if (location.protocol === 'file:') { window.test = 'preload' window.require = require From a5eef516a793b01f3eed2e8586fe7e459142ee42 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 21 Mar 2017 10:53:17 -0300 Subject: [PATCH 021/337] Fix indent in api-crash-reporter-spec.js --- spec/api-crash-reporter-spec.js | 132 ++++++++++++++++---------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 41910d6228a8..dc4b98150160 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -16,83 +16,83 @@ describe('crashReporter module', function () { } var fixtures = path.resolve(__dirname, 'fixtures') const generateSpecs = (description, browserWindowOpts) => { - describe(description, function () { - var w = null - var originalTempDirectory = null - var tempDirectory = null + describe(description, function () { + var w = null + var originalTempDirectory = null + var tempDirectory = null - beforeEach(function () { - w = new BrowserWindow(Object.assign({ - show: false - }, browserWindowOpts)) - tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') - originalTempDirectory = app.getPath('temp') - app.setPath('temp', tempDirectory) - }) + beforeEach(function () { + w = new BrowserWindow(Object.assign({ + show: false + }, browserWindowOpts)) + tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') + originalTempDirectory = app.getPath('temp') + app.setPath('temp', tempDirectory) + }) - afterEach(function () { - app.setPath('temp', originalTempDirectory) - return closeWindow(w).then(function () { w = null }) - }) + afterEach(function () { + app.setPath('temp', originalTempDirectory) + return closeWindow(w).then(function () { w = null }) + }) - it('should send minidump when renderer crashes', function (done) { - if (process.env.APPVEYOR === 'True') return done() - if (process.env.TRAVIS === 'true') return done() + it('should send minidump when renderer crashes', function (done) { + if (process.env.APPVEYOR === 'True') return done() + if (process.env.TRAVIS === 'true') return done() - this.timeout(120000) + this.timeout(120000) - startServer({ - callback (port) { - const crashUrl = url.format({ - protocol: 'file', - pathname: path.join(fixtures, 'api', 'crash.html'), - search: '?port=' + port + startServer({ + callback (port) { + const crashUrl = url.format({ + protocol: 'file', + pathname: path.join(fixtures, 'api', 'crash.html'), + search: '?port=' + port + }) + w.loadURL(crashUrl) + }, + processType: 'renderer', + done: done }) - w.loadURL(crashUrl) - }, - processType: 'renderer', - done: done - }) - }) + }) - it('should send minidump when node processes crash', function (done) { - if (process.env.APPVEYOR === 'True') return done() - if (process.env.TRAVIS === 'true') return done() + it('should send minidump when node processes crash', function (done) { + if (process.env.APPVEYOR === 'True') return done() + if (process.env.TRAVIS === 'true') return done() - this.timeout(120000) + this.timeout(120000) - startServer({ - callback (port) { - const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`) - const version = app.getVersion() - const crashPath = path.join(fixtures, 'module', 'crash.js') - childProcess.fork(crashPath, [port, version, crashesDir], {silent: true}) - }, - processType: 'browser', - done: done - }) - }) - - it('should send minidump with updated extra parameters', function (done) { - if (process.env.APPVEYOR === 'True') return done() - if (process.env.TRAVIS === 'true') return done() - - this.timeout(10000) - - startServer({ - callback (port) { - const crashUrl = url.format({ - protocol: 'file', - pathname: path.join(fixtures, 'api', 'crash-restart.html'), - search: '?port=' + port + startServer({ + callback (port) { + const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`) + const version = app.getVersion() + const crashPath = path.join(fixtures, 'module', 'crash.js') + childProcess.fork(crashPath, [port, version, crashesDir], {silent: true}) + }, + processType: 'browser', + done: done }) - w.loadURL(crashUrl) - }, - processType: 'renderer', - done: done + }) + + it('should send minidump with updated extra parameters', function (done) { + if (process.env.APPVEYOR === 'True') return done() + if (process.env.TRAVIS === 'true') return done() + + this.timeout(10000) + + startServer({ + callback (port) { + const crashUrl = url.format({ + protocol: 'file', + pathname: path.join(fixtures, 'api', 'crash-restart.html'), + search: '?port=' + port + }) + w.loadURL(crashUrl) + }, + processType: 'renderer', + done: done + }) + }) }) - }) - }) } generateSpecs('without sandbox', {}) From 93b444eef972968353e2bce08dd2b9e4338177cf Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Thu, 23 Mar 2017 23:36:05 +0530 Subject: [PATCH 022/337] net: catch source stream creation failure for content encoding --- atom/browser/net/atom_url_request.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/atom/browser/net/atom_url_request.cc b/atom/browser/net/atom_url_request.cc index 2c7bb61da0b1..83d2548a9c29 100644 --- a/atom/browser/net/atom_url_request.cc +++ b/atom/browser/net/atom_url_request.cc @@ -348,6 +348,14 @@ void AtomURLRequest::OnReadCompleted(net::URLRequest* request, int bytes_read) { DCHECK_EQ(request, request_.get()); const auto status = request_->status(); + if (status.error() == bytes_read && + bytes_read == net::ERR_CONTENT_DECODING_INIT_FAILED) { + // When the request job is unable to create a source stream for the + // content encoding, we fail the request. + DoCancelWithError(net::ErrorToString(net::ERR_CONTENT_DECODING_INIT_FAILED), + true); + return; + } bool response_error = false; bool data_ended = false; From a92f639b64cb8d16e91228da54e449a4dc0a316d Mon Sep 17 00:00:00 2001 From: Cory Reed Date: Thu, 23 Mar 2017 11:55:46 -0700 Subject: [PATCH 023/337] :memo: Add note regarding dynamic addition/removal of menu items. Closes #8928. [ci skip] --- docs/api/menu.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/menu.md b/docs/api/menu.md index cd6817625a35..ad846fb84d8e 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -25,6 +25,10 @@ will be set as each window's top menu. Returns `Menu` - The application menu, if set, or `null`, if not set. +**Note:** The returned `Menu` instance doesn't support dynamic addition or +removal of menu items. [Instance properties](#instance-properties) can still +be dynamically modified. + #### `Menu.sendActionToFirstResponder(action)` _macOS_ * `action` String From 437f1192d9e570d98ff016d729eda21533ffb8ed Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 9 Mar 2017 09:23:03 -0300 Subject: [PATCH 024/337] Add initial documentation for `sandbox` option. --- docs/api/browser-window.md | 5 + docs/api/sandbox-option.md | 186 +++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 docs/api/sandbox-option.md diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 2456c73e8033..13d823c231c3 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -225,6 +225,11 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope. See example [here](process.md#event-loaded). + * `sandbox` Boolean (optional) - If set, this will sandbox the renderer + associated with the window, making it compatible with chromium sandbox and + disabling the node.js engine. This is not the same as the + `nodeIntegration` option and the APIs available to the preload script are + more limited. Read more about the option [here](sandbox-option.md). * `session` [Session](session.md#class-session) (optional) - Sets the session used by the page. Instead of passing the Session object directly, you can also choose to use the `partition` option instead, which accepts a partition string. When diff --git a/docs/api/sandbox-option.md b/docs/api/sandbox-option.md new file mode 100644 index 000000000000..454a8ad05cca --- /dev/null +++ b/docs/api/sandbox-option.md @@ -0,0 +1,186 @@ +# `sandbox` Option + +> Create a browser window with renderer that can run inside chromium OS sandbox. + +One of chromium key security features is that all blink rendering/javascript +code is confined in a sandbox. This sandbox uses OS-specific features to ensure +that exploits in the renderer process cannot harm the system. + +In other words, when the sandbox is enabled, the renderers can only make changes +to the system by delegating tasks to the main process via IPC. +[Here's](https://www.chromium.org/developers/design-documents/sandbox) more +information about the sandbox. + +Since a major feature in electron is the ability to run node.js in the +renderer process(making it easier to develop desktop applications using only web +technologies), the sandbox has to disabled by electron. One of the reasons is +that most node.js APIs require system access. `require()` for example, is not +possible without file system permissions, which are unavailable in a sandboxed +environment. + +Usually this is not a problem for desktop applications since the code is always +trusted, but it makes electron less secure than chromium for displaying +untrusted web content. For applications that require more security, the +`sandbox` flag will force electron to spawn a classic chromium renderer that is +compatible with the sandbox. + +A sandboxed renderer doesn't have a node.js environment running and doesn't +expose javascript APIs to client code. The only exception is the preload script, +which has access to a subset of electron renderer API. + +Another difference is that sandboxed renderers don't modify any of the default +javascript APIs. Consequently, some APIs such as `window.open` will work as they +do in chromium(no `BrowserWindowProxy`). + +## Example + +Create a sandboxed window, simply pass `sandbox: true` to `webPreferences`: + +```js +let win +app.on('ready', () => { + win = new BrowserWindow({ + webPreferences: { + sandbox: true + } + }) + w.loadURL('http://google.com') +}) +``` + +This alone won't enable the OS-enforced sandbox. To use it, the +`--enable-sandbox` command-line argument must be passed to electron, which will +force `sandbox: true` to all BrowserWindow instances. + +```js +let win +app.on('ready', () => { + // no need to pass `sandbox: true` since `--enable-sandbox` was enabled. + win = new BrowserWindow() + w.loadURL('http://google.com') +}) +``` + +Note that it is not enough to call +`app.commandLine.appendSwitch('--enable-sandbox')`, as electron/node startup +code runs after it is possible to make changes to chromium sandbox settings. The +switch must be passed to electron command-line: + +``` +electron --enable-sandbox app.js +``` + +It is not possible to have the OS sandbox active only for some renderers, if +`--enable-sandbox` is enabled, normal electron windows cannot be created. + +If you need to mix sandboxed and non-sandboxed renderers in one application, +simply omit the `--enable-sandbox` argument. Without this argument, windows +created with `sandbox: true` will still have node.js disabled and communicate +only via IPC, which by itself is already a gain from security POV. + +## Preload + +An app can make customizations to sandboxed renderers using a preload script. +Here's an example: + +```js +let win +app.on('ready', () => { + win = new BrowserWindow({ + webPreferences: { + sandbox: true, + preload: 'preload.js' + } + }) + w.loadURL('http://google.com') +}) +``` + +and preload.js: + +```js +// This file is loaded whenever a javascript context is created. It runs in a +// private scope that can access a subset of electron renderer APIs. We must be +// careful to not leak any objects into the global scope! +const fs = require('fs') +const {ipcRenderer} = require('electron') + +// read a configuration file using the `fs` module +const buf = fs.readFileSync('allowed-popup-urls.json') +const allowedUrls = JSON.parse(buf.toString('utf8')) + +const defaultWindowOpen = window.open + +function customWindowOpen (url, ...args) { + if (allowedUrls.indexOf(url) === -1) { + ipcRenderer.sendSync('blocked-popup-notification', location.origin, url) + return null + } + return defaultWindowOpen(url, ...args) +} + +window.open = customWindowOpen +``` + +Important things to notice in the preload script: + +- Even though the sandboxed renderer doesn't have node.js running, it still has + access to a limited node-like environment:`Buffer`, `process`, `setImmediate` + and `require` are available. +- The preload can indirectly access all APIs from the main process through the + `remote` and `ipcRenderer` modules. This is how `fs`(used above) and other + modules are implemented: They are proxies to remote counterparts in the main + process. +- The preload must be contained in a single script, but it is possible to have + complex preload code composed with multiple modules by using a tool like + browserify, as explained below. In fact, browserify is already used by + electron to provide a node-like environment to the preload script. + +To create a browserify bundle and use it as a preload script, something like +the following should be used: + + browserify preload/index.js \ + -x electron \ + -x fs \ + --insert-global-vars=__filename,__dirname -o preload.js + +The `-x` flag should be used with any required module that is already exposed in +the preload scope, and tells browserify to use the enclosing `require` function +for it. `--insert-global-vars` will ensure that `process`,`Buffer` and +`setImmediate` are also taken from the enclosing scope(normally browserify +injects code for those). + +Currently the `require` function provided in the preload scope exposes the +following modules: + +- `child_process` +- `electron`(crashReporter, remote and ipcRenderer) +- `fs` +- `os` +- `timers` +- `url` + +More may be added as needed to expose more electron APIs in the sandbox, but any +module in the main process can already be used through +`electron.remote.require`. + +## Status + +Please use the `sandbox` option with care, as it still is an experimental +feature. We are still not aware of the security implications of exposing some +electron renderer APIs to the preload script, but here are some things to +consider before rendering untrusted content: + +- A preload script can accidentaly leak privileged APIs to untrusted code. +- Some bug in V8 engine may allow malicious code to access the renderer preload + APIs, effectively granting full access to the system through the `remote` + module. + +Since renderering untrusted content in electron is still uncharted territory, +the APIs exposed to the sandbox preload script should be considered more +unstable than the rest of electron APIs, and may have breaking changes to fix +security issues. + +One planned enhancement that should greatly increase security is to block IPC +messages from sandboxed renderers by default, allowing the main process +explicitly define a set of messages the renderer is allowed to send. From 9e471d8f1cce79626491cea4be21be3b30cd6c2e Mon Sep 17 00:00:00 2001 From: mst128256 Date: Fri, 24 Mar 2017 12:14:08 +0100 Subject: [PATCH 025/337] Added specs --- docs/api/menu-item.md | 4 +-- lib/browser/api/menu-item-roles.js | 4 +-- spec/api-menu-spec.js | 46 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 76fcae1129f3..dc403ea8f7be 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -64,8 +64,8 @@ The `role` property can have following values: * `zoomin` - Zoom in the focused page by 10% * `zoomout` - Zoom out the focused page by 10% -* `menuEdit` - Whole default "Edit" menu (Undo,Copy, etc.) -* `menuWindow` - Whole default "Window" menu (Minimize, Close, etc.) +* `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.) +* `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.) On macOS `role` can also have following additional values: diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 8919b8d10ec7..b843bb82e8b6 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -156,7 +156,7 @@ const roles = { } }, // submenu Edit (should fit both Mac & Windows) - menuEdit: { + editMenu: { label: 'Edit', submenu: [ { @@ -197,7 +197,7 @@ const roles = { }, // submenu Window should be used for Mac only - menuWindow: { + windowMenu: { label: 'Window', submenu: [ { diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index 176f1eafae52..cfe5e3934821 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -455,6 +455,52 @@ describe('menu module', function () { }) }) + describe('MenuItem editMenu', function() { + it('includes a default submenu layout when submenu is empty', function() { + var item = new MenuItem({role: 'editMenu'}) + assert.equal(item.label, 'Edit') + assert.equal(item.submenu.items[0].role, 'undo') + assert.equal(item.submenu.items[1].role, 'redo') + assert.equal(item.submenu.items[2].type, 'separator') + assert.equal(item.submenu.items[3].role, 'cut') + assert.equal(item.submenu.items[4].role, 'copy') + assert.equal(item.submenu.items[5].role, 'paste') + if (process.platform == 'darwin') { + assert.equal(item.submenu.items[6].role, 'pasteandmatchstyle') + assert.equal(item.submenu.items[7].role, 'delete') + assert.equal(item.submenu.items[8].role, 'selectall') + } + if (process.platform == 'win32') { + assert.equal(item.submenu.items[6].role, 'delete') + assert.equal(item.submenu.items[7].type, 'separator') + assert.equal(item.submenu.items[8].role, 'selectall') + } + }) + it('overrides default layout when submenu is specified', function() { + var item = new MenuItem({role: 'editMenu', submenu: [{ role: 'close'}]}) + assert.equal(item.label, 'Edit') + assert.equal(item.submenu.items[0].role, 'close') + }) + }) + + describe('MenuItem windowMenu', function() { + it('includes a default submenu layout when submenu is empty', function() { + var item = new MenuItem({role: 'windowMenu'}) + assert.equal(item.label, 'Window') + assert.equal(item.submenu.items[0].role, 'minimize') + assert.equal(item.submenu.items[1].role, 'close') + if (process.platform == 'darwin') { + assert.equal(item.submenu.items[2].type, 'separator') + assert.equal(item.submenu.items[3].role, 'front') + } + }) + it('overrides default layout when submenu is specified', function() { + var item = new MenuItem({role: 'windowMenu', submenu: [{ role: 'copy'}]}) + assert.equal(item.label, 'Window') + assert.equal(item.submenu.items[0].role, 'copy') + }) + }) + describe('MenuItem with custom properties in constructor', function () { it('preserves the custom properties', function () { var template = [{ From 6a7b4feb35ad46b71aea0ffd74c91d248660269e Mon Sep 17 00:00:00 2001 From: mst128256 Date: Fri, 24 Mar 2017 12:31:49 +0100 Subject: [PATCH 026/337] Fixed for linting --- spec/api-menu-spec.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index cfe5e3934821..0d809789d71e 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -455,8 +455,8 @@ describe('menu module', function () { }) }) - describe('MenuItem editMenu', function() { - it('includes a default submenu layout when submenu is empty', function() { + describe('MenuItem editMenu', function () { + it('includes a default submenu layout when submenu is empty', function () { var item = new MenuItem({role: 'editMenu'}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'undo') @@ -465,37 +465,37 @@ describe('menu module', function () { assert.equal(item.submenu.items[3].role, 'cut') assert.equal(item.submenu.items[4].role, 'copy') assert.equal(item.submenu.items[5].role, 'paste') - if (process.platform == 'darwin') { + if (process.platform === 'darwin') { assert.equal(item.submenu.items[6].role, 'pasteandmatchstyle') assert.equal(item.submenu.items[7].role, 'delete') assert.equal(item.submenu.items[8].role, 'selectall') } - if (process.platform == 'win32') { + if (process.platform === 'win32') { assert.equal(item.submenu.items[6].role, 'delete') assert.equal(item.submenu.items[7].type, 'separator') assert.equal(item.submenu.items[8].role, 'selectall') } }) - it('overrides default layout when submenu is specified', function() { - var item = new MenuItem({role: 'editMenu', submenu: [{ role: 'close'}]}) + it('overrides default layout when submenu is specified', function () { + var item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'close') }) }) - describe('MenuItem windowMenu', function() { - it('includes a default submenu layout when submenu is empty', function() { + describe('MenuItem windowMenu', function () { + it('includes a default submenu layout when submenu is empty', function () { var item = new MenuItem({role: 'windowMenu'}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'minimize') assert.equal(item.submenu.items[1].role, 'close') - if (process.platform == 'darwin') { + if (process.platform === 'darwin') { assert.equal(item.submenu.items[2].type, 'separator') assert.equal(item.submenu.items[3].role, 'front') } }) - it('overrides default layout when submenu is specified', function() { - var item = new MenuItem({role: 'windowMenu', submenu: [{ role: 'copy'}]}) + it('overrides default layout when submenu is specified', function () { + var item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'copy') }) From 095df457b23a0308ba14c08c0de6e5da6c458008 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Fri, 24 Mar 2017 11:14:43 -0700 Subject: [PATCH 027/337] fix docs for thumbnailSize --- docs/api/desktop-capturer.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 85755dc03ef9..f552753445d4 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -60,8 +60,9 @@ The `desktopCapturer` module has the following methods: * `options` Object * `types` String[] - An array of Strings that lists the types of desktop sources to be captured, available types are `screen` and `window`. - * `thumbnailSize` Object (optional) - The suggested size that the media source - thumbnail should be scaled to, defaults to `{width: 150, height: 150}`. + * `thumbnailSize` Object (optional) - The size that the media source thumbnail should be scaled to. + * `width` Integer - Default is `150` + * `height` Integer - Default is `150` * `callback` Function * `error` Error * `sources` [DesktopCapturerSource[]](structures/desktop-capturer-source.md) From d95114016dea559872a06fb2fcedfaa564f66b63 Mon Sep 17 00:00:00 2001 From: Hari Juturu Date: Fri, 24 Mar 2017 15:40:23 -0700 Subject: [PATCH 028/337] V8 dev resources (#9008) * Adding V8 documentation links * Removing extra space * use electron markdown conventions * cross-link v8 and chromium dev docs * fix v8 link --- docs/README.md | 1 + docs/development/chromium-development.md | 2 ++ docs/development/v8-development.md | 11 +++++++++++ 3 files changed, 14 insertions(+) create mode 100644 docs/development/v8-development.md diff --git a/docs/README.md b/docs/README.md index 2df14cc5c1ac..24b23f92a760 100644 --- a/docs/README.md +++ b/docs/README.md @@ -105,3 +105,4 @@ an issue: * [Documentation Styleguide](styleguide.md) * [Updating Chrome](development/updating-chrome.md) * [Chromium Development](development/chromium-development.md) +* [V8 Development](development/v8-development.md) diff --git a/docs/development/chromium-development.md b/docs/development/chromium-development.md index a692714482e4..23506ae918fa 100644 --- a/docs/development/chromium-development.md +++ b/docs/development/chromium-development.md @@ -10,3 +10,5 @@ - [Source Code](https://cs.chromium.org/chromium/src/) - [Development Calendar and Release Info](https://www.chromium.org/developers/calendar) - [Discussion Groups](http://www.chromium.org/developers/discussion-groups) + +See also [V8 Development](v8-development.md) diff --git a/docs/development/v8-development.md b/docs/development/v8-development.md new file mode 100644 index 000000000000..76d13299ca7e --- /dev/null +++ b/docs/development/v8-development.md @@ -0,0 +1,11 @@ +# V8 Development + +> A collection of resources for learning and using V8 + +* [V8 Tracing](https://github.com/v8/v8/wiki/Tracing-V8) +* [V8 Profiler](https://github.com/v8/v8/wiki/V8-Profiler) - Profiler combinations which are useful for profiling: `--prof`, `--trace-ic`, `--trace-opt`, `--trace-deopt`, `--print-bytecode`, `--print-opt-code` +* [V8 Interpreter Design](https://docs.google.com/document/d/11T2CRex9hXxoJwbYqVQ32yIPMh0uouUZLdyrtmMoL44/edit?ts=56f27d9d#heading=h.6jz9dj3bnr8t) +* [Optimizing compiler](https://github.com/v8/v8/wiki/TurboFan) +* [V8 GDB Debugging](https://github.com/v8/v8/wiki/GDB-JIT-Interface) + +See also [Chromium Development](chromium-development.md) From aa5c778ca23182085c331e098175c5c13ac3dec9 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 12:37:07 +1100 Subject: [PATCH 029/337] Generic doc fixes --- docs/api/client-request.md | 2 ++ docs/api/touch-bar-scrubber.md | 4 ++-- docs/api/touch-bar-segmented-control.md | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 0b722f2f09d3..71ade14a8ef3 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -65,6 +65,8 @@ Returns: * `port` Integer * `realm` String * `callback` Function + * `username` String + * `password` String Emitted when an authenticating proxy is asking for user credentials. diff --git a/docs/api/touch-bar-scrubber.md b/docs/api/touch-bar-scrubber.md index 370c98beed1d..31f65d8770cb 100644 --- a/docs/api/touch-bar-scrubber.md +++ b/docs/api/touch-bar-scrubber.md @@ -9,9 +9,9 @@ Process: [Main](../tutorial/quick-start.md#main-process) * `options` Object * `items` [ScrubberItem[]](structures/scrubber-item.md) - An array of items to place in this scrubber * `select` Function - Called when the user taps an item that was not the last tapped item - * `selectedIndex` - The index of the item the user selected + * `selectedIndex` Integer - The index of the item the user selected * `highlight` Function - Called when the user taps any item - * `highlightedIndex` - The index of the item the user touched + * `highlightedIndex` Integer - The index of the item the user touched * `selectedStyle` String - Selected item style. Defaults to `null`. * `overlayStyle` String - Selected overlay item style. Defaults to `null`. * `showArrowButtons` Boolean - Defaults to `false`. diff --git a/docs/api/touch-bar-segmented-control.md b/docs/api/touch-bar-segmented-control.md index 5c8a0de7eba1..4ea037057670 100644 --- a/docs/api/touch-bar-segmented-control.md +++ b/docs/api/touch-bar-segmented-control.md @@ -19,7 +19,7 @@ Process: [Main](../tutorial/quick-start.md#main-process) * `segments` [SegmentedControlSegment[]](structures/segmented-control-segment.md) - An array of segments to place in this control * `selectedIndex` Integer (Optional) - The index of the currently selected segment, will update automatically with user interaction * `change` Function - Called when the user selects a new segment - * `selectedIndex` - The index of the segment the user selected + * `selectedIndex` Integer - The index of the segment the user selected ### Instance Properties From a80148aa299711b81cd587c256261309e7b06de7 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 14:51:23 +1100 Subject: [PATCH 030/337] Add missing property types on the process docs --- docs/api/process.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/api/process.md b/docs/api/process.md index 951abc7df1af..84320ca98bb0 100644 --- a/docs/api/process.md +++ b/docs/api/process.md @@ -32,38 +32,38 @@ process.once('loaded', () => { ### `process.noAsar` -Setting this to `true` can disable the support for `asar` archives in Node's -built-in modules. +A `Boolean` that controls ASAR support inside your application. Setting this to `true` +will disable the support for `asar` archives in Node's built-in modules. ### `process.type` -Current process's type, can be `"browser"` (i.e. main process) or `"renderer"`. +A `String` representing the current process's type, can be `"browser"` (i.e. main process) or `"renderer"`. ### `process.versions.electron` -Electron's version string. +A `String` representing Electron's version string. ### `process.versions.chrome` -Chrome's version string. +A `String` representing Chrome's version string. ### `process.resourcesPath` -Path to the resources directory. +A `String` representing the path to the resources directory. ### `process.mas` -For Mac App Store build, this property is `true`, for other builds it is +A `Boolean`. For Mac App Store build, this property is `true`, for other builds it is `undefined`. ### `process.windowsStore` -If the app is running as a Windows Store app (appx), this property is `true`, +A `Boolean`. If the app is running as a Windows Store app (appx), this property is `true`, for otherwise it is `undefined`. ### `process.defaultApp` -When app is started by being passed as parameter to the default app, this +A `Boolean`. When app is started by being passed as parameter to the default app, this property is `true` in the main process, otherwise it is `undefined`. ## Methods From b62f1fd0229343cf0fdce6ca2ca46de93d78073f Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 14:59:48 +1100 Subject: [PATCH 031/337] Add missing return type on executeJavaScript --- docs/api/web-frame.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 25ae3480f938..abe8e4d91626 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -136,6 +136,9 @@ Inserts `text` to the focused element. * `callback` Function (optional) - Called after script has been executed. * `result` Any +Returns `Promise` - A promise that resolves with the result of the executed code +or is rejected if the result of the code is a rejected promise. + Evaluates `code` in page. In the browser window some HTML APIs like `requestFullScreen` can only be From 168c47bf105d0f3081612b7f78cea12866bd2a2a Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 25 Mar 2017 18:27:43 +1100 Subject: [PATCH 032/337] Update web-contents.md --- docs/api/web-contents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index b91f6d9edef5..72dc4b0f7454 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1247,7 +1247,7 @@ one through the `'paint'` event. #### `contents.getWebRTCIPHandlingPolicy()` -* Returns `String` - Returns the WebRTC IP Handling Policy. +Returns `String` - Returns the WebRTC IP Handling Policy. #### `contents.setWebRTCIPHandlingPolicy(policy)` From 4e1b237649ab47be976d7df6598f63f32b207c19 Mon Sep 17 00:00:00 2001 From: owwo Date: Sun, 26 Mar 2017 18:42:07 -0500 Subject: [PATCH 033/337] Fix translation error --- docs-translations/zh-CN/tutorial/electron-versioning.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs-translations/zh-CN/tutorial/electron-versioning.md b/docs-translations/zh-CN/tutorial/electron-versioning.md index 18bd3735404f..7027347b3927 100644 --- a/docs-translations/zh-CN/tutorial/electron-versioning.md +++ b/docs-translations/zh-CN/tutorial/electron-versioning.md @@ -5,7 +5,7 @@ 版本号使用参照以下规则: * 主要版本: 适用于 Electron API 的突破性变更 - 如果您从 `0.37.0` 升级到 `1.0.0`, 您将需要升级您的应用程序。 -* 次要版本: 适用于 Chrome 主要版本 和 Node 次要版本升级; 或重大的 Electron 变动 - 如果您从 `0.37.0` 升级到 `1.0.0`, 您的应用程序仍然可以正常运行, 但你可能需要解决一些小幅的变动。 -* 补丁版本: 适用于新功能的添加和 bug 修复 - 如果您从 `0.37.0` 升级到 `1.0.0`, 你的应用程序仍然像之前一样正常运行。 +* 次要版本: 适用于 Chrome 主要版本 和 Node 次要版本升级; 或重大的 Electron 变动 - 如果您从 `1.0.0` 升级到 `1.1.0`, 您的应用程序仍然可以正常运行, 但你可能需要解决一些小幅的变动。 +* 补丁版本: 适用于新功能的添加和 bug 修复 - 如果您从 `1.0.0` 升级到 `1.0.1`, 你的应用程序仍然像之前一样正常运行。 如果你使用 `electron` 或 `electron-prebuilt`,我们建议您设置固定的版本号(如 1.1.0 而不是 ^1.1.0),以确保Electron的所有升级都是由您(开发人员)进行的手动操作。 From dccfadd2bce9d8231787c201d096372d0580dac4 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Mon, 27 Mar 2017 11:16:05 +0800 Subject: [PATCH 034/337] add getFileIcon method --- docs-translations/zh-CN/api/app.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs-translations/zh-CN/api/app.md b/docs-translations/zh-CN/api/app.md index 99429119f3f6..04680d548ba5 100644 --- a/docs-translations/zh-CN/api/app.md +++ b/docs-translations/zh-CN/api/app.md @@ -356,6 +356,27 @@ Windows, 使应用的第一个窗口获取焦点. * `pictures` 用户图片目录的路径. * `videos` 用户视频目录的路径. +### `app.getFileIcon(path[, options], callback)` +* `path` String +* `options` Object(可选) + * `size` String + * `small` - 16x16 + * `normal` - 32x32 + * `large` - Linux 为 48x48, Windows 为 32x32, Mac 系统不支持 +* `callback` Function + * `error` Error + * `icon` [NativeImage](native-image.md) + + +获取文件关联的图标. + +在 Windows 系统中, 有2种图标类型: + +- 图标与某些文件扩展名关联, 比如 `.mp3`, `.png`, 等等. +- 图标在文件内部, 比如 `.exe`, `.dll`, `.ico`. + +在 Linux 和 Mac 系统中, 图标取决于应用程序相关文件的 mime 类型 + ### `app.setPath(name, path)` * `name` String From 9a4783bf34ba07a3f181418eb7c3766aad3bb190 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 09:15:40 -0700 Subject: [PATCH 035/337] Disable flaky post navigation spec on AppVeyor --- spec/webview-spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 2f5cb8068c4d..4ea9369d666f 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -121,6 +121,9 @@ describe(' tag', function () { }) it('loads node symbols after POST navigation when set', function (done) { + // FIXME Figure out why this is timing out on AppVeyor + if (process.env.APPVEYOR === 'True') return done() + webview.addEventListener('console-message', function (e) { assert.equal(e.message, 'function object object') done() From 870dcb9071fe9f5a883dfd2c0f04e77d1d7bb90b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 10:14:38 -0700 Subject: [PATCH 036/337] Remove old sandbox option in list and mark as experimental --- docs/api/browser-window.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 13d823c231c3..182e798158b1 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -226,10 +226,12 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. Node global symbols back to the global scope. See example [here](process.md#event-loaded). * `sandbox` Boolean (optional) - If set, this will sandbox the renderer - associated with the window, making it compatible with chromium sandbox and - disabling the node.js engine. This is not the same as the - `nodeIntegration` option and the APIs available to the preload script are - more limited. Read more about the option [here](sandbox-option.md). + associated with the window, making it compatible with the Chromium + OS-level sandbox and disabling the Node.js engine. This is not the same as + the `nodeIntegration` option and the APIs available to the preload script + are more limited. Read more about the option [here](sandbox-option.md). + **Note:** This option is currently experimental and may change or be + removed in future Electron releases. * `session` [Session](session.md#class-session) (optional) - Sets the session used by the page. Instead of passing the Session object directly, you can also choose to use the `partition` option instead, which accepts a partition string. When @@ -287,7 +289,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. window. Defaults to `false`. See the [offscreen rendering tutorial](../tutorial/offscreen-rendering.md) for more details. - * `sandbox` Boolean (optional) - Whether to enable Chromium OS-level sandbox. * `contextIsolation` Boolean (optional) - Whether to run Electron APIs and the specified `preload` script in a separate JavaScript context. Defaults to `false`. The context that the `preload` script runs in will still From f24baffc79b770cbbee25327650f17d228ad1cc6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 10:21:01 -0700 Subject: [PATCH 037/337] Expect count to be 0 --- spec/api-session-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index f5a4cbf56c2a..c34cdfdab0ff 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -226,7 +226,7 @@ describe('session module', function () { it('clears localstorage data', function (done) { ipcMain.on('count', function (event, count) { ipcMain.removeAllListeners('count') - assert(!count) + assert.equal(count, 0) done() }) w.loadURL('file://' + path.join(fixtures, 'api', 'localstorage.html')) From 3028bffa736f0e22b1fd4106d36fd012c64bb139 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Mar 2017 11:40:52 -0700 Subject: [PATCH 038/337] Upgrade libcc for webview dnd fix --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index fc87d083750c..94109bdbb231 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -9,7 +9,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \ - '44448acf6a21024b9adb7140ffef6402a509f8bf' + 'dd95b11e52f1e5596184d83d91c91d7b089d05f6' PLATFORM = { 'cygwin': 'win32', From c3a8f665f299bb73dafdcefb515691c3b9dc3eb0 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 27 Mar 2017 18:19:34 -0300 Subject: [PATCH 039/337] Extract base class from AtomRendererClient The new `RendererClientBase` class contains code that is not specific to node.js integration with the renderer. --- atom/renderer/atom_renderer_client.cc | 165 +--------------------- atom/renderer/atom_renderer_client.h | 19 +-- atom/renderer/renderer_client_base.cc | 190 ++++++++++++++++++++++++++ atom/renderer/renderer_client_base.h | 50 +++++++ filenames.gypi | 2 + 5 files changed, 248 insertions(+), 178 deletions(-) create mode 100644 atom/renderer/renderer_client_base.cc create mode 100644 atom/renderer/renderer_client_base.h diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index eb1bdccbe34c..9d015b4f229f 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -9,53 +9,23 @@ #include "atom_natives.h" // NOLINT: This file is generated with js2c -#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/asar/asar_util.h" #include "atom/common/atom_constants.h" -#include "atom/common/color_util.h" -#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_bindings.h" #include "atom/common/options_switches.h" #include "atom/renderer/api/atom_api_renderer_ipc.h" #include "atom/renderer/atom_render_view_observer.h" -#include "atom/renderer/content_settings_observer.h" -#include "atom/renderer/guest_view_container.h" #include "atom/renderer/node_array_buffer_bridge.h" -#include "atom/renderer/preferences_manager.h" #include "atom/renderer/web_worker_observer.h" #include "base/command_line.h" -#include "chrome/renderer/media/chrome_key_systems.h" -#include "chrome/renderer/pepper/pepper_helper.h" -#include "chrome/renderer/printing/print_web_view_helper.h" -#include "chrome/renderer/tts_dispatcher.h" -#include "content/public/common/content_constants.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame_observer.h" -#include "content/public/renderer/render_thread.h" -#include "content/public/renderer/render_view.h" -#include "ipc/ipc_message_macros.h" #include "native_mate/dictionary.h" -#include "third_party/WebKit/public/web/WebCustomElement.h" #include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebFrameWidget.h" -#include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebPluginParams.h" -#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "third_party/WebKit/public/web/WebScriptSource.h" -#include "third_party/WebKit/public/web/WebSecurityPolicy.h" -#include "third_party/WebKit/public/web/WebView.h" - -#if defined(OS_MACOSX) -#include "base/mac/mac_util.h" -#include "base/strings/sys_string_conversions.h" -#endif - -#if defined(OS_WIN) -#include -#endif #include "atom/common/node_includes.h" @@ -184,35 +154,11 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); }; -v8::Local GetRenderProcessPreferences( - const PreferencesManager* preferences_manager, v8::Isolate* isolate) { - if (preferences_manager->preferences()) - return mate::ConvertToV8(isolate, *preferences_manager->preferences()); - else - return v8::Null(isolate); -} - -void AddRenderBindings(v8::Isolate* isolate, - v8::Local process, - const PreferencesManager* preferences_manager) { - mate::Dictionary dict(isolate, process); - dict.SetMethod( - "getRenderProcessPreferences", - base::Bind(GetRenderProcessPreferences, preferences_manager)); -} - bool IsDevToolsExtension(content::RenderFrame* render_frame) { return static_cast(render_frame->GetWebFrame()->document().url()) .SchemeIs("chrome-extension"); } -std::vector ParseSchemesCLISwitch(const char* switch_name) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name); - return base::SplitString( - custom_schemes, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); -} - } // namespace AtomRendererClient::AtomRendererClient() @@ -221,11 +167,6 @@ AtomRendererClient::AtomRendererClient() atom_bindings_(new AtomBindings(uv_default_loop())) { isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kContextIsolation); - // Parse --standard-schemes=scheme1,scheme2 - std::vector standard_schemes_list = - ParseSchemesCLISwitch(switches::kStandardSchemes); - for (const std::string& scheme : standard_schemes_list) - url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); } AtomRendererClient::~AtomRendererClient() { @@ -233,80 +174,19 @@ AtomRendererClient::~AtomRendererClient() { } void AtomRendererClient::RenderThreadStarted() { - blink::WebCustomElement::addEmbedderCustomElementName("webview"); - blink::WebCustomElement::addEmbedderCustomElementName("browserplugin"); - OverrideNodeArrayBuffer(); - - preferences_manager_.reset(new PreferencesManager); - -#if defined(OS_WIN) - // Set ApplicationUserModelID in renderer process. - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - base::string16 app_id = - command_line->GetSwitchValueNative(switches::kAppUserModelId); - if (!app_id.empty()) { - SetCurrentProcessExplicitAppUserModelID(app_id.c_str()); - } -#endif - -#if defined(OS_MACOSX) - // Disable rubber banding by default. - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (!command_line->HasSwitch(switches::kScrollBounce)) { - base::ScopedCFTypeRef key( - base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding")); - base::ScopedCFTypeRef value( - base::SysUTF8ToCFStringRef("false")); - CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication); - CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); - } -#endif + RendererClientBase::RenderThreadStarted(); } void AtomRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { - new PepperHelper(render_frame); new AtomRenderFrameObserver(render_frame, this); - new ContentSettingsObserver(render_frame); - new printing::PrintWebViewHelper(render_frame); - - // Allow file scheme to handle service worker by default. - // FIXME(zcbenz): Can this be moved elsewhere? - blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers("file"); - - // This is required for widevine plugin detection provided during runtime. - blink::resetPluginCache(); - - // Allow access to file scheme from pdf viewer. - blink::WebSecurityPolicy::addOriginAccessWhitelistEntry( - GURL(kPdfViewerUIOrigin), "file", "", true); - - // Parse --secure-schemes=scheme1,scheme2 - std::vector secure_schemes_list = - ParseSchemesCLISwitch(switches::kSecureSchemes); - for (const std::string& secure_scheme : secure_schemes_list) - blink::WebSecurityPolicy::registerURLSchemeAsSecure( - blink::WebString::fromUTF8(secure_scheme)); + RendererClientBase::RenderFrameCreated(render_frame); } void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { new AtomRenderViewObserver(render_view, this); - - blink::WebFrameWidget* web_frame_widget = render_view->GetWebFrameWidget(); - if (!web_frame_widget) - return; - - base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); - if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview. - web_frame_widget->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); - web_frame_widget->setBaseBackgroundColor(color); - } + RendererClientBase::RenderViewCreated(render_view); } void AtomRendererClient::DidClearWindowObject( @@ -335,26 +215,6 @@ void AtomRendererClient::RunScriptsAtDocumentEnd( } } -blink::WebSpeechSynthesizer* AtomRendererClient::OverrideSpeechSynthesizer( - blink::WebSpeechSynthesizerClient* client) { - return new TtsDispatcher(client); -} - -bool AtomRendererClient::OverrideCreatePlugin( - content::RenderFrame* render_frame, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - blink::WebPlugin** plugin) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (params.mimeType.utf8() == content::kBrowserPluginMimeType || - params.mimeType.utf8() == kPdfPluginMimeType || - command_line->HasSwitch(switches::kEnablePlugins)) - return false; - - *plugin = nullptr; - return true; -} - void AtomRendererClient::DidCreateScriptContext( v8::Handle context, content::RenderFrame* render_frame) { // Only allow node integration for the main frame, unless it is a devtools @@ -374,8 +234,7 @@ void AtomRendererClient::DidCreateScriptContext( // Add Electron extended APIs. atom_bindings_->BindTo(env->isolate(), env->process_object()); - AddRenderBindings(env->isolate(), env->process_object(), - preferences_manager_.get()); + AddRenderBindings(env->isolate(), env->process_object()); // Load everything. node_bindings_->LoadEnvironment(env); @@ -423,22 +282,6 @@ bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame, return http_method == "GET"; } -content::BrowserPluginDelegate* AtomRendererClient::CreateBrowserPluginDelegate( - content::RenderFrame* render_frame, - const std::string& mime_type, - const GURL& original_url) { - if (mime_type == content::kBrowserPluginMimeType) { - return new GuestViewContainer(render_frame); - } else { - return nullptr; - } -} - -void AtomRendererClient::AddSupportedKeySystems( - std::vector>* key_systems) { - AddChromeKeySystems(key_systems); -} - void AtomRendererClient::DidInitializeWorkerContextOnWorkerThread( v8::Local context) { if (base::CommandLine::ForCurrentProcess()->HasSwitch( diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index af8397854e3e..5a1141d1036d 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -8,15 +8,14 @@ #include #include -#include "content/public/renderer/content_renderer_client.h" +#include "atom/renderer/renderer_client_base.h" namespace atom { class AtomBindings; -class PreferencesManager; class NodeBindings; -class AtomRendererClient : public content::ContentRendererClient { +class AtomRendererClient : public RendererClientBase { public: AtomRendererClient(); virtual ~AtomRendererClient(); @@ -46,25 +45,12 @@ class AtomRendererClient : public content::ContentRendererClient { void RenderViewCreated(content::RenderView*) override; void RunScriptsAtDocumentStart(content::RenderFrame* render_frame) override; void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override; - blink::WebSpeechSynthesizer* OverrideSpeechSynthesizer( - blink::WebSpeechSynthesizerClient* client) override; - bool OverrideCreatePlugin(content::RenderFrame* render_frame, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - blink::WebPlugin** plugin) override; bool ShouldFork(blink::WebLocalFrame* frame, const GURL& url, const std::string& http_method, bool is_initial_navigation, bool is_server_redirect, bool* send_referrer) override; - content::BrowserPluginDelegate* CreateBrowserPluginDelegate( - content::RenderFrame* render_frame, - const std::string& mime_type, - const GURL& original_url) override; - void AddSupportedKeySystems( - std::vector>* key_systems) - override; void DidInitializeWorkerContextOnWorkerThread( v8::Local context) override; void WillDestroyWorkerContextOnWorkerThread( @@ -75,7 +61,6 @@ class AtomRendererClient : public content::ContentRendererClient { std::unique_ptr node_bindings_; std::unique_ptr atom_bindings_; - std::unique_ptr preferences_manager_; bool isolated_world_; DISALLOW_COPY_AND_ASSIGN(AtomRendererClient); diff --git a/atom/renderer/renderer_client_base.cc b/atom/renderer/renderer_client_base.cc new file mode 100644 index 000000000000..3ee72b3c0da2 --- /dev/null +++ b/atom/renderer/renderer_client_base.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/renderer/renderer_client_base.h" + +#include +#include + +#include "atom/common/atom_constants.h" +#include "atom/common/color_util.h" +#include "atom/common/native_mate_converters/value_converter.h" +#include "atom/common/options_switches.h" +#include "atom/renderer/content_settings_observer.h" +#include "atom/renderer/guest_view_container.h" +#include "atom/renderer/preferences_manager.h" +#include "base/command_line.h" +#include "base/strings/string_split.h" +#include "chrome/renderer/media/chrome_key_systems.h" +#include "chrome/renderer/pepper/pepper_helper.h" +#include "chrome/renderer/printing/print_web_view_helper.h" +#include "chrome/renderer/tts_dispatcher.h" +#include "content/public/common/content_constants.h" +#include "content/public/renderer/render_view.h" +#include "native_mate/dictionary.h" +#include "third_party/WebKit/public/web/WebCustomElement.h" +#include "third_party/WebKit/public/web/WebFrameWidget.h" +#include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebPluginParams.h" +#include "third_party/WebKit/public/web/WebSecurityPolicy.h" + +#if defined(OS_MACOSX) +#include "base/mac/mac_util.h" +#include "base/strings/sys_string_conversions.h" +#endif + +#if defined(OS_WIN) +#include +#endif + +namespace atom { + +namespace { + +v8::Local GetRenderProcessPreferences( + const PreferencesManager* preferences_manager, v8::Isolate* isolate) { + if (preferences_manager->preferences()) + return mate::ConvertToV8(isolate, *preferences_manager->preferences()); + else + return v8::Null(isolate); +} + +std::vector ParseSchemesCLISwitch(const char* switch_name) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name); + return base::SplitString( + custom_schemes, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); +} + +} // namespace + +RendererClientBase::RendererClientBase() { + // Parse --standard-schemes=scheme1,scheme2 + std::vector standard_schemes_list = + ParseSchemesCLISwitch(switches::kStandardSchemes); + for (const std::string& scheme : standard_schemes_list) + url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); +} + +RendererClientBase::~RendererClientBase() { +} + +void RendererClientBase::AddRenderBindings( + v8::Isolate* isolate, + v8::Local binding_object) { + mate::Dictionary dict(isolate, binding_object); + dict.SetMethod( + "getRenderProcessPreferences", + base::Bind(GetRenderProcessPreferences, preferences_manager_.get())); +} + +void RendererClientBase::RenderThreadStarted() { + blink::WebCustomElement::addEmbedderCustomElementName("webview"); + blink::WebCustomElement::addEmbedderCustomElementName("browserplugin"); + + preferences_manager_.reset(new PreferencesManager); + +#if defined(OS_WIN) + // Set ApplicationUserModelID in renderer process. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + base::string16 app_id = + command_line->GetSwitchValueNative(switches::kAppUserModelId); + if (!app_id.empty()) { + SetCurrentProcessExplicitAppUserModelID(app_id.c_str()); + } +#endif + +#if defined(OS_MACOSX) + // Disable rubber banding by default. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(switches::kScrollBounce)) { + base::ScopedCFTypeRef key( + base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding")); + base::ScopedCFTypeRef value( + base::SysUTF8ToCFStringRef("false")); + CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication); + CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); + } +#endif +} + +void RendererClientBase::RenderFrameCreated( + content::RenderFrame* render_frame) { + new PepperHelper(render_frame); + new ContentSettingsObserver(render_frame); + new printing::PrintWebViewHelper(render_frame); + + // Allow file scheme to handle service worker by default. + // FIXME(zcbenz): Can this be moved elsewhere? + blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers("file"); + + // This is required for widevine plugin detection provided during runtime. + blink::resetPluginCache(); + + // Allow access to file scheme from pdf viewer. + blink::WebSecurityPolicy::addOriginAccessWhitelistEntry( + GURL(kPdfViewerUIOrigin), "file", "", true); + + // Parse --secure-schemes=scheme1,scheme2 + std::vector secure_schemes_list = + ParseSchemesCLISwitch(switches::kSecureSchemes); + for (const std::string& secure_scheme : secure_schemes_list) + blink::WebSecurityPolicy::registerURLSchemeAsSecure( + blink::WebString::fromUTF8(secure_scheme)); +} + +void RendererClientBase::RenderViewCreated(content::RenderView* render_view) { + blink::WebFrameWidget* web_frame_widget = render_view->GetWebFrameWidget(); + if (!web_frame_widget) + return; + + base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); + if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview. + web_frame_widget->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); + web_frame_widget->setBaseBackgroundColor(color); + } +} + +blink::WebSpeechSynthesizer* RendererClientBase::OverrideSpeechSynthesizer( + blink::WebSpeechSynthesizerClient* client) { + return new TtsDispatcher(client); +} + +bool RendererClientBase::OverrideCreatePlugin( + content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + blink::WebPlugin** plugin) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (params.mimeType.utf8() == content::kBrowserPluginMimeType || + params.mimeType.utf8() == kPdfPluginMimeType || + command_line->HasSwitch(switches::kEnablePlugins)) + return false; + + *plugin = nullptr; + return true; +} + +content::BrowserPluginDelegate* RendererClientBase::CreateBrowserPluginDelegate( + content::RenderFrame* render_frame, + const std::string& mime_type, + const GURL& original_url) { + if (mime_type == content::kBrowserPluginMimeType) { + return new GuestViewContainer(render_frame); + } else { + return nullptr; + } +} + +void RendererClientBase::AddSupportedKeySystems( + std::vector>* key_systems) { + AddChromeKeySystems(key_systems); +} + +} // namespace atom diff --git a/atom/renderer/renderer_client_base.h b/atom/renderer/renderer_client_base.h new file mode 100644 index 000000000000..3a91255c60b1 --- /dev/null +++ b/atom/renderer/renderer_client_base.h @@ -0,0 +1,50 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_RENDERER_RENDERER_CLIENT_BASE_H_ +#define ATOM_RENDERER_RENDERER_CLIENT_BASE_H_ + +#include +#include + +#include "content/public/renderer/content_renderer_client.h" + +namespace atom { + +class PreferencesManager; + +class RendererClientBase : public content::ContentRendererClient { + public: + RendererClientBase(); + virtual ~RendererClientBase(); + + protected: + void AddRenderBindings(v8::Isolate* isolate, + v8::Local binding_object); + + // content::ContentRendererClient: + void RenderThreadStarted() override; + void RenderFrameCreated(content::RenderFrame*) override; + void RenderViewCreated(content::RenderView*) override; + blink::WebSpeechSynthesizer* OverrideSpeechSynthesizer( + blink::WebSpeechSynthesizerClient* client) override; + bool OverrideCreatePlugin(content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + blink::WebPlugin** plugin) override; + content::BrowserPluginDelegate* CreateBrowserPluginDelegate( + content::RenderFrame* render_frame, + const std::string& mime_type, + const GURL& original_url) override; + void AddSupportedKeySystems( + std::vector>* key_systems) + override; + + private: + std::unique_ptr preferences_manager_; +}; + +} // namespace atom + +#endif // ATOM_RENDERER_RENDERER_CLIENT_BASE_H_ diff --git a/filenames.gypi b/filenames.gypi index 3b557fcb88a4..935d7033153a 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -480,6 +480,8 @@ 'atom/renderer/node_array_buffer_bridge.h', 'atom/renderer/preferences_manager.cc', 'atom/renderer/preferences_manager.h', + 'atom/renderer/renderer_client_base.cc', + 'atom/renderer/renderer_client_base.h', 'atom/renderer/web_worker_observer.cc', 'atom/renderer/web_worker_observer.h', 'atom/utility/atom_content_utility_client.cc', From d1f08beddfb7991411a890c6b0afd5f73ee2cdb5 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 27 Mar 2017 18:31:18 -0300 Subject: [PATCH 040/337] Make AtomSandboxedRendererClient a RendererClientBase subclass. --- atom/renderer/atom_sandboxed_renderer_client.cc | 4 +++- atom/renderer/atom_sandboxed_renderer_client.h | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index bf9ea6fd9ef8..48d1640f976c 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -182,12 +182,13 @@ AtomSandboxedRendererClient::~AtomSandboxedRendererClient() { void AtomSandboxedRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { new AtomSandboxedRenderFrameObserver(render_frame, this); - new printing::PrintWebViewHelper(render_frame); + RendererClientBase::RenderFrameCreated(render_frame); } void AtomSandboxedRendererClient::RenderViewCreated( content::RenderView* render_view) { new AtomSandboxedRenderViewObserver(render_view, this); + RendererClientBase::RenderViewCreated(render_view); } void AtomSandboxedRendererClient::DidCreateScriptContext( @@ -218,6 +219,7 @@ void AtomSandboxedRendererClient::DidCreateScriptContext( // Create and initialize the binding object auto binding = v8::Object::New(isolate); InitializeBindings(binding, context); + AddRenderBindings(isolate, binding); v8::Local args[] = { binding, mate::ConvertToV8(isolate, preload_script) diff --git a/atom/renderer/atom_sandboxed_renderer_client.h b/atom/renderer/atom_sandboxed_renderer_client.h index 0912c6b24bd0..aefd10caf70d 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.h +++ b/atom/renderer/atom_sandboxed_renderer_client.h @@ -7,12 +7,11 @@ #include #include -#include "content/public/renderer/content_renderer_client.h" -#include "content/public/renderer/render_frame.h" +#include "atom/renderer/renderer_client_base.h" namespace atom { -class AtomSandboxedRendererClient : public content::ContentRendererClient { +class AtomSandboxedRendererClient : public RendererClientBase { public: AtomSandboxedRendererClient(); virtual ~AtomSandboxedRendererClient(); From 3004f3c76216c44613c5ff766bad7bd7022309bf Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Tue, 28 Mar 2017 11:49:47 +0800 Subject: [PATCH 041/337] Update dialog.md --- docs-translations/zh-CN/api/dialog.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/docs-translations/zh-CN/api/dialog.md b/docs-translations/zh-CN/api/dialog.md index 702b6ea3e2bf..41ec25672196 100644 --- a/docs-translations/zh-CN/api/dialog.md +++ b/docs-translations/zh-CN/api/dialog.md @@ -107,20 +107,23 @@ console.log(dialog) * `options` Object * `type` String - 可以是 `"none"`, `"info"`, `"error"`, `"question"` 或 `"warning"`. 在 Windows, "question" 与 "info" 展示图标相同, 除非你使用 "icon" 参数. - * `buttons` Array - buttons 内容,数组. - * `defaultId` Integer - 在message box 对话框打开的时候,设置默认button选中,值为在 buttons 数组中的button索引. - * `title` String - message box 的标题,一些平台不显示. - * `message` String - message box 内容. - * `detail` String - 额外信息. - * `icon` [NativeImage](native-image.md) - * `cancelId` Integer - 当用户关闭对话框的时候,不是通过点击对话框的button,就返回值.默认值为对应 "cancel" 或 "no" 标签button 的索引值, 或者如果没有这种button,就返回0. 在 macOS 和 Windows 上, "Cancel" button 的索引值将一直是 `cancelId`, 不管之前是不是特别指出的. - * `noLink` Boolean - 在 Windows ,Electron 将尝试识别哪个button 是普通 button (如 "Cancel" 或 "Yes"), 然后在对话框中以链接命令(command links)方式展现其它的 button . 这能让对话框展示得很炫酷.如果你不喜欢这种效果,你可以设置 `noLink` 为 `true`. - * `callback` Function (可选) - * `response` Number - The index of the button that was clicked + * `buttons` String[]- (可选) - 按钮上文字的数组,在 Windows 系统中,空数组在按钮上会显示 “OK”. + * `defaultId` Integer (可选) - 在 message box 对话框打开的时候,设置默认选中的按钮,值为在 buttons 数组中的索引. + * `title` String (可选) - message box 的标题,一些平台不显示. + * `message` String (可选) - message box 的内容. + * `detail` String (可选)- 额外信息. + * `checkboxLabel` String (可选) - 如果有该参数,message box 中会显示一个 checkbox 复选框,它的勾选状态可以在 `callback` 回调方法中获取。 + * `checkboxChecked` Boolean (可选) - checkbox 的初始值,默认为`false`. + * `icon` [NativeImage](native-image.md)(可选) + * `cancelId` Integer - 当用户不是通过按钮而是使用其他方式关闭对话框时,比如按`Esc`键,就返回该值.默认值为对应 "cancel" 或 "no" 标签 button 的索引值, 如果没有这种 button,就返回0. 该选项在 Windows 上无效. + * `noLink` Boolean(可选) - 在 Windows 系统中,Electron 将尝试识别哪个button 是普通 button (如 "Cancel" 或 "Yes"), 然后在对话框中以链接命令(command links)方式展现其它的 button . 这能让对话框展示得很炫酷.如果你不喜欢这种效果,你可以设置 `noLink` 为 `true`. +* `callback` Function (可选) + * `response` Number - 被点击按钮的索引值。 + * `checkboxChecked` Boolean - 如果设置了 `checkboxLabel` ,会显示 checkbox 的选中状态,否则显示 `false` 返回 `Integer`,如果提供了回调,它会返回点击的按钮的索引或者 undefined 。 -展示 message box, 它会阻塞进程,直到 message box 关闭为止.返回点击按钮的索引值。 +显示 message box 时, 它会阻塞进程,直到 message box 关闭为止.返回点击按钮的索引值。 `browserWindow` 参数允许对话框将自身附加到父窗口,使其成为模态。 From 2ef1b70897cbc86afe4cde7350fe6d2a801c4966 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 28 Mar 2017 17:19:14 +0900 Subject: [PATCH 042/337] Fix crash happened in UvRunOnce --- atom/common/node_bindings.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 314a7b9c0330..f4696773dad6 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -232,6 +232,12 @@ void NodeBindings::RunMessageLoop() { void NodeBindings::UvRunOnce() { node::Environment* env = uv_env(); + // When doing navigation without restarting renderer process, it may happen + // that the node environment is destroyed but the message loop is still there. + // In this case we should not run uv loop. + if (!env) + return; + // Use Locker in browser process. mate::Locker locker(env->isolate()); v8::HandleScope handle_scope(env->isolate()); From 3ae62615f4248a874c5614098ccbd19444a73fce Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Fri, 24 Mar 2017 01:07:54 +0530 Subject: [PATCH 043/337] net: allow controlling redirects --- atom/browser/api/atom_api_url_request.cc | 37 ++++- atom/browser/api/atom_api_url_request.h | 6 + atom/browser/net/atom_url_request.cc | 55 ++++++- atom/browser/net/atom_url_request.h | 15 +- lib/browser/api/net.js | 12 +- spec/api-net-spec.js | 193 +++++++++++++++++++++++ 6 files changed, 312 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/atom_api_url_request.cc b/atom/browser/api/atom_api_url_request.cc index 967ae50a7e1f..d3607e7283cc 100644 --- a/atom/browser/api/atom_api_url_request.cc +++ b/atom/browser/api/atom_api_url_request.cc @@ -8,6 +8,7 @@ #include "atom/browser/net/atom_url_request.h" #include "atom/common/api/event_emitter_caller.h" #include "atom/common/native_mate_converters/callback.h" +#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/node_includes.h" @@ -145,6 +146,8 @@ mate::WrappableBase* URLRequest::New(mate::Arguments* args) { dict.Get("method", &method); std::string url; dict.Get("url", &url); + std::string redirect_policy; + dict.Get("redirect", &redirect_policy); std::string partition; mate::Handle session; if (dict.Get("session", &session)) { @@ -156,8 +159,8 @@ mate::WrappableBase* URLRequest::New(mate::Arguments* args) { } auto browser_context = session->browser_context(); auto api_url_request = new URLRequest(args->isolate(), args->GetThis()); - auto atom_url_request = - AtomURLRequest::Create(browser_context, method, url, api_url_request); + auto atom_url_request = AtomURLRequest::Create( + browser_context, method, url, redirect_policy, api_url_request); api_url_request->atom_request_ = atom_url_request; @@ -176,6 +179,7 @@ void URLRequest::BuildPrototype(v8::Isolate* isolate, .SetMethod("setExtraHeader", &URLRequest::SetExtraHeader) .SetMethod("removeExtraHeader", &URLRequest::RemoveExtraHeader) .SetMethod("setChunkedUpload", &URLRequest::SetChunkedUpload) + .SetMethod("followRedirect", &URLRequest::FollowRedirect) .SetMethod("_setLoadFlags", &URLRequest::SetLoadFlags) .SetProperty("notStarted", &URLRequest::NotStarted) .SetProperty("finished", &URLRequest::Finished) @@ -246,6 +250,17 @@ void URLRequest::Cancel() { Close(); } +void URLRequest::FollowRedirect() { + if (request_state_.Canceled() || request_state_.Closed()) { + return; + } + + DCHECK(atom_request_); + if (atom_request_) { + atom_request_->FollowRedirect(); + } +} + bool URLRequest::SetExtraHeader(const std::string& name, const std::string& value) { // Request state must be in the initial non started state. @@ -305,6 +320,24 @@ void URLRequest::SetLoadFlags(int flags) { } } +void URLRequest::OnReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers) { + if (request_state_.Canceled() || request_state_.Closed()) { + return; + } + + DCHECK(atom_request_); + if (!atom_request_) { + return; + } + + EmitRequestEvent(false, "redirect", status_code, method, url, + response_headers.get()); +} + void URLRequest::OnAuthenticationRequired( scoped_refptr auth_info) { if (request_state_.Canceled() || request_state_.Closed()) { diff --git a/atom/browser/api/atom_api_url_request.h b/atom/browser/api/atom_api_url_request.h index c92ac01961cd..372ac98ac657 100644 --- a/atom/browser/api/atom_api_url_request.h +++ b/atom/browser/api/atom_api_url_request.h @@ -99,6 +99,11 @@ class URLRequest : public mate::EventEmitter { v8::Local prototype); // Methods for reporting events into JavaScript. + void OnReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers); void OnAuthenticationRequired( scoped_refptr auth_info); void OnResponseStarted( @@ -170,6 +175,7 @@ class URLRequest : public mate::EventEmitter { bool Failed() const; bool Write(scoped_refptr buffer, bool is_last); void Cancel(); + void FollowRedirect(); bool SetExtraHeader(const std::string& name, const std::string& value); void RemoveExtraHeader(const std::string& name); void SetChunkedUpload(bool is_chunked_upload); diff --git a/atom/browser/net/atom_url_request.cc b/atom/browser/net/atom_url_request.cc index 2c7bb61da0b1..19c526700d20 100644 --- a/atom/browser/net/atom_url_request.cc +++ b/atom/browser/net/atom_url_request.cc @@ -13,6 +13,7 @@ #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/upload_bytes_element_reader.h" +#include "net/url_request/redirect_info.h" namespace { const int kBufferSize = 4096; @@ -58,6 +59,7 @@ scoped_refptr AtomURLRequest::Create( AtomBrowserContext* browser_context, const std::string& method, const std::string& url, + const std::string& redirect_policy, api::URLRequest* delegate) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -76,7 +78,7 @@ scoped_refptr AtomURLRequest::Create( if (content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&AtomURLRequest::DoInitialize, atom_url_request, - request_context_getter, method, url))) { + request_context_getter, method, url, redirect_policy))) { return atom_url_request; } return nullptr; @@ -93,10 +95,12 @@ void AtomURLRequest::Terminate() { void AtomURLRequest::DoInitialize( scoped_refptr request_context_getter, const std::string& method, - const std::string& url) { + const std::string& url, + const std::string& redirect_policy) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(request_context_getter); + redirect_policy_ = redirect_policy; request_context_getter_ = request_context_getter; request_context_getter_->AddObserver(this); auto context = request_context_getter_->GetURLRequestContext(); @@ -150,6 +154,13 @@ void AtomURLRequest::Cancel() { base::Bind(&AtomURLRequest::DoCancel, this)); } +void AtomURLRequest::FollowRedirect() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&AtomURLRequest::DoFollowRedirect, this)); +} + void AtomURLRequest::SetExtraHeader(const std::string& name, const std::string& value) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -246,6 +257,13 @@ void AtomURLRequest::DoCancel() { DoTerminate(); } +void AtomURLRequest::DoFollowRedirect() { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (request_ && request_->is_redirecting() && redirect_policy_ == "manual") { + request_->FollowDeferredRedirect(); + } +} + void AtomURLRequest::DoSetExtraHeader(const std::string& name, const std::string& value) const { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -297,6 +315,29 @@ void AtomURLRequest::DoSetLoadFlags(int flags) const { request_->SetLoadFlags(request_->load_flags() | flags); } +void AtomURLRequest::OnReceivedRedirect(net::URLRequest* request, + const net::RedirectInfo& info, + bool* defer_redirect) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (!request_ || redirect_policy_ == "follow") + return; + + if (redirect_policy_ == "error") { + request->Cancel(); + DoCancelWithError( + "Request cannot follow redirect with the current redirect mode", true); + } else if (redirect_policy_ == "manual") { + *defer_redirect = true; + scoped_refptr response_headers = + request->response_headers(); + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::Bind(&AtomURLRequest::InformDelegateReceivedRedirect, this, + info.status_code, info.new_method, info.new_url, + response_headers)); + } +} + void AtomURLRequest::OnAuthRequired(net::URLRequest* request, net::AuthChallengeInfo* auth_info) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -399,6 +440,16 @@ bool AtomURLRequest::CopyAndPostBuffer(int bytes_read) { buffer_copy)); } +void AtomURLRequest::InformDelegateReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers) const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (delegate_) + delegate_->OnReceivedRedirect(status_code, method, url, response_headers); +} + void AtomURLRequest::InformDelegateAuthenticationRequired( scoped_refptr auth_info) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); diff --git a/atom/browser/net/atom_url_request.h b/atom/browser/net/atom_url_request.h index db00390b955c..654798d8aac8 100644 --- a/atom/browser/net/atom_url_request.h +++ b/atom/browser/net/atom_url_request.h @@ -30,12 +30,14 @@ class AtomURLRequest : public base::RefCountedThreadSafe, AtomBrowserContext* browser_context, const std::string& method, const std::string& url, + const std::string& redirect_policy, api::URLRequest* delegate); void Terminate(); bool Write(scoped_refptr buffer, bool is_last); void SetChunkedUpload(bool is_chunked_upload); void Cancel(); + void FollowRedirect(); void SetExtraHeader(const std::string& name, const std::string& value) const; void RemoveExtraHeader(const std::string& name) const; void PassLoginInformation(const base::string16& username, @@ -44,6 +46,9 @@ class AtomURLRequest : public base::RefCountedThreadSafe, protected: // Overrides of net::URLRequest::Delegate + void OnReceivedRedirect(net::URLRequest* request, + const net::RedirectInfo& info, + bool* defer_redirect) override; void OnAuthRequired(net::URLRequest* request, net::AuthChallengeInfo* auth_info) override; void OnResponseStarted(net::URLRequest* request) override; @@ -60,11 +65,13 @@ class AtomURLRequest : public base::RefCountedThreadSafe, void DoInitialize(scoped_refptr, const std::string& method, - const std::string& url); + const std::string& url, + const std::string& redirect_policy); void DoTerminate(); void DoWriteBuffer(scoped_refptr buffer, bool is_last); void DoCancel(); + void DoFollowRedirect(); void DoSetExtraHeader(const std::string& name, const std::string& value) const; void DoRemoveExtraHeader(const std::string& name) const; @@ -77,6 +84,11 @@ class AtomURLRequest : public base::RefCountedThreadSafe, void ReadResponse(); bool CopyAndPostBuffer(int bytes_read); + void InformDelegateReceivedRedirect( + int status_code, + const std::string& method, + const GURL& url, + scoped_refptr response_headers) const; void InformDelegateAuthenticationRequired( scoped_refptr auth_info) const; void InformDelegateResponseStarted( @@ -92,6 +104,7 @@ class AtomURLRequest : public base::RefCountedThreadSafe, scoped_refptr request_context_getter_; bool is_chunked_upload_; + std::string redirect_policy_; std::unique_ptr chunked_stream_; std::unique_ptr chunked_stream_writer_; std::vector> diff --git a/lib/browser/api/net.js b/lib/browser/api/net.js index 10d903919e9d..049cef9e3ab4 100644 --- a/lib/browser/api/net.js +++ b/lib/browser/api/net.js @@ -156,9 +156,15 @@ class ClientRequest extends EventEmitter { urlStr = url.format(urlObj) } + const redirectPolicy = options.redirect || 'follow' + if (!['follow', 'error', 'manual'].includes(redirectPolicy)) { + throw new Error('redirect mode should be one of follow, error or manual') + } + let urlRequestOptions = { method: method, - url: urlStr + url: urlStr, + redirect: redirectPolicy } if (options.session) { if (options.session instanceof Session) { @@ -339,6 +345,10 @@ class ClientRequest extends EventEmitter { return this._write(data, encoding, callback, true) } + followRedirect () { + this.urlRequest.followRedirect() + } + abort () { this.urlRequest.cancel() } diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index 49fe2edadcce..80f24a46e9c4 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -906,6 +906,199 @@ describe('net module', function () { urlRequest.end() }) + it('should throw if given an invalid redirect mode', function (done) { + const requestUrl = '/requestUrl' + try { + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'custom' + }) + urlRequest + } catch (exception) { + done() + } + }) + + it('should follow redirect when no redirect mode is provided', function (done) { + const requestUrl = '/301' + server.on('request', function (request, response) { + switch (request.url) { + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}` + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + done() + }) + urlRequest.end() + }) + + it('should follow redirect chain when no redirect mode is provided', function (done) { + const requestUrl = '/redirectChain' + server.on('request', function (request, response) { + switch (request.url) { + case '/redirectChain': + response.statusCode = '301' + response.setHeader('Location', '/301') + response.end() + break + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}` + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + done() + }) + urlRequest.end() + }) + + it('should not follow redirect when mode is error', function (done) { + const requestUrl = '/301' + server.on('request', function (request, response) { + switch (request.url) { + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'error' + }) + urlRequest.on('error', function (error) { + assert.equal(error.message, 'Request cannot follow redirect with the current redirect mode') + }) + urlRequest.on('close', function () { + done() + }) + urlRequest.end() + }) + + it('should allow follow redirect when mode is manual', function (done) { + const requestUrl = '/redirectChain' + let redirectCount = 0 + server.on('request', function (request, response) { + switch (request.url) { + case '/redirectChain': + response.statusCode = '301' + response.setHeader('Location', '/301') + response.end() + break + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'manual' + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + assert.equal(redirectCount, 2) + done() + }) + urlRequest.on('redirect', function (status, method, url) { + if (url === `${server.url}/301` || url === `${server.url}/200`) { + redirectCount += 1 + urlRequest.followRedirect() + } + }) + urlRequest.end() + }) + + it('should allow cancelling redirect when mode is manual', function (done) { + const requestUrl = '/redirectChain' + let redirectCount = 0 + server.on('request', function (request, response) { + switch (request.url) { + case '/redirectChain': + response.statusCode = '301' + response.setHeader('Location', '/redirect/1') + response.end() + break + case '/redirect/1': + response.statusCode = '200' + response.setHeader('Location', '/redirect/2') + response.end() + break + case '/redirect/2': + response.statusCode = '200' + response.end() + break + default: + assert(false) + } + }) + const urlRequest = net.request({ + url: `${server.url}${requestUrl}`, + redirect: 'manual' + }) + urlRequest.on('response', function (response) { + assert.equal(response.statusCode, 200) + response.pause() + response.on('data', function (chunk) { + }) + response.on('end', function () { + urlRequest.abort() + }) + response.resume() + }) + urlRequest.on('close', function () { + assert.equal(redirectCount, 1) + done() + }) + urlRequest.on('redirect', function (status, method, url) { + if (url === `${server.url}/redirect/1`) { + redirectCount += 1 + urlRequest.followRedirect() + } + }) + urlRequest.end() + }) + it('should throw if given an invalid session option', function (done) { const requestUrl = '/requestUrl' try { From 8db1eacd1c19f0570bd76783ac1077ae2e831f85 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Sat, 25 Mar 2017 12:37:34 +0530 Subject: [PATCH 044/337] [skip ci] add docs --- docs/api/client-request.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 71ade14a8ef3..4a16d9510ec4 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -29,6 +29,11 @@ the hostname and the port number 'hostname:port' * `hostname` String (optional) - The server host name. * `port` Integer (optional) - The server's listening port number. * `path` String (optional) - The path part of the request URL. + * `redirect` String (optional) - The redirect mode for this request. Should be +one of `follow`, `error` or `manual`. Defaults to `follow`. When mode is `error`, +any redirection will be aborted. When mode is `manual` the redirection will be +deferred until [`request.followRedirect`](#requestfollowRedirect) is invoked. Listen for the [`redirect`](#event-redirect) event in +this mode to get more details about the redirect request. `options` properties such as `protocol`, `host`, `hostname`, `port` and `path` strictly follow the Node.js model as described in the @@ -121,6 +126,19 @@ Emitted as the last event in the HTTP request-response transaction. The `close` event indicates that no more events will be emitted on either the `request` or `response` objects. + +#### Event: 'redirect' + +Returns: + +* `statusCode` Integer +* `method` String +* `redirectUrl` String +* `responseHeaders` Object + +Emitted when there is redirection and the mode is `manual`. Calling +[`request.followRedirect`](#requestfollowRedirect) will continue with the redirection. + ### Instance Properties #### `request.chunkedEncoding` @@ -192,3 +210,7 @@ Cancels an ongoing HTTP transaction. If the request has already emitted the `close` event, the abort operation will have no effect. Otherwise an ongoing event will emit `abort` and `close` events. Additionally, if there is an ongoing response object,it will emit the `aborted` event. + +#### `request.followRedirect()` + +Continues any deferred redirection request when the redirection mode is `manual`. From b14c4dcdc060d0f2f0f7133ce371e94b7b00ee34 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 28 Mar 2017 19:05:44 +0530 Subject: [PATCH 045/337] address review comments --- spec/api-net-spec.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index 80f24a46e9c4..68db813d6495 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -906,17 +906,15 @@ describe('net module', function () { urlRequest.end() }) - it('should throw if given an invalid redirect mode', function (done) { + it('should throw if given an invalid redirect mode', function () { const requestUrl = '/requestUrl' - try { - const urlRequest = net.request({ - url: `${server.url}${requestUrl}`, - redirect: 'custom' - }) - urlRequest - } catch (exception) { - done() + const options = { + url: `${server.url}${requestUrl}`, + redirect: 'custom' } + assert.throws(function () { + net.request(options) + }, 'redirect mode should be one of follow, error or manual') }) it('should follow redirect when no redirect mode is provided', function (done) { From f9dbdf45228ccda206b9e7280b481aa85a664f85 Mon Sep 17 00:00:00 2001 From: Anatzum Date: Sat, 28 Jan 2017 02:54:26 -0600 Subject: [PATCH 046/337] Updated MoveItemToTrash in platform_util_linux.cc If ELECTRON_TRASH is null, first check the DESKTOP_SESSION variable and set trash accordingly. Additional desktop environments can be added easily this way with the fallback of ELECTRON_DEFAULT_TRASH. --- atom/common/platform_util_linux.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index 923adbd882be..66ef0cc477e2 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -98,11 +98,19 @@ void OpenExternal(const GURL& url, bool activate, bool MoveItemToTrash(const base::FilePath& full_path) { std::string trash; if (getenv(ELECTRON_TRASH) != NULL) { - trash = getenv(ELECTRON_TRASH); + trash = getenv(ELECTRON_TRASH); } else { - trash = ELECTRON_DEFAULT_TRASH; + // Determine desktop environment and set accordingly. + std::string desktopEnv = getenv(DESKTOP_SESSION); + if (desktopEnv.find("plasma") != std::string::npos) { + trash = "kioclient5"; + } else if (desktopEnv.find("kde") != std::string::npos) { + trash = "kioclient"; + } else { + trash = ELECTRON_DEFAULT_TRASH; + } } - + std::vector argv; if (trash.compare("kioclient5") == 0 || trash.compare("kioclient") == 0) { From 6db827cc9a6221cb20f7b9831187a4e3ffe0805a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 29 Mar 2017 16:21:38 +0900 Subject: [PATCH 047/337] Use GetDesktopEnvironment to determien desktop env Which can get a much more precise result for us. --- atom/common/platform_util_linux.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index 66ef0cc477e2..5c0eaecdd1c2 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -7,7 +7,9 @@ #include #include "base/cancelable_callback.h" +#include "base/environment.h" #include "base/files/file_util.h" +#include "base/nix/xdg_util.h" #include "base/process/kill.h" #include "base/process/launch.h" #include "url/gurl.h" @@ -98,19 +100,22 @@ void OpenExternal(const GURL& url, bool activate, bool MoveItemToTrash(const base::FilePath& full_path) { std::string trash; if (getenv(ELECTRON_TRASH) != NULL) { - trash = getenv(ELECTRON_TRASH); + trash = getenv(ELECTRON_TRASH); } else { // Determine desktop environment and set accordingly. - std::string desktopEnv = getenv(DESKTOP_SESSION); - if (desktopEnv.find("plasma") != std::string::npos) { + std::unique_ptr env(base::Environment::Create()); + base::nix::DesktopEnvironment desktop_env( + base::nix::GetDesktopEnvironment(env.get())); + if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4 || + desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE5) { trash = "kioclient5"; - } else if (desktopEnv.find("kde") != std::string::npos) { + } else if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3) { trash = "kioclient"; } else { - trash = ELECTRON_DEFAULT_TRASH; + trash = ELECTRON_DEFAULT_TRASH; } } - + std::vector argv; if (trash.compare("kioclient5") == 0 || trash.compare("kioclient") == 0) { From 6ae198a6253fdf2321a280ea4b7ac582e69979cc Mon Sep 17 00:00:00 2001 From: mst128256 Date: Wed, 29 Mar 2017 12:17:50 +0200 Subject: [PATCH 048/337] Empty objects within default menu replaced by nulls --- lib/browser/api/menu-item-roles.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index b843bb82e8b6..30ea3f888dba 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -180,7 +180,7 @@ const roles = { process.platform === 'darwin' ? { role: 'pasteandmatchstyle' - } : {}, + } : null, { role: 'delete' @@ -188,7 +188,7 @@ const roles = { process.platform === 'win32' ? { type: 'separator' - } : {}, + } : null, { role: 'selectall' @@ -209,12 +209,11 @@ const roles = { process.platform === 'darwin' ? { type: 'separator' - } : {}, + } : null, process.platform === 'darwin' ? { - label: 'Bring All to Front', role: 'front' - } : {} + } : null ] } @@ -246,7 +245,7 @@ exports.getDefaultSubmenu = (role) => { // remove empty objects from within the submenu if (Array.isArray(submenu)) { submenu = submenu.filter(function (n) { - return n.constructor !== Object || Object.keys(n).length > 0 + return n != null }) } From ed76e0373069570d1825ba0ad91d5470d846bf24 Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Tue, 21 Mar 2017 10:18:57 +0100 Subject: [PATCH 049/337] Revert "Add forward declaration of NSWindow.allowsAutomaticWindowTabbing" This reverts commit 770a3509cfcd62c958dc2b70bd497585f55b565c. --- atom/browser/mac/atom_application_delegate.mm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index 9e245f99078d..74f45e2d2669 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -10,10 +10,6 @@ #include "base/strings/sys_string_conversions.h" #include "base/values.h" -@interface NSWindow (SierraSDK) -@property(class) BOOL allowsAutomaticWindowTabbing; -@end - @implementation AtomApplicationDelegate - (void)setApplicationDockMenu:(atom::AtomMenuModel*)model { @@ -26,8 +22,9 @@ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; // Don't add the "Show Tab Bar" menu item. - if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)]) + if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)]) { NSWindow.allowsAutomaticWindowTabbing = NO; + } atom::Browser::Get()->WillFinishLaunching(); } From 9e02c60e2229d38de47405030a99acdc8830a0af Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Tue, 21 Mar 2017 10:19:08 +0100 Subject: [PATCH 050/337] Revert "Disable Show Tab Bar menu item on macOS Sierrra" This reverts commit 24b93139581836ea8ec3f88cda0edbb3baba8812. --- atom/browser/mac/atom_application_delegate.mm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index 74f45e2d2669..4c6a938fba59 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -21,11 +21,6 @@ // Don't add the "Enter Full Screen" menu item automatically. [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; - // Don't add the "Show Tab Bar" menu item. - if ([NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)]) { - NSWindow.allowsAutomaticWindowTabbing = NO; - } - atom::Browser::Get()->WillFinishLaunching(); } From a7565f0d5704c1c5a12ec24a3ee669358efc413b Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Mon, 27 Mar 2017 16:15:17 +0200 Subject: [PATCH 051/337] Enable native tabs on macOS --- atom/browser/native_window_mac.h | 2 ++ atom/browser/native_window_mac.mm | 15 ++++++++++++++- atom/common/options_switches.cc | 3 +++ atom/common/options_switches.h | 1 + docs/api/browser-window.md | 3 +++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index bd34993fb119..066bcc503ea9 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -179,6 +179,8 @@ class NativeWindowMac : public NativeWindow, // The "titleBarStyle" option. TitleBarStyle title_bar_style_; + std::string tabbing_identifier_; + DISALLOW_COPY_AND_ASSIGN(NativeWindowMac); }; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index c88469a9c8a1..f73cda1fd07c 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -656,7 +656,8 @@ NativeWindowMac::NativeWindowMac( was_fullscreen_(false), zoom_to_page_width_(false), attention_request_id_(0), - title_bar_style_(NORMAL) { + title_bar_style_(NORMAL), + tabbing_identifier_(""){ int width = 800, height = 600; options.Get(options::kWidth, &width); options.Get(options::kHeight, &height); @@ -682,6 +683,8 @@ NativeWindowMac::NativeWindowMac( options.Get(options::kTitleBarStyle, &title_bar_style_); + options.Get(options::kTabbingIdentifier, &tabbing_identifier_); + std::string windowType; options.Get(options::kType, &windowType); @@ -754,6 +757,16 @@ NativeWindowMac::NativeWindowMac( [window_ setOpaque:NO]; } + if (base::mac::IsAtLeastOS10_12()) { + // Create a tab only if tabbing identifier is specified and window has + // a native title bar. + if (tabbing_identifier_.empty() || transparent() || !has_frame()) { + [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + } else { + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + } + } + // We will manage window's lifetime ourselves. [window_ setReleasedWhenClosed:NO]; diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index d040489b9f76..288fcd3a0753 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -51,6 +51,9 @@ const char kZoomToPageWidth[] = "zoomToPageWidth"; // The requested title bar style for the window const char kTitleBarStyle[] = "titleBarStyle"; +// Tabbing identifier for the window if native tabs are enabled on macOS. +const char kTabbingIdentifier[] = "tabbingIdentifier"; + // The menu bar is hidden unless "Alt" is pressed. const char kAutoHideMenuBar[] = "autoHideMenuBar"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index dd2824c55c74..9e1a71ca5bda 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -36,6 +36,7 @@ extern const char kAcceptFirstMouse[]; extern const char kUseContentSize[]; extern const char kZoomToPageWidth[]; extern const char kTitleBarStyle[]; +extern const char kTabbingIdentifier[]; extern const char kAutoHideMenuBar[]; extern const char kEnableLargerThanScreen[]; extern const char kDarkTheme[]; diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 182e798158b1..73b7fe9c18b8 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -264,6 +264,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. canvas features. Default is `false`. * `scrollBounce` Boolean (optional) - Enables scroll bounce (rubber banding) effect on macOS. Default is `false`. + * `tabbingIdentifier` String (optional) - Tab group name, allows opening the + window as a native tab on macOS 10.12+. Windows with the same tabbing identifier will + be grouped together. * `blinkFeatures` String (optional) - A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature strings can be found in the [RuntimeEnabledFeatures.json5][blink-feature-string] From 99293dd57ffd152e68cf549041680145c495da24 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 29 Mar 2017 20:47:41 +0200 Subject: [PATCH 052/337] Fix namespace comments. --- atom/browser/auto_updater_mac.mm | 2 +- atom/browser/osr/osr_render_widget_host_view_mac.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/auto_updater_mac.mm b/atom/browser/auto_updater_mac.mm index a6102f3e73fa..3802fef16299 100644 --- a/atom/browser/auto_updater_mac.mm +++ b/atom/browser/auto_updater_mac.mm @@ -27,7 +27,7 @@ namespace { bool g_update_available = false; std::string update_url_ = ""; -} +} // namespace std::string AutoUpdater::GetFeedURL() { return update_url_; diff --git a/atom/browser/osr/osr_render_widget_host_view_mac.mm b/atom/browser/osr/osr_render_widget_host_view_mac.mm index 664261947d1d..7cf010ff8e28 100644 --- a/atom/browser/osr/osr_render_widget_host_view_mac.mm +++ b/atom/browser/osr/osr_render_widget_host_view_mac.mm @@ -145,4 +145,4 @@ OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const { return browser_compositor_->GetDelegatedFrameHost(); } -} // namespace +} // namespace atom From 8b4bf1f29ed5629037c93525beabab246e9eda92 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 12:27:59 -0700 Subject: [PATCH 053/337] :art: --- lib/browser/api/menu-item-roles.js | 20 +++++++++----------- spec/api-menu-spec.js | 5 +++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.js index 30ea3f888dba..af0d35b4a56a 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.js @@ -155,7 +155,7 @@ const roles = { }) } }, - // submenu Edit (should fit both Mac & Windows) + // Edit submenu (should fit both Mac & Windows) editMenu: { label: 'Edit', submenu: [ @@ -196,7 +196,7 @@ const roles = { ] }, - // submenu Window should be used for Mac only + // Window submenu should be used for Mac only windowMenu: { label: 'Window', submenu: [ @@ -239,18 +239,16 @@ exports.getDefaultAccelerator = (role) => { } exports.getDefaultSubmenu = (role) => { - if (roles.hasOwnProperty(role)) { - let submenu = roles[role].submenu + if (!roles.hasOwnProperty(role)) return - // remove empty objects from within the submenu - if (Array.isArray(submenu)) { - submenu = submenu.filter(function (n) { - return n != null - }) - } + let {submenu} = roles[role] - return submenu + // remove null items from within the submenu + if (Array.isArray(submenu)) { + submenu = submenu.filter((item) => item != null) } + + return submenu } exports.execute = (role, focusedWindow, focusedWebContents) => { diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index 0d809789d71e..9b1f3de36906 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -465,17 +465,20 @@ describe('menu module', function () { assert.equal(item.submenu.items[3].role, 'cut') assert.equal(item.submenu.items[4].role, 'copy') assert.equal(item.submenu.items[5].role, 'paste') + if (process.platform === 'darwin') { assert.equal(item.submenu.items[6].role, 'pasteandmatchstyle') assert.equal(item.submenu.items[7].role, 'delete') assert.equal(item.submenu.items[8].role, 'selectall') } + if (process.platform === 'win32') { assert.equal(item.submenu.items[6].role, 'delete') assert.equal(item.submenu.items[7].type, 'separator') assert.equal(item.submenu.items[8].role, 'selectall') } }) + it('overrides default layout when submenu is specified', function () { var item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]}) assert.equal(item.label, 'Edit') @@ -489,11 +492,13 @@ describe('menu module', function () { assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'minimize') assert.equal(item.submenu.items[1].role, 'close') + if (process.platform === 'darwin') { assert.equal(item.submenu.items[2].type, 'separator') assert.equal(item.submenu.items[3].role, 'front') } }) + it('overrides default layout when submenu is specified', function () { var item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]}) assert.equal(item.label, 'Window') From 5f724e57bccd3c1d4b84f7516db41d4ea8c78e8c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 29 Mar 2017 21:29:52 +0200 Subject: [PATCH 054/337] Avoid unnecessary copy of parameters. --- atom/browser/api/atom_api_session.cc | 2 +- atom/browser/api/atom_api_web_contents.cc | 2 +- atom/browser/browser.h | 2 +- atom/browser/browser_linux.cc | 2 +- atom/browser/browser_mac.mm | 2 +- atom/browser/browser_win.cc | 2 +- atom/renderer/atom_sandboxed_renderer_client.cc | 2 +- atom/renderer/atom_sandboxed_renderer_client.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 0c850888e8e7..83d103a631f7 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -233,7 +233,7 @@ class ResolveProxyHelper { public: ResolveProxyHelper(AtomBrowserContext* browser_context, const GURL& url, - Session::ResolveProxyCallback callback) + const Session::ResolveProxyCallback& callback) : callback_(callback), original_thread_(base::ThreadTaskRunnerHandle::Get()) { scoped_refptr context_getter = diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index a0100fd65c6e..9390777f9c58 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -240,7 +240,7 @@ content::ServiceWorkerContext* GetServiceWorkerContext( } // Called when CapturePage is done. -void OnCapturePageDone(base::Callback callback, +void OnCapturePageDone(const base::Callback& callback, const SkBitmap& bitmap, content::ReadbackResponse response) { callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap)); diff --git a/atom/browser/browser.h b/atom/browser/browser.h index 28103a99c704..78cac65f7e40 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -102,7 +102,7 @@ class Browser : public WindowListObserver { std::vector args; }; void SetLoginItemSettings(LoginItemSettings settings); - LoginItemSettings GetLoginItemSettings(LoginItemSettings options); + LoginItemSettings GetLoginItemSettings(const LoginItemSettings& options); #if defined(OS_MACOSX) // Hide the application. diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc index 6abfcf5c3481..4dd799dfaf02 100644 --- a/atom/browser/browser_linux.cc +++ b/atom/browser/browser_linux.cc @@ -64,7 +64,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) { } Browser::LoginItemSettings Browser::GetLoginItemSettings( - LoginItemSettings options) { + const LoginItemSettings& options) { return LoginItemSettings(); } diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index c318cf850701..bbc848cb6990 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -152,7 +152,7 @@ bool Browser::ContinueUserActivity(const std::string& type, } Browser::LoginItemSettings Browser::GetLoginItemSettings( - LoginItemSettings options) { + const LoginItemSettings& options) { LoginItemSettings settings; settings.open_at_login = base::mac::CheckLoginItemStatus( &settings.open_as_hidden); diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 85990bbc67e3..50a9f9da330e 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -287,7 +287,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) { } Browser::LoginItemSettings Browser::GetLoginItemSettings( - LoginItemSettings options) { + const LoginItemSettings& options) { LoginItemSettings settings; base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS); diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index bf9ea6fd9ef8..fe10860621a9 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -236,7 +236,7 @@ void AtomSandboxedRendererClient::WillReleaseScriptContext( void AtomSandboxedRendererClient::InvokeIpcCallback( v8::Handle context, - std::string callback_name, + const std::string& callback_name, std::vector> args) { auto isolate = context->GetIsolate(); auto binding_key = mate::ConvertToV8(isolate, kIpcKey)->ToString(); diff --git a/atom/renderer/atom_sandboxed_renderer_client.h b/atom/renderer/atom_sandboxed_renderer_client.h index 0912c6b24bd0..6754e0cb89d4 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.h +++ b/atom/renderer/atom_sandboxed_renderer_client.h @@ -22,7 +22,7 @@ class AtomSandboxedRendererClient : public content::ContentRendererClient { void WillReleaseScriptContext( v8::Handle context, content::RenderFrame* render_frame); void InvokeIpcCallback(v8::Handle context, - std::string callback_name, + const std::string& callback_name, std::vector> args); // content::ContentRendererClient: void RenderFrameCreated(content::RenderFrame*) override; From bed32682b736e8a4564afc55ea37b8cea2fbc472 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Wed, 29 Mar 2017 14:27:01 +0100 Subject: [PATCH 055/337] Clarification of the chromium sandbox support --- docs/api/sandbox-option.md | 59 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/docs/api/sandbox-option.md b/docs/api/sandbox-option.md index 454a8ad05cca..9598e47257d1 100644 --- a/docs/api/sandbox-option.md +++ b/docs/api/sandbox-option.md @@ -1,9 +1,12 @@ # `sandbox` Option -> Create a browser window with renderer that can run inside chromium OS sandbox. +> Create a browser window with a renderer that can run inside Chromium OS sandbox. With this +option enabled, the renderer must communicate via IPC to the main process in order to access node APIs. +However, in order to enable the Chromium OS sandbox, electron must be run with the `--enable-sandbox` +command line argument. -One of chromium key security features is that all blink rendering/javascript -code is confined in a sandbox. This sandbox uses OS-specific features to ensure +One of the key security features of Chromium is that all blink rendering/JavaScript +code is executed within a sandbox. This sandbox uses OS-specific features to ensure that exploits in the renderer process cannot harm the system. In other words, when the sandbox is enabled, the renderers can only make changes @@ -12,10 +15,10 @@ to the system by delegating tasks to the main process via IPC. information about the sandbox. Since a major feature in electron is the ability to run node.js in the -renderer process(making it easier to develop desktop applications using only web -technologies), the sandbox has to disabled by electron. One of the reasons is -that most node.js APIs require system access. `require()` for example, is not -possible without file system permissions, which are unavailable in a sandboxed +renderer process (making it easier to develop desktop applications using web +technologies), the sandbox is disabled by electron. This is because +most node.js APIs require system access. `require()` for example, is not +possible without file system permissions, which are not available in a sandboxed environment. Usually this is not a problem for desktop applications since the code is always @@ -25,16 +28,16 @@ untrusted web content. For applications that require more security, the compatible with the sandbox. A sandboxed renderer doesn't have a node.js environment running and doesn't -expose javascript APIs to client code. The only exception is the preload script, -which has access to a subset of electron renderer API. +expose node.js JavaScript APIs to client code. The only exception is the preload script, +which has access to a subset of the electron renderer API. Another difference is that sandboxed renderers don't modify any of the default -javascript APIs. Consequently, some APIs such as `window.open` will work as they -do in chromium(no `BrowserWindowProxy`). +JavaScript APIs. Consequently, some APIs such as `window.open` will work as they +do in chromium (i.e. they do not return a `BrowserWindowProxy`). ## Example -Create a sandboxed window, simply pass `sandbox: true` to `webPreferences`: +To create a sandboxed window, simply pass `sandbox: true` to `webPreferences`: ```js let win @@ -48,9 +51,15 @@ app.on('ready', () => { }) ``` -This alone won't enable the OS-enforced sandbox. To use it, the +In the above code the `BrowserWindow` that was created has node.js disabled and can communicate +only via IPC. The use of this option stops electron from creating a node.js runtime in the renderer. Also, +within this new window `window.open` follows the native behaviour (by default electron creates a `BrowserWindow` +and returns a proxy to this via `window.open`). + +It is important to note that this option alone won't enable the OS-enforced sandbox. To enable this feature, the `--enable-sandbox` command-line argument must be passed to electron, which will -force `sandbox: true` to all BrowserWindow instances. +force `sandbox: true` for all `BrowserWindow` instances. + ```js let win @@ -64,7 +73,7 @@ app.on('ready', () => { Note that it is not enough to call `app.commandLine.appendSwitch('--enable-sandbox')`, as electron/node startup code runs after it is possible to make changes to chromium sandbox settings. The -switch must be passed to electron command-line: +switch must be passed to electron on the command-line: ``` electron --enable-sandbox app.js @@ -125,16 +134,16 @@ window.open = customWindowOpen Important things to notice in the preload script: - Even though the sandboxed renderer doesn't have node.js running, it still has - access to a limited node-like environment:`Buffer`, `process`, `setImmediate` + access to a limited node-like environment: `Buffer`, `process`, `setImmediate` and `require` are available. -- The preload can indirectly access all APIs from the main process through the - `remote` and `ipcRenderer` modules. This is how `fs`(used above) and other +- The preload script can indirectly access all APIs from the main process through the + `remote` and `ipcRenderer` modules. This is how `fs` (used above) and other modules are implemented: They are proxies to remote counterparts in the main process. -- The preload must be contained in a single script, but it is possible to have +- The preload script must be contained in a single script, but it is possible to have complex preload code composed with multiple modules by using a tool like browserify, as explained below. In fact, browserify is already used by - electron to provide a node-like environment to the preload script. + electron to provide a node-like environment to the preload script. To create a browserify bundle and use it as a preload script, something like the following should be used: @@ -146,7 +155,7 @@ the following should be used: The `-x` flag should be used with any required module that is already exposed in the preload scope, and tells browserify to use the enclosing `require` function -for it. `--insert-global-vars` will ensure that `process`,`Buffer` and +for it. `--insert-global-vars` will ensure that `process`, `Buffer` and `setImmediate` are also taken from the enclosing scope(normally browserify injects code for those). @@ -154,7 +163,7 @@ Currently the `require` function provided in the preload scope exposes the following modules: - `child_process` -- `electron`(crashReporter, remote and ipcRenderer) +- `electron` (crashReporter, remote and ipcRenderer) - `fs` - `os` - `timers` @@ -166,7 +175,7 @@ module in the main process can already be used through ## Status -Please use the `sandbox` option with care, as it still is an experimental +Please use the `sandbox` option with care, as it is still an experimental feature. We are still not aware of the security implications of exposing some electron renderer APIs to the preload script, but here are some things to consider before rendering untrusted content: @@ -176,11 +185,11 @@ consider before rendering untrusted content: APIs, effectively granting full access to the system through the `remote` module. -Since renderering untrusted content in electron is still uncharted territory, +Since rendering untrusted content in electron is still uncharted territory, the APIs exposed to the sandbox preload script should be considered more unstable than the rest of electron APIs, and may have breaking changes to fix security issues. One planned enhancement that should greatly increase security is to block IPC -messages from sandboxed renderers by default, allowing the main process +messages from sandboxed renderers by default, allowing the main process to explicitly define a set of messages the renderer is allowed to send. From bd935b213f2c9a9aa1807aefecb33d8c47aaead1 Mon Sep 17 00:00:00 2001 From: Tony Ganch Date: Thu, 30 Mar 2017 15:13:49 +0200 Subject: [PATCH 056/337] Fix compilation against macOS 10.10 SDK --- atom/browser/native_window_mac.mm | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index f73cda1fd07c..f006873efd78 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -336,6 +336,14 @@ bool ScopedDisableResize::disable_resize_ = false; @end +enum { + NSWindowTabbingModeDisallowed = 2 +}; +@interface NSWindow (SierraSDK) +- (void)setTabbingMode:(NSInteger)mode; +- (void)setTabbingIdentifier:(NSString *)identifier; +@end + @interface AtomNSWindow : EventDispatchingWindow { @private atom::NativeWindowMac* shell_; @@ -656,8 +664,7 @@ NativeWindowMac::NativeWindowMac( was_fullscreen_(false), zoom_to_page_width_(false), attention_request_id_(0), - title_bar_style_(NORMAL), - tabbing_identifier_(""){ + title_bar_style_(NORMAL) { int width = 800, height = 600; options.Get(options::kWidth, &width); options.Get(options::kHeight, &height); @@ -761,9 +768,13 @@ NativeWindowMac::NativeWindowMac( // Create a tab only if tabbing identifier is specified and window has // a native title bar. if (tabbing_identifier_.empty() || transparent() || !has_frame()) { - [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + if ([window_ respondsToSelector:@selector(tabbingMode)]) { + [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + } } else { - [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + } } } From d779ecf6745a6cf08ad6fa4c765dfae2474bb1a7 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 30 Mar 2017 11:07:25 -0700 Subject: [PATCH 057/337] create a linkable heading for MenuItem roles --- docs/api/menu-item.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index dc403ea8f7be..494bdb74f196 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -15,7 +15,7 @@ See [`Menu`](menu.md) for examples. * `browserWindow` BrowserWindow * `event` Event * `role` String (optional) - Define the action of the menu item, when specified the - `click` property will be ignored. + `click` property will be ignored. See [roles](#roles). * `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. * `label` String - (optional) @@ -36,12 +36,16 @@ See [`Menu`](menu.md) for examples. * `position` String (optional) - This field allows fine-grained definition of the specific location within a given menu. +### Roles + +Roles allow menu items to have predefined behaviors. + It is best to specify `role` for any menu item that matches a standard role, rather than trying to manually implement the behavior in a `click` function. The built-in `role` behavior will give the best native experience. -The `label` and `accelerator` are optional when using a `role` and will default -to appropriate values for each platform. +The `label` and `accelerator` values are optional when using a `role` and will +default to appropriate values for each platform. The `role` property can have following values: @@ -63,11 +67,10 @@ The `role` property can have following values: * `resetzoom` - Reset the focused page's zoom level to the original size * `zoomin` - Zoom in the focused page by 10% * `zoomout` - Zoom out the focused page by 10% - * `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.) * `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.) -On macOS `role` can also have following additional values: +The following additional roles are avaiable on macOS: * `about` - Map to the `orderFrontStandardAboutPanel` action * `hide` - Map to the `hide` action @@ -81,8 +84,8 @@ On macOS `role` can also have following additional values: * `help` - The submenu is a "Help" menu * `services` - The submenu is a "Services" menu -When specifying `role` on macOS, `label` and `accelerator` are the only options -that will affect the MenuItem. All other options will be ignored. +When specifying a `role` on macOS, `label` and `accelerator` are the only +options that will affect the menu item. All other options will be ignored. ### Instance Properties From b24be19fac195bfd3fe19459c6498851dfa34ebd Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 30 Mar 2017 11:07:59 -0700 Subject: [PATCH 058/337] tighten up formatting of menu example --- docs/api/menu.md | 161 ++++++++++++----------------------------------- 1 file changed, 41 insertions(+), 120 deletions(-) diff --git a/docs/api/menu.md b/docs/api/menu.md index cd6817625a35..391b52d43724 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -115,76 +115,36 @@ const template = [ { label: 'Edit', submenu: [ - { - role: 'undo' - }, - { - role: 'redo' - }, - { - type: 'separator' - }, - { - role: 'cut' - }, - { - role: 'copy' - }, - { - role: 'paste' - }, - { - role: 'pasteandmatchstyle' - }, - { - role: 'delete' - }, - { - role: 'selectall' - } + {role: 'undo'}, + {role: 'redo'}, + {type: 'separator'}, + {role: 'cut'}, + {role: 'copy'}, + {role: 'paste'}, + {role: 'pasteandmatchstyle'}, + {role: 'delete'}, + {role: 'selectall'} ] }, { label: 'View', submenu: [ - { - role: 'reload' - }, - { - role: 'forcereload' - }, - { - role: 'toggledevtools' - }, - { - type: 'separator' - }, - { - role: 'resetzoom' - }, - { - role: 'zoomin' - }, - { - role: 'zoomout' - }, - { - type: 'separator' - }, - { - role: 'togglefullscreen' - } + {role: 'reload'}, + {role: 'forcereload'}, + {role: 'toggledevtools'}, + {type: 'separator'}, + {role: 'resetzoom'}, + {role: 'zoomin'}, + {role: 'zoomout'}, + {type: 'separator'}, + {role: 'togglefullscreen'} ] }, { role: 'window', submenu: [ - { - role: 'minimize' - }, - { - role: 'close' - } + {role: 'minimize'}, + {role: 'close'} ] }, { @@ -202,76 +162,37 @@ if (process.platform === 'darwin') { template.unshift({ label: app.getName(), submenu: [ - { - role: 'about' - }, - { - type: 'separator' - }, - { - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - role: 'hide' - }, - { - role: 'hideothers' - }, - { - role: 'unhide' - }, - { - type: 'separator' - }, - { - role: 'quit' - } + {role: 'about'}, + {type: 'separator'}, + {role: 'services', submenu: []}, + {type: 'separator'}, + {role: 'hide'}, + {role: 'hideothers'}, + {role: 'unhide'}, + {type: 'separator'}, + {role: 'quit'} ] }) - // Edit menu. + + // Edit menu template[1].submenu.push( - { - type: 'separator' - }, + {type: 'separator'}, { label: 'Speech', submenu: [ - { - role: 'startspeaking' - }, - { - role: 'stopspeaking' - } + {role: 'startspeaking'}, + {role: 'stopspeaking'} ] } ) - // Window menu. + + // Window menu template[3].submenu = [ - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Zoom', - role: 'zoom' - }, - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } + {role: 'close'}, + {role: 'minimize'}, + {role: 'zoom'}, + {type: 'separator'}, + {role: 'front'} ] } From d5bc8990fc18a9e0af7a34b82f7c3933824e0c50 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 30 Mar 2017 11:08:12 -0700 Subject: [PATCH 059/337] link to roles list from Menu doc --- docs/api/menu.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/menu.md b/docs/api/menu.md index 391b52d43724..42724e1d4afc 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -30,8 +30,8 @@ Returns `Menu` - The application menu, if set, or `null`, if not set. * `action` String Sends the `action` to the first responder of application. This is used for -emulating default Cocoa menu behaviors, usually you would just use the -`role` property of `MenuItem`. +emulating default macOS menu behaviors. Usually you would just use the +[`role`](menu-item.md#roles) property of a [`MenuItem`](menu-item.md). See the [macOS Cocoa Event Handling Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html#//apple_ref/doc/uid/10000060i-CH3-SW7) for more information on macOS' native actions. From 55bf2239dfa332197abd54874ddfb6a55c43119e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 11:58:09 -0700 Subject: [PATCH 060/337] Remove spaces around brackets --- docs/api/remote.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/remote.md b/docs/api/remote.md index 2db8d17c9992..2abb2a843110 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -158,7 +158,7 @@ project/ ```js // main process: main/index.js -const { app } = require('electron') +const {app} = require('electron') app.on('ready', () => { /* ... */ }) ``` From b3cf00a19aa57c32774e60eb2a0b70c0f25aef1e Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 30 Mar 2017 13:24:40 -0300 Subject: [PATCH 061/337] Fix net module to accept non-string header values This is required to be compatible with node.js http module. --- docs/api/client-request.md | 7 ++++--- lib/browser/api/net.js | 4 ++-- spec/api-net-spec.js | 43 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 4a16d9510ec4..9821b44261a5 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -158,17 +158,18 @@ internally buffered inside Electron process memory. #### `request.setHeader(name, value)` * `name` String - An extra HTTP header name. -* `value` String - An extra HTTP header value. +* `value` Object - An extra HTTP header value. Adds an extra HTTP header. The header name will issued as it is without lowercasing. It can be called only before first write. Calling this method after -the first write will throw an error. +the first write will throw an error. If the passed value is not a `String`, its +`toString()` method will be called to obtain the final value. #### `request.getHeader(name)` * `name` String - Specify an extra header name. -Returns String - The value of a previously set extra header name. +Returns Object - The value of a previously set extra header name. #### `request.removeHeader(name)` diff --git a/lib/browser/api/net.js b/lib/browser/api/net.js index 049cef9e3ab4..5a4d23b07397 100644 --- a/lib/browser/api/net.js +++ b/lib/browser/api/net.js @@ -246,7 +246,7 @@ class ClientRequest extends EventEmitter { if (typeof name !== 'string') { throw new TypeError('`name` should be a string in setHeader(name, value).') } - if (value === undefined) { + if (value == null) { throw new Error('`value` required in setHeader("' + name + '", value).') } if (!this.urlRequest.notStarted) { @@ -255,7 +255,7 @@ class ClientRequest extends EventEmitter { const key = name.toLowerCase() this.extraHeaders[key] = value - this.urlRequest.setExtraHeader(name, value) + this.urlRequest.setExtraHeader(name, value.toString()) } getHeader (name) { diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index 68db813d6495..ec4f45fb7246 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -364,6 +364,49 @@ describe('net module', function () { urlRequest.end() }) + it('should be able to set a non-string object as a header value', function (done) { + const requestUrl = '/requestUrl' + const customHeaderName = 'Some-Integer-Value' + const customHeaderValue = 900 + server.on('request', function (request, response) { + switch (request.url) { + case requestUrl: + assert.equal(request.headers[customHeaderName.toLowerCase()], + customHeaderValue.toString()) + response.statusCode = 200 + response.statusMessage = 'OK' + response.end() + break + default: + assert.equal(request.url, requestUrl) + } + }) + const urlRequest = net.request({ + method: 'GET', + url: `${server.url}${requestUrl}` + }) + urlRequest.on('response', function (response) { + const statusCode = response.statusCode + assert.equal(statusCode, 200) + response.pause() + response.on('end', function () { + done() + }) + response.resume() + }) + urlRequest.setHeader(customHeaderName, customHeaderValue) + assert.equal(urlRequest.getHeader(customHeaderName), + customHeaderValue) + assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()), + customHeaderValue) + urlRequest.write('') + assert.equal(urlRequest.getHeader(customHeaderName), + customHeaderValue) + assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()), + customHeaderValue) + urlRequest.end() + }) + it('should not be able to set a custom HTTP request header after first write', function (done) { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' From 4001ba038e66812c50707687114f7cadf87c6bf0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 12:06:33 -0700 Subject: [PATCH 062/337] Add descriptions for each segmentStyle --- docs/api/touch-bar-segmented-control.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/api/touch-bar-segmented-control.md b/docs/api/touch-bar-segmented-control.md index 4ea037057670..42be09079082 100644 --- a/docs/api/touch-bar-segmented-control.md +++ b/docs/api/touch-bar-segmented-control.md @@ -8,14 +8,19 @@ Process: [Main](../tutorial/quick-start.md#main-process) * `options` Object * `segmentStyle` String - (Optional) Style of the segments: - * `automatic` - Default - * `rounded` - * `textured-rounded` - * `round-rect` - * `textured-square` - * `capsule` - * `small-square` - * `separated` + * `automatic` - Default. The appearance of the segmented control is + automatically determined based on the type of window in which the control + is displayed and the position within the window. + * `rounded` - The control is displayed using the rounded style. + * `textured-rounded` - The control is displayed using the textured rounded + style. + * `round-rect` - The control is displayed using the round rect style. + * `textured-square` - The control is displayed using the textured square + style. + * `capsule` - The control is displayed using the capsule style + * `small-square` - The control is displayed using the small square style. + * `separated` - The segments in the control are displayed very close to each + other but not touching. * `segments` [SegmentedControlSegment[]](structures/segmented-control-segment.md) - An array of segments to place in this control * `selectedIndex` Integer (Optional) - The index of the currently selected segment, will update automatically with user interaction * `change` Function - Called when the user selects a new segment From 6ef3be23fd9685a803908cf8aaa20acbe482cb68 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 21:56:28 +0200 Subject: [PATCH 063/337] Avoid copy in for range loop. --- atom/browser/common_web_contents_delegate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 59ffc7dcbc08..f7f9e46250eb 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -338,7 +338,7 @@ void CommonWebContentsDelegate::DevToolsRequestFileSystems() { } std::vector file_systems; - for (auto file_system_path : file_system_paths) { + for (const auto& file_system_path : file_system_paths) { base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path); std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(), path); From 00693ba075504fd006bde3c66ca8dc8bcf31d8fe Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 21:59:18 +0200 Subject: [PATCH 064/337] Replace "size()" with "empty()". --- atom/app/atom_content_client.cc | 2 +- atom/browser/api/atom_api_app.cc | 2 +- atom/browser/api/atom_api_auto_updater.cc | 2 +- atom/browser/browser.cc | 4 ++-- atom/browser/node_debugger.cc | 2 +- atom/browser/ui/cocoa/atom_touch_bar.mm | 2 +- atom/browser/window_list.cc | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/atom/app/atom_content_client.cc b/atom/app/atom_content_client.cc index 954d239b5034..8e2a6c573097 100644 --- a/atom/app/atom_content_client.cc +++ b/atom/app/atom_content_client.cc @@ -44,7 +44,7 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, std::vector flash_version_numbers = base::SplitString( version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - if (flash_version_numbers.size() < 1) + if (flash_version_numbers.empty()) flash_version_numbers.push_back("11"); // |SplitString()| puts in an empty string given an empty string. :( else if (flash_version_numbers[0].empty()) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 56a11daf69bd..c64ad41113f8 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -427,7 +427,7 @@ void OnClientCertificateSelected( auto certs = net::X509Certificate::CreateCertificateListFromBytes( data.c_str(), data.length(), net::X509Certificate::FORMAT_AUTO); - if (certs.size() > 0) + if (!certs.empty()) delegate->ContinueWithCertificate(certs[0].get()); } diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index 67079abf2864..276d889006d1 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -88,7 +88,7 @@ void AutoUpdater::SetFeedURL(const std::string& url, mate::Arguments* args) { void AutoUpdater::QuitAndInstall() { // If we don't have any window then quitAndInstall immediately. WindowList* window_list = WindowList::GetInstance(); - if (window_list->size() == 0) { + if (window_list->empty()) { auto_updater::AutoUpdater::QuitAndInstall(); return; } diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index 9b7423cd7d9f..b18ab7b70fd7 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -44,7 +44,7 @@ void Browser::Quit() { return; atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->size() == 0) + if (window_list->empty()) NotifyAndShutdown(); window_list->CloseAllWindows(); @@ -66,7 +66,7 @@ void Browser::Exit(mate::Arguments* args) { // Must destroy windows before quitting, otherwise bad things can happen. atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->size() == 0) { + if (window_list->empty()) { Shutdown(); } else { // Unlike Quit(), we do not ask to close window, but destroy the window diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc index e95369fba190..9fdeb6099e6a 100644 --- a/atom/browser/node_debugger.cc +++ b/atom/browser/node_debugger.cc @@ -164,7 +164,7 @@ void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket, buffer_.append(data, len); do { - if (buffer_.size() == 0) + if (buffer_.empty()) return; // Read the "Content-Length" header. diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 4952e28876c6..639ec2aaa698 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -319,7 +319,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; - (void)updateColorPicker:(NSColorPickerTouchBarItem*)item withSettings:(const mate::PersistentDictionary&)settings { std::vector colors; - if (settings.Get("availableColors", &colors) && colors.size() > 0) { + if (settings.Get("availableColors", &colors) && !colors.empty()) { NSColorList* color_list = [[[NSColorList alloc] initWithName:@""] autorelease]; for (size_t i = 0; i < colors.size(); ++i) { [color_list insertColor:[self colorFromHexColorString:colors[i]] diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc index b835e07e752a..d627f6d1206b 100644 --- a/atom/browser/window_list.cc +++ b/atom/browser/window_list.cc @@ -46,7 +46,7 @@ void WindowList::RemoveWindow(NativeWindow* window) { for (WindowListObserver& observer : observers_.Get()) observer.OnWindowRemoved(window); - if (windows.size() == 0) { + if (windows.empty()) { for (WindowListObserver& observer : observers_.Get()) observer.OnWindowAllClosed(); } From d425b63b0da1ee7d922b36dde3f8173847ef509e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:12:14 +0200 Subject: [PATCH 065/337] NULL => nullptr --- atom/browser/native_window_mac.mm | 2 +- atom/browser/ui/cocoa/atom_menu_controller.mm | 2 +- atom/browser/ui/file_dialog_mac.mm | 4 ++-- atom/common/platform_util_mac.mm | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index c88469a9c8a1..520ba2d6698e 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1262,7 +1262,7 @@ void NativeWindowMac::SetProgressBar(double progress, const NativeWindow::Progre NSDockTile* dock_tile = [NSApp dockTile]; // For the first time API invoked, we need to create a ContentView in DockTile. - if (dock_tile.contentView == NULL) { + if (dock_tile.contentView == nullptr) { NSImageView* image_view = [[NSImageView alloc] init]; [image_view setImage:[NSApp applicationIconImage]]; [dock_tile setContentView:image_view]; diff --git a/atom/browser/ui/cocoa/atom_menu_controller.mm b/atom/browser/ui/cocoa/atom_menu_controller.mm index b3e293153f96..d0bbf6a153a3 100644 --- a/atom/browser/ui/cocoa/atom_menu_controller.mm +++ b/atom/browser/ui/cocoa/atom_menu_controller.mm @@ -70,7 +70,7 @@ Role kRolesMap[] = { // while its context menu is still open. [self cancel]; - model_ = NULL; + model_ = nullptr; [super dealloc]; } diff --git a/atom/browser/ui/file_dialog_mac.mm b/atom/browser/ui/file_dialog_mac.mm index 70272cbddc8f..80143a987bc7 100644 --- a/atom/browser/ui/file_dialog_mac.mm +++ b/atom/browser/ui/file_dialog_mac.mm @@ -154,7 +154,7 @@ void ShowOpenDialog(const DialogSettings& settings, NSWindow* window = settings.parent_window ? settings.parent_window->GetNativeWindow() : - NULL; + nullptr; [dialog beginSheetModalForWindow:window completionHandler:^(NSInteger chosen) { if (chosen == NSFileHandlingPanelCancelButton) { @@ -193,7 +193,7 @@ void ShowSaveDialog(const DialogSettings& settings, NSWindow* window = settings.parent_window ? settings.parent_window->GetNativeWindow() : - NULL; + nullptr; [dialog beginSheetModalForWindow:window completionHandler:^(NSInteger chosen) { if (chosen == NSFileHandlingPanelCancelButton) { diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index aa64678caffe..4a91efd70538 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -71,10 +71,10 @@ std::string MessageForOSStatus(OSStatus status, const char* default_message) { // thread safe, including LSGetApplicationForURL (> 10.2) and // NSWorkspace#openURLs. std::string OpenURL(NSURL* ns_url, bool activate) { - CFURLRef openingApp = NULL; + CFURLRef openingApp = nullptr; OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, kLSRolesAll, - NULL, + nullptr, &openingApp); if (status != noErr) return MessageForOSStatus(status, "Failed to open"); @@ -156,7 +156,7 @@ bool OpenItem(const base::FilePath& full_path) { // Create the list of files (only ever one) to open. base::mac::ScopedAEDesc fileList; - status = AECreateList(NULL, // factoringPtr + status = AECreateList(nullptr, // factoringPtr 0, // factoredSize false, // isRecord fileList.OutPointer()); // resultList @@ -202,8 +202,8 @@ bool OpenItem(const base::FilePath& full_path) { kAENoReply + kAEAlwaysInteract, // sendMode kAENormalPriority, // sendPriority kAEDefaultTimeout, // timeOutInTicks - NULL, // idleProc - NULL); // filterProc + nullptr, // idleProc + nullptr); // filterProc if (status != noErr) { OSSTATUS_LOG(WARNING, status) << "Could not send AE to Finder in OpenItem()"; From 1b9780035c7aeb57ec8e03087aacef1544947abb Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:22:40 +0200 Subject: [PATCH 066/337] Remove redundant calls to smart pointer's get method. --- atom/browser/api/atom_api_app.cc | 6 +++--- atom/browser/net/atom_network_delegate.cc | 2 +- atom/browser/osr/osr_render_widget_host_view.cc | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index c64ad41113f8..709696340274 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -520,7 +520,7 @@ void App::OnQuit() { int exitCode = AtomBrowserMainParts::Get()->GetExitCode(); Emit("quit", exitCode); - if (process_singleton_.get()) { + if (process_singleton_) { process_singleton_->Cleanup(); process_singleton_.reset(); } @@ -695,7 +695,7 @@ std::string App::GetLocale() { bool App::MakeSingleInstance( const ProcessSingleton::NotificationCallback& callback) { - if (process_singleton_.get()) + if (process_singleton_) return false; base::FilePath user_dir; @@ -716,7 +716,7 @@ bool App::MakeSingleInstance( } void App::ReleaseSingleInstance() { - if (process_singleton_.get()) { + if (process_singleton_) { process_singleton_->Cleanup(); process_singleton_.reset(); } diff --git a/atom/browser/net/atom_network_delegate.cc b/atom/browser/net/atom_network_delegate.cc index 2ba3f8e35781..3a5b667f06d0 100644 --- a/atom/browser/net/atom_network_delegate.cc +++ b/atom/browser/net/atom_network_delegate.cc @@ -402,7 +402,7 @@ void AtomNetworkDelegate::OnListenerResultInIO( if (!base::ContainsKey(callbacks_, id)) return; - ReadFromResponseObject(*response.get(), out); + ReadFromResponseObject(*response, out); bool cancel = false; response->GetBoolean("cancel", &cancel); diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc index 7355f1a0c1e2..2003118f389e 100644 --- a/atom/browser/osr/osr_render_widget_host_view.cc +++ b/atom/browser/osr/osr_render_widget_host_view.cc @@ -851,12 +851,12 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval( base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_)); - if (copy_frame_generator_.get()) { + if (copy_frame_generator_) { copy_frame_generator_->set_frame_rate_threshold_ms( frame_rate_threshold_ms_); } - if (begin_frame_timer_.get()) { + if (begin_frame_timer_) { begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_); } else { begin_frame_timer_.reset(new AtomBeginFrameTimer( @@ -871,7 +871,7 @@ void OffScreenRenderWidgetHostView::Invalidate() { if (software_output_device_) { software_output_device_->OnPaint(bounds_in_pixels); - } else if (copy_frame_generator_.get()) { + } else if (copy_frame_generator_) { copy_frame_generator_->GenerateCopyFrame(true, bounds_in_pixels); } } From bb51401c4c13e56c35337ab2f335683eca29a8f5 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:33:09 +0200 Subject: [PATCH 067/337] Use base::mac::NSToCast. --- atom/common/platform_util_mac.mm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index 4a91efd70538..9cbbaedbe181 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -11,6 +11,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/mac/foundation_util.h" #include "base/mac/mac_logging.h" #include "base/mac/scoped_aedesc.h" #include "base/strings/stringprintf.h" @@ -72,10 +73,10 @@ std::string MessageForOSStatus(OSStatus status, const char* default_message) { // NSWorkspace#openURLs. std::string OpenURL(NSURL* ns_url, bool activate) { CFURLRef openingApp = nullptr; - OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, - kLSRolesAll, - nullptr, - &openingApp); + OSStatus status = LSGetApplicationForURL(base::mac::NSToCFCast(ns_url), + kLSRolesAll, + nullptr, + &openingApp); if (status != noErr) return MessageForOSStatus(status, "Failed to open"); @@ -167,7 +168,8 @@ bool OpenItem(const base::FilePath& full_path) { // Add the single path to the file list. C-style cast to avoid both a // static_cast and a const_cast to get across the toll-free bridge. - CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; + CFURLRef pathURLRef = base::mac::NSToCFCast( + [NSURL fileURLWithPath:path_string]); FSRef pathRef; if (CFURLGetFSRef(pathURLRef, &pathRef)) { status = AEPutPtr(fileList.OutPointer(), // theAEDescList From c8b992fa3982ffd880c8c2cc931d5a0c892f56e3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:46:34 -0700 Subject: [PATCH 068/337] Remove 10.12 check handled by respondsToSelector --- atom/browser/native_window_mac.mm | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index f006873efd78..077eee52288f 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -764,17 +764,15 @@ NativeWindowMac::NativeWindowMac( [window_ setOpaque:NO]; } - if (base::mac::IsAtLeastOS10_12()) { - // Create a tab only if tabbing identifier is specified and window has - // a native title bar. - if (tabbing_identifier_.empty() || transparent() || !has_frame()) { - if ([window_ respondsToSelector:@selector(tabbingMode)]) { - [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; - } - } else { - if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { - [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; - } + // Create a tab only if tabbing identifier is specified and window has + // a native title bar. + if (tabbing_identifier_.empty() || transparent() || !has_frame()) { + if ([window_ respondsToSelector:@selector(tabbingMode)]) { + [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; + } + } else { + if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; } } From e699e88b4caed3929ce8b3e077a08660f0612ccc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:46:58 -0700 Subject: [PATCH 069/337] Add initial tabbingIdentifier spec --- spec/api-browser-window-spec.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index b5985e4b7406..d83c173f26f1 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -692,7 +692,7 @@ describe('BrowserWindow module', function () { }) }) - describe('"title-bar-style" option', function () { + describe('"titleBarStyle" option', function () { if (process.platform !== 'darwin') { return } @@ -772,6 +772,20 @@ describe('BrowserWindow module', function () { }) }) + describe('"tabbingIdentifier" option', function () { + it('can be set on a window', function () { + w.destroy() + w = new BrowserWindow({ + tabbingIdentifier: 'group1' + }) + w.destroy() + w = new BrowserWindow({ + tabbingIdentifier: 'group2', + frame: false + }) + }) + }) + describe('"web-preferences" option', function () { afterEach(function () { ipcMain.removeAllListeners('answer') From 42300ae58ef31a911a20828718741275f0fdf067 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:47:11 -0700 Subject: [PATCH 070/337] Make tabbing identifier var local --- atom/browser/native_window_mac.h | 2 -- atom/browser/native_window_mac.mm | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 066bcc503ea9..bd34993fb119 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -179,8 +179,6 @@ class NativeWindowMac : public NativeWindow, // The "titleBarStyle" option. TitleBarStyle title_bar_style_; - std::string tabbing_identifier_; - DISALLOW_COPY_AND_ASSIGN(NativeWindowMac); }; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 077eee52288f..2912022bd634 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -690,7 +690,8 @@ NativeWindowMac::NativeWindowMac( options.Get(options::kTitleBarStyle, &title_bar_style_); - options.Get(options::kTabbingIdentifier, &tabbing_identifier_); + std::string tabbingIdentifier; + options.Get(options::kTabbingIdentifier, &tabbingIdentifier); std::string windowType; options.Get(options::kType, &windowType); @@ -766,13 +767,13 @@ NativeWindowMac::NativeWindowMac( // Create a tab only if tabbing identifier is specified and window has // a native title bar. - if (tabbing_identifier_.empty() || transparent() || !has_frame()) { + if (tabbingIdentifier.empty() || transparent() || !has_frame()) { if ([window_ respondsToSelector:@selector(tabbingMode)]) { [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; } } else { if ([window_ respondsToSelector:@selector(tabbingIdentifier)]) { - [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbing_identifier_)]; + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbingIdentifier)]; } } From 6f27d466a508852455d973441f99dbdf77a483ab Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 13:49:00 -0700 Subject: [PATCH 071/337] Move tabbingIdentifier out of webPreferences list --- docs/api/browser-window.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 73b7fe9c18b8..01f5431ecf73 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -211,6 +211,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. width of the web page when zoomed, `false` will cause it to zoom to the width of the screen. This will also affect the behavior when calling `maximize()` directly. Default is `false`. + * `tabbingIdentifier` String (optional) - Tab group name, allows opening the + window as a native tab on macOS 10.12+. Windows with the same tabbing + identifier will be grouped together. * `webPreferences` Object (optional) - Settings of web page's features. * `devTools` Boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. * `nodeIntegration` Boolean (optional) - Whether node integration is enabled. Default @@ -264,9 +267,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. canvas features. Default is `false`. * `scrollBounce` Boolean (optional) - Enables scroll bounce (rubber banding) effect on macOS. Default is `false`. - * `tabbingIdentifier` String (optional) - Tab group name, allows opening the - window as a native tab on macOS 10.12+. Windows with the same tabbing identifier will - be grouped together. * `blinkFeatures` String (optional) - A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature strings can be found in the [RuntimeEnabledFeatures.json5][blink-feature-string] From 8d8c7ce6ad37ce0b512d0775b297c2880e401927 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:53:20 +0200 Subject: [PATCH 072/337] Correct type cast. --- atom/browser/browser_mac.mm | 3 ++- atom/browser/ui/cocoa/atom_touch_bar.mm | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index bbc848cb6990..f231d7a4f0ae 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -65,7 +65,8 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol, // Apple's defaults first, so we'll use the first option that isn't our bundle CFStringRef other = nil; for (CFIndex i = 0; i < CFArrayGetCount(bundleList); i++) { - other = (CFStringRef)CFArrayGetValueAtIndex(bundleList, i); + other = base::mac::CFCast(CFArrayGetValueAtIndex(bundleList, + i)); if (![identifier isEqualToString: (__bridge NSString *)other]) { break; } diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 639ec2aaa698..6e3fc838c157 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -474,7 +474,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; settings.Get("segments", &segments); control.segmentCount = segments.size(); - for (int i = 0; i < (int)segments.size(); i++) { + for (size_t i = 0; i < segments.size(); i++) { std::string label; gfx::Image image; bool enabled = true; @@ -581,7 +581,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; std::vector items; if (!settings.Get("items", &items)) return nil; - if (index >= (long)items.size()) return nil; + if (index >= static_cast(items.size())) return nil; mate::PersistentDictionary item = items[index]; From ff745e1a823b059c243aa39895e7160b69a7a0b6 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 22:56:21 +0200 Subject: [PATCH 073/337] Use prefix increment in for loops. --- atom/browser/browser_mac.mm | 2 +- atom/browser/ui/cocoa/atom_touch_bar.mm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index f231d7a4f0ae..1a15bc013917 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -64,7 +64,7 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol, // On macOS, we can't query the default, but the handlers list seems to put // Apple's defaults first, so we'll use the first option that isn't our bundle CFStringRef other = nil; - for (CFIndex i = 0; i < CFArrayGetCount(bundleList); i++) { + for (CFIndex i = 0; i < CFArrayGetCount(bundleList); ++i) { other = base::mac::CFCast(CFArrayGetValueAtIndex(bundleList, i)); if (![identifier isEqualToString: (__bridge NSString *)other]) { diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 6e3fc838c157..69926684b67a 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -414,7 +414,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; NSMutableArray* generatedItems = [NSMutableArray array]; NSMutableArray* identifiers = [self identifiersFromSettings:items]; - for (NSUInteger i = 0; i < [identifiers count]; i++) { + for (NSUInteger i = 0; i < [identifiers count]; ++i) { if ([identifiers objectAtIndex:i] != NSTouchBarItemIdentifierOtherItemsProxy) { NSTouchBarItem* generatedItem = [self makeItemForIdentifier:[identifiers objectAtIndex:i]]; if (generatedItem) { @@ -474,7 +474,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; settings.Get("segments", &segments); control.segmentCount = segments.size(); - for (size_t i = 0; i < segments.size(); i++) { + for (size_t i = 0; i < segments.size(); ++i) { std::string label; gfx::Image image; bool enabled = true; From fcb7cbc54a552f67a064ca564fdf898cdcc91746 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 12:37:40 -0700 Subject: [PATCH 074/337] Check name directly instead of arguments length --- lib/browser/api/net.js | 4 ++-- spec/api-net-spec.js | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/browser/api/net.js b/lib/browser/api/net.js index 5a4d23b07397..d32f6946eee5 100644 --- a/lib/browser/api/net.js +++ b/lib/browser/api/net.js @@ -259,7 +259,7 @@ class ClientRequest extends EventEmitter { } getHeader (name) { - if (arguments.length < 1) { + if (name == null) { throw new Error('`name` is required for getHeader(name).') } @@ -272,7 +272,7 @@ class ClientRequest extends EventEmitter { } removeHeader (name) { - if (arguments.length < 1) { + if (name == null) { throw new Error('`name` is required for removeHeader(name).') } diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index ec4f45fb7246..dc024553a858 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -960,6 +960,26 @@ describe('net module', function () { }, 'redirect mode should be one of follow, error or manual') }) + it('should throw when calling getHeader without a name', function () { + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).getHeader() + }, /`name` is required for getHeader\(name\)\./) + + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).getHeader(null) + }, /`name` is required for getHeader\(name\)\./) + }) + + it('should throw when calling removeHeader without a name', function () { + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).removeHeader() + }, /`name` is required for removeHeader\(name\)\./) + + assert.throws(function () { + net.request({url: `${server.url}/requestUrl`}).removeHeader(null) + }, /`name` is required for removeHeader\(name\)\./) + }) + it('should follow redirect when no redirect mode is provided', function (done) { const requestUrl = '/301' server.on('request', function (request, response) { From e8abee9ca904abc744db42dba200c808c6630b1e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 23:05:47 +0200 Subject: [PATCH 075/337] Replace C-style casts with static_cast. --- atom/browser/api/atom_api_dialog.cc | 4 ++-- atom/browser/browser_mac.mm | 2 +- atom/browser/native_window_mac.mm | 12 ++++++------ atom/browser/web_contents_permission_helper.cc | 6 +++--- .../native_mate_converters/content_converter.cc | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 326834472d24..c226d3d20218 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -78,11 +78,11 @@ void ShowMessageBox(int type, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, + atom::ShowMessageBox(window, static_cast(type), buttons, default_id, cancel_id, options, title, message, detail, checkbox_label, checkbox_checked, icon, callback); } else { - int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, + int chosen = atom::ShowMessageBox(window, static_cast(type), buttons, default_id, cancel_id, options, title, message, detail, icon); args->Return(chosen); diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 1a15bc013917..51604e377cd6 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -180,7 +180,7 @@ std::string Browser::GetExecutableFileProductName() const { int Browser::DockBounce(BounceType type) { return [[AtomApplication sharedApplication] - requestUserAttention:(NSRequestUserAttentionType)type]; + requestUserAttention:static_cast(type)]; } void Browser::DockCancelBounce(int request_id) { diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 520ba2d6698e..4cec64e1cade 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1358,22 +1358,22 @@ void NativeWindowMac::SetVibrancy(const std::string& type) { // they are available in the minimum SDK version if (type == "selection") { // NSVisualEffectMaterialSelection - vibrancyType = (NSVisualEffectMaterial) 4; + vibrancyType = static_cast( 4); } else if (type == "menu") { // NSVisualEffectMaterialMenu - vibrancyType = (NSVisualEffectMaterial) 5; + vibrancyType = static_cast( 5); } else if (type == "popover") { // NSVisualEffectMaterialPopover - vibrancyType = (NSVisualEffectMaterial) 6; + vibrancyType = static_cast( 6); } else if (type == "sidebar") { // NSVisualEffectMaterialSidebar - vibrancyType = (NSVisualEffectMaterial) 7; + vibrancyType = static_cast( 7); } else if (type == "medium-light") { // NSVisualEffectMaterialMediumLight - vibrancyType = (NSVisualEffectMaterial) 8; + vibrancyType = static_cast( 8); } else if (type == "ultra-dark") { // NSVisualEffectMaterialUltraDark - vibrancyType = (NSVisualEffectMaterial) 9; + vibrancyType = static_cast( 9); } } diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc index 2c79270591b8..050e1d6b4a29 100644 --- a/atom/browser/web_contents_permission_helper.cc +++ b/atom/browser/web_contents_permission_helper.cc @@ -66,7 +66,7 @@ void WebContentsPermissionHelper::RequestPermission( void WebContentsPermissionHelper::RequestFullscreenPermission( const base::Callback& callback) { - RequestPermission((content::PermissionType)(PermissionType::FULLSCREEN), + RequestPermission(static_cast(PermissionType::FULLSCREEN), callback); } @@ -86,7 +86,7 @@ void WebContentsPermissionHelper::RequestWebNotificationPermission( void WebContentsPermissionHelper::RequestPointerLockPermission( bool user_gesture) { - RequestPermission((content::PermissionType)(PermissionType::POINTER_LOCK), + RequestPermission(static_cast(PermissionType::POINTER_LOCK), base::Bind(&OnPointerLockResponse, web_contents_), user_gesture); } @@ -94,7 +94,7 @@ void WebContentsPermissionHelper::RequestPointerLockPermission( void WebContentsPermissionHelper::RequestOpenExternalPermission( const base::Callback& callback, bool user_gesture) { - RequestPermission((content::PermissionType)(PermissionType::OPEN_EXTERNAL), + RequestPermission(static_cast(PermissionType::OPEN_EXTERNAL), callback, user_gesture); } diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index 72f1011a72c3..444faa697247 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -168,11 +168,11 @@ v8::Local Converter::ToV8( break; } - if (val == (content::PermissionType)(PermissionType::POINTER_LOCK)) + if (val == static_cast(PermissionType::POINTER_LOCK)) return StringToV8(isolate, "pointerLock"); - else if (val == (content::PermissionType)(PermissionType::FULLSCREEN)) + else if (val == static_cast(PermissionType::FULLSCREEN)) return StringToV8(isolate, "fullscreen"); - else if (val == (content::PermissionType)(PermissionType::OPEN_EXTERNAL)) + else if (val == static_cast(PermissionType::OPEN_EXTERNAL)) return StringToV8(isolate, "openExternal"); return StringToV8(isolate, "unknown"); From 328cf4789bc021a4cd1664245cae0619530d13a3 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 30 Mar 2017 23:13:23 +0200 Subject: [PATCH 076/337] Should override the virtual destructor. --- atom/browser/net/atom_cert_verifier.cc | 2 +- atom/browser/web_dialog_helper.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/net/atom_cert_verifier.cc b/atom/browser/net/atom_cert_verifier.cc index 5dee107eb36e..2a2229f19d1f 100644 --- a/atom/browser/net/atom_cert_verifier.cc +++ b/atom/browser/net/atom_cert_verifier.cc @@ -50,7 +50,7 @@ class CertVerifierRequest : public AtomCertVerifier::Request { first_response_(true), weak_ptr_factory_(this) {} - ~CertVerifierRequest() { + ~CertVerifierRequest() override { cert_verifier_->RemoveRequest(params_); default_verifier_request_.reset(); while (!response_list_.empty() && !first_response_) { diff --git a/atom/browser/web_dialog_helper.cc b/atom/browser/web_dialog_helper.cc index 448fccd31f5a..fcd598b1aaea 100644 --- a/atom/browser/web_dialog_helper.cc +++ b/atom/browser/web_dialog_helper.cc @@ -51,7 +51,7 @@ class FileSelectHelper : public base::RefCounted, private: friend class base::RefCounted; - ~FileSelectHelper() {} + ~FileSelectHelper() override {} void OnOpenDialogDone(bool result, const std::vector& paths) { std::vector file_info; From 64369cd07fa2b90dbe4aa978bd7baf32721b1cae Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 30 Mar 2017 17:25:44 -0400 Subject: [PATCH 077/337] Show a certificate trust panel --- atom/browser/api/atom_api_certificate_trust.h | 33 +++++++++++++ .../api/atom_api_certificate_trust_mac.mm | 48 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 atom/browser/api/atom_api_certificate_trust.h create mode 100644 atom/browser/api/atom_api_certificate_trust_mac.mm diff --git a/atom/browser/api/atom_api_certificate_trust.h b/atom/browser/api/atom_api_certificate_trust.h new file mode 100644 index 000000000000..c3e6994b3baf --- /dev/null +++ b/atom/browser/api/atom_api_certificate_trust.h @@ -0,0 +1,33 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_API_ATOM_API_CERTIFICATE_TRUST_H_ +#define ATOM_BROWSER_API_ATOM_API_CERTIFICATE_TRUST_H_ + +#include + +#include "base/callback_forward.h" + +namespace net { +class X509Certificate; +} // namespace net + +namespace atom { + +class NativeWindow; + +namespace api { + +typedef base::Callback ShowTrustCallback; + +void ShowCertificateTrustUI(atom::NativeWindow* parent_window, + const net::X509Certificate& cert, + std::string message, + const ShowTrustCallback& callback); + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_CERTIFICATE_TRUST_H_ diff --git a/atom/browser/api/atom_api_certificate_trust_mac.mm b/atom/browser/api/atom_api_certificate_trust_mac.mm new file mode 100644 index 000000000000..c0109d9f45a7 --- /dev/null +++ b/atom/browser/api/atom_api_certificate_trust_mac.mm @@ -0,0 +1,48 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_certificate_trust.h" + +#import +#import +#import + +#include "atom/browser/native_window.h" +#include "base/files/file_util.h" +#include "base/mac/foundation_util.h" +#include "base/mac/mac_util.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/strings/sys_string_conversions.h" +#include "net/cert/x509_certificate.h" + +namespace atom { + +namespace api { + +void ShowCertificateTrustUI(atom::NativeWindow* parent_window, + const net::X509Certificate& cert, + std::string message, + const ShowTrustCallback& callback) { + auto sec_policy = SecPolicyCreateBasicX509(); + SecTrustRef trust = nullptr; + SecTrustCreateWithCertificates(cert.CreateOSCertChainForCert(), sec_policy, &trust); + // CFRelease(sec_policy); + + NSWindow* window = parent_window ? + parent_window->GetNativeWindow() : + NULL; + + auto msg = base::SysUTF8ToNSString(message); + + SFCertificateTrustPanel *panel = [[SFCertificateTrustPanel alloc] init]; + [panel beginSheetForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL trust:trust message:msg]; + + callback.Run(true); + // CFRelease(trust); + // [panel release]; +} + +} // namespace api + +} // namespace atom From 653b2d15c325638d4a9aca0cba15bb6dcc35a352 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 30 Mar 2017 17:25:55 -0400 Subject: [PATCH 078/337] Expose the certificate trust panel as part of app --- atom/browser/api/atom_api_app.cc | 12 ++++++++++++ atom/browser/api/atom_api_app.h | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 56a11daf69bd..3a8f4ef0f8b5 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/api/atom_api_certificate_trust.h" #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_session.h" #include "atom/browser/api/atom_api_web_contents.h" @@ -810,6 +811,16 @@ void App::OnCertificateManagerModelCreated( } #endif +#if defined(OS_MACOSX) +void App::ShowCertificateTrust(atom::NativeWindow* parent_window, + const net::X509Certificate& cert, + std::string message, + const ShowTrustCallback& callback, + mate::Arguments* args) { + ShowCertificateTrustUI(parent_window, cert, message, callback); +} +#endif + #if defined(OS_WIN) v8::Local App::GetJumpListSettings() { JumpList jump_list(Browser::Get()->GetAppUserModelID()); @@ -949,6 +960,7 @@ void App::BuildPrototype( base::Bind(&Browser::GetCurrentActivityType, browser)) .SetMethod("setAboutPanelOptions", base::Bind(&Browser::SetAboutPanelOptions, browser)) + // .SetMethod("showCertificateTrust", &App::ShowCertificateTrust) #endif #if defined(OS_WIN) .SetMethod("setUserTasks", base::Bind(&Browser::SetUserTasks, browser)) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 8b276f334d5c..367709cf0c6f 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -8,6 +8,7 @@ #include #include +#include "atom/browser/api/atom_api_certificate_trust.h" #include "atom/browser/api/event_emitter.h" #include "atom/browser/atom_browser_client.h" #include "atom/browser/browser.h" @@ -19,6 +20,7 @@ #include "content/public/browser/gpu_data_manager_observer.h" #include "native_mate/handle.h" #include "net/base/completion_callback.h" +#include "net/cert/x509_certificate.h" #if defined(USE_NSS_CERTS) #include "chrome/browser/certificate_manager_model.h" @@ -151,6 +153,15 @@ class App : public AtomBrowserClient::Delegate, std::unique_ptr certificate_manager_model_; #endif + +#if defined(OS_MACOSX) + void ShowCertificateTrust(atom::NativeWindow* parent_window, + const net::X509Certificate& cert, + std::string message, + const ShowTrustCallback& callback, + mate::Arguments* args); +#endif + // Tracks tasks requesting file icons. base::CancelableTaskTracker cancelable_task_tracker_; From 7b044ffe0e723c67e77ab509754655f72df7cfd8 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 30 Mar 2017 17:26:03 -0400 Subject: [PATCH 079/337] Compile these lovely files --- filenames.gypi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/filenames.gypi b/filenames.gypi index 935d7033153a..f2a78ad4d4b6 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -103,6 +103,8 @@ 'atom/browser/api/atom_api_app.h', 'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.h', + 'atom/browser/api/atom_api_certificate_trust_mac.mm', + 'atom/browser/api/atom_api_certificate_trust.h', 'atom/browser/api/atom_api_content_tracing.cc', 'atom/browser/api/atom_api_cookies.cc', 'atom/browser/api/atom_api_cookies.h', From edf61d41ba3a3efed0b45f80e252cdb75b154895 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 30 Mar 2017 17:26:11 -0400 Subject: [PATCH 080/337] Link against the Security frameworks --- electron.gyp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/electron.gyp b/electron.gyp index 78eed743cc36..71c53fe6f591 100644 --- a/electron.gyp +++ b/electron.gyp @@ -549,6 +549,8 @@ '$(SDKROOT)/System/Library/Frameworks/Carbon.framework', '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework', '$(SDKROOT)/System/Library/Frameworks/Quartz.framework', + '$(SDKROOT)/System/Library/Frameworks/Security.framework', + '$(SDKROOT)/System/Library/Frameworks/SecurityInterface.framework', ], }, 'mac_bundle': 1, From c8951d0d4d419766fb47a12d4c10c971ab9ddc98 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 09:19:21 -0700 Subject: [PATCH 081/337] Upgrade libcc for ffmpeg linking fix --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index 94109bdbb231..7a66fd560d60 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -9,7 +9,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \ - 'dd95b11e52f1e5596184d83d91c91d7b089d05f6' + 'd101a45ee8705e14fa7b5d9691e8268bcfa818b5' PLATFORM = { 'cygwin': 'win32', From 5b4f715d2e6ffc1427205448825e85857f28240b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 15:07:30 -0700 Subject: [PATCH 082/337] Add test page to check for proprietary codecs --- docs/development/upgrading-chrome.md | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/development/upgrading-chrome.md b/docs/development/upgrading-chrome.md index 5cb9337cd09c..fa877faba5ee 100644 --- a/docs/development/upgrading-chrome.md +++ b/docs/development/upgrading-chrome.md @@ -45,6 +45,46 @@ Chrome/Node API changes. - 64-bit Linux - ARM Linux +## Verify ffmpeg builds + +Electron ships with a version of `ffmpeg` that includes proprietary codecs by +default. A version without these codecs is built and distributed with each +release as well. Each Chrome upgrade should verify that switching this version is +still supported. + +You can verify Electron's support for multiple `ffmpeg` builds by loading the +following page. It should work with the default `ffmpeg` library distributed +with Electron and not work with the `ffmpeg` library built without proprietary +codecs. + +```html + + + + + Proprietary Codec Check + + +

Checking if Electron is using proprietary codecs by loading video from http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4

+

+ + + + +``` + ## Links - [Chrome Release Schedule](https://www.chromium.org/developers/calendar) From 740de02d6c80c25009ce2e7e1e8627ef5cb7d419 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 15:08:06 -0700 Subject: [PATCH 083/337] builds -> Support --- docs/development/upgrading-chrome.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/development/upgrading-chrome.md b/docs/development/upgrading-chrome.md index fa877faba5ee..6e47a8b4f521 100644 --- a/docs/development/upgrading-chrome.md +++ b/docs/development/upgrading-chrome.md @@ -45,7 +45,7 @@ Chrome/Node API changes. - 64-bit Linux - ARM Linux -## Verify ffmpeg builds +## Verify ffmpeg Support Electron ships with a version of `ffmpeg` that includes proprietary codecs by default. A version without these codecs is built and distributed with each From 6b8f840da05e9cc326770c8c7105f3b5d8ce395b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 16:23:30 -0700 Subject: [PATCH 084/337] Add script to verify ffmpeg without proprietary codecs --- script/cibuild | 1 + script/verify-ffmpeg.py | 75 ++++++++++++++++++++++++++ spec/fixtures/no-proprietary-codecs.js | 36 +++++++++++++ 3 files changed, 112 insertions(+) create mode 100755 script/verify-ffmpeg.py create mode 100644 spec/fixtures/no-proprietary-codecs.js diff --git a/script/cibuild b/script/cibuild index 92dec9db2dee..dc2d9d081045 100755 --- a/script/cibuild +++ b/script/cibuild @@ -91,6 +91,7 @@ def main(): run_script('build.py', ['-c', 'D']) if PLATFORM == 'win32' or target_arch == 'x64': run_script('test.py', ['--ci']) + run_script('verify-ffmpeg.py') def run_script(script, args=[]): diff --git a/script/verify-ffmpeg.py b/script/verify-ffmpeg.py new file mode 100755 index 000000000000..0024552076b7 --- /dev/null +++ b/script/verify-ffmpeg.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python + +import os +import shutil +import subprocess +import sys + +from lib.util import electron_gyp, rm_rf + + +SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) +FFMPEG_LIBCC_PATH = os.path.join(SOURCE_ROOT, 'vendor', 'brightray', 'vendor', + 'download', 'libchromiumcontent', 'ffmpeg') + +PROJECT_NAME = electron_gyp()['project_name%'] +PRODUCT_NAME = electron_gyp()['product_name%'] + + +def main(): + os.chdir(SOURCE_ROOT) + + if len(sys.argv) == 2 and sys.argv[1] == '-R': + config = 'R' + else: + config = 'D' + + app_path = create_app_copy(config) + + if sys.platform == 'darwin': + electron = os.path.join(app_path, 'Contents', 'MacOS', PRODUCT_NAME) + ffmpeg_name = 'libffmpeg.dylib' + ffmpeg_app_path = os.path.join(app_path, 'Contents', 'Frameworks', + '{0} Framework.framework'.format(PROJECT_NAME), + 'Libraries') + elif sys.platform == 'win32': + electron = os.path.join(app_path, '{0}.exe'.format(PROJECT_NAME)) + ffmpeg_app_path = app_path + ffmpeg_name = 'libffmpeg.dll' + else: + electron = os.path.join(app_path, PROJECT_NAME) + ffmpeg_app_path = app_path + ffmpeg_name = 'libffmpeg.so' + + # Copy ffmpeg without proprietary codecs into app + shutil.copy(os.path.join(FFMPEG_LIBCC_PATH, ffmpeg_name), ffmpeg_app_path) + + returncode = 0 + try: + test_path = os.path.join('spec', 'fixtures', 'no-proprietary-codecs.js') + subprocess.check_call([electron, test_path] + sys.argv[1:]) + except subprocess.CalledProcessError as e: + returncode = e.returncode + except KeyboardInterrupt: + returncode = 0 + + return returncode + + +# Create copy of app to install ffmpeg library without proprietary codecs into +def create_app_copy(config): + initial_app_path = os.path.join(SOURCE_ROOT, 'out', config) + app_path = os.path.join(SOURCE_ROOT, 'out', config + '-no-proprietary-codecs') + + if sys.platform == 'darwin': + app_name = '{0}.app'.format(PRODUCT_NAME) + initial_app_path = os.path.join(initial_app_path, app_name) + app_path = os.path.join(app_path, app_name) + + rm_rf(app_path) + shutil.copytree(initial_app_path, app_path, symlinks=True) + return app_path + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js new file mode 100644 index 000000000000..b1450d45b926 --- /dev/null +++ b/spec/fixtures/no-proprietary-codecs.js @@ -0,0 +1,36 @@ +const {app, BrowserWindow, ipcMain} = require('electron') +const path = require('path') +const url = require('url') + +const MEDIA_ERR_SRC_NOT_SUPPORTED = 4 + +let window + +app.once('ready', () => { + window = new BrowserWindow({ + show: false + }) + + window.loadURL(url.format({ + protocol: 'file', + slashed: true, + pathname: path.resolve(__dirname, 'asar', 'video.asar', 'index.html') + })) + + ipcMain.on('asar-video', function (event, message, error) { + if (message === 'ended') { + console.log('Video played, proprietary codecs are included') + app.exit(1) + return + } + + if (message === 'error' && error === MEDIA_ERR_SRC_NOT_SUPPORTED) { + console.log('Video format not supported, proprietary codecs are not included') + app.exit(0) + return + } + + console.log(`Unexpected error: ${error}`) + app.exit(1) + }) +}) From 787313001927ec8f3a0cff490c1fa861612ad100 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 16:30:04 -0700 Subject: [PATCH 085/337] Add comment to codecs app script --- spec/fixtures/no-proprietary-codecs.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index b1450d45b926..b561e14e580f 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -1,3 +1,9 @@ +// Verifies that Electron cannot play a video that uses proprietary codecs +// +// This application should be run with the ffmpeg that does not include +// proprietary codecs to ensure Electron uses it instead of the version +// that does include proprietary codecs. + const {app, BrowserWindow, ipcMain} = require('electron') const path = require('path') const url = require('url') From b85ebb00aaa5ded34c95c83807514972068717c8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 16:38:34 -0700 Subject: [PATCH 086/337] Tweak logged messages --- spec/fixtures/no-proprietary-codecs.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index b561e14e580f..3e0e40933745 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -31,12 +31,11 @@ app.once('ready', () => { } if (message === 'error' && error === MEDIA_ERR_SRC_NOT_SUPPORTED) { - console.log('Video format not supported, proprietary codecs are not included') app.exit(0) return } - console.log(`Unexpected error: ${error}`) + console.log(`Unexpected response from page: ${message} ${error}`) app.exit(1) }) }) From 90d0179fe96773fe819f794c1be72f1a70d058bd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 17:01:25 -0700 Subject: [PATCH 087/337] Use correct dll name --- script/verify-ffmpeg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/verify-ffmpeg.py b/script/verify-ffmpeg.py index 0024552076b7..9d9dba067030 100755 --- a/script/verify-ffmpeg.py +++ b/script/verify-ffmpeg.py @@ -35,7 +35,7 @@ def main(): elif sys.platform == 'win32': electron = os.path.join(app_path, '{0}.exe'.format(PROJECT_NAME)) ffmpeg_app_path = app_path - ffmpeg_name = 'libffmpeg.dll' + ffmpeg_name = 'ffmpeg.dll' else: electron = os.path.join(app_path, PROJECT_NAME) ffmpeg_app_path = app_path From c85d667e663cfa213d7a7d1303511bbef294c617 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 14:37:19 -0700 Subject: [PATCH 088/337] Upgrade libcc to latest master --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index 7a66fd560d60..d033d8a41c6a 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -9,7 +9,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \ - 'd101a45ee8705e14fa7b5d9691e8268bcfa818b5' + '8d551064d2b3d11f89ce8d5c4610f34e0408bad8' PLATFORM = { 'cygwin': 'win32', From 39fdc26921023d9b4bf3ac94de0779556f9786dc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Mar 2017 14:39:48 -0700 Subject: [PATCH 089/337] Time out after 5 minutes --- spec/fixtures/no-proprietary-codecs.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/fixtures/no-proprietary-codecs.js b/spec/fixtures/no-proprietary-codecs.js index 3e0e40933745..23a7d815a924 100644 --- a/spec/fixtures/no-proprietary-codecs.js +++ b/spec/fixtures/no-proprietary-codecs.js @@ -9,6 +9,7 @@ const path = require('path') const url = require('url') const MEDIA_ERR_SRC_NOT_SUPPORTED = 4 +const FIVE_MINUTES = 5 * 60 * 1000 let window @@ -23,7 +24,7 @@ app.once('ready', () => { pathname: path.resolve(__dirname, 'asar', 'video.asar', 'index.html') })) - ipcMain.on('asar-video', function (event, message, error) { + ipcMain.on('asar-video', (event, message, error) => { if (message === 'ended') { console.log('Video played, proprietary codecs are included') app.exit(1) @@ -38,4 +39,9 @@ app.once('ready', () => { console.log(`Unexpected response from page: ${message} ${error}`) app.exit(1) }) + + setTimeout(() => { + console.log('No IPC message after 5 minutes') + app.exit(1) + }, FIVE_MINUTES) }) From 1c80102218e8a1b56886996acf192c1bc1d9151c Mon Sep 17 00:00:00 2001 From: Philip Jackson Date: Fri, 31 Mar 2017 16:42:03 +1300 Subject: [PATCH 090/337] :memo: Document passing null to Menu.setApplicationMenu [ci skip] --- docs/api/menu.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api/menu.md b/docs/api/menu.md index 42724e1d4afc..13585fef72e7 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -17,7 +17,8 @@ The `menu` class has the following static methods: * `menu` Menu Sets `menu` as the application menu on macOS. On Windows and Linux, the `menu` -will be set as each window's top menu. +will be set as each window's top menu. Setting it to `null` will remove the +menu bar. **Note:** This API has to be called after the `ready` event of `app` module. From f0d447cd681c276acc4ab560650770a270b030c0 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 29 Mar 2017 09:16:27 -0300 Subject: [PATCH 091/337] Pass `uploadToServer` to windows crash reporter --- atom/common/crash_reporter/crash_reporter_win.cc | 11 ++++++++--- atom/common/crash_reporter/crash_reporter_win.h | 3 ++- atom/common/crash_reporter/win/crash_service.cc | 2 +- docs/api/crash-reporter.md | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index 25969dc32eb3..b13108dbfec5 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -179,7 +179,7 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name, google_breakpad::ExceptionHandler::HANDLER_ALL, kSmallDumpType, pipe_name.c_str(), - GetCustomInfo(product_name, version, company_name))); + GetCustomInfo(product_name, version, company_name, upload_to_server))); if (!breakpad_->IsOutOfProcess()) LOG(ERROR) << "Cannot initialize out-of-process crash handler"; @@ -238,14 +238,19 @@ bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path, google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo( const std::string& product_name, const std::string& version, - const std::string& company_name) { + const std::string& company_name, + bool upload_to_server) { custom_info_entries_.clear(); - custom_info_entries_.reserve(2 + upload_parameters_.size()); + custom_info_entries_.reserve(3 + upload_parameters_.size()); custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( L"prod", L"Electron")); custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( L"ver", base::UTF8ToWide(version).c_str())); + if (!upload_to_server) { + custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( + L"skip_upload", L"1")); + } for (StringMap::const_iterator iter = upload_parameters_.begin(); iter != upload_parameters_.end(); ++iter) { diff --git a/atom/common/crash_reporter/crash_reporter_win.h b/atom/common/crash_reporter/crash_reporter_win.h index 3fc139aca190..5070df206006 100644 --- a/atom/common/crash_reporter/crash_reporter_win.h +++ b/atom/common/crash_reporter/crash_reporter_win.h @@ -56,7 +56,8 @@ class CrashReporterWin : public CrashReporter { google_breakpad::CustomClientInfo* GetCustomInfo( const std::string& product_name, const std::string& version, - const std::string& company_name); + const std::string& company_name, + bool upload_to_server); // Custom information to be passed to crash handler. std::vector custom_info_entries_; diff --git a/atom/common/crash_reporter/win/crash_service.cc b/atom/common/crash_reporter/win/crash_service.cc index 5782fd72a3fb..a306a567a711 100644 --- a/atom/common/crash_reporter/win/crash_service.cc +++ b/atom/common/crash_reporter/win/crash_service.cc @@ -391,7 +391,7 @@ void CrashService::OnClientDumpRequest(void* context, LOG(ERROR) << "could not write custom info file"; } - if (!self->sender_) + if (!self->sender_ || map.find(L"skip_upload") != map.end()) return; // Send the crash dump using a worker thread. This operation has retry diff --git a/docs/api/crash-reporter.md b/docs/api/crash-reporter.md index 98bf0f3662f2..2f0848c1193e 100644 --- a/docs/api/crash-reporter.md +++ b/docs/api/crash-reporter.md @@ -40,7 +40,7 @@ The `crashReporter` module has the following methods: * `companyName` String (optional) * `submitURL` String - URL that crash reports will be sent to as POST. * `productName` String (optional) - Defaults to `app.getName()`. - * `uploadToServer` Boolean (optional) _Linux_ _macOS_ - Whether crash reports should be sent to the server + * `uploadToServer` Boolean (optional) - Whether crash reports should be sent to the server Default is `true`. * `ignoreSystemCrashHandler` Boolean (optional) - Default is `false`. * `extra` Object (optional) - An object you can define that will be sent along with the From 460fb9cdb93a160a8e3ebf8d3351ad87551a4906 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 30 Mar 2017 11:11:49 -0300 Subject: [PATCH 092/337] Add tests for `uploadToServer` option. --- spec/api-crash-reporter-spec.js | 89 +++++++++++++++++++++++++++++++++ spec/fixtures/api/crash.html | 12 +++-- 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index dc4b98150160..555445ee7813 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -1,5 +1,6 @@ const assert = require('assert') const childProcess = require('child_process') +const fs = require('fs') const http = require('http') const multiparty = require('multiparty') const path = require('path') @@ -73,6 +74,93 @@ describe('crashReporter module', function () { }) }) + it('should not send minidump if uploadToServer is false', function (done) { + this.timeout(120000) + + if (process.platform === 'darwin') { + crashReporter.setUploadToServer(false) + } + + let server + let dumpFile + let crashesDir + const testDone = (uploaded) => { + if (uploaded) { + return done(new Error('fail')) + } + server.close() + if (process.platform === 'darwin') { + crashReporter.setUploadToServer(true) + } + assert(fs.existsSync(dumpFile)) + fs.unlinkSync(dumpFile) + done() + } + + let pollInterval + const pollDumpFile = () => { + fs.readdir(crashesDir, (err, files) => { + if (err) { + return + } + let dumps = files.filter((f) => /\.dmp$/.test(f)) + if (!dumps.length) { + return + } + assert.equal(1, dumps.length) + dumpFile = path.join(crashesDir, dumps[0]) + clearInterval(pollInterval) + // dump file should not be deleted when not uploading, so we wait + // 500 ms and assert it still exists in `testDone` + setTimeout(testDone, 500) + }) + } + + remote.ipcMain.once('set-crash-directory', (event, dir) => { + if (process.platform === 'linux') { + crashesDir = dir + } else { + crashesDir = crashReporter.getCrashesDirectory() + if (process.platform === 'darwin') { + // crashpad uses an extra subdirectory + crashesDir = path.join(crashesDir, 'completed') + } + } + + // Before starting, remove all dump files in the crash directory. + // This is required because: + // - mac crashpad not seem to allow changing the crash directory after + // the first "start" call. + // - Other tests in this suite may leave dumps there. + // - We want to verify in `testDone` that a dump file is created and + // not deleted. + fs.readdir(crashesDir, (err, files) => { + if (!err) { + for (let file of files) { + if (/\.dmp$/.test(file)) { + fs.unlinkSync(path.join(crashesDir, file)) + } + } + } + event.returnValue = null // allow the renderer to crash + pollInterval = setInterval(pollDumpFile, 100) + }) + }) + + server = startServer({ + callback (port) { + const crashUrl = url.format({ + protocol: 'file', + pathname: path.join(fixtures, 'api', 'crash.html'), + search: `?port=${port}&skipUpload=1` + }) + w.loadURL(crashUrl) + }, + processType: 'renderer', + done: testDone.bind(null, true) + }) + }) + it('should send minidump with updated extra parameters', function (done) { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() @@ -215,4 +303,5 @@ const startServer = ({callback, processType, done}) => { } callback(port) }) + return server } diff --git a/spec/fixtures/api/crash.html b/spec/fixtures/api/crash.html index 2b1cea6e9af3..6f013a2c7ba5 100644 --- a/spec/fixtures/api/crash.html +++ b/spec/fixtures/api/crash.html @@ -1,20 +1,24 @@ From d677a436ec91eec708e78bfcb1e1d96827dfc6fa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 10:42:43 -0700 Subject: [PATCH 093/337] :art: --- atom/common/crash_reporter/crash_reporter_win.cc | 2 +- spec/api-crash-reporter-spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index b13108dbfec5..a7908ef30c6b 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -249,7 +249,7 @@ google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo( L"ver", base::UTF8ToWide(version).c_str())); if (!upload_to_server) { custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( - L"skip_upload", L"1")); + L"skip_upload", L"1")); } for (StringMap::const_iterator iter = upload_parameters_.begin(); diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 555445ee7813..8a51b5ef2db1 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -103,7 +103,7 @@ describe('crashReporter module', function () { if (err) { return } - let dumps = files.filter((f) => /\.dmp$/.test(f)) + const dumps = files.filter((file) => /\.dmp$/.test(file)) if (!dumps.length) { return } @@ -136,7 +136,7 @@ describe('crashReporter module', function () { // not deleted. fs.readdir(crashesDir, (err, files) => { if (!err) { - for (let file of files) { + for (const file of files) { if (/\.dmp$/.test(file)) { fs.unlinkSync(path.join(crashesDir, file)) } From deae70de4ddc063d976373f25e3eed11baadb449 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 13:53:31 -0400 Subject: [PATCH 094/337] Dummy out the certificate FromV8 converter --- atom/common/native_mate_converters/net_converter.cc | 6 ++++++ atom/common/native_mate_converters/net_converter.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 94fff2ff6027..477e382fdca3 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -73,6 +73,12 @@ v8::Local Converter>::ToV8( return dict.GetHandle(); } +bool Converter>::FromV8(v8::Isolate* isolate, + v8::Local val, + scoped_refptr* out) { + return true; +} + // static v8::Local Converter::ToV8( v8::Isolate* isolate, const net::CertPrincipal& val) { diff --git a/atom/common/native_mate_converters/net_converter.h b/atom/common/native_mate_converters/net_converter.h index 33117ca974f1..9e3128fdb546 100644 --- a/atom/common/native_mate_converters/net_converter.h +++ b/atom/common/native_mate_converters/net_converter.h @@ -33,6 +33,10 @@ template<> struct Converter> { static v8::Local ToV8(v8::Isolate* isolate, const scoped_refptr& val); + + static bool FromV8(v8::Isolate* isolate, + v8::Local val, + scoped_refptr* out); }; template<> From 16cc79354c5dcc8758c043185a16196d64c14bb6 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 13:53:42 -0400 Subject: [PATCH 095/337] Errrrybody's a scoped_refptr now --- atom/browser/api/atom_api_app.cc | 4 ++-- atom/browser/api/atom_api_app.h | 2 +- atom/browser/api/atom_api_certificate_trust.h | 3 ++- atom/browser/api/atom_api_certificate_trust_mac.mm | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 3a8f4ef0f8b5..41e7655a66f1 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -813,7 +813,7 @@ void App::OnCertificateManagerModelCreated( #if defined(OS_MACOSX) void App::ShowCertificateTrust(atom::NativeWindow* parent_window, - const net::X509Certificate& cert, + const scoped_refptr& cert, std::string message, const ShowTrustCallback& callback, mate::Arguments* args) { @@ -960,7 +960,7 @@ void App::BuildPrototype( base::Bind(&Browser::GetCurrentActivityType, browser)) .SetMethod("setAboutPanelOptions", base::Bind(&Browser::SetAboutPanelOptions, browser)) - // .SetMethod("showCertificateTrust", &App::ShowCertificateTrust) + .SetMethod("showCertificateTrust", &App::ShowCertificateTrust) #endif #if defined(OS_WIN) .SetMethod("setUserTasks", base::Bind(&Browser::SetUserTasks, browser)) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 367709cf0c6f..19640cb84886 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -156,7 +156,7 @@ class App : public AtomBrowserClient::Delegate, #if defined(OS_MACOSX) void ShowCertificateTrust(atom::NativeWindow* parent_window, - const net::X509Certificate& cert, + const scoped_refptr& cert, std::string message, const ShowTrustCallback& callback, mate::Arguments* args); diff --git a/atom/browser/api/atom_api_certificate_trust.h b/atom/browser/api/atom_api_certificate_trust.h index c3e6994b3baf..1de7d653bb18 100644 --- a/atom/browser/api/atom_api_certificate_trust.h +++ b/atom/browser/api/atom_api_certificate_trust.h @@ -8,6 +8,7 @@ #include #include "base/callback_forward.h" +#include "base/memory/ref_counted.h" namespace net { class X509Certificate; @@ -22,7 +23,7 @@ namespace api { typedef base::Callback ShowTrustCallback; void ShowCertificateTrustUI(atom::NativeWindow* parent_window, - const net::X509Certificate& cert, + const scoped_refptr& cert, std::string message, const ShowTrustCallback& callback); diff --git a/atom/browser/api/atom_api_certificate_trust_mac.mm b/atom/browser/api/atom_api_certificate_trust_mac.mm index c0109d9f45a7..dc12ada27f84 100644 --- a/atom/browser/api/atom_api_certificate_trust_mac.mm +++ b/atom/browser/api/atom_api_certificate_trust_mac.mm @@ -21,12 +21,12 @@ namespace atom { namespace api { void ShowCertificateTrustUI(atom::NativeWindow* parent_window, - const net::X509Certificate& cert, + const scoped_refptr& cert, std::string message, const ShowTrustCallback& callback) { auto sec_policy = SecPolicyCreateBasicX509(); SecTrustRef trust = nullptr; - SecTrustCreateWithCertificates(cert.CreateOSCertChainForCert(), sec_policy, &trust); + SecTrustCreateWithCertificates(cert->CreateOSCertChainForCert(), sec_policy, &trust); // CFRelease(sec_policy); NSWindow* window = parent_window ? From 8ae91682cbb0a2e727db9e21a361e0dc68db7c7e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 31 Mar 2017 20:09:13 +0200 Subject: [PATCH 096/337] Lines should be <= 80 characters. --- atom/browser/api/atom_api_dialog.cc | 13 +++++++------ atom/browser/web_contents_permission_helper.cc | 17 +++++++++-------- .../native_mate_converters/content_converter.cc | 6 ++++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index c226d3d20218..cc849e026ea1 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -78,13 +78,14 @@ void ShowMessageBox(int type, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - atom::ShowMessageBox(window, static_cast(type), buttons, - default_id, cancel_id, options, title, message, detail, - checkbox_label, checkbox_checked, icon, callback); + atom::ShowMessageBox(window, static_cast(type), + buttons, default_id, cancel_id, options, title, + message, detail, checkbox_label, checkbox_checked, + icon, callback); } else { - int chosen = atom::ShowMessageBox(window, static_cast(type), - buttons, default_id, cancel_id, - options, title, message, detail, icon); + int chosen = atom::ShowMessageBox( + window, static_cast(type), buttons, default_id, + cancel_id, options, title, message, detail, icon); args->Return(chosen); } } diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc index 050e1d6b4a29..ec9e4ad6e941 100644 --- a/atom/browser/web_contents_permission_helper.cc +++ b/atom/browser/web_contents_permission_helper.cc @@ -66,8 +66,9 @@ void WebContentsPermissionHelper::RequestPermission( void WebContentsPermissionHelper::RequestFullscreenPermission( const base::Callback& callback) { - RequestPermission(static_cast(PermissionType::FULLSCREEN), - callback); + RequestPermission( + static_cast(PermissionType::FULLSCREEN), + callback); } void WebContentsPermissionHelper::RequestMediaAccessPermission( @@ -86,17 +87,17 @@ void WebContentsPermissionHelper::RequestWebNotificationPermission( void WebContentsPermissionHelper::RequestPointerLockPermission( bool user_gesture) { - RequestPermission(static_cast(PermissionType::POINTER_LOCK), - base::Bind(&OnPointerLockResponse, web_contents_), - user_gesture); + RequestPermission( + static_cast(PermissionType::POINTER_LOCK), + base::Bind(&OnPointerLockResponse, web_contents_), user_gesture); } void WebContentsPermissionHelper::RequestOpenExternalPermission( const base::Callback& callback, bool user_gesture) { - RequestPermission(static_cast(PermissionType::OPEN_EXTERNAL), - callback, - user_gesture); + RequestPermission( + static_cast(PermissionType::OPEN_EXTERNAL), + callback, user_gesture); } } // namespace atom diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index 444faa697247..7869e37deeea 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -170,9 +170,11 @@ v8::Local Converter::ToV8( if (val == static_cast(PermissionType::POINTER_LOCK)) return StringToV8(isolate, "pointerLock"); - else if (val == static_cast(PermissionType::FULLSCREEN)) + else if (val == + static_cast(PermissionType::FULLSCREEN)) return StringToV8(isolate, "fullscreen"); - else if (val == static_cast(PermissionType::OPEN_EXTERNAL)) + else if (val == + static_cast(PermissionType::OPEN_EXTERNAL)) return StringToV8(isolate, "openExternal"); return StringToV8(isolate, "unknown"); From 141a5ad73f2ecdc4305ef9a7572a3ae72333257e Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 14:16:26 -0400 Subject: [PATCH 097/337] Maybe this is a valid conversion? --- atom/common/native_mate_converters/net_converter.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 477e382fdca3..8e8f6c001498 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -73,9 +73,16 @@ v8::Local Converter>::ToV8( return dict.GetHandle(); } -bool Converter>::FromV8(v8::Isolate* isolate, - v8::Local val, - scoped_refptr* out) { +bool Converter>::FromV8( + v8::Isolate* isolate, v8::Local val, + scoped_refptr* out) { + mate::Dictionary dict; + if (!ConvertFromV8(isolate, val, &dict)) + return false; + + std::string data; + dict.Get("data", &data); + *out = net::X509Certificate::CreateFromBytes(data.c_str(), data.length()); return true; } From 08db63c3cc6a0079b004ca81deb636c85bff947e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 10:20:02 -0700 Subject: [PATCH 098/337] Only define NSWindowTabbingModeDisallowed on pre-10.12 --- atom/browser/native_window_mac.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 2912022bd634..10b6e3e311cf 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -336,14 +336,19 @@ bool ScopedDisableResize::disable_resize_ = false; @end +#if !defined(MAC_OS_X_VERSION_10_12) + enum { NSWindowTabbingModeDisallowed = 2 }; + @interface NSWindow (SierraSDK) - (void)setTabbingMode:(NSInteger)mode; -- (void)setTabbingIdentifier:(NSString *)identifier; +- (void)setTabbingIdentifier:(NSString*)identifier; @end +#endif // MAC_OS_X_VERSION_10_12 + @interface AtomNSWindow : EventDispatchingWindow { @private atom::NativeWindowMac* shell_; From a724b6555fdbcc4c135e67129332e580dc49684d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 09:39:43 -0700 Subject: [PATCH 099/337] Bump v1.6.5 --- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- electron.gyp | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 091614ffd428..6fc30bf6a3b3 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 1.6.4 + 1.6.5 CFBundleShortVersionString - 1.6.4 + 1.6.5 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 5a2d8ea32ece..34879fe41ec9 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 1,6,4,0 - PRODUCTVERSION 1,6,4,0 + FILEVERSION 1,6,5,0 + PRODUCTVERSION 1,6,5,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "1.6.4" + VALUE "FileVersion", "1.6.5" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "1.6.4" + VALUE "ProductVersion", "1.6.5" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 73528b45eaae..1054a3dc9f1e 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 1 #define ATOM_MINOR_VERSION 6 -#define ATOM_PATCH_VERSION 4 +#define ATOM_PATCH_VERSION 5 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/electron.gyp b/electron.gyp index 78eed743cc36..3dec2ee8a072 100644 --- a/electron.gyp +++ b/electron.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '1.6.4', + 'version%': '1.6.5', 'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c', }, 'includes': [ diff --git a/package.json b/package.json index d321d7831f05..015be4a12e09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "1.6.4", + "version": "1.6.5", "devDependencies": { "asar": "^0.11.0", "browserify": "^13.1.0", From 302ca8669dd35121ab1a2bb5126ba6c3e48ff792 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 15:44:47 -0400 Subject: [PATCH 100/337] Slightly better conversion --- atom/common/native_mate_converters/net_converter.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 8e8f6c001498..59f897c8a74b 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -82,7 +82,18 @@ bool Converter>::FromV8( std::string data; dict.Get("data", &data); - *out = net::X509Certificate::CreateFromBytes(data.c_str(), data.length()); + + auto certificate_list = net::X509Certificate::CreateCertificateListFromBytes( + data.c_str(), data.length(), + net::X509Certificate::FORMAT_SINGLE_CERTIFICATE); + if (certificate_list.empty()) + return false; + + auto certificate = certificate_list.front(); + if (!certificate) + return false; + + *out = certificate; return true; } From 6d516fbae3c61b9bda188de3d77428d0123acbe2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 31 Mar 2017 15:08:03 -0700 Subject: [PATCH 101/337] Move normalizeAccessKeys docs to right method --- docs/api/dialog.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 230930abd948..8885c315144b 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -46,16 +46,8 @@ The `dialog` module has the following methods: * `noResolveAliases` - Disable the automatic alias (symlink) path resolution. Selected aliases will now return the alias path instead of their target path. _macOS_ - * `normalizeAccessKeys` Boolean (optional) - Normalize the keyboard access keys - across platforms. Default is `false`. Enabling this assumes `&` is used in - the button labels for the placement of the keyboard shortcut access key - and labels will be converted so they work correctly on each platform, `&` - characters are removed on macOS, converted to `_` on Linux, and left - untouched on Windows. For example, a button label of `Vie&w` will be - converted to `Vie_w` on Linux and `View` on macOS and can be selected - via `Alt-W` on Windows and Linux. - * `message` String (optional) _macOS_ - Message to display above input - boxes. + * `message` String (optional) _macOS_ - Message to display above input + boxes. * `callback` Function (optional) * `filePaths` String[] - An array of file paths chosen by the user @@ -147,6 +139,14 @@ will be passed via `callback(filename)` others as command links in the dialog. This can make the dialog appear in the style of modern Windows apps. If you don't like this behavior, you can set `noLink` to `true`. + * `normalizeAccessKeys` Boolean (optional) - Normalize the keyboard access keys + across platforms. Default is `false`. Enabling this assumes `&` is used in + the button labels for the placement of the keyboard shortcut access key + and labels will be converted so they work correctly on each platform, `&` + characters are removed on macOS, converted to `_` on Linux, and left + untouched on Windows. For example, a button label of `Vie&w` will be + converted to `Vie_w` on Linux and `View` on macOS and can be selected + via `Alt-W` on Windows and Linux. * `callback` Function (optional) * `response` Number - The index of the button that was clicked * `checkboxChecked` Boolean - The checked state of the checkbox if From f757912f902e09df340ed48ed1ff60a7cc8dff58 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 1 Apr 2017 12:11:34 +1100 Subject: [PATCH 102/337] Add missing finalUpdate prop --- docs/api/web-contents.md | 1 + docs/api/webview-tag.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 72dc4b0f7454..87530234a282 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -336,6 +336,7 @@ Returns: * `activeMatchOrdinal` Integer - Position of the active match. * `matches` Integer - Number of Matches. * `selectionArea` Object - Coordinates of first match region. + * `finalUpdate` Boolean Emitted when a result is available for [`webContents.findInPage`] request. diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index 5efc225a1d65..9c09c8ef730e 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -749,6 +749,7 @@ Returns: * `activeMatchOrdinal` Integer - Position of the active match. * `matches` Integer - Number of Matches. * `selectionArea` Object - Coordinates of first match region. + * `finalUpdate` Boolean Fired when a result is available for [`webview.findInPage`](webview-tag.md#webviewtagfindinpage) request. From 69defc5166ac69bd05c8640630f1375e7968dee0 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 21:27:33 -0400 Subject: [PATCH 103/337] Encode all the intermediates --- atom/common/native_mate_converters/net_converter.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 59f897c8a74b..5ceb23a04b8d 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -59,7 +59,8 @@ v8::Local Converter>::ToV8( net::HashValue( val->CalculateFingerprint256(val->os_cert_handle())).ToString()); - if (!val->GetIntermediateCertificates().empty()) { + auto intermediates = val->GetIntermediateCertificates(); + if (!intermediates.empty()) { net::X509Certificate::OSCertHandles issuer_intermediates( val->GetIntermediateCertificates().begin() + 1, val->GetIntermediateCertificates().end()); @@ -68,6 +69,16 @@ v8::Local Converter>::ToV8( val->GetIntermediateCertificates().front(), issuer_intermediates); dict.Set("issuerCert", issuer_cert); + + std::vector intermediates_encoded; + for (size_t i = 0; i < intermediates.size(); i++) { + auto native_cert = intermediates[i]; + std::string encoded; + net::X509Certificate::GetPEMEncoded(native_cert, &encoded); + intermediates_encoded.push_back(encoded); + } + + dict.Set("intermediates", intermediates_encoded); } return dict.GetHandle(); From bde2a597f362fd3b1b4a024367442f8d71c9bc91 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 21:27:49 -0400 Subject: [PATCH 104/337] Decode all the intermediates --- .../native_mate_converters/net_converter.cc | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 5ceb23a04b8d..bfd346835b75 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -84,6 +84,23 @@ v8::Local Converter>::ToV8( return dict.GetHandle(); } +bool CertFromData(const std::string& data, + scoped_refptr* out) { + auto cert_list = net::X509Certificate::CreateCertificateListFromBytes( + data.c_str(), data.length(), + net::X509Certificate::FORMAT_SINGLE_CERTIFICATE); + if (cert_list.empty()) + return false; + + auto leaf_cert = cert_list.front(); + if (!leaf_cert) + return false; + + *out = leaf_cert; + + return true; +} + bool Converter>::FromV8( v8::Isolate* isolate, v8::Local val, scoped_refptr* out) { @@ -93,18 +110,28 @@ bool Converter>::FromV8( std::string data; dict.Get("data", &data); - - auto certificate_list = net::X509Certificate::CreateCertificateListFromBytes( - data.c_str(), data.length(), - net::X509Certificate::FORMAT_SINGLE_CERTIFICATE); - if (certificate_list.empty()) + scoped_refptr leaf_cert; + if (!CertFromData(data, &leaf_cert)) return false; - auto certificate = certificate_list.front(); - if (!certificate) + std::vector intermediates_encoded; + dict.Get("intermediates", &intermediates_encoded); + std::vector intermediates; + for (size_t i = 0; i < intermediates_encoded.size(); i++) { + auto data = intermediates_encoded[i]; + scoped_refptr cert; + if (!CertFromData(data, &cert)) + return false; + + intermediates.push_back(cert->os_cert_handle()); + } + + auto cert = net::X509Certificate::CreateFromHandle( + leaf_cert->os_cert_handle(), intermediates); + if (!cert) return false; - *out = certificate; + *out = cert; return true; } From 4f3d3557cc244741340f12684c06d91ea5a9488b Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 21:51:29 -0400 Subject: [PATCH 105/337] Notify that the cert changed --- .../browser/api/atom_api_certificate_trust_mac.mm | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_certificate_trust_mac.mm b/atom/browser/api/atom_api_certificate_trust_mac.mm index dc12ada27f84..5057ef55ab51 100644 --- a/atom/browser/api/atom_api_certificate_trust_mac.mm +++ b/atom/browser/api/atom_api_certificate_trust_mac.mm @@ -15,6 +15,7 @@ #include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" #include "net/cert/x509_certificate.h" +#include "net/cert/cert_database.h" namespace atom { @@ -29,14 +30,20 @@ void ShowCertificateTrustUI(atom::NativeWindow* parent_window, SecTrustCreateWithCertificates(cert->CreateOSCertChainForCert(), sec_policy, &trust); // CFRelease(sec_policy); - NSWindow* window = parent_window ? - parent_window->GetNativeWindow() : - NULL; + // NSWindow* window = parent_window ? + // parent_window->GetNativeWindow() : + // NULL; auto msg = base::SysUTF8ToNSString(message); SFCertificateTrustPanel *panel = [[SFCertificateTrustPanel alloc] init]; - [panel beginSheetForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL trust:trust message:msg]; + [panel runModalForTrust:trust message:msg]; + // [panel beginSheetForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL trust:trust message:msg]; + + auto cert_db = net::CertDatabase::GetInstance(); + // This forces Chromium to reload the certificate since it might be trusted + // now. + cert_db->NotifyObserversCertDBChanged(cert.get()); callback.Run(true); // CFRelease(trust); From ee7389bb6ddfe5f6486f8a07c2ac1298cbbb950c Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 31 Mar 2017 22:57:56 -0400 Subject: [PATCH 106/337] Rename to make VS happy --- atom/common/native_mate_converters/net_converter.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index bfd346835b75..2d3095a63ea0 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -118,9 +118,9 @@ bool Converter>::FromV8( dict.Get("intermediates", &intermediates_encoded); std::vector intermediates; for (size_t i = 0; i < intermediates_encoded.size(); i++) { - auto data = intermediates_encoded[i]; + auto intermediate_data = intermediates_encoded[i]; scoped_refptr cert; - if (!CertFromData(data, &cert)) + if (!CertFromData(intermediate_data, &cert)) return false; intermediates.push_back(cert->os_cert_handle()); From f09e3f38355532a7cfb4a477de9231677986127c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 1 Apr 2017 15:09:53 +0200 Subject: [PATCH 107/337] Remove extra blank. --- atom/common/platform_util_mac.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm index 9cbbaedbe181..7259b3b13031 100644 --- a/atom/common/platform_util_mac.mm +++ b/atom/common/platform_util_mac.mm @@ -73,10 +73,10 @@ std::string MessageForOSStatus(OSStatus status, const char* default_message) { // NSWorkspace#openURLs. std::string OpenURL(NSURL* ns_url, bool activate) { CFURLRef openingApp = nullptr; - OSStatus status = LSGetApplicationForURL(base::mac::NSToCFCast(ns_url), - kLSRolesAll, - nullptr, - &openingApp); + OSStatus status = LSGetApplicationForURL(base::mac::NSToCFCast(ns_url), + kLSRolesAll, + nullptr, + &openingApp); if (status != noErr) return MessageForOSStatus(status, "Failed to open"); From 671bcf2161b37faa22b5f04b88cf3374dcbb52ce Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Sun, 2 Apr 2017 00:41:36 +0800 Subject: [PATCH 108/337] Update web-contents.md --- docs-translations/zh-CN/api/web-contents.md | 820 +++++++++++++------- 1 file changed, 558 insertions(+), 262 deletions(-) diff --git a/docs-translations/zh-CN/api/web-contents.md b/docs-translations/zh-CN/api/web-contents.md index b13628533ee1..dd5c926126c2 100644 --- a/docs-translations/zh-CN/api/web-contents.md +++ b/docs-translations/zh-CN/api/web-contents.md @@ -48,15 +48,14 @@ console.log(webContents) 可使用的进程: [主进程](../tutorial/quick-start.md#main-process) -## 事件 +### 实例事件 -`webContents` 对象可发出下列事件: -### Event: 'did-finish-load' +#### Event: 'did-finish-load' -当导航完成时发出事件,`onload` 事件也完成。 +当导航完成时,发出 `onload` 事件。 -### Event: 'did-fail-load' +#### Event: 'did-fail-load' 返回: @@ -66,9 +65,9 @@ console.log(webContents) * `validatedURL` String * `isMainFrame` Boolean -这个事件类似 `did-finish-load` ,但是是在加载失败或取消加载时发出, 例如, `window.stop()` 请求结束。错误代码的完整列表和它们的含义都可以在 [这里](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) 找到。 +这个事件类似 `did-finish-load` ,但是是在加载失败或取消加载时发出, 例如, `window.stop()` 被调用时。错误代码的完整列表和它们的含义都可以在 [这里](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) 找到。 -### Event: 'did-frame-finish-load' +#### Event: 'did-frame-finish-load' 返回: @@ -77,15 +76,15 @@ console.log(webContents) 当一个 frame 导航完成的时候发出事件。 -### Event: 'did-start-loading' +#### Event: 'did-start-loading' 当 tab 的spinner 开始 spinning的时候。 -### Event: 'did-stop-loading' +#### Event: 'did-stop-loading' 当 tab 的spinner 结束 spinning的时候。 -### Event: 'did-get-response-details' +#### Event: 'did-get-response-details' 返回: @@ -102,7 +101,7 @@ console.log(webContents) 当有关请求资源的详细信息可用的时候发出事件。 `status` 标识了 socket 链接来下载资源。 -### Event: 'did-get-redirect-request' +#### Event: 'did-get-redirect-request' 返回: @@ -117,7 +116,7 @@ console.log(webContents) 当在请求资源时收到重定向的时候发出事件。 -### Event: 'dom-ready' +#### Event: 'dom-ready' 返回: @@ -125,7 +124,7 @@ console.log(webContents) 当指定 frame 中的 文档加载完成的时候发出事件。 -### Event: 'page-favicon-updated' +#### Event: 'page-favicon-updated' 返回: @@ -134,15 +133,15 @@ console.log(webContents) 当 page 收到图标 url 的时候发出事件。 -### Event: 'new-window' +#### Event: 'new-window' 返回: * `event` Event * `url` String * `frameName` String -* `disposition` String - 可为 `default`、 `foreground-tab`、 `background-tab`、 - `new-window` 和 `other`。 +* `disposition` String - 可为 `default`, `foreground-tab`, `background-tab`, + `new-window`, `save-to-disk` 和 `other` * `options` Object - 创建新的 `BrowserWindow`时使用的参数。 * `additionalFeatures` String[] - 非标准功能(功能未处理    由 Chromium 或 Electron )赋予 `window.open()`。 @@ -168,7 +167,7 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { }) ``` -### Event: 'will-navigate' +#### Event: 'will-navigate' 返回: @@ -183,7 +182,7 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { 调用 `event.preventDefault()` 可以阻止导航。 -### Event: 'did-navigate' +#### Event: 'did-navigate' 返回: @@ -194,22 +193,28 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { 页内跳转时不会发出这个事件,例如点击锚链接或更新 `window.location.hash`。使用 `did-navigate-in-page` 事件可以达到目的。 -### Event: 'did-navigate-in-page' +#### Event: 'did-navigate-in-page' 返回: * `event` Event * `url` String +* `isMainFrame ` Boolean 当页内导航发生的时候发出事件。 当页内导航发生的时候,page 的url 改变,但是不会跳出界面。例如当点击锚链接时或者 DOM 的 `hashchange` 事件发生。 -### Event: 'crashed' +#### Event: 'crashed' + +返回: + +* `event` Event +* `killed` Boolean 当渲染进程崩溃的时候发出事件。 -### Event: 'plugin-crashed' +#### Event: 'plugin-crashed' 返回: @@ -219,54 +224,70 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { 当插件进程崩溃时候发出事件。 -### Event: 'destroyed' +#### Event: 'destroyed' 当 `webContents` 被删除的时候发出事件。 -### Event: 'devtools-opened' +#### Event: 'before-input-event' + +返回: + +* `event` Event +* `input` Object - 属性 + * `type` String - `keyUp` 或者 `keyDown` + * `key` String - [KeyboardEvent.key][keyboardevent] + * `code` String - [KeyboardEvent.code][keyboardevent] + * `isAutoRepeat` Boolean - [KeyboardEvent.repeat][keyboardevent] + * `shift` Boolean - [KeyboardEvent.shiftKey][keyboardevent] + * `control` Boolean - [KeyboardEvent.controlKey][keyboardevent] + * `alt` Boolean - [KeyboardEvent.altKey][keyboardevent] + * `meta` Boolean - [KeyboardEvent.metaKey][keyboardevent] + +在 `keydown` 和 `keyup` 事件触发前发送。调用 `event.preventDefault` 方法可以阻止页面的 `keydown/keyup` 事件。 + +#### Event: 'devtools-opened' 当开发者工具栏打开的时候发出事件。 -### Event: 'devtools-closed' +#### Event: 'devtools-closed' 当开发者工具栏关闭时候发出事件。 -### Event: 'devtools-focused' +#### Event: 'devtools-focused' 当开发者工具栏获得焦点或打开的时候发出事件。 -### Event: 'certificate-error' +#### Event: 'certificate-error' 返回: * `event` Event * `url` URL * `error` String - The error code -* `certificate` Object - * `data` Buffer - PEM encoded data - * `issuerName` String +* `certificate` [Certificate](structures/certificate.md) * `callback` Function + * `isTrusted ` Boolean - 表明证书是否可以被认为是可信的 -当验证证书或 `url` 失败的时候发出事件。 +当验证 `certificate` 或 `url` 失败的时候发出事件。 使用方法类似 [`app` 的 `certificate-error` 事件](app.md#event-certificate-error)。 -### Event: 'select-client-certificate' + +#### Event: 'select-client-certificate' 返回: * `event` Event * `url` URL -* `certificateList` [Objects] - * `data` Buffer - PEM encoded data - * `issuerName` String - Issuer's Common Name +* `certificateList` [Certificate[]](structures/certificate.md) * `callback` Function + * `certificate` [Certificate](structures/certificate.md) - 证书必须来自于指定的列表 当请求客户端证书的时候发出事件。 使用方法类似 [`app` 的 `select-client-certificate` 事件](app.md#event-select-client-certificate)。 -### Event: 'login' +#### Event: 'login' 返回: @@ -282,34 +303,37 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { * `port` Integer * `realm` String * `callback` Function + * `username` String + * `password` String 当 `webContents` 想做基本验证的时候发出事件. 使用方法类似 [the `login` event of `app`](app.md#event-login)。 -### Event: 'found-in-page' +#### Event: 'found-in-page' 返回: * `event` Event * `result` Object * `requestId` Integer - * `finalUpdate` Boolean - 标识是否还有更多的值可以查看。 - * `activeMatchOrdinal` Integer (可选) - 活动匹配位置。 - * `matches` Integer (可选) - 匹配数量。 - * `selectionArea` Object (可选) - 协调首个匹配位置。 + * `activeMatchOrdinal` Integer - 活动匹配位置。 + * `matches` Integer - 匹配数量。 + * `selectionArea` Object - 协调首个匹配位置。 + * `finalUpdate` Boolean + 当使用 [`webContents.findInPage`] 进行页内查找并且找到可用值得时候发出事件。 -### Event: 'media-started-playing' +#### Event: 'media-started-playing' 当媒体开始播放的时候发出事件。 -### Event: 'media-paused' +#### Event: 'media-paused' 当媒体停止播放的时候发出事件。 -### Event: 'did-change-theme-color' +#### Event: 'did-change-theme-color' 当page 的主题色时候发出事件。这通常由于引入了一个 meta 标签: @@ -317,14 +341,29 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { ``` -### Event: 'cursor-changed' +#### Event: 'update-target-url' + +返回: + +* `event` Event +* `url` String + +当鼠标移到一个链接上或键盘焦点移动到一个链接上时发送。 + +#### Event: 'cursor-changed' 返回: * `event` Event * `type` String * `image` NativeImage (可选) -* `scale` Float (可选) +* `scale` Float (可选) 自定义光标的比例 +* `size` Object (可选) - `image`的大小 + * `width` Integer + * `height` Integer +* `hotspot` Object (可选) - 自定义光标热点的坐标 + * `x` Integer - x 坐标 + * `y` Integer - y 坐标 当鼠标的类型发生改变的时候发出事件. `type` 的参数可以是 `default`, `crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, @@ -333,221 +372,428 @@ myBrowserWindow.webContents.on('new-window', (event, url) => { `row-resize`, `m-panning`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, `s-panning`, `se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, `cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`, -`not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing`, `custom`。 +`not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing`, `custom`. -如果 `type` 参数值为 `custom`、 `image` 参数会在一个`NativeImage` 中控制自定义鼠标图片,并且 `scale` 会控制图片的缩放比例。 +如果 `type` 参数值为 `custom`、 `image` 参数会在一个`NativeImage` 中控制自定义鼠标图片,并且 `scale` 、`size` 和 `hotspot`会控制自定义光标的属性。 -## 实例方法 +#### Event: 'context-menu' -`webContents` 对象有如下的实例方法: +Returns: -### `webContents.loadURL(url[, options])` +* `event` Event +* `params` Object + * `x` Integer - x 坐标 + * `y` Integer - y 坐标 + * `linkURL` String - 菜单中调用的节点的 URL 链接. + * `linkText` String - 链接的文本。当链接是一个图像时文本可以为空. + * `pageURL` String - 菜单被调用时顶级页面的 URL 链接. + * `frameURL` String - 菜单被调用时子级页面的 URL 链接. + * `srcURL` String - 菜单被调用时元素的原始链接。带有链接的元素可以为图像、音频和视频。 + * `mediaType` String - 菜单被调用时的节点类型。可以为 `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`. + * `hasImageContents` Boolean - 菜单中是否含有图像. + * `isEditable` Boolean - 菜单是否可以被编辑. + * `selectionText` String - Text of the selection that the context menu was + invoked on. + * `titleText` String - Title or alt text of the selection that the context + was invoked on. + * `misspelledWord` String - The misspelled word under the cursor, if any. + * `frameCharset` String - The character encoding of the frame on which the + menu was invoked. + * `inputFieldType` String - If the context menu was invoked on an input + field, the type of that field. Possible values are `none`, `plainText`, + `password`, `other`. + * `menuSourceType` String - Input source that invoked the context menu. + Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`. + * `mediaFlags` Object - The flags for the media element the context menu was + invoked on. + * `inError` Boolean - Whether the media element has crashed. + * `isPaused` Boolean - Whether the media element is paused. + * `isMuted` Boolean - Whether the media element is muted. + * `hasAudio` Boolean - Whether the media element has audio. + * `isLooping` Boolean - Whether the media element is looping. + * `isControlsVisible` Boolean - Whether the media element's controls are + visible. + * `canToggleControls` Boolean - Whether the media element's controls are + toggleable. + * `canRotate` Boolean - Whether the media element can be rotated. + * `editFlags` Object - These flags indicate whether the renderer believes it + is able to perform the corresponding action. + * `canUndo` Boolean - Whether the renderer believes it can undo. + * `canRedo` Boolean - Whether the renderer believes it can redo. + * `canCut` Boolean - Whether the renderer believes it can cut. + * `canCopy` Boolean - Whether the renderer believes it can copy + * `canPaste` Boolean - Whether the renderer believes it can paste. + * `canDelete` Boolean - Whether the renderer believes it can delete. + * `canSelectAll` Boolean - Whether the renderer believes it can select all. + +Emitted when there is a new context menu that needs to be handled. + +#### Event: 'select-bluetooth-device' + +Returns: + +* `event` Event +* `devices` [BluetoothDevice[]](structures/bluetooth-device.md) +* `callback` Function + * `deviceId` String + +Emitted when bluetooth device needs to be selected on call to +`navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api +`webBluetooth` should be enabled. If `event.preventDefault` is not called, +first available device will be selected. `callback` should be called with +`deviceId` to be selected, passing empty string to `callback` will +cancel the request. + +```javascript +const {app, webContents} = require('electron') +app.commandLine.appendSwitch('enable-web-bluetooth') + +app.on('ready', () => { + webContents.on('select-bluetooth-device', (event, deviceList, callback) => { + event.preventDefault() + let result = deviceList.find((device) => { + return device.deviceName === 'test' + }) + if (!result) { + callback('') + } else { + callback(result.deviceId) + } + }) +}) +``` + +#### Event: 'paint' + +Returns: + +* `event` Event +* `dirtyRect` [Rectangle](structures/rectangle.md) +* `image` [NativeImage](native-image.md) - The image data of the whole frame. + +Emitted when a new frame is generated. Only the dirty area is passed in the +buffer. + +```javascript +const {BrowserWindow} = require('electron') + +let win = new BrowserWindow({webPreferences: {offscreen: true}}) +win.webContents.on('paint', (event, dirty, image) => { + // updateBitmap(dirty, image.getBitmap()) +}) +win.loadURL('http://github.com') +``` + +#### Event: 'devtools-reload-page' +当 devtools 调试工具页面重新加载时发送 + +#### Event: 'will-attach-webview' + +Returns: + +* `event` Event +* `webPreferences` Object - The web preferences that will be used by the guest + page. This object can be modified to adjust the preferences for the guest + page. +* `params` Object - The other `` parameters such as the `src` URL. + This object can be modified to adjust the parameters of the guest page. + +Emitted when a ``'s web contents is being attached to this web +contents. Calling `event.preventDefault()` will destroy the guest page. + +This event can be used to configure `webPreferences` for the `webContents` +of a `` before it's loaded, and provides the ability to set settings +that can't be set via `` attributes. +### 实例方法 + + +#### `contents.loadURL(url[, options])` * `url` URL * `options` Object (可选) - * `httpReferrer` String - A HTTP Referrer url. + * `httpReferrer` String - HTTP 的 url 链接. * `userAgent` String - 产生请求的用户代理 * `extraHeaders` String - 以 "\n" 分隔的额外头 + * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md) | [UploadFileSystem](structures/upload-file-system.md) | [UploadBlob](structures/upload-blob.md))[] - (optional) + * `baseURLForDataURL` String (optional) - 由数据URL加载的文件的基本URL(带尾随路径分隔符)。只有当指定的URL是一个数据URL并且需要加载其他文件时才需要设置。 -在窗口中加载 `url` 、 `url` 必须包含协议前缀, +在窗口中加载 `url`。 `url` 必须包含协议前缀, 比如 `http://` 或 `file://`。如果加载想要忽略 http 缓存,可以使用 `pragma` 头来达到目的。 ```javascript -const options = {'extraHeaders': 'pragma: no-cache\n'} -webContents.loadURL(url, options) +const {webContents} = require('electron') +const options = {extraHeaders: 'pragma: no-cache\n'} +webContents.loadURL('https://github.com', options) ``` -### `webContents.downloadURL(url)` +#### `contents.downloadURL(url)` * `url` URL 初始化一个指定 `url` 的资源下载,不导航跳转。 `session` 的 `will-download` 事件会触发。 -### `webContents.getURL()` +#### `contents.getURL()` -返回当前 page 的 url。 +Returns `String` - 当前页面的 URL. ```javascript -var win = new BrowserWindow({width: 800, height: 600}) +const {BrowserWindow} = require('electron') +let win = new BrowserWindow({width: 800, height: 600}) win.loadURL('http://github.com') -var currentURL = win.webContents.getURL() +let currentURL = win.webContents.getURL() +console.log(currentURL) ``` -### `webContents.getTitle()` +#### `contents.getTitle()` -返回当前 page 的标题。 +Returns `String` - 当前页面的标题. -### `webContents.isLoading()` +#### `contents.isDestroyed()` -返回一个布尔值,标识当前页是否正在加载。 +Returns `Boolean` - 当前的页面是否被销毁了 -### `webContents.isWaitingForResponse()` +#### `contents.isFocused()` -返回一个布尔值,标识当前页是否正在等待主要资源的第一次响应。 +Returns `Boolean` - 焦点是否在当前页面上. -### `webContents.stop()` +#### `contents.isLoading()` + +Returns `Boolean` - 当前页是否正在加载资源。 + +#### `contents.isLoadingMainFrame()` + +Returns `Boolean` - 是否主框架(而不仅是 iframe 或者在帧内)仍在加载中。 + +#### `contents.isWaitingForResponse()` + +Returns `Boolean` - 当前页是否正在等待主要资源的第一次响应。 + +#### `contents.stop()` 停止还为开始的导航。 -### `webContents.reload()` +#### `contents.reload()` 重载当前页。 -### `webContents.reloadIgnoringCache()` +#### `contents.reloadIgnoringCache()` 重载当前页,忽略缓存。 -### `webContents.canGoBack()` +#### `contents.canGoBack()` -返回一个布尔值,标识浏览器是否能回到前一个page。 +Returns `Boolean` - 浏览器是否能回到前一个页面。 -### `webContents.canGoForward()` +#### `contents.canGoForward()` -返回一个布尔值,标识浏览器是否能前往下一个page。 +Returns `Boolean` - 浏览器是否能前往下一个页面。 -### `webContents.canGoToOffset(offset)` +#### `contents.canGoToOffset(offset)` * `offset` Integer -返回一个布尔值,标识浏览器是否能前往指定 `offset` 的page。 +Returns `Boolean` - 页面是否能前往 `offset`。 -### `webContents.clearHistory()` +#### `contents.clearHistory()` 清除导航历史。 -### `webContents.goBack()` +#### `contents.goBack()` -让浏览器回退到前一个page。 +让浏览器回退到前一个页面。 -### `webContents.goForward()` +#### `contents.goForward()` -让浏览器回前往下一个page。 +让浏览器回前往下一个页面。 -### `webContents.goToIndex(index)` +#### `contents.goToIndex(index)` * `index` Integer -让浏览器回前往指定 `index` 的page。 +让浏览器回前往指定 `index` 的页面。 -### `webContents.goToOffset(offset)` +#### `contents.goToOffset(offset)` * `offset` Integer 导航到相对于当前页的偏移位置页。 -### `webContents.isCrashed()` +#### `contents.isCrashed()` -渲染进程是否崩溃。 +Returns `Boolean` - 渲染进程是否崩溃。 -### `webContents.setUserAgent(userAgent)` +#### `contents.setUserAgent(userAgent)` * `userAgent` String 重写本页用户代理。 -### `webContents.getUserAgent()` +#### `contents.getUserAgent()` -返回一个 `String` ,标识本页用户代理信息。 +Returns `String` - 页面的用户代理信息。 -### `webContents.insertCSS(css)` +#### `contents.insertCSS(css)` * `css` String 为当前页插入css。 -### `webContents.executeJavaScript(code[, userGesture, callback])` +#### `contents.executeJavaScript(code[, userGesture, callback])` * `code` String -* `userGesture` Boolean (可选) +* `userGesture` Boolean (可选) - 默认值为 `false` * `callback` Function (可选) - 脚本执行完成后调用的回调函数. - * `result` + * `result` Any -评估 page `代码`。 +Returns `Promise` - 成功了返回 resolves,失败了返回 rejected + +评估页面的 `code` 代码。 浏览器窗口中的一些 HTML API ,例如 `requestFullScreen`,只能被用户手势请求。设置 `userGesture` 为 `true` 可以取消这个限制。 -### `webContents.setAudioMuted(muted)` +如果执行的代码的结果是一个 promise,回调方法将为 promise 的 resolved 的值。我们建议您使用返回的 Promise 来处理导致结果的代码。 + +```js +contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true) + .then((result) => { + console.log(result) // Will be the JSON object from the fetch call + }) +``` +#### `contents.setAudioMuted(muted)` * `muted` Boolean -减缓当前页的 audio 的播放速度。 +设置当前页为静音。 -### `webContents.isAudioMuted()` +#### `contents.isAudioMuted()` -返回一个布尔值,标识当前页是否减缓了 audio 的播放速度。 +Returns `Boolean` - 当前页是否为静音状态 -### `webContents.undo()` +#### `contents.setZoomFactor(factor)` -执行网页的编辑命令 `undo`。 +* `factor` Number - 缩放系数 -### `webContents.redo()` +改变缩放系数为指定的数值。缩放系数是缩放的百分比除以100,比如 300% = 3.0 -执行网页的编辑命令 `redo`。 +#### `contents.getZoomFactor(callback)` -### `webContents.cut()` +* `callback` Function + * `zoomFactor` Number -执行网页的编辑命令 `cut`。 +发送一个请求来获取当前的缩放系数,`callback` 回调方法会在 `callback(zoomFactor)` 中调用. -### `webContents.copy()` +#### `contents.setZoomLevel(level)` -执行网页的编辑命令 `copy`。 +* `level` Number - 缩放等级 -### `webContents.paste()` +改变缩放等级为指定的等级。原始大小为0,每升高或降低一次,代表 20% 的大小缩放。限制为原始大小的 300% 到 50%。 -执行网页的编辑命令 `paste`。 +#### `contents.getZoomLevel(callback)` -### `webContents.pasteAndMatchStyle()` +* `callback` Function + * `zoomLevel` Number -执行网页的编辑命令 `pasteAndMatchStyle`。 +发送一个请求来获取当前的缩放等级,`callback` 回调方法会在 `callback(zoomLevel)` 中调用. +#### `contents.setZoomLevelLimits(minimumLevel, maximumLevel)` -### `webContents.delete()` +* `minimumLevel` Number +* `maximumLevel` Number -执行网页的编辑命令 `delete`。 +**废弃:** 使用 `setVisualZoomLevelLimits` 来代替. 这个方法将在 Electron 2.0 中移除. -### `webContents.selectAll()` +#### `contents.setVisualZoomLevelLimits(minimumLevel, maximumLevel)` -执行网页的编辑命令 `selectAll`。 +* `minimumLevel` Number +* `maximumLevel` Number -### `webContents.unselect()` +设置最大和最小的手势缩放等级。 -执行网页的编辑命令 `unselect`。 +#### `contents.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)` -### `webContents.replace(text)` +* `minimumLevel` Number +* `maximumLevel` Number + +设置最大和最小的 layout-based (i.e. non-visual) zoom level. + +#### `contents.undo()` + +在网页中执行编辑命令 `undo`。 + +#### `contents.redo()` + +在网页中执行编辑命令 `redo`。 + +#### `contents.cut()` + +在网页中执行编辑命令 `cut`。 + +#### `contents.copy()` + +在网页中执行编辑命令 `copy`。 + +#### `contents.copyImageAt(x, y)` + +* `x` Integer +* `y` Integer + +拷贝剪贴板中指定位置的图像. + +#### `contents.paste()` + +在网页中执行编辑命令 `paste`。 + +#### `contents.pasteAndMatchStyle()` + +在网页中执行编辑命令 `pasteAndMatchStyle`。 + +#### `contents.delete()` + +在网页中执行编辑命令 `delete`。 + +#### `contents.selectAll()` + +在网页中执行编辑命令 `selectAll`。 + +#### `contents.unselect()` + +在网页中执行编辑命令 `unselect`。 + +#### `contents.replace(text)` * `text` String -执行网页的编辑命令 `replace`。 +在网页中执行编辑命令 `replace`。 -### `webContents.replaceMisspelling(text)` +#### `contents.replaceMisspelling(text)` * `text` String -执行网页的编辑命令 `replaceMisspelling`。 +在网页中执行编辑命令 `replaceMisspelling`。 -### `webContents.insertText(text)` +#### `contents.insertText(text)` * `text` String 插入 `text` 到获得了焦点的元素。 -### `webContents.findInPage(text[, options])` +#### `contents.findInPage(text[, options])` * `text` String - 查找内容,不能为空。 * `options` Object (可选) - * `forward` Boolean - 是否向前或向后查找,默认为 `true`。 - * `findNext` Boolean - 当前操作是否是第一次查找或下一次查找, + * `forward` Boolean - (可选) 是否向前或向后查找,默认为 `true`。 + * `findNext` Boolean - (可选) 当前操作是否是第一次查找或下一次查找, 默认为 `false`。 - * `matchCase` Boolean - 查找是否区分大小写, + * `matchCase` Boolean - (可选) 查找是否区分大小写, 默认为 `false`。 - * `wordStart` Boolean -是否仅以首字母查找, + * `wordStart` Boolean - (可选) 是否仅以首字母查找, 默认为 `false`。 - * `medialCapitalAsWordStart` Boolean - 是否结合 `wordStart`,如果匹配是大写字母开头,后面接小写字母或无字母,那么就接受这个词中匹配。接受几个其它的合成词匹配,默认为 `false`。 + * `medialCapitalAsWordStart` Boolean - (可选) 是否结合 `wordStart`,如果匹配是大写字母开头,后面接小写字母或无字母,那么就接受这个词中匹配。接受几个其它的合成词匹配,默认为 `false`。 发起请求,在网页中查找所有与 `text` 相匹配的项,并且返回一个 `Integer` 来表示这个请求用的请求 Id。这个请求结果可以通过订阅 [`found-in-page`](web-contents.md#event-found-in-page) 事件来取得。 -### `webContents.stopFindInPage(action)` +#### `contents.stopFindInPage(action)` * `action` String - 指定一个行为来接替停止 [`webContents.findInPage`] 请求。 @@ -558,47 +804,62 @@ var currentURL = win.webContents.getURL() 使用给定的 `action` 来为 `webContents` 停止任何 `findInPage` 请求。 ```javascript -webContents.on('found-in-page', function (event, result) { +const {webContents} = require('electron') +webContents.on('found-in-page', (event, result) => { if (result.finalUpdate) webContents.stopFindInPage('clearSelection') }) const requestId = webContents.findInPage('api') +console.log(requestId) ``` -### `webContents.hasServiceWorker(callback)` +#### `contents.capturePage([rect, ]callback)` + +* `rect` [Rectangle](structures/rectangle.md) (optional) - 页面被捕捉的区域 +* `callback` Function + * `image` [NativeImage](native-image.md) + +捕捉页面 `rect` 区域的快照。在完成后 `callback` 方法会通过 `callback(image)` 调用 。`image` 是 [NativeImage](native-image.md) 的实例。省略 `rect` 参数会捕捉整个页面的可视区域。 + +#### `contents.hasServiceWorker(callback)` * `callback` Function - + * `hasWorker` Boolean + 检查是否有任何 ServiceWorker 注册了,并且返回一个布尔值,来作为 `callback`响应的标识。 -### `webContents.unregisterServiceWorker(callback)` +#### `contents.unregisterServiceWorker(callback)` * `callback` Function - + * `success` Boolean + 如果存在任何 ServiceWorker,则全部注销,并且当JS承诺执行行或JS拒绝执行而失败的时候,返回一个布尔值,它标识了相应的 `callback`。 -### `webContents.print([options])` +#### `contents.print([options])` * `options` Object (可选) * `silent` Boolean - 不需要请求用户的打印设置. 默认为 `false`。 * `printBackground` Boolean - 打印背景和网页图片. 默认为 `false`。 -打印窗口的网页。当设置 `silent` 为 `false` 的时候,Electron 将使用系统默认的打印机和打印方式来打印。 +打印窗口的网页。当设置 `silent` 为 `true` 的时候,Electron 将使用系统默认的打印机和打印方式来打印。 在网页中调用 `window.print()` 和 调用 `webContents.print({silent: false, printBackground: false})`具有相同的作用。 -**注意:** 在 Windows,打印 API 依赖于 `pdf.dll`。如果你的应用不使用任何的打印,你可以安全删除 `pdf.dll` 来减少二进制文件的size。 +使用 `page-break-before: always; ` CSS 的样式将强制打印到一个新的页面. -### `webContents.printToPDF(options, callback)` +#### `contents.printToPDF(options, callback)` * `options` Object * `marginsType` Integer - 指定使用的 margin type。默认 margin 使用 0,无 margin 使用 1,最小化 margin 使用 2。 * `pageSize` String - 指定生成的PDF文件的page size. 可以是 `A3`、 - `A4`、 `A5`、 `Legal`、`Letter` 和 `Tabloid`。 + `A4`、 `A5`、 `Legal`、`Letter` 和 `Tabloid`。或者是一个包含 `height` + 和 `width` 的对象,单位是微米。 * `printBackground` Boolean - 是否打印 css 背景。 * `printSelectionOnly` Boolean - 是否只打印选中的部分。 * `landscape` Boolean - landscape 为 `true`, portrait 为 `false`。 * `callback` Function + * `error` Error + * `data` Buffer 打印窗口的网页为 pdf,使用 Chromium 预览打印的自定义设置。 @@ -615,18 +876,22 @@ const requestId = webContents.findInPage('api') } ``` +使用 `page-break-before: always; ` CSS 的样式将强制打印到一个新的页面. + +一个 `webContents.printToPDF` 的示例: + ```javascript -const BrowserWindow = require('electron').BrowserWindow +const {BrowserWindow} = require('electron') const fs = require('fs') -var win = new BrowserWindow({width: 800, height: 600}) +let win = new BrowserWindow({width: 800, height: 600}) win.loadURL('http://github.com') -win.webContents.on('did-finish-load', function () { +win.webContents.on('did-finish-load', () => { // Use default printing options - win.webContents.printToPDF({}, function (error, data) { + win.webContents.printToPDF({}, (error, data) => { if (error) throw error - fs.writeFile('/tmp/print.pdf', data, function (error) { + fs.writeFile('/tmp/print.pdf', data, (error) => { if (error) throw error console.log('Write PDF successfully.') }) @@ -634,59 +899,61 @@ win.webContents.on('did-finish-load', function () { }) ``` -### `webContents.addWorkSpace(path)` +#### `contents.addWorkSpace(path)` * `path` String 添加指定的路径给开发者工具栏的 workspace。必须在 DevTools 创建之后使用它: ```javascript -mainWindow.webContents.on('devtools-opened', function () { - mainWindow.webContents.addWorkSpace(__dirname) +const {BrowserWindow} = require('electron') +let win = new BrowserWindow() +win.webContents.on('devtools-opened', () => { + win.webContents.addWorkSpace(__dirname) }) ``` -### `webContents.removeWorkSpace(path)` +#### `contents.removeWorkSpace(path)` * `path` String 从开发者工具栏的 workspace 删除指定的路径。 -### `webContents.openDevTools([options])` +#### `contents.openDevTools([options])` * `options` Object (可选) - * `detach` Boolean - 在一个新窗口打开开发者工具栏 + * `mode` String - 打开开发者工具的状态属性。可以为 `right`, `bottom`, `undocked`, `detach`。默认值为上一次使用时的状态。在`undocked`模式可以把工具栏放回来,`detach`模式不可以。 打开开发者工具栏。 -### `webContents.closeDevTools()` +#### `contents.closeDevTools()` 关闭开发者工具栏。 -### `webContents.isDevToolsOpened()` +#### `contents.isDevToolsOpened()` -返回布尔值,开发者工具栏是否打开。 +Returns `Boolean` - 开发者工具栏是否打开。 -### `webContents.isDevToolsFocused()` +#### `contents.isDevToolsFocused()` -返回布尔值,开发者工具栏视图是否获得焦点。 +Returns `Boolean` - 开发者工具栏视图是否获得焦点。 -### `webContents.toggleDevTools()` +#### `contents.toggleDevTools()` Toggles 开发者工具。 -### `webContents.inspectElement(x, y)` +#### `contents.inspectElement(x, y)` * `x` Integer * `y` Integer 在 (`x`, `y`) 开始检测元素。 -### `webContents.inspectServiceWorker()` +#### `contents.inspectServiceWorker()` 为 service worker 上下文打开开发者工具栏。 -### `webContents.send(channel[, arg1][, arg2][, ...])` +#### `contents.send(channel[, arg1][, arg2][, ...])` * `channel` String * `arg` (可选) @@ -695,16 +962,18 @@ Toggles 开发者工具。 渲染进程可以通过使用 `ipcRenderer` 监听 `channel` 来处理消息。 -例子,从主进程向渲染进程发送消息: +从主进程向渲染进程发送消息的示例: ```javascript // 主进程. -var window = null -app.on('ready', function () { - window = new BrowserWindow({width: 800, height: 600}) - window.loadURL(`file://${__dirname}/index.html`) - window.webContents.on('did-finish-load', function () { - window.webContents.send('ping', 'whoooooooh!') +const {app, BrowserWindow} = require('electron') +let win = null + +app.on('ready', () => { + win = new BrowserWindow({width: 800, height: 600}) + win.loadURL(`file://${__dirname}/index.html`) + win.webContents.on('did-finish-load', () => { + win.webContents.send('ping', 'whoooooooh!') }) }) ``` @@ -714,31 +983,31 @@ app.on('ready', function () { ``` -### `webContents.enableDeviceEmulation(parameters)` +#### `contents.enableDeviceEmulation(parameters)` -`parameters` Object, properties: +`parameters` Object, 属性为: * `screenPosition` String - 指定需要模拟的屏幕 (默认 : `desktop`) - * `desktop` - * `mobile` -* `screenSize` Object - 设置模拟屏幕 size (screenPosition == mobile) + * `desktop` - 桌面屏幕模式 + * `mobile` - 手机屏幕模式 +* `screenSize` Object - 设置模拟屏幕的尺寸 (screenPosition == mobile) * `width` Integer - 设置模拟屏幕 width * `height` Integer - 设置模拟屏幕 height -* `viewPosition` Object - 在屏幕放置 view +* `viewPosition` Object - 屏幕中可视区域的位置 (screenPosition == mobile) (默认: `{x: 0, y: 0}`) * `x` Integer - 设置偏移左上角的x轴 * `y` Integer - 设置偏移左上角的y轴 -* `deviceScaleFactor` Integer - 设置设备比例因子 (如果为0,默认为原始屏幕比例) (默认: `0`) -* `viewSize` Object - 设置模拟视图 size (空表示不覆盖) +* `deviceScaleFactor` Integer - 设置设备缩放比例系数 (如果为0,默认为原始屏幕比例) (默认: `0`) +* `viewSize` Object - 设置模拟视图的尺寸 (空表示不覆盖) * `width` Integer - 设置模拟视图 width * `height` Integer - 设置模拟视图 height * `fitToView` Boolean - 如果有必要的话,是否把模拟视图按比例缩放来适应可用空间 (默认: `false`) @@ -749,32 +1018,30 @@ app.on('ready', function () { 使用给定的参数来开启设备模拟。 -### `webContents.disableDeviceEmulation()` +#### `contents.disableDeviceEmulation()` -使用 `webContents.enableDeviceEmulation` 关闭设备模拟。 +关闭模拟器,使用 `webContents.enableDeviceEmulation` 来启用。 -### `webContents.sendInputEvent(event)` +#### `contents.sendInputEvent(event)` * `event` Object * `type` String (**必需**) - 事件类型,可以是 `mouseDown`, `mouseUp`, `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel`, `mouseMove`, `keyDown`, `keyUp`, `char`. - * `modifiers` Array - 事件的 modifiers 数组, 可以是 - include `shift`, `control`, `alt`, `meta`, `isKeypad`, `isAutoRepeat`, + * `modifiers` String[] - 事件的 modifiers 数组, 可以包含 `shift`, `control`, `alt`, `meta`, `isKeypad`, `isAutoRepeat`, `leftButtonDown`, `middleButtonDown`, `rightButtonDown`, `capsLock`, `numLock`, `left`, `right`. -向 page 发送一个输入 `event`。 +向页面发送一个输入 `event`。 对键盘事件来说,`event` 对象还有如下属性: -* `keyCode` String (**必需**) - 特点是将作为键盘事件发送。可用的 key codes [Accelerator](accelerator.md)。 - +* `keyCode` String (**必需**) - 将字符串作为键盘事件发送。可用的 key codes [Accelerator](accelerator.md)。 对鼠标事件来说,`event` 对象还有如下属性: -* `x` Integer (**required**) -* `y` Integer (**required**) +* `x` Integer (**必需**) +* `y` Integer (**必需**) * `button` String - button 按下, 可以是 `left`, `middle`, `right` * `globalX` Integer * `globalY` Integer @@ -793,122 +1060,151 @@ app.on('ready', function () { * `hasPreciseScrollingDeltas` Boolean * `canScroll` Boolean -### `webContents.beginFrameSubscription(callback)` - +#### `contents.beginFrameSubscription(callback)` +* `onlyDirty` Boolean (可选) - 默认值为 `false` * `callback` Function - + * `frameBuffer` Buffer + * `dirtyRect` [Rectangle](structures/rectangle.md) + 开始订阅 提交 事件和捕获数据帧,当有提交事件时,使用 `callback(frameBuffer)` 调用 `callback`。 `frameBuffer` 是一个包含原始像素数据的 `Buffer`,像素数据是按照 32bit BGRA 格式有效存储的,但是实际情况是取决于处理器的字节顺序的(大多数的处理器是存放小端序的,如果是在大端序的处理器上,数据是 32bit ARGB 格式)。 -### `webContents.endFrameSubscription()` +`dirtyRect` 脏区域是一个包含 `x, y, width, height` 属性的对象,它们描述了一个页面中的重绘区域。如果 `onlyDirty` 被设置为`true`, `frameBuffer` 将只包含重绘区域。`onlyDirty` 的默认值为 `false`. + +#### `contents.endFrameSubscription()` 停止订阅帧提交事件。 -### `webContents.savePage(fullPath, saveType, callback)` +#### `contents.startDrag(item)` + +* `item` Object + * `file` String 或 `files` Array - 要拖拽的文件(可以为多个)的路径。 + * `icon` [NativeImage](native-image.md) - 在 macOS 中图标不能为空. + +设置 `item` 作为当前拖拽操作的对象。`file` 是作为拖拽文件的绝对路径。`icon` 是拖拽时光标下面显示的图像。 + +#### `contents.savePage(fullPath, saveType, callback)` * `fullPath` String - 文件的完整路径. * `saveType` String - 指定保存类型. * `HTMLOnly` - 只保存html. * `HTMLComplete` - 保存整个 page 内容. * `MHTML` - 保存完整的 html 为 MHTML. -* `callback` Function - `function(error) {}`. +* `callback` Function - `(error) => {}`. * `error` Error -如果保存界面过程初始化成功,返回 true。 +Returns `Boolean` - 如果保存界面过程初始化成功,返回 true。 ```javascript +const {BrowserWindow} = require('electron') +let win = new BrowserWindow() + win.loadURL('https://github.com') -win.webContents.on('did-finish-load', function () { - win.webContents.savePage('/tmp/test.html', 'HTMLComplete', function (error) { +win.webContents.on('did-finish-load', () => { + win.webContents.savePage('/tmp/test.html', 'HTMLComplete', (error) => { if (!error) console.log('Save page successfully') }) }) ``` -## 实例属性 +#### `contents.showDefinitionForSelection()` _macOS_ + +在页面上显示搜索的弹窗。 + +#### `contents.setSize(options)` + +设置页面的大小。This is only supported for `` guest contents. + +* `options` Object + * `normal` Object (可选) - Normal size of the page. This can be used in + combination with the [`disableguestresize`](web-view-tag.md#disableguestresize) + attribute to manually resize the webview guest contents. + * `width` Integer + * `height` Integer + +#### `contents.isOffscreen()` + +Returns `Boolean` - 表明是否设置了 *offscreen rendering*. + +#### `contents.startPainting()` + +如果设置了 *offscreen rendering* 并且没有绘制,开始绘制. + +#### `contents.stopPainting()` + +如果设置了 *offscreen rendering* 并且绘制了,停止绘制. + +#### `contents.isPainting()` + +Returns `Boolean` - 如果设置了 *offscreen rendering* ,返回当前是否正在绘制. + +#### `contents.setFrameRate(fps)` + +* `fps` Integer + +如果设置了 *offscreen rendering*,设置帧频为制定数值。有效范围为1-60. + +#### `contents.getFrameRate()` + +Returns `Integer` - 如果设置了 *offscreen rendering*,返回当前的帧频 + +#### `contents.invalidate()` + +全部重新绘制整个页面的内容。 + +如果设置了*offscreen rendering* ,让页面失效并且生成一个新的`'paint'`事件 + +#### `contents.getWebRTCIPHandlingPolicy()` + +Returns `String` - Returns the WebRTC IP Handling Policy. + +#### `contents.setWebRTCIPHandlingPolicy(policy)` + +* `policy` String - Specify the WebRTC IP Handling Policy. + * `default` - Exposes user's public and local IPs. This is the default + behavior. When this policy is used, WebRTC has the right to enumerate all + interfaces and bind them to discover public interfaces. + * `default_public_interface_only` - Exposes user's public IP, but does not + expose user's local IP. When this policy is used, WebRTC should only use the + default route used by http. This doesn't expose any local addresses. + * `default_public_and_private_interfaces` - Exposes user's public and local + IPs. When this policy is used, WebRTC should only use the default route used + by http. This also exposes the associated default private address. Default + route is the route chosen by the OS on a multi-homed endpoint. + * `disable_non_proxied_udp` - Does not expose public or local IPs. When this + policy is used, WebRTC should only use TCP to contact peers or servers unless + the proxy server supports UDP. + +Setting the WebRTC IP handling policy allows you to control which IPs are +exposed via WebRTC. See [BrowserLeaks](https://browserleaks.com/webrtc) for +more details. + +### 实例属性 `WebContents` 对象也有下列属性: -### `webContents.session` +#### `contents.id` + +表明 WebContents 唯一标示的整数 + +#### `contents.session` 返回这个 `webContents` 使用的 [session](session.md) 对象。 -### `webContents.hostWebContents` +#### `contents.hostWebContents` -返回这个 `webContents` 的父 `webContents`。 +返回这个 `webContents` 的父 [`WebContents`](web-contents.md)。 -### `webContents.devToolsWebContents` +#### `contents.devToolsWebContents` 获取这个 `WebContents` 的开发者工具栏的 `WebContents`。 **注意:** 用户不可保存这个对象,因为当开发者工具栏关闭的时候它的值为 `null`。 -### `webContents.debugger` +#### `contents.debugger` -调试 API 为 [remote debugging protocol][rdp] 提供交替传送。 +webContents 的 [Debugger](debugger.md) 实例. -```javascript -try { - win.webContents.debugger.attach('1.1') -} catch (err) { - console.log('Debugger attach failed : ', err) -} - -win.webContents.debugger.on('detach', function (event, reason) { - console.log('Debugger detached due to : ', reason) -}) - -win.webContents.debugger.on('message', function (event, method, params) { - if (method === 'Network.requestWillBeSent') { - if (params.request.url === 'https://www.github.com') { - win.webContents.debugger.detach() - } - } -}) - -win.webContents.debugger.sendCommand('Network.enable') -``` - -#### `webContents.debugger.attach([protocolVersion])` - -* `protocolVersion` String (可选) - 请求调试协议版本。 - -添加 `webContents` 调试。 - -#### `webContents.debugger.isAttached()` - -返回一个布尔值,标识是否已经给 `webContents` 添加了调试。 - -#### `webContents.debugger.detach()` - -删除 `webContents` 调试。 - -#### `webContents.debugger.sendCommand(method[, commandParams, callback])` - -* `method` String - 方法名, 应该是由远程调试协议定义的方法。 -* `commandParams` Object (可选) - 请求参数为 JSON 对象。 -* `callback` Function (可选) - Response - * `error` Object - 错误消息,标识命令失败。 - * `result` Object - 回复在远程调试协议中由 'returns'属性定义的命令描述。 - -发送给定命令给调试目标。 - -### Event: 'detach' - -* `event` Event -* `reason` String - 拆分调试器原因。 - -在调试 session 结束时发出事件.这在 `webContents` 关闭时或 `webContents` 请求开发者工具栏时发生。 - -### Event: 'message' - -* `event` Event -* `method` String - 方法名。 -* `params` Object - 在远程调试协议中由 'parameters' 属性定义的事件参数。 - -每当调试目标发出事件时发出。 - -[rdp]: https://developer.chrome.com/devtools/docs/debugger-protocol -[`webContents.findInPage`]: web-contents.md#webcontentsfindinpagetext-options +[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent From 34a91434aac148d8562da23af5e2001a347fb223 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 1 Apr 2017 22:01:29 +0200 Subject: [PATCH 109/337] Remove extra spaces. --- atom/browser/native_window_mac.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 4cec64e1cade..d8fc4617966b 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1358,22 +1358,22 @@ void NativeWindowMac::SetVibrancy(const std::string& type) { // they are available in the minimum SDK version if (type == "selection") { // NSVisualEffectMaterialSelection - vibrancyType = static_cast( 4); + vibrancyType = static_cast(4); } else if (type == "menu") { // NSVisualEffectMaterialMenu - vibrancyType = static_cast( 5); + vibrancyType = static_cast(5); } else if (type == "popover") { // NSVisualEffectMaterialPopover - vibrancyType = static_cast( 6); + vibrancyType = static_cast(6); } else if (type == "sidebar") { // NSVisualEffectMaterialSidebar - vibrancyType = static_cast( 7); + vibrancyType = static_cast(7); } else if (type == "medium-light") { // NSVisualEffectMaterialMediumLight - vibrancyType = static_cast( 8); + vibrancyType = static_cast(8); } else if (type == "ultra-dark") { // NSVisualEffectMaterialUltraDark - vibrancyType = static_cast( 9); + vibrancyType = static_cast(9); } } From 673f4f4d0c9167bc03a54e73bad4b0cab78708eb Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Mon, 3 Apr 2017 19:46:24 +0900 Subject: [PATCH 110/337] Add test for `require` to search under app dir --- spec/modules-spec.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/modules-spec.js b/spec/modules-spec.js index 5f8271752711..26cafc7ccb25 100644 --- a/spec/modules-spec.js +++ b/spec/modules-spec.js @@ -2,6 +2,8 @@ const assert = require('assert') const Module = require('module') const path = require('path') const temp = require('temp') +const {remote} = require('electron') +const {BrowserWindow} = remote describe('third-party module', function () { var fixtures = path.join(__dirname, 'fixtures') @@ -129,3 +131,17 @@ describe('Module._nodeModulePaths', function () { }) }) }) + +describe('require', () => { + describe('when loaded URL is not file: protocol', () => { + it('searches for module under app directory', async () => { + const w = new BrowserWindow({ + show: false, + }) + w.loadURL('about:blank') + const result = await w.webContents.executeJavaScript('typeof require("q").when') + assert.equal(result, 'function') + w.destroy() + }) + }) +}) From 50c99e4507d3a9f06c66d52754c977d24eea347c Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Mon, 3 Apr 2017 20:12:02 +0900 Subject: [PATCH 111/337] Search for module under the app directory --- lib/renderer/init.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/renderer/init.js b/lib/renderer/init.js index 38441c9ec143..c6fd6a2e24c5 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -116,6 +116,9 @@ if (nodeIntegration === 'true') { } else { global.__filename = __filename global.__dirname = __dirname + + // Search for module under the app directory + module.paths = module.paths.concat(Module._nodeModulePaths(electron.remote.app.getAppPath())) } // Redirect window.onerror to uncaughtException. From d1212d4a43a15dc1d501365cda513e7dcee51353 Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Mon, 3 Apr 2017 20:23:36 +0900 Subject: [PATCH 112/337] Fix JS style --- spec/modules-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/modules-spec.js b/spec/modules-spec.js index 26cafc7ccb25..c918d377ddb8 100644 --- a/spec/modules-spec.js +++ b/spec/modules-spec.js @@ -136,7 +136,7 @@ describe('require', () => { describe('when loaded URL is not file: protocol', () => { it('searches for module under app directory', async () => { const w = new BrowserWindow({ - show: false, + show: false }) w.loadURL('about:blank') const result = await w.webContents.executeJavaScript('typeof require("q").when') From 001d03c859be5e68267c6b59d3a73d7f2fe7a9fd Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Mon, 3 Apr 2017 22:11:29 +0900 Subject: [PATCH 113/337] Do not add search paths in devtools --- lib/renderer/init.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/renderer/init.js b/lib/renderer/init.js index c6fd6a2e24c5..72f7c9ebab9a 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -117,8 +117,11 @@ if (nodeIntegration === 'true') { global.__filename = __filename global.__dirname = __dirname - // Search for module under the app directory - module.paths = module.paths.concat(Module._nodeModulePaths(electron.remote.app.getAppPath())) + if (window.location.protocol !== 'chrome-devtools:') { + // Search for module under the app directory + // (remote.app doesn't work in devtools) + module.paths = module.paths.concat(Module._nodeModulePaths(electron.remote.app.getAppPath())) + } } // Redirect window.onerror to uncaughtException. From 0989fd7a1cf694d9d324bfc31939afb10907ad5e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 08:32:16 -0700 Subject: [PATCH 114/337] Upgrade brightray to latest --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index 53aa2cfc8a40..baccc077948f 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 53aa2cfc8a40627d62bf5be757ff9dea444f80bd +Subproject commit baccc077948f504c6a6db58e855fd33938b2b625 From 257f6b142f6e726dae1f767727e7255cbc2162b0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 09:09:37 -0700 Subject: [PATCH 115/337] Add spec for remote setter not surfacing error --- spec/api-ipc-spec.js | 12 ++++++++++++ spec/fixtures/module/error-properties.js | 11 +++++++++++ 2 files changed, 23 insertions(+) create mode 100644 spec/fixtures/module/error-properties.js diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index 47f2eef21685..c5e38e83e4db 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -187,6 +187,18 @@ describe('ipc module', function () { property.property = 1127 }) + it('rethrows errors getting/setting properties', function () { + const foo = remote.require(path.join(fixtures, 'module', 'error-properties.js')) + + assert.throws(function () { + foo.bar + }, /getting error/) + + assert.throws(function () { + foo.bar = 'test' + }, /setting error/) + }) + it('can construct an object from its member', function () { var call = remote.require(path.join(fixtures, 'module', 'call.js')) var obj = new call.constructor() diff --git a/spec/fixtures/module/error-properties.js b/spec/fixtures/module/error-properties.js new file mode 100644 index 000000000000..c3a1e3b3a7f6 --- /dev/null +++ b/spec/fixtures/module/error-properties.js @@ -0,0 +1,11 @@ +class Foo { + set bar (value) { + throw new Error('setting error') + } + + get bar () { + throw new Error('getting error') + } +} + +module.exports = new Foo() From 1ed443ea294ad4a84e1100c90ea5acf3df2e29f3 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 13:21:44 -0400 Subject: [PATCH 116/337] Do the callback & release dance --- .../api/atom_api_certificate_trust_mac.mm | 59 +++++++++++++------ 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/atom/browser/api/atom_api_certificate_trust_mac.mm b/atom/browser/api/atom_api_certificate_trust_mac.mm index 5057ef55ab51..d767330c9453 100644 --- a/atom/browser/api/atom_api_certificate_trust_mac.mm +++ b/atom/browser/api/atom_api_certificate_trust_mac.mm @@ -17,6 +17,26 @@ #include "net/cert/x509_certificate.h" #include "net/cert/cert_database.h" +@interface Trampoline : NSObject + +- (void)createPanelDidEnd:(NSWindow *)sheet + returnCode:(int)returnCode + contextInfo:(void *)contextInfo; + +@end + +@implementation Trampoline + +- (void)createPanelDidEnd:(NSWindow *)sheet + returnCode:(int)returnCode + contextInfo:(void *)contextInfo { + void (^block)(int) = (void (^)(int))contextInfo; + block(returnCode); + [(id)block autorelease]; +} + +@end + namespace atom { namespace api { @@ -26,28 +46,33 @@ void ShowCertificateTrustUI(atom::NativeWindow* parent_window, std::string message, const ShowTrustCallback& callback) { auto sec_policy = SecPolicyCreateBasicX509(); + auto cert_chain = cert->CreateOSCertChainForCert(); SecTrustRef trust = nullptr; - SecTrustCreateWithCertificates(cert->CreateOSCertChainForCert(), sec_policy, &trust); - // CFRelease(sec_policy); - - // NSWindow* window = parent_window ? - // parent_window->GetNativeWindow() : - // NULL; - - auto msg = base::SysUTF8ToNSString(message); + SecTrustCreateWithCertificates(cert_chain, sec_policy, &trust); SFCertificateTrustPanel *panel = [[SFCertificateTrustPanel alloc] init]; - [panel runModalForTrust:trust message:msg]; - // [panel beginSheetForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL trust:trust message:msg]; - auto cert_db = net::CertDatabase::GetInstance(); - // This forces Chromium to reload the certificate since it might be trusted - // now. - cert_db->NotifyObserversCertDBChanged(cert.get()); + void (^callbackBlock)(int) = [^(int returnCode) { + // if (returnCode == NSFileHandlingPanelOKButton) { + auto cert_db = net::CertDatabase::GetInstance(); + // This forces Chromium to reload the certificate since it might be trusted + // now. + cert_db->NotifyObserversCertDBChanged(cert.get()); + // } - callback.Run(true); - // CFRelease(trust); - // [panel release]; + callback.Run(returnCode); + + [panel autorelease]; + CFRelease(trust); + CFRelease(cert_chain); + CFRelease(sec_policy); + } copy]; + + NSWindow* window = parent_window ? + parent_window->GetNativeWindow() : + NULL; + auto msg = base::SysUTF8ToNSString(message); + [panel beginSheetForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:callbackBlock trust:trust message:msg]; } } // namespace api From 4bbbcd093b7812b8658b6e585973d132576b0a47 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 14:01:48 -0400 Subject: [PATCH 117/337] Handle the callback and cleanup properly --- .../api/atom_api_certificate_trust_mac.mm | 102 +++++++++++++----- 1 file changed, 73 insertions(+), 29 deletions(-) diff --git a/atom/browser/api/atom_api_certificate_trust_mac.mm b/atom/browser/api/atom_api_certificate_trust_mac.mm index d767330c9453..7f14a72f5016 100644 --- a/atom/browser/api/atom_api_certificate_trust_mac.mm +++ b/atom/browser/api/atom_api_certificate_trust_mac.mm @@ -17,22 +17,71 @@ #include "net/cert/x509_certificate.h" #include "net/cert/cert_database.h" -@interface Trampoline : NSObject +@interface TrustDelegate : NSObject { + @private + atom::api::ShowTrustCallback callback_; + SFCertificateTrustPanel* panel_; + scoped_refptr cert_; + SecTrustRef trust_; + CFArrayRef cert_chain_; + SecPolicyRef sec_policy_; +} -- (void)createPanelDidEnd:(NSWindow *)sheet +- (id)initWithCallback:(const atom::api::ShowTrustCallback&)callback + panel:(SFCertificateTrustPanel*)panel + cert:(const scoped_refptr&)cert + trust:(SecTrustRef)trust + certChain:(CFArrayRef)certChain + secPolicy:(SecPolicyRef)secPolicy; + +- (void)panelDidEnd:(NSWindow *)sheet returnCode:(int)returnCode - contextInfo:(void *)contextInfo; + contextInfo:(void*)contextInfo; @end -@implementation Trampoline +@implementation TrustDelegate -- (void)createPanelDidEnd:(NSWindow *)sheet +- (void)dealloc { + [panel_ release]; + CFRelease(trust_); + CFRelease(cert_chain_); + CFRelease(sec_policy_); + + [super dealloc]; +} + +- (id)initWithCallback:(const atom::api::ShowTrustCallback&)callback + panel:(SFCertificateTrustPanel*)panel + cert:(const scoped_refptr&)cert + trust:(SecTrustRef)trust + certChain:(CFArrayRef)certChain + secPolicy:(SecPolicyRef)secPolicy { + if ((self = [super init])) { + callback_ = callback; + panel_ = panel; + cert_ = cert; + trust_ = trust; + cert_chain_ = certChain; + sec_policy_ = secPolicy; + } + + return self; +} + +- (void)panelDidEnd:(NSWindow *)sheet returnCode:(int)returnCode - contextInfo:(void *)contextInfo { - void (^block)(int) = (void (^)(int))contextInfo; - block(returnCode); - [(id)block autorelease]; + contextInfo:(void*)contextInfo { + if (returnCode == NSFileHandlingPanelOKButton) { + auto cert_db = net::CertDatabase::GetInstance(); + // This forces Chromium to reload the certificate since it might be trusted + // now. + cert_db->NotifyObserversCertDBChanged(cert_.get()); + } + + callback_.Run(returnCode); + + [self autorelease]; } @end @@ -50,29 +99,24 @@ void ShowCertificateTrustUI(atom::NativeWindow* parent_window, SecTrustRef trust = nullptr; SecTrustCreateWithCertificates(cert_chain, sec_policy, &trust); - SFCertificateTrustPanel *panel = [[SFCertificateTrustPanel alloc] init]; - - void (^callbackBlock)(int) = [^(int returnCode) { - // if (returnCode == NSFileHandlingPanelOKButton) { - auto cert_db = net::CertDatabase::GetInstance(); - // This forces Chromium to reload the certificate since it might be trusted - // now. - cert_db->NotifyObserversCertDBChanged(cert.get()); - // } - - callback.Run(returnCode); - - [panel autorelease]; - CFRelease(trust); - CFRelease(cert_chain); - CFRelease(sec_policy); - } copy]; - NSWindow* window = parent_window ? parent_window->GetNativeWindow() : - NULL; + nil; auto msg = base::SysUTF8ToNSString(message); - [panel beginSheetForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:callbackBlock trust:trust message:msg]; + + SFCertificateTrustPanel *panel = [[SFCertificateTrustPanel alloc] init]; + auto delegate = [[TrustDelegate alloc] initWithCallback:callback + panel:panel + cert:cert + trust:trust + certChain:cert_chain + secPolicy:sec_policy]; + [panel beginSheetForWindow:window + modalDelegate:delegate + didEndSelector:@selector(panelDidEnd:returnCode:contextInfo:) + contextInfo:nil + trust:trust + message:msg]; } } // namespace api From 6e89cb9d7c8fe28ffb3148b518a070b12c657e8f Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:05:24 -0400 Subject: [PATCH 118/337] Move it into `dialog` --- atom/browser/api/atom_api_app.cc | 12 ------- atom/browser/api/atom_api_app.h | 10 ------ atom/browser/api/atom_api_certificate_trust.h | 34 ------------------- atom/browser/api/atom_api_dialog.cc | 15 ++++++++ atom/browser/ui/certificate_trust.h | 29 ++++++++++++++++ .../certificate_trust_mac.mm} | 25 ++++++-------- filenames.gypi | 4 +-- 7 files changed, 56 insertions(+), 73 deletions(-) delete mode 100644 atom/browser/api/atom_api_certificate_trust.h create mode 100644 atom/browser/ui/certificate_trust.h rename atom/browser/{api/atom_api_certificate_trust_mac.mm => ui/certificate_trust_mac.mm} (83%) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 41e7655a66f1..56a11daf69bd 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -7,7 +7,6 @@ #include #include -#include "atom/browser/api/atom_api_certificate_trust.h" #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_session.h" #include "atom/browser/api/atom_api_web_contents.h" @@ -811,16 +810,6 @@ void App::OnCertificateManagerModelCreated( } #endif -#if defined(OS_MACOSX) -void App::ShowCertificateTrust(atom::NativeWindow* parent_window, - const scoped_refptr& cert, - std::string message, - const ShowTrustCallback& callback, - mate::Arguments* args) { - ShowCertificateTrustUI(parent_window, cert, message, callback); -} -#endif - #if defined(OS_WIN) v8::Local App::GetJumpListSettings() { JumpList jump_list(Browser::Get()->GetAppUserModelID()); @@ -960,7 +949,6 @@ void App::BuildPrototype( base::Bind(&Browser::GetCurrentActivityType, browser)) .SetMethod("setAboutPanelOptions", base::Bind(&Browser::SetAboutPanelOptions, browser)) - .SetMethod("showCertificateTrust", &App::ShowCertificateTrust) #endif #if defined(OS_WIN) .SetMethod("setUserTasks", base::Bind(&Browser::SetUserTasks, browser)) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 19640cb84886..f2debdf2e533 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -8,7 +8,6 @@ #include #include -#include "atom/browser/api/atom_api_certificate_trust.h" #include "atom/browser/api/event_emitter.h" #include "atom/browser/atom_browser_client.h" #include "atom/browser/browser.h" @@ -153,15 +152,6 @@ class App : public AtomBrowserClient::Delegate, std::unique_ptr certificate_manager_model_; #endif - -#if defined(OS_MACOSX) - void ShowCertificateTrust(atom::NativeWindow* parent_window, - const scoped_refptr& cert, - std::string message, - const ShowTrustCallback& callback, - mate::Arguments* args); -#endif - // Tracks tasks requesting file icons. base::CancelableTaskTracker cancelable_task_tracker_; diff --git a/atom/browser/api/atom_api_certificate_trust.h b/atom/browser/api/atom_api_certificate_trust.h deleted file mode 100644 index 1de7d653bb18..000000000000 --- a/atom/browser/api/atom_api_certificate_trust.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2017 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_CERTIFICATE_TRUST_H_ -#define ATOM_BROWSER_API_ATOM_API_CERTIFICATE_TRUST_H_ - -#include - -#include "base/callback_forward.h" -#include "base/memory/ref_counted.h" - -namespace net { -class X509Certificate; -} // namespace net - -namespace atom { - -class NativeWindow; - -namespace api { - -typedef base::Callback ShowTrustCallback; - -void ShowCertificateTrustUI(atom::NativeWindow* parent_window, - const scoped_refptr& cert, - std::string message, - const ShowTrustCallback& callback); - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_CERTIFICATE_TRUST_H_ diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 326834472d24..310b1b233b80 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -8,11 +8,13 @@ #include "atom/browser/api/atom_api_window.h" #include "atom/browser/native_window.h" +#include "atom/browser/ui/certificate_trust.h" #include "atom/browser/ui/file_dialog.h" #include "atom/browser/ui/message_box.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/image_converter.h" +#include "atom/common/native_mate_converters/net_converter.h" #include "native_mate/dictionary.h" #include "atom/common/node_includes.h" @@ -119,6 +121,16 @@ void ShowSaveDialog(const file_dialog::DialogSettings& settings, } } +// #if defined(OS_MACOSX) +void ShowCertificateTrust(atom::NativeWindow* parent_window, + const scoped_refptr& cert, + std::string message, + const certificate_trust::ShowTrustCallback& callback, + mate::Arguments* args) { + certificate_trust::ShowCertificateTrust(parent_window, cert, message, callback); +} +// #endif + void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { mate::Dictionary dict(context->GetIsolate(), exports); @@ -126,6 +138,9 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("showErrorBox", &atom::ShowErrorBox); dict.SetMethod("showOpenDialog", &ShowOpenDialog); dict.SetMethod("showSaveDialog", &ShowSaveDialog); +// #if defined(OS_MACOSX) + dict.SetMethod("showCertificateTrustDialog", &ShowCertificateTrust); +// #endif } } // namespace diff --git a/atom/browser/ui/certificate_trust.h b/atom/browser/ui/certificate_trust.h new file mode 100644 index 000000000000..30271edff072 --- /dev/null +++ b/atom/browser/ui/certificate_trust.h @@ -0,0 +1,29 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_UI_CERTIFICATE_TRUST_H_ +#define ATOM_BROWSER_UI_CERTIFICATE_TRUST_H_ + +#include + +#include "base/callback_forward.h" +#include "base/memory/ref_counted.h" +#include "net/cert/x509_certificate.h" + +namespace atom { +class NativeWindow; +} // namespace atom + +namespace certificate_trust { + +typedef base::Callback ShowTrustCallback; + +void ShowCertificateTrust(atom::NativeWindow* parent_window, + const scoped_refptr& cert, + std::string message, + const ShowTrustCallback& callback); + +} // namespace certificate_trust + +#endif // ATOM_BROWSER_UI_CERTIFICATE_TRUST_H_ diff --git a/atom/browser/api/atom_api_certificate_trust_mac.mm b/atom/browser/ui/certificate_trust_mac.mm similarity index 83% rename from atom/browser/api/atom_api_certificate_trust_mac.mm rename to atom/browser/ui/certificate_trust_mac.mm index 7f14a72f5016..a3774e51c348 100644 --- a/atom/browser/api/atom_api_certificate_trust_mac.mm +++ b/atom/browser/ui/certificate_trust_mac.mm @@ -2,7 +2,7 @@ // 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_certificate_trust.h" +#include "atom/browser/ui/certificate_trust.h" #import #import @@ -14,12 +14,11 @@ #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" -#include "net/cert/x509_certificate.h" #include "net/cert/cert_database.h" @interface TrustDelegate : NSObject { @private - atom::api::ShowTrustCallback callback_; + certificate_trust::ShowTrustCallback callback_; SFCertificateTrustPanel* panel_; scoped_refptr cert_; SecTrustRef trust_; @@ -27,7 +26,7 @@ SecPolicyRef sec_policy_; } -- (id)initWithCallback:(const atom::api::ShowTrustCallback&)callback +- (id)initWithCallback:(const certificate_trust::ShowTrustCallback&)callback panel:(SFCertificateTrustPanel*)panel cert:(const scoped_refptr&)cert trust:(SecTrustRef)trust @@ -51,7 +50,7 @@ [super dealloc]; } -- (id)initWithCallback:(const atom::api::ShowTrustCallback&)callback +- (id)initWithCallback:(const certificate_trust::ShowTrustCallback&)callback panel:(SFCertificateTrustPanel*)panel cert:(const scoped_refptr&)cert trust:(SecTrustRef)trust @@ -86,14 +85,12 @@ @end -namespace atom { +namespace certificate_trust { -namespace api { - -void ShowCertificateTrustUI(atom::NativeWindow* parent_window, - const scoped_refptr& cert, - std::string message, - const ShowTrustCallback& callback) { +void ShowCertificateTrust(atom::NativeWindow* parent_window, + const scoped_refptr& cert, + std::string message, + const ShowTrustCallback& callback) { auto sec_policy = SecPolicyCreateBasicX509(); auto cert_chain = cert->CreateOSCertChainForCert(); SecTrustRef trust = nullptr; @@ -119,6 +116,4 @@ void ShowCertificateTrustUI(atom::NativeWindow* parent_window, message:msg]; } -} // namespace api - -} // namespace atom +} // namespace certificate_trust diff --git a/filenames.gypi b/filenames.gypi index f2a78ad4d4b6..ff7bbaee4d79 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -103,8 +103,6 @@ 'atom/browser/api/atom_api_app.h', 'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.h', - 'atom/browser/api/atom_api_certificate_trust_mac.mm', - 'atom/browser/api/atom_api_certificate_trust.h', 'atom/browser/api/atom_api_content_tracing.cc', 'atom/browser/api/atom_api_cookies.cc', 'atom/browser/api/atom_api_cookies.h', @@ -281,6 +279,8 @@ 'atom/browser/ui/accelerator_util_views.cc', 'atom/browser/ui/atom_menu_model.cc', 'atom/browser/ui/atom_menu_model.h', + 'atom/browser/ui/certificate_trust_mac.mm', + 'atom/browser/ui/certificate_trust.h', 'atom/browser/ui/cocoa/atom_menu_controller.h', 'atom/browser/ui/cocoa/atom_menu_controller.mm', 'atom/browser/ui/cocoa/atom_touch_bar.h', From 4ffaf2cd99d44b8d143dcc2a4bf81e7a641144a0 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:09:04 -0400 Subject: [PATCH 119/337] Remove old unnecssary change on `app` --- atom/browser/api/atom_api_app.h | 1 - 1 file changed, 1 deletion(-) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index f2debdf2e533..8b276f334d5c 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -19,7 +19,6 @@ #include "content/public/browser/gpu_data_manager_observer.h" #include "native_mate/handle.h" #include "net/base/completion_callback.h" -#include "net/cert/x509_certificate.h" #if defined(USE_NSS_CERTS) #include "chrome/browser/certificate_manager_model.h" From bcecba20e6096e3b8ebeef3daa3a4397d201b6c3 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:09:24 -0400 Subject: [PATCH 120/337] Fix indentation --- atom/browser/api/atom_api_dialog.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 310b1b233b80..6c6e49bb7f7d 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -123,10 +123,10 @@ void ShowSaveDialog(const file_dialog::DialogSettings& settings, // #if defined(OS_MACOSX) void ShowCertificateTrust(atom::NativeWindow* parent_window, - const scoped_refptr& cert, - std::string message, - const certificate_trust::ShowTrustCallback& callback, - mate::Arguments* args) { + const scoped_refptr& cert, + std::string message, + const certificate_trust::ShowTrustCallback& callback, + mate::Arguments* args) { certificate_trust::ShowCertificateTrust(parent_window, cert, message, callback); } // #endif From e85e483c710097a2bf890e52e398044a6d9c1673 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 09:11:06 -0700 Subject: [PATCH 121/337] Parse setting response to surface thrown errors --- lib/renderer/api/remote.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index b3d3d2ab17cc..f65d61790ace 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -139,7 +139,12 @@ const setObjectMembers = function (ref, object, metaId, members) { // Only set setter when it is writable. if (member.writable) { descriptor.set = function (value) { - ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, value) + const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, value) + // Meta will be non-null when a setter error occurred so parse it + // to a value so it gets re-thrown. + if (meta != null) { + metaToValue(meta) + } return value } } From 0b7ffd094aace166dea48e9495d01335f732e97f Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:25:06 -0400 Subject: [PATCH 122/337] Expose through the actual JS API too --- lib/browser/api/dialog.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/browser/api/dialog.js b/lib/browser/api/dialog.js index 834a6a6d7d8d..814a8a2af574 100644 --- a/lib/browser/api/dialog.js +++ b/lib/browser/api/dialog.js @@ -280,6 +280,10 @@ module.exports = { showErrorBox: function (...args) { return binding.showErrorBox(...args) + }, + + showCertificateTrustDialog: function (...args) { + return binding.showCertificateTrustDialog(...args) } } From 11f5c942ce70d85a573d2aa42701d9aa54329b35 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:25:09 -0400 Subject: [PATCH 123/337] Conditionalize --- atom/browser/api/atom_api_dialog.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 6c6e49bb7f7d..9a93ba703770 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -121,7 +121,7 @@ void ShowSaveDialog(const file_dialog::DialogSettings& settings, } } -// #if defined(OS_MACOSX) +#if defined(OS_MACOSX) void ShowCertificateTrust(atom::NativeWindow* parent_window, const scoped_refptr& cert, std::string message, @@ -129,7 +129,7 @@ void ShowCertificateTrust(atom::NativeWindow* parent_window, mate::Arguments* args) { certificate_trust::ShowCertificateTrust(parent_window, cert, message, callback); } -// #endif +#endif void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { @@ -138,9 +138,9 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("showErrorBox", &atom::ShowErrorBox); dict.SetMethod("showOpenDialog", &ShowOpenDialog); dict.SetMethod("showSaveDialog", &ShowSaveDialog); -// #if defined(OS_MACOSX) +#if defined(OS_MACOSX) dict.SetMethod("showCertificateTrustDialog", &ShowCertificateTrust); -// #endif +#endif } } // namespace From 06643e525a084816fab48eb13053d713358a5b95 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:28:44 -0400 Subject: [PATCH 124/337] Const ref that message --- atom/browser/ui/certificate_trust.h | 2 +- atom/browser/ui/certificate_trust_mac.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/ui/certificate_trust.h b/atom/browser/ui/certificate_trust.h index 30271edff072..085d04d1030a 100644 --- a/atom/browser/ui/certificate_trust.h +++ b/atom/browser/ui/certificate_trust.h @@ -21,7 +21,7 @@ typedef base::Callback ShowTrustCallback; void ShowCertificateTrust(atom::NativeWindow* parent_window, const scoped_refptr& cert, - std::string message, + const std::string& message, const ShowTrustCallback& callback); } // namespace certificate_trust diff --git a/atom/browser/ui/certificate_trust_mac.mm b/atom/browser/ui/certificate_trust_mac.mm index a3774e51c348..1e7ad5204f2e 100644 --- a/atom/browser/ui/certificate_trust_mac.mm +++ b/atom/browser/ui/certificate_trust_mac.mm @@ -89,7 +89,7 @@ namespace certificate_trust { void ShowCertificateTrust(atom::NativeWindow* parent_window, const scoped_refptr& cert, - std::string message, + const std::string& message, const ShowTrustCallback& callback) { auto sec_policy = SecPolicyCreateBasicX509(); auto cert_chain = cert->CreateOSCertChainForCert(); From b0ef7ddf44cc7f20f43f4d9cab88ded82e181cab Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:28:51 -0400 Subject: [PATCH 125/337] Use better iteration --- atom/common/native_mate_converters/net_converter.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 2d3095a63ea0..305627ad5bcd 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -71,8 +71,7 @@ v8::Local Converter>::ToV8( dict.Set("issuerCert", issuer_cert); std::vector intermediates_encoded; - for (size_t i = 0; i < intermediates.size(); i++) { - auto native_cert = intermediates[i]; + for (auto& native_cert : intermediates) { std::string encoded; net::X509Certificate::GetPEMEncoded(native_cert, &encoded); intermediates_encoded.push_back(encoded); From da1b0aab3e157c063a7ffc2a94d714d8841261cb Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:39:45 -0400 Subject: [PATCH 126/337] Flesh out some docs --- docs/api/dialog.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 230930abd948..71224b69cd4c 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -175,6 +175,17 @@ it is usually used to report errors in early stage of startup. If called before the app `ready`event on Linux, the message will be emitted to stderr, and no GUI dialog will appear. +### `dialog.showCertificateTrustDialog(browserWindow, certificate, message, callback)` _macOS_ + +* `browserWindow` BrowserWindow +* `certificate` [Certificate](structures/certificate.md) - The certificate to trust/import. +* `message` String - The message to display to the user. +* `callback` Function + * `result` Boolean - Whether the user chose to cancel or continue. + +Displays a modal dialog that shows a message and certificate information, and +gives the user the option of trusting/importing the certificate. + ## Sheets On macOS, dialogs are presented as sheets attached to a window if you provide From b8ff4666c84c249b002cc6fd2aa95bc6b7db6f04 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 15:48:47 -0400 Subject: [PATCH 127/337] Remove stale includes --- atom/browser/ui/certificate_trust_mac.mm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/atom/browser/ui/certificate_trust_mac.mm b/atom/browser/ui/certificate_trust_mac.mm index 1e7ad5204f2e..32dc1ce91e19 100644 --- a/atom/browser/ui/certificate_trust_mac.mm +++ b/atom/browser/ui/certificate_trust_mac.mm @@ -5,14 +5,9 @@ #include "atom/browser/ui/certificate_trust.h" #import -#import #import #include "atom/browser/native_window.h" -#include "base/files/file_util.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" #include "net/cert/cert_database.h" From 74c0cbddaed65827268a9ad19b607b68cdbc245d Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 16:07:02 -0400 Subject: [PATCH 128/337] Linebreak to keep the linter happy --- atom/browser/api/atom_api_dialog.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 9a93ba703770..090f4c5d8ac5 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -127,7 +127,8 @@ void ShowCertificateTrust(atom::NativeWindow* parent_window, std::string message, const certificate_trust::ShowTrustCallback& callback, mate::Arguments* args) { - certificate_trust::ShowCertificateTrust(parent_window, cert, message, callback); + certificate_trust::ShowCertificateTrust(parent_window, cert, + message, callback); } #endif From 370cf815d9ae4ce85c13b7dc725a76e5651169d6 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 16:27:53 -0400 Subject: [PATCH 129/337] Get rid of `intermediates` and rehydrate from `issuerCert` --- .../native_mate_converters/net_converter.cc | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 305627ad5bcd..7453dd009775 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -59,8 +59,7 @@ v8::Local Converter>::ToV8( net::HashValue( val->CalculateFingerprint256(val->os_cert_handle())).ToString()); - auto intermediates = val->GetIntermediateCertificates(); - if (!intermediates.empty()) { + if (!val->GetIntermediateCertificates().empty()) { net::X509Certificate::OSCertHandles issuer_intermediates( val->GetIntermediateCertificates().begin() + 1, val->GetIntermediateCertificates().end()); @@ -69,15 +68,6 @@ v8::Local Converter>::ToV8( val->GetIntermediateCertificates().front(), issuer_intermediates); dict.Set("issuerCert", issuer_cert); - - std::vector intermediates_encoded; - for (auto& native_cert : intermediates) { - std::string encoded; - net::X509Certificate::GetPEMEncoded(native_cert, &encoded); - intermediates_encoded.push_back(encoded); - } - - dict.Set("intermediates", intermediates_encoded); } return dict.GetHandle(); @@ -113,24 +103,21 @@ bool Converter>::FromV8( if (!CertFromData(data, &leaf_cert)) return false; - std::vector intermediates_encoded; - dict.Get("intermediates", &intermediates_encoded); - std::vector intermediates; - for (size_t i = 0; i < intermediates_encoded.size(); i++) { - auto intermediate_data = intermediates_encoded[i]; - scoped_refptr cert; - if (!CertFromData(intermediate_data, &cert)) + scoped_refptr parent; + if (dict.Get("issuerCert", &parent)) { + auto parents = std::vector( + parent->GetIntermediateCertificates()); + parents.insert(parents.begin(), parent->os_cert_handle()); + auto cert = net::X509Certificate::CreateFromHandle( + leaf_cert->os_cert_handle(), parents); + if (!cert) return false; - intermediates.push_back(cert->os_cert_handle()); + *out = cert; + } else { + *out = leaf_cert; } - auto cert = net::X509Certificate::CreateFromHandle( - leaf_cert->os_cert_handle(), intermediates); - if (!cert) - return false; - - *out = cert; return true; } From 9cb6bc098de5a9df75c6afda0be6f5c697a4ed3f Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Tue, 4 Apr 2017 09:08:27 +0900 Subject: [PATCH 130/337] Use beforeEach/afterEach --- spec/modules-spec.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/modules-spec.js b/spec/modules-spec.js index c918d377ddb8..02fec41444d7 100644 --- a/spec/modules-spec.js +++ b/spec/modules-spec.js @@ -134,13 +134,21 @@ describe('Module._nodeModulePaths', function () { describe('require', () => { describe('when loaded URL is not file: protocol', () => { - it('searches for module under app directory', async () => { - const w = new BrowserWindow({ + let w + + beforeEach(() => { + w = new BrowserWindow({ show: false }) + }) + + it('searches for module under app directory', async () => { w.loadURL('about:blank') const result = await w.webContents.executeJavaScript('typeof require("q").when') assert.equal(result, 'function') + }) + + afterEach(() => { w.destroy() }) }) From 4a7eec8f2dd74217aa99d8da4ed0cc61038eee3a Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Tue, 4 Apr 2017 09:36:01 +0900 Subject: [PATCH 131/337] Pass app path as command line argument --- atom/browser/api/atom_api_app.cc | 10 ++++++++++ atom/browser/api/atom_api_app.h | 6 ++++++ atom/browser/atom_browser_client.cc | 6 ++++++ atom/common/options_switches.cc | 3 +++ atom/common/options_switches.h | 1 + lib/browser/api/app.js | 4 ---- lib/renderer/init.js | 8 +++++--- 7 files changed, 31 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 56a11daf69bd..a53e957660ee 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -655,6 +655,14 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) { status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); } +std::string App::GetAppPath() { + return app_path_; +} + +void App::SetAppPath(const std::string& app_path) { + app_path_ = app_path; +} + base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) { bool succeed = false; base::FilePath path; @@ -959,6 +967,8 @@ void App::BuildPrototype( .SetMethod("isUnityRunning", base::Bind(&Browser::IsUnityRunning, browser)) #endif + .SetMethod("setAppPath", &App::SetAppPath) + .SetMethod("getAppPath", &App::GetAppPath) .SetMethod("setPath", &App::SetPath) .SetMethod("getPath", &App::GetPath) .SetMethod("setDesktopName", &App::SetDesktopName) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 8b276f334d5c..4b09d7703105 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -70,6 +70,8 @@ class App : public AtomBrowserClient::Delegate, std::unique_ptr model); #endif + std::string GetAppPath(); + protected: explicit App(v8::Isolate* isolate); ~App() override; @@ -115,6 +117,8 @@ class App : public AtomBrowserClient::Delegate, void OnGpuProcessCrashed(base::TerminationStatus status) override; private: + void SetAppPath(const std::string& app_path); + // Get/Set the pre-defined path in PathService. base::FilePath GetPath(mate::Arguments* args, const std::string& name); void SetPath(mate::Arguments* args, @@ -154,6 +158,8 @@ class App : public AtomBrowserClient::Delegate, // Tracks tasks requesting file icons. base::CancelableTaskTracker cancelable_task_tracker_; + std::string app_path_; + DISALLOW_COPY_AND_ASSIGN(App); }; diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index d0bbf4ad535f..9894e5e9287c 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -234,6 +234,12 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( } #endif + if (delegate_) { + auto app_path = static_cast(delegate_)->GetAppPath(); + command_line->AppendSwitchASCII(switches::kAppPath, + app_path); + } + content::WebContents* web_contents = GetWebContentsFromProcessID(process_id); if (!web_contents) return; diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 288fcd3a0753..2f1c0368f35e 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -159,6 +159,9 @@ const char kSecureSchemes[] = "secure-schemes"; // The browser process app model ID const char kAppUserModelId[] = "app-user-model-id"; +// The application path +const char kAppPath[] = "app-path"; + // The command line switch versions of the options. const char kBackgroundColor[] = "background-color"; const char kPreloadScript[] = "preload"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 9e1a71ca5bda..69e7af029e15 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -81,6 +81,7 @@ extern const char kStandardSchemes[]; extern const char kRegisterServiceWorkerSchemes[]; extern const char kSecureSchemes[]; extern const char kAppUserModelId[]; +extern const char kAppPath[]; extern const char kBackgroundColor[]; extern const char kPreloadScript[]; diff --git a/lib/browser/api/app.js b/lib/browser/api/app.js index c5865f2242b8..d1ca60280e93 100644 --- a/lib/browser/api/app.js +++ b/lib/browser/api/app.js @@ -12,11 +12,7 @@ const {EventEmitter} = require('events') Object.setPrototypeOf(App.prototype, EventEmitter.prototype) -let appPath = null - Object.assign(app, { - getAppPath () { return appPath }, - setAppPath (path) { appPath = path }, setApplicationMenu (menu) { return Menu.setApplicationMenu(menu) }, diff --git a/lib/renderer/init.js b/lib/renderer/init.js index 72f7c9ebab9a..0306463bc486 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -56,6 +56,7 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (ev let nodeIntegration = 'false' let preloadScript = null let isBackgroundPage = false +let appPath = null for (let arg of process.argv) { if (arg.indexOf('--guest-instance-id=') === 0) { // This is a guest web view. @@ -69,6 +70,8 @@ for (let arg of process.argv) { preloadScript = arg.substr(arg.indexOf('=') + 1) } else if (arg === '--background-page') { isBackgroundPage = true + } else if (arg.indexOf('--app-path=') === 0) { + appPath = arg.substr(arg.indexOf('=') + 1) } } @@ -117,10 +120,9 @@ if (nodeIntegration === 'true') { global.__filename = __filename global.__dirname = __dirname - if (window.location.protocol !== 'chrome-devtools:') { + if (appPath) { // Search for module under the app directory - // (remote.app doesn't work in devtools) - module.paths = module.paths.concat(Module._nodeModulePaths(electron.remote.app.getAppPath())) + module.paths = module.paths.concat(Module._nodeModulePaths(appPath)) } } From 24fedb2e20e9468f9b12a03198fe9c649039a9e5 Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Tue, 4 Apr 2017 09:40:38 +0900 Subject: [PATCH 132/337] No extra linebreak --- atom/browser/atom_browser_client.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 9894e5e9287c..3908c9613a03 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -236,8 +236,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( if (delegate_) { auto app_path = static_cast(delegate_)->GetAppPath(); - command_line->AppendSwitchASCII(switches::kAppPath, - app_path); + command_line->AppendSwitchASCII(switches::kAppPath, app_path); } content::WebContents* web_contents = GetWebContentsFromProcessID(process_id); From 398132cfe383f3e8cbc3742011596fcd4dceaed9 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 21:19:00 -0400 Subject: [PATCH 133/337] Fix file sorting --- filenames.gypi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filenames.gypi b/filenames.gypi index ff7bbaee4d79..192d953287d7 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -279,8 +279,8 @@ 'atom/browser/ui/accelerator_util_views.cc', 'atom/browser/ui/atom_menu_model.cc', 'atom/browser/ui/atom_menu_model.h', - 'atom/browser/ui/certificate_trust_mac.mm', 'atom/browser/ui/certificate_trust.h', + 'atom/browser/ui/certificate_trust_mac.mm', 'atom/browser/ui/cocoa/atom_menu_controller.h', 'atom/browser/ui/cocoa/atom_menu_controller.mm', 'atom/browser/ui/cocoa/atom_touch_bar.h', From b3e865a4787b8b0aa844c8466a0b8ca83649314c Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 21:22:14 -0400 Subject: [PATCH 134/337] Fix some style things --- atom/browser/ui/certificate_trust_mac.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/browser/ui/certificate_trust_mac.mm b/atom/browser/ui/certificate_trust_mac.mm index 32dc1ce91e19..ad54eaa3831c 100644 --- a/atom/browser/ui/certificate_trust_mac.mm +++ b/atom/browser/ui/certificate_trust_mac.mm @@ -28,7 +28,7 @@ certChain:(CFArrayRef)certChain secPolicy:(SecPolicyRef)secPolicy; -- (void)panelDidEnd:(NSWindow *)sheet +- (void)panelDidEnd:(NSWindow*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo; @@ -63,7 +63,7 @@ return self; } -- (void)panelDidEnd:(NSWindow *)sheet +- (void)panelDidEnd:(NSWindow*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo { if (returnCode == NSFileHandlingPanelOKButton) { @@ -73,7 +73,7 @@ cert_db->NotifyObserversCertDBChanged(cert_.get()); } - callback_.Run(returnCode); + callback_.Run(returnCode == NSFileHandlingPanelOKButton ? true : false); [self autorelease]; } @@ -96,7 +96,7 @@ void ShowCertificateTrust(atom::NativeWindow* parent_window, nil; auto msg = base::SysUTF8ToNSString(message); - SFCertificateTrustPanel *panel = [[SFCertificateTrustPanel alloc] init]; + auto panel = [[SFCertificateTrustPanel alloc] init]; auto delegate = [[TrustDelegate alloc] initWithCallback:callback panel:panel cert:cert From 2badfbe04fbee7104317cffa7031b8fedf1191e8 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 21:22:37 -0400 Subject: [PATCH 135/337] Remove the intermediate function --- atom/browser/api/atom_api_dialog.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 090f4c5d8ac5..0105a433dbfd 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -121,17 +121,6 @@ void ShowSaveDialog(const file_dialog::DialogSettings& settings, } } -#if defined(OS_MACOSX) -void ShowCertificateTrust(atom::NativeWindow* parent_window, - const scoped_refptr& cert, - std::string message, - const certificate_trust::ShowTrustCallback& callback, - mate::Arguments* args) { - certificate_trust::ShowCertificateTrust(parent_window, cert, - message, callback); -} -#endif - void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { mate::Dictionary dict(context->GetIsolate(), exports); @@ -140,7 +129,7 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("showOpenDialog", &ShowOpenDialog); dict.SetMethod("showSaveDialog", &ShowSaveDialog); #if defined(OS_MACOSX) - dict.SetMethod("showCertificateTrustDialog", &ShowCertificateTrust); + dict.SetMethod("showCertificateTrustDialog", &certificate_trust::ShowCertificateTrust); #endif } From e2bda3ca0f8cc1bf982815040df78cb952261e79 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 21:33:21 -0400 Subject: [PATCH 136/337] Use an options object for most of the params --- docs/api/dialog.md | 7 ++++--- lib/browser/api/dialog.js | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 71224b69cd4c..17aa7341bb57 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -175,11 +175,12 @@ it is usually used to report errors in early stage of startup. If called before the app `ready`event on Linux, the message will be emitted to stderr, and no GUI dialog will appear. -### `dialog.showCertificateTrustDialog(browserWindow, certificate, message, callback)` _macOS_ +### `dialog.showCertificateTrustDialog(browserWindow, options, callback)` _macOS_ * `browserWindow` BrowserWindow -* `certificate` [Certificate](structures/certificate.md) - The certificate to trust/import. -* `message` String - The message to display to the user. +* `options` Object + * `certificate` [Certificate](structures/certificate.md) - The certificate to trust/import. + * `message` String - The message to display to the user. * `callback` Function * `result` Boolean - Whether the user chose to cancel or continue. diff --git a/lib/browser/api/dialog.js b/lib/browser/api/dialog.js index 814a8a2af574..908ffaf670f4 100644 --- a/lib/browser/api/dialog.js +++ b/lib/browser/api/dialog.js @@ -282,8 +282,23 @@ module.exports = { return binding.showErrorBox(...args) }, - showCertificateTrustDialog: function (...args) { - return binding.showCertificateTrustDialog(...args) + showCertificateTrustDialog: function (window, options, callback) { + if (options == null || typeof options !== 'object') { + throw new TypeError('options must be an object') + } + + let {certificate, message} = options + if (certificate == null || typeof options !== 'object') { + throw new TypeError('certificate must be an object') + } + + if (message == null) { + message = '' + } else if (typeof message !== 'string') { + throw new TypeError('message must be a string') + } + + return binding.showCertificateTrustDialog(window, certificate, message, callback) } } From 8d465234e40e601e215220270e5c11eec8469276 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 3 Apr 2017 21:40:46 -0400 Subject: [PATCH 137/337] Appease our linty overlords --- atom/browser/api/atom_api_dialog.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 0105a433dbfd..4f152e3602df 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -129,7 +129,8 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("showOpenDialog", &ShowOpenDialog); dict.SetMethod("showSaveDialog", &ShowSaveDialog); #if defined(OS_MACOSX) - dict.SetMethod("showCertificateTrustDialog", &certificate_trust::ShowCertificateTrust); + dict.SetMethod("showCertificateTrustDialog", + &certificate_trust::ShowCertificateTrust); #endif } From 6169ccd1e2b4595e083b7a3d38281ed4db638772 Mon Sep 17 00:00:00 2001 From: Philip Jackson Date: Tue, 4 Apr 2017 18:00:20 +1200 Subject: [PATCH 138/337] :memo: Document that setApplicationMenu(null) has no effect on macOS --- docs/api/menu.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/api/menu.md b/docs/api/menu.md index 13585fef72e7..72d8164270dc 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -16,9 +16,11 @@ The `menu` class has the following static methods: * `menu` Menu -Sets `menu` as the application menu on macOS. On Windows and Linux, the `menu` -will be set as each window's top menu. Setting it to `null` will remove the -menu bar. +Sets `menu` as the application menu on macOS. On Windows and Linux, the +`menu` will be set as each window's top menu. + +Passing `null` will remove the menu bar on Windows and Linux but has no +effect on macOS. **Note:** This API has to be called after the `ready` event of `app` module. From 568454525db8dbbde99b240cdfd264625e10bce8 Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Tue, 4 Apr 2017 00:35:39 +0200 Subject: [PATCH 139/337] Use point / size / rectangle structures consistently in API docs --- docs/api/browser-window.md | 4 +--- docs/api/desktop-capturer.md | 5 ++--- docs/api/native-image.md | 11 ++--------- docs/api/screen.md | 9 ++------- docs/api/structures/display.md | 8 ++------ docs/api/structures/point.md | 4 ++++ docs/api/structures/size.md | 4 ++++ docs/api/tray.md | 4 +--- docs/api/web-contents.md | 26 +++++++------------------- 9 files changed, 25 insertions(+), 50 deletions(-) create mode 100644 docs/api/structures/point.md create mode 100644 docs/api/structures/size.md diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 01f5431ecf73..ee46a3fa03ec 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -682,10 +682,8 @@ Returns `Boolean` - Whether the window is in fullscreen mode. * `aspectRatio` Float - The aspect ratio to maintain for some portion of the content view. -* `extraSize` Object (optional) - The extra size not to be included while +* `extraSize` [Size](structures/size.md) - The extra size not to be included while maintaining the aspect ratio. - * `width` Integer - * `height` Integer This will make a window maintain an aspect ratio. The extra size allows a developer to have space, specified in pixels, not included within the aspect diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index f552753445d4..00542f402f45 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -60,9 +60,8 @@ The `desktopCapturer` module has the following methods: * `options` Object * `types` String[] - An array of Strings that lists the types of desktop sources to be captured, available types are `screen` and `window`. - * `thumbnailSize` Object (optional) - The size that the media source thumbnail should be scaled to. - * `width` Integer - Default is `150` - * `height` Integer - Default is `150` + * `thumbnailSize` [Size](structures/size.md) (optional) - The size that the media source thumbnail + should be scaled to. Default is `150` x `150`. * `callback` Function * `error` Error * `sources` [DesktopCapturerSource[]](structures/desktop-capturer-source.md) diff --git a/docs/api/native-image.md b/docs/api/native-image.md index 100fb0e1a222..da496436b324 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -219,10 +219,7 @@ Returns `Boolean` - Whether the image is empty. #### `image.getSize()` -Returns `Object`: - -* `width` Integer -* `height` Integer +Returns [`Size`](structures/size.md) #### `image.setTemplateImage(option)` @@ -236,11 +233,7 @@ Returns `Boolean` - Whether the image is a template image. #### `image.crop(rect)` -* `rect` Object - The area of the image to crop - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer +* `rect` [Rectangle](structures/rectangle.md) - The area of the image to crop Returns `NativeImage` - The cropped image. diff --git a/docs/api/screen.md b/docs/api/screen.md index 9704f88134f0..49f0d9f55c9c 100644 --- a/docs/api/screen.md +++ b/docs/api/screen.md @@ -91,10 +91,7 @@ The `screen` module has the following methods: ### `screen.getCursorScreenPoint()` -Returns `Object`: - -* `x` Integer -* `y` Integer +Returns [`Point`](structures/point.md) The current absolute position of the mouse pointer. @@ -108,9 +105,7 @@ Returns [`Display[]`](structures/display.md) - An array of displays that are cur ### `screen.getDisplayNearestPoint(point)` -* `point` Object - * `x` Integer - * `y` Integer +* `point` [Point](structures/point.md) Returns [`Display`](structures/display.md) - The display nearest the specified point. diff --git a/docs/api/structures/display.md b/docs/api/structures/display.md index d702b35a1bec..f5f5b9866ba1 100644 --- a/docs/api/structures/display.md +++ b/docs/api/structures/display.md @@ -6,13 +6,9 @@ * `scaleFactor` Number - Output device's pixel scale factor. * `touchSupport` String - Can be `available`, `unavailable`, `unknown`. * `bounds` [Rectangle](rectangle.md) -* `size` Object - * `height` Number - * `width` Number +* `size` [Size](size.md) * `workArea` [Rectangle](rectangle.md) -* `workAreaSize` Object - * `height` Number - * `width` Number +* `workAreaSize` [Size](size.md) The `Display` object represents a physical display connected to the system. A fake `Display` may exist on a headless system, or a `Display` may correspond to diff --git a/docs/api/structures/point.md b/docs/api/structures/point.md new file mode 100644 index 000000000000..69b87cbdf9c4 --- /dev/null +++ b/docs/api/structures/point.md @@ -0,0 +1,4 @@ +# Point Object + +* `x` Number +* `y` Number diff --git a/docs/api/structures/size.md b/docs/api/structures/size.md new file mode 100644 index 000000000000..1d9c8b1f5a12 --- /dev/null +++ b/docs/api/structures/size.md @@ -0,0 +1,4 @@ +# Size Object + +* `width` Number +* `height` Number diff --git a/docs/api/tray.md b/docs/api/tray.md index 0be970298650..141b24bbbff1 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -219,9 +219,7 @@ Displays a tray balloon. #### `tray.popUpContextMenu([menu, position])` _macOS_ _Windows_ * `menu` Menu (optional) -* `position` Object (optional) - The pop up position. - * `x` Integer - * `y` Integer +* `position` [Point](structures/point.md) (optional) - The pop up position. Pops up the context menu of the tray icon. When `menu` is passed, the `menu` will be shown instead of the tray icon's context menu. diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 87530234a282..98b1cbd2f241 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -375,12 +375,8 @@ Returns: * `type` String * `image` NativeImage (optional) * `scale` Float (optional) - scaling factor for the custom cursor -* `size` Object (optional) - the size of the `image` - * `width` Integer - * `height` Integer -* `hotspot` Object (optional) - coordinates of the custom cursor's hotspot - * `x` Integer - x coordinate - * `y` Integer - y coordinate +* `size` [Size](structures/size.md) (optional) - the size of the `image` +* `hotspot` [Point](structures/point.md) (optional) - coordinates of the custom cursor's hotspot Emitted when the cursor's type changes. The `type` parameter can be `default`, `crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, @@ -1067,24 +1063,16 @@ app.on('ready', () => { (default: `desktop`) * `desktop` - Desktop screen type * `mobile` - Mobile screen type - * `screenSize` Object - Set the emulated screen size (screenPosition == mobile) - * `width` Integer - Set the emulated screen width - * `height` Integer - Set the emulated screen height - * `viewPosition` Object - Position the view on the screen + * `screenSize` [Size](structures/size.md) - Set the emulated screen size (screenPosition == mobile) + * `viewPosition` [Point](structures/point.md) - Position the view on the screen (screenPosition == mobile) (default: `{x: 0, y: 0}`) - * `x` Integer - Set the x axis offset from top left corner - * `y` Integer - Set the y axis offset from top left corner * `deviceScaleFactor` Integer - Set the device scale factor (if zero defaults to original device scale factor) (default: `0`) - * `viewSize` Object - Set the emulated view size (empty means no override) - * `width` Integer - Set the emulated view width - * `height` Integer - Set the emulated view height + * `viewSize` [Size](structures/size.md) - Set the emulated view size (empty means no override) * `fitToView` Boolean - Whether emulated view should be scaled down if necessary to fit into available space (default: `false`) - * `offset` Object - Offset of the emulated view inside available space (not in - fit to view mode) (default: `{x: 0, y: 0}`) - * `x` Float - Set the x axis offset from top left corner - * `y` Float - Set the y axis offset from top left corner + * `offset` [Point](structures/point.md) - Offset of the emulated view inside available space + (not in fit to view mode) (default: `{x: 0, y: 0}`) * `scale` Float - Scale of emulated view inside available space (not in fit to view mode) (default: `1`) From 0cab8a3322450465f70e60b00178af4c8b7d0e07 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 4 Apr 2017 09:19:23 -0400 Subject: [PATCH 140/337] Put CertFromData in an anon namespace --- .../native_mate_converters/net_converter.cc | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 7453dd009775..401cd5328ceb 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -26,6 +26,27 @@ namespace mate { +namespace { + +bool CertFromData(const std::string& data, + scoped_refptr* out) { + auto cert_list = net::X509Certificate::CreateCertificateListFromBytes( + data.c_str(), data.length(), + net::X509Certificate::FORMAT_SINGLE_CERTIFICATE); + if (cert_list.empty()) + return false; + + auto leaf_cert = cert_list.front(); + if (!leaf_cert) + return false; + + *out = leaf_cert; + + return true; +} + +} + // static v8::Local Converter::ToV8( v8::Isolate* isolate, const net::AuthChallengeInfo* val) { @@ -73,23 +94,6 @@ v8::Local Converter>::ToV8( return dict.GetHandle(); } -bool CertFromData(const std::string& data, - scoped_refptr* out) { - auto cert_list = net::X509Certificate::CreateCertificateListFromBytes( - data.c_str(), data.length(), - net::X509Certificate::FORMAT_SINGLE_CERTIFICATE); - if (cert_list.empty()) - return false; - - auto leaf_cert = cert_list.front(); - if (!leaf_cert) - return false; - - *out = leaf_cert; - - return true; -} - bool Converter>::FromV8( v8::Isolate* isolate, v8::Local val, scoped_refptr* out) { From 146e1ed3ce5a4e8eac8f2dfd95f9e221f90a329f Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 4 Apr 2017 09:21:15 -0400 Subject: [PATCH 141/337] Don't pass the result through It's meaningless on macOS, at least. --- atom/browser/ui/certificate_trust.h | 2 +- atom/browser/ui/certificate_trust_mac.mm | 12 +++++------- docs/api/dialog.md | 1 - 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/atom/browser/ui/certificate_trust.h b/atom/browser/ui/certificate_trust.h index 085d04d1030a..7cbf31ea41fb 100644 --- a/atom/browser/ui/certificate_trust.h +++ b/atom/browser/ui/certificate_trust.h @@ -17,7 +17,7 @@ class NativeWindow; namespace certificate_trust { -typedef base::Callback ShowTrustCallback; +typedef base::Callback ShowTrustCallback; void ShowCertificateTrust(atom::NativeWindow* parent_window, const scoped_refptr& cert, diff --git a/atom/browser/ui/certificate_trust_mac.mm b/atom/browser/ui/certificate_trust_mac.mm index ad54eaa3831c..e0888dd3ea24 100644 --- a/atom/browser/ui/certificate_trust_mac.mm +++ b/atom/browser/ui/certificate_trust_mac.mm @@ -66,14 +66,12 @@ - (void)panelDidEnd:(NSWindow*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo { - if (returnCode == NSFileHandlingPanelOKButton) { - auto cert_db = net::CertDatabase::GetInstance(); - // This forces Chromium to reload the certificate since it might be trusted - // now. - cert_db->NotifyObserversCertDBChanged(cert_.get()); - } + auto cert_db = net::CertDatabase::GetInstance(); + // This forces Chromium to reload the certificate since it might be trusted + // now. + cert_db->NotifyObserversCertDBChanged(cert_.get()); - callback_.Run(returnCode == NSFileHandlingPanelOKButton ? true : false); + callback_.Run(); [self autorelease]; } diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 17aa7341bb57..58bbd050845a 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -182,7 +182,6 @@ and no GUI dialog will appear. * `certificate` [Certificate](structures/certificate.md) - The certificate to trust/import. * `message` String - The message to display to the user. * `callback` Function - * `result` Boolean - Whether the user chose to cancel or continue. Displays a modal dialog that shows a message and certificate information, and gives the user the option of trusting/importing the certificate. From 736d6afe730d297f58eca96df367676d7c6b013f Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 4 Apr 2017 09:23:30 -0400 Subject: [PATCH 142/337] As you wish linter --- atom/common/native_mate_converters/net_converter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc index 401cd5328ceb..b78bc5b8e118 100644 --- a/atom/common/native_mate_converters/net_converter.cc +++ b/atom/common/native_mate_converters/net_converter.cc @@ -45,7 +45,7 @@ bool CertFromData(const std::string& data, return true; } -} +} // namespace // static v8::Local Converter::ToV8( From 2749ded062c820e0680d802698a67eb82c8eab51 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 4 Apr 2017 11:45:27 -0400 Subject: [PATCH 143/337] Fix c&p error --- lib/browser/api/dialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/browser/api/dialog.js b/lib/browser/api/dialog.js index 908ffaf670f4..215d3f25dd97 100644 --- a/lib/browser/api/dialog.js +++ b/lib/browser/api/dialog.js @@ -288,7 +288,7 @@ module.exports = { } let {certificate, message} = options - if (certificate == null || typeof options !== 'object') { + if (certificate == null || typeof certificate !== 'object') { throw new TypeError('certificate must be an object') } From 2e32525e8f041056c10c908c80f55e1d56f2b426 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 4 Apr 2017 10:49:10 -0700 Subject: [PATCH 144/337] Make browser window optional --- docs/api/dialog.md | 7 +++++-- lib/browser/api/dialog.js | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 58bbd050845a..6515a0feb940 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -175,9 +175,9 @@ it is usually used to report errors in early stage of startup. If called before the app `ready`event on Linux, the message will be emitted to stderr, and no GUI dialog will appear. -### `dialog.showCertificateTrustDialog(browserWindow, options, callback)` _macOS_ +### `dialog.showCertificateTrustDialog([browserWindow, ]options, callback)` _macOS_ -* `browserWindow` BrowserWindow +* `browserWindow` BrowserWindow (optional) * `options` Object * `certificate` [Certificate](structures/certificate.md) - The certificate to trust/import. * `message` String - The message to display to the user. @@ -186,6 +186,9 @@ and no GUI dialog will appear. Displays a modal dialog that shows a message and certificate information, and gives the user the option of trusting/importing the certificate. +The `browserWindow` argument allows the dialog to attach itself to a parent +window, making it modal. + ## Sheets On macOS, dialogs are presented as sheets attached to a window if you provide diff --git a/lib/browser/api/dialog.js b/lib/browser/api/dialog.js index 215d3f25dd97..964461804769 100644 --- a/lib/browser/api/dialog.js +++ b/lib/browser/api/dialog.js @@ -282,7 +282,9 @@ module.exports = { return binding.showErrorBox(...args) }, - showCertificateTrustDialog: function (window, options, callback) { + showCertificateTrustDialog: function (...args) { + let [window, options, callback] = parseArgs(...args) + if (options == null || typeof options !== 'object') { throw new TypeError('options must be an object') } From 2bd47eb67262a79016edb2c9aef220ee766ba607 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 4 Apr 2017 10:49:21 -0700 Subject: [PATCH 145/337] Add specs for showCertificateTrustDialog option errors --- spec/api-dialog-spec.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/api-dialog-spec.js b/spec/api-dialog-spec.js index 6b245c2b65f7..601e28ca53ca 100644 --- a/spec/api-dialog-spec.js +++ b/spec/api-dialog-spec.js @@ -93,4 +93,20 @@ describe('dialog module', () => { }, /Error processing argument at index 1/) }) }) + + describe('showCertificateTrustDialog', () => { + it('throws errors when the options are invalid', () => { + assert.throws(() => { + dialog.showCertificateTrustDialog() + }, /options must be an object/) + + assert.throws(() => { + dialog.showCertificateTrustDialog({}) + }, /certificate must be an object/) + + assert.throws(() => { + dialog.showCertificateTrustDialog({certificate: {}, message: false}) + }, /message must be a string/) + }) + }) }) From e5f70f90a40e1202e49df96fcc5f45a676e0bd62 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 14:17:16 -0700 Subject: [PATCH 146/337] Add spec for remote setter with remote object --- spec/api-ipc-spec.js | 8 ++++++++ spec/fixtures/module/remote-object-set.js | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 spec/fixtures/module/remote-object-set.js diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index c5e38e83e4db..798c26d87a48 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -199,6 +199,14 @@ describe('ipc module', function () { }, /setting error/) }) + it('can set a remote property with a remote object', function () { + const foo = remote.require(path.join(fixtures, 'module', 'remote-object-set.js')) + + assert.doesNotThrow(function () { + foo.bar = remote.getCurrentWindow() + }) + }) + it('can construct an object from its member', function () { var call = remote.require(path.join(fixtures, 'module', 'call.js')) var obj = new call.constructor() diff --git a/spec/fixtures/module/remote-object-set.js b/spec/fixtures/module/remote-object-set.js new file mode 100644 index 000000000000..5fefbf5cf36a --- /dev/null +++ b/spec/fixtures/module/remote-object-set.js @@ -0,0 +1,11 @@ +const {BrowserWindow} = require('electron') + +class Foo { + set bar (value) { + if (!(value instanceof BrowserWindow)) { + throw new Error('setting error') + } + } +} + +module.exports = new Foo() From 7065123266ec17d709348185c699d07a1f5555f1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 14:18:04 -0700 Subject: [PATCH 147/337] Wrap remote value being set as an arg --- lib/browser/rpc-server.js | 5 +++-- lib/renderer/api/remote.js | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 13d6f882c2e1..3da059079ac5 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -360,9 +360,10 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, id, method, args) { } }) -ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, id, name, value) { +ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, id, name, args) { try { - let obj = objectsRegistry.get(id) + const [value] = unwrapArgs(event.sender, args) + const obj = objectsRegistry.get(id) if (obj == null) { throwRPCError(`Cannot set property '${name}' on missing remote object ${id}`) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index f65d61790ace..5e790133d383 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -139,7 +139,8 @@ const setObjectMembers = function (ref, object, metaId, members) { // Only set setter when it is writable. if (member.writable) { descriptor.set = function (value) { - const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, value) + const args = wrapArgs([value]) + const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, args) // Meta will be non-null when a setter error occurred so parse it // to a value so it gets re-thrown. if (meta != null) { From 746f636016e2cafb8ea05d08d6632066eb30fb5a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 14:26:39 -0700 Subject: [PATCH 148/337] Add tests for setting remote property null/undefined --- spec/api-ipc-spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index 798c26d87a48..fb4278d180fb 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -175,8 +175,14 @@ describe('ipc module', function () { it('can change its properties', function () { var property = remote.require(path.join(fixtures, 'module', 'property.js')) assert.equal(property.property, 1127) + + property.property = null + assert.equal(property.property, null) + property.property = undefined + assert.equal(property.property, undefined) property.property = 1007 assert.equal(property.property, 1007) + assert.equal(property.getFunctionProperty(), 'foo-browser') property.func.property = 'bar' assert.equal(property.getFunctionProperty(), 'bar-browser') From fdd36334e5ae949ce4c92b7395a748cb46788d48 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 14:30:21 -0700 Subject: [PATCH 149/337] Match args style of other IPC handlers --- lib/browser/rpc-server.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 3da059079ac5..8d543f2d7d30 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -362,14 +362,14 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, id, method, args) { ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, id, name, args) { try { - const [value] = unwrapArgs(event.sender, args) - const obj = objectsRegistry.get(id) + args = unwrapArgs(event.sender, args) + let obj = objectsRegistry.get(id) if (obj == null) { throwRPCError(`Cannot set property '${name}' on missing remote object ${id}`) } - obj[name] = value + obj[name] = args[0] event.returnValue = null } catch (error) { event.returnValue = exceptionToMeta(error) From 4d6b0fc01b471adf7529f6e3bb60cb2a3e96759e Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 27 Mar 2017 11:22:52 +1100 Subject: [PATCH 150/337] Add a method to set the escape identifier on the touch bar --- atom/browser/api/atom_api_window.cc | 5 +++++ atom/browser/api/atom_api_window.h | 1 + atom/browser/native_window.cc | 3 +++ atom/browser/native_window.h | 1 + atom/browser/native_window_mac.h | 1 + atom/browser/native_window_mac.mm | 9 +++++++++ atom/browser/ui/cocoa/atom_touch_bar.h | 2 ++ atom/browser/ui/cocoa/atom_touch_bar.mm | 18 ++++++++++++++++++ docs/api/touch-bar.md | 13 ++++++++++++- lib/browser/api/touch-bar.js | 14 ++++++++++++++ 10 files changed, 66 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 6748c9c0dd1d..f64b0408274a 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -853,6 +853,10 @@ void Window::RefreshTouchBarItem(const std::string& item_id) { window_->RefreshTouchBarItem(item_id); } +void Window::SetEscapeTouchBarItem(const mate::PersistentDictionary item) { + window_->SetEscapeTouchBarItem(item); +} + int32_t Window::ID() const { return weak_map_id(); } @@ -975,6 +979,7 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("setVibrancy", &Window::SetVibrancy) .SetMethod("_setTouchBarItems", &Window::SetTouchBar) .SetMethod("_refreshTouchBarItem", &Window::RefreshTouchBarItem) + .SetMethod("_setEscapeTouchBarItem", &Window::SetEscapeTouchBarItem) #if defined(OS_WIN) .SetMethod("hookWindowMessage", &Window::HookWindowMessage) .SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index f30baf79d4df..c7b6a37265b7 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -208,6 +208,7 @@ class Window : public mate::TrackableObject, void SetVibrancy(mate::Arguments* args); void SetTouchBar(const std::vector& items); void RefreshTouchBarItem(const std::string& item_id); + void SetEscapeTouchBarItem(const mate::PersistentDictionary item); v8::Local WebContents(v8::Isolate* isolate); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 90a823f80b65..4866e4294caa 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -347,6 +347,9 @@ void NativeWindow::SetTouchBar( void NativeWindow::RefreshTouchBarItem(const std::string& item_id) { } +void NativeWindow::SetEscapeTouchBarItem(const mate::PersistentDictionary item) { +} + void NativeWindow::FocusOnWebView() { web_contents()->GetRenderViewHost()->GetWidget()->Focus(); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 941f5849a65c..3de57895e522 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -174,6 +174,7 @@ class NativeWindow : public base::SupportsUserData, virtual void SetTouchBar( const std::vector& items); virtual void RefreshTouchBarItem(const std::string& item_id); + virtual void SetEscapeTouchBarItem(const mate::PersistentDictionary item); // Webview APIs. virtual void FocusOnWebView(); diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index bd34993fb119..80ae8895aa19 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -103,6 +103,7 @@ class NativeWindowMac : public NativeWindow, void SetTouchBar( const std::vector& items) override; void RefreshTouchBarItem(const std::string& item_id) override; + void SetEscapeTouchBarItem(const mate::PersistentDictionary item) override; // content::RenderWidgetHost::InputEventObserver: void OnInputEvent(const blink::WebInputEvent& event) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 621e786ddc0d..7cbb8e2dffde 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -410,6 +410,11 @@ enum { return nil; } +-(void)setEscapeTouchBarItem:(mate::PersistentDictionary)item { + if (self.touchBar && atom_touch_bar_) + [atom_touch_bar_ setEscapeTouchBarItem:item forTouchBar:self.touchBar]; +} + // NSWindow overrides. - (void)swipeWithEvent:(NSEvent *)event { @@ -1417,6 +1422,10 @@ void NativeWindowMac::RefreshTouchBarItem(const std::string& item_id) { [window_ refreshTouchBarItem:item_id]; } +void NativeWindowMac::SetEscapeTouchBarItem(const mate::PersistentDictionary item) { + [window_ setEscapeTouchBarItem:item]; +} + void NativeWindowMac::OnInputEvent(const blink::WebInputEvent& event) { switch (event.type) { case blink::WebInputEvent::GestureScrollBegin: diff --git a/atom/browser/ui/cocoa/atom_touch_bar.h b/atom/browser/ui/cocoa/atom_touch_bar.h index 29cdf79b2558..8232e56f0a17 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.h +++ b/atom/browser/ui/cocoa/atom_touch_bar.h @@ -31,6 +31,8 @@ - (NSTouchBar*)touchBarFromItemIdentifiers:(NSMutableArray*)items; - (NSMutableArray*)identifiersFromSettings:(const std::vector&)settings; - (void)refreshTouchBarItem:(NSTouchBar*)touchBar id:(const std::string&)item_id; +- (void)addNonDefaultTouchBarItems:(std::vector)items; +- (void)setEscapeTouchBarItem:(mate::PersistentDictionary)item forTouchBar:(NSTouchBar*)touchBar; - (NSString*)idFromIdentifier:(NSString*)identifier withPrefix:(NSString*)prefix; diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 69926684b67a..c12434467eef 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -145,7 +145,25 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; } else if (item_type == "scrubber") { [self updateScrubber:(NSCustomTouchBarItem*)item withSettings:settings]; } +} +- (void)addNonDefaultTouchBarItems:(std::vector)items { + [self identifiersFromSettings:items]; +} + +- (void)setEscapeTouchBarItem:(mate::PersistentDictionary)item forTouchBar:(NSTouchBar*)touchBar { + std::string type; + std::string item_id; + NSTouchBarItemIdentifier identifier = nil; + if (item.Get("type", &type) && item.Get("id", &item_id)) { + identifier = [self identifierFromID:item_id type:type]; + } + if (identifier) { + [self addNonDefaultTouchBarItems:{ item }]; + touchBar.escapeKeyReplacementItemIdentifier = identifier; + } else { + touchBar.escapeKeyReplacementItemIdentifier = nil; + } } - (void)buttonAction:(id)sender { diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 7eb2eb0209be..d5496b8b3f75 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -6,7 +6,7 @@ Process: [Main](../tutorial/quick-start.md#main-process) ### `new TouchBar(items)` _Experimental_ -* `items` ([TouchBarButton](touch-bar-button.md) | [TouchBarColorPicker](touch-bar-color-picker.md) | [TouchBarGroup](touch-bar-group.md) | [TouchBarLabel](touch-bar-label.md) | [TouchBarPopover](touch-bar-popover.md) | [TouchBarSlider](touch-bar-slider.md) | [TouchBarSpacer](touch-bar-spacer.md))[] +* `items` ([TouchBarButton](touch-bar-button.md) | [TouchBarColorPicker](touch-bar-color-picker.md) | [TouchBarGroup](touch-bar-group.md) | [TouchBarLabel](touch-bar-label.md) | [TouchBarPopover](touch-bar-popover.md) | [TouchBarScrubber](touch-bar-scrubber.md) | [TouchBarSegmentedControl](touch-bar-segmented-control.md) | [TouchBarSlider](touch-bar-slider.md) | [TouchBarSpacer](touch-bar-spacer.md))[] Creates a new touch bar with the specified items. Use `BrowserWindow.setTouchBar` to add the `TouchBar` to a window. @@ -14,6 +14,17 @@ Creates a new touch bar with the specified items. Use **Note:** The TouchBar API is currently experimental and may change or be removed in future Electron releases. +### Instance Methods + +The following methods are available on instances of `TouchBar`: + +#### `touchBar.replaceEscapeItem([touchBarItem])` + +* `touchBarItem` (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer) - (Optional) The touch bar item to replace the escape button with + +Replaces the "esc" button on the touchbar with the given TouchBarItem, if `touchBarItem` is not provided or is falsey the button is reset +to the "esc" button automatically. + ## Examples Below is an example of a simple slot machine touch bar game with a button diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 74951edbac6d..68cd62386169 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -28,6 +28,7 @@ class TouchBar extends EventEmitter { } this.windowListeners = {} + this.windows = {} this.items = {} this.ordereredItems = [] @@ -49,6 +50,15 @@ class TouchBar extends EventEmitter { }) } + replaceEscapeItem(item) { + if (!item) item = {} + Object.keys(this.windows).forEach((windowID) => { + const window = this.windows[windowID] + window._setEscapeTouchBarItem(item) + }) + this._escape = item; + } + _addToWindow (window) { const {id} = window @@ -76,11 +86,15 @@ class TouchBar extends EventEmitter { window.removeListener('closed', removeListeners) window._touchBar = null delete this.windowListeners[id] + delete this.windows[id] } window.once('closed', removeListeners) this.windowListeners[id] = removeListeners + this.windows[id] = window; window._setTouchBarItems(this.ordereredItems) + + if (this._escape) window._setEscapeTouchBarItem(this._escape) } _removeFromWindow (window) { From 2ba937289c71b4c7f1da8d31a3d0edf4eabf0d4e Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 27 Mar 2017 11:23:48 +1100 Subject: [PATCH 151/337] Add smoke test for escape replacement --- spec/api-touch-bar-spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index a8e90502f55d..0c2f917821ca 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -56,6 +56,9 @@ describe('TouchBar module', function () { }) ]) window.setTouchBar(touchBar) + touchBar.replaceEscapeItem(new TouchBarButton({ + label: 'foo' + })) label.label = 'baz' window.setTouchBar() window.setTouchBar(new TouchBar([new TouchBarLabel({label: 'two'})])) From 60cc8620317e604401cc2c06b13530a9e9e705fa Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Wed, 29 Mar 2017 15:11:39 +1100 Subject: [PATCH 152/337] Make everything pointer like --- atom/browser/api/atom_api_window.cc | 2 +- atom/browser/api/atom_api_window.h | 2 +- atom/browser/native_window.cc | 2 +- atom/browser/native_window.h | 2 +- atom/browser/native_window_mac.h | 2 +- atom/browser/native_window_mac.mm | 4 ++-- atom/browser/ui/cocoa/atom_touch_bar.h | 4 ++-- atom/browser/ui/cocoa/atom_touch_bar.mm | 4 ++-- docs/api/touch-bar.md | 2 +- lib/browser/api/touch-bar.js | 6 +++--- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index f64b0408274a..9a4ae5850dc1 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -853,7 +853,7 @@ void Window::RefreshTouchBarItem(const std::string& item_id) { window_->RefreshTouchBarItem(item_id); } -void Window::SetEscapeTouchBarItem(const mate::PersistentDictionary item) { +void Window::SetEscapeTouchBarItem(const mate::PersistentDictionary& item) { window_->SetEscapeTouchBarItem(item); } diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index c7b6a37265b7..24afec354df5 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -208,7 +208,7 @@ class Window : public mate::TrackableObject, void SetVibrancy(mate::Arguments* args); void SetTouchBar(const std::vector& items); void RefreshTouchBarItem(const std::string& item_id); - void SetEscapeTouchBarItem(const mate::PersistentDictionary item); + void SetEscapeTouchBarItem(const mate::PersistentDictionary& item); v8::Local WebContents(v8::Isolate* isolate); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 4866e4294caa..413c756cdc3d 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -347,7 +347,7 @@ void NativeWindow::SetTouchBar( void NativeWindow::RefreshTouchBarItem(const std::string& item_id) { } -void NativeWindow::SetEscapeTouchBarItem(const mate::PersistentDictionary item) { +void NativeWindow::SetEscapeTouchBarItem(const mate::PersistentDictionary& item) { } void NativeWindow::FocusOnWebView() { diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 3de57895e522..227e28c1e46d 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -174,7 +174,7 @@ class NativeWindow : public base::SupportsUserData, virtual void SetTouchBar( const std::vector& items); virtual void RefreshTouchBarItem(const std::string& item_id); - virtual void SetEscapeTouchBarItem(const mate::PersistentDictionary item); + virtual void SetEscapeTouchBarItem(const mate::PersistentDictionary& item); // Webview APIs. virtual void FocusOnWebView(); diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 80ae8895aa19..a535cdb4bef1 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -103,7 +103,7 @@ class NativeWindowMac : public NativeWindow, void SetTouchBar( const std::vector& items) override; void RefreshTouchBarItem(const std::string& item_id) override; - void SetEscapeTouchBarItem(const mate::PersistentDictionary item) override; + void SetEscapeTouchBarItem(const mate::PersistentDictionary& item) override; // content::RenderWidgetHost::InputEventObserver: void OnInputEvent(const blink::WebInputEvent& event) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 7cbb8e2dffde..438bab6e5afd 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -411,7 +411,7 @@ enum { } -(void)setEscapeTouchBarItem:(mate::PersistentDictionary)item { - if (self.touchBar && atom_touch_bar_) + if (atom_touch_bar_ && self.touchBar) [atom_touch_bar_ setEscapeTouchBarItem:item forTouchBar:self.touchBar]; } @@ -1422,7 +1422,7 @@ void NativeWindowMac::RefreshTouchBarItem(const std::string& item_id) { [window_ refreshTouchBarItem:item_id]; } -void NativeWindowMac::SetEscapeTouchBarItem(const mate::PersistentDictionary item) { +void NativeWindowMac::SetEscapeTouchBarItem(const mate::PersistentDictionary& item) { [window_ setEscapeTouchBarItem:item]; } diff --git a/atom/browser/ui/cocoa/atom_touch_bar.h b/atom/browser/ui/cocoa/atom_touch_bar.h index 8232e56f0a17..26662cf48502 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.h +++ b/atom/browser/ui/cocoa/atom_touch_bar.h @@ -31,8 +31,8 @@ - (NSTouchBar*)touchBarFromItemIdentifiers:(NSMutableArray*)items; - (NSMutableArray*)identifiersFromSettings:(const std::vector&)settings; - (void)refreshTouchBarItem:(NSTouchBar*)touchBar id:(const std::string&)item_id; -- (void)addNonDefaultTouchBarItems:(std::vector)items; -- (void)setEscapeTouchBarItem:(mate::PersistentDictionary)item forTouchBar:(NSTouchBar*)touchBar; +- (void)addNonDefaultTouchBarItems:(const std::vector&)items; +- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item forTouchBar:(NSTouchBar*)touchBar; - (NSString*)idFromIdentifier:(NSString*)identifier withPrefix:(NSString*)prefix; diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index c12434467eef..3a8037b1c5fe 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -147,11 +147,11 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; } } -- (void)addNonDefaultTouchBarItems:(std::vector)items { +- (void)addNonDefaultTouchBarItems:(const std::vector&)items { [self identifiersFromSettings:items]; } -- (void)setEscapeTouchBarItem:(mate::PersistentDictionary)item forTouchBar:(NSTouchBar*)touchBar { +- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item forTouchBar:(NSTouchBar*)touchBar { std::string type; std::string item_id; NSTouchBarItemIdentifier identifier = nil; diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index d5496b8b3f75..54315d797733 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -18,7 +18,7 @@ removed in future Electron releases. The following methods are available on instances of `TouchBar`: -#### `touchBar.replaceEscapeItem([touchBarItem])` +#### `touchBar.setEscapeItem([touchBarItem])` * `touchBarItem` (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer) - (Optional) The touch bar item to replace the escape button with diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 68cd62386169..1af18dfbe76f 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -50,13 +50,13 @@ class TouchBar extends EventEmitter { }) } - replaceEscapeItem(item) { + setEscapeItem(item) { if (!item) item = {} Object.keys(this.windows).forEach((windowID) => { const window = this.windows[windowID] window._setEscapeTouchBarItem(item) }) - this._escape = item; + this._escape = item } _addToWindow (window) { @@ -90,7 +90,7 @@ class TouchBar extends EventEmitter { } window.once('closed', removeListeners) this.windowListeners[id] = removeListeners - this.windows[id] = window; + this.windows[id] = window window._setTouchBarItems(this.ordereredItems) From df0f468dea069e6a511235e4ffb02e3fe6e7f463 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 12:41:36 -0700 Subject: [PATCH 153/337] Add escapeKeyReplacementItemIdentifier forward declaration --- atom/browser/ui/cocoa/touch_bar_forward_declarations.h | 1 + 1 file changed, 1 insertion(+) diff --git a/atom/browser/ui/cocoa/touch_bar_forward_declarations.h b/atom/browser/ui/cocoa/touch_bar_forward_declarations.h index 57d5bd7453bb..6fe7c820a1cc 100644 --- a/atom/browser/ui/cocoa/touch_bar_forward_declarations.h +++ b/atom/browser/ui/cocoa/touch_bar_forward_declarations.h @@ -55,6 +55,7 @@ static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierOtherItemsProxy = @property(copy) NSArray* defaultItemIdentifiers; @property(copy, readonly) NSArray* itemIdentifiers; @property(copy, nullable) NSTouchBarItemIdentifier principalItemIdentifier; +@property(copy, nullable) NSTouchBarItemIdentifier escapeKeyReplacementItemIdentifier; @property(copy) NSSet* templateItems; @property(nullable, weak) id delegate; From d596d85288ddca1c5c9e50a26097e3ff76129762 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 12:41:49 -0700 Subject: [PATCH 154/337] :art: --- atom/browser/native_window.cc | 3 ++- lib/browser/api/touch-bar.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 413c756cdc3d..af32a2e8a85a 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -347,7 +347,8 @@ void NativeWindow::SetTouchBar( void NativeWindow::RefreshTouchBarItem(const std::string& item_id) { } -void NativeWindow::SetEscapeTouchBarItem(const mate::PersistentDictionary& item) { +void NativeWindow::SetEscapeTouchBarItem( + const mate::PersistentDictionary& item) { } void NativeWindow::FocusOnWebView() { diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 1af18dfbe76f..2c6b72b89331 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -50,7 +50,7 @@ class TouchBar extends EventEmitter { }) } - setEscapeItem(item) { + setEscapeItem (item) { if (!item) item = {} Object.keys(this.windows).forEach((windowID) => { const window = this.windows[windowID] From 7f8e490839560c63bbf3372ef9699c1d19d3611f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 12:45:01 -0700 Subject: [PATCH 155/337] Take const reference --- atom/browser/native_window_mac.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 438bab6e5afd..c3ca24a3d418 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -368,6 +368,7 @@ enum { - (void)enableWindowButtonsOffset; - (void)resetTouchBar:(const std::vector&)settings; - (void)refreshTouchBarItem:(const std::string&)item_id; +- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item; @end @@ -410,7 +411,7 @@ enum { return nil; } --(void)setEscapeTouchBarItem:(mate::PersistentDictionary)item { +- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item { if (atom_touch_bar_ && self.touchBar) [atom_touch_bar_ setEscapeTouchBarItem:item forTouchBar:self.touchBar]; } From 6eacec7dc3ddddac37c5f14f41a8b9c6ec16034b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 12:46:33 -0700 Subject: [PATCH 156/337] replaceEscapeItem -> setEscapeItem --- spec/api-touch-bar-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 0c2f917821ca..5564556585fa 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -56,7 +56,7 @@ describe('TouchBar module', function () { }) ]) window.setTouchBar(touchBar) - touchBar.replaceEscapeItem(new TouchBarButton({ + touchBar.setEscapeItem(new TouchBarButton({ label: 'foo' })) label.label = 'baz' From 0501a20fe67f6ef3ba348d27bb68bc9ca3f2eb2c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 12:48:58 -0700 Subject: [PATCH 157/337] Clear escape item --- spec/api-touch-bar-spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 5564556585fa..465be6287fc9 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -62,6 +62,7 @@ describe('TouchBar module', function () { label.label = 'baz' window.setTouchBar() window.setTouchBar(new TouchBar([new TouchBarLabel({label: 'two'})])) + touchBar.setEscapeItem() }) }) }) From 591cd8d07338c69dd177e90dd222cf1112ec35ce Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 13:11:25 -0700 Subject: [PATCH 158/337] Update window via listener when escape item changes --- lib/browser/api/touch-bar.js | 25 ++++++++++++++----------- spec/api-touch-bar-spec.js | 7 +++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 2c6b72b89331..02e719ada71e 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -28,9 +28,9 @@ class TouchBar extends EventEmitter { } this.windowListeners = {} - this.windows = {} this.items = {} this.ordereredItems = [] + this.escapeItem = {} const registerItem = (item) => { this.items[item.id] = item @@ -51,12 +51,12 @@ class TouchBar extends EventEmitter { } setEscapeItem (item) { - if (!item) item = {} - Object.keys(this.windows).forEach((windowID) => { - const window = this.windows[windowID] - window._setEscapeTouchBarItem(item) - }) - this._escape = item + if (item != null && !(item instanceof TouchBarItem)) { + throw new Error('Escape item must be an instance of TouchBarItem') + } + if (item == null) item = {} + this.escapeItem = item + this.emit('escape-item-change', item) } _addToWindow (window) { @@ -72,6 +72,11 @@ class TouchBar extends EventEmitter { } this.on('change', changeListener) + const escapeItemListener = (item) => { + window._setEscapeTouchBarItem(item) + } + this.on('escape-item-change', escapeItemListener) + const interactionListener = (event, itemID, details) => { const item = this.items[itemID] if (item != null && item.onInteraction != null) { @@ -82,19 +87,17 @@ class TouchBar extends EventEmitter { const removeListeners = () => { this.removeListener('change', changeListener) + this.removeListener('escape-item-change', escapeItemListener) window.removeListener('-touch-bar-interaction', interactionListener) window.removeListener('closed', removeListeners) window._touchBar = null delete this.windowListeners[id] - delete this.windows[id] } window.once('closed', removeListeners) this.windowListeners[id] = removeListeners - this.windows[id] = window window._setTouchBarItems(this.ordereredItems) - - if (this._escape) window._setEscapeTouchBarItem(this._escape) + window._setEscapeTouchBarItem(this.escapeItem) } _removeFromWindow (window) { diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 465be6287fc9..81bf47eba392 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -20,6 +20,13 @@ describe('TouchBar module', function () { }, /Each item must be an instance of TouchBarItem/) }) + it('throws an error when an invalid escape item is set', function () { + assert.throws(() => { + const touchBar = new TouchBar([]) + touchBar.setEscapeItem('esc') + }, /Escape item must be an instance of TouchBarItem/) + }) + describe('BrowserWindow behavior', function () { let window From 21c1ddffb38cd6eededb057d6af5997727f20067 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Mar 2017 13:26:52 -0700 Subject: [PATCH 159/337] Handle change and interaction events on escape items --- lib/browser/api/touch-bar.js | 24 +++++++++++++++++------- spec/api-touch-bar-spec.js | 8 +++++--- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 02e719ada71e..2b95616f2217 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -2,6 +2,8 @@ const {EventEmitter} = require('events') let nextItemID = 1 +const DEFAULT_ESCAPE_ITEM = new EventEmitter() + class TouchBar extends EventEmitter { // Bind a touch bar to a window static _setOnWindow (touchBar, window) { @@ -30,13 +32,14 @@ class TouchBar extends EventEmitter { this.windowListeners = {} this.items = {} this.ordereredItems = [] - this.escapeItem = {} + this.escapeItem = DEFAULT_ESCAPE_ITEM + this.changeListener = (item) => { + this.emit('change', item.id, item.type) + } const registerItem = (item) => { this.items[item.id] = item - item.on('change', () => { - this.emit('change', item.id, item.type) - }) + item.on('change', this.changeListener) if (item.child instanceof TouchBar) { item.child.ordereredItems.forEach(registerItem) } @@ -54,8 +57,12 @@ class TouchBar extends EventEmitter { if (item != null && !(item instanceof TouchBarItem)) { throw new Error('Escape item must be an instance of TouchBarItem') } - if (item == null) item = {} + if (item == null) { + item = DEFAULT_ESCAPE_ITEM + } + this.escapeItem.removeListener('change', this.changeListener) this.escapeItem = item + this.escapeItem.on('change', this.changeListener) this.emit('escape-item-change', item) } @@ -78,7 +85,10 @@ class TouchBar extends EventEmitter { this.on('escape-item-change', escapeItemListener) const interactionListener = (event, itemID, details) => { - const item = this.items[itemID] + let item = this.items[itemID] + if (item == null && this.escapeItem.id === itemID) { + item = this.escapeItem + } if (item != null && item.onInteraction != null) { item.onInteraction(details) } @@ -121,7 +131,7 @@ class TouchBarItem extends EventEmitter { }, set: function (value) { this[privateName] = value - this.emit('change') + this.emit('change', this) }, enumerable: true }) diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 81bf47eba392..aafb8c68217c 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -62,11 +62,13 @@ describe('TouchBar module', function () { showArrowButtons: true }) ]) - window.setTouchBar(touchBar) - touchBar.setEscapeItem(new TouchBarButton({ + const escapeButton = new TouchBarButton({ label: 'foo' - })) + }) + window.setTouchBar(touchBar) + touchBar.setEscapeItem(escapeButton) label.label = 'baz' + escapeButton.label = 'hello' window.setTouchBar() window.setTouchBar(new TouchBar([new TouchBarLabel({label: 'two'})])) touchBar.setEscapeItem() From b24b4212c517557db34c02a378394acb12b49062 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 09:34:55 -0700 Subject: [PATCH 160/337] Make escape item a property instead of setter --- docs/api/touch-bar.md | 13 ++++++------- lib/browser/api/touch-bar.js | 25 ++++++++++++++----------- spec/api-touch-bar-spec.js | 6 +++--- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 54315d797733..a1d86794dd7b 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -14,16 +14,15 @@ Creates a new touch bar with the specified items. Use **Note:** The TouchBar API is currently experimental and may change or be removed in future Electron releases. -### Instance Methods +### Instance Properties -The following methods are available on instances of `TouchBar`: +The following properties are available on instances of `TouchBar`: -#### `touchBar.setEscapeItem([touchBarItem])` +#### `touchBar.escapeItem` -* `touchBarItem` (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer) - (Optional) The touch bar item to replace the escape button with - -Replaces the "esc" button on the touchbar with the given TouchBarItem, if `touchBarItem` is not provided or is falsey the button is reset -to the "esc" button automatically. +The `TouchBarItem` that will replace the "esc" button on the touch bar when set. +Setting to `null` restores the default "esc" button. Changing this value +immediately updates the escape item in the touch bar. ## Examples diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 2b95616f2217..cd806a5562be 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -2,8 +2,6 @@ const {EventEmitter} = require('events') let nextItemID = 1 -const DEFAULT_ESCAPE_ITEM = new EventEmitter() - class TouchBar extends EventEmitter { // Bind a touch bar to a window static _setOnWindow (touchBar, window) { @@ -32,7 +30,7 @@ class TouchBar extends EventEmitter { this.windowListeners = {} this.items = {} this.ordereredItems = [] - this.escapeItem = DEFAULT_ESCAPE_ITEM + this.escapeItem = null this.changeListener = (item) => { this.emit('change', item.id, item.type) } @@ -53,19 +51,24 @@ class TouchBar extends EventEmitter { }) } - setEscapeItem (item) { + set escapeItem (item) { if (item != null && !(item instanceof TouchBarItem)) { throw new Error('Escape item must be an instance of TouchBarItem') } - if (item == null) { - item = DEFAULT_ESCAPE_ITEM + if (this.escapeItem != null) { + this.escapeItem.removeListener('change', this.changeListener) + } + this._escapeItem = item + if (this.escapeItem != null) { + this.escapeItem.on('change', this.changeListener) } - this.escapeItem.removeListener('change', this.changeListener) - this.escapeItem = item - this.escapeItem.on('change', this.changeListener) this.emit('escape-item-change', item) } + get escapeItem () { + return this._escapeItem + } + _addToWindow (window) { const {id} = window @@ -80,7 +83,7 @@ class TouchBar extends EventEmitter { this.on('change', changeListener) const escapeItemListener = (item) => { - window._setEscapeTouchBarItem(item) + window._setEscapeTouchBarItem(item != null ? item : {}) } this.on('escape-item-change', escapeItemListener) @@ -107,7 +110,7 @@ class TouchBar extends EventEmitter { this.windowListeners[id] = removeListeners window._setTouchBarItems(this.ordereredItems) - window._setEscapeTouchBarItem(this.escapeItem) + escapeItemListener(this.escapeItem) } _removeFromWindow (window) { diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index aafb8c68217c..3b986ba032ea 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -23,7 +23,7 @@ describe('TouchBar module', function () { it('throws an error when an invalid escape item is set', function () { assert.throws(() => { const touchBar = new TouchBar([]) - touchBar.setEscapeItem('esc') + touchBar.escapeItem = 'esc' }, /Escape item must be an instance of TouchBarItem/) }) @@ -66,12 +66,12 @@ describe('TouchBar module', function () { label: 'foo' }) window.setTouchBar(touchBar) - touchBar.setEscapeItem(escapeButton) + touchBar.escapeItem = escapeButton label.label = 'baz' escapeButton.label = 'hello' window.setTouchBar() window.setTouchBar(new TouchBar([new TouchBarLabel({label: 'two'})])) - touchBar.setEscapeItem() + touchBar.escapeItem = null }) }) }) From 414540bfcb28cf6c79b35616a48485f265db7378 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 15:12:57 -0700 Subject: [PATCH 161/337] Support passing escape item to TouchBar constructor --- docs/api/touch-bar.md | 6 ++++-- lib/browser/api/touch-bar.js | 18 +++++++++++++++--- spec/api-touch-bar-spec.js | 13 +++++++++---- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index a1d86794dd7b..7ac578da46db 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -4,9 +4,11 @@ Process: [Main](../tutorial/quick-start.md#main-process) -### `new TouchBar(items)` _Experimental_ +### `new TouchBar(options)` _Experimental_ -* `items` ([TouchBarButton](touch-bar-button.md) | [TouchBarColorPicker](touch-bar-color-picker.md) | [TouchBarGroup](touch-bar-group.md) | [TouchBarLabel](touch-bar-label.md) | [TouchBarPopover](touch-bar-popover.md) | [TouchBarScrubber](touch-bar-scrubber.md) | [TouchBarSegmentedControl](touch-bar-segmented-control.md) | [TouchBarSlider](touch-bar-slider.md) | [TouchBarSpacer](touch-bar-spacer.md))[] +* `options` - Object + * `items` ([TouchBarButton](touch-bar-button.md) | [TouchBarColorPicker](touch-bar-color-picker.md) | [TouchBarGroup](touch-bar-group.md) | [TouchBarLabel](touch-bar-label.md) | [TouchBarPopover](touch-bar-popover.md) | [TouchBarScrubber](touch-bar-scrubber.md) | [TouchBarSegmentedControl](touch-bar-segmented-control.md) | [TouchBarSlider](touch-bar-slider.md) | [TouchBarSpacer](touch-bar-spacer.md))[] + * `escapeItem` ([TouchBarButton](touch-bar-button.md) | [TouchBarColorPicker](touch-bar-color-picker.md) | [TouchBarGroup](touch-bar-group.md) | [TouchBarLabel](touch-bar-label.md) | [TouchBarPopover](touch-bar-popover.md) | [TouchBarScrubber](touch-bar-scrubber.md) | [TouchBarSegmentedControl](touch-bar-segmented-control.md) | [TouchBarSlider](touch-bar-slider.md) | [TouchBarSpacer](touch-bar-spacer.md)) (optional) Creates a new touch bar with the specified items. Use `BrowserWindow.setTouchBar` to add the `TouchBar` to a window. diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index cd806a5562be..f9629a66ce2b 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -20,17 +20,29 @@ class TouchBar extends EventEmitter { touchBar._addToWindow(window) } - constructor (items) { + constructor (options) { super() + if (options == null) { + throw new Error('Must specify options object as first argument') + } + + let {items, escapeItem} = options + + // FIXME Support array as first argument, remove in 2.0 + if (Array.isArray(options)) { + items = options + escapeItem = null + } + if (!Array.isArray(items)) { - throw new Error('Must specify items array as first argument') + items = [] } this.windowListeners = {} this.items = {} this.ordereredItems = [] - this.escapeItem = null + this.escapeItem = escapeItem this.changeListener = (item) => { this.emit('change', item.id, item.type) } diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 3b986ba032ea..c2d5d26c3e46 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -6,23 +6,28 @@ const {TouchBarButton, TouchBarColorPicker, TouchBarGroup} = TouchBar const {TouchBarLabel, TouchBarPopover, TouchBarScrubber, TouchBarSegmentedControl, TouchBarSlider, TouchBarSpacer} = TouchBar describe('TouchBar module', function () { - it('throws an error when created without an items array', function () { + it('throws an error when created without an options object', function () { assert.throws(() => { const touchBar = new TouchBar() touchBar.toString() - }, /Must specify items array as first argument/) + }, /Must specify options object as first argument/) }) it('throws an error when created with invalid items', function () { assert.throws(() => { - const touchBar = new TouchBar([1, true, {}, []]) + const touchBar = new TouchBar({items: [1, true, {}, []]}) touchBar.toString() }, /Each item must be an instance of TouchBarItem/) }) it('throws an error when an invalid escape item is set', function () { assert.throws(() => { - const touchBar = new TouchBar([]) + const touchBar = new TouchBar({items: [], escapeItem: 'esc'}) + touchBar.toString() + }, /Escape item must be an instance of TouchBarItem/) + + assert.throws(() => { + const touchBar = new TouchBar({items: []}) touchBar.escapeItem = 'esc' }, /Escape item must be an instance of TouchBarItem/) }) From bbadeb62ac2a2c4745a4481cc3dc334abf7685d1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 4 Apr 2017 13:12:29 -0700 Subject: [PATCH 162/337] Check that escape item is non-null before checking id --- lib/browser/api/touch-bar.js | 2 +- spec/api-touch-bar-spec.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index f9629a66ce2b..327b6392fe8a 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -101,7 +101,7 @@ class TouchBar extends EventEmitter { const interactionListener = (event, itemID, details) => { let item = this.items[itemID] - if (item == null && this.escapeItem.id === itemID) { + if (item == null && this.escapeItem != null && this.escapeItem.id === itemID) { item = this.escapeItem } if (item != null && item.onInteraction != null) { diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index c2d5d26c3e46..70803045911a 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -78,5 +78,17 @@ describe('TouchBar module', function () { window.setTouchBar(new TouchBar([new TouchBarLabel({label: 'two'})])) touchBar.escapeItem = null }) + + it('calls the callback on the items when a window interaction event fires', function (done) { + const button = new TouchBarButton({ + label: 'bar', + click: () => { + done() + } + }) + const touchBar = new TouchBar({items: [button]}) + window.setTouchBar(touchBar) + window.emit('-touch-bar-interaction', {}, button.id) + }) }) }) From 74a3a34caa301cbe5390d00d2cc35fdcf2b97fa7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 4 Apr 2017 13:14:56 -0700 Subject: [PATCH 163/337] Add spec for interaction event with escape item --- lib/browser/api/touch-bar.js | 7 ++++--- spec/api-touch-bar-spec.js | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 327b6392fe8a..1070398c75c9 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -39,13 +39,14 @@ class TouchBar extends EventEmitter { items = [] } + this.changeListener = (item) => { + this.emit('change', item.id, item.type) + } + this.windowListeners = {} this.items = {} this.ordereredItems = [] this.escapeItem = escapeItem - this.changeListener = (item) => { - this.emit('change', item.id, item.type) - } const registerItem = (item) => { this.items[item.id] = item diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 70803045911a..420ef3fc7b37 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -90,5 +90,17 @@ describe('TouchBar module', function () { window.setTouchBar(touchBar) window.emit('-touch-bar-interaction', {}, button.id) }) + + it('calls the callback on the escape item when a window interaction event fires', function (done) { + const button = new TouchBarButton({ + label: 'bar', + click: () => { + done() + } + }) + const touchBar = new TouchBar({escapeItem: button}) + window.setTouchBar(touchBar) + window.emit('-touch-bar-interaction', {}, button.id) + }) }) }) From f05dfc74daba55603e5a4d478947617e3ec97c6f Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 27 Mar 2017 20:45:27 +1100 Subject: [PATCH 164/337] Store parent popover in popover touch bar items --- atom/browser/ui/cocoa/atom_touch_bar.mm | 10 +++++++++- lib/browser/api/touch-bar.js | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 3a8037b1c5fe..2bd290bd9ac7 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -126,7 +126,15 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; type:item_type]; if (!identifier) return; - NSTouchBarItem* item = [touchBar itemForIdentifier:identifier]; + NSTouchBar* targetTouchBar = touchBar; + + std::string popover_id; + if (settings.Get("_popover", &popover_id)) { + NSPopoverTouchBarItem* popoverItem = [touchBar itemForIdentifier:[self identifierFromID:popover_id type:"popover"]]; + targetTouchBar = popoverItem.popoverTouchBar; + } + + NSTouchBarItem* item = [targetTouchBar itemForIdentifier:identifier]; if (!item) return; if (item_type == "button") { diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 1070398c75c9..2bdbdbe2ae8b 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -223,6 +223,7 @@ TouchBar.TouchBarPopover = class TouchBarPopover extends TouchBarItem { if (!(this.child instanceof TouchBar)) { this.child = new TouchBar(this.child) } + this.child.ordereredItems.forEach((item) => item._popover = this.id) } } From 2fd62d090a7d50cb27a5be089bc34b1aa9c90f5c Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 27 Mar 2017 21:10:14 +1100 Subject: [PATCH 165/337] Allow items to be assigned to multiple popovers --- atom/browser/ui/cocoa/atom_touch_bar.mm | 51 ++++++++++++++----------- lib/browser/api/touch-bar.js | 5 ++- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 2bd290bd9ac7..4b60627488fa 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -113,28 +113,11 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; return nil; } - - (void)refreshTouchBarItem:(NSTouchBar*)touchBar - id:(const std::string&)item_id { - if (![self hasItemWithID:item_id]) return; - - mate::PersistentDictionary settings = settings_[item_id]; - std::string item_type; - settings.Get("type", &item_type); - - NSTouchBarItemIdentifier identifier = [self identifierFromID:item_id - type:item_type]; - if (!identifier) return; - - NSTouchBar* targetTouchBar = touchBar; - - std::string popover_id; - if (settings.Get("_popover", &popover_id)) { - NSPopoverTouchBarItem* popoverItem = [touchBar itemForIdentifier:[self identifierFromID:popover_id type:"popover"]]; - targetTouchBar = popoverItem.popoverTouchBar; - } - - NSTouchBarItem* item = [targetTouchBar itemForIdentifier:identifier]; + id:(NSTouchBarItemIdentifier)identifier + withType:(std::string)item_type + withSettings:(mate::PersistentDictionary)settings { + NSTouchBarItem* item = [touchBar itemForIdentifier:identifier]; if (!item) return; if (item_type == "button") { @@ -143,7 +126,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; [self updateLabel:(NSCustomTouchBarItem*)item withSettings:settings]; } else if (item_type == "colorpicker") { [self updateColorPicker:(NSColorPickerTouchBarItem*)item - withSettings:settings]; + withSettings:settings]; } else if (item_type == "slider") { [self updateSlider:(NSSliderTouchBarItem*)item withSettings:settings]; } else if (item_type == "popover") { @@ -174,6 +157,30 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; } } +- (void)refreshTouchBarItem:(NSTouchBar*)touchBar + id:(const std::string&)item_id { + if (![self hasItemWithID:item_id]) return; + + mate::PersistentDictionary settings = settings_[item_id]; + std::string item_type; + settings.Get("type", &item_type); + + NSTouchBarItemIdentifier identifier = [self identifierFromID:item_id + type:item_type]; + if (!identifier) return; + + std::vector popover_ids; + if (settings.Get("_popover", &popover_ids)) { + for (size_t i = 0; i < popover_ids.size(); ++i) { + std::string popover_id = popover_ids[i]; + NSPopoverTouchBarItem* popoverItem = [touchBar itemForIdentifier:[self identifierFromID:popover_id type:"popover"]]; + NSTouchBar* targetTouchBar = popoverItem.popoverTouchBar; + [self refreshTouchBarItem:targetTouchBar id:identifier withType:item_type withSettings:settings]; + } + } + [self refreshTouchBarItem:touchBar id:identifier withType:item_type withSettings:settings]; +} + - (void)buttonAction:(id)sender { NSString* item_id = [NSString stringWithFormat:@"%ld", ((NSButton*)sender).tag]; window_->NotifyTouchBarItemInteraction([item_id UTF8String], diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 2bdbdbe2ae8b..d0b7d54a5986 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -223,7 +223,10 @@ TouchBar.TouchBarPopover = class TouchBarPopover extends TouchBarItem { if (!(this.child instanceof TouchBar)) { this.child = new TouchBar(this.child) } - this.child.ordereredItems.forEach((item) => item._popover = this.id) + this.child.ordereredItems.forEach((item) => { + item._popover = item._popover || [] + if (!item._popover.find(itemID => itemID === this.id)) item._popover.push(this.id) + }) } } From bea56bbdc8507f6f7ba250e999dc6d099f1e6d68 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Wed, 29 Mar 2017 15:01:14 +1100 Subject: [PATCH 166/337] Update as per feedback --- atom/browser/ui/cocoa/atom_touch_bar.mm | 12 +++++------- lib/browser/api/touch-bar.js | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 4b60627488fa..674f572b1eb0 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -115,8 +115,8 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; - (void)refreshTouchBarItem:(NSTouchBar*)touchBar id:(NSTouchBarItemIdentifier)identifier - withType:(std::string)item_type - withSettings:(mate::PersistentDictionary)settings { + withType:(std::string)item_type + withSettings:(mate::PersistentDictionary)settings { NSTouchBarItem* item = [touchBar itemForIdentifier:identifier]; if (!item) return; @@ -126,7 +126,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; [self updateLabel:(NSCustomTouchBarItem*)item withSettings:settings]; } else if (item_type == "colorpicker") { [self updateColorPicker:(NSColorPickerTouchBarItem*)item - withSettings:settings]; + withSettings:settings]; } else if (item_type == "slider") { [self updateSlider:(NSSliderTouchBarItem*)item withSettings:settings]; } else if (item_type == "popover") { @@ -171,11 +171,9 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; std::vector popover_ids; if (settings.Get("_popover", &popover_ids)) { - for (size_t i = 0; i < popover_ids.size(); ++i) { - std::string popover_id = popover_ids[i]; + for (auto& popover_id : popover_ids) { NSPopoverTouchBarItem* popoverItem = [touchBar itemForIdentifier:[self identifierFromID:popover_id type:"popover"]]; - NSTouchBar* targetTouchBar = popoverItem.popoverTouchBar; - [self refreshTouchBarItem:targetTouchBar id:identifier withType:item_type withSettings:settings]; + [self refreshTouchBarItem:popoverItem.popoverTouchBar id:identifier withType:item_type withSettings:settings]; } } [self refreshTouchBarItem:touchBar id:identifier withType:item_type withSettings:settings]; diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index d0b7d54a5986..1a9c3238a97f 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -225,7 +225,7 @@ TouchBar.TouchBarPopover = class TouchBarPopover extends TouchBarItem { } this.child.ordereredItems.forEach((item) => { item._popover = item._popover || [] - if (!item._popover.find(itemID => itemID === this.id)) item._popover.push(this.id) + if (!item._popover.includes(this.id)) item._popover.push(this.id) }) } } From 9c73c991d726ad1decf980e4535890634cc5d964 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 10:57:57 -0700 Subject: [PATCH 167/337] Use const references for params --- atom/browser/ui/cocoa/atom_touch_bar.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 674f572b1eb0..944501471ca6 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -115,8 +115,8 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; - (void)refreshTouchBarItem:(NSTouchBar*)touchBar id:(NSTouchBarItemIdentifier)identifier - withType:(std::string)item_type - withSettings:(mate::PersistentDictionary)settings { + withType:(const std::string&)item_type + withSettings:(const mate::PersistentDictionary&)settings { NSTouchBarItem* item = [touchBar itemForIdentifier:identifier]; if (!item) return; From 6a22c6645e1417de44ee2ddd6ad2dd003d9f2738 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 3 Apr 2017 11:05:16 -0700 Subject: [PATCH 168/337] Guard against missing popover identifier --- atom/browser/ui/cocoa/atom_touch_bar.mm | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 944501471ca6..a3e846df4871 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -165,18 +165,27 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; std::string item_type; settings.Get("type", &item_type); - NSTouchBarItemIdentifier identifier = [self identifierFromID:item_id - type:item_type]; + auto identifier = [self identifierFromID:item_id type:item_type]; if (!identifier) return; std::vector popover_ids; - if (settings.Get("_popover", &popover_ids)) { - for (auto& popover_id : popover_ids) { - NSPopoverTouchBarItem* popoverItem = [touchBar itemForIdentifier:[self identifierFromID:popover_id type:"popover"]]; - [self refreshTouchBarItem:popoverItem.popoverTouchBar id:identifier withType:item_type withSettings:settings]; - } + settings.Get("_popover", &popover_ids); + for (auto& popover_id : popover_ids) { + auto popoverIdentifier = [self identifierFromID:popover_id type:"popover"]; + if (!popoverIdentifier) continue; + + NSPopoverTouchBarItem* popoverItem = + [touchBar itemForIdentifier:popoverIdentifier]; + [self refreshTouchBarItem:popoverItem.popoverTouchBar + id:identifier + withType:item_type + withSettings:settings]; } - [self refreshTouchBarItem:touchBar id:identifier withType:item_type withSettings:settings]; + + [self refreshTouchBarItem:touchBar + id:identifier + withType:item_type + withSettings:settings]; } - (void)buttonAction:(id)sender { From aa75e4562e5c3f0300429321f21fc3c9c8cea9d2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 4 Apr 2017 20:40:43 -0700 Subject: [PATCH 169/337] Restore delivering IPC messages to utility handlers --- atom/utility/atom_content_utility_client.cc | 12 ++++++++++++ atom/utility/atom_content_utility_client.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/atom/utility/atom_content_utility_client.cc b/atom/utility/atom_content_utility_client.cc index 37fa7558712f..cc36293f4352 100644 --- a/atom/utility/atom_content_utility_client.cc +++ b/atom/utility/atom_content_utility_client.cc @@ -19,4 +19,16 @@ AtomContentUtilityClient::AtomContentUtilityClient() { AtomContentUtilityClient::~AtomContentUtilityClient() { } +bool AtomContentUtilityClient::OnMessageReceived( + const IPC::Message& message) { +#if defined(OS_WIN) + for (auto* handler : handlers_) { + if (handler->OnMessageReceived(message)) + return true; + } +#endif + + return false; +} + } // namespace atom diff --git a/atom/utility/atom_content_utility_client.h b/atom/utility/atom_content_utility_client.h index 0edc4d5d80c9..b4aa7960f6ff 100644 --- a/atom/utility/atom_content_utility_client.h +++ b/atom/utility/atom_content_utility_client.h @@ -20,6 +20,8 @@ class AtomContentUtilityClient : public content::ContentUtilityClient { AtomContentUtilityClient(); ~AtomContentUtilityClient() override; + bool OnMessageReceived(const IPC::Message& message) override; + private: #if defined(OS_WIN) typedef ScopedVector Handlers; From b27b1c3b24b52969ba0487814fb91591b07ea7ae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 4 Apr 2017 20:47:05 -0700 Subject: [PATCH 170/337] Append printed page to job --- chromium_src/chrome/browser/printing/print_view_manager_base.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.cc b/chromium_src/chrome/browser/printing/print_view_manager_base.cc index bc5d3f31f01d..07ec2992f338 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.cc +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.cc @@ -159,6 +159,7 @@ void PrintViewManagerBase::OnDidPrintPage( ShouldQuitFromInnerMessageLoop(); #else + print_job_->AppendPrintedPage(params.page_number); if (metafile_must_be_valid) { bool print_text_with_gdi = document->settings().print_text_with_gdi() && From 73e3fd01eb6554e65496882cadc2aec5ba731954 Mon Sep 17 00:00:00 2001 From: Ales Pergl Date: Wed, 5 Apr 2017 14:45:46 +0200 Subject: [PATCH 171/337] Fixed a couple of failing debug checks when calling Chromium APIs --- atom/browser/browser_win.cc | 7 +++---- atom/browser/ui/views/submenu_button.cc | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 50a9f9da330e..ac0f713c8895 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -61,11 +61,11 @@ bool GetProtocolLaunchPath(mate::Arguments* args, base::string16* exe) { // Read in optional args arg std::vector launch_args; if (args->GetNext(&launch_args) && !launch_args.empty()) - *exe = base::StringPrintf(L"\"%s\" %s \"%%1\"", + *exe = base::StringPrintf(L"\"%ls\" %ls \"%%1\"", exe->c_str(), base::JoinString(launch_args, L" ").c_str()); else - *exe = base::StringPrintf(L"\"%s\" \"%%1\"", exe->c_str()); + *exe = base::StringPrintf(L"\"%ls\" \"%%1\"", exe->c_str()); return true; } @@ -76,8 +76,7 @@ bool FormatCommandLineString(base::string16* exe, } if (!launch_args.empty()) { - base::string16 formatString = L"%s %s"; - *exe = base::StringPrintf(formatString.c_str(), + *exe = base::StringPrintf(L"%ls %ls", exe->c_str(), base::JoinString(launch_args, L" ").c_str()); } diff --git a/atom/browser/ui/views/submenu_button.cc b/atom/browser/ui/views/submenu_button.cc index 92f2a791cd09..617dd3346dad 100644 --- a/atom/browser/ui/views/submenu_button.cc +++ b/atom/browser/ui/views/submenu_button.cc @@ -23,8 +23,8 @@ SubmenuButton::SubmenuButton(const base::string16& title, menu_button_listener, false), accelerator_(0), show_underline_(false), - underline_start_(-1), - underline_end_(-1), + underline_start_(0), + underline_end_(0), text_width_(0), text_height_(0), underline_color_(SK_ColorBLACK), @@ -106,7 +106,7 @@ bool SubmenuButton::GetUnderlinePosition(const base::string16& text, void SubmenuButton::GetCharacterPosition( const base::string16& text, int index, int* pos) { - int height; + int height = 0; gfx::Canvas::SizeStringInt(text.substr(0, index), GetFontList(), pos, &height, 0, 0); } From ce1a5e3c9c5d231233035fc1b5836656d64de56c Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 5 Apr 2017 17:42:24 -0300 Subject: [PATCH 172/337] Fix sandboxed crashReporter for windows. - Use `path` module from browser process in sandboxed renderer. This is required because the return value of `path.join` is platform-specific, and this is an assumtion of crash-reporter.js which is shared between sandboxed and non-sandboxed renderers. - Set `process.platform` and `process.execPath` in sandboxed renderer environment. This is required to spawn the windows crash service from sandboxed renderer. - Use a single temporary directory for all crashReporter tests. This is required to make tests more deterministic across platforms(since mac's crashpad doesn't support changing the crash dump directory). Also make a few improvements/fixes to the `uploadToServer` test. --- electron.gyp | 2 + lib/sandboxed_renderer/api/exports/path.js | 1 + lib/sandboxed_renderer/init.js | 4 +- spec/api-crash-reporter-spec.js | 60 ++++++++++------------ spec/fixtures/api/crash.html | 2 +- 5 files changed, 33 insertions(+), 36 deletions(-) create mode 100644 lib/sandboxed_renderer/api/exports/path.js diff --git a/electron.gyp b/electron.gyp index ee8120097495..ab7a52c3daec 100644 --- a/electron.gyp +++ b/electron.gyp @@ -447,6 +447,8 @@ '-r', './lib/sandboxed_renderer/api/exports/os.js:os', '-r', + './lib/sandboxed_renderer/api/exports/path.js:path', + '-r', './lib/sandboxed_renderer/api/exports/child_process.js:child_process' ], 'isolated_args': [ diff --git a/lib/sandboxed_renderer/api/exports/path.js b/lib/sandboxed_renderer/api/exports/path.js new file mode 100644 index 000000000000..f2b2f2a77fd4 --- /dev/null +++ b/lib/sandboxed_renderer/api/exports/path.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.require('path') diff --git a/lib/sandboxed_renderer/init.js b/lib/sandboxed_renderer/init.js index 46b74ee7b042..5194f9515448 100644 --- a/lib/sandboxed_renderer/init.js +++ b/lib/sandboxed_renderer/init.js @@ -27,6 +27,7 @@ const preloadModules = new Map([ ['electron', electron], ['fs', fs], ['os', require('os')], + ['path', require('path')], ['url', require('url')], ['timers', require('timers')] ]) @@ -36,8 +37,9 @@ const preloadSrc = fs.readFileSync(preloadPath).toString() // Pass different process object to the preload script(which should not have // access to things like `process.atomBinding`). const preloadProcess = new events.EventEmitter() -preloadProcess.platform = electron.remote.process.platform preloadProcess.crash = () => binding.crash() +process.platform = preloadProcess.platform = electron.remote.process.platform +process.execPath = preloadProcess.execPath = electron.remote.process.execPath process.on('exit', () => preloadProcess.emit('exit')) // This is the `require` function that will be visible to the preload script diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 8a51b5ef2db1..a0fde2d54fe9 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -15,24 +15,32 @@ describe('crashReporter module', function () { if (process.mas) { return } + + var originalTempDirectory = null + var tempDirectory = null + + before(function () { + tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') + originalTempDirectory = app.getPath('temp') + app.setPath('temp', tempDirectory) + }) + + after(function () { + app.setPath('temp', originalTempDirectory) + }) + var fixtures = path.resolve(__dirname, 'fixtures') const generateSpecs = (description, browserWindowOpts) => { describe(description, function () { var w = null - var originalTempDirectory = null - var tempDirectory = null beforeEach(function () { w = new BrowserWindow(Object.assign({ show: false }, browserWindowOpts)) - tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') - originalTempDirectory = app.getPath('temp') - app.setPath('temp', tempDirectory) }) afterEach(function () { - app.setPath('temp', originalTempDirectory) return closeWindow(w).then(function () { w = null }) }) @@ -77,13 +85,15 @@ describe('crashReporter module', function () { it('should not send minidump if uploadToServer is false', function (done) { this.timeout(120000) - if (process.platform === 'darwin') { - crashReporter.setUploadToServer(false) - } - let server let dumpFile - let crashesDir + let crashesDir = crashReporter.getCrashesDirectory() + const existingDumpFiles = new Set() + if (process.platform === 'darwin') { + // crashpad puts the dump files in the "completed" subdirectory + crashesDir = path.join(crashesDir, 'completed') + crashReporter.setUploadToServer(false) + } const testDone = (uploaded) => { if (uploaded) { return done(new Error('fail')) @@ -93,7 +103,6 @@ describe('crashReporter module', function () { crashReporter.setUploadToServer(true) } assert(fs.existsSync(dumpFile)) - fs.unlinkSync(dumpFile) done() } @@ -103,7 +112,7 @@ describe('crashReporter module', function () { if (err) { return } - const dumps = files.filter((file) => /\.dmp$/.test(file)) + const dumps = files.filter((file) => /\.dmp$/.test(file) && !existingDumpFiles.has(file)) if (!dumps.length) { return } @@ -111,34 +120,17 @@ describe('crashReporter module', function () { dumpFile = path.join(crashesDir, dumps[0]) clearInterval(pollInterval) // dump file should not be deleted when not uploading, so we wait - // 500 ms and assert it still exists in `testDone` - setTimeout(testDone, 500) + // 1s and assert it still exists in `testDone` + setTimeout(testDone, 1000) }) } - remote.ipcMain.once('set-crash-directory', (event, dir) => { - if (process.platform === 'linux') { - crashesDir = dir - } else { - crashesDir = crashReporter.getCrashesDirectory() - if (process.platform === 'darwin') { - // crashpad uses an extra subdirectory - crashesDir = path.join(crashesDir, 'completed') - } - } - - // Before starting, remove all dump files in the crash directory. - // This is required because: - // - mac crashpad not seem to allow changing the crash directory after - // the first "start" call. - // - Other tests in this suite may leave dumps there. - // - We want to verify in `testDone` that a dump file is created and - // not deleted. + remote.ipcMain.once('list-existing-dumps', (event) => { fs.readdir(crashesDir, (err, files) => { if (!err) { for (const file of files) { if (/\.dmp$/.test(file)) { - fs.unlinkSync(path.join(crashesDir, file)) + existingDumpFiles.add(file) } } } diff --git a/spec/fixtures/api/crash.html b/spec/fixtures/api/crash.html index 6f013a2c7ba5..6a1433a0e61e 100644 --- a/spec/fixtures/api/crash.html +++ b/spec/fixtures/api/crash.html @@ -17,7 +17,7 @@ crashReporter.start({ } }); if (!uploadToServer) { - ipcRenderer.sendSync('set-crash-directory', crashReporter.getCrashesDirectory()) + ipcRenderer.sendSync('list-existing-dumps') } setImmediate(function() { process.crash(); }); From 59fe7d3dbbe539f5fcdaf5fb7cb1e33c0ffe3307 Mon Sep 17 00:00:00 2001 From: Tasuku Uno Date: Thu, 6 Apr 2017 11:38:59 +0900 Subject: [PATCH 173/337] :memo: Fix document of MimeTypedBuffer Object [ci skip] --- docs/api/structures/mime-typed-buffer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/structures/mime-typed-buffer.md b/docs/api/structures/mime-typed-buffer.md index dc1a20d28f79..08e5cd47a4a9 100644 --- a/docs/api/structures/mime-typed-buffer.md +++ b/docs/api/structures/mime-typed-buffer.md @@ -1,4 +1,4 @@ # MimeTypedBuffer Object * `mimeType` String - The mimeType of the Buffer that you are sending -* `buffer` Buffer - The actual Buffer content +* `data` Buffer - The actual Buffer content From 95e782d26cf034280af80393b49ff0494d448969 Mon Sep 17 00:00:00 2001 From: Vadim Macagon Date: Thu, 6 Apr 2017 16:04:19 +1000 Subject: [PATCH 174/337] Fix link to the Upgrading Chrome doc --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 24b23f92a760..e36eef9dd26e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -103,6 +103,6 @@ an issue: * [Debug Instructions (Windows)](development/debug-instructions-windows.md) * [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md) * [Documentation Styleguide](styleguide.md) -* [Updating Chrome](development/updating-chrome.md) +* [Upgrading Chrome](development/upgrading-chrome.md) * [Chromium Development](development/chromium-development.md) * [V8 Development](development/v8-development.md) From 0eed821788197da39e658771d19ff87596de8b69 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Thu, 6 Apr 2017 15:06:02 +0800 Subject: [PATCH 175/337] Update menu.md --- docs-translations/zh-CN/api/menu.md | 185 +++++++++------------------- 1 file changed, 58 insertions(+), 127 deletions(-) diff --git a/docs-translations/zh-CN/api/menu.md b/docs-translations/zh-CN/api/menu.md index 5d31d62f1a95..ebccfe5ee93d 100644 --- a/docs-translations/zh-CN/api/menu.md +++ b/docs-translations/zh-CN/api/menu.md @@ -19,6 +19,8 @@ 在 macOS 上设置应用菜单 `menu`。 在 windows 和 linux,是为每个窗口都在其顶部设置菜单 `menu`。 +设置为 `null` 时,将在 Windows 和 Linux 上删除菜单条,但在 macOS 系统中无效。 + **注意:** 这个API必须在 `app` 模块的 `ready` 事件后调用。 #### `Menu.getApplicationMenu()` @@ -29,7 +31,7 @@ * `action` String -发送 `action` 给应用的第一个响应器.这个用来模仿 Cocoa 菜单的默认行为,通常你只需要使用 `MenuItem` 的属性 `role`. +发送 `action` 给应用的第一个响应器.这个用来模仿 Cocoa 菜单的默认行为,通常你只需要使用 [`MenuItem`](menu-item.md) 的属性 [`role`](menu-item.md#roles). 查看更多 macOS 的原生 action [macOS Cocoa Event Handling Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html#//apple_ref/doc/uid/10000060i-CH3-SW7) . @@ -47,15 +49,23 @@ `menu` 对象有如下实例方法 -#### `menu.popup([browserWindow, x, y, positioningItem])` +#### `menu.popup([browserWindow, options])` -* `browserWindow` BrowserWindow (可选) - 默认为 `null`. -* `x` Number (可选) - 默认为 -1. -* `y` Number (**必须** 如果x设置了) - 默认为 -1. -* `positioningItem` Number (可选) _macOS_ - 在指定坐标鼠标位置下面的菜单项的索引. 默认为 +* `browserWindow` BrowserWindow (可选) - 默认为当前激活的窗口. +* `options` Object (可选) + * `x` Number (可选) - 默认为当前光标所在的位置. + * `y` Number (**必须** 如果x设置了) - 默认为当前光标所在的位置. + * `async` Boolean (可选) - 设置为 `true` 时,调用这个方法会立即返回。设置为 `false` 时,当菜单被选择或者被关闭时才会返回。默认为 `false`。 + * `positioningItem` Number (可选) _macOS_ - 指定坐标鼠标位置下面的菜单项的索引. 默认为 -1. -在 `browserWindow` 中弹出 context menu .你可以选择性地提供指定的 `x, y` 来设置菜单应该放在哪里,否则它将默认地放在当前鼠标的位置. +在 `browserWindow` 中弹出菜单. + +#### `menu.closePopup([browserWindow])` + +* `browserWindow` BrowserWindow (可选) - 默认为当前激活的窗口. + +在 `browserWindow` 关闭菜单. #### `menu.append(menuItem)` @@ -95,76 +105,36 @@ const template = [ { label: 'Edit', submenu: [ - { - role: 'undo' - }, - { - role: 'redo' - }, - { - type: 'separator' - }, - { - role: 'cut' - }, - { - role: 'copy' - }, - { - role: 'paste' - }, - { - role: 'pasteandmatchstyle' - }, - { - role: 'delete' - }, - { - role: 'selectall' - } + {role: 'undo'}, + {role: 'redo'}, + {type: 'separator'}, + {role: 'cut'}, + {role: 'copy'}, + {role: 'paste'}, + {role: 'pasteandmatchstyle'}, + {role: 'delete'}, + {role: 'selectall'} ] }, { label: 'View', submenu: [ - { - role: 'reload' - }, - { - role: 'forcereload' - }, - { - role: 'toggledevtools' - }, - { - type: 'separator' - }, - { - role: 'resetzoom' - }, - { - role: 'zoomin' - }, - { - role: 'zoomout' - }, - { - type: 'separator' - }, - { - role: 'togglefullscreen' - } + {role: 'reload'}, + {role: 'forcereload'}, + {role: 'toggledevtools'}, + {type: 'separator'}, + {role: 'resetzoom'}, + {role: 'zoomin'}, + {role: 'zoomout'}, + {type: 'separator'}, + {role: 'togglefullscreen'} ] }, { role: 'window', submenu: [ - { - role: 'minimize' - }, - { - role: 'close' - } + {role: 'minimize'}, + {role: 'close'} ] }, { @@ -182,76 +152,37 @@ if (process.platform === 'darwin') { template.unshift({ label: app.getName(), submenu: [ - { - role: 'about' - }, - { - type: 'separator' - }, - { - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - role: 'hide' - }, - { - role: 'hideothers' - }, - { - role: 'unhide' - }, - { - type: 'separator' - }, - { - role: 'quit' - } + {role: 'about'}, + {type: 'separator'}, + {role: 'services', submenu: []}, + {type: 'separator'}, + {role: 'hide'}, + {role: 'hideothers'}, + {role: 'unhide'}, + {type: 'separator'}, + {role: 'quit'} ] }) - // Edit menu. + + // Edit menu template[1].submenu.push( - { - type: 'separator' - }, + {type: 'separator'}, { label: 'Speech', submenu: [ - { - role: 'startspeaking' - }, - { - role: 'stopspeaking' - } + {role: 'startspeaking'}, + {role: 'stopspeaking'} ] } ) - // Window menu. + + // Window menu template[3].submenu = [ - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Zoom', - role: 'zoom' - }, - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } + {role: 'close'}, + {role: 'minimize'}, + {role: 'zoom'}, + {type: 'separator'}, + {role: 'front'} ] } From c305517957eb68ca7d42ff0dbd50a61c5ab4b596 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Thu, 6 Apr 2017 15:06:46 +0800 Subject: [PATCH 176/337] Update menu-item.md --- docs-translations/zh-CN/api/menu-item.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs-translations/zh-CN/api/menu-item.md b/docs-translations/zh-CN/api/menu-item.md index c2091674a52a..75c3b935fd84 100644 --- a/docs-translations/zh-CN/api/menu-item.md +++ b/docs-translations/zh-CN/api/menu-item.md @@ -15,26 +15,24 @@ * `menuItem` MenuItem * `browserWindow` BrowserWindow * `event` Event - * `role` String (可选) - 定义菜单项的行为,在指定 `click` 属性时将会被忽略。 - * `type` String (可选) - 取值 `normal`, `separator`, `submenu`, `checkbox` or `radio`。 + * `role` String (可选) - 定义菜单项的行为,在指定 `click` 属性时将会被忽略。参见 [roles](#roles). + * `type` String (可选) - 取值 `normal`, `separator`, `submenu`, `checkbox` 或 `radio`。 * `label` String - (可选) * `sublabel` String - (可选) * `accelerator` [Accelerator](accelerator.md) (可选) * `icon` ([NativeImage](native-image.md) | String) (可选) * `enabled` Boolean (可选) - 如果为 false,菜单项将显示为灰色不可点击。 - unclickable. * `visible` Boolean (可选) - 如果为 false,菜单项将完全隐藏。 * `checked` Boolean (可选) - 只为 `checkbox` 或 `radio` 类型的菜单项。 * `submenu` (MenuItemConstructorOptions[] | Menu) (可选) - 应当作为 `submenu` 菜单项的特定类型,当它作为 `type: 'submenu'` 菜单项的特定类型时可以忽略。如果它的值不是 `Menu`,将自动转为 `Menu.buildFromTemplate`。 - * `id` String (可选) - 标志一个菜单的唯一性。如果被定义使用,它将被用作这个菜单项的参考位置属性。 + * `id` String (可选) - 菜单的唯一标识。如果被定义使用,它将被用作这个菜单项的参考位置属性。 * `position` String (可选) - 定义菜单的具体指定位置信息。 -在创建菜单项时,如果有匹配的方法,建议指定 `role` 属性, -而不是试图手动实现在一个 `click` 函数中的行为。 -内置的 `role` 行为将提供最好的原生体验。 +### Roles +Roles 允许菜单项有预定义的行为。最好为每个菜单项指定一个行为,而不是自己实现一个 `click` 函数中的行为。内置的 `role` 行为将提供最好的原生体验。 + +当使用 `role` 时,`label` 和 `accelerator` 的值是可选的,会针对每个平台设置默认值。 -当使用 `role' 时,`label' 和 `accelerator` 是可选的,默认为 -到每个平台的适当值。 `role`属性值可以为: @@ -56,6 +54,8 @@ * `resetzoom` - 将对焦页面的缩放级别重置为原始大小 * `zoomin` - 将聚焦页面缩小10% * `zoomout` - 将聚焦页面放大10% +* `editMenu` - 完整的默认 "Edit" 编辑菜单(拷贝,黏贴,等) +* `windowMenu` - 完整的默认 "Window" 窗口菜单(最小化,关闭,等) 在 macOS 上,`role` 还可以有以下值: From a7d9230497a9dbeed0cf57aaaf4583f4434169b8 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Thu, 6 Apr 2017 17:29:06 +0800 Subject: [PATCH 177/337] Update accelerator.md --- docs-translations/zh-CN/api/accelerator.md | 25 +++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs-translations/zh-CN/api/accelerator.md b/docs-translations/zh-CN/api/accelerator.md index 0b1e2cd3f4df..0e6d44b742be 100644 --- a/docs-translations/zh-CN/api/accelerator.md +++ b/docs-translations/zh-CN/api/accelerator.md @@ -4,15 +4,30 @@ 例如: -* `Command+A` -* `Ctrl+Shift+Z` +* `CommandOrControl+A` +* `CommandOrControl+Shift+Z` + +快捷键使用 [`globalShortcut`](global-shortcut.md)里的 [`register`](global-shortcut.md#globalshortcutregisteraccelerator-callback) 方法注册 + +```javascript +const {app, globalShortcut} = require('electron') + +app.on('ready', () => { + // Register a 'CommandOrControl+Y' shortcut listener. + globalShortcut.register('CommandOrControl+Y', () => { + // Do stuff when Y and either Command/Control is pressed. + }) +}) +``` ## 运行平台相关的提示 在 Linux 和 Windows 上,`Command` 键并不存在,因此我们通常用 `CommandOrControl` 来表示“在 macOS 下为 `Command` 键,但在 Linux 和 Windows 下为 `Control` 键。 -`Super` 键是指 Linux 和 Windows 上的 `Windows` 键,但是在 macOS 下为 `Command` 键。 +使用 `Alt` 键 代替 `Option`。`Option` 键只在 macOS 系统上存在,而 `Alt` 键在任何系统上都有效。 + +`Super` 键是指 Linux 和 Windows 上的 `Windows` 键,但是在 macOS 下为 `Cmd` 键。 ## 可用的功能按键 @@ -20,6 +35,8 @@ Linux 和 Windows 下为 `Control` 键。 * `Control`(缩写为 `Ctrl`) * `CommandOrControl`(缩写为 `CmdOrCtrl`) * `Alt` +* `Option` +* `AltGr` * `Shift` * `Super` @@ -31,6 +48,7 @@ Linux 和 Windows 下为 `Control` 键。 * 类似与 `~`、`!`、`@`、`#`、`$` 的标点符号。 * `Plus` * `Space` +* `Tab` * `Backspace` * `Delete` * `Insert` @@ -41,3 +59,4 @@ Linux 和 Windows 下为 `Control` 键。 * `Escape`(缩写为 `Esc`) * `VolumeUp`、`VolumeDown` 和 `VolumeMute` * `MediaNextTrack`、`MediaPreviousTrack`、`MediaStop` 和 `MediaPlayPause` +* `PrintScreen` From 7f28b7a151ee8b5c9ccd197d7d92535f3b909788 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 09:47:33 -0700 Subject: [PATCH 178/337] Add failing spec for fork --eval message bug --- spec/node-spec.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/node-spec.js b/spec/node-spec.js index 98db1efeb08e..07f562f7c9c6 100644 --- a/spec/node-spec.js +++ b/spec/node-spec.js @@ -91,6 +91,16 @@ describe('node feature', function () { done() }) }) + + it('works when sending message to a forked process using the --eval argument', function (done) { + const source = "process.on('message', function (msg) { process.send(msg) })" + const forked = ChildProcess.fork('--eval', [source]) + forked.on('message', (message) => { + assert.equal(message, 'hello') + done() + }) + forked.send('hello') + }) }) describe('child_process.spawn', function () { From c3798be9b8e0508e821c9b5ea5db1ac72cac7ba3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 09:48:04 -0700 Subject: [PATCH 179/337] Upgrade node for fork --eval cherry pick fix --- vendor/node | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/node b/vendor/node index a6663598aa78..3fe90cfcf54d 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit a6663598aa78832e7955cb93c51a098eac787abb +Subproject commit 3fe90cfcf54dd946980e59daf550a7cdb2317c8f From 588f699d56aef20ea94ed34f3283bc61bd28ee17 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 09:52:52 -0700 Subject: [PATCH 180/337] :art: --- spec/node-spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/node-spec.js b/spec/node-spec.js index 07f562f7c9c6..8f1d7163bbbb 100644 --- a/spec/node-spec.js +++ b/spec/node-spec.js @@ -92,10 +92,10 @@ describe('node feature', function () { }) }) - it('works when sending message to a forked process using the --eval argument', function (done) { - const source = "process.on('message', function (msg) { process.send(msg) })" + it('works when sending a message to a process forked with the --eval argument', function (done) { + const source = "process.on('message', (message) => { process.send(message) })" const forked = ChildProcess.fork('--eval', [source]) - forked.on('message', (message) => { + forked.once('message', (message) => { assert.equal(message, 'hello') done() }) From ad0a22af23b37a826999c9ac3cf66eb002767e10 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:03:21 +0800 Subject: [PATCH 181/337] Update README.md --- docs-translations/zh-CN/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs-translations/zh-CN/README.md b/docs-translations/zh-CN/README.md index 8d1fd8500d70..706738d60d2c 100644 --- a/docs-translations/zh-CN/README.md +++ b/docs-translations/zh-CN/README.md @@ -26,6 +26,7 @@ * [使用 Widevine CDM 插件](tutorial/using-widevine-cdm-plugin.md) * [通过自动化持续集成系统(CI)进行测试 (Travis, Jenkins)](tutorial/testing-on-headless-ci.md) * [离屏渲染](tutorial/offscreen-rendering.md) +* [快捷键](tutorial/keyboard-shortcuts.md) ## 教程 @@ -96,3 +97,6 @@ * [调试步骤 (Windows)](development/debug-instructions-windows.md) * [在调试中使用 Symbol Server](development/setting-up-symbol-server.md) * [文档风格指南](styleguide.md) +* [升级 Chrome](development/upgrading-chrome.md) +* [Chromium 开发](development/chromium-development.md) +* [V8 开发](development/v8-development.md) From a6f5c35fa64d7d0ce6ea80985e5db5185b2ba733 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:10:12 +0800 Subject: [PATCH 182/337] Create bluetooth-device.md --- docs-translations/zh-CN/api/structures/bluetooth-device.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/bluetooth-device.md diff --git a/docs-translations/zh-CN/api/structures/bluetooth-device.md b/docs-translations/zh-CN/api/structures/bluetooth-device.md new file mode 100644 index 000000000000..2fa0c799a10e --- /dev/null +++ b/docs-translations/zh-CN/api/structures/bluetooth-device.md @@ -0,0 +1,4 @@ +# 蓝牙设备 Object + +* `deviceName` String +* `deviceId` String From 202b8e40c4a114e3ea10aa509401dedc22c736e1 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:14:51 +0800 Subject: [PATCH 183/337] Create certificate-principal.md --- .../zh-CN/api/structures/certificate-principal.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/certificate-principal.md diff --git a/docs-translations/zh-CN/api/structures/certificate-principal.md b/docs-translations/zh-CN/api/structures/certificate-principal.md new file mode 100644 index 000000000000..f4184e8faf94 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/certificate-principal.md @@ -0,0 +1,8 @@ +# CertificatePrincipal Object + +* `commonName` String - 通用名 +* `organizations` String[] - 组织名 +* `organizationUnits` String[] - 组织单位名称 +* `locality` String - 地区 +* `state` String - 州或省 +* `country` String - 国家或地区 From 5986d36059d68b02e5fecb1caeeeb90989df5ba8 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:16:32 +0800 Subject: [PATCH 184/337] Create certificate.md --- .../zh-CN/api/structures/certificate.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/certificate.md diff --git a/docs-translations/zh-CN/api/structures/certificate.md b/docs-translations/zh-CN/api/structures/certificate.md new file mode 100644 index 000000000000..546cefb42da8 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/certificate.md @@ -0,0 +1,12 @@ +# Certificate Object 证书对象 + +* `data` String - PEM encoded data +* `issuer` [CertificatePrincipal](certificate-principal.md) - Issuer principal +* `issuerName` String - Issuer's Common Name +* `issuerCert` Certificate - Issuer certificate (if not self-signed) +* `subject` [CertificatePrincipal](certificate-principal.md) - Subject principal +* `subjectName` String - Subject's Common Name +* `serialNumber` String - Hex value represented string +* `validStart` Number - Start date of the certificate being valid in seconds +* `validExpiry` Number - End date of the certificate being valid in seconds +* `fingerprint` String - Fingerprint of the certificate From 9e33f2efeb65850f6b791f4969de6aa2d1a9900a Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:24:11 +0800 Subject: [PATCH 185/337] Create cookie.md --- docs-translations/zh-CN/api/structures/cookie.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/cookie.md diff --git a/docs-translations/zh-CN/api/structures/cookie.md b/docs-translations/zh-CN/api/structures/cookie.md new file mode 100644 index 000000000000..79f21e1080ac --- /dev/null +++ b/docs-translations/zh-CN/api/structures/cookie.md @@ -0,0 +1,12 @@ +# Cookie Object + +* `name` String - cookie 的名称. +* `value` String - cookie 的值. +* `domain` String (optional) - cookie 的域名. +* `hostOnly` Boolean (optional) - cookie 的类型是否为 host-only. +* `path` String (optional) - cookie 的路径. +* `secure` Boolean (optional) - cookie 是否标记为安全. +* `httpOnly` Boolean (optional) - cookie 是否只标记为 HTTP. +* `session` Boolean (optional) - cookie 是否是一个 session cookie, 还是一个带有过期时间的持续 cookie. +* `expirationDate` Double (optional) - cookie 距离 UNIX 时间戳的过期时间,数值为秒。不需要提供给 session + cookies. From 6a4e7225e2b967e1526a0fc630831f4a88611dbb Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:25:22 +0800 Subject: [PATCH 186/337] Create crash-report.md --- docs-translations/zh-CN/api/structures/crash-report.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/crash-report.md diff --git a/docs-translations/zh-CN/api/structures/crash-report.md b/docs-translations/zh-CN/api/structures/crash-report.md new file mode 100644 index 000000000000..f16b5acdb6d5 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/crash-report.md @@ -0,0 +1,4 @@ +# 崩溃报告的对象 + +* `date` String +* `ID` Integer From e811f809b54daf5cf36f5cde9d7dc7ad5bb78509 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:36:50 +0800 Subject: [PATCH 187/337] Create desktop-capturer-source.md --- .../zh-CN/api/structures/desktop-capturer-source.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/desktop-capturer-source.md diff --git a/docs-translations/zh-CN/api/structures/desktop-capturer-source.md b/docs-translations/zh-CN/api/structures/desktop-capturer-source.md new file mode 100644 index 000000000000..1ab3db17414e --- /dev/null +++ b/docs-translations/zh-CN/api/structures/desktop-capturer-source.md @@ -0,0 +1,7 @@ +# DesktopCapturerSource Object + +* `id` String - 窗口或者屏幕的标识符,当调用 [`navigator.webkitGetUserMedia`] 时可以被当成 `chromeMediaSourceId` 使用。 +标识符的格式为`window:XX` 或 `screen:XX`,`XX` 是一个随机生成的数字. +* `name` String - 窗口的来源将被命名为 `Entire Screen` 或 `Screen `,而窗口来源的名字将会和窗口的标题匹配. +* `thumbnail` [NativeImage](../native-image.md) - 缩略图. **注:** 通过 `desktopCapturer.getSources` 方法, +不能保证缩略图的大小与 `options` 中指定的 `thumbnailSize` 相同。实际大小取决于窗口或者屏幕的比例。 From 27a45009b3f5b6e6a5c7a1a5595b7735b87f6123 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:40:47 +0800 Subject: [PATCH 188/337] Create display.md --- docs-translations/zh-CN/api/structures/display.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/display.md diff --git a/docs-translations/zh-CN/api/structures/display.md b/docs-translations/zh-CN/api/structures/display.md new file mode 100644 index 000000000000..f5f5b9866ba1 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/display.md @@ -0,0 +1,15 @@ +# Display Object + +* `id` Number - Unique identifier associated with the display. +* `rotation` Number - Can be 0, 90, 180, 270, represents screen rotation in + clock-wise degrees. +* `scaleFactor` Number - Output device's pixel scale factor. +* `touchSupport` String - Can be `available`, `unavailable`, `unknown`. +* `bounds` [Rectangle](rectangle.md) +* `size` [Size](size.md) +* `workArea` [Rectangle](rectangle.md) +* `workAreaSize` [Size](size.md) + +The `Display` object represents a physical display connected to the system. A +fake `Display` may exist on a headless system, or a `Display` may correspond to +a remote, virtual display. From 1fb0a5f0da6e3e6a1238d174c63de527d752a4c2 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:42:04 +0800 Subject: [PATCH 189/337] Create file-filter.md --- docs-translations/zh-CN/api/structures/file-filter.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/file-filter.md diff --git a/docs-translations/zh-CN/api/structures/file-filter.md b/docs-translations/zh-CN/api/structures/file-filter.md new file mode 100644 index 000000000000..014350a60f86 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/file-filter.md @@ -0,0 +1,4 @@ +# FileFilter Object + +* `name` String +* `extensions` String[] From 913644504c703e4a5e4a4eb1c14463ada0409d18 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:42:39 +0800 Subject: [PATCH 190/337] Create jump-list-category.md --- .../api/structures/jump-list-category.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/jump-list-category.md diff --git a/docs-translations/zh-CN/api/structures/jump-list-category.md b/docs-translations/zh-CN/api/structures/jump-list-category.md new file mode 100644 index 000000000000..07627e78c98e --- /dev/null +++ b/docs-translations/zh-CN/api/structures/jump-list-category.md @@ -0,0 +1,21 @@ +# JumpListCategory Object + +* `type` String (optional) - One of the following: + * `tasks` - Items in this category will be placed into the standard `Tasks` + category. There can be only one such category, and it will always be + displayed at the bottom of the Jump List. + * `frequent` - Displays a list of files frequently opened by the app, the + name of the category and its items are set by Windows. + * `recent` - Displays a list of files recently opened by the app, the name + of the category and its items are set by Windows. Items may be added to + this category indirectly using `app.addRecentDocument(path)`. + * `custom` - Displays tasks or file links, `name` must be set by the app. +* `name` String (optional) - Must be set if `type` is `custom`, otherwise it should be + omitted. +* `items` JumpListItem[] (optional) - Array of [`JumpListItem`](jump-list-item.md) objects if `type` is `tasks` or + `custom`, otherwise it should be omitted. + +**Note:** If a `JumpListCategory` object has neither the `type` nor the `name` +property set then its `type` is assumed to be `tasks`. If the `name` property +is set but the `type` property is omitted then the `type` is assumed to be +`custom`. From aa3703021118e066dc3c83efc663ff6acaa74728 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:43:05 +0800 Subject: [PATCH 191/337] Create jump-list-item.md --- .../zh-CN/api/structures/jump-list-item.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/jump-list-item.md diff --git a/docs-translations/zh-CN/api/structures/jump-list-item.md b/docs-translations/zh-CN/api/structures/jump-list-item.md new file mode 100644 index 000000000000..f17d72e0a41b --- /dev/null +++ b/docs-translations/zh-CN/api/structures/jump-list-item.md @@ -0,0 +1,28 @@ +# JumpListItem Object + +* `type` String (optional) - One of the following: + * `task` - A task will launch an app with specific arguments. + * `separator` - Can be used to separate items in the standard `Tasks` + category. + * `file` - A file link will open a file using the app that created the + Jump List, for this to work the app must be registered as a handler for + the file type (though it doesn't have to be the default handler). +* `path` String (optional) - Path of the file to open, should only be set if `type` is + `file`. +* `program` String (optional) - Path of the program to execute, usually you should + specify `process.execPath` which opens the current program. Should only be + set if `type` is `task`. +* `args` String (optional) - The command line arguments when `program` is executed. Should + only be set if `type` is `task`. +* `title` String (optional) - The text to be displayed for the item in the Jump List. + Should only be set if `type` is `task`. +* `description` String (optional) - Description of the task (displayed in a tooltip). + Should only be set if `type` is `task`. +* `iconPath` String (optional) - The absolute path to an icon to be displayed in a + Jump List, which can be an arbitrary resource file that contains an icon + (e.g. `.ico`, `.exe`, `.dll`). You can usually specify `process.execPath` to + show the program icon. +* `iconIndex` Number (optional) - The index of the icon in the resource file. If a + resource file contains multiple icons this value can be used to specify the + zero-based index of the icon that should be displayed for this task. If a + resource file contains only one icon, this property should be set to zero. From 32ee0f05e39b8104008db186d23db35c682a3b4a Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:43:51 +0800 Subject: [PATCH 192/337] Create memory-usage-details.md --- .../zh-CN/api/structures/memory-usage-details.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/memory-usage-details.md diff --git a/docs-translations/zh-CN/api/structures/memory-usage-details.md b/docs-translations/zh-CN/api/structures/memory-usage-details.md new file mode 100644 index 000000000000..d77e07dedfc2 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/memory-usage-details.md @@ -0,0 +1,5 @@ +# MemoryUsageDetails Object + +* `count` Number +* `size` Number +* `liveSize` Number From b117f14c2ad8d9dddfa6daf33e94f29f1fb46803 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:44:09 +0800 Subject: [PATCH 193/337] Create mime-typed-buffer.md --- docs-translations/zh-CN/api/structures/mime-typed-buffer.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/mime-typed-buffer.md diff --git a/docs-translations/zh-CN/api/structures/mime-typed-buffer.md b/docs-translations/zh-CN/api/structures/mime-typed-buffer.md new file mode 100644 index 000000000000..08e5cd47a4a9 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/mime-typed-buffer.md @@ -0,0 +1,4 @@ +# MimeTypedBuffer Object + +* `mimeType` String - The mimeType of the Buffer that you are sending +* `data` Buffer - The actual Buffer content From 30fe4a6f2bb2219ced8b2eb763780c9c89bad997 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:44:26 +0800 Subject: [PATCH 194/337] Create point.md --- docs-translations/zh-CN/api/structures/point.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/point.md diff --git a/docs-translations/zh-CN/api/structures/point.md b/docs-translations/zh-CN/api/structures/point.md new file mode 100644 index 000000000000..69b87cbdf9c4 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/point.md @@ -0,0 +1,4 @@ +# Point Object + +* `x` Number +* `y` Number From 7a552da192600094bd3f03e552488b975b9df99a Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:44:41 +0800 Subject: [PATCH 195/337] Create rectangle.md --- docs-translations/zh-CN/api/structures/rectangle.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/rectangle.md diff --git a/docs-translations/zh-CN/api/structures/rectangle.md b/docs-translations/zh-CN/api/structures/rectangle.md new file mode 100644 index 000000000000..0cd000699ea0 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/rectangle.md @@ -0,0 +1,6 @@ +# Rectangle Object + +* `x` Number - The x coordinate of the origin of the rectangle +* `y` Number - The y coordinate of the origin of the rectangle +* `width` Number +* `height` Number From 6e36ec77701c6494f835b56edb7e118260718fa6 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:45:00 +0800 Subject: [PATCH 196/337] Create remove-client-certificate.md --- .../zh-CN/api/structures/remove-client-certificate.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/remove-client-certificate.md diff --git a/docs-translations/zh-CN/api/structures/remove-client-certificate.md b/docs-translations/zh-CN/api/structures/remove-client-certificate.md new file mode 100644 index 000000000000..7ec853f1633b --- /dev/null +++ b/docs-translations/zh-CN/api/structures/remove-client-certificate.md @@ -0,0 +1,5 @@ +# RemoveClientCertificate Object + +* `type` String - `clientCertificate`. +* `origin` String - Origin of the server whose associated client certificate + must be removed from the cache. From bffec5e68e4dea24bd4dde168334a406752d7d0f Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:45:19 +0800 Subject: [PATCH 197/337] Create remove-password.md --- .../zh-CN/api/structures/remove-password.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/remove-password.md diff --git a/docs-translations/zh-CN/api/structures/remove-password.md b/docs-translations/zh-CN/api/structures/remove-password.md new file mode 100644 index 000000000000..28a9ed8ae104 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/remove-password.md @@ -0,0 +1,15 @@ +# RemovePassword Object + +* `type` String - `password`. +* `origin` String (optional) - When provided, the authentication info + related to the origin will only be removed otherwise the entire cache + will be cleared. +* `scheme` String (optional) - Scheme of the authentication. + Can be `basic`, `digest`, `ntlm`, `negotiate`. Must be provided if + removing by `origin`. +* `realm` String (optional) - Realm of the authentication. Must be provided if + removing by `origin`. +* `username` String (optional) - Credentials of the authentication. Must be + provided if removing by `origin`. +* `password` String (optional) - Credentials of the authentication. Must be + provided if removing by `origin`. From 826932199b7f961bd7ce5e375b97f77e47103afb Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:45:36 +0800 Subject: [PATCH 198/337] Create scrubber-item.md --- docs-translations/zh-CN/api/structures/scrubber-item.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/scrubber-item.md diff --git a/docs-translations/zh-CN/api/structures/scrubber-item.md b/docs-translations/zh-CN/api/structures/scrubber-item.md new file mode 100644 index 000000000000..0dd3c4ff0fd4 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/scrubber-item.md @@ -0,0 +1,4 @@ +# ScrubberItem Object + +* `label` String - (Optional) The text to appear in this item +* `icon` NativeImage - (Optional) The image to appear in this item From 3475387d9cf2d32d457418e6ec7d0c661618db52 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:45:50 +0800 Subject: [PATCH 199/337] Create segmented-control-segment.md --- .../zh-CN/api/structures/segmented-control-segment.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/segmented-control-segment.md diff --git a/docs-translations/zh-CN/api/structures/segmented-control-segment.md b/docs-translations/zh-CN/api/structures/segmented-control-segment.md new file mode 100644 index 000000000000..ae01a07f32d2 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/segmented-control-segment.md @@ -0,0 +1,5 @@ +# SegmentedControlSegment Object + +* `label` String - (Optional) The text to appear in this segment +* `icon` NativeImage - (Optional) The image to appear in this segment +* `enabled` Boolean - (Optional) Whether this segment is selectable. Default: true From e8f030af150bba60bc45197569cfd698cf3bbc04 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:46:04 +0800 Subject: [PATCH 200/337] Create shortcut-details.md --- .../zh-CN/api/structures/shortcut-details.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/shortcut-details.md diff --git a/docs-translations/zh-CN/api/structures/shortcut-details.md b/docs-translations/zh-CN/api/structures/shortcut-details.md new file mode 100644 index 000000000000..e7b272d09994 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/shortcut-details.md @@ -0,0 +1,15 @@ +# ShortcutDetails Object + +* `target` String - The target to launch from this shortcut. +* `cwd` String (optional) - The working directory. Default is empty. +* `args` String (optional) - The arguments to be applied to `target` when +launching from this shortcut. Default is empty. +* `description` String (optional) - The description of the shortcut. Default +is empty. +* `icon` String (optional) - The path to the icon, can be a DLL or EXE. `icon` +and `iconIndex` have to be set together. Default is empty, which uses the +target's icon. +* `iconIndex` Number (optional) - The resource ID of icon when `icon` is a +DLL or EXE. Default is 0. +* `appUserModelId` String (optional) - The Application User Model ID. Default +is empty. From 39111b9e34fbebf0db9e1d5fb15e024fec166199 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:46:19 +0800 Subject: [PATCH 201/337] Create size.md --- docs-translations/zh-CN/api/structures/size.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/size.md diff --git a/docs-translations/zh-CN/api/structures/size.md b/docs-translations/zh-CN/api/structures/size.md new file mode 100644 index 000000000000..1d9c8b1f5a12 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/size.md @@ -0,0 +1,4 @@ +# Size Object + +* `width` Number +* `height` Number From a584785254b3cd5c1c840575acb613c7be81b3e4 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:46:34 +0800 Subject: [PATCH 202/337] Create task.md --- docs-translations/zh-CN/api/structures/task.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/task.md diff --git a/docs-translations/zh-CN/api/structures/task.md b/docs-translations/zh-CN/api/structures/task.md new file mode 100644 index 000000000000..61a28de879e7 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/task.md @@ -0,0 +1,14 @@ +# Task Object + +* `program` String - Path of the program to execute, usually you should + specify `process.execPath` which opens the current program. +* `arguments` String - The command line arguments when `program` is + executed. +* `title` String - The string to be displayed in a JumpList. +* `description` String - Description of this task. +* `iconPath` String - The absolute path to an icon to be displayed in a + JumpList, which can be an arbitrary resource file that contains an icon. You + can usually specify `process.execPath` to show the icon of the program. +* `iconIndex` Number - The icon index in the icon file. If an icon file + consists of two or more icons, set this value to identify the icon. If an + icon file consists of one icon, this value is 0. From 3ba8a7516a187d521a7dc6341f64e204d1ec73ac Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:46:53 +0800 Subject: [PATCH 203/337] Create thumbar-button.md --- .../zh-CN/api/structures/thumbar-button.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/thumbar-button.md diff --git a/docs-translations/zh-CN/api/structures/thumbar-button.md b/docs-translations/zh-CN/api/structures/thumbar-button.md new file mode 100644 index 000000000000..259195852a4f --- /dev/null +++ b/docs-translations/zh-CN/api/structures/thumbar-button.md @@ -0,0 +1,21 @@ +# ThumbarButton Object + +* `icon` [NativeImage](../native-image.md) - The icon showing in thumbnail + toolbar. +* `click` Function +* `tooltip` String (optional) - The text of the button's tooltip. +* `flags` String[] (optional) - Control specific states and behaviors of the + button. By default, it is `['enabled']`. + +The `flags` is an array that can include following `String`s: + +* `enabled` - The button is active and available to the user. +* `disabled` - The button is disabled. It is present, but has a visual state + indicating it will not respond to user action. +* `dismissonclick` - When the button is clicked, the thumbnail window closes + immediately. +* `nobackground` - Do not draw a button border, use only the image. +* `hidden` - The button is not shown to the user. +* `noninteractive` - The button is enabled but not interactive; no pressed + button state is drawn. This value is intended for instances where the button + is used in a notification. From 6b44692b0d51f07ab5d6db5c43b1035ca1620a42 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:47:09 +0800 Subject: [PATCH 204/337] Create upload-blob.md --- docs-translations/zh-CN/api/structures/upload-blob.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/upload-blob.md diff --git a/docs-translations/zh-CN/api/structures/upload-blob.md b/docs-translations/zh-CN/api/structures/upload-blob.md new file mode 100644 index 000000000000..be93cacb495e --- /dev/null +++ b/docs-translations/zh-CN/api/structures/upload-blob.md @@ -0,0 +1,4 @@ +# UploadBlob Object + +* `type` String - `blob`. +* `blobUUID` String - UUID of blob data to upload. From 05d59185b29c8784b1e529924b82b7edcd2ab1da Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:47:23 +0800 Subject: [PATCH 205/337] Create upload-data.md --- docs-translations/zh-CN/api/structures/upload-data.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/upload-data.md diff --git a/docs-translations/zh-CN/api/structures/upload-data.md b/docs-translations/zh-CN/api/structures/upload-data.md new file mode 100644 index 000000000000..8e5c07725a54 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/upload-data.md @@ -0,0 +1,6 @@ +# UploadData Object + +* `bytes` Buffer - Content being sent. +* `file` String - Path of file being uploaded. +* `blobUUID` String - UUID of blob data. Use [ses.getBlobData](../session.md#sesgetblobdataidentifier-callback) method + to retrieve the data. From 6089456c84da83d9c78edf92255373176e78d47f Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:47:37 +0800 Subject: [PATCH 206/337] Create upload-file-system.md --- .../zh-CN/api/structures/upload-file-system.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/upload-file-system.md diff --git a/docs-translations/zh-CN/api/structures/upload-file-system.md b/docs-translations/zh-CN/api/structures/upload-file-system.md new file mode 100644 index 000000000000..d62b0a8ba788 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/upload-file-system.md @@ -0,0 +1,9 @@ +# UploadFileSystem Object + +* `type` String - `fileSystem`. +* `filsSystemURL` String - FileSystem url to read data for upload. +* `offset` Integer - Defaults to `0`. +* `length` Integer - Number of bytes to read from `offset`. + Defaults to `0`. +* `modificationTime` Double - Last Modification time in + number of seconds sine the UNIX epoch. From ca584fcaf911ab7b4c8ac47dc2fe87b33d70a011 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:47:52 +0800 Subject: [PATCH 207/337] Create upload-file.md --- docs-translations/zh-CN/api/structures/upload-file.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/upload-file.md diff --git a/docs-translations/zh-CN/api/structures/upload-file.md b/docs-translations/zh-CN/api/structures/upload-file.md new file mode 100644 index 000000000000..8a2197301444 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/upload-file.md @@ -0,0 +1,9 @@ +# UploadFile Object + +* `type` String - `file`. +* `filePath` String - Path of file to be uploaded. +* `offset` Integer - Defaults to `0`. +* `length` Integer - Number of bytes to read from `offset`. + Defaults to `0`. +* `modificationTime` Double - Last Modification time in + number of seconds sine the UNIX epoch. From b6481fde142d45c6c802dd6e15f8267976660b29 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Fri, 7 Apr 2017 10:48:07 +0800 Subject: [PATCH 208/337] Create upload-raw-data.md --- docs-translations/zh-CN/api/structures/upload-raw-data.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/upload-raw-data.md diff --git a/docs-translations/zh-CN/api/structures/upload-raw-data.md b/docs-translations/zh-CN/api/structures/upload-raw-data.md new file mode 100644 index 000000000000..4fe162311fa1 --- /dev/null +++ b/docs-translations/zh-CN/api/structures/upload-raw-data.md @@ -0,0 +1,4 @@ +# UploadRawData Object + +* `type` String - `rawData`. +* `bytes` Buffer - Data to be uploaded. From 8a324a9375d7affd5ae44049182c9df11e613400 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 7 Apr 2017 09:01:28 -0700 Subject: [PATCH 209/337] Bump v1.6.6 --- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- electron.gyp | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 6fc30bf6a3b3..5509969014a1 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 1.6.5 + 1.6.6 CFBundleShortVersionString - 1.6.5 + 1.6.6 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 34879fe41ec9..d572d20ada20 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 1,6,5,0 - PRODUCTVERSION 1,6,5,0 + FILEVERSION 1,6,6,0 + PRODUCTVERSION 1,6,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "1.6.5" + VALUE "FileVersion", "1.6.6" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "1.6.5" + VALUE "ProductVersion", "1.6.6" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 1054a3dc9f1e..3afa163b90aa 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 1 #define ATOM_MINOR_VERSION 6 -#define ATOM_PATCH_VERSION 5 +#define ATOM_PATCH_VERSION 6 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/electron.gyp b/electron.gyp index ee8120097495..e6dd08bdfb95 100644 --- a/electron.gyp +++ b/electron.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '1.6.5', + 'version%': '1.6.6', 'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c', }, 'includes': [ diff --git a/package.json b/package.json index 015be4a12e09..c34a27e2751c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "1.6.5", + "version": "1.6.6", "devDependencies": { "asar": "^0.11.0", "browserify": "^13.1.0", From e2e9e8ae2434e9deff2bb5ecdd7cb9136678b447 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 7 Apr 2017 16:42:01 -0700 Subject: [PATCH 210/337] Wait until server closes in afterEach --- spec/api-net-spec.js | 76 +++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index dc024553a858..a5c3df821056 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -26,22 +26,34 @@ const kOneKiloByte = 1024 const kOneMegaByte = kOneKiloByte * kOneKiloByte describe('net module', function () { - describe('HTTP basics', function () { - let server - beforeEach(function (done) { - server = http.createServer() - server.listen(0, '127.0.0.1', function () { - server.url = 'http://127.0.0.1:' + server.address().port - done() + let server + const connections = new Set() + + beforeEach(function (done) { + server = http.createServer() + server.listen(0, '127.0.0.1', function () { + server.url = `http://127.0.0.1:${server.address().port}` + done() + }) + server.on('connection', (connection) => { + connections.add(connection) + connection.once('close', () => { + connections.delete(connection) }) }) + }) - afterEach(function () { - server.close(function () { - }) + afterEach(function (done) { + for (const connection of connections) { + connection.destroy() + } + server.close(function () { server = null + done() }) + }) + describe('HTTP basics', function () { it('should be able to issue a basic GET request', function (done) { const requestUrl = '/requestUrl' server.on('request', function (request, response) { @@ -224,19 +236,7 @@ describe('net module', function () { }) describe('ClientRequest API', function () { - let server - beforeEach(function (done) { - server = http.createServer() - server.listen(0, '127.0.0.1', function () { - server.url = 'http://127.0.0.1:' + server.address().port - done() - }) - }) - afterEach(function () { - server.close(function () { - }) - server = null session.defaultSession.webRequest.onBeforeRequest(null) }) @@ -1363,21 +1363,8 @@ describe('net module', function () { urlRequest.end() }) }) + describe('IncomingMessage API', function () { - let server - beforeEach(function (done) { - server = http.createServer() - server.listen(0, '127.0.0.1', function () { - server.url = 'http://127.0.0.1:' + server.address().port - done() - }) - }) - - afterEach(function () { - server.close() - server = null - }) - it('response object should implement the IncomingMessage API', function (done) { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' @@ -1544,21 +1531,8 @@ describe('net module', function () { urlRequest.end() }) }) + describe('Stability and performance', function (done) { - let server - beforeEach(function (done) { - server = http.createServer() - server.listen(0, '127.0.0.1', function () { - server.url = 'http://127.0.0.1:' + server.address().port - done() - }) - }) - - afterEach(function () { - server.close() - server = null - }) - it('should free unreferenced, never-started request objects without crash', function (done) { const requestUrl = '/requestUrl' ipcRenderer.once('api-net-spec-done', function () { @@ -1574,6 +1548,7 @@ describe('net module', function () { }) `) }) + it('should not collect on-going requests without crash', function (done) { const requestUrl = '/requestUrl' server.on('request', function (request, response) { @@ -1615,6 +1590,7 @@ describe('net module', function () { urlRequest.end() `) }) + it('should collect unreferenced, ended requests without crash', function (done) { const requestUrl = '/requestUrl' server.on('request', function (request, response) { From 91ee0ea7405d81bcfbbac913db7ec8f0d0106c75 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 31 Mar 2017 10:01:33 -0300 Subject: [PATCH 211/337] Move AtomRenderFrameObserver into a separate module. Also move SetupMainWorldOverrides into the AtomRendererClient class(since the code there is specific to AtomRendererClient). --- atom/renderer/atom_render_frame_observer.cc | 84 +++++++++++ atom/renderer/atom_render_frame_observer.h | 53 +++++++ atom/renderer/atom_renderer_client.cc | 157 +++++--------------- atom/renderer/atom_renderer_client.h | 1 + filenames.gypi | 2 + 5 files changed, 175 insertions(+), 122 deletions(-) create mode 100644 atom/renderer/atom_render_frame_observer.cc create mode 100644 atom/renderer/atom_render_frame_observer.h diff --git a/atom/renderer/atom_render_frame_observer.cc b/atom/renderer/atom_render_frame_observer.cc new file mode 100644 index 000000000000..4a2b493d5164 --- /dev/null +++ b/atom/renderer/atom_render_frame_observer.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/renderer/atom_render_frame_observer.h" + +#include "content/public/renderer/render_frame.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" + +namespace atom { + +AtomRenderFrameObserver::AtomRenderFrameObserver( + content::RenderFrame* frame, + AtomRendererClient* renderer_client) + : content::RenderFrameObserver(frame), + render_frame_(frame), + renderer_client_(renderer_client) {} + +void AtomRenderFrameObserver::DidClearWindowObject() { + renderer_client_->DidClearWindowObject(render_frame_); +} + +void AtomRenderFrameObserver::DidCreateScriptContext( + v8::Handle context, + int extension_group, + int world_id) { + if (ShouldNotifyClient(world_id)) + renderer_client_->DidCreateScriptContext(context, render_frame_); + + if (renderer_client_->isolated_world() && IsMainWorld(world_id) + && render_frame_->IsMainFrame()) { + CreateIsolatedWorldContext(); + renderer_client_->SetupMainWorldOverrides(context); + } +} + +void AtomRenderFrameObserver::WillReleaseScriptContext( + v8::Local context, + int world_id) { + if (ShouldNotifyClient(world_id)) + renderer_client_->WillReleaseScriptContext(context, render_frame_); +} + +void AtomRenderFrameObserver::OnDestruct() { + delete this; +} + +void AtomRenderFrameObserver::CreateIsolatedWorldContext() { + auto frame = render_frame_->GetWebFrame(); + + // This maps to the name shown in the context combo box in the Console tab + // of the dev tools. + frame->setIsolatedWorldHumanReadableName( + World::ISOLATED_WORLD, + blink::WebString::fromUTF8("Electron Isolated Context")); + + // Setup document's origin policy in isolated world + frame->setIsolatedWorldSecurityOrigin( + World::ISOLATED_WORLD, frame->document().getSecurityOrigin()); + + // Create initial script context in isolated world + blink::WebScriptSource source("void 0"); + frame->executeScriptInIsolatedWorld( + World::ISOLATED_WORLD, &source, 1, ExtensionGroup::MAIN_GROUP); +} + +bool AtomRenderFrameObserver::IsMainWorld(int world_id) { + return world_id == World::MAIN_WORLD; +} + +bool AtomRenderFrameObserver::IsIsolatedWorld(int world_id) { + return world_id == World::ISOLATED_WORLD; +} + +bool AtomRenderFrameObserver::ShouldNotifyClient(int world_id) { + if (renderer_client_->isolated_world() && render_frame_->IsMainFrame()) + return IsIsolatedWorld(world_id); + else + return IsMainWorld(world_id); +} + +} // namespace atom diff --git a/atom/renderer/atom_render_frame_observer.h b/atom/renderer/atom_render_frame_observer.h new file mode 100644 index 000000000000..3705667c66fe --- /dev/null +++ b/atom/renderer/atom_render_frame_observer.h @@ -0,0 +1,53 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ +#define ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ + +#include "atom/renderer/atom_renderer_client.h" +#include "content/public/renderer/render_frame_observer.h" + +namespace atom { + +enum World { + MAIN_WORLD = 0, + // Use a high number far away from 0 to not collide with any other world + // IDs created internally by Chrome. + ISOLATED_WORLD = 999 +}; + +enum ExtensionGroup { + MAIN_GROUP = 1 +}; + +// Helper class to forward the messages to the client. +class AtomRenderFrameObserver : public content::RenderFrameObserver { + public: + AtomRenderFrameObserver(content::RenderFrame* frame, + AtomRendererClient* renderer_client); + + // content::RenderFrameObserver: + void DidClearWindowObject() override; + void DidCreateScriptContext(v8::Handle context, + int extension_group, + int world_id) override; + void WillReleaseScriptContext(v8::Local context, + int world_id) override; + void OnDestruct() override; + + private: + bool ShouldNotifyClient(int world_id); + void CreateIsolatedWorldContext(); + bool IsMainWorld(int world_id); + bool IsIsolatedWorld(int world_id); + + content::RenderFrame* render_frame_; + AtomRendererClient* renderer_client_; + + DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); +}; + +} // namespace atom + +#endif // ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 9d015b4f229f..6137593e8093 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -16,12 +16,12 @@ #include "atom/common/node_bindings.h" #include "atom/common/options_switches.h" #include "atom/renderer/api/atom_api_renderer_ipc.h" +#include "atom/renderer/atom_render_frame_observer.h" #include "atom/renderer/atom_render_view_observer.h" #include "atom/renderer/node_array_buffer_bridge.h" #include "atom/renderer/web_worker_observer.h" #include "base/command_line.h" #include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_frame_observer.h" #include "native_mate/dictionary.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -33,127 +33,6 @@ namespace atom { namespace { -enum World { - MAIN_WORLD = 0, - // Use a high number far away from 0 to not collide with any other world - // IDs created internally by Chrome. - ISOLATED_WORLD = 999 -}; - -enum ExtensionGroup { - MAIN_GROUP = 1 -}; - -// Helper class to forward the messages to the client. -class AtomRenderFrameObserver : public content::RenderFrameObserver { - public: - AtomRenderFrameObserver(content::RenderFrame* frame, - AtomRendererClient* renderer_client) - : content::RenderFrameObserver(frame), - render_frame_(frame), - renderer_client_(renderer_client) {} - - // content::RenderFrameObserver: - void DidClearWindowObject() override { - renderer_client_->DidClearWindowObject(render_frame_); - } - - void CreateIsolatedWorldContext() { - auto frame = render_frame_->GetWebFrame(); - - // This maps to the name shown in the context combo box in the Console tab - // of the dev tools. - frame->setIsolatedWorldHumanReadableName( - World::ISOLATED_WORLD, - blink::WebString::fromUTF8("Electron Isolated Context")); - - // Setup document's origin policy in isolated world - frame->setIsolatedWorldSecurityOrigin( - World::ISOLATED_WORLD, frame->document().getSecurityOrigin()); - - // Create initial script context in isolated world - blink::WebScriptSource source("void 0"); - frame->executeScriptInIsolatedWorld( - World::ISOLATED_WORLD, &source, 1, ExtensionGroup::MAIN_GROUP); - } - - void SetupMainWorldOverrides(v8::Handle context) { - // Setup window overrides in the main world context - v8::Isolate* isolate = context->GetIsolate(); - - // Wrap the bundle into a function that receives the binding object as - // an argument. - std::string bundle(node::isolated_bundle_data, - node::isolated_bundle_data + sizeof(node::isolated_bundle_data)); - std::string wrapper = "(function (binding, require) {\n" + bundle + "\n})"; - auto script = v8::Script::Compile( - mate::ConvertToV8(isolate, wrapper)->ToString()); - auto func = v8::Handle::Cast( - script->Run(context).ToLocalChecked()); - - auto binding = v8::Object::New(isolate); - api::Initialize(binding, v8::Null(isolate), context, nullptr); - - // Pass in CLI flags needed to setup window - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - mate::Dictionary dict(isolate, binding); - if (command_line->HasSwitch(switches::kGuestInstanceID)) - dict.Set(options::kGuestInstanceID, - command_line->GetSwitchValueASCII(switches::kGuestInstanceID)); - if (command_line->HasSwitch(switches::kOpenerID)) - dict.Set(options::kOpenerID, - command_line->GetSwitchValueASCII(switches::kOpenerID)); - dict.Set("hiddenPage", command_line->HasSwitch(switches::kHiddenPage)); - - v8::Local args[] = { binding }; - ignore_result(func->Call(context, v8::Null(isolate), 1, args)); - } - - bool IsMainWorld(int world_id) { - return world_id == World::MAIN_WORLD; - } - - bool IsIsolatedWorld(int world_id) { - return world_id == World::ISOLATED_WORLD; - } - - bool ShouldNotifyClient(int world_id) { - if (renderer_client_->isolated_world() && render_frame_->IsMainFrame()) - return IsIsolatedWorld(world_id); - else - return IsMainWorld(world_id); - } - - void DidCreateScriptContext(v8::Handle context, - int extension_group, - int world_id) override { - if (ShouldNotifyClient(world_id)) - renderer_client_->DidCreateScriptContext(context, render_frame_); - - if (renderer_client_->isolated_world() && IsMainWorld(world_id) - && render_frame_->IsMainFrame()) { - CreateIsolatedWorldContext(); - SetupMainWorldOverrides(context); - } - } - - void WillReleaseScriptContext(v8::Local context, - int world_id) override { - if (ShouldNotifyClient(world_id)) - renderer_client_->WillReleaseScriptContext(context, render_frame_); - } - - void OnDestruct() override { - delete this; - } - - private: - content::RenderFrame* render_frame_; - AtomRendererClient* renderer_client_; - - DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); -}; - bool IsDevToolsExtension(content::RenderFrame* render_frame) { return static_cast(render_frame->GetWebFrame()->document().url()) .SchemeIs("chrome-extension"); @@ -307,4 +186,38 @@ v8::Local AtomRendererClient::GetContext( return frame->mainWorldScriptContext(); } +void AtomRendererClient::SetupMainWorldOverrides( + v8::Handle context) { + // Setup window overrides in the main world context + v8::Isolate* isolate = context->GetIsolate(); + + // Wrap the bundle into a function that receives the binding object as + // an argument. + std::string bundle(node::isolated_bundle_data, + node::isolated_bundle_data + sizeof(node::isolated_bundle_data)); + std::string wrapper = "(function (binding, require) {\n" + bundle + "\n})"; + auto script = v8::Script::Compile( + mate::ConvertToV8(isolate, wrapper)->ToString()); + auto func = v8::Handle::Cast( + script->Run(context).ToLocalChecked()); + + auto binding = v8::Object::New(isolate); + api::Initialize(binding, v8::Null(isolate), context, nullptr); + + // Pass in CLI flags needed to setup window + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + mate::Dictionary dict(isolate, binding); + if (command_line->HasSwitch(switches::kGuestInstanceID)) + dict.Set(options::kGuestInstanceID, + command_line->GetSwitchValueASCII(switches::kGuestInstanceID)); + if (command_line->HasSwitch(switches::kOpenerID)) + dict.Set(options::kOpenerID, + command_line->GetSwitchValueASCII(switches::kOpenerID)); + dict.Set("hiddenPage", command_line->HasSwitch(switches::kHiddenPage)); + + v8::Local args[] = { binding }; + ignore_result(func->Call(context, v8::Null(isolate), 1, args)); +} + + } // namespace atom diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 5a1141d1036d..4e45df15d9c1 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -29,6 +29,7 @@ class AtomRendererClient : public RendererClientBase { // Get the context that the Electron API is running in. v8::Local GetContext( blink::WebFrame* frame, v8::Isolate* isolate); + void SetupMainWorldOverrides(v8::Handle context); bool isolated_world() { return isolated_world_; } private: diff --git a/filenames.gypi b/filenames.gypi index 192d953287d7..ec9c68241c25 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -468,6 +468,8 @@ 'atom/renderer/api/atom_api_spell_check_client.h', 'atom/renderer/api/atom_api_web_frame.cc', 'atom/renderer/api/atom_api_web_frame.h', + 'atom/renderer/atom_render_frame_observer.cc', + 'atom/renderer/atom_render_frame_observer.h', 'atom/renderer/atom_render_view_observer.cc', 'atom/renderer/atom_render_view_observer.h', 'atom/renderer/atom_renderer_client.cc', From 0227254774eff00f72b578b44f52ff0c12524671 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sat, 8 Apr 2017 10:43:19 -0300 Subject: [PATCH 212/337] Move DidClearWindowObject into RendererClientBase. Also adapt AtomSandboxedRenderFrameObserver to forward DidClearWindowObject to RendererClientBase. --- atom/renderer/atom_renderer_client.cc | 7 ------- atom/renderer/atom_renderer_client.h | 1 - atom/renderer/atom_sandboxed_renderer_client.cc | 4 +--- atom/renderer/renderer_client_base.cc | 7 +++++++ atom/renderer/renderer_client_base.h | 2 ++ 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 6137593e8093..519b04338986 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -25,7 +25,6 @@ #include "native_mate/dictionary.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebScriptSource.h" #include "atom/common/node_includes.h" @@ -68,12 +67,6 @@ void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { RendererClientBase::RenderViewCreated(render_view); } -void AtomRendererClient::DidClearWindowObject( - content::RenderFrame* render_frame) { - // Make sure every page will get a script context created. - render_frame->GetWebFrame()->executeScript(blink::WebScriptSource("void 0")); -} - void AtomRendererClient::RunScriptsAtDocumentStart( content::RenderFrame* render_frame) { // Inform the document start pharse. diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 4e45df15d9c1..01787fdc10b5 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -20,7 +20,6 @@ class AtomRendererClient : public RendererClientBase { AtomRendererClient(); virtual ~AtomRendererClient(); - void DidClearWindowObject(content::RenderFrame* render_frame); void DidCreateScriptContext( v8::Handle context, content::RenderFrame* render_frame); void WillReleaseScriptContext( diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index 80f8cae713a3..9eb11c830420 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -100,9 +100,7 @@ class AtomSandboxedRenderFrameObserver : public content::RenderFrameObserver { // content::RenderFrameObserver: void DidClearWindowObject() override { - // Make sure every page will get a script context created. - render_frame_->GetWebFrame()->executeScript( - blink::WebScriptSource("void 0")); + renderer_client_->DidClearWindowObject(render_frame_); } void DidCreateScriptContext(v8::Handle context, diff --git a/atom/renderer/renderer_client_base.cc b/atom/renderer/renderer_client_base.cc index 3ee72b3c0da2..6cb6cb9b95d5 100644 --- a/atom/renderer/renderer_client_base.cc +++ b/atom/renderer/renderer_client_base.cc @@ -27,6 +27,7 @@ #include "third_party/WebKit/public/web/WebFrameWidget.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebPluginParams.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #if defined(OS_MACOSX) @@ -151,6 +152,12 @@ void RendererClientBase::RenderViewCreated(content::RenderView* render_view) { } } +void RendererClientBase::DidClearWindowObject( + content::RenderFrame* render_frame) { + // Make sure every page will get a script context created. + render_frame->GetWebFrame()->executeScript(blink::WebScriptSource("void 0")); +} + blink::WebSpeechSynthesizer* RendererClientBase::OverrideSpeechSynthesizer( blink::WebSpeechSynthesizerClient* client) { return new TtsDispatcher(client); diff --git a/atom/renderer/renderer_client_base.h b/atom/renderer/renderer_client_base.h index 3a91255c60b1..167eefaa8e60 100644 --- a/atom/renderer/renderer_client_base.h +++ b/atom/renderer/renderer_client_base.h @@ -19,6 +19,8 @@ class RendererClientBase : public content::ContentRendererClient { RendererClientBase(); virtual ~RendererClientBase(); + virtual void DidClearWindowObject(content::RenderFrame* render_frame); + protected: void AddRenderBindings(v8::Isolate* isolate, v8::Local binding_object); From f751335bf9e8b08741ba23f9225b7b83e23a5c8a Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sat, 8 Apr 2017 10:58:13 -0300 Subject: [PATCH 213/337] Make DidCreateScriptContext/WillReleaseScriptContext pure virtual. --- atom/renderer/atom_renderer_client.h | 13 ++++++++----- atom/renderer/atom_sandboxed_renderer_client.h | 11 +++++++---- atom/renderer/renderer_client_base.h | 4 ++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 01787fdc10b5..4feca84816e4 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -20,17 +20,20 @@ class AtomRendererClient : public RendererClientBase { AtomRendererClient(); virtual ~AtomRendererClient(); - void DidCreateScriptContext( - v8::Handle context, content::RenderFrame* render_frame); - void WillReleaseScriptContext( - v8::Handle context, content::RenderFrame* render_frame); - // Get the context that the Electron API is running in. v8::Local GetContext( blink::WebFrame* frame, v8::Isolate* isolate); void SetupMainWorldOverrides(v8::Handle context); bool isolated_world() { return isolated_world_; } + // atom::RendererClientBase: + void DidCreateScriptContext( + v8::Handle context, + content::RenderFrame* render_frame) override; + void WillReleaseScriptContext( + v8::Handle context, + content::RenderFrame* render_frame) override; + private: enum NodeIntegration { ALL, diff --git a/atom/renderer/atom_sandboxed_renderer_client.h b/atom/renderer/atom_sandboxed_renderer_client.h index 5e0614c9c9ec..c6f8a23577d9 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.h +++ b/atom/renderer/atom_sandboxed_renderer_client.h @@ -16,13 +16,16 @@ class AtomSandboxedRendererClient : public RendererClientBase { AtomSandboxedRendererClient(); virtual ~AtomSandboxedRendererClient(); - void DidCreateScriptContext( - v8::Handle context, content::RenderFrame* render_frame); - void WillReleaseScriptContext( - v8::Handle context, content::RenderFrame* render_frame); void InvokeIpcCallback(v8::Handle context, const std::string& callback_name, std::vector> args); + // atom::RendererClientBase: + void DidCreateScriptContext( + v8::Handle context, + content::RenderFrame* render_frame) override; + void WillReleaseScriptContext( + v8::Handle context, + content::RenderFrame* render_frame) override; // content::ContentRendererClient: void RenderFrameCreated(content::RenderFrame*) override; void RenderViewCreated(content::RenderView*) override; diff --git a/atom/renderer/renderer_client_base.h b/atom/renderer/renderer_client_base.h index 167eefaa8e60..804e214cbbbd 100644 --- a/atom/renderer/renderer_client_base.h +++ b/atom/renderer/renderer_client_base.h @@ -19,6 +19,10 @@ class RendererClientBase : public content::ContentRendererClient { RendererClientBase(); virtual ~RendererClientBase(); + virtual void DidCreateScriptContext( + v8::Handle context, content::RenderFrame* render_frame) = 0; + virtual void WillReleaseScriptContext( + v8::Handle context, content::RenderFrame* render_frame) = 0; virtual void DidClearWindowObject(content::RenderFrame* render_frame); protected: From ef07e25f9d93f94f93638dd1c1b2b530ee5196ac Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sat, 8 Apr 2017 11:12:18 -0300 Subject: [PATCH 214/337] Make SetupMainWorldOverrides/isolated_world pure virtual. Also implement stubs in AtomSandboxedRendererClient. --- atom/renderer/atom_renderer_client.h | 4 ++-- atom/renderer/atom_sandboxed_renderer_client.h | 2 ++ atom/renderer/renderer_client_base.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 4feca84816e4..3feaff452858 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -23,8 +23,6 @@ class AtomRendererClient : public RendererClientBase { // Get the context that the Electron API is running in. v8::Local GetContext( blink::WebFrame* frame, v8::Isolate* isolate); - void SetupMainWorldOverrides(v8::Handle context); - bool isolated_world() { return isolated_world_; } // atom::RendererClientBase: void DidCreateScriptContext( @@ -33,6 +31,8 @@ class AtomRendererClient : public RendererClientBase { void WillReleaseScriptContext( v8::Handle context, content::RenderFrame* render_frame) override; + void SetupMainWorldOverrides(v8::Handle context) override; + bool isolated_world() override { return isolated_world_; } private: enum NodeIntegration { diff --git a/atom/renderer/atom_sandboxed_renderer_client.h b/atom/renderer/atom_sandboxed_renderer_client.h index c6f8a23577d9..a8eae0ba8491 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.h +++ b/atom/renderer/atom_sandboxed_renderer_client.h @@ -26,6 +26,8 @@ class AtomSandboxedRendererClient : public RendererClientBase { void WillReleaseScriptContext( v8::Handle context, content::RenderFrame* render_frame) override; + void SetupMainWorldOverrides(v8::Handle context) override { } + bool isolated_world() override { return false; } // content::ContentRendererClient: void RenderFrameCreated(content::RenderFrame*) override; void RenderViewCreated(content::RenderView*) override; diff --git a/atom/renderer/renderer_client_base.h b/atom/renderer/renderer_client_base.h index 804e214cbbbd..c8958de9042b 100644 --- a/atom/renderer/renderer_client_base.h +++ b/atom/renderer/renderer_client_base.h @@ -24,6 +24,8 @@ class RendererClientBase : public content::ContentRendererClient { virtual void WillReleaseScriptContext( v8::Handle context, content::RenderFrame* render_frame) = 0; virtual void DidClearWindowObject(content::RenderFrame* render_frame); + virtual void SetupMainWorldOverrides(v8::Handle context) = 0; + virtual bool isolated_world() = 0; protected: void AddRenderBindings(v8::Isolate* isolate, From 72781e38c8f9d0efef13142c50c5c69a3437dc98 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sat, 8 Apr 2017 11:27:19 -0300 Subject: [PATCH 215/337] Change AtomRenderFrameObserver.renderer_client_ type to RendererClientBase. --- atom/renderer/atom_render_frame_observer.cc | 2 +- atom/renderer/atom_render_frame_observer.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/renderer/atom_render_frame_observer.cc b/atom/renderer/atom_render_frame_observer.cc index 4a2b493d5164..d9a41a48d4a9 100644 --- a/atom/renderer/atom_render_frame_observer.cc +++ b/atom/renderer/atom_render_frame_observer.cc @@ -13,7 +13,7 @@ namespace atom { AtomRenderFrameObserver::AtomRenderFrameObserver( content::RenderFrame* frame, - AtomRendererClient* renderer_client) + RendererClientBase* renderer_client) : content::RenderFrameObserver(frame), render_frame_(frame), renderer_client_(renderer_client) {} diff --git a/atom/renderer/atom_render_frame_observer.h b/atom/renderer/atom_render_frame_observer.h index 3705667c66fe..51cb21b3b0e7 100644 --- a/atom/renderer/atom_render_frame_observer.h +++ b/atom/renderer/atom_render_frame_observer.h @@ -5,7 +5,7 @@ #ifndef ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ #define ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ -#include "atom/renderer/atom_renderer_client.h" +#include "atom/renderer/renderer_client_base.h" #include "content/public/renderer/render_frame_observer.h" namespace atom { @@ -25,7 +25,7 @@ enum ExtensionGroup { class AtomRenderFrameObserver : public content::RenderFrameObserver { public: AtomRenderFrameObserver(content::RenderFrame* frame, - AtomRendererClient* renderer_client); + RendererClientBase* renderer_client); // content::RenderFrameObserver: void DidClearWindowObject() override; @@ -43,7 +43,7 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { bool IsIsolatedWorld(int world_id); content::RenderFrame* render_frame_; - AtomRendererClient* renderer_client_; + RendererClientBase* renderer_client_; DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); }; From 039aaba75860dc191d79d86dae05d67225fd5dd7 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sat, 8 Apr 2017 11:54:58 -0300 Subject: [PATCH 216/337] Move AtomRenderFrameObserver creation to RendererClientBase. Also remove AtomSandboxedRenderFrameObserver class. --- atom/renderer/atom_renderer_client.cc | 1 - .../atom_sandboxed_renderer_client.cc | 44 ------------------- atom/renderer/renderer_client_base.cc | 2 + 3 files changed, 2 insertions(+), 45 deletions(-) diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 519b04338986..5dafe084ce27 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -58,7 +58,6 @@ void AtomRendererClient::RenderThreadStarted() { void AtomRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { - new AtomRenderFrameObserver(render_frame, this); RendererClientBase::RenderFrameCreated(render_frame); } diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index 9eb11c830420..4fe9bd449dd7 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -20,7 +20,6 @@ #include "base/command_line.h" #include "chrome/renderer/printing/print_web_view_helper.h" #include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view_observer.h" #include "ipc/ipc_message_macros.h" @@ -89,48 +88,6 @@ void InitializeBindings(v8::Local binding, b.SetMethod("crash", AtomBindings::Crash); } -class AtomSandboxedRenderFrameObserver : public content::RenderFrameObserver { - public: - AtomSandboxedRenderFrameObserver(content::RenderFrame* frame, - AtomSandboxedRendererClient* renderer_client) - : content::RenderFrameObserver(frame), - render_frame_(frame), - world_id_(-1), - renderer_client_(renderer_client) {} - - // content::RenderFrameObserver: - void DidClearWindowObject() override { - renderer_client_->DidClearWindowObject(render_frame_); - } - - void DidCreateScriptContext(v8::Handle context, - int extension_group, - int world_id) override { - if (world_id_ != -1 && world_id_ != world_id) - return; - world_id_ = world_id; - renderer_client_->DidCreateScriptContext(context, render_frame_); - } - - void WillReleaseScriptContext(v8::Local context, - int world_id) override { - if (world_id_ != world_id) - return; - renderer_client_->WillReleaseScriptContext(context, render_frame_); - } - - void OnDestruct() override { - delete this; - } - - private: - content::RenderFrame* render_frame_; - int world_id_; - AtomSandboxedRendererClient* renderer_client_; - - DISALLOW_COPY_AND_ASSIGN(AtomSandboxedRenderFrameObserver); -}; - class AtomSandboxedRenderViewObserver : public AtomRenderViewObserver { public: AtomSandboxedRenderViewObserver(content::RenderView* render_view, @@ -179,7 +136,6 @@ AtomSandboxedRendererClient::~AtomSandboxedRendererClient() { void AtomSandboxedRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { - new AtomSandboxedRenderFrameObserver(render_frame, this); RendererClientBase::RenderFrameCreated(render_frame); } diff --git a/atom/renderer/renderer_client_base.cc b/atom/renderer/renderer_client_base.cc index 6cb6cb9b95d5..09a4c3c0c8f4 100644 --- a/atom/renderer/renderer_client_base.cc +++ b/atom/renderer/renderer_client_base.cc @@ -11,6 +11,7 @@ #include "atom/common/color_util.h" #include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/options_switches.h" +#include "atom/renderer/atom_render_frame_observer.h" #include "atom/renderer/content_settings_observer.h" #include "atom/renderer/guest_view_container.h" #include "atom/renderer/preferences_manager.h" @@ -112,6 +113,7 @@ void RendererClientBase::RenderThreadStarted() { void RendererClientBase::RenderFrameCreated( content::RenderFrame* render_frame) { + new AtomRenderFrameObserver(render_frame, this); new PepperHelper(render_frame); new ContentSettingsObserver(render_frame); new printing::PrintWebViewHelper(render_frame); From b7b7f28c5a896a5a5113ec6c70d910e3da099428 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Sat, 8 Apr 2017 18:50:55 -0700 Subject: [PATCH 217/337] Link properties to class docs --- docs/api/session.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/session.md b/docs/api/session.md index 7c7831c8ac37..e85f5a246f45 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -388,15 +388,15 @@ The following properties are available on instances of `Session`: #### `ses.cookies` -A Cookies object for this session. +A [Cookies](cookies.md) object for this session. #### `ses.webRequest` -A WebRequest object for this session. +A [WebRequest](web-request.md) object for this session. #### `ses.protocol` -A Protocol object (an instance of [protocol](protocol.md) module) for this session. +A [Protocol](protocol.md) object for this session. ```javascript const {app, session} = require('electron') From 6a729f90e569e2441ba70ac907fb101e57af8027 Mon Sep 17 00:00:00 2001 From: "Mustafa C. Izol" Date: Mon, 10 Apr 2017 00:47:00 +0200 Subject: [PATCH 218/337] add translation files for application-distrubution and supported platforms --- docs-translations/tr-TR/README.md | 4 +- .../tutorial/application-distribution.md | 178 ++++++++++++++++++ .../tr-TR/tutorial/supported-platforms.md | 29 +++ 3 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 docs-translations/tr-TR/tutorial/application-distribution.md create mode 100644 docs-translations/tr-TR/tutorial/supported-platforms.md diff --git a/docs-translations/tr-TR/README.md b/docs-translations/tr-TR/README.md index d9d8a1bdceb9..494433ee5a3c 100644 --- a/docs-translations/tr-TR/README.md +++ b/docs-translations/tr-TR/README.md @@ -9,8 +9,8 @@ Bir problem(issue) bildirmeden önce sıkça sorulan sorulara göz atın: ## 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) +* [Desteklenen Platformlar ](tutorial/supported-platforms.md) +* [Uygulama Dağıtımı](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) diff --git a/docs-translations/tr-TR/tutorial/application-distribution.md b/docs-translations/tr-TR/tutorial/application-distribution.md new file mode 100644 index 000000000000..319f8af787e5 --- /dev/null +++ b/docs-translations/tr-TR/tutorial/application-distribution.md @@ -0,0 +1,178 @@ +# Application Distribution + +Electron uygulamanızı dağıtmak için önce Electron nun [prebuilt mimarilerini] +(https://github.com/electron/electron/releases) indirmeniz gerekmektedir. +Sonrasında, uygulamanızın bulundugu klasör `app` şeklinde isimlendirilmeli ve +Electron kaynaklar klasörüne aşagıda gösterildiği gibi yerleştirilmelidir. +Unutmayın, Electronun prebuilt mimarileri aşağıdaki örneklerde `electron/` +şeklinde belirtilmiştir. + + +MacOS da: + +```text +electron/Electron.app/Contents/Resources/app/ +├── package.json +├── main.js +└── index.html +``` + +Windows ve Linux da: + +```text +electron/resources/app +├── package.json +├── main.js +└── index.html +``` + +Ardından `Electron.app` (veya `electron` Linux'da, `electron.exe` Windows'da) şeklinde çalıstırın, +ve Electron uygulama şeklinde çalışacaktır. +`electron` klasörü son kullanıcıya aktaracağınız dağıtımınız olacaktır. + +## Uygulamanın bir dosya şeklinde paketlenmesi + +Tüm kaynak kodlarını kopyalama yoluyla uygulamanızı dağıtmak haricinde, +uygulamanızı [asar](https://github.com/electron/asar) ile arşiv haline getirerek, +kaynak kodlarınızın kullanıcılar tarafından görülmesini engelliye bilirsiniz. + +`app` klasörü yerine `asar` arşiv dosyası kullanmak için, arşiv dosyanızı `app.asar` +şeklinde isimlendirmeniz gerekiyor, ve bu dosyayı Electron'nun kaynak klasörüne aşağıdaki +gibi yerleştirmelisiniz. Böylelikle Electron arşivi okuyup ondan başlayacaktır. + + +MacOS'da: + +```text +electron/Electron.app/Contents/Resources/ +└── app.asar +``` + +Windows ve Linux'da: + +```text +electron/resources/ +└── app.asar +``` + +Daha fazla bilgi için [Application packaging](application-packaging.md). + +## İndirilen mimarileri yeniden adlandırma + +Uygulamanızı Electron ile paketledikten sonra ve kullanıcılara uygulamanızı dağıtmadan önce +adını değiştirmek isteye bilirsiniz. + +### Windows + +`electron.exe` istediğiniz şekilde yeniden adlandırabilirsiniz. Icon ve diğer +bilgileri bu gibi araçlar [rcedit](https://github.com/atom/rcedit) ile düzenleye bilirsiniz. + +### macOS + +`Electron.app`'i istediğiniz şekilde yeniden adlandırabilirsiniz, ve aşağıdaki dosyalarda +`CFBundleDisplayName`, `CFBundleIdentifier` ve `CFBundleName` kısımlarınıda düzenlemelisiniz. + +* `Electron.app/Contents/Info.plist` +* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` + +Görev yöneticisinde `Electron Helper` şeklinde göstermek yerine, +isterseniz helper uygulamasınında adını değiştire bilirsiniz, +ancak dosyanın adını açılabilir olduğundan emin olun. + +Yeniden adlandırılmış uygulamanın klasör yapısı bu şekilde görünecektir: + +``` +MyApp.app/Contents +├── Info.plist +├── MacOS/ +│   └── MyApp +└── Frameworks/ + ├── MyApp Helper EH.app + | ├── Info.plist + | └── MacOS/ + |    └── MyApp Helper EH + ├── MyApp Helper NP.app + | ├── Info.plist + | └── MacOS/ + |    └── MyApp Helper NP + └── MyApp Helper.app + ├── Info.plist + └── MacOS/ +    └── MyApp Helper +``` + +### Linux + +`electron` dosyasını istediğiniz şekilde yeniden adlandırabilirsiniz. + +## Paketleme Araçları + +Uygulamanızı manuel şekilde paketlemek dışında, üçüncü parti +paketleme araçlarıylada otomatik olarak ayni şekilde paketliye bilirsiniz: + +* [electron-builder](https://github.com/electron-userland/electron-builder) +* [electron-packager](https://github.com/electron-userland/electron-packager) + +## Kaynaktan yeniden kurulum yoluyla isim değişikliği + +Ürün adını değiştirip, kaynaktan kurulum yoluylada Electron'nun adını değiştirmek mümkün. +Bunun için `atom.gyp` dosyasını yeniden modifiye edip, tekrardan temiz bir kurulum yapmalısınız. + +### grunt-build-atom-shell + +Manuel olarak Electron kodlarını kontrol edip tekrar kurulum yapmak biraz zor olabilir, +bu yüzden tüm bu işlemleri otomatik olarak gerçekleştirecek bir Grunt görevi oluşturuldu: +[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). + +Bu görev otomatik olarak `.gyp` dosyasını düzenleyecek, kaynaktan kurulumu gerçekleştirecek, +sonrasında ise uygulamanızın doğal Node modüllerini, yeni yürütülebilen isim ile eşleştirmek icin +tekrardan kuracaktır. + +### Özel bir Electron kopyası oluşturma + +Electron'un size ait bir kopyasını oluşturmak, neredeyse uygulamanızı kurmak için hiç ihtiyacınız +olmayacak bir işlemdir, "Production Level" uygulamalarda buna dahildir. +`electron-packager` veya `electron-builder` gibi araçlar kullanarak yukarıda ki işlemleri +gerçekleştirmeksizin, "Rebrand" Electron işlemini uygulaya bilirsiniz. + +Eğer kendinize ait yüklenemiyen veya resmi versiyondan red edilmiş, +direk olarak Electron a paketlediğiniz C++ kodunuz var ise, +öncelikle Electron'un bir kopyasını oluşturmalısınız. +Electron'nun destekleyicileri olarak, senaryonuzun çalışmasını çok isteriz, +bu yüzden lütfen yapacağınız değişiklikleri Electron'nun resmi versiyonuna +entegre etmeye calışın, bu sizin için daha kolay olacaktır, ve yardimlarınız +için cok minnettar olacağız. + +#### surf-build İle Özel Dağıtım oluşturulması + +1. Npm yoluyla [Surf](https://github.com/surf-build/surf) yükleyin: + `npm install -g surf-build@latest` + + +2. Yeni bir S3 bucket ve aşağıdakı boş klasör yapısını oluşturun: + + ``` + - atom-shell/ + - symbols/ + - dist/ + ``` + +3. Aşağıdaki Ortam Değişkenlerini ayarlayın: + + * `ELECTRON_GITHUB_TOKEN` - GitHub üzerinden dağıtım oluşturan token + * `ELECTRON_S3_ACCESS_KEY`, `ELECTRON_S3_BUCKET`, `ELECTRON_S3_SECRET_KEY` - + node.js bağlantılarını ve sembollerini yükleyeceğiniz yer + * `ELECTRON_RELEASE` - `true` şeklinde ayarlayın ve yükleme işlemi çalışacaktır, + yapmamanız halinde, `surf-build` sadece CI-type kontrolü yapacak, + tüm pull isteklerine uygun hale getirecektir. + * `CI` - `true` olarak ayarlayın yoksa çalışmayacaktır. + * `GITHUB_TOKEN` - bununla aynı şekilde ayarlayın `ELECTRON_GITHUB_TOKEN` + * `SURF_TEMP` - Windowsda ki 'path too long' sorunundan kaçınmak için `C:\Temp` şeklinde ayarlayın + * `TARGET_ARCH` - `ia32` veya `x64` şeklinde ayarlayın + +4. `script/upload.py` dosyasında ki `ELECTRON_REPO` kısmını, kendi kopyanız ile değiştirmek _zorundasınız_, + özellikle eğer bir Electron proper destekleyicisi iseniz. + +5. `surf-build -r https://github.com/MYORG/electron -s YOUR_COMMIT -n 'surf-PLATFORM-ARCH'` + +6. Kurulum bitene kadar uzunca bekleyin. diff --git a/docs-translations/tr-TR/tutorial/supported-platforms.md b/docs-translations/tr-TR/tutorial/supported-platforms.md new file mode 100644 index 000000000000..4cc131b103a5 --- /dev/null +++ b/docs-translations/tr-TR/tutorial/supported-platforms.md @@ -0,0 +1,29 @@ +# Desteklenen platformlar + +Aşağıdaki platformlar Electron tarafından desteklenmektedir: + +### macOS + +MacOS için sadece 64bit mimariler sağlanmakta olup, desteklenen minimum macOS versiyonu 10.9 dur. + +### Windows + +Windows 7 ve gelişmiş versiyonlar desteklenmektedir, eski işletim sistemleri desteklenmemektedir +(ve çalışmayacaktır). + +Windows `ia32` (`x86`) ve `x64` (`amd64`) mimarileri desteklenmektedir. +Unutmayın, `ARM` mimarisi al₺tında çalışan Windows işletim sistemleri şuan için desteklenmemektedir. + +### Linux + +Electron `ia32` (`i686`) ve `x64` (`amd64`) Prebuilt mimarileri Ubuntu 12.04 üzerinde kurulmuştur, +`arm` mimarisi ARM v7 ye karşılık olarak, hard-float ABI ve NEON Debian Wheezy ile kurulmuştur. + +Prebuilt +Prebuilt mimarisi ancak Electron'nun yapı platformu ile bağlantılı olan kütüphaneleri içeren dağıtımlar ile çalışır. +Bu yüzden sadece Ubuntu 12.04 üzerinde çalışması garanti ediliyor, fakat aşagidaki platformlarında +Electron Prebuilt mimarisini çalıştıra bileceği doğrulanmıştır. + +* Ubuntu 12.04 ve sonrası +* Fedora 21 +* Debian 8 From 34beb52edb49f9e6b64dc834524ac15cd09d695d Mon Sep 17 00:00:00 2001 From: "Mustafa C. Izol" Date: Mon, 10 Apr 2017 01:23:14 +0200 Subject: [PATCH 219/337] fix link to electron faq --- docs-translations/tr-TR/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-translations/tr-TR/README.md b/docs-translations/tr-TR/README.md index 494433ee5a3c..a3487d298a2e 100644 --- a/docs-translations/tr-TR/README.md +++ b/docs-translations/tr-TR/README.md @@ -5,7 +5,7 @@ Eğer öyleyse, atom.io üzerinden [mevcut sürümler](https://electron.atom.io/ ## 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) +* [Electron SSS](https://github.com/electron/electron/blob/master/docs/faq.md) ## Klavuzlar From 613c835eec62df8acde4287c9edbe009817c0687 Mon Sep 17 00:00:00 2001 From: "Mustafa C. Izol" Date: Mon, 10 Apr 2017 02:10:52 +0200 Subject: [PATCH 220/337] add turkish readme file --- docs-translations/tr-TR/project/README.md | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 docs-translations/tr-TR/project/README.md diff --git a/docs-translations/tr-TR/project/README.md b/docs-translations/tr-TR/project/README.md new file mode 100644 index 000000000000..d5be7773932c --- /dev/null +++ b/docs-translations/tr-TR/project/README.md @@ -0,0 +1,85 @@ +[![Electron Logo](https://electron.atom.io/images/electron-logo.svg)](https://electron.atom.io/) + +[![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/bc56v83355fi3369/branch/master?svg=true)](https://ci.appveyor.com/project/electron-bot/electron/branch/master) +[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev) +[![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) + +:memo: Mevcut çeviriler: [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) | [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es/project/README.md)| [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR/project/README.md) + +Electron framework JavaScript, HTML ve CSS kullanarak çapraz platform +masaüstü uygulamaları yazmanıza yarar. Electron [Node.js](https://nodejs.org/) ile geliştirilmiş; +[Atom editor](https://github.com/atom/atom) ve birçok uygulama [apps](https://electron.atom.io/apps) tarafından kullanılmaktadir. + +Önemli duyurular için Twitter da [@ElectronJS](https://twitter.com/electronjs) adresini takip edin. + +Bu proje katılımcı sözleşmesine bağlıdır. Katılarak, +bu kodun sürdürülebilir olduğunu üstlenmeniz beklenmekte. +Lütfen uygun olmayan davranışları electron@github.com'a rapor edin. + +## Downloads + +Electron prebuilt mimarisini yüklemek için, +[`npm`](https://docs.npmjs.com/): + +```sh +# Development dependency olarak yükleyin +npm install electron --save-dev + +# `electron` komutunu global olarak $PATH'a yükleyin +npm install electron -g +``` + +Prebuilt mimarileri, debug sembolleri, ve fazlası için +[releases page](https://github.com/electron/electron/releases) sayfasını ziyaret edin. + +### Mirrors + +- [China](https://npm.taobao.org/mirrors/electron) + +## Dokümantasyon + +Klavuz ve API referansları [docs](https://github.com/electron/electron/tree/master/docs) klasöründe bulunabilir. +Aynı zamanda nasıl kurulum gerçekleştirileceği ve Electron'un gelişimine nasıl katılacağınızı +açıklayan dosyalar içermektedir. + +## Dökümantasyon Çevirileri + +- [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) +- [Thai](https://github.com/electron/electron/tree/master/docs-Translations/th-TH) +- [Ukrainian](https://github.com/electron/electron/tree/master/docs-translations/uk-UA) +- [Russian](https://github.com/electron/electron/tree/master/docs-translations/ru-RU) +- [French](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) + +## Hızlı Başlangıç + +Minimal Electron uygulamasını calışırken görmek için [`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) +repository'ni klonla ve çalıştır. + +## Topluluk + +Asağıdaki sayfalardan sorular sorabilir ve topluluk ile etkileşime geçebilirsiniz: + +- [`electron`](http://discuss.atom.io/c/electron) Atom forumundaki kategoriler +- `#atom-shell` Freenode kanal'ı +- [`Atom`](http://atom-slack.herokuapp.com/) Slack kanal'ı +- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)* +- [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)* +- [`electron-jp`](https://electron-jp.slack.com) *(Japanese)* +- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turkish)* +- [`electron-id`](https://electron-id.slack.com) *(Indonesia)* + +Topluluk tarafından sağlanan örnek uygulamaları, aracları ve kaynaklara ulaşmak için +[awesome-electron](https://github.com/sindresorhus/awesome-electron) sayfasını ziyaret et. + +## Lisans + +[MIT](https://github.com/electron/electron/blob/master/LICENSE) + +Electron veya Github logolarını kullandığınızda, [GitHub logo guidelines](https://github.com/logos) sayfasını okuduğunuzdan emin olun. From 8f46137fda20aa98486f62e1ff776f261b46ea97 Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Mon, 10 Apr 2017 02:12:15 +0200 Subject: [PATCH 221/337] Fix session.setPermissionRequestHandler webContents argument type --- docs/api/session.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/session.md b/docs/api/session.md index 7c7831c8ac37..64c526c304d5 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -287,7 +287,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => { #### `ses.setPermissionRequestHandler(handler)` * `handler` Function - * `webContents` Object - [WebContents](web-contents.md) requesting the permission. + * `webContents` [WebContents](web-contents.md) - WebContents requesting the permission. * `permission` String - Enum of 'media', 'geolocation', 'notifications', 'midiSysex', 'pointerLock', 'fullscreen', 'openExternal'. * `callback` Function From 475620119efd4b5a1cfc1c0ff1af003e753d41b7 Mon Sep 17 00:00:00 2001 From: "Mustafa C. Izol" Date: Mon, 10 Apr 2017 02:12:53 +0200 Subject: [PATCH 222/337] add turkish translation link to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8f55c19bd21..8a682bb727c5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev) [![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) -:memo: Available Translations: [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) | [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es/project/README.md) +:memo: Available Translations: [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) | [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es/project/README.md) | [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR/project/README.md) The Electron framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org/) and From fa0de5c2b4f861a7fb2494fc505daec562b2c4ff Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Mon, 10 Apr 2017 02:18:36 +0200 Subject: [PATCH 223/337] Define filter argument type for WebRequest methods --- docs/api/web-request.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/api/web-request.md b/docs/api/web-request.md index 6da98d81f1ff..a271add9da26 100644 --- a/docs/api/web-request.md +++ b/docs/api/web-request.md @@ -42,6 +42,8 @@ The following methods are available on instances of `WebRequest`: #### `webRequest.onBeforeRequest([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function * `details` Object * `id` Integer @@ -66,6 +68,8 @@ The `callback` has to be called with an `response` object. #### `webRequest.onBeforeSendHeaders([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function The `listener` will be called with `listener(details, callback)` before sending @@ -90,6 +94,8 @@ The `callback` has to be called with an `response` object. #### `webRequest.onSendHeaders([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function * `details` Object * `id` Integer @@ -106,6 +112,8 @@ response are visible by the time this listener is fired. #### `webRequest.onHeadersReceived([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function The `listener` will be called with `listener(details, callback)` when HTTP @@ -134,6 +142,8 @@ The `callback` has to be called with an `response` object. #### `webRequest.onResponseStarted([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function * `details` Object * `id` Integer @@ -154,6 +164,8 @@ and response headers are available. #### `webRequest.onBeforeRedirect([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function * `details` Object * `id` String @@ -174,6 +186,8 @@ redirect is about to occur. #### `webRequest.onCompleted([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function * `details` Object * `id` Integer @@ -192,6 +206,8 @@ completed. #### `webRequest.onErrorOccurred([filter, ]listener)` * `filter` Object + * `urls` String[] - Array of URL patterns that will be used to filter out the + requests that do not match the URL patterns. * `listener` Function * `details` Object * `id` Integer From 0ce983363bfd841275d7adb3d281f25340444459 Mon Sep 17 00:00:00 2001 From: Hum4n01d Date: Sun, 9 Apr 2017 23:05:56 -0700 Subject: [PATCH 224/337] Add information about dragging not working with Dev tools open --- docs/api/frameless-window.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index 3ef5cdc93e9e..8fbbae10f641 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -98,6 +98,8 @@ By default, the frameless window is non-draggable. Apps need to specify `-webkit-app-region: no-drag` to exclude the non-draggable area from the draggable region. Note that only rectangular shapes are currently supported. +Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [Github issue](https://github.com/electron/electron/issues/3647) for more information including a workaround. + To make the whole window draggable, you can add `-webkit-app-region: drag` as `body`'s style: From d3953f72802f68a45b18b9902be4d604cab9015f Mon Sep 17 00:00:00 2001 From: Catalin Fratila Date: Mon, 10 Apr 2017 16:41:16 +0200 Subject: [PATCH 225/337] #9128: Removed unused dll from distribution. --- docs-translations/ko-KR/tutorial/windows-store-guide.md | 3 +-- docs-translations/zh-CN/tutorial/windows-store-guide.md | 3 +-- docs/tutorial/windows-store-guide.md | 3 +-- electron.gyp | 1 - script/create-dist.py | 1 - 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs-translations/ko-KR/tutorial/windows-store-guide.md b/docs-translations/ko-KR/tutorial/windows-store-guide.md index 34d36d6bc544..23a4bbc32f63 100644 --- a/docs-translations/ko-KR/tutorial/windows-store-guide.md +++ b/docs-translations/ko-KR/tutorial/windows-store-guide.md @@ -67,8 +67,7 @@ npm install -g electron-windows-store │ └── atom.asar ├── snapshot_blob.bin ├── squirrel.exe -├── ui_resources_200_percent.pak -└── xinput1_3.dll +└── ui_resources_200_percent.pak ``` ## `electron-windows-store` 실행하기 diff --git a/docs-translations/zh-CN/tutorial/windows-store-guide.md b/docs-translations/zh-CN/tutorial/windows-store-guide.md index 67cd39e5a520..a34f40d2ee40 100644 --- a/docs-translations/zh-CN/tutorial/windows-store-guide.md +++ b/docs-translations/zh-CN/tutorial/windows-store-guide.md @@ -49,8 +49,7 @@ npm install -g electron-windows-store │   └── atom.asar ├── snapshot_blob.bin ├── squirrel.exe -├── ui_resources_200_percent.pak -└── xinput1_3.dll +└── ui_resources_200_percent.pak ``` ## 步骤 2: 运行 electron-windows-store diff --git a/docs/tutorial/windows-store-guide.md b/docs/tutorial/windows-store-guide.md index 4cca798aec65..abf964318102 100644 --- a/docs/tutorial/windows-store-guide.md +++ b/docs/tutorial/windows-store-guide.md @@ -69,8 +69,7 @@ The output should look roughly like this: │   └── atom.asar ├── snapshot_blob.bin ├── squirrel.exe -├── ui_resources_200_percent.pak -└── xinput1_3.dll +└── ui_resources_200_percent.pak ``` ## Step 2: Running electron-windows-store diff --git a/electron.gyp b/electron.gyp index e6dd08bdfb95..8456a337e1c7 100644 --- a/electron.gyp +++ b/electron.gyp @@ -159,7 +159,6 @@ '<(libchromiumcontent_dir)/natives_blob.bin', '<(libchromiumcontent_dir)/snapshot_blob.bin', 'external_binaries/d3dcompiler_47.dll', - 'external_binaries/xinput1_3.dll', ], }, ], diff --git a/script/create-dist.py b/script/create-dist.py index 3d4b62624eee..27032400f3d3 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -43,7 +43,6 @@ TARGET_BINARIES = { 'content_resources_200_percent.pak', 'ui_resources_200_percent.pak', 'views_resources_200_percent.pak', - 'xinput1_3.dll', 'natives_blob.bin', 'snapshot_blob.bin', ], From 676f02e0016a69a47343dd82966808bb2beefe59 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 10 Apr 2017 08:17:55 -0700 Subject: [PATCH 226/337] Tweak GitHub spelling --- docs/api/frameless-window.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index 8fbbae10f641..4f091ec6c3c9 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -98,7 +98,7 @@ By default, the frameless window is non-draggable. Apps need to specify `-webkit-app-region: no-drag` to exclude the non-draggable area from the draggable region. Note that only rectangular shapes are currently supported. -Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [Github issue](https://github.com/electron/electron/issues/3647) for more information including a workaround. +Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [GitHub issue](https://github.com/electron/electron/issues/3647) for more information including a workaround. To make the whole window draggable, you can add `-webkit-app-region: drag` as `body`'s style: From 2c6ef95923b71786f1d84e6105af64e199c144ae Mon Sep 17 00:00:00 2001 From: Mustafa Date: Mon, 10 Apr 2017 18:41:52 +0200 Subject: [PATCH 227/337] add electron slack channel for turkish community --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a682bb727c5..213580a5e2a7 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ forums - [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)* - [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)* - [`electron-jp`](https://electron-jp.slack.com) *(Japanese)* -- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turkish)* +- [`electron-tr`](https://electron-tr.slack.com) *(Turkish)* - [`electron-id`](https://electron-id.slack.com) *(Indonesia)* Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron) From c59ef0efc5473b7fa3210c65199a608d4b22fa93 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 11 Apr 2017 15:17:15 +0900 Subject: [PATCH 228/337] Enable per-monitor DPI --- atom/browser/resources/win/atom.manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/resources/win/atom.manifest b/atom/browser/resources/win/atom.manifest index 64c07ded17b0..7608ffb20f6c 100644 --- a/atom/browser/resources/win/atom.manifest +++ b/atom/browser/resources/win/atom.manifest @@ -32,7 +32,7 @@ - true + true/pm true From 29c68182df5d25d46911aecfac161f895861638c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 15:42:37 -0700 Subject: [PATCH 229/337] Always set NSScrollViewRubberbanding scroll bounce pref --- atom/renderer/renderer_client_base.cc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/atom/renderer/renderer_client_base.cc b/atom/renderer/renderer_client_base.cc index 3ee72b3c0da2..4d8bc6bebe28 100644 --- a/atom/renderer/renderer_client_base.cc +++ b/atom/renderer/renderer_client_base.cc @@ -96,16 +96,14 @@ void RendererClientBase::RenderThreadStarted() { #endif #if defined(OS_MACOSX) - // Disable rubber banding by default. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (!command_line->HasSwitch(switches::kScrollBounce)) { - base::ScopedCFTypeRef key( - base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding")); - base::ScopedCFTypeRef value( - base::SysUTF8ToCFStringRef("false")); - CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication); - CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); - } + bool scroll_bounce = command_line->HasSwitch(switches::kScrollBounce); + base::ScopedCFTypeRef rubber_banding_key( + base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding")); + CFPreferencesSetAppValue(rubber_banding_key, + scroll_bounce ? kCFBooleanTrue : kCFBooleanFalse, + kCFPreferencesCurrentApplication); + CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); #endif } From bfb93881916578f73bf48c929ceb73a1b3b95710 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 15:02:32 -0700 Subject: [PATCH 230/337] Add failing spec for app.exit with >2 windows --- spec/api-app-spec.js | 10 ++++++++++ .../api/exit-closes-all-windows-app/main.js | 19 +++++++++++++++++++ .../exit-closes-all-windows-app/package.json | 4 ++++ 3 files changed, 33 insertions(+) create mode 100644 spec/fixtures/api/exit-closes-all-windows-app/main.js create mode 100644 spec/fixtures/api/exit-closes-all-windows-app/package.json diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 301d6ae4bf47..9a9b4334bceb 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -137,6 +137,16 @@ describe('app module', function () { done() }) }) + + it('closes all windows', function (done) { + var appPath = path.join(__dirname, 'fixtures', 'api', 'exit-closes-all-windows-app') + var electronPath = remote.getGlobal('process').execPath + appProcess = ChildProcess.spawn(electronPath, [appPath]) + appProcess.on('close', function (code) { + assert.equal(code, 123) + done() + }) + }) }) describe('app.relaunch', function () { diff --git a/spec/fixtures/api/exit-closes-all-windows-app/main.js b/spec/fixtures/api/exit-closes-all-windows-app/main.js new file mode 100644 index 000000000000..c97d8d1f195b --- /dev/null +++ b/spec/fixtures/api/exit-closes-all-windows-app/main.js @@ -0,0 +1,19 @@ +const {app, BrowserWindow} = require('electron') + +const windows = [] + +function createWindow (id) { + const window = new BrowserWindow({show: false}) + window.loadURL(`data:,window${id}`) + windows.push(window) +} + +app.once('ready', () => { + for (let i = 1; i <= 5; i++) { + createWindow(i) + } + + setImmediate(function () { + app.exit(123) + }) +}) diff --git a/spec/fixtures/api/exit-closes-all-windows-app/package.json b/spec/fixtures/api/exit-closes-all-windows-app/package.json new file mode 100644 index 000000000000..ae52532315a3 --- /dev/null +++ b/spec/fixtures/api/exit-closes-all-windows-app/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron-exit-closes-all-windows", + "main": "main.js" +} From 8311aa667c0bc637e9cf7ba72b1a8d32ee706991 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 14:25:22 -0700 Subject: [PATCH 231/337] Add DestroyAllWindows helper that uses vector copy --- atom/browser/browser.cc | 3 +-- atom/browser/window_list.cc | 7 +++++++ atom/browser/window_list.h | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index b18ab7b70fd7..1df1f316c1b8 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -71,8 +71,7 @@ void Browser::Exit(mate::Arguments* args) { } else { // Unlike Quit(), we do not ask to close window, but destroy the window // without asking. - for (NativeWindow* window : *window_list) - window->CloseContents(nullptr); // e.g. Destroy() + atom::WindowList::DestroyAllWindows(); } } } diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc index d627f6d1206b..bcf4a9f1e2c0 100644 --- a/atom/browser/window_list.cc +++ b/atom/browser/window_list.cc @@ -76,6 +76,13 @@ void WindowList::CloseAllWindows() { window->Close(); } +// static +void WindowList::DestroyAllWindows() { + WindowVector windows = GetInstance()->windows_; + for (const auto& window : windows) + window->CloseContents(nullptr); // e.g. Destroy() +} + WindowList::WindowList() { } diff --git a/atom/browser/window_list.h b/atom/browser/window_list.h index d9b307352e90..557a7969e59a 100644 --- a/atom/browser/window_list.h +++ b/atom/browser/window_list.h @@ -51,6 +51,9 @@ class WindowList { // Closes all windows. static void CloseAllWindows(); + // Destroy all windows. + static void DestroyAllWindows(); + private: WindowList(); ~WindowList(); From 0883a9f96606cb54fd29693eab5d1ec3c573f7f6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 14:37:39 -0700 Subject: [PATCH 232/337] Use CloseAllWindows helper --- atom/browser/api/atom_api_auto_updater.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index 276d889006d1..60bbcbda044f 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -95,8 +95,7 @@ void AutoUpdater::QuitAndInstall() { // Otherwise do the restart after all windows have been closed. window_list->AddObserver(this); - for (NativeWindow* window : *window_list) - window->Close(); + WindowList::CloseAllWindows(); } // static From da5d7d72b034c4bd7f7b1dbdd2d4f6f4c8cd0fb6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 14:43:37 -0700 Subject: [PATCH 233/337] Add GetWindows helper that returns a vector --- atom/browser/browser_linux.cc | 4 +--- atom/browser/browser_mac.mm | 5 ++--- atom/browser/native_window.cc | 3 +-- atom/browser/window_list.cc | 5 +++++ atom/browser/window_list.h | 15 ++------------- 5 files changed, 11 insertions(+), 21 deletions(-) diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc index 4dd799dfaf02..f569040a2189 100644 --- a/atom/browser/browser_linux.cc +++ b/atom/browser/browser_linux.cc @@ -16,9 +16,7 @@ namespace atom { void Browser::Focus() { // Focus on the first visible window. - WindowList* list = WindowList::GetInstance(); - for (WindowList::iterator iter = list->begin(); iter != list->end(); ++iter) { - NativeWindow* window = *iter; + for (const auto& window : WindowList::GetWindows()) { if (window->IsVisible()) { window->Focus(true); break; diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 51604e377cd6..38a0a003d968 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -204,9 +204,8 @@ std::string Browser::DockGetBadgeText() { } void Browser::DockHide() { - WindowList* list = WindowList::GetInstance(); - for (WindowList::iterator it = list->begin(); it != list->end(); ++it) - [(*it)->GetNativeWindow() setCanHide:NO]; + for (const auto& window : WindowList::GetWindows()) + [window->GetNativeWindow() setCanHide:NO]; ProcessSerialNumber psn = { 0, kCurrentProcess }; TransformProcessType(&psn, kProcessTransformToUIElementApplication); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index af32a2e8a85a..316cc8dc2e3d 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -104,8 +104,7 @@ NativeWindow::~NativeWindow() { // static NativeWindow* NativeWindow::FromWebContents( content::WebContents* web_contents) { - WindowList& window_list = *WindowList::GetInstance(); - for (NativeWindow* window : window_list) { + for (const auto& window : WindowList::GetWindows()) { if (window->web_contents() == web_contents) return window; } diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc index bcf4a9f1e2c0..8fa2ed67438e 100644 --- a/atom/browser/window_list.cc +++ b/atom/browser/window_list.cc @@ -26,6 +26,11 @@ WindowList* WindowList::GetInstance() { return instance_; } +// static +WindowList::WindowVector WindowList::GetWindows() { + return GetInstance()->windows_; +} + // static void WindowList::AddWindow(NativeWindow* window) { DCHECK(window); diff --git a/atom/browser/window_list.h b/atom/browser/window_list.h index 557a7969e59a..81ff5de10573 100644 --- a/atom/browser/window_list.h +++ b/atom/browser/window_list.h @@ -19,24 +19,13 @@ class WindowListObserver; class WindowList { public: typedef std::vector WindowVector; - typedef WindowVector::iterator iterator; - typedef WindowVector::const_iterator const_iterator; - - // Windows are added to the list before they have constructed windows, - // so the |window()| member function may return NULL. - const_iterator begin() const { return windows_.begin(); } - const_iterator end() const { return windows_.end(); } - - iterator begin() { return windows_.begin(); } - iterator end() { return windows_.end(); } bool empty() const { return windows_.empty(); } - size_t size() const { return windows_.size(); } - - NativeWindow* get(size_t index) const { return windows_[index]; } static WindowList* GetInstance(); + static WindowVector GetWindows(); + // Adds or removes |window| from the list it is associated with. static void AddWindow(NativeWindow* window); static void RemoveWindow(NativeWindow* window); From e7b679ead64045846aa457a6af8bd251ffe239e3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 6 Apr 2017 14:48:58 -0700 Subject: [PATCH 234/337] Add IsEmpty helper and remove GetInstance public usage --- atom/browser/api/atom_api_auto_updater.cc | 5 ++--- atom/browser/browser.cc | 10 ++++------ atom/browser/window_list.cc | 5 +++++ atom/browser/window_list.h | 7 +++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index 60bbcbda044f..ea3024191e97 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -87,14 +87,13 @@ void AutoUpdater::SetFeedURL(const std::string& url, mate::Arguments* args) { void AutoUpdater::QuitAndInstall() { // If we don't have any window then quitAndInstall immediately. - WindowList* window_list = WindowList::GetInstance(); - if (window_list->empty()) { + if (WindowList::IsEmpty()) { auto_updater::AutoUpdater::QuitAndInstall(); return; } // Otherwise do the restart after all windows have been closed. - window_list->AddObserver(this); + WindowList::AddObserver(this); WindowList::CloseAllWindows(); } diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index 1df1f316c1b8..b2900a326ff3 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -43,11 +43,10 @@ void Browser::Quit() { if (!is_quiting_) return; - atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->empty()) + if (atom::WindowList::IsEmpty()) NotifyAndShutdown(); - - window_list->CloseAllWindows(); + else + atom::WindowList::CloseAllWindows(); } void Browser::Exit(mate::Arguments* args) { @@ -65,8 +64,7 @@ void Browser::Exit(mate::Arguments* args) { is_exiting_ = true; // Must destroy windows before quitting, otherwise bad things can happen. - atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->empty()) { + if (atom::WindowList::IsEmpty()) { Shutdown(); } else { // Unlike Quit(), we do not ask to close window, but destroy the window diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc index 8fa2ed67438e..374389e0a786 100644 --- a/atom/browser/window_list.cc +++ b/atom/browser/window_list.cc @@ -31,6 +31,11 @@ WindowList::WindowVector WindowList::GetWindows() { return GetInstance()->windows_; } +// static +bool WindowList::IsEmpty() { + return GetInstance()->windows_.empty(); +} + // static void WindowList::AddWindow(NativeWindow* window) { DCHECK(window); diff --git a/atom/browser/window_list.h b/atom/browser/window_list.h index 81ff5de10573..e336c8073dc8 100644 --- a/atom/browser/window_list.h +++ b/atom/browser/window_list.h @@ -20,11 +20,8 @@ class WindowList { public: typedef std::vector WindowVector; - bool empty() const { return windows_.empty(); } - - static WindowList* GetInstance(); - static WindowVector GetWindows(); + static bool IsEmpty(); // Adds or removes |window| from the list it is associated with. static void AddWindow(NativeWindow* window); @@ -44,6 +41,8 @@ class WindowList { static void DestroyAllWindows(); private: + static WindowList* GetInstance(); + WindowList(); ~WindowList(); From c77e07bc1539e3d395047a03adbfb1ef0e2e249d Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Wed, 12 Apr 2017 11:55:41 +0900 Subject: [PATCH 235/337] Fix afterEach --- spec/modules-spec.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/spec/modules-spec.js b/spec/modules-spec.js index 02fec41444d7..7cc5d34fe682 100644 --- a/spec/modules-spec.js +++ b/spec/modules-spec.js @@ -4,6 +4,7 @@ const path = require('path') const temp = require('temp') const {remote} = require('electron') const {BrowserWindow} = remote +const {closeWindow} = require('./window-helpers') describe('third-party module', function () { var fixtures = path.join(__dirname, 'fixtures') @@ -142,14 +143,15 @@ describe('require', () => { }) }) + afterEach(async () => { + await closeWindow(w) + w = null + }) + it('searches for module under app directory', async () => { w.loadURL('about:blank') const result = await w.webContents.executeJavaScript('typeof require("q").when') assert.equal(result, 'function') }) - - afterEach(() => { - w.destroy() - }) }) }) From 4f26424ace569e25dd35f21f9ef09895b84df0f4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 11 Apr 2017 16:53:24 -0700 Subject: [PATCH 236/337] Upgrade brightray for Windows 7 notifications --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index baccc077948f..28d713bb2a82 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit baccc077948f504c6a6db58e855fd33938b2b625 +Subproject commit 28d713bb2a82ba690a21d62522ecd7bad09caba8 From 8b9f7e5b00187a1fc608c883fdfdbae9727f1729 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Tue, 11 Apr 2017 20:47:30 +0300 Subject: [PATCH 237/337] Implement initial, experimental BrowserView API Right now, `` is the only way to embed additional content in a `BrowserWindow`. Unfortunately `` suffers from a [number of problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20). To make matters worse, many of these are upstream Chromium bugs instead of Electron-specific bugs. For us at [Figma](https://www.figma.com), the main issue is very slow performance. Despite the upstream improvements to `` through the OOPIF work, it is probable that there will continue to be ``-specific bugs in the future. Therefore, this introduces a `` alternative to called `BrowserView`, which... - is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will likely also be bugs in `BrowserWindow` web contents) - is instantiated in the main process like `BrowserWindow` (and unlike ``, which lives in the DOM of a `BrowserWindow` web contents) - needs to be added to a `BrowserWindow` to display something on the screen This implements the most basic API. The API is expected to evolve and change in the near future and has consequently been marked as experimental. Please do not use this API in production unless you are prepared to deal with breaking changes. In the future, we will want to change the API to support multiple `BrowserView`s per window. We will also want to consider z-ordering auto-resizing, and possibly even nested views. --- atom/browser/api/atom_api_browser_view.cc | 128 +++++++++++++++++++ atom/browser/api/atom_api_browser_view.h | 70 ++++++++++ atom/browser/api/atom_api_web_contents.cc | 11 +- atom/browser/api/atom_api_web_contents.h | 9 +- atom/browser/api/atom_api_window.cc | 29 ++++- atom/browser/api/atom_api_window.h | 3 + atom/browser/common_web_contents_delegate.cc | 9 +- atom/browser/native_browser_view.cc | 18 +++ atom/browser/native_browser_view.h | 51 ++++++++ atom/browser/native_browser_view_mac.h | 29 +++++ atom/browser/native_browser_view_mac.mm | 40 ++++++ atom/browser/native_browser_view_views.cc | 36 ++++++ atom/browser/native_browser_view_views.h | 27 ++++ atom/browser/native_window.h | 3 + atom/browser/native_window_mac.h | 3 + atom/browser/native_window_mac.mm | 24 +++- atom/browser/native_window_views.cc | 16 +++ atom/browser/native_window_views.h | 3 + atom/common/node_bindings.cc | 5 +- docs/api/browser-view.md | 62 +++++++++ docs/api/browser-window.md | 7 + filenames.gypi | 25 ++-- lib/browser/api/browser-view.js | 8 ++ lib/browser/api/module-list.js | 1 + spec/api-browser-view-spec.js | 71 ++++++++++ 25 files changed, 665 insertions(+), 23 deletions(-) create mode 100644 atom/browser/api/atom_api_browser_view.cc create mode 100644 atom/browser/api/atom_api_browser_view.h create mode 100644 atom/browser/native_browser_view.cc create mode 100644 atom/browser/native_browser_view.h create mode 100644 atom/browser/native_browser_view_mac.h create mode 100644 atom/browser/native_browser_view_mac.mm create mode 100644 atom/browser/native_browser_view_views.cc create mode 100644 atom/browser/native_browser_view_views.h create mode 100644 docs/api/browser-view.md create mode 100644 lib/browser/api/browser-view.js create mode 100644 spec/api-browser-view-spec.js diff --git a/atom/browser/api/atom_api_browser_view.cc b/atom/browser/api/atom_api_browser_view.cc new file mode 100644 index 000000000000..67533e645d39 --- /dev/null +++ b/atom/browser/api/atom_api_browser_view.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_browser_view.h" + +#include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/browser.h" +#include "atom/browser/native_browser_view.h" +#include "atom/common/color_util.h" +#include "atom/common/native_mate_converters/gfx_converter.h" +#include "atom/common/native_mate_converters/value_converter.h" +#include "atom/common/node_includes.h" +#include "atom/common/options_switches.h" +#include "native_mate/constructor.h" +#include "native_mate/dictionary.h" +#include "ui/gfx/geometry/rect.h" + +namespace atom { + +namespace api { + +BrowserView::BrowserView(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options) + : api_web_contents_(nullptr) { + Init(isolate, wrapper, options); +} + +void BrowserView::Init(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options) { + mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); + options.Get(options::kWebPreferences, &web_preferences); + web_preferences.Set("isBrowserView", true); + mate::Handle web_contents = + WebContents::Create(isolate, web_preferences); + + web_contents_.Reset(isolate, web_contents.ToV8()); + api_web_contents_ = web_contents.get(); + + view_.reset(NativeBrowserView::Create( + api_web_contents_->managed_web_contents()->GetView())); + + InitWith(isolate, wrapper); +} + +BrowserView::~BrowserView() { + api_web_contents_->DestroyWebContents(); +} + +// static +mate::WrappableBase* BrowserView::New(mate::Arguments* args) { + if (!Browser::Get()->is_ready()) { + args->ThrowError("Cannot create BrowserView before app is ready"); + return nullptr; + } + + if (args->Length() > 1) { + args->ThrowError("Too many arguments"); + return nullptr; + } + + mate::Dictionary options; + if (!(args->Length() == 1 && args->GetNext(&options))) { + options = mate::Dictionary::CreateEmpty(args->isolate()); + } + + return new BrowserView(args->isolate(), args->GetThis(), options); +} + +int32_t BrowserView::ID() const { + return weak_map_id(); +} + +void BrowserView::SetBounds(const gfx::Rect& bounds) { + view_->SetBounds(bounds); +} + +void BrowserView::SetBackgroundColor(const std::string& color_name) { + view_->SetBackgroundColor(ParseHexColor(color_name)); +} + +v8::Local BrowserView::WebContents() { + if (web_contents_.IsEmpty()) { + return v8::Null(isolate()); + } + + return v8::Local::New(isolate(), web_contents_); +} + +// static +void BrowserView::BuildPrototype(v8::Isolate* isolate, + v8::Local prototype) { + prototype->SetClassName(mate::StringToV8(isolate, "BrowserView")); + mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) + .MakeDestroyable() + .SetMethod("setBounds", &BrowserView::SetBounds) + .SetMethod("setBackgroundColor", &BrowserView::SetBackgroundColor) + .SetProperty("webContents", &BrowserView::WebContents) + .SetProperty("id", &BrowserView::ID); +} + +} // namespace api + +} // namespace atom + +namespace { + +using atom::api::BrowserView; + +void Initialize(v8::Local exports, + v8::Local unused, + v8::Local context, + void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + BrowserView::SetConstructor(isolate, base::Bind(&BrowserView::New)); + + mate::Dictionary browser_view( + isolate, BrowserView::GetConstructor(isolate)->GetFunction()); + + mate::Dictionary dict(isolate, exports); + dict.Set("BrowserView", browser_view); +} + +} // namespace + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_browser_view, Initialize) diff --git a/atom/browser/api/atom_api_browser_view.h b/atom/browser/api/atom_api_browser_view.h new file mode 100644 index 000000000000..875d84289825 --- /dev/null +++ b/atom/browser/api/atom_api_browser_view.h @@ -0,0 +1,70 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_API_ATOM_API_BROWSER_VIEW_H_ +#define ATOM_BROWSER_API_ATOM_API_BROWSER_VIEW_H_ + +#include +#include + +#include "atom/browser/api/trackable_object.h" +#include "native_mate/handle.h" + +namespace gfx { +class Rect; +} + +namespace mate { +class Arguments; +class Dictionary; +} // namespace mate + +namespace atom { + +class NativeBrowserView; + +namespace api { + +class WebContents; + +class BrowserView : public mate::TrackableObject { + public: + static mate::WrappableBase* New(mate::Arguments* args); + + static void BuildPrototype(v8::Isolate* isolate, + v8::Local prototype); + + NativeBrowserView* view() const { return view_.get(); } + + int32_t ID() const; + + protected: + BrowserView(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options); + ~BrowserView() override; + + private: + void Init(v8::Isolate* isolate, + v8::Local wrapper, + const mate::Dictionary& options); + + void SetBounds(const gfx::Rect& bounds); + void SetBackgroundColor(const std::string& color_name); + + v8::Local WebContents(); + + v8::Global web_contents_; + class WebContents* api_web_contents_; + + std::unique_ptr view_; + + DISALLOW_COPY_AND_ASSIGN(BrowserView); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_BROWSER_VIEW_H_ diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 9390777f9c58..d3e7bae2e412 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -188,6 +188,7 @@ struct Converter { switch (val) { case Type::BACKGROUND_PAGE: type = "backgroundPage"; break; case Type::BROWSER_WINDOW: type = "window"; break; + case Type::BROWSER_VIEW: type = "browserView"; break; case Type::REMOTE: type = "remote"; break; case Type::WEB_VIEW: type = "webview"; break; case Type::OFF_SCREEN: type = "offscreen"; break; @@ -202,10 +203,12 @@ struct Converter { std::string type; if (!ConvertFromV8(isolate, val, &type)) return false; - if (type == "webview") { - *out = Type::WEB_VIEW; - } else if (type == "backgroundPage") { + if (type == "backgroundPage") { *out = Type::BACKGROUND_PAGE; + } else if (type == "browserView") { + *out = Type::BROWSER_VIEW; + } else if (type == "webview") { + *out = Type::WEB_VIEW; } else if (type == "offscreen") { *out = Type::OFF_SCREEN; } else { @@ -306,6 +309,8 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options) type_ = WEB_VIEW; else if (options.Get("isBackgroundPage", &b) && b) type_ = BACKGROUND_PAGE; + else if (options.Get("isBrowserView", &b) && b) + type_ = BROWSER_VIEW; else if (options.Get("offscreen", &b) && b) type_ = OFF_SCREEN; diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index c289503b43c9..1301ed15f7fa 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -53,10 +53,11 @@ class WebContents : public mate::TrackableObject, public: enum Type { BACKGROUND_PAGE, // A DevTools extension background page. - BROWSER_WINDOW, // Used by BrowserWindow. - REMOTE, // Thin wrap around an existing WebContents. - WEB_VIEW, // Used by . - OFF_SCREEN, // Used for offscreen rendering + BROWSER_WINDOW, // Used by BrowserWindow. + BROWSER_VIEW, // Used by BrowserView. + REMOTE, // Thin wrap around an existing WebContents. + WEB_VIEW, // Used by . + OFF_SCREEN, // Used for offscreen rendering }; // For node.js callback function type: function(error, buffer) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 9a4ae5850dc1..c6707624913d 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -5,6 +5,7 @@ #include "atom/browser/api/atom_api_window.h" #include "atom/common/native_mate_converters/value_converter.h" +#include "atom/browser/api/atom_api_browser_view.h" #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/browser.h" @@ -816,6 +817,25 @@ std::vector> Window::GetChildWindows() const { return child_windows_.Values(isolate()); } +v8::Local Window::GetBrowserView() const { + if (browser_view_.IsEmpty()) { + return v8::Null(isolate()); + } + + return v8::Local::New(isolate(), browser_view_); +} + +void Window::SetBrowserView(v8::Local value) { + mate::Handle browser_view; + if (value->IsNull()) { + window_->SetBrowserView(nullptr); + browser_view_.Reset(); + } else if (mate::ConvertFromV8(isolate(), value, &browser_view)) { + window_->SetBrowserView(browser_view->view()); + browser_view_.Reset(isolate(), value); + } +} + bool Window::IsModal() const { return window_->is_modal(); } @@ -862,10 +882,11 @@ int32_t Window::ID() const { } v8::Local Window::WebContents(v8::Isolate* isolate) { - if (web_contents_.IsEmpty()) + if (web_contents_.IsEmpty()) { return v8::Null(isolate); - else - return v8::Local::New(isolate, web_contents_); + } + + return v8::Local::New(isolate, web_contents_); } void Window::RemoveFromParentChildWindows() { @@ -910,6 +931,8 @@ void Window::BuildPrototype(v8::Isolate* isolate, #endif .SetMethod("getParentWindow", &Window::GetParentWindow) .SetMethod("getChildWindows", &Window::GetChildWindows) + .SetMethod("getBrowserView", &Window::GetBrowserView) + .SetMethod("setBrowserView", &Window::SetBrowserView) .SetMethod("isModal", &Window::IsModal) .SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle) .SetMethod("getBounds", &Window::GetBounds) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 24afec354df5..d464af58ea9d 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -180,6 +180,8 @@ class Window : public mate::TrackableObject, void SetParentWindow(v8::Local value, mate::Arguments* args); v8::Local GetParentWindow() const; std::vector> GetChildWindows() const; + v8::Local GetBrowserView() const; + void SetBrowserView(v8::Local value); bool IsModal() const; v8::Local GetNativeWindowHandle(); @@ -220,6 +222,7 @@ class Window : public mate::TrackableObject, MessageCallbackMap messages_callback_map_; #endif + v8::Global browser_view_; v8::Global web_contents_; v8::Global menu_; v8::Global parent_window_; diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index f7f9e46250eb..a10f959dce90 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -178,9 +178,14 @@ void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) { void CommonWebContentsDelegate::SetOwnerWindow( content::WebContents* web_contents, NativeWindow* owner_window) { - owner_window_ = owner_window->GetWeakPtr(); + owner_window_ = owner_window ? owner_window->GetWeakPtr() : nullptr; NativeWindowRelay* relay = new NativeWindowRelay(owner_window_); - web_contents->SetUserData(relay->key, relay); + if (owner_window) { + web_contents->SetUserData(relay->key, relay); + } else { + web_contents->RemoveUserData(relay->key); + delete relay; + } } void CommonWebContentsDelegate::ResetManagedWebContents() { diff --git a/atom/browser/native_browser_view.cc b/atom/browser/native_browser_view.cc new file mode 100644 index 000000000000..949e5e9ec96d --- /dev/null +++ b/atom/browser/native_browser_view.cc @@ -0,0 +1,18 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/native_browser_view.h" + +#include "atom/browser/api/atom_api_web_contents.h" +#include "brightray/browser/inspectable_web_contents_view.h" + +namespace atom { + +NativeBrowserView::NativeBrowserView( + brightray::InspectableWebContentsView* web_contents_view) + : web_contents_view_(web_contents_view) {} + +NativeBrowserView::~NativeBrowserView() {} + +} // namespace atom diff --git a/atom/browser/native_browser_view.h b/atom/browser/native_browser_view.h new file mode 100644 index 000000000000..f9af80f65edd --- /dev/null +++ b/atom/browser/native_browser_view.h @@ -0,0 +1,51 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_ +#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_ + +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace brightray { +class InspectableWebContentsView; +} + +namespace gfx { +class Rect; +} + +namespace atom { + +namespace api { +class WebContents; +} + +class NativeBrowserView { + public: + virtual ~NativeBrowserView(); + + static NativeBrowserView* Create( + brightray::InspectableWebContentsView* web_contents_view); + + brightray::InspectableWebContentsView* GetInspectableWebContentsView() { + return web_contents_view_; + } + + virtual void SetBounds(const gfx::Rect& bounds) = 0; + virtual void SetBackgroundColor(SkColor color) = 0; + + protected: + explicit NativeBrowserView( + brightray::InspectableWebContentsView* web_contents_view); + + brightray::InspectableWebContentsView* web_contents_view_; + + private: + DISALLOW_COPY_AND_ASSIGN(NativeBrowserView); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_ diff --git a/atom/browser/native_browser_view_mac.h b/atom/browser/native_browser_view_mac.h new file mode 100644 index 000000000000..3053a098fca2 --- /dev/null +++ b/atom/browser/native_browser_view_mac.h @@ -0,0 +1,29 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_ +#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_ + +#import + +#include "atom/browser/native_browser_view.h" + +namespace atom { + +class NativeBrowserViewMac : public NativeBrowserView { + public: + explicit NativeBrowserViewMac( + brightray::InspectableWebContentsView* web_contents_view); + ~NativeBrowserViewMac() override; + + void SetBounds(const gfx::Rect& bounds) override; + void SetBackgroundColor(SkColor color) override; + + private: + DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewMac); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_ diff --git a/atom/browser/native_browser_view_mac.mm b/atom/browser/native_browser_view_mac.mm new file mode 100644 index 000000000000..73a36cd347e0 --- /dev/null +++ b/atom/browser/native_browser_view_mac.mm @@ -0,0 +1,40 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/native_browser_view_mac.h" + +#include "brightray/browser/inspectable_web_contents_view.h" +#include "skia/ext/skia_utils_mac.h" +#include "ui/gfx/geometry/rect.h" + +namespace atom { + +NativeBrowserViewMac::NativeBrowserViewMac( + brightray::InspectableWebContentsView* web_contents_view) + : NativeBrowserView(web_contents_view) {} + +NativeBrowserViewMac::~NativeBrowserViewMac() {} + +void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) { + auto* view = GetInspectableWebContentsView()->GetNativeView(); + auto* superview = view.superview; + const auto superview_height = superview ? superview.frame.size.height : 0; + view.frame = + NSMakeRect(bounds.x(), superview_height - bounds.y() - bounds.height(), + bounds.width(), bounds.height()); +} + +void NativeBrowserViewMac::SetBackgroundColor(SkColor color) { + auto* view = GetInspectableWebContentsView()->GetNativeView(); + view.wantsLayer = YES; + view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color); +} + +// static +NativeBrowserView* NativeBrowserView::Create( + brightray::InspectableWebContentsView* web_contents_view) { + return new NativeBrowserViewMac(web_contents_view); +} + +} // namespace atom diff --git a/atom/browser/native_browser_view_views.cc b/atom/browser/native_browser_view_views.cc new file mode 100644 index 000000000000..08a8123bcaef --- /dev/null +++ b/atom/browser/native_browser_view_views.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/native_browser_view_views.h" + +#include "brightray/browser/inspectable_web_contents_view.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/background.h" +#include "ui/views/view.h" + +namespace atom { + +NativeBrowserViewViews::NativeBrowserViewViews( + brightray::InspectableWebContentsView* web_contents_view) + : NativeBrowserView(web_contents_view) {} + +NativeBrowserViewViews::~NativeBrowserViewViews() {} + +void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) { + auto* view = GetInspectableWebContentsView()->GetView(); + view->SetBoundsRect(bounds); +} + +void NativeBrowserViewViews::SetBackgroundColor(SkColor color) { + auto* view = GetInspectableWebContentsView()->GetView(); + view->set_background(views::Background::CreateSolidBackground(color)); +} + +// static +NativeBrowserView* NativeBrowserView::Create( + brightray::InspectableWebContentsView* web_contents_view) { + return new NativeBrowserViewViews(web_contents_view); +} + +} // namespace atom diff --git a/atom/browser/native_browser_view_views.h b/atom/browser/native_browser_view_views.h new file mode 100644 index 000000000000..ecfc6989df82 --- /dev/null +++ b/atom/browser/native_browser_view_views.h @@ -0,0 +1,27 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_ +#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_ + +#include "atom/browser/native_browser_view.h" + +namespace atom { + +class NativeBrowserViewViews : public NativeBrowserView { + public: + explicit NativeBrowserViewViews( + brightray::InspectableWebContentsView* web_contents_view); + ~NativeBrowserViewViews() override; + + void SetBounds(const gfx::Rect& bounds) override; + void SetBackgroundColor(SkColor color) override; + + private: + DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_ diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 227e28c1e46d..56702daef63b 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -47,6 +47,8 @@ class Dictionary; namespace atom { +class NativeBrowserView; + struct DraggableRegion; class NativeWindow : public base::SupportsUserData, @@ -144,6 +146,7 @@ class NativeWindow : public base::SupportsUserData, virtual void SetFocusable(bool focusable); virtual void SetMenu(AtomMenuModel* menu); virtual void SetParentWindow(NativeWindow* parent); + virtual void SetBrowserView(NativeBrowserView* browser_view) = 0; virtual gfx::NativeWindow GetNativeWindow() = 0; virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index a535cdb4bef1..af0f157ecaef 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -87,6 +87,7 @@ class NativeWindowMac : public NativeWindow, bool IsDocumentEdited() override; void SetIgnoreMouseEvents(bool ignore) override; void SetContentProtection(bool enable) override; + void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; gfx::NativeWindow GetNativeWindow() override; gfx::AcceleratedWidget GetAcceleratedWidget() override; @@ -164,6 +165,8 @@ class NativeWindowMac : public NativeWindow, // The view that will fill the whole frameless window. base::scoped_nsobject content_view_; + NativeBrowserView* browser_view_; + std::vector draggable_regions_; bool is_kiosk_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index c3ca24a3d418..b695f8eafa89 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/native_browser_view_mac.h" #include "atom/browser/ui/cocoa/atom_touch_bar.h" #include "atom/browser/window_list.h" #include "atom/common/color_util.h" @@ -19,9 +20,9 @@ #include "brightray/browser/inspectable_web_contents_view.h" #include "brightray/browser/mac/event_dispatching_window.h" #include "content/public/browser/browser_accessibility_state.h" -#include "content/public/browser/web_contents.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" #include "native_mate/dictionary.h" #include "skia/ext/skia_utils_mac.h" #include "third_party/skia/include/core/SkRegion.h" @@ -671,6 +672,7 @@ NativeWindowMac::NativeWindowMac( const mate::Dictionary& options, NativeWindow* parent) : NativeWindow(web_contents, options, parent), + browser_view_(nullptr), is_kiosk_(false), was_fullscreen_(false), zoom_to_page_width_(false), @@ -1269,6 +1271,26 @@ void NativeWindowMac::SetContentProtection(bool enable) { : NSWindowSharingReadOnly]; } +void NativeWindowMac::SetBrowserView(NativeBrowserView* browser_view) { + if (browser_view_) { + [browser_view_->GetInspectableWebContentsView()->GetNativeView() + removeFromSuperview]; + browser_view_ = nullptr; + } + + if (!browser_view) { + return; + } + + browser_view_ = browser_view; + auto* native_view = + browser_view->GetInspectableWebContentsView()->GetNativeView(); + [[window_ contentView] addSubview:native_view + positioned:NSWindowAbove + relativeTo:nil]; + native_view.hidden = NO; +} + void NativeWindowMac::SetParentWindow(NativeWindow* parent) { if (is_modal()) return; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index b0722cbc4afd..68e210a62568 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/native_browser_view.h" #include "atom/browser/ui/views/menu_bar.h" #include "atom/browser/ui/views/menu_layout.h" #include "atom/browser/window_list.h" @@ -135,6 +136,7 @@ NativeWindowViews::NativeWindowViews( : NativeWindow(web_contents, options, parent), window_(new views::Widget), web_view_(inspectable_web_contents()->GetView()->GetView()), + browser_view_(nullptr), menu_bar_autohide_(false), menu_bar_visible_(false), menu_bar_alt_pressed_(false), @@ -881,6 +883,20 @@ void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) { Layout(); } +void NativeWindowViews::SetBrowserView(NativeBrowserView* browser_view) { + if (browser_view_) { + RemoveChildView(browser_view_->GetInspectableWebContentsView()->GetView()); + browser_view_ = nullptr; + } + + if (!browser_view) { + return; + } + + browser_view_ = browser_view; + AddChildView(browser_view->GetInspectableWebContentsView()->GetView()); +} + void NativeWindowViews::SetParentWindow(NativeWindow* parent) { NativeWindow::SetParentWindow(parent); diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index a7f02fb2727d..cf605a0231ba 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -104,6 +104,7 @@ class NativeWindowViews : public NativeWindow, void SetContentProtection(bool enable) override; void SetFocusable(bool focusable) override; void SetMenu(AtomMenuModel* menu_model) override; + void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; gfx::NativeWindow GetNativeWindow() override; void SetOverlayIcon(const gfx::Image& overlay, @@ -189,6 +190,8 @@ class NativeWindowViews : public NativeWindow, std::unique_ptr window_; views::View* web_view_; // Managed by inspectable_web_contents_. + NativeBrowserView* browser_view_; + std::unique_ptr menu_bar_; bool menu_bar_autohide_; bool menu_bar_visible_; diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index f4696773dad6..ae757b1da883 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -33,17 +33,18 @@ // Electron's builtin modules. REFERENCE_MODULE(atom_browser_app); REFERENCE_MODULE(atom_browser_auto_updater); +REFERENCE_MODULE(atom_browser_browser_view); REFERENCE_MODULE(atom_browser_content_tracing); -REFERENCE_MODULE(atom_browser_dialog); REFERENCE_MODULE(atom_browser_debugger); REFERENCE_MODULE(atom_browser_desktop_capturer); +REFERENCE_MODULE(atom_browser_dialog); REFERENCE_MODULE(atom_browser_download_item); +REFERENCE_MODULE(atom_browser_global_shortcut); REFERENCE_MODULE(atom_browser_menu); REFERENCE_MODULE(atom_browser_net); REFERENCE_MODULE(atom_browser_power_monitor); REFERENCE_MODULE(atom_browser_power_save_blocker); REFERENCE_MODULE(atom_browser_protocol); -REFERENCE_MODULE(atom_browser_global_shortcut); REFERENCE_MODULE(atom_browser_render_process_preferences); REFERENCE_MODULE(atom_browser_session); REFERENCE_MODULE(atom_browser_system_preferences); diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md new file mode 100644 index 000000000000..1fa518fdd777 --- /dev/null +++ b/docs/api/browser-view.md @@ -0,0 +1,62 @@ +## Class: BrowserView + +> Create and control views. + +**Note:** The BrowserView API is currently experimental and may change or be +removed in future Electron releases. + +Process: [Main](../glossary.md#main-process) + +A `BrowserView` can be used to embed additional web content into a +`BrowserWindow`. It is like a child window, except that it is positioned +relative to its owning window. It is meant to be an alternative to the +`webview` tag. + +## Example + +```javascript +// In the main process. +const {BrowserView, BrowserWindow} = require('electron') + +let win = new BrowserWindow({width: 800, height: 600}) +win.on('closed', () => { + win = null +}) + +let view = new BrowserView() +win.addChildView(view) +view.setBounds(0, 0, 300, 300) +view.webContents.loadURL('https://electron.atom.io') +``` + +### `new BrowserView([options])` _Experimental_ + +* `options` Object (optional) + * `webPreferences` Object (optional) - See [BrowserWindow](browser-window.md). + +### Instance Properties + +Objects created with `new BrowserView` have the following properties: + +#### `view.webContents` _Experimental_ + +A [`webContents`](web-contents.md) object owned by this view. + +#### `win.id` _Experimental_ + +A `Integer` representing the unique ID of the view. + +### Instance Methods + +Objects created with `new BrowserWindow` have the following instance methods: + +#### `win.setBounds(bounds)` _Experimental_ + +* `bounds` [Rectangle](structures/rectangle.md) + +Resizes and moves the view to the supplied bounds relative to the window. + +#### `win.setBackgroundColor(color)` _Experimental_ + +* `color` String - Color in `#aarrggbb` or `#argb` form. The alpha channel is + optional. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index ee46a3fa03ec..2c720fdfac11 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -1289,6 +1289,13 @@ machine has a touch bar and is running on macOS 10.12.1+. **Note:** The TouchBar API is currently experimental and may change or be removed in future Electron releases. +#### `win.setBrowserView(browserView)` _Experimental_ + +* `browserView` [BrowserView](browser-view.md) + +**Note:** The BrowserView API is currently experimental and may change or be +removed in future Electron releases. + [blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5?l=62 [quick-look]: https://en.wikipedia.org/wiki/Quick_Look [vibrancy-docs]: https://developer.apple.com/reference/appkit/nsvisualeffectview?language=objc diff --git a/filenames.gypi b/filenames.gypi index ec9c68241c25..f9fa4227ea1d 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -13,23 +13,24 @@ 'lib/browser/api/auto-updater/auto-updater-native.js', 'lib/browser/api/auto-updater/auto-updater-win.js', 'lib/browser/api/auto-updater/squirrel-update-win.js', + 'lib/browser/api/browser-view.js', 'lib/browser/api/browser-window.js', 'lib/browser/api/content-tracing.js', 'lib/browser/api/dialog.js', 'lib/browser/api/exports/electron.js', 'lib/browser/api/global-shortcut.js', 'lib/browser/api/ipc-main.js', - 'lib/browser/api/menu.js', - 'lib/browser/api/menu-item.js', 'lib/browser/api/menu-item-roles.js', + 'lib/browser/api/menu-item.js', + 'lib/browser/api/menu.js', 'lib/browser/api/module-list.js', 'lib/browser/api/navigation-controller.js', 'lib/browser/api/net.js', 'lib/browser/api/power-monitor.js', 'lib/browser/api/power-save-blocker.js', 'lib/browser/api/protocol.js', - 'lib/browser/api/session.js', 'lib/browser/api/screen.js', + 'lib/browser/api/session.js', 'lib/browser/api/system-preferences.js', 'lib/browser/api/touch-bar.js', 'lib/browser/api/tray.js', @@ -103,6 +104,8 @@ 'atom/browser/api/atom_api_app.h', 'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.h', + 'atom/browser/api/atom_api_browser_view.cc', + 'atom/browser/api/atom_api_browser_view.h', 'atom/browser/api/atom_api_content_tracing.cc', 'atom/browser/api/atom_api_cookies.cc', 'atom/browser/api/atom_api_cookies.h', @@ -110,27 +113,27 @@ 'atom/browser/api/atom_api_debugger.h', 'atom/browser/api/atom_api_desktop_capturer.cc', 'atom/browser/api/atom_api_desktop_capturer.h', + 'atom/browser/api/atom_api_dialog.cc', 'atom/browser/api/atom_api_download_item.cc', 'atom/browser/api/atom_api_download_item.h', - 'atom/browser/api/atom_api_dialog.cc', 'atom/browser/api/atom_api_global_shortcut.cc', 'atom/browser/api/atom_api_global_shortcut.h', 'atom/browser/api/atom_api_menu.cc', 'atom/browser/api/atom_api_menu.h', - 'atom/browser/api/atom_api_menu_views.cc', - 'atom/browser/api/atom_api_menu_views.h', 'atom/browser/api/atom_api_menu_mac.h', 'atom/browser/api/atom_api_menu_mac.mm', + 'atom/browser/api/atom_api_menu_views.cc', + 'atom/browser/api/atom_api_menu_views.h', 'atom/browser/api/atom_api_net.cc', 'atom/browser/api/atom_api_net.h', 'atom/browser/api/atom_api_power_monitor.cc', 'atom/browser/api/atom_api_power_monitor.h', 'atom/browser/api/atom_api_power_save_blocker.cc', 'atom/browser/api/atom_api_power_save_blocker.h', - 'atom/browser/api/atom_api_render_process_preferences.cc', - 'atom/browser/api/atom_api_render_process_preferences.h', 'atom/browser/api/atom_api_protocol.cc', 'atom/browser/api/atom_api_protocol.h', + 'atom/browser/api/atom_api_render_process_preferences.cc', + 'atom/browser/api/atom_api_render_process_preferences.h', 'atom/browser/api/atom_api_screen.cc', 'atom/browser/api/atom_api_screen.h', 'atom/browser/api/atom_api_session.cc', @@ -216,6 +219,12 @@ 'atom/browser/mac/atom_application_delegate.mm', 'atom/browser/mac/dict_util.h', 'atom/browser/mac/dict_util.mm', + 'atom/browser/native_browser_view.cc', + 'atom/browser/native_browser_view.h', + 'atom/browser/native_browser_view_mac.h', + 'atom/browser/native_browser_view_mac.mm', + 'atom/browser/native_browser_view_views.h', + 'atom/browser/native_browser_view_views.cc', 'atom/browser/native_window.cc', 'atom/browser/native_window.h', 'atom/browser/native_window_views_win.cc', diff --git a/lib/browser/api/browser-view.js b/lib/browser/api/browser-view.js new file mode 100644 index 000000000000..60023fef92bb --- /dev/null +++ b/lib/browser/api/browser-view.js @@ -0,0 +1,8 @@ +'use strict' + +const {EventEmitter} = require('events') +const {BrowserView} = process.atomBinding('browser_view') + +Object.setPrototypeOf(BrowserView.prototype, EventEmitter.prototype) + +module.exports = BrowserView diff --git a/lib/browser/api/module-list.js b/lib/browser/api/module-list.js index 3274f0b6d4fb..64b2829064b6 100644 --- a/lib/browser/api/module-list.js +++ b/lib/browser/api/module-list.js @@ -2,6 +2,7 @@ module.exports = [ {name: 'app', file: 'app'}, {name: 'autoUpdater', file: 'auto-updater'}, + {name: 'BrowserView', file: 'browser-view'}, {name: 'BrowserWindow', file: 'browser-window'}, {name: 'contentTracing', file: 'content-tracing'}, {name: 'dialog', file: 'dialog'}, diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js new file mode 100644 index 000000000000..d4ab02a41786 --- /dev/null +++ b/spec/api-browser-view-spec.js @@ -0,0 +1,71 @@ +'use strict' + +const assert = require('assert') +const {closeWindow} = require('./window-helpers') + +const {remote} = require('electron') +const {BrowserView, BrowserWindow} = remote + +describe('View module', function () { + var w = null + + beforeEach(function () { + w = new BrowserWindow({ + show: false, + width: 400, + height: 400, + webPreferences: { + backgroundThrottling: false + } + }) + }) + + afterEach(function () { + return closeWindow(w).then(function () { w = null }) + }) + + describe('BrowserView.setBackgroundColor()', function () { + it('does not throw for valid args', function () { + const view = new BrowserView() + view.setBackgroundColor('#000') + }) + + it('throws for invalid args', function () { + const view = new BrowserView() + assert.throws(function () { + view.setBackgroundColor(null) + }, /conversion failure/) + }) + }) + + describe('BrowserView.setBounds()', function () { + it('does not throw for valid args', function () { + const view = new BrowserView() + view.setBounds({ x: 0, y: 0, width: 1, height: 1 }) + }) + + it('throws for invalid args', function () { + const view = new BrowserView() + assert.throws(function () { + view.setBounds(null) + }, /conversion failure/) + assert.throws(function () { + view.setBounds({}) + }, /conversion failure/) + }) + }) + + describe('BrowserWindow.setBrowserView()', function () { + it('does not throw for valid args', function () { + const view = new BrowserView() + w.setBrowserView(view) + }) + + it('does not throw if called multiple times with same view', function () { + const view = new BrowserView() + w.setBrowserView(view) + w.setBrowserView(view) + w.setBrowserView(view) + }) + }) +}) From 638eae10807f41013b4efbf58f1706786ea7000c Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Wed, 12 Apr 2017 14:00:00 +0300 Subject: [PATCH 238/337] Remove MenuLayout in favor of NativeWindowViews::Layout --- atom/browser/native_window_views.cc | 43 +++++++++++-- atom/browser/native_window_views.h | 1 + atom/browser/ui/views/menu_layout.cc | 91 ---------------------------- atom/browser/ui/views/menu_layout.h | 36 ----------- filenames.gypi | 2 - 5 files changed, 40 insertions(+), 133 deletions(-) delete mode 100644 atom/browser/ui/views/menu_layout.cc delete mode 100644 atom/browser/ui/views/menu_layout.h diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 68e210a62568..8f5072931b1a 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -9,7 +9,6 @@ #include "atom/browser/native_browser_view.h" #include "atom/browser/ui/views/menu_bar.h" -#include "atom/browser/ui/views/menu_layout.h" #include "atom/browser/window_list.h" #include "atom/common/color_util.h" #include "atom/common/draggable_region.h" @@ -71,6 +70,20 @@ const int kMenuBarHeight = 25; #endif #if defined(OS_WIN) +gfx::Rect SubtractBorderSize(gfx::Rect bounds) { + gfx::Point borderSize = gfx::Point( + GetSystemMetrics(SM_CXSIZEFRAME) - 1, // width + GetSystemMetrics(SM_CYSIZEFRAME) - 1); // height + gfx::Point dpiAdjustedSize = + display::win::ScreenWin::ScreenToDIPPoint(borderSize); + + bounds.set_x(bounds.x() + dpiAdjustedSize.x()); + bounds.set_y(bounds.y() + dpiAdjustedSize.y()); + bounds.set_width(bounds.width() - 2 * dpiAdjustedSize.x()); + bounds.set_height(bounds.height() - 2 * dpiAdjustedSize.y()); + return bounds; +} + void FlipWindowStyle(HWND handle, bool on, DWORD flag) { DWORD style = ::GetWindowLong(handle, GWL_STYLE); if (on) @@ -276,9 +289,6 @@ NativeWindowViews::NativeWindowViews( SetWindowType(GetAcceleratedWidget(), window_type); #endif - // Add web view. - SetLayoutManager(new MenuLayout(this, kMenuBarHeight)); - AddChildView(web_view_); #if defined(OS_WIN) @@ -1264,6 +1274,31 @@ void NativeWindowViews::HandleKeyboardEvent( } } +void NativeWindowViews::Layout() { +#if defined(OS_WIN) + // Reserve border space for maximized frameless window so we won't have the + // content go outside of screen. + if (!has_frame() && IsMaximized()) { + gfx::Rect bounds = SubtractBorderSize(GetContentsBounds()); + web_view_->SetBoundsRect(bounds); + return; + } +#endif + + const auto size = GetContentsBounds().size(); + const auto menu_bar_bounds = + menu_bar_ ? gfx::Rect(0, 0, size.width(), kMenuBarHeight) : gfx::Rect(); + if (menu_bar_) { + menu_bar_->SetBoundsRect(menu_bar_bounds); + } + + if (web_view_) { + web_view_->SetBoundsRect( + gfx::Rect(0, menu_bar_bounds.height(), size.width(), + size.height() - menu_bar_bounds.height())); + } +} + gfx::Size NativeWindowViews::GetMinimumSize() { return NativeWindow::GetMinimumSize(); } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index cf605a0231ba..276cd4adde2d 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -177,6 +177,7 @@ class NativeWindowViews : public NativeWindow, const content::NativeWebKeyboardEvent& event) override; // views::View: + void Layout() override; gfx::Size GetMinimumSize() override; gfx::Size GetMaximumSize() override; bool AcceleratorPressed(const ui::Accelerator& accelerator) override; diff --git a/atom/browser/ui/views/menu_layout.cc b/atom/browser/ui/views/menu_layout.cc deleted file mode 100644 index d70a4655a121..000000000000 --- a/atom/browser/ui/views/menu_layout.cc +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/menu_layout.h" - -#if defined(OS_WIN) -#include "atom/browser/native_window_views.h" -#include "ui/display/win/screen_win.h" -#endif - -namespace atom { - -namespace { - -#if defined(OS_WIN) -gfx::Rect SubtractBorderSize(gfx::Rect bounds) { - gfx::Point borderSize = gfx::Point( - GetSystemMetrics(SM_CXSIZEFRAME) - 1, // width - GetSystemMetrics(SM_CYSIZEFRAME) - 1); // height - gfx::Point dpiAdjustedSize = - display::win::ScreenWin::ScreenToDIPPoint(borderSize); - - bounds.set_x(bounds.x() + dpiAdjustedSize.x()); - bounds.set_y(bounds.y() + dpiAdjustedSize.y()); - bounds.set_width(bounds.width() - 2 * dpiAdjustedSize.x()); - bounds.set_height(bounds.height() - 2 * dpiAdjustedSize.y()); - return bounds; -} -#endif - -} // namespace - -MenuLayout::MenuLayout(NativeWindowViews* window, int menu_height) - : window_(window), - menu_height_(menu_height) { -} - -MenuLayout::~MenuLayout() { -} - -void MenuLayout::Layout(views::View* host) { -#if defined(OS_WIN) - // Reserve border space for maximized frameless window so we won't have the - // content go outside of screen. - if (!window_->has_frame() && window_->IsMaximized()) { - gfx::Rect bounds = SubtractBorderSize(host->GetContentsBounds()); - host->child_at(0)->SetBoundsRect(bounds); - return; - } -#endif - - if (!HasMenu(host)) { - views::FillLayout::Layout(host); - return; - } - - gfx::Size size = host->GetContentsBounds().size(); - gfx::Rect menu_Bar_bounds = gfx::Rect(0, 0, size.width(), menu_height_); - gfx::Rect web_view_bounds = gfx::Rect( - 0, menu_height_, size.width(), size.height() - menu_height_); - - views::View* web_view = host->child_at(0); - views::View* menu_bar = host->child_at(1); - web_view->SetBoundsRect(web_view_bounds); - menu_bar->SetBoundsRect(menu_Bar_bounds); -} - -gfx::Size MenuLayout::GetPreferredSize(const views::View* host) const { - gfx::Size size = views::FillLayout::GetPreferredSize(host); - if (!HasMenu(host)) - return size; - - size.set_height(size.height() + menu_height_); - return size; -} - -int MenuLayout::GetPreferredHeightForWidth( - const views::View* host, int width) const { - int height = views::FillLayout::GetPreferredHeightForWidth(host, width); - if (!HasMenu(host)) - return height; - - return height + menu_height_; -} - -bool MenuLayout::HasMenu(const views::View* host) const { - return host->child_count() == 2; -} - -} // namespace atom diff --git a/atom/browser/ui/views/menu_layout.h b/atom/browser/ui/views/menu_layout.h deleted file mode 100644 index 0a8464a1d44a..000000000000 --- a/atom/browser/ui/views/menu_layout.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_ -#define ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_ - -#include "ui/views/layout/fill_layout.h" - -namespace atom { - -class NativeWindowViews; - -class MenuLayout : public views::FillLayout { - public: - MenuLayout(NativeWindowViews* window, int menu_height); - virtual ~MenuLayout(); - - // views::LayoutManager: - void Layout(views::View* host) override; - gfx::Size GetPreferredSize(const views::View* host) const override; - int GetPreferredHeightForWidth( - const views::View* host, int width) const override; - - private: - bool HasMenu(const views::View* host) const; - - NativeWindowViews* window_; - int menu_height_; - - DISALLOW_COPY_AND_ASSIGN(MenuLayout); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_ diff --git a/filenames.gypi b/filenames.gypi index f9fa4227ea1d..8f14b298837b 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -322,8 +322,6 @@ 'atom/browser/ui/views/menu_bar.h', 'atom/browser/ui/views/menu_delegate.cc', 'atom/browser/ui/views/menu_delegate.h', - 'atom/browser/ui/views/menu_layout.cc', - 'atom/browser/ui/views/menu_layout.h', 'atom/browser/ui/views/menu_model_adapter.cc', 'atom/browser/ui/views/menu_model_adapter.h', 'atom/browser/ui/views/native_frame_view.cc', From 06fcf2c19df127078320656dcb2a0a4500f61b8a Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Wed, 12 Apr 2017 14:40:31 +0300 Subject: [PATCH 239/337] Add support for BrowserView autoresizing --- atom/browser/api/atom_api_browser_view.cc | 34 +++++++++++++++++++++++ atom/browser/api/atom_api_browser_view.h | 2 ++ atom/browser/native_browser_view.h | 6 ++++ atom/browser/native_browser_view_mac.h | 1 + atom/browser/native_browser_view_mac.mm | 22 ++++++++++++++- atom/browser/native_browser_view_views.h | 6 ++++ atom/browser/native_window_views.cc | 31 +++++++++++++++++++-- docs/api/browser-view.md | 8 ++++++ spec/api-browser-view-spec.js | 15 ++++++++++ 9 files changed, 121 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_browser_view.cc b/atom/browser/api/atom_api_browser_view.cc index 67533e645d39..dc17fce9e9a3 100644 --- a/atom/browser/api/atom_api_browser_view.cc +++ b/atom/browser/api/atom_api_browser_view.cc @@ -16,6 +16,35 @@ #include "native_mate/dictionary.h" #include "ui/gfx/geometry/rect.h" +namespace mate { + +template <> +struct Converter { + static bool FromV8(v8::Isolate* isolate, + v8::Local val, + atom::AutoResizeFlags* auto_resize_flags) { + mate::Dictionary params; + if (!ConvertFromV8(isolate, val, ¶ms)) { + return false; + } + + uint8_t flags = 0; + bool width = false; + if (params.Get("width", &width) && width) { + flags |= atom::kAutoResizeWidth; + } + bool height = false; + if (params.Get("height", &height) && height) { + flags |= atom::kAutoResizeHeight; + } + + *auto_resize_flags = static_cast(flags); + return true; + } +}; + +} // namespace mate + namespace atom { namespace api { @@ -73,6 +102,10 @@ int32_t BrowserView::ID() const { return weak_map_id(); } +void BrowserView::SetAutoResize(AutoResizeFlags flags) { + view_->SetAutoResizeFlags(flags); +} + void BrowserView::SetBounds(const gfx::Rect& bounds) { view_->SetBounds(bounds); } @@ -95,6 +128,7 @@ void BrowserView::BuildPrototype(v8::Isolate* isolate, prototype->SetClassName(mate::StringToV8(isolate, "BrowserView")); mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) .MakeDestroyable() + .SetMethod("setAutoResize", &BrowserView::SetAutoResize) .SetMethod("setBounds", &BrowserView::SetBounds) .SetMethod("setBackgroundColor", &BrowserView::SetBackgroundColor) .SetProperty("webContents", &BrowserView::WebContents) diff --git a/atom/browser/api/atom_api_browser_view.h b/atom/browser/api/atom_api_browser_view.h index 875d84289825..7531cfcc4a1b 100644 --- a/atom/browser/api/atom_api_browser_view.h +++ b/atom/browser/api/atom_api_browser_view.h @@ -9,6 +9,7 @@ #include #include "atom/browser/api/trackable_object.h" +#include "atom/browser/native_browser_view.h" #include "native_mate/handle.h" namespace gfx { @@ -50,6 +51,7 @@ class BrowserView : public mate::TrackableObject { v8::Local wrapper, const mate::Dictionary& options); + void SetAutoResize(AutoResizeFlags flags); void SetBounds(const gfx::Rect& bounds); void SetBackgroundColor(const std::string& color_name); diff --git a/atom/browser/native_browser_view.h b/atom/browser/native_browser_view.h index f9af80f65edd..4216cc1e3439 100644 --- a/atom/browser/native_browser_view.h +++ b/atom/browser/native_browser_view.h @@ -22,6 +22,11 @@ namespace api { class WebContents; } +enum AutoResizeFlags { + kAutoResizeWidth = 0x1, + kAutoResizeHeight = 0x2, +}; + class NativeBrowserView { public: virtual ~NativeBrowserView(); @@ -33,6 +38,7 @@ class NativeBrowserView { return web_contents_view_; } + virtual void SetAutoResizeFlags(uint8_t flags) = 0; virtual void SetBounds(const gfx::Rect& bounds) = 0; virtual void SetBackgroundColor(SkColor color) = 0; diff --git a/atom/browser/native_browser_view_mac.h b/atom/browser/native_browser_view_mac.h index 3053a098fca2..4e7aa429ce27 100644 --- a/atom/browser/native_browser_view_mac.h +++ b/atom/browser/native_browser_view_mac.h @@ -17,6 +17,7 @@ class NativeBrowserViewMac : public NativeBrowserView { brightray::InspectableWebContentsView* web_contents_view); ~NativeBrowserViewMac() override; + void SetAutoResizeFlags(uint8_t flags) override; void SetBounds(const gfx::Rect& bounds) override; void SetBackgroundColor(SkColor color) override; diff --git a/atom/browser/native_browser_view_mac.mm b/atom/browser/native_browser_view_mac.mm index 73a36cd347e0..2ce2adc1f4fe 100644 --- a/atom/browser/native_browser_view_mac.mm +++ b/atom/browser/native_browser_view_mac.mm @@ -8,14 +8,34 @@ #include "skia/ext/skia_utils_mac.h" #include "ui/gfx/geometry/rect.h" +// Match view::Views behavior where the view sticks to the top-left origin. +const NSAutoresizingMaskOptions kDefaultAutoResizingMask = + NSViewMaxXMargin | NSViewMinYMargin; + namespace atom { NativeBrowserViewMac::NativeBrowserViewMac( brightray::InspectableWebContentsView* web_contents_view) - : NativeBrowserView(web_contents_view) {} + : NativeBrowserView(web_contents_view) { + auto* view = GetInspectableWebContentsView()->GetNativeView(); + view.autoresizingMask = kDefaultAutoResizingMask; +} NativeBrowserViewMac::~NativeBrowserViewMac() {} +void NativeBrowserViewMac::SetAutoResizeFlags(uint8_t flags) { + NSAutoresizingMaskOptions autoresizing_mask = kDefaultAutoResizingMask; + if (flags & kAutoResizeWidth) { + autoresizing_mask |= NSViewWidthSizable; + } + if (flags & kAutoResizeHeight) { + autoresizing_mask |= NSViewHeightSizable; + } + + auto* view = GetInspectableWebContentsView()->GetNativeView(); + view.autoresizingMask = autoresizing_mask; +} + void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) { auto* view = GetInspectableWebContentsView()->GetNativeView(); auto* superview = view.superview; diff --git a/atom/browser/native_browser_view_views.h b/atom/browser/native_browser_view_views.h index ecfc6989df82..5dcda13447cd 100644 --- a/atom/browser/native_browser_view_views.h +++ b/atom/browser/native_browser_view_views.h @@ -15,10 +15,16 @@ class NativeBrowserViewViews : public NativeBrowserView { brightray::InspectableWebContentsView* web_contents_view); ~NativeBrowserViewViews() override; + uint8_t GetAutoResizeFlags() { return auto_resize_flags_; } + void SetAutoResizeFlags(uint8_t flags) override { + auto_resize_flags_ = flags; + } void SetBounds(const gfx::Rect& bounds) override; void SetBackgroundColor(SkColor color) override; private: + uint8_t auto_resize_flags_; + DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews); }; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 8f5072931b1a..615c848daac8 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -7,7 +7,7 @@ #include #include -#include "atom/browser/native_browser_view.h" +#include "atom/browser/native_browser_view_views.h" #include "atom/browser/ui/views/menu_bar.h" #include "atom/browser/window_list.h" #include "atom/common/color_util.h" @@ -895,7 +895,8 @@ void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) { void NativeWindowViews::SetBrowserView(NativeBrowserView* browser_view) { if (browser_view_) { - RemoveChildView(browser_view_->GetInspectableWebContentsView()->GetView()); + web_view_->RemoveChildView( + browser_view_->GetInspectableWebContentsView()->GetView()); browser_view_ = nullptr; } @@ -903,8 +904,11 @@ void NativeWindowViews::SetBrowserView(NativeBrowserView* browser_view) { return; } + // Add as child of the main web view to avoid (0, 0) origin from overlapping + // with menu bar. browser_view_ = browser_view; - AddChildView(browser_view->GetInspectableWebContentsView()->GetView()); + web_view_->AddChildView( + browser_view->GetInspectableWebContentsView()->GetView()); } void NativeWindowViews::SetParentWindow(NativeWindow* parent) { @@ -1292,11 +1296,32 @@ void NativeWindowViews::Layout() { menu_bar_->SetBoundsRect(menu_bar_bounds); } + const auto old_web_view_size = web_view_ ? web_view_->size() : gfx::Size(); if (web_view_) { web_view_->SetBoundsRect( gfx::Rect(0, menu_bar_bounds.height(), size.width(), size.height() - menu_bar_bounds.height())); } + const auto new_web_view_size = web_view_ ? web_view_->size() : gfx::Size(); + + if (browser_view_) { + const auto flags = static_cast(browser_view_) + ->GetAutoResizeFlags(); + int width_delta = 0; + int height_delta = 0; + if (flags & kAutoResizeWidth) { + width_delta = new_web_view_size.width() - old_web_view_size.width(); + } + if (flags & kAutoResizeHeight) { + height_delta = new_web_view_size.height() - old_web_view_size.height(); + } + + auto* view = browser_view_->GetInspectableWebContentsView()->GetView(); + auto new_view_size = view->size(); + new_view_size.set_width(new_view_size.width() + width_delta); + new_view_size.set_height(new_view_size.height() + height_delta); + view->SetSize(new_view_size); + } } gfx::Size NativeWindowViews::GetMinimumSize() { diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md index 1fa518fdd777..c6d8fb590415 100644 --- a/docs/api/browser-view.md +++ b/docs/api/browser-view.md @@ -50,6 +50,14 @@ A `Integer` representing the unique ID of the view. Objects created with `new BrowserWindow` have the following instance methods: +#### `win.setAutoResize(options)` _Experimental_ + +* `options` Object + * `width`: If `true`, the view's width will grow and shrink together with + the window. `false` by default. + * `height`: If `true`, the view's height will grow and shrink together with + the window. `false` by default. + #### `win.setBounds(bounds)` _Experimental_ * `bounds` [Rectangle](structures/rectangle.md) diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js index d4ab02a41786..fc138b0b6f1a 100644 --- a/spec/api-browser-view-spec.js +++ b/spec/api-browser-view-spec.js @@ -38,6 +38,21 @@ describe('View module', function () { }) }) + describe('BrowserView.setAutoResize()', function () { + it('does not throw for valid args', function () { + const view = new BrowserView() + view.setAutoResize({}) + view.setAutoResize({ width: true, height: false }) + }) + + it('throws for invalid args', function () { + const view = new BrowserView() + assert.throws(function () { + view.setAutoResize(null) + }, /conversion failure/) + }) + }) + describe('BrowserView.setBounds()', function () { it('does not throw for valid args', function () { const view = new BrowserView() From ccdeb4746ec25555b11709b19742e1f1b7fe7cb8 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Thu, 13 Apr 2017 00:52:07 +0300 Subject: [PATCH 240/337] Destroy BrowserViews after each test --- spec/api-browser-view-spec.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js index fc138b0b6f1a..3ccb9502c237 100644 --- a/spec/api-browser-view-spec.js +++ b/spec/api-browser-view-spec.js @@ -8,6 +8,7 @@ const {BrowserView, BrowserWindow} = remote describe('View module', function () { var w = null + var view = null beforeEach(function () { w = new BrowserWindow({ @@ -21,17 +22,22 @@ describe('View module', function () { }) afterEach(function () { + if (view) { + view.destroy() + view = null + } + return closeWindow(w).then(function () { w = null }) }) describe('BrowserView.setBackgroundColor()', function () { it('does not throw for valid args', function () { - const view = new BrowserView() + view = new BrowserView() view.setBackgroundColor('#000') }) it('throws for invalid args', function () { - const view = new BrowserView() + view = new BrowserView() assert.throws(function () { view.setBackgroundColor(null) }, /conversion failure/) @@ -40,13 +46,13 @@ describe('View module', function () { describe('BrowserView.setAutoResize()', function () { it('does not throw for valid args', function () { - const view = new BrowserView() + view = new BrowserView() view.setAutoResize({}) view.setAutoResize({ width: true, height: false }) }) it('throws for invalid args', function () { - const view = new BrowserView() + view = new BrowserView() assert.throws(function () { view.setAutoResize(null) }, /conversion failure/) @@ -55,12 +61,12 @@ describe('View module', function () { describe('BrowserView.setBounds()', function () { it('does not throw for valid args', function () { - const view = new BrowserView() + view = new BrowserView() view.setBounds({ x: 0, y: 0, width: 1, height: 1 }) }) it('throws for invalid args', function () { - const view = new BrowserView() + view = new BrowserView() assert.throws(function () { view.setBounds(null) }, /conversion failure/) @@ -72,12 +78,12 @@ describe('View module', function () { describe('BrowserWindow.setBrowserView()', function () { it('does not throw for valid args', function () { - const view = new BrowserView() + view = new BrowserView() w.setBrowserView(view) }) it('does not throw if called multiple times with same view', function () { - const view = new BrowserView() + view = new BrowserView() w.setBrowserView(view) w.setBrowserView(view) w.setBrowserView(view) From 000aedf2e796788f5375b5a26752e7c645b1f2b9 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Thu, 13 Apr 2017 01:05:19 +0300 Subject: [PATCH 241/337] Avoid insecure nodeIntegration in example --- docs/api/browser-view.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md index c6d8fb590415..3b7e6f9b9bf3 100644 --- a/docs/api/browser-view.md +++ b/docs/api/browser-view.md @@ -23,7 +23,11 @@ win.on('closed', () => { win = null }) -let view = new BrowserView() +let view = new BrowserView({ + webPreferences: { + nodeIntegration: false + } +}) win.addChildView(view) view.setBounds(0, 0, 300, 300) view.webContents.loadURL('https://electron.atom.io') From 9d62b196d3676cfe43963ad7dab0917aa2992ad9 Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Thu, 13 Apr 2017 10:59:12 +0900 Subject: [PATCH 242/337] Use base::FilePath --- atom/browser/api/atom_api_app.cc | 4 ++-- atom/browser/api/atom_api_app.h | 6 +++--- atom/browser/atom_browser_client.cc | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index a53e957660ee..d8e79171f879 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -655,11 +655,11 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) { status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); } -std::string App::GetAppPath() { +base::FilePath App::GetAppPath() { return app_path_; } -void App::SetAppPath(const std::string& app_path) { +void App::SetAppPath(const base::FilePath& app_path) { app_path_ = app_path; } diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 4b09d7703105..78871f6920ec 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -70,7 +70,7 @@ class App : public AtomBrowserClient::Delegate, std::unique_ptr model); #endif - std::string GetAppPath(); + base::FilePath GetAppPath(); protected: explicit App(v8::Isolate* isolate); @@ -117,7 +117,7 @@ class App : public AtomBrowserClient::Delegate, void OnGpuProcessCrashed(base::TerminationStatus status) override; private: - void SetAppPath(const std::string& app_path); + void SetAppPath(const base::FilePath& app_path); // Get/Set the pre-defined path in PathService. base::FilePath GetPath(mate::Arguments* args, const std::string& name); @@ -158,7 +158,7 @@ class App : public AtomBrowserClient::Delegate, // Tracks tasks requesting file icons. base::CancelableTaskTracker cancelable_task_tracker_; - std::string app_path_; + base::FilePath app_path_; DISALLOW_COPY_AND_ASSIGN(App); }; diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 3908c9613a03..db33e2e38fd1 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -236,7 +236,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( if (delegate_) { auto app_path = static_cast(delegate_)->GetAppPath(); - command_line->AppendSwitchASCII(switches::kAppPath, app_path); + command_line->AppendSwitchPath(switches::kAppPath, app_path); } content::WebContents* web_contents = GetWebContentsFromProcessID(process_id); From ed20cc0af826b9b3c317b0a1182f8f7e64e569b8 Mon Sep 17 00:00:00 2001 From: ZhangYu Date: Thu, 13 Apr 2017 10:27:32 +0800 Subject: [PATCH 243/337] Update shell.md --- docs-translations/zh-CN/api/shell.md | 44 +++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/docs-translations/zh-CN/api/shell.md b/docs-translations/zh-CN/api/shell.md index 1f36046b1e17..22fa0d1cd1ff 100644 --- a/docs-translations/zh-CN/api/shell.md +++ b/docs-translations/zh-CN/api/shell.md @@ -1,4 +1,7 @@ # shell +> 使用系统默认应用管理文件和 URL . + +进程: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) `shell` 模块提供了集成其他桌面客户端的关联功能. @@ -11,7 +14,7 @@ const {shell} = require('electron') shell.openExternal('https://github.com') ``` -## Methods +## 方法 `shell` 模块包含以下函数: @@ -19,27 +22,60 @@ shell.openExternal('https://github.com') * `fullPath` String -打开文件所在文件夹,一般情况下还会选中它. +Returns `Boolean` - +是否成功打开文件所在文件夹,一般情况下还会选中它. ### `shell.openItem(fullPath)` * `fullPath` String -以默认打开方式打开文件. +Returns `Boolean` - 是否成功的以默认打开方式打开文件. + ### `shell.openExternal(url)` * `url` String +* `options` Object (可选) _macOS_ + * `activate` Boolean - `true` 让打开的应用在前面显示,默认为 `true`. +* `callback` Function (可选) - 如果指定将执行异步打开. _macOS_ + * `error` Error -以系统默认设置打开外部协议.(例如,mailto: somebody@somewhere.io会打开用户默认的邮件客户端) +Returns `Boolean` - 应用程序是否打开URL.如果指定了 callback 回调方法, 则返回 true. + +以系统默认设置打开外部协议.(例如,mailto: URLs 会打开用户默认的邮件客户端) ### `shell.moveItemToTrash(fullPath)` * `fullPath` String +Returns `Boolean` - 文件是否成功移动到垃圾桶 + 删除指定路径文件,并返回此操作的状态值(boolean类型). ### `shell.beep()` 播放 beep 声音. + +### `shell.writeShortcutLink(shortcutPath[, operation], options)` _Windows_ + +* `shortcutPath` String +* `operation` String (可选) - 默认为 `create`, 可以为下列的值: + * `create` - 创建一个新的快捷方式,如果存在的话会覆盖. + * `update` - 仅在现有快捷方式上更新指定属性. + * `replace` - 覆盖现有的快捷方式,如果快捷方式不存在则会失败. +* `options` [ShortcutDetails](structures/shortcut-details.md) + +Returns `Boolean` - 快捷方式是否成功创建 + +为 `shortcutPath` 创建或更新快捷链接. + +### `shell.readShortcutLink(shortcutPath)` _Windows_ + +* `shortcutPath` String + +Returns [`ShortcutDetails`](structures/shortcut-details.md) + +读取 `shortcutPath` 的快捷连接的信息. + +发生错误时,会抛出异常信息. From fe8726d77556616d407644fabe94c82e6ac82710 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 11 Apr 2017 13:08:15 -0700 Subject: [PATCH 244/337] Use Chrome default client inset handling --- atom/browser/native_window_views.cc | 24 ------------------- atom/browser/ui/views/win_frame_view.cc | 1 - .../win/atom_desktop_window_tree_host_win.cc | 8 ------- .../win/atom_desktop_window_tree_host_win.h | 1 - electron.gyp | 7 +++++- 5 files changed, 6 insertions(+), 35 deletions(-) diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 615c848daac8..690a47ececbd 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -70,20 +70,6 @@ const int kMenuBarHeight = 25; #endif #if defined(OS_WIN) -gfx::Rect SubtractBorderSize(gfx::Rect bounds) { - gfx::Point borderSize = gfx::Point( - GetSystemMetrics(SM_CXSIZEFRAME) - 1, // width - GetSystemMetrics(SM_CYSIZEFRAME) - 1); // height - gfx::Point dpiAdjustedSize = - display::win::ScreenWin::ScreenToDIPPoint(borderSize); - - bounds.set_x(bounds.x() + dpiAdjustedSize.x()); - bounds.set_y(bounds.y() + dpiAdjustedSize.y()); - bounds.set_width(bounds.width() - 2 * dpiAdjustedSize.x()); - bounds.set_height(bounds.height() - 2 * dpiAdjustedSize.y()); - return bounds; -} - void FlipWindowStyle(HWND handle, bool on, DWORD flag) { DWORD style = ::GetWindowLong(handle, GWL_STYLE); if (on) @@ -1279,16 +1265,6 @@ void NativeWindowViews::HandleKeyboardEvent( } void NativeWindowViews::Layout() { -#if defined(OS_WIN) - // Reserve border space for maximized frameless window so we won't have the - // content go outside of screen. - if (!has_frame() && IsMaximized()) { - gfx::Rect bounds = SubtractBorderSize(GetContentsBounds()); - web_view_->SetBoundsRect(bounds); - return; - } -#endif - const auto size = GetContentsBounds().size(); const auto menu_bar_bounds = menu_bar_ ? gfx::Rect(0, 0, size.width(), kMenuBarHeight) : gfx::Rect(); diff --git a/atom/browser/ui/views/win_frame_view.cc b/atom/browser/ui/views/win_frame_view.cc index fca7cb23347c..3908a2774ef9 100644 --- a/atom/browser/ui/views/win_frame_view.cc +++ b/atom/browser/ui/views/win_frame_view.cc @@ -23,7 +23,6 @@ WinFrameView::WinFrameView() { WinFrameView::~WinFrameView() { } - gfx::Rect WinFrameView::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { return views::GetWindowBoundsForClientBounds( diff --git a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc index 9cc2ef9e8d22..84a6d9aa3e50 100644 --- a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc +++ b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc @@ -25,12 +25,4 @@ bool AtomDesktopWindowTreeHostWin::PreHandleMSG( return delegate_->PreHandleMSG(message, w_param, l_param, result); } -/** Override the client area inset - * Returning true forces a border of 0 for frameless windows - */ -bool AtomDesktopWindowTreeHostWin::GetClientAreaInsets( - gfx::Insets* insets) const { - return !HasFrame(); -} - } // namespace atom diff --git a/atom/browser/ui/win/atom_desktop_window_tree_host_win.h b/atom/browser/ui/win/atom_desktop_window_tree_host_win.h index 2df70547c5ba..47e4cb6aed2a 100644 --- a/atom/browser/ui/win/atom_desktop_window_tree_host_win.h +++ b/atom/browser/ui/win/atom_desktop_window_tree_host_win.h @@ -27,7 +27,6 @@ class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin { protected: bool PreHandleMSG( UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override; - bool GetClientAreaInsets(gfx::Insets* insets) const override; private: MessageHandlerDelegate* delegate_; // weak ref diff --git a/electron.gyp b/electron.gyp index 7775907380d7..6a54c389993c 100644 --- a/electron.gyp +++ b/electron.gyp @@ -126,7 +126,12 @@ 'VCManifestTool': { 'EmbedManifest': 'true', 'AdditionalManifestFiles': 'atom/browser/resources/win/atom.manifest', - } + }, + 'VCLinkerTool': { + 'AdditionalOptions': [ + "/SUBSYSTEM:WINDOWS,5.02" + ], + }, }, 'copies': [ { From 1a75bf8fb9c6e2298202c7eed3d1fc9154982d4f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 11 Apr 2017 14:35:09 -0700 Subject: [PATCH 245/337] Add comment to subsystem linker option --- electron.gyp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/electron.gyp b/electron.gyp index 6a54c389993c..c3f632c9eb82 100644 --- a/electron.gyp +++ b/electron.gyp @@ -129,6 +129,8 @@ }, 'VCLinkerTool': { 'AdditionalOptions': [ + # Chrome builds with this minimum environment which changes the + # values returned from APIs like GetSystemMetrics(SM_CXSIZEFRAME) "/SUBSYSTEM:WINDOWS,5.02" ], }, From 4ca4eb01d412185921ea5fa09636642410047a6f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 11 Apr 2017 14:44:22 -0700 Subject: [PATCH 246/337] Use MinimumRequiredVersion instead of argument --- electron.gyp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/electron.gyp b/electron.gyp index c3f632c9eb82..6070b84d385a 100644 --- a/electron.gyp +++ b/electron.gyp @@ -128,11 +128,9 @@ 'AdditionalManifestFiles': 'atom/browser/resources/win/atom.manifest', }, 'VCLinkerTool': { - 'AdditionalOptions': [ - # Chrome builds with this minimum environment which changes the - # values returned from APIs like GetSystemMetrics(SM_CXSIZEFRAME) - "/SUBSYSTEM:WINDOWS,5.02" - ], + # Chrome builds with this minimum environment which changes the + # values returned from APIs like GetSystemMetrics(SM_CXSIZEFRAME) + 'MinimumRequiredVersion': '5.02' }, }, 'copies': [ From 108f246d89dc928095b8ea6447ce42d6ad73a23a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 11 Apr 2017 14:54:34 -0700 Subject: [PATCH 247/337] Add SubSystem setting --- electron.gyp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/electron.gyp b/electron.gyp index 6070b84d385a..8c3718b1cd60 100644 --- a/electron.gyp +++ b/electron.gyp @@ -128,9 +128,14 @@ 'AdditionalManifestFiles': 'atom/browser/resources/win/atom.manifest', }, 'VCLinkerTool': { - # Chrome builds with this minimum environment which changes the - # values returned from APIs like GetSystemMetrics(SM_CXSIZEFRAME) - 'MinimumRequiredVersion': '5.02' + # Chrome builds with this minimum environment which makes e.g. + # GetSystemMetrics(SM_CXSIZEFRAME) return Windows XP/2003 + # compatible metrics. See: https://crbug.com/361720 + # + # The following two settings translate to a linker flag + # of /SUBSYSTEM:WINDOWS,5.02 + 'MinimumRequiredVersion': '5.02', + 'SubSystem': '2', }, }, 'copies': [ From ea6890aa5ce178ec993ab805b4e29f174dcb090b Mon Sep 17 00:00:00 2001 From: Ryohei Ikegami Date: Thu, 13 Apr 2017 23:26:42 +0900 Subject: [PATCH 248/337] Use const --- atom/browser/api/atom_api_app.cc | 2 +- atom/browser/api/atom_api_app.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index d8e79171f879..acf7ce8c74f6 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -655,7 +655,7 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) { status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); } -base::FilePath App::GetAppPath() { +base::FilePath App::GetAppPath() const { return app_path_; } diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 78871f6920ec..a87b88bc4642 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -70,7 +70,7 @@ class App : public AtomBrowserClient::Delegate, std::unique_ptr model); #endif - base::FilePath GetAppPath(); + base::FilePath GetAppPath() const; protected: explicit App(v8::Isolate* isolate); From eee0b35d19a1934d2fb456a1f2eb9d8e66400d82 Mon Sep 17 00:00:00 2001 From: Junyoung Jung Date: Thu, 13 Apr 2017 23:47:01 +0900 Subject: [PATCH 249/337] Update protocol.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 오타 수정, Edit typo --- docs-translations/ko-KR/api/protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-translations/ko-KR/api/protocol.md b/docs-translations/ko-KR/api/protocol.md index dc3bb51ba2f3..38a17bed14ff 100644 --- a/docs-translations/ko-KR/api/protocol.md +++ b/docs-translations/ko-KR/api/protocol.md @@ -1,6 +1,6 @@ # protocol -> 커스텀 프로토콜을 등록하거나 이미 존재하능 프로토콜의 요청의 동작을 변경합니다. +> 커스텀 프로토콜을 등록하거나 이미 존재하는 프로토콜의 요청의 동작을 변경합니다. 프로세스: [메인](../tutorial/quick-start.md#main-process) From e7d71000eea11c6ec77f657e1ff5c2a2b813d126 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Thu, 13 Apr 2017 21:36:48 +0300 Subject: [PATCH 250/337] Fix missing warning icon with dialog.showMessageBox() on macOS Fixes #9183. --- atom/browser/ui/message_box_mac.mm | 10 +++++++--- docs/api/dialog.md | 5 +++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/atom/browser/ui/message_box_mac.mm b/atom/browser/ui/message_box_mac.mm index 3550e47cf86e..f752f2945c2e 100644 --- a/atom/browser/ui/message_box_mac.mm +++ b/atom/browser/ui/message_box_mac.mm @@ -71,10 +71,14 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window, switch (type) { case MESSAGE_BOX_TYPE_INFORMATION: - [alert setAlertStyle:NSInformationalAlertStyle]; + alert.alertStyle = NSInformationalAlertStyle; break; case MESSAGE_BOX_TYPE_WARNING: - [alert setAlertStyle:NSWarningAlertStyle]; + case MESSAGE_BOX_TYPE_ERROR: + // NSWarningAlertStyle shows the app icon while NSCriticalAlertStyle + // shows a warning icon with an app icon badge. Since there is no + // error variant, lets just use NSCriticalAlertStyle. + alert.alertStyle = NSCriticalAlertStyle; break; default: break; @@ -192,7 +196,7 @@ void ShowErrorBox(const base::string16& title, const base::string16& content) { NSAlert* alert = [[NSAlert alloc] init]; [alert setMessageText:base::SysUTF16ToNSString(title)]; [alert setInformativeText:base::SysUTF16ToNSString(content)]; - [alert setAlertStyle:NSWarningAlertStyle]; + [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; [alert release]; } diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 51760c2d59db..615e3b2c6f93 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -115,8 +115,9 @@ will be passed via `callback(filename)` * `browserWindow` BrowserWindow (optional) * `options` Object * `type` String (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or - `"warning"`. On Windows, "question" displays the same icon as "info", unless - you set an icon using the "icon" option. + `"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless + you set an icon using the `"icon"` option. On macOS, both `"warning"` and + `"error"` display the same warning icon. * `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array will result in one button labeled "OK". * `defaultId` Integer (optional) - Index of the button in the buttons array which will From 228517edde1e61f1dae93ad70dbfe6cca38f5c2c Mon Sep 17 00:00:00 2001 From: "Mustafa C. Izol" Date: Fri, 14 Apr 2017 19:38:46 +0200 Subject: [PATCH 251/337] add turkish quick start file --- .../tr-TR/tutorial/quick-start.md | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 docs-translations/tr-TR/tutorial/quick-start.md diff --git a/docs-translations/tr-TR/tutorial/quick-start.md b/docs-translations/tr-TR/tutorial/quick-start.md new file mode 100644 index 000000000000..1941060df2a9 --- /dev/null +++ b/docs-translations/tr-TR/tutorial/quick-start.md @@ -0,0 +1,252 @@ +# Hızlı Başlangıç + +Electron, zengin native(işletim sistemi) API runtime sağlayarak, saf Javascript +ile masaüstü uygulamalar geliştirmenize yarar. Electron'u Node.js in, web serverları +yerine masaüstü uygulamalara odaklanmış bir variyasyonu olarak kabul edebilirsiniz. + +Bu Electronun, grafik kullanıcı arayüzüne bir JavaScript bağlantısı olduğu +anlamına gelmez. Aksine, Electron web sayfalarını GUI'si olarak kullanır, +yani onu Javascript tarafından kontrol edilen bir minimal Chromium tarayıcısı +olarak görebilirsiniz. + +### Ana İşlem + +Electron da, `package.json` nun `main` skriptini cağıran işlem _the main process__ dir. +Ana işlemde çalışan bu script, GUI'yi web sayfalarını oluşturarak gösterebilir. + +### Render İşlemi + +Electron, web sayfalarını görüntülemek için Chromium kullandığından, +aynı zamanda Chromiumun multi-işlem mimarisinide kullanmaktadır. +Electron da calıştırılan her web sayfası, __the renderer process__ +adı altında kendi işlemlerini çalıştırırlar. + +Normal tarayıcılarda, web sayfaları genellikle korumalı bir ortamda çalışır ve +yerel kaynaklara erişmesine izin verilmez. Bununla birlikte, elektron kullanıcıları, +alt düzey işletim sistemi etkileşimlerine izin veren web sayfalarında +Node.js API'lerini kullanma imkanina sahiplerdir. + +### Ana işlem ile render işlemi arasındaki farklar + +Ana işlem, `BrowserWindow` örneklerini oluşturarak, web sayfalarını hazır +hale getirir. Her bir `BrowserWindow` örneği web sayfasını kendi render +işleminde çalıştırır. Eger bir `BrowserWindow` örneği ortadan kaldırıldıysa, +bununla bağlantılı olan render işlemide aynı şekilde sonlandırılır. + +Ana işlem tüm web sayfaları ve onların ilgili olduğu render işlemlerini yönetir. +Her bir render işlemi izole edilmiş ve sadece kendisinde çalışan web sayfasıyla ilgilenir. + +Native GUI ile çalışan API ları web sayfalarında çalıştırmaya izin verilmemektedir, +çünkü native GUI kaynaklarının web sayfalarında yönetimi çok tehlikeli ve +kaynakların sızdırılması gayet kolaydır. Eğer GUI operasyonlarını bir web sayfasinda +gerçekleştirmek istiyorsanız, web sayfasının render işlemi, ana işlem ile, bu tür +işlemleri gerçekleştirilmesini talep etmek için kommunikasyon halinde olmalı. + +Electron da ana işlem ve render işlemi arasında birden fazla kommunikasyon yolu vardır. +[`ipcRenderer`](../api/ipc-renderer.md) gibi ve mesaj gönderimi icin +[`ipcMain`](../api/ipc-main.md) modülleri, RPC tarzında kommunikasyon +için ise [remote](../api/remote.md) modülü barındırmakta. +Ayrıca SSS başlıkları [how to share data between web pages][share-data] adresinde bulunabilir. + +## İlk Electron uygulamanızı yazın + +Electron uygulaması genellikle aşağıdaki gibi yapılandırılmıştır: + +```text +your-app/ +├── package.json +├── main.js +└── index.html +``` + +`package.json` dosyasının formatı tamamen Node modüllerine benzer veya aynıdır ve +`main` şeklinde adlandırılmış script uygulamanızı başlatan komut dosyasıdır, +bu komut dosyası daha sonra main process'i çalıştıracak dosyadır. +`package.json` dosyasınızın bir örneği aşağıdaki gibi olabilir: + + +```json +{ + "name" : "your-app", + "version" : "0.1.0", + "main" : "main.js" +} +``` + +__Note__: Eğer `package.json` dosyasında `main` kısmı bulunmuyorsa, Electron standart olarak +`index.js` dosyasını cağıracaktır. + +`main.js` dosyası pencereleri oluşturur, sistem durumlarını handle eder, tipik bir +örnek asağıdaki gibidir: + +```javascript +const {app, BrowserWindow} = require('electron') +const path = require('path') +const url = require('url') + +// Pencere objesini daima global referans olarak tanımla, aksi takdirde, +// eğer JavaScript objesi gereksiz veriler toplayacağı için, pencere +// otomatik olarak kapanacaktır. + +let win + +function createWindow () { + // Tarayıcı pencerelerini oluşturur. + win = new BrowserWindow({width: 800, height: 600}) + + // ve uygulamanın index.html sayfasını yükler. + win.loadURL(url.format({ + pathname: path.join(__dirname, 'index.html'), + protocol: 'file:', + slashes: true + })) + + // DevTools her uygulama başlatıldığında açılır. + + win.webContents.openDevTools() + + // Pencere kapandıktan sonra çağrılacaktır. + win.on('closed', () => { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + win = null + }) +} + +// Bu metod Electronun başlatılması tamamlandıktan sonra +// çagrılacak ve yeni tarayıcı pencereleri açmaya hazır hale gelecektir. +// Bazı API lar sadece bu event gerçekleştikten sonra kullanılabilir. + +app.on('ready', createWindow) + +// Eğer tüm pencereler kapandıysa, çıkış yap. + +app.on('window-all-closed', () => { + // On macOS it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', () => { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (win === null) { + createWindow() + } +}) + +// Bu sayfada, uygulamanızın spesifik main process kodlarını dahil edebilirsiniz. +// Aynı zamanda bu kodları ayrı dosyalar halinde oluştura bilir +// ve buraya require yoluyla ekleye bilirsiniz. + +``` + +Son olarak `index.html` yani göstermek istediğiniz web sayfası: + +```html + + + + + Hello World! + + +

Hello World!

+ We are using node , + Chrome , + and Electron . + + +``` + +## Uygulamanızı çalıştırın + +`main.js`, `index.html`, ve `package.json` dosyalarını oluşturduktan sonra, +uygulamanızı lokal olarak test ederek, doğru çalışıp çalışmadığını +test etmek isteye bilirsiniz. O halde aşağıdaki yönergeleri takip edin: + +### `electron` + +[`electron`](https://github.com/electron-userland/electron-prebuilt), +Electron'un pre-compiled versiyonunu içeren bir `npm` modülüdür. + + +Eğer bunu global olarak `npm` yoluyla yüklediyseniz, o halde sadece aşağıdaki komutu +uygulamanızın kaynak klasöründe çalıstırmanız yeterlidir: + +```bash +electron . +``` + +Eğer lokal olarak yüklediyseniz, o zaman aşağıda ki gibi +çalıştırın: + +#### macOS / Linux + +```bash +$ ./node_modules/.bin/electron . +``` + +#### Windows + +```bash +$ .\node_modules\.bin\electron . +``` + +### Manuel olarak indirilmiş Electron mimarisi + +Eğer Electronu manuel olarak indirdiyseniz, aynı zamanda dahili olan +mimariyide kullanarak, uygulamanızı çalıştıra bilirsiniz. + +#### Windows + +```bash +$ .\electron\electron.exe your-app\ +``` + +#### Linux + +```bash +$ ./electron/electron your-app/ +``` + +#### macOS + +```bash +$ ./Electron.app/Contents/MacOS/Electron your-app/ +``` + +`Electron.app` Electron un dağı₺tım paketinin bir parçasıdır, +bunu [adresinden](https://github.com/electron/electron/releases) indirebilirsiniz. + +### Dağıtım olarak çalıştır + +Uygulamanızı yazdıktan sonra, bir dağıtım oluşturmak için +[Application Distribution](./application-distribution.md) +sayfasında ki yönergeleri izleyin ve daha sonra arşivlenmiş uygulamayı çalıştırın. + +### Örneği deneyin + +[`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) repository klonlayarak bu eğitimdeki kodu çalıştıra bilirsiniz. + +**Note**: Bu işlemleri uygulamak için [Git](https://git-scm.com) ve [Node.js](https://nodejs.org/en/download/) ([npm](https://npmjs.org) da bununla birlikte gelir) sisteminizde yüklü olması gerekmektedir. + +```bash +# Repository klonla +$ git clone https://github.com/electron/electron-quick-start +# Electron repositorye git +$ cd electron-quick-start +# Gerekli kütüphaneleri yükle +$ npm install +# Uygulamayı çalıştır +$ npm start +``` + +Daha fazla örnek uygulama için, harika electron topluluğu tarafından oluşturulan, +[list of boilerplates](https://electron.atom.io/community/#boilerplates) +sayfasını ziyaret edin. + +[share-data]: ../faq.md#how-to-share-data-between-web-pages From 7b3f1b5d91c77f0c6e38fda34c5d3fed5f587825 Mon Sep 17 00:00:00 2001 From: "Mustafa C. Izol" Date: Fri, 14 Apr 2017 19:47:39 +0200 Subject: [PATCH 252/337] update link to turkish quick-start --- docs-translations/tr-TR/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-translations/tr-TR/README.md b/docs-translations/tr-TR/README.md index a3487d298a2e..ac11a02f4d3a 100644 --- a/docs-translations/tr-TR/README.md +++ b/docs-translations/tr-TR/README.md @@ -23,7 +23,7 @@ Bir problem(issue) bildirmeden önce sıkça sorulan sorulara göz atın: ## Eğitimler -* [Quick Start](https://github.com/electron/electron/tree/master/docs/tutorial/quick-start.md) +* [Hızlı Başlangıç](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) From 75184046f6c6cc3af31e8a086694d4f11cef0486 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Tue, 4 Apr 2017 01:44:26 +0900 Subject: [PATCH 253/337] Add events to manage sheets of macOS BrowserWindow --- atom/browser/api/atom_api_window.cc | 10 ++++++ atom/browser/api/atom_api_window.h | 5 +++ atom/browser/native_window.cc | 12 +++++++ atom/browser/native_window.h | 5 +++ atom/browser/native_window_mac.mm | 8 +++++ atom/browser/native_window_observer.h | 5 +++ docs/api/browser-window.md | 8 +++++ spec/api-browser-window-spec.js | 48 +++++++++++++++++++++++++++ 8 files changed, 101 insertions(+) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index c6707624913d..573d0215d234 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -298,6 +298,16 @@ void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) { } #endif +#if defined(OS_MACOSX) +void Window::OnWindowSheetBegin() { + Emit("sheet-begin"); +} + +void Window::OnWindowSheetEnd() { + Emit("sheet-end"); +} +#endif + // static mate::WrappableBase* Window::New(mate::Arguments* args) { if (!Browser::Get()->is_ready()) { diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index d464af58ea9d..79e757833ec8 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -93,6 +93,11 @@ class Window : public mate::TrackableObject, void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override; #endif + #if defined(OS_MACOSX) + void OnWindowSheetBegin() override; + void OnWindowSheetEnd() override; + #endif + private: void Init(v8::Isolate* isolate, v8::Local wrapper, diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 316cc8dc2e3d..eec00996debe 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -590,6 +590,18 @@ void NativeWindow::NotifyWindowMessage( } #endif +#if defined(OS_MACOSX) +void NativeWindow::NotifyWindowSheetBegin() { + for (NativeWindowObserver& observer : observers_) + observer.OnWindowSheetBegin(); +} + +void NativeWindow::NotifyWindowSheetEnd() { + for (NativeWindowObserver& observer : observers_) + observer.OnWindowSheetEnd(); +} +#endif + std::unique_ptr NativeWindow::DraggableRegionsToSkRegion( const std::vector& regions) { std::unique_ptr sk_region(new SkRegion); diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 56702daef63b..83ac0e521fc4 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -245,6 +245,11 @@ class NativeWindow : public base::SupportsUserData, void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param); #endif + #if defined(OS_MACOSX) + void NotifyWindowSheetBegin(); + void NotifyWindowSheetEnd(); + #endif + void AddObserver(NativeWindowObserver* obs) { observers_.AddObserver(obs); } diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index b695f8eafa89..9dc119e239dd 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -313,6 +313,14 @@ bool ScopedDisableResize::disable_resize_ = false; return rect; } +- (void)windowWillBeginSheet:(NSNotification *)notification { + shell_->NotifyWindowSheetBegin(); +} + +- (void)windowDidEndSheet:(NSNotification *)notification { + shell_->NotifyWindowSheetEnd(); +} + @end @interface AtomPreviewItem : NSObject diff --git a/atom/browser/native_window_observer.h b/atom/browser/native_window_observer.h index 3b8d86e6fb0f..3235976e247a 100644 --- a/atom/browser/native_window_observer.h +++ b/atom/browser/native_window_observer.h @@ -79,6 +79,11 @@ class NativeWindowObserver { virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {} #endif + #if defined(OS_MACOSX) + virtual void OnWindowSheetBegin() {} + virtual void OnWindowSheetEnd() {} + #endif + // Called when renderer is hung. virtual void OnRendererUnresponsive() {} diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 2c720fdfac11..cd55ba0bbda3 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -498,6 +498,14 @@ Returns: Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`. +#### Event: 'sheet-begin' _macOS_ + +Emitted when the window opens a sheet. + +#### Event: 'sheet-end' _macOS_ + +Emitted when the window has closed a sheet. + ### Static Methods The `BrowserWindow` class has the following static methods: diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index d83c173f26f1..eb5e1bd9574b 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -1191,6 +1191,54 @@ describe('BrowserWindow module', function () { }) }) + describe('sheet-begin event', function () { + if (process.platform !== 'darwin') { + return + } + + let sheet = null + + afterEach(function () { + return closeWindow(sheet, {assertSingleWindow: false}).then(function () { sheet = null }) + }) + + it('emits when window opens a sheet', function (done) { + w.show() + w.once('sheet-begin', function () { + sheet.close() + done() + }) + sheet = new BrowserWindow({ + modal: true, + parent: w + }) + }) + }) + + describe('sheet-end event', function () { + if (process.platform !== 'darwin') { + return + } + + let sheet = null + + afterEach(function () { + return closeWindow(sheet, {assertSingleWindow: false}).then(function () { sheet = null }) + }) + + it('emits when window has closed a sheet', function (done) { + w.show() + sheet = new BrowserWindow({ + modal: true, + parent: w + }) + w.once('sheet-end', function () { + done() + }) + sheet.close() + }) + }) + describe('beginFrameSubscription method', function () { // This test is too slow, only test it on CI. if (!isCI) return From dc914fdb288754cafd9b4fc176222d62179027d8 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Sun, 16 Apr 2017 18:00:51 +0300 Subject: [PATCH 254/337] Update Brightray for electron/brightray#289 This fixes #9197. --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index 28d713bb2a82..909c49265493 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 28d713bb2a82ba690a21d62522ecd7bad09caba8 +Subproject commit 909c49265493bd095c27cefd999567be2107899a From 39caa6ad2339ea35360091ba1c8231325942c931 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 17 Apr 2017 14:37:05 +0700 Subject: [PATCH 255/337] :memo: Add docs tip about testing Touch Bar usage Disclosure: I made it. Most devs don't have the new MacBook with Touch Bar, but would like to support it. I think it would be useful to point out how to easily develop and test Touch Bar usage in Electron apps. [ci skip] --- docs/api/touch-bar.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 7ac578da46db..0a0827a2b2fa 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -16,6 +16,10 @@ Creates a new touch bar with the specified items. Use **Note:** The TouchBar API is currently experimental and may change or be removed in future Electron releases. +**Tip:** If you don't have a MacBook with Touch Bar, you can use +[Touch Bar Simulator](https://github.com/sindresorhus/touch-bar-simulator) +to test Touch Bar usage in your app. + ### Instance Properties The following properties are available on instances of `TouchBar`: From dcf6c52f51bcf3635bd97238a851f73cda1d7b40 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Mon, 17 Apr 2017 12:29:42 +0300 Subject: [PATCH 256/337] Actually hide menubar area when menu is autohidden This was a regression introduced in 638eae10. --- atom/browser/native_window_views.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 690a47ececbd..7e6f23947c29 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -1267,7 +1267,8 @@ void NativeWindowViews::HandleKeyboardEvent( void NativeWindowViews::Layout() { const auto size = GetContentsBounds().size(); const auto menu_bar_bounds = - menu_bar_ ? gfx::Rect(0, 0, size.width(), kMenuBarHeight) : gfx::Rect(); + menu_bar_visible_ ? gfx::Rect(0, 0, size.width(), kMenuBarHeight) + : gfx::Rect(); if (menu_bar_) { menu_bar_->SetBoundsRect(menu_bar_bounds); } From 4a7125d9f831b47993e2e7b16e64f55cf78f7f78 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Mon, 17 Apr 2017 23:21:43 +0300 Subject: [PATCH 257/337] Update libcc for electron/libchromiumcontent#285 This fixes non-client area DPI scaling on recent Windows 10 versions. See discussion in #8786. --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index d033d8a41c6a..5818571089ff 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -9,7 +9,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \ - '8d551064d2b3d11f89ce8d5c4610f34e0408bad8' + '4a0e32606e52c12c50c2e3a0973d015d8cdff494' PLATFORM = { 'cygwin': 'win32', From 3bcf5e0e9f0862d62fdd9e937225e9137300d98e Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Tue, 18 Apr 2017 11:51:38 +0300 Subject: [PATCH 258/337] Fix OverrideSiteInstanceForNavigation() signature --- atom/browser/atom_browser_client.cc | 1 + atom/browser/atom_browser_client.h | 1 + 2 files changed, 2 insertions(+) diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index d0bbf4ad535f..9b096ae8aef6 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -172,6 +172,7 @@ std::string AtomBrowserClient::GetApplicationLocale() { } void AtomBrowserClient::OverrideSiteInstanceForNavigation( + content::RenderFrameHost* render_frame_host, content::BrowserContext* browser_context, content::SiteInstance* current_instance, const GURL& url, diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index c2a7d5edd0f4..70573d6eee37 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -54,6 +54,7 @@ class AtomBrowserClient : public brightray::BrowserClient, content::WebPreferences* prefs) override; std::string GetApplicationLocale() override; void OverrideSiteInstanceForNavigation( + content::RenderFrameHost* render_frame_host, content::BrowserContext* browser_context, content::SiteInstance* current_instance, const GURL& dest_url, From 11c7c107a958f3de2bbb7f6df4f5340e8c40ef03 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 17 Apr 2017 12:26:33 +1200 Subject: [PATCH 259/337] add iconPosition property to touch bar buttons --- atom/browser/ui/cocoa/atom_touch_bar.mm | 9 +++++++++ docs/api/touch-bar-button.md | 1 + lib/browser/api/touch-bar.js | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index a3e846df4871..95f36cf02d02 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -307,9 +307,18 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; settings.Get("label", &label); button.title = base::SysUTF8ToNSString(label); + std::string iconPosition = "left"; + settings.Get("iconPosition", &iconPosition); gfx::Image image; if (settings.Get("icon", &image)) { button.image = image.AsNSImage(); + if (iconPosition == "overlay") { + button.imagePosition = NSImageOverlaps; + } else if (iconPosition == "right") { + button.imagePosition = NSImageRight; + } else { + button.imagePosition = NSImageLeft; + } } } diff --git a/docs/api/touch-bar-button.md b/docs/api/touch-bar-button.md index 177e51bcdb20..456fc207fe98 100644 --- a/docs/api/touch-bar-button.md +++ b/docs/api/touch-bar-button.md @@ -11,6 +11,7 @@ Process: [Main](../tutorial/quick-start.md#main-process) * `backgroundColor` String (optional) - Button background color in hex format, i.e `#ABCDEF`. * `icon` [NativeImage](native-image.md) (optional) - Button icon. + * `iconPosition` String - Can be `left`, `right` or `overlay`. * `click` Function (optional) - Function to call when the button is clicked. ### Instance Properties diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index 1a9c3238a97f..4bb129449eb9 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -159,10 +159,11 @@ TouchBar.TouchBarButton = class TouchBarButton extends TouchBarItem { super() if (config == null) config = {} this.type = 'button' - const {click, icon, label, backgroundColor} = config + const {click, icon, iconPosition, label, backgroundColor} = config this._addLiveProperty('label', label) this._addLiveProperty('backgroundColor', backgroundColor) this._addLiveProperty('icon', icon) + this._addLiveProperty('iconPosition', iconPosition) if (typeof click === 'function') { this.onInteraction = () => { config.click() From 526d287d25787f657b015c9f379ee51339de2cb3 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 17 Apr 2017 12:30:55 +1200 Subject: [PATCH 260/337] Make iconPosition non-breaking by defaulting to overlay --- atom/browser/ui/cocoa/atom_touch_bar.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 95f36cf02d02..97eebf73f688 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -307,17 +307,17 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; settings.Get("label", &label); button.title = base::SysUTF8ToNSString(label); - std::string iconPosition = "left"; + std::string iconPosition = "overlay"; settings.Get("iconPosition", &iconPosition); gfx::Image image; if (settings.Get("icon", &image)) { button.image = image.AsNSImage(); - if (iconPosition == "overlay") { - button.imagePosition = NSImageOverlaps; + if (iconPosition == "left") { + button.imagePosition = NSImageLeft; } else if (iconPosition == "right") { button.imagePosition = NSImageRight; } else { - button.imagePosition = NSImageLeft; + button.imagePosition = NSImageOverlaps; } } } From c32a723e2906de3741bf5abd95234e7efdb1703b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 08:58:54 -0700 Subject: [PATCH 261/337] Only read iconPosition when icon is present --- atom/browser/ui/cocoa/atom_touch_bar.mm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/atom/browser/ui/cocoa/atom_touch_bar.mm b/atom/browser/ui/cocoa/atom_touch_bar.mm index 97eebf73f688..a21fbc5497a3 100644 --- a/atom/browser/ui/cocoa/atom_touch_bar.mm +++ b/atom/browser/ui/cocoa/atom_touch_bar.mm @@ -307,17 +307,18 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; settings.Get("label", &label); button.title = base::SysUTF8ToNSString(label); - std::string iconPosition = "overlay"; - settings.Get("iconPosition", &iconPosition); gfx::Image image; if (settings.Get("icon", &image)) { button.image = image.AsNSImage(); + + std::string iconPosition; + settings.Get("iconPosition", &iconPosition); if (iconPosition == "left") { - button.imagePosition = NSImageLeft; + button.imagePosition = NSImageLeft; } else if (iconPosition == "right") { - button.imagePosition = NSImageRight; + button.imagePosition = NSImageRight; } else { - button.imagePosition = NSImageOverlaps; + button.imagePosition = NSImageOverlaps; } } } From ca46d52b0c9b1f43c0b5daf877bef774fc74cc29 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 09:01:43 -0700 Subject: [PATCH 262/337] Add button with icon to touch bar spec --- spec/api-touch-bar-spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 420ef3fc7b37..6177e3cb85fa 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -1,4 +1,5 @@ const assert = require('assert') +const path = require('path') const {BrowserWindow, TouchBar} = require('electron').remote const {closeWindow} = require('./window-helpers') @@ -48,6 +49,11 @@ describe('TouchBar module', function () { const label = new TouchBarLabel({label: 'bar'}) const touchBar = new TouchBar([ new TouchBarButton({label: 'foo', backgroundColor: '#F00', click: () => {}}), + new TouchBarButton({ + icon: path.join(__dirname, 'fixtures', 'assets', 'logo.png'), + iconPosition: 'right', + click: () => {} + }), new TouchBarColorPicker({selectedColor: '#F00', change: () => {}}), new TouchBarGroup({items: new TouchBar([new TouchBarLabel({label: 'hello'})])}), label, From 19709a50e9490cb1add345ba614de2c61ce6fab9 Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Fri, 14 Apr 2017 06:12:22 -0700 Subject: [PATCH 263/337] Adding cookie flush store api --- atom/browser/api/atom_api_cookies.cc | 16 +++++++++++++++- atom/browser/api/atom_api_cookies.h | 1 + docs/api/cookies.md | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_cookies.cc b/atom/browser/api/atom_api_cookies.cc index ddb6910b509a..d3607fe50259 100644 --- a/atom/browser/api/atom_api_cookies.cc +++ b/atom/browser/api/atom_api_cookies.cc @@ -179,6 +179,12 @@ void OnSetCookie(const Cookies::SetCallback& callback, bool success) { base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED)); } +// Flushes cookie store in IO thread. +void FlushCookieStoreOnIOThread(scoped_refptr getter, + const base::Closure& callback) { + GetCookieStore(getter)->FlushStore(base::Bind(RunCallbackInUI, callback)); +} + // Sets cookie with |details| in IO thread. void SetCookieOnIO(scoped_refptr getter, std::unique_ptr details, @@ -265,6 +271,13 @@ void Cookies::Set(const base::DictionaryValue& details, base::Bind(SetCookieOnIO, getter, Passed(&copied), callback)); } +void Cookies::FlushStore(const base::Closure& callback) { + auto getter = make_scoped_refptr(request_context_getter_); + content::BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(FlushCookieStoreOnIOThread, getter, callback)); +} + void Cookies::OnCookieChanged(const net::CanonicalCookie& cookie, bool removed, net::CookieStore::ChangeCause cause) { @@ -286,7 +299,8 @@ void Cookies::BuildPrototype(v8::Isolate* isolate, mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) .SetMethod("get", &Cookies::Get) .SetMethod("remove", &Cookies::Remove) - .SetMethod("set", &Cookies::Set); + .SetMethod("set", &Cookies::Set) + .SetMethod("flushStore", &Cookies::FlushStore); } } // namespace api diff --git a/atom/browser/api/atom_api_cookies.h b/atom/browser/api/atom_api_cookies.h index 3a7a98fbafd9..d20dab8394c6 100644 --- a/atom/browser/api/atom_api_cookies.h +++ b/atom/browser/api/atom_api_cookies.h @@ -53,6 +53,7 @@ class Cookies : public mate::TrackableObject, void Remove(const GURL& url, const std::string& name, const base::Closure& callback); void Set(const base::DictionaryValue& details, const SetCallback& callback); + void FlushStore(const base::Closure& callback); // AtomCookieDelegate::Observer: void OnCookieChanged(const net::CanonicalCookie& cookie, diff --git a/docs/api/cookies.md b/docs/api/cookies.md index 8e6420296733..060034a16c1f 100644 --- a/docs/api/cookies.md +++ b/docs/api/cookies.md @@ -104,3 +104,7 @@ on complete. Removes the cookies matching `url` and `name`, `callback` will called with `callback()` on complete. + +#### `cookies.flushStore()` + +Writes any unwritten cookies data to disk. From efca0a6e07434dddebd7fa50d90824ad52554cef Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Fri, 14 Apr 2017 10:03:52 -0700 Subject: [PATCH 264/337] fixup! Adding cookie flush store api --- docs/api/cookies.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api/cookies.md b/docs/api/cookies.md index 060034a16c1f..ba3cff33609f 100644 --- a/docs/api/cookies.md +++ b/docs/api/cookies.md @@ -105,6 +105,8 @@ on complete. Removes the cookies matching `url` and `name`, `callback` will called with `callback()` on complete. -#### `cookies.flushStore()` +#### `cookies.flushStore(callback)` + +* `callback` Function Writes any unwritten cookies data to disk. From fe88697348a88b975564afb1b89795d58af77cf8 Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Mon, 17 Apr 2017 04:37:10 -0700 Subject: [PATCH 265/337] fixup! fixup! Adding cookie flush store api --- atom/browser/api/atom_api_cookies.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_cookies.cc b/atom/browser/api/atom_api_cookies.cc index d3607fe50259..2ce9e12f6c5b 100644 --- a/atom/browser/api/atom_api_cookies.cc +++ b/atom/browser/api/atom_api_cookies.cc @@ -180,8 +180,9 @@ void OnSetCookie(const Cookies::SetCallback& callback, bool success) { } // Flushes cookie store in IO thread. -void FlushCookieStoreOnIOThread(scoped_refptr getter, - const base::Closure& callback) { +void FlushCookieStoreOnIOThread( + scoped_refptr getter, + const base::Closure& callback) { GetCookieStore(getter)->FlushStore(base::Bind(RunCallbackInUI, callback)); } From 8f0ac057e303558877cdf9630802b194f44c52a7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 09:08:27 -0700 Subject: [PATCH 266/337] Add initial spec for cookies.flushStore --- spec/api-session-spec.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index c34cdfdab0ff..d361c10d947e 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -219,6 +219,21 @@ describe('session module', function () { if (error) return done(error) }) }) + + describe('ses.cookies.flushStore(callback)', function () { + it('flushes the cookies to disk and invokes the callback when done', function (done) { + session.defaultSession.cookies.set({ + url: url, + name: 'foo', + value: 'bar' + }, (error) => { + if (error) return done(error) + session.defaultSession.cookies.flushStore(() => { + done() + }) + }) + }) + }) }) describe('ses.clearStorageData(options)', function () { From 4a9383b50bc2f15f42c027d7369e4a8129820cf1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 09:17:16 -0700 Subject: [PATCH 267/337] Bump v1.6.7 --- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- electron.gyp | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 5509969014a1..ecd6a28b5cdf 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 1.6.6 + 1.6.7 CFBundleShortVersionString - 1.6.6 + 1.6.7 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index d572d20ada20..f7a9b32351b7 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 1,6,6,0 - PRODUCTVERSION 1,6,6,0 + FILEVERSION 1,6,7,0 + PRODUCTVERSION 1,6,7,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "1.6.6" + VALUE "FileVersion", "1.6.7" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "1.6.6" + VALUE "ProductVersion", "1.6.7" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 3afa163b90aa..79ece65408bf 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 1 #define ATOM_MINOR_VERSION 6 -#define ATOM_PATCH_VERSION 6 +#define ATOM_PATCH_VERSION 7 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/electron.gyp b/electron.gyp index 8c3718b1cd60..ce3673abf114 100644 --- a/electron.gyp +++ b/electron.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '1.6.6', + 'version%': '1.6.7', 'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c', }, 'includes': [ diff --git a/package.json b/package.json index c34a27e2751c..bfb35f29689a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "1.6.6", + "version": "1.6.7", "devDependencies": { "asar": "^0.11.0", "browserify": "^13.1.0", From 4af44b1be69abec3dcffc5e6ad060b632c514898 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 16:04:27 -0700 Subject: [PATCH 268/337] Consolidate window closing --- spec/chromium-spec.js | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index a54c6744f7c8..2f8c24c2580f 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -13,6 +13,7 @@ const isCI = remote.getGlobal('isCi') describe('chromium feature', function () { var fixtures = path.resolve(__dirname, 'fixtures') var listener = null + let w = null afterEach(function () { if (listener != null) { @@ -21,6 +22,10 @@ describe('chromium feature', function () { listener = null }) + afterEach(function () { + return closeWindow(w).then(function () { w = null }) + }) + describe('heap snapshot', function () { it('does not crash', function () { if (process.env.TRAVIS === 'true') return @@ -44,11 +49,6 @@ describe('chromium feature', function () { describe('document.hidden', function () { var url = 'file://' + fixtures + '/pages/document-hidden.html' - var w = null - - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) it('is set correctly when window is not shown', function (done) { w = new BrowserWindow({ @@ -119,7 +119,7 @@ describe('chromium feature', function () { } const deviceIds = [] const ses = session.fromPartition('persist:media-device-id') - let w = new BrowserWindow({ + w = new BrowserWindow({ show: false, webPreferences: { session: ses @@ -155,11 +155,6 @@ describe('chromium feature', function () { describe('navigator.serviceWorker', function () { var url = 'file://' + fixtures + '/pages/service-worker/index.html' - var w = null - - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) it('should register for file scheme', function (done) { w = new BrowserWindow({ @@ -188,12 +183,6 @@ describe('chromium feature', function () { return } - let w = null - - afterEach(() => { - return closeWindow(w).then(function () { w = null }) - }) - it('returns a BrowserWindowProxy object', function () { var b = window.open('about:blank', '', 'show=no') assert.equal(b.closed, false) @@ -343,11 +332,6 @@ describe('chromium feature', function () { describe('window.opener', function () { let url = 'file://' + fixtures + '/pages/window-opener.html' - let w = null - - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) it('is null for main window', function (done) { w = new BrowserWindow({ @@ -849,7 +833,6 @@ describe('chromium feature', function () { }) describe('PDF Viewer', function () { - let w = null const pdfSource = url.format({ pathname: path.join(fixtures, 'assets', 'cat.pdf').replace(/\\/g, '/'), protocol: 'file', @@ -865,10 +848,6 @@ describe('chromium feature', function () { }) }) - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) - it('opens when loading a pdf resource as top level navigation', function (done) { ipcMain.once('pdf-loaded', function (event, success) { if (success) done() From f891df55d443eb425769753d186920123da505e1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 16:06:10 -0700 Subject: [PATCH 269/337] Call done callback with Error --- spec/chromium-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 2f8c24c2580f..a67c109a5ed9 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -107,7 +107,7 @@ describe('chromium feature', function () { if (labelFound) { done() } else { - done('No device labels found: ' + JSON.stringify(labels)) + done(new Error(`No device labels found: ${JSON.stringify(labels)}`)) } }).catch(done) }) From 5153c1f353b093c929affad9ef02e5e5df5159d6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 16:16:08 -0700 Subject: [PATCH 270/337] Disable media device specs on CI where they may not be available --- spec/chromium-spec.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index a67c109a5ed9..6a5937bbce26 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -90,13 +90,7 @@ describe('chromium feature', function () { }) describe('navigator.mediaDevices', function () { - if (process.env.TRAVIS === 'true') { - return - } - if (isCI && process.platform === 'linux') { - return - } - if (isCI && process.platform === 'win32') { + if (isCI) { return } From 6b13fab83a32462c93163c17bdf3074516640df8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 18 Apr 2017 16:42:01 -0700 Subject: [PATCH 271/337] Wait for full screen event before leaving kiosk mode --- spec/api-browser-window-spec.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index d83c173f26f1..a50ff0bc0d07 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -1474,13 +1474,19 @@ describe('BrowserWindow module', function () { // Only implemented on macOS. if (process.platform !== 'darwin') return - it('can be changed with setKiosk method', function () { + it('can be changed with setKiosk method', function (done) { w.destroy() w = new BrowserWindow() w.setKiosk(true) assert.equal(w.isKiosk(), true) - w.setKiosk(false) - assert.equal(w.isKiosk(), false) + + w.once('enter-full-screen', () => { + w.setKiosk(false) + assert.equal(w.isKiosk(), false) + }) + w.once('leave-full-screen', () => { + done() + }) }) }) From c05c324464cfe72439b2573ff3c8adfff44ed54a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 19 Apr 2017 09:28:52 -0700 Subject: [PATCH 272/337] Remove extra space in description --- spec/api-crash-reporter-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index a0fde2d54fe9..b5ae5ae8a70d 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -176,7 +176,7 @@ describe('crashReporter module', function () { } generateSpecs('without sandbox', {}) - generateSpecs('with sandbox ', { + generateSpecs('with sandbox', { webPreferences: { sandbox: true, preload: path.join(fixtures, 'module', 'preload-sandbox.js') From ece4df0ac7b23d4d9c6324862be8a8ff99e2ac7e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 19 Apr 2017 09:30:03 -0700 Subject: [PATCH 273/337] Increase timeout to 2 minutes --- spec/api-crash-reporter-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index b5ae5ae8a70d..8e22c8a1e0dd 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -157,7 +157,7 @@ describe('crashReporter module', function () { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() - this.timeout(10000) + this.timeout(120000) startServer({ callback (port) { From 4d9cdad37a8c1832491127958608f09f84e5e105 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 19 Apr 2017 09:48:32 -0700 Subject: [PATCH 274/337] Close server and connections after each spec --- spec/api-crash-reporter-spec.js | 38 ++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 8e22c8a1e0dd..ca30cacb7f32 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -33,8 +33,10 @@ describe('crashReporter module', function () { const generateSpecs = (description, browserWindowOpts) => { describe(description, function () { var w = null + var stopServer = null beforeEach(function () { + stopServer = null w = new BrowserWindow(Object.assign({ show: false }, browserWindowOpts)) @@ -44,13 +46,19 @@ describe('crashReporter module', function () { return closeWindow(w).then(function () { w = null }) }) + afterEach(function (done) { + if (stopServer != null) { + stopServer(done) + } + }) + it('should send minidump when renderer crashes', function (done) { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() this.timeout(120000) - startServer({ + stopServer = startServer({ callback (port) { const crashUrl = url.format({ protocol: 'file', @@ -70,7 +78,7 @@ describe('crashReporter module', function () { this.timeout(120000) - startServer({ + stopServer = startServer({ callback (port) { const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`) const version = app.getVersion() @@ -85,7 +93,6 @@ describe('crashReporter module', function () { it('should not send minidump if uploadToServer is false', function (done) { this.timeout(120000) - let server let dumpFile let crashesDir = crashReporter.getCrashesDirectory() const existingDumpFiles = new Set() @@ -98,7 +105,6 @@ describe('crashReporter module', function () { if (uploaded) { return done(new Error('fail')) } - server.close() if (process.platform === 'darwin') { crashReporter.setUploadToServer(true) } @@ -139,7 +145,7 @@ describe('crashReporter module', function () { }) }) - server = startServer({ + stopServer = startServer({ callback (port) { const crashUrl = url.format({ protocol: 'file', @@ -159,7 +165,7 @@ describe('crashReporter module', function () { this.timeout(120000) - startServer({ + stopServer = startServer({ callback (port) { const crashUrl = url.format({ protocol: 'file', @@ -254,7 +260,6 @@ const waitForCrashReport = () => { const startServer = ({callback, processType, done}) => { var called = false var server = http.createServer((req, res) => { - server.close() var form = new multiparty.Form() form.parse(req, (error, fields) => { if (error) throw error @@ -283,6 +288,15 @@ const startServer = ({callback, processType, done}) => { }) }) }) + + const activeConnections = new Set() + server.on('connection', (connection) => { + activeConnections.add(connection) + connection.once('close', () => { + activeConnections.delete(connection) + }) + }) + let {port} = remote.process server.listen(port, '127.0.0.1', () => { port = server.address().port @@ -295,5 +309,13 @@ const startServer = ({callback, processType, done}) => { } callback(port) }) - return server + + return function stopServer (done) { + for (const connection of activeConnections) { + connection.destroy() + } + server.close(function () { + done() + }) + } } From a7a92e1cd30b3c4ee1f2040c460bfeb325a5b675 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 19 Apr 2017 09:52:28 -0700 Subject: [PATCH 275/337] Still call done when stop server function is null --- spec/api-crash-reporter-spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index ca30cacb7f32..e016b05f1d48 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -49,6 +49,8 @@ describe('crashReporter module', function () { afterEach(function (done) { if (stopServer != null) { stopServer(done) + } else { + done() } }) From de62f1ea6cd7015d1c4cf951cbe7f054d87dc0e4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 19 Apr 2017 16:32:43 -0700 Subject: [PATCH 276/337] Restart crash service in each spec --- lib/common/api/crash-reporter.js | 2 +- spec/api-crash-reporter-spec.js | 37 ++++++++++++++++++++++++++-- spec/fixtures/api/crash-restart.html | 6 ++++- spec/fixtures/api/crash.html | 5 ++++ spec/static/main.js | 10 +++++++- 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lib/common/api/crash-reporter.js b/lib/common/api/crash-reporter.js index 658622e8f5a7..7a54e24fbc2a 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/api/crash-reporter.js @@ -56,7 +56,7 @@ class CrashReporter { const env = { ELECTRON_INTERNAL_CRASH_SERVICE: 1 } - spawn(process.execPath, args, { + this._crashServiceProcess = spawn(process.execPath, args, { env: env, detached: true }) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index e016b05f1d48..3ed81c40b147 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -46,6 +46,10 @@ describe('crashReporter module', function () { return closeWindow(w).then(function () { w = null }) }) + afterEach(function () { + stopCrashService() + }) + afterEach(function (done) { if (stopServer != null) { stopServer(done) @@ -82,9 +86,24 @@ describe('crashReporter module', function () { stopServer = startServer({ callback (port) { - const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`) + const crashesDir = path.join(app.getPath('temp'), `Zombies Crashes`) const version = app.getVersion() const crashPath = path.join(fixtures, 'module', 'crash.js') + + if (process.platform === 'win32') { + const crashServiceProcess = childProcess.spawn(process.execPath, [ + `--reporter-url=http://127.0.0.1:${port}`, + '--application-name=Zombies', + `--crashes-directory=${crashesDir}` + ], { + env: { + ELECTRON_INTERNAL_CRASH_SERVICE: 1 + }, + detached: true + }) + remote.process.crashServicePid = crashServiceProcess.pid + } + childProcess.fork(crashPath, [port, version, crashesDir], {silent: true}) }, processType: 'browser', @@ -105,7 +124,7 @@ describe('crashReporter module', function () { } const testDone = (uploaded) => { if (uploaded) { - return done(new Error('fail')) + return done(new Error('Uploaded crash report')) } if (process.platform === 'darwin') { crashReporter.setUploadToServer(true) @@ -321,3 +340,17 @@ const startServer = ({callback, processType, done}) => { }) } } + +const stopCrashService = () => { + const {crashServicePid} = remote.process + if (crashServicePid) { + remote.process.crashServicePid = 0 + try { + process.kill(crashServicePid) + } catch (error) { + if (error.code !== 'ESRCH') { + throw error + } + } + } +} diff --git a/spec/fixtures/api/crash-restart.html b/spec/fixtures/api/crash-restart.html index 2f55c539bbd8..22f3b45b5c82 100644 --- a/spec/fixtures/api/crash-restart.html +++ b/spec/fixtures/api/crash-restart.html @@ -3,7 +3,7 @@ +
Docs @@ -162,25 +162,15 @@ Console (or Terminal):

- +

 
     

The path-to-your-app should be the path to your own Electron app.

-

You can read the - - guide in Electron's - +

You can read the quick start + guide in Electron's docs to learn how to write one.

@@ -214,6 +204,12 @@ }).unref(); return false; }; + + const version = process.versions.electron; + document.querySelector('.header-version').innerText = version; + document.querySelector('.command-example').innerText = command; + document.querySelector('.quick-start-link').href = `https://github.com/electron/electron/blob/v${version}/docs/tutorial/quick-start.md`; + document.querySelector('.docs-link').href = `https://github.com/electron/electron/tree/v${version}/docs#readme`; From a00d36fb071be1344396ee90279cb5bbadcf9e0e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 12:19:37 -0700 Subject: [PATCH 295/337] Add spec for alert/confirm toString errors --- spec/chromium-spec.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 6a5937bbce26..4c5b85521ac2 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -880,4 +880,28 @@ describe('chromium feature', function () { }) }) }) + + describe('window.alert(message, title)', function () { + it('throws an exception when the arguments cannot be converted to strings', function () { + assert.throws(function () { + window.alert({toString: null}) + }, /Cannot convert object to primitive value/) + + assert.throws(function () { + window.alert('message', {toString: 3}) + }, /Cannot convert object to primitive value/) + }) + }) + + describe('window.confirm(message, title)', function () { + it('throws an exception when the arguments cannot be converted to strings', function () { + assert.throws(function () { + window.confirm({toString: null}, 'title') + }, /Cannot convert object to primitive value/) + + assert.throws(function () { + window.confirm('message', {toString: 3}) + }, /Cannot convert object to primitive value/) + }) + }) }) From c90fd4dc888662599a2f13d60eb39849db926abc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 12:21:05 -0700 Subject: [PATCH 296/337] Convert message/title to strings in render process --- lib/renderer/window-setup.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/renderer/window-setup.js b/lib/renderer/window-setup.js index 21f0741a22aa..d29133c88f0b 100644 --- a/lib/renderer/window-setup.js +++ b/lib/renderer/window-setup.js @@ -121,11 +121,11 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => { } window.alert = function (message, title) { - ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title) + ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', `${message}`, `${title}`) } window.confirm = function (message, title) { - return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title) + return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', `${message}`, `${title}`) } // But we do not support prompt(). From 35a627fd603b4f340aa60eaaf397c0dad985b9b2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 12:29:46 -0700 Subject: [PATCH 297/337] Log all crashes during specs --- spec/static/main.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/spec/static/main.js b/spec/static/main.js index 033a0c5546cf..7e56da623bf8 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -2,20 +2,15 @@ process.throwDeprecation = true const electron = require('electron') -const app = electron.app -const crashReporter = electron.crashReporter -const ipcMain = electron.ipcMain -const dialog = electron.dialog -const BrowserWindow = electron.BrowserWindow -const protocol = electron.protocol -const webContents = electron.webContents -const v8 = require('v8') +const {app, BrowserWindow, crashReporter, dialog, ipcMain, protocol, webContents} = electron + +const {Coverage} = require('electabul') -const Coverage = require('electabul').Coverage const fs = require('fs') const path = require('path') const url = require('url') const util = require('util') +const v8 = require('v8') var argv = require('yargs') .boolean('ci') @@ -103,6 +98,12 @@ app.on('window-all-closed', function () { app.quit() }) +app.on('web-contents-created', (event, contents) => { + contents.on('crashed', (event, killed) => { + console.log(`webContents ${contents.id} crashed: ${contents.getURL()} (killed=${killed})`) + }) +}) + app.on('ready', function () { // Test if using protocol module would crash. electron.protocol.registerStringProtocol('test-if-crashes', function () {}) From 423dd4d57aebd8ba83b8a291d95618b71eb5b5e0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 15:12:08 -0700 Subject: [PATCH 298/337] Add spec for remote autoUpdater error event --- spec/api-auto-updater-spec.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/spec/api-auto-updater-spec.js b/spec/api-auto-updater-spec.js index 0716c2245df8..3e2be93d1381 100644 --- a/spec/api-auto-updater-spec.js +++ b/spec/api-auto-updater-spec.js @@ -1,6 +1,6 @@ const assert = require('assert') -const autoUpdater = require('electron').remote.autoUpdater -const ipcRenderer = require('electron').ipcRenderer +const {autoUpdater} = require('electron').remote +const {ipcRenderer} = require('electron') // Skip autoUpdater tests in MAS build. if (!process.mas) { @@ -64,5 +64,21 @@ if (!process.mas) { autoUpdater.quitAndInstall() }) }) + + describe('error event', function () { + it('serializes correctly over the remote module', function (done) { + autoUpdater.once('error', function (error) { + assert.equal(error instanceof Error, true) + assert.deepEqual(Object.getOwnPropertyNames(error), ['stack', 'message', 'name']) + done() + }) + + autoUpdater.setFeedURL('') + + if (process.platform === 'win32') { + autoUpdater.checkForUpdates() + } + }) + }) }) } From 13e4582697e8df68c8271ac6c813e81ec20722a1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 15:13:43 -0700 Subject: [PATCH 299/337] Emit autoUpdater error directly as Error object --- atom/browser/api/atom_api_auto_updater.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index ea3024191e97..c23e488f64fd 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -7,6 +7,7 @@ #include "atom/browser/browser.h" #include "atom/browser/native_window.h" #include "atom/browser/window_list.h" +#include "atom/common/api/event_emitter_caller.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/node_includes.h" #include "base/time/time.h" @@ -47,7 +48,9 @@ void AutoUpdater::OnError(const std::string& message) { v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); auto error = v8::Exception::Error(mate::StringToV8(isolate(), message)); - EmitCustomEvent( + mate::EmitEvent( + isolate(), + GetWrapper(), "error", error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(), // Message is also emitted to keep compatibility with old code. From c2d4c93e12da6af51158bb31fd46f7f6ba261813 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 16:50:19 -0700 Subject: [PATCH 300/337] Don't run error event on Linux --- spec/api-auto-updater-spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/api-auto-updater-spec.js b/spec/api-auto-updater-spec.js index 3e2be93d1381..df77822e456d 100644 --- a/spec/api-auto-updater-spec.js +++ b/spec/api-auto-updater-spec.js @@ -67,6 +67,10 @@ if (!process.mas) { describe('error event', function () { it('serializes correctly over the remote module', function (done) { + if (process.platform === 'linux') { + return done() + } + autoUpdater.once('error', function (error) { assert.equal(error instanceof Error, true) assert.deepEqual(Object.getOwnPropertyNames(error), ['stack', 'message', 'name']) From 9e70372c1fa408946bfbd8339ad65f583d6c9d73 Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Mon, 24 Apr 2017 10:16:11 -0700 Subject: [PATCH 301/337] change endsession event name to session-end --- atom/browser/api/atom_api_window.cc | 2 +- docs/api/browser-window.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 1914899297d8..95168efe9abd 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -193,7 +193,7 @@ void Window::OnWindowClosed() { #if defined(OS_WIN) void Window::OnWindowEndSession() { - Emit("endsession"); + Emit("session-end"); } #endif diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 2147645b21e0..8fcc3f8213d0 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -376,7 +376,7 @@ window.onbeforeunload = (e) => { Emitted when the window is closed. After you have received this event you should remove the reference to the window and avoid using it any more. -#### Event: 'endsession' _Windows_ +#### Event: 'session-end' _Windows_ Emitted when window session is going to end due to force shutdown or machine restart or session log off. From 8a328268763d23377bfb06f573c5942077f26645 Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Mon, 24 Apr 2017 11:49:21 -0700 Subject: [PATCH 302/337] Removing #ifdef windows for endsession methods --- atom/browser/api/atom_api_window.h | 2 +- atom/browser/native_window.cc | 2 -- atom/browser/native_window.h | 2 +- atom/browser/native_window_observer.h | 4 +++- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 9620a6bf4af7..75f0328ba64f 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -63,6 +63,7 @@ class Window : public mate::TrackableObject, void WillCloseWindow(bool* prevent_default) override; void WillDestroyNativeObject() override; void OnWindowClosed() override; + void OnWindowEndSession() override; void OnWindowBlur() override; void OnWindowFocus() override; void OnWindowShow() override; @@ -92,7 +93,6 @@ class Window : public mate::TrackableObject, const base::DictionaryValue& details) override; #if defined(OS_WIN) - void Window::OnWindowEndSession() override; void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override; #endif diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index f97e34378aaa..9e2c11aec4ab 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -474,12 +474,10 @@ void NativeWindow::NotifyWindowClosed() { observer.OnWindowClosed(); } -#if defined(OS_WIN) void NativeWindow::NotifyWindowEndSession() { for (NativeWindowObserver& observer : observers_) observer.OnWindowEndSession(); } -#endif void NativeWindow::NotifyWindowBlur() { for (NativeWindowObserver& observer : observers_) diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index f8c75352ed93..d3f18d8fb95c 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -218,6 +218,7 @@ class NativeWindow : public base::SupportsUserData, // Public API used by platform-dependent delegates and observers to send UI // related notifications. void NotifyWindowClosed(); + void NotifyWindowEndSession(); void NotifyWindowBlur(); void NotifyWindowFocus(); void NotifyWindowShow(); @@ -244,7 +245,6 @@ class NativeWindow : public base::SupportsUserData, const base::DictionaryValue& details); #if defined(OS_WIN) - void NotifyWindowEndSession(); void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param); #endif diff --git a/atom/browser/native_window_observer.h b/atom/browser/native_window_observer.h index ba99b5b0c87e..8c908dc8237a 100644 --- a/atom/browser/native_window_observer.h +++ b/atom/browser/native_window_observer.h @@ -40,6 +40,9 @@ class NativeWindowObserver { // Called when the window is closed. virtual void OnWindowClosed() {} + // Called when Windows sends WM_ENDSESSION message + virtual void OnWindowEndSession() {} + // Called when window loses focus. virtual void OnWindowBlur() {} @@ -78,7 +81,6 @@ class NativeWindowObserver { // Called when window message received #if defined(OS_WIN) - virtual void OnWindowEndSession() {} virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {} #endif From 8458acff2600b2d2384c653b23ecaea74306be94 Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Mon, 24 Apr 2017 11:58:08 -0700 Subject: [PATCH 303/337] Removing #ifdef on endsession api --- atom/browser/api/atom_api_window.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 95168efe9abd..72b8e33ef7b5 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -191,11 +191,9 @@ void Window::OnWindowClosed() { FROM_HERE, GetDestroyClosure()); } -#if defined(OS_WIN) void Window::OnWindowEndSession() { Emit("session-end"); } -#endif void Window::OnWindowBlur() { Emit("blur"); From ca5a8b6166e7ae4d9677d44c9fcc4d0804e322a4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 24 Apr 2017 11:54:05 -0700 Subject: [PATCH 304/337] Extract script tags to renderer.js file --- default_app/index.html | 44 +--------------------------------------- default_app/renderer.js | 45 +++++++++++++++++++++++++++++++++++++++++ filenames.gypi | 1 + 3 files changed, 47 insertions(+), 43 deletions(-) create mode 100644 default_app/renderer.js diff --git a/default_app/index.html b/default_app/index.html index 86100e19dd84..41b5396360db 100644 --- a/default_app/index.html +++ b/default_app/index.html @@ -113,24 +113,6 @@ - -
diff --git a/default_app/renderer.js b/default_app/renderer.js new file mode 100644 index 000000000000..6196195eab93 --- /dev/null +++ b/default_app/renderer.js @@ -0,0 +1,45 @@ +const {remote, shell} = require('electron') +const {execFile} = require('child_process') + +const {execPath} = remote.process + +document.onclick = function (e) { + e.preventDefault() + if (e.target.tagName === 'A') { + shell.openExternal(e.target.href) + } + return false +} + +document.ondragover = document.ondrop = function (e) { + e.preventDefault() + return false +} + +const holder = document.getElementById('holder') +holder.ondragover = function () { + this.className = 'hover' + return false +} + +holder.ondragleave = holder.ondragend = function () { + this.className = '' + return false +} + +holder.ondrop = function (e) { + this.className = '' + e.preventDefault() + + const file = e.dataTransfer.files[0] + execFile(execPath, [file.path], { + detached: true, stdio: 'ignore' + }).unref() + return false +} + +const version = process.versions.electron +document.querySelector('.header-version').innerText = version +document.querySelector('.command-example').innerText = `${execPath} path-to-your-app` +document.querySelector('.quick-start-link').href = `https://github.com/electron/electron/blob/v${version}/docs/tutorial/quick-start.md` +document.querySelector('.docs-link').href = `https://github.com/electron/electron/tree/v${version}/docs#readme` diff --git a/filenames.gypi b/filenames.gypi index 8f14b298837b..6107ab956e60 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -89,6 +89,7 @@ 'default_app/index.html', 'default_app/main.js', 'default_app/package.json', + 'default_app/renderer.js', ], 'lib_sources': [ 'atom/app/atom_content_client.cc', From 6ec74060b4dae3f44c7d73358071f44ad77a01b3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 10:57:22 -0700 Subject: [PATCH 305/337] Enable setting javascript and contextIsolation via window.open --- lib/browser/guest-window-manager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index e5bfa7412386..e96fc12ac585 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -48,7 +48,7 @@ const mergeBrowserWindowOptions = function (embedder, options) { options.webPreferences.nodeIntegration = false } - // Enable context isolation on child window if enable on parent window + // Enable context isolation on child window if enabled on parent window if (embedder.getWebPreferences().contextIsolation === true) { options.webPreferences.contextIsolation = true } @@ -186,7 +186,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName, const options = {} const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor'] - const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload'] + const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload', 'javascript', 'contextIsolation'] const disposition = 'new-window' // Used to store additional features From cee050709017144e567c7b6ca1494e56ddc93ade Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 10:58:47 -0700 Subject: [PATCH 306/337] Add failing spec for inheriting Javascript web preference --- spec/chromium-spec.js | 25 +++++++++++++++++++ spec/fixtures/pages/window-no-javascript.html | 12 +++++++++ 2 files changed, 37 insertions(+) create mode 100644 spec/fixtures/pages/window-no-javascript.html diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 4c5b85521ac2..977f25e10359 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -229,6 +229,31 @@ describe('chromium feature', function () { b = window.open(windowUrl, '', 'nodeIntegration=no,show=no') }) + it('disables JavaScript when it is disabled on the parent window', function (done) { + var b + app.once('web-contents-created', (event, contents) => { + contents.once('did-finish-load', () => { + app.once('browser-window-created', (event, window) => { + const preferences = window.webContents.getWebPreferences() + assert.equal(preferences.javascript, false) + window.destroy() + b.close() + done() + }) + // Click link on page + contents.sendInputEvent({type: 'mouseDown', clickCount: 1, x: 1, y: 1}) + contents.sendInputEvent({type: 'mouseUp', clickCount: 1, x: 1, y: 1}) + }) + }) + + var windowUrl = require('url').format({ + pathname: `${fixtures}/pages/window-no-javascript.html`, + protocol: 'file', + slashes: true + }) + b = window.open(windowUrl, '', 'javascript=no,show=no') + }) + it('does not override child options', function (done) { var b, size size = { diff --git a/spec/fixtures/pages/window-no-javascript.html b/spec/fixtures/pages/window-no-javascript.html new file mode 100644 index 000000000000..9c38c9e0bba4 --- /dev/null +++ b/spec/fixtures/pages/window-no-javascript.html @@ -0,0 +1,12 @@ + + + + +CLICK + + From 3e2a1034af80c369e7c3d89dcbee9965eb5611a7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 10:59:33 -0700 Subject: [PATCH 307/337] Disable JavaScript on child when disabled on parent --- lib/browser/guest-window-manager.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index e96fc12ac585..8a8e9f46b8fe 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -53,6 +53,11 @@ const mergeBrowserWindowOptions = function (embedder, options) { options.webPreferences.contextIsolation = true } + // Disable JavaScript on child window if disabled on parent window + if (embedder.getWebPreferences().javascript === false) { + options.webPreferences.javascript = false + } + // Sets correct openerId here to give correct options to 'new-window' event handler options.webPreferences.openerId = embedder.id From 87db1b8aa718530a7b9ad050d145d21dee985cc4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 21 Apr 2017 11:00:31 -0700 Subject: [PATCH 308/337] Document other inherited web preferences --- docs/api/window-open.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/window-open.md b/docs/api/window-open.md index 56216f551a0f..41332aa6cfd2 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -30,6 +30,10 @@ has to be a field of `BrowserWindow`'s options. * Node integration will always be disabled in the opened `window` if it is disabled on the parent window. +* Context isolation will always be enabled in the opened `window` if it is + enabled on the parent window. +* JavaScript will always be disabled in the opened `window` if it is disabled on + the parent window. * Non-standard features (that are not handled by Chromium or Electron) given in `features` will be passed to any registered `webContent`'s `new-window` event handler in the `additionalFeatures` argument. From 3f88eb2f867f4340320b378a18605bd060fc97f5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 24 Apr 2017 10:25:12 -0700 Subject: [PATCH 309/337] Add spec for chrome-devtools URL with no node integration --- spec/chromium-spec.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 977f25e10359..9cce9fe2808a 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -229,6 +229,20 @@ describe('chromium feature', function () { b = window.open(windowUrl, '', 'nodeIntegration=no,show=no') }) + it('disables node integration when it is disabled on the parent window for chrome devtools URLs', function (done) { + var b + app.once('web-contents-created', (event, contents) => { + contents.once('did-finish-load', () => { + contents.executeJavaScript('typeof process').then((typeofProcessGlobal) => { + assert.equal(typeofProcessGlobal, 'undefined') + b.close() + done() + }).catch(done) + }) + }) + b = window.open('chrome-devtools://devtools/bundled/inspector.html', '', 'nodeIntegration=no,show=no') + }) + it('disables JavaScript when it is disabled on the parent window', function (done) { var b app.once('web-contents-created', (event, contents) => { From 05b6d91bf4c1e0ee65eeef70cd5d1bd1df125644 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 24 Apr 2017 10:25:40 -0700 Subject: [PATCH 310/337] Disable node integration in chrome-devtools: URLs --- lib/renderer/init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/renderer/init.js b/lib/renderer/init.js index 0306463bc486..9b7ea9dabdb6 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -78,7 +78,7 @@ for (let arg of process.argv) { if (window.location.protocol === 'chrome-devtools:') { // Override some inspector APIs. require('./inspector') - nodeIntegration = 'true' + nodeIntegration = 'false' } else if (window.location.protocol === 'chrome-extension:') { // Add implementations of chrome API. require('./chrome-api').injectTo(window.location.hostname, isBackgroundPage, window) From 7e285711ca7d72a45bcec19039796354a9abbc6c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 13:16:07 -0700 Subject: [PATCH 311/337] Add spec for window.open toString errors --- spec/chromium-spec.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 9cce9fe2808a..dd992dc0ae5a 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -361,6 +361,16 @@ describe('chromium feature', function () { }) b = window.open() }) + + it('throws an exception when the arguments cannot be converted to strings', function () { + assert.throws(function () { + window.open('', {toString: null}) + }, /Cannot convert object to primitive value/) + + assert.throws(function () { + window.open('', '', {toString: 3}) + }, /Cannot convert object to primitive value/) + }) }) describe('window.opener', function () { From 3894c1c625c568d77a539fb8ff60b39145e43e20 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 13:16:28 -0700 Subject: [PATCH 312/337] Convert frameName/features to strings in render process --- lib/renderer/window-setup.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/renderer/window-setup.js b/lib/renderer/window-setup.js index d29133c88f0b..0bd43fb9a1a0 100644 --- a/lib/renderer/window-setup.js +++ b/lib/renderer/window-setup.js @@ -32,6 +32,10 @@ const resolveURL = function (url) { return a.href } +const toString = (value) => { + return value != null ? `${value}` : value +} + const windowProxies = {} const getOrCreateProxy = (ipcRenderer, guestId) => { @@ -112,7 +116,7 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => { if (url != null && url !== '') { url = resolveURL(url) } - const guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, features) + const guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, toString(frameName), toString(features)) if (guestId != null) { return getOrCreateProxy(ipcRenderer, guestId) } else { @@ -121,11 +125,11 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => { } window.alert = function (message, title) { - ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', `${message}`, `${title}`) + ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', toString(message), toString(title)) } window.confirm = function (message, title) { - return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', `${message}`, `${title}`) + return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', toString(message), toString(title)) } // But we do not support prompt(). From 246937a37209810779d43bd2c02c71174df29f28 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 13:26:47 -0700 Subject: [PATCH 313/337] Convert targetOrigin to string in render process --- lib/renderer/window-setup.js | 5 ++++- spec/chromium-spec.js | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/renderer/window-setup.js b/lib/renderer/window-setup.js index 0bd43fb9a1a0..87a31f06240b 100644 --- a/lib/renderer/window-setup.js +++ b/lib/renderer/window-setup.js @@ -32,6 +32,9 @@ const resolveURL = function (url) { return a.href } +// Use this method to ensure value expected as string in the main process +// are convertible to string in the renderer process. This ensures exceptions +// converting values to string are thrown in this process. const toString = (value) => { return value != null ? `${value}` : value } @@ -86,7 +89,7 @@ function BrowserWindowProxy (ipcRenderer, guestId) { } this.postMessage = (message, targetOrigin) => { - ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', guestId, message, targetOrigin, window.location.origin) + ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', guestId, message, toString(targetOrigin), window.location.origin) } this.eval = (...args) => { diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index dd992dc0ae5a..b0ae69af51f8 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -548,6 +548,14 @@ describe('chromium feature', function () { }) b = window.open('file://' + fixtures + '/pages/window-open-postMessage.html', '', 'show=no') }) + + it('throws an exception when the targetOrigin cannot be converted to a string', function () { + var b = window.open('') + assert.throws(function () { + b.postMessage('test', {toString: null}) + }, /Cannot convert object to primitive value/) + b.close() + }) }) describe('window.opener.postMessage', function () { From 2c48300daa487fdfab0c9786e3aa2ffe467d89c5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 26 Apr 2017 09:09:42 -0700 Subject: [PATCH 314/337] Fix typos in comment --- lib/renderer/window-setup.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/renderer/window-setup.js b/lib/renderer/window-setup.js index 87a31f06240b..5ccb6fec463d 100644 --- a/lib/renderer/window-setup.js +++ b/lib/renderer/window-setup.js @@ -32,9 +32,9 @@ const resolveURL = function (url) { return a.href } -// Use this method to ensure value expected as string in the main process -// are convertible to string in the renderer process. This ensures exceptions -// converting values to string are thrown in this process. +// Use this method to ensure values expected as strings in the main process +// are convertible to strings in the renderer process. This ensures exceptions +// converting values to strings are thrown in this process. const toString = (value) => { return value != null ? `${value}` : value } From 9643b2a5c52e4d81b4d267920cd78f42027244a1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 13:52:56 -0700 Subject: [PATCH 315/337] Add specs for window.open frameName argument --- spec/chromium-spec.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index b0ae69af51f8..1b88d78e2ab3 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -371,6 +371,26 @@ describe('chromium feature', function () { window.open('', '', {toString: 3}) }, /Cannot convert object to primitive value/) }) + + it('sets the window title to the specified frameName', function (done) { + let b + app.once('browser-window-created', (event, createdWindow) => { + assert.equal(createdWindow.getTitle(), 'hello') + b.close() + done() + }) + b = window.open('', 'hello') + }) + + it('does not throw an exception when the frameName is a built-in object property', function (done) { + let b + app.once('browser-window-created', (event, createdWindow) => { + assert.equal(createdWindow.getTitle(), '__proto__') + b.close() + done() + }) + b = window.open('', '__proto__') + }) }) describe('window.opener', function () { From 91a1e5cdfef0e7efed130de5aff0d83af629c970 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 13:53:29 -0700 Subject: [PATCH 316/337] Store frame to guests in map --- lib/browser/guest-window-manager.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index 8a8e9f46b8fe..33ec15a101d4 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -5,7 +5,7 @@ const {isSameOrigin} = process.atomBinding('v8_util') const parseFeaturesString = require('../common/parse-features-string') const hasProp = {}.hasOwnProperty -const frameToGuest = {} +const frameToGuest = new Map() // Copy attribute of |parent| to |child| if it is not defined in |child|. const mergeOptions = function (child, parent, visited) { @@ -92,10 +92,10 @@ const setupGuest = function (embedder, frameName, guest, options) { guest.once('closed', closedByUser) } if (frameName) { - frameToGuest[frameName] = guest + frameToGuest.set(frameName, guest) guest.frameName = frameName guest.once('closed', function () { - delete frameToGuest[frameName] + frameToGuest.delete(frameName) }) } return guestId @@ -103,7 +103,7 @@ const setupGuest = function (embedder, frameName, guest, options) { // Create a new guest created by |embedder| with |options|. const createGuest = function (embedder, url, frameName, options, postData) { - let guest = frameToGuest[frameName] + let guest = frameToGuest.get(frameName) if (frameName && (guest != null)) { guest.loadURL(url) return guest.webContents.id From 7726c7c6c4eb6cf037eef207958705578ad2271a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 14:19:59 -0700 Subject: [PATCH 317/337] Add spec for webPreferences in features string --- spec/chromium-spec.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 1b88d78e2ab3..700983bb5ae9 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -391,6 +391,14 @@ describe('chromium feature', function () { }) b = window.open('', '__proto__') }) + + it('does not throw an exception when the features include webPreferences', function () { + let b + assert.doesNotThrow(function () { + b = window.open('', '', 'webPreferences=') + }) + b.close() + }) }) describe('window.opener', function () { From 507f60e33e656248aeb40cc0d5fd8065a7dde5e4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 14:20:39 -0700 Subject: [PATCH 318/337] Don't allow webPreferences to be overrideden in features string --- lib/browser/guest-window-manager.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index 33ec15a101d4..e668a3114a5f 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -202,6 +202,10 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName, if (value === undefined) { additionalFeatures.push(key) } else { + // Don't allow webPreferences to be set since it must be an object + // that cannot be directly overridden + if (key === 'webPreferences') return + if (webPreferences.includes(key)) { if (options.webPreferences == null) { options.webPreferences = {} From 775753c3d738b50c3d02c18f0e48cd55ee258385 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 14:48:01 -0700 Subject: [PATCH 319/337] Add spec for invalid window.history.go offset --- spec/chromium-spec.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 700983bb5ae9..d5d1b3f4782a 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -989,4 +989,12 @@ describe('chromium feature', function () { }, /Cannot convert object to primitive value/) }) }) + + describe('window.history.go(offset)', function () { + it('throws an exception when the argumnet cannot be converted to a string', function () { + assert.throws(function () { + window.history.go({toString: null}) + }, /Cannot convert object to primitive value/) + }) + }) }) From 95ef422ab4c350c089ecc4f8fbce24b97c958f19 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 25 Apr 2017 14:49:14 -0700 Subject: [PATCH 320/337] Coerce offset to number in renderer process --- lib/renderer/window-setup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/renderer/window-setup.js b/lib/renderer/window-setup.js index 5ccb6fec463d..99f7aef54237 100644 --- a/lib/renderer/window-setup.js +++ b/lib/renderer/window-setup.js @@ -164,7 +164,7 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => { } window.history.go = function (offset) { - sendHistoryOperation(ipcRenderer, 'goToOffset', offset) + sendHistoryOperation(ipcRenderer, 'goToOffset', +offset) } defineProperty(window.history, 'length', { From f6bbcc6efa198e1215bc99fdb6919aa507adbeb6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 26 Apr 2017 09:06:10 -0700 Subject: [PATCH 321/337] Fix typos --- docs/api/menu-item.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 494bdb74f196..a7486f3003cf 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -70,7 +70,7 @@ The `role` property can have following values: * `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.) * `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.) -The following additional roles are avaiable on macOS: +The following additional roles are available on macOS: * `about` - Map to the `orderFrontStandardAboutPanel` action * `hide` - Map to the `hide` action @@ -120,4 +120,4 @@ A String representing the menu items visible label #### `menuItem.click` -A Function that is fired when the MenuItem recieves a click event +A Function that is fired when the MenuItem receives a click event From c0669cb46e7524e0bb8c07443ac0ba21ee244814 Mon Sep 17 00:00:00 2001 From: Neil Craig Date: Thu, 27 Apr 2017 20:19:17 +0100 Subject: [PATCH 322/337] Update touch-bar.md Add a simple example of running the example code as it might not be obvious to people who've not used Electron. Hopefully it makes sense :-) --- docs/api/touch-bar.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 0a0827a2b2fa..371982fc2b47 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -138,3 +138,11 @@ app.once('ready', () => { window.setTouchBar(touchBar) }) ``` +### Running the above example +To run the example above, you'll need to (assuming you've got a terminal open in the dirtectory you want to run the example): + +1. Save the above file to your computer, named as touchbar.js +2. Install electron via e.g. `npm install electron` +3. Run the example inside electron: `./node_modules/.bin/electron touchbar.js` + +You should then see a new electron window and the app running in your touchbar (or touchbar emulator). From c26605c384ecc8d2342fe134ed84e5ee006d2ebc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 27 Apr 2017 14:22:56 -0700 Subject: [PATCH 323/337] Minor edits to example guide --- docs/api/touch-bar.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 371982fc2b47..8f1b8732f8b4 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -138,11 +138,13 @@ app.once('ready', () => { window.setTouchBar(touchBar) }) ``` + ### Running the above example + To run the example above, you'll need to (assuming you've got a terminal open in the dirtectory you want to run the example): -1. Save the above file to your computer, named as touchbar.js -2. Install electron via e.g. `npm install electron` -3. Run the example inside electron: `./node_modules/.bin/electron touchbar.js` +1. Save the above file to your computer as `touchbar.js` +2. Install Electron via `npm install electron` +3. Run the example inside Electron: `./node_modules/.bin/electron touchbar.js` -You should then see a new electron window and the app running in your touchbar (or touchbar emulator). +You should then see a new Electron window and the app running in your touch bar (or touch bar emulator). From 19b6ba044b523580d60046e199ecd6ca025e78ef Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 28 Apr 2017 11:21:53 -0300 Subject: [PATCH 324/337] Fix context leak in ObjectLifeMonitor. The RemoteObjectFreer class is keeping the context alive even when the window is closed. For electron applications that use sandbox, this will cause a memory leak every time a new window is created with `window.open`. Close #9191 --- atom/common/api/object_life_monitor.cc | 3 +-- atom/common/api/object_life_monitor.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/atom/common/api/object_life_monitor.cc b/atom/common/api/object_life_monitor.cc index cd5537e8874c..cc68130d34bd 100644 --- a/atom/common/api/object_life_monitor.cc +++ b/atom/common/api/object_life_monitor.cc @@ -12,8 +12,7 @@ namespace atom { ObjectLifeMonitor::ObjectLifeMonitor(v8::Isolate* isolate, v8::Local target) - : context_(isolate, isolate->GetCurrentContext()), - target_(isolate, target), + : target_(isolate, target), weak_ptr_factory_(this) { target_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter); } diff --git a/atom/common/api/object_life_monitor.h b/atom/common/api/object_life_monitor.h index 73030864b933..e047960e8130 100644 --- a/atom/common/api/object_life_monitor.h +++ b/atom/common/api/object_life_monitor.h @@ -22,7 +22,6 @@ class ObjectLifeMonitor { static void OnObjectGC(const v8::WeakCallbackInfo& data); static void Free(const v8::WeakCallbackInfo& data); - v8::Global context_; v8::Global target_; base::WeakPtrFactory weak_ptr_factory_; From f974a6bda9a32487bb021cb6ec221f5100a770c1 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 4 Apr 2017 01:33:51 +0530 Subject: [PATCH 325/337] browser: make destruction of webContents async --- atom/browser/api/atom_api_web_contents.cc | 15 +++++++++++---- atom/browser/api/atom_api_web_contents.h | 2 +- atom/browser/api/atom_api_window.cc | 2 +- atom/browser/common_web_contents_delegate.cc | 9 +++++++-- atom/browser/common_web_contents_delegate.h | 2 +- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index d3e7bae2e412..7cb8574efb40 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -417,15 +417,22 @@ WebContents::~WebContents() { guest_delegate_->Destroy(); RenderViewDeleted(web_contents()->GetRenderViewHost()); - DestroyWebContents(); + + if (type_ == BROWSER_WINDOW && owner_window()) { + owner_window()->CloseContents(nullptr); + } else if (type_ == WEB_VIEW) { + DestroyWebContents(false /* async */); + } else { + DestroyWebContents(true /* async */); + } } } -void WebContents::DestroyWebContents() { +void WebContents::DestroyWebContents(bool async) { // This event is only for internal use, which is emitted when WebContents is // being destroyed. Emit("will-destroy"); - ResetManagedWebContents(); + ResetManagedWebContents(async); } bool WebContents::DidAddMessageToConsole(content::WebContents* source, @@ -477,7 +484,7 @@ void WebContents::AddNewContents(content::WebContents* source, if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture, initial_rect.x(), initial_rect.y(), initial_rect.width(), initial_rect.height())) { - api_web_contents->DestroyWebContents(); + api_web_contents->DestroyWebContents(false /* async */); } } diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 1301ed15f7fa..2289cdb4a45b 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -78,7 +78,7 @@ class WebContents : public mate::TrackableObject, v8::Local prototype); // Notifies to destroy any guest web contents before destroying self. - void DestroyWebContents(); + void DestroyWebContents(bool async); int64_t GetID() const; int GetProcessID() const; diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 72b8e33ef7b5..6862915f9cf2 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -173,7 +173,7 @@ void Window::WillDestroyNativeObject() { } void Window::OnWindowClosed() { - api_web_contents_->DestroyWebContents(); + api_web_contents_->DestroyWebContents(true /* async */); RemoveFromWeakMap(); window_->RemoveObserver(this); diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index a10f959dce90..282fa92de69e 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -188,8 +188,13 @@ void CommonWebContentsDelegate::SetOwnerWindow( } } -void CommonWebContentsDelegate::ResetManagedWebContents() { - web_contents_.reset(); +void CommonWebContentsDelegate::ResetManagedWebContents(bool async) { + if (async) { + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, + web_contents_.release()); + } else { + web_contents_.reset(); + } } content::WebContents* CommonWebContentsDelegate::GetWebContents() const { diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h index 27209411c72b..d1d26314966e 100644 --- a/atom/browser/common_web_contents_delegate.h +++ b/atom/browser/common_web_contents_delegate.h @@ -112,7 +112,7 @@ class CommonWebContentsDelegate #endif // Destroy the managed InspectableWebContents object. - void ResetManagedWebContents(); + void ResetManagedWebContents(bool async); private: // Callback for when DevToolsSaveToFile has completed. From 9e3b8ade12213e9ae870ea6bd4834c5cbca34f50 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 5 Apr 2017 11:52:11 +0530 Subject: [PATCH 326/337] invoke WebContentsDestroyed manually when destruction path is async --- atom/browser/api/atom_api_web_contents.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 7cb8574efb40..70af26290eca 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -418,12 +418,18 @@ WebContents::~WebContents() { RenderViewDeleted(web_contents()->GetRenderViewHost()); - if (type_ == BROWSER_WINDOW && owner_window()) { - owner_window()->CloseContents(nullptr); - } else if (type_ == WEB_VIEW) { + if (type_ == WEB_VIEW) { DestroyWebContents(false /* async */); } else { - DestroyWebContents(true /* async */); + if (type_ == BROWSER_WINDOW && owner_window()) { + owner_window()->CloseContents(nullptr); + } else { + DestroyWebContents(true /* async */); + } + // The WebContentsDestroyed will not be called automatically because we + // destroy the webContents in the next tick. So we have to manually + // call it here to make sure "destroyed" event is emitted. + WebContentsDestroyed(); } } } From e4524ce42e164158b61c384220397e515c911838 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 5 Apr 2017 12:00:36 +0530 Subject: [PATCH 327/337] add spec --- spec/api-browser-window-spec.js | 63 +++++++++++++++++++++++++++++++ spec/api-web-contents-spec.js | 66 +++++++++++++++++++++++++++++++++ spec/static/main.js | 21 +++++++++++ 3 files changed, 150 insertions(+) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 5998768bd72f..86bf9bdcc880 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -86,6 +86,38 @@ describe('BrowserWindow module', function () { }) describe('BrowserWindow.close()', function () { + let server + + before(function (done) { + server = http.createServer((request, response) => { + switch (request.url) { + case '/404': + response.statusCode = '404' + response.end() + break + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end('hello') + break + default: + done('unsupported endpoint') + } + }).listen(0, '127.0.0.1', () => { + server.url = 'http://127.0.0.1:' + server.address().port + done() + }) + }) + + after(function () { + server.close() + server = null + }) + it('should emit unload handler', function (done) { w.webContents.on('did-finish-load', function () { w.close() @@ -109,6 +141,37 @@ describe('BrowserWindow module', function () { }) w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false.html')) }) + + it('should not crash when invoked synchronously inside navigation observer', function (done) { + const events = [ + { name: 'did-start-loading', url: `${server.url}/200` }, + { name: 'did-get-redirect-request', url: `${server.url}/301` }, + { name: 'did-get-response-details', url: `${server.url}/200` }, + { name: 'dom-ready', url: `${server.url}/200` }, + { name: 'did-stop-loading', url: `${server.url}/200` }, + { name: 'did-finish-load', url: `${server.url}/200` }, + { name: 'did-frame-finish-load', url: `${server.url}/200` }, + { name: 'did-fail-load', url: `${server.url}/404` } + ] + const responseEvent = 'window-webContents-destroyed' + + function* genNavigationEvent () { + let eventOptions = null + while ((eventOptions = events.shift()) && events.length) { + let w = new BrowserWindow({show: false}) + eventOptions.id = w.id + eventOptions.responseEvent = responseEvent + ipcRenderer.send('test-webcontents-navigation-observer', eventOptions) + yield 1 + } + } + + let gen = genNavigationEvent() + ipcRenderer.on(responseEvent, function () { + if (!gen.next().value) done() + }) + gen.next() + }) }) describe('window.close()', function () { diff --git a/spec/api-web-contents-spec.js b/spec/api-web-contents-spec.js index f081b3900944..7eac9d3e0e96 100644 --- a/spec/api-web-contents-spec.js +++ b/spec/api-web-contents-spec.js @@ -542,4 +542,70 @@ describe('webContents module', function () { }) }) }) + + describe('destroy()', () => { + let server + + before(function (done) { + server = http.createServer((request, response) => { + switch (request.url) { + case '/404': + response.statusCode = '404' + response.end() + break + case '/301': + response.statusCode = '301' + response.setHeader('Location', '/200') + response.end() + break + case '/200': + response.statusCode = '200' + response.end('hello') + break + default: + done('unsupported endpoint') + } + }).listen(0, '127.0.0.1', () => { + server.url = 'http://127.0.0.1:' + server.address().port + done() + }) + }) + + after(function () { + server.close() + server = null + }) + + it('should not crash when invoked synchronously inside navigation observer', (done) => { + const events = [ + { name: 'did-start-loading', url: `${server.url}/200` }, + { name: 'did-get-redirect-request', url: `${server.url}/301` }, + { name: 'did-get-response-details', url: `${server.url}/200` }, + { name: 'dom-ready', url: `${server.url}/200` }, + { name: 'did-stop-loading', url: `${server.url}/200` }, + { name: 'did-finish-load', url: `${server.url}/200` }, + // FIXME: Multiple Emit calls inside an observer assume that object + // will be alive till end of the observer. Synchronous `destroy` api + // violates this contract and crashes. + // { name: 'did-frame-finish-load', url: `${server.url}/200` }, + { name: 'did-fail-load', url: `${server.url}/404` } + ] + const responseEvent = 'webcontents-destroyed' + + function* genNavigationEvent () { + let eventOptions = null + while ((eventOptions = events.shift()) && events.length) { + eventOptions.responseEvent = responseEvent + ipcRenderer.send('test-webcontents-navigation-observer', eventOptions) + yield 1 + } + } + + let gen = genNavigationEvent() + ipcRenderer.on(responseEvent, () => { + if (!gen.next().value) done() + }) + gen.next() + }) + }) }) diff --git a/spec/static/main.js b/spec/static/main.js index 7e56da623bf8..ba31b61ae07d 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -338,6 +338,27 @@ ipcMain.on('crash-service-pid', (event, pid) => { event.returnValue = null }) +ipcMain.on('test-webcontents-navigation-observer', (event, options) => { + let contents = null + let destroy = () => {} + if (options.id) { + const w = BrowserWindow.fromId(options.id) + contents = w.webContents + destroy = () => w.close() + } else { + contents = webContents.create() + destroy = () => contents.destroy() + } + + contents.once(options.name, () => destroy()) + + contents.once('destroyed', () => { + event.sender.send(options.responseEvent) + }) + + contents.loadURL(options.url) +}) + // Suspend listeners until the next event and then restore them const suspendListeners = (emitter, eventName, callback) => { const listeners = emitter.listeners(eventName) From 5e976be43bcf459c2ce8f5283609a464cf6da865 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 5 Apr 2017 16:57:33 +0530 Subject: [PATCH 328/337] remove page-title-updated workaround for #3380 --- atom/browser/api/atom_api_web_contents.cc | 6 ++---- lib/browser/api/browser-window.js | 6 +----- lib/browser/api/web-contents.js | 7 ------- spec/api-browser-window-spec.js | 5 +++++ 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 70af26290eca..4dd3d51fe0a2 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -829,10 +829,8 @@ void WebContents::DidFinishNavigation( void WebContents::TitleWasSet(content::NavigationEntry* entry, bool explicit_set) { - if (entry) - Emit("-page-title-updated", entry->GetTitle(), explicit_set); - else - Emit("-page-title-updated", "", explicit_set); + auto title = entry ? entry->GetTitle() : base::string16(); + Emit("page-title-updated", title, explicit_set); } void WebContents::DidUpdateFaviconURL( diff --git a/lib/browser/api/browser-window.js b/lib/browser/api/browser-window.js index 4b3f70139f0d..49a134f39415 100644 --- a/lib/browser/api/browser-window.js +++ b/lib/browser/api/browser-window.js @@ -76,13 +76,9 @@ BrowserWindow.prototype._init = function () { // Change window title to page title. this.webContents.on('page-title-updated', (event, title) => { - // The page-title-updated event is not emitted immediately (see #3645), so - // when the callback is called the BrowserWindow might have been closed. - if (this.isDestroyed()) return - // Route the event to BrowserWindow. this.emit('page-title-updated', event, title) - if (!event.defaultPrevented) this.setTitle(title) + if (!this.isDestroyed() && !event.defaultPrevented) this.setTitle(title) }) // Sometimes the webContents doesn't get focus when window is shown, so we diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 6af96e175715..c49c1be8ba64 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -268,13 +268,6 @@ WebContents.prototype._init = function () { this.reload() }) - // Delays the page-title-updated event to next tick. - this.on('-page-title-updated', function (...args) { - setImmediate(() => { - this.emit('page-title-updated', ...args) - }) - }) - app.emit('web-contents-created', {}, this) } diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 86bf9bdcc880..34db4a6ae79a 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -104,6 +104,10 @@ describe('BrowserWindow module', function () { response.statusCode = '200' response.end('hello') break + case '/title': + response.statusCode = '200' + response.end('Hello') + break default: done('unsupported endpoint') } @@ -148,6 +152,7 @@ describe('BrowserWindow module', function () { { name: 'did-get-redirect-request', url: `${server.url}/301` }, { name: 'did-get-response-details', url: `${server.url}/200` }, { name: 'dom-ready', url: `${server.url}/200` }, + { name: 'page-title-updated', url: `${server.url}/title` }, { name: 'did-stop-loading', url: `${server.url}/200` }, { name: 'did-finish-load', url: `${server.url}/200` }, { name: 'did-frame-finish-load', url: `${server.url}/200` }, From c68f41b8d837f21e8cf2a5d9c09b2a475a0230ef Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 19 Apr 2017 21:54:04 +0530 Subject: [PATCH 329/337] destroy new window webContents asynchronously --- atom/browser/api/atom_api_web_contents.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 4dd3d51fe0a2..a06ec2244dde 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -490,7 +490,7 @@ void WebContents::AddNewContents(content::WebContents* source, if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture, initial_rect.x(), initial_rect.y(), initial_rect.width(), initial_rect.height())) { - api_web_contents->DestroyWebContents(false /* async */); + api_web_contents->DestroyWebContents(true /* async */); } } From 0476e2fd3d64724f881d7afd2976e69f8eaaf990 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 19 Apr 2017 22:07:12 +0530 Subject: [PATCH 330/337] destroy browserView webContents asynchronously --- atom/browser/api/atom_api_browser_view.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_browser_view.cc b/atom/browser/api/atom_api_browser_view.cc index dc17fce9e9a3..d37d2df41c5b 100644 --- a/atom/browser/api/atom_api_browser_view.cc +++ b/atom/browser/api/atom_api_browser_view.cc @@ -75,7 +75,7 @@ void BrowserView::Init(v8::Isolate* isolate, } BrowserView::~BrowserView() { - api_web_contents_->DestroyWebContents(); + api_web_contents_->DestroyWebContents(true /* async */); } // static From 3c58d50f8792652853cec84efdf385da323e763e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 26 Apr 2017 10:44:16 -0700 Subject: [PATCH 331/337] Add failing spec for targetOrigin handling --- spec/chromium-spec.js | 34 +++++++++++++++++++ .../pages/window-opener-targetOrigin.html | 18 ++++++++++ 2 files changed, 52 insertions(+) create mode 100644 spec/fixtures/pages/window-opener-targetOrigin.html diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index d5d1b3f4782a..67448276443b 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -1,4 +1,5 @@ const assert = require('assert') +const fs = require('fs') const http = require('http') const path = require('path') const ws = require('ws') @@ -618,6 +619,39 @@ describe('chromium feature', function () { }) document.body.appendChild(webview) }) + + describe('targetOrigin argument', function () { + let serverURL + let server + + beforeEach(function (done) { + server = http.createServer(function (req, res) { + res.writeHead(200) + const filePath = path.join(fixtures, 'pages', 'window-opener-targetOrigin.html') + res.end(fs.readFileSync(filePath, 'utf8')) + }) + server.listen(0, '127.0.0.1', function () { + serverURL = `http://127.0.0.1:${server.address().port}` + done() + }) + }) + + afterEach(function () { + server.close() + }) + + it('delivers messages that match the origin', function (done) { + let b + listener = function (event) { + window.removeEventListener('message', listener) + b.close() + assert.equal(event.data, 'second message') + done() + } + window.addEventListener('message', listener) + b = window.open(serverURL, '', 'show=no') + }) + }) }) describe('creating a Uint8Array under browser side', function () { diff --git a/spec/fixtures/pages/window-opener-targetOrigin.html b/spec/fixtures/pages/window-opener-targetOrigin.html new file mode 100644 index 000000000000..c4a19fdca2b2 --- /dev/null +++ b/spec/fixtures/pages/window-opener-targetOrigin.html @@ -0,0 +1,18 @@ + + + + + From fa4ec11a1213280c64fe8afc55af56c6e4ab9698 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 26 Apr 2017 10:53:54 -0700 Subject: [PATCH 332/337] Use isSameOrigin helper when posting message --- lib/browser/guest-window-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index e668a3114a5f..ecf4093dcf06 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -309,7 +309,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, // The W3C does not seem to have word on how postMessage should work when the // origins do not match, so we do not do |canAccessWindow| check here since // postMessage across origins is useful and not harmful. - if (guestContents.getURL().indexOf(targetOrigin) === 0 || targetOrigin === '*') { + if (targetOrigin === '*' || isSameOrigin(guestContents.getURL(), targetOrigin)) { const sourceId = event.sender.id guestContents.send('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) } From efc62629efb5cd2acac7584c5c45513f8f3806ec Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 26 Apr 2017 10:55:38 -0700 Subject: [PATCH 333/337] Fix typo in fixture comment --- spec/fixtures/pages/window-opener-targetOrigin.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fixtures/pages/window-opener-targetOrigin.html b/spec/fixtures/pages/window-opener-targetOrigin.html index c4a19fdca2b2..c1f708818411 100644 --- a/spec/fixtures/pages/window-opener-targetOrigin.html +++ b/spec/fixtures/pages/window-opener-targetOrigin.html @@ -3,7 +3,7 @@