Compare commits

..

53 Commits

Author SHA1 Message Date
Electron Bot
ec0fa836d2 Bump v13.1.5 2021-07-01 11:36:42 -07:00
trop[bot]
56a34d3b10 build: add support for spawning builds for a specific commit on appveyor (#29971) (#29983)
Co-authored-by: Samuel Attard <sam@electronjs.org>
2021-07-01 10:53:33 -07:00
Shelley Vohr
bde3d403a8 fix: child window alwaysOnTop level persistence (#29956) 2021-07-01 10:22:37 -04:00
John Kleinschmidt
8779a3ac0f ci: fixup arm testing (#29927)
* ci: fixup arm testing

* update patch for 13-x-y

* also check against kPartitionAllocPCScan
2021-06-30 14:12:47 -04:00
Omar Kilani
b465ee721e fix: geolocation crashes electron on macOS (#29343) (#29912) 2021-06-28 20:31:04 -07:00
trop[bot]
50b0750df3 docs: fix broken markdown in dialog.md (#29848)
* docs: fix broken markdown in dialog.md

* &#32;

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2021-06-29 09:15:47 +09:00
electron-roller[bot]
1a3da54563 chore: bump chromium to 91.0.4472.124 (13-x-y) (#29774)
* chore: bump chromium in DEPS to 91.0.4472.114

* chore: bump chromium in DEPS to 91.0.4472.124

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2021-06-28 14:06:13 -04:00
trop[bot]
fa3767564a fix: stop window.open from hanging when prevented (#29882)
* fix: stop window.open from hanging when prevented

* add test

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-06-28 15:24:18 +09:00
trop[bot]
85db7e7077 fix: properly order out child windows (#29888)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-25 17:55:45 +09:00
trop[bot]
9b1d2d5b88 fix: Inspector method overrides when contextIsolation enabled (#29885)
* fix: Inspector method overrides when contextIsolation enabled

* fix: handle DevToolsAPI call

* refactor: always use webFrame.executeJavaScript

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-25 17:50:39 +09:00
trop[bot]
e8621de3f5 fix: properly handle optional requestHeaders with onBeforeSendHeaders (#29836)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-23 10:09:25 +09:00
Electron Bot
9942b2ba80 Bump v13.1.4 2021-06-22 10:20:05 -07:00
trop[bot]
2bf125f82a fix: allow ppapi processes access to resource bundle on all platforms (#29830)
* wip: debug resource bundle failure

* fix: include ppapi subprocesses for windows resource bundle

* fix: allow ppapi plugin processes access to resource bundle on all platforms.

Aligns with chrome_main_delegate here: https://chromium-review.googlesource.com/c/chromium/src/+/2619003

* chore: remove incorrectly backported patches

Co-authored-by: VerteDinde <keeleymhammond@gmail.com>
Co-authored-by: VerteDinde <khammond@slack-corp.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2021-06-22 14:59:06 +09:00
John Kleinschmidt
69493ac51e ci: run linux arm tests on CircleCI (#29766)
* ci: run linux arm tests on CircleCI

* cleanup electron dirs after testing

(cherry picked from commit 1c0a6045fb)

* use start-stop-daemon to kill Xvfb

(cherry picked from commit 1d10a68c31)
2021-06-22 14:58:07 +09:00
Electron Bot
6504c4bbc8 Bump v13.1.3 2021-06-21 10:03:02 -07:00
trop[bot]
5c1e1ee5ec fix: do not cancel CORS preflight request on proxy auth. (#29811)
* fix: do not cancel CORS preflight request on proxy auth. (#29266)

* fix: do not cancel CORS preflight request on proxy auth.

If connecting via proxy, preflight request can receive 407
header response from proxy. This does not mean request
was finished even though it received headers (from proxy,
not the destination server), so prevent "completing"
and most importantly deleting it, which causes request
to be canceled in network layer. Just continue to monitor it
and await proper response from server. Also add circut breaker
to cancel request if proxy auth failed 3 times (for example
user keeps cancelling auth). This behavior happens only
when app registered WebRequest api listeners.

* Port chromium webrequest changes to electron code.

Move relevant parts of chromium WebRequestProxyingURLLoaderFactory from
https://chromium-review.googlesource.com/c/chromium/src/+/2011781
into electron ProxyingURLLoaderFactory.

* Update code to upstreamed version and remove retyr count failsafe.

Co-authored-by: Milan Burda <milan.burda@gmail.com>

* chore: add required header

Co-authored-by: marekharanczyk <48673767+marekharanczyk@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-06-21 21:20:05 +09:00
trop[bot]
f39ac0764d fix: update Squirel.Mac to fix CPU spin during update (#29805)
* fix: update Squirel.Mac to fix CPU spin during update

Refs: https://github.com/Squirrel/Squirrel.Mac/pull/259
Closes: #29119

* chore: update patches

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-21 19:06:06 +09:00
trop[bot]
252805ddb4 fix: microtasks policy in CreateEnvironment (#29808)
* fix: microtasks policy in CreateEnvironment

Microtasks policy should not be updated for the renderer because
`NodeBindings::CreateEnvironment` might be entered with or without
`UvRunOnce()` on stack. One of the examples of such calls is
`window.open()` which is possible to invoke while `uv_run()` is still
running (e.g. with `setImmediate()`).

All in all, it doesn't matter that much which policy we use since
`v8::MicrotasksScope` has a check for the policy in its destructor and
no commits will be made if the policy is `kExplicit`. It is important,
however, to not change the policy in the middle of `UvRunOnce()` so we
should respect whatever we currently have and move on.

Fix: #29463

* Move test to a better place

* Update spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.html

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

* Update spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.html

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

* simplify crash-case

* comment

* fix comment

Co-authored-by: Fedor Indutny <fedor@indutny.com>
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
Co-authored-by: Fedor Indutny <indutny@signal.org>
2021-06-21 15:49:17 +09:00
trop[bot]
df27597c05 docs: fix frontmatter for Tray tutorial (#29803)
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-06-21 14:00:25 +09:00
trop[bot]
fa683ef8b7 fix: fix hover state not clear bug when BrowserWindow is not resizable (#611) (#29800)
Co-authored-by: sssooonnnggg <sssooonnnggg111@gmail.com>
2021-06-21 13:59:36 +09:00
trop[bot]
16b09a676f docs: clarify use of ELECTRON_SKIP_BINARY_DOWNLOAD (#29745)
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-06-21 10:10:05 +09:00
George Xu
301108ece4 docs: Add clarification for Visual Zoom behavior (#28860) (#29764)
* Add clarification for visual zoom documentation

Co-authored-by: Michael Kozakov <michael.kozakov@snapchat.com>
2021-06-18 11:02:42 -07:00
Keeley Hammond
5d36cdf485 fix: color select eyedropper not working within DevTools (#29729) (#29760)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-18 11:34:03 +02:00
George Xu
c94ab729dd docs: added guide and updated docs for Tray (#29385) (#29762)
* docs: added guide and updated docs for Tray

* docs: improve clarity
2021-06-17 14:03:07 -07:00
trop[bot]
b35f904e58 fix: ensure detached devtools are not always draggable (#29737)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-06-17 15:29:27 +09:00
trop[bot]
b143042c7f fix: draggable regions with devtools open (#29734)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-17 15:21:27 +09:00
trop[bot]
10c238c0ea fix: potential crash when setting vibrancy (#29722)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-17 15:20:05 +09:00
trop[bot]
ad2f34491c fix setWindowOpenHandler call syntax (#29726)
Co-authored-by: kdau <kevin@kdau.com>
2021-06-16 10:13:02 -07:00
electron-roller[bot]
d6c51bc456 chore: bump chromium in DEPS to 91.0.4472.106 (#29700)
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2021-06-15 13:23:07 -07:00
trop[bot]
f313d00083 docs: update WebPreferences default values for Electron 12 (#29710)
Updates the values for `contextIsolation` and `worldSafeExecuteJavaScript` for Electron 12.

Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-06-15 16:15:51 -04:00
trop[bot]
2ef55e1e9e chore: disable default async spellchecker on Windows (#29706)
* chore: disable default async spellchecker on Windows

* chore: disable kWinRetrieveSuggestionsOnlyOnDemand in feature list

* chore: remove incorrectly backported patches

Co-authored-by: VerteDinde <keeleymhammond@gmail.com>
Co-authored-by: VerteDinde <khammond@slack-corp.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2021-06-15 12:49:52 -07:00
Milan Burda
62402870fd fix: warnAboutRemoteModuleWithRemoteContent (#29691)
Co-authored-by: Milan Burda <miburda@microsoft.com>
2021-06-15 12:02:03 +02:00
trop[bot]
7b2a4c9984 docs: Update represented-file fiddle tutorial (#29693)
* Update represented-file fiddle.

* add index and code back to guide

Co-authored-by: Kevin Hartman <kevin@hart.mn>
Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
2021-06-15 11:36:57 +09:00
trop[bot]
7958f3efbb docs: fix typo in process-model.md (#29683)
Co-authored-by: Luke Ingalls <45518011+lukeingalls@users.noreply.github.com>
2021-06-14 10:12:58 -07:00
trop[bot]
3e90aff6fd docs: fix file mode of versioning-sketch-2.png (#29681)
Unlike the other files, this file had its executable bit set in its file
mode. This change removes the executable bit to align its file mode with
the rest of the files.

Signed-off-by: Darshan Sen <raisinten@gmail.com>

Co-authored-by: Darshan Sen <raisinten@gmail.com>
2021-06-14 10:12:35 -07:00
trop[bot]
192fc3ee2c fix: check DCHECK_IS_ON() instead of #ifdef DCHECK_IS_ON (#29674)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-06-14 21:00:20 +09:00
trop[bot]
e0e7b14bdc fix: use correct spelling of attachment with Content-Disposition header (#29672)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-14 20:59:05 +09:00
trop[bot]
4cecc87c55 fix: copy received data in URLPipeLoader to prevent corruption (#29669)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-14 17:47:17 +09:00
Shelley Vohr
46e7511af9 fix: ensure custom traffic lights float to top (#29663)
* fix: ensure custom traffic lights float to top

* chore: split into separate function
2021-06-14 09:36:15 +09:00
trop[bot]
72733bae8a docs: fix typo (#29582)
* Typo fix

* Update main.js

Co-authored-by: ZReC <contact.zrec@gmail.com>
2021-06-14 09:35:07 +09:00
trop[bot]
38fce95417 docs: fix image links in performance.md (#29631)
* docs: fix image links in performance.md

Fixes https://github.com/electron/electron/issues/29580

Signed-off-by: Darshan Sen <raisinten@gmail.com>

* Apply suggestions from code review

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

Co-authored-by: Darshan Sen <raisinten@gmail.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-14 09:33:53 +09:00
electron-roller[bot]
54de33464d chore: bump chromium to 91.0.4472.101 (13-x-y) (#29629)
* chore: bump chromium in DEPS to 91.0.4472.101

* chore: update patches

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-10 15:59:28 -07:00
trop[bot]
6c4c66d2cd fix: select-bluetooth-device on Windows (#29611)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-06-09 12:48:41 -04:00
Electron Bot
839dcbbbdb Bump v13.1.2 2021-06-09 09:39:07 -07:00
trop[bot]
05ae55d131 fix: ensure fuse order is read in a stable way (#29615)
Co-authored-by: Samuel Attard <sattard@slack-corp.com>
2021-06-09 09:26:51 -07:00
trop[bot]
d7736e5924 fix: improper wrapping of fs.promises.readFile (#29576) 2021-06-08 10:31:27 +02:00
trop[bot]
30921548ed fix: make intermediates work with 'select-client-certificate' (#29569)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-08 11:40:09 +09:00
Cheng Zhao
9059a50f93 fix: keep shifted character in menu accelerator (#29482)
* fix: keep shifted character in menu accelerator

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-07 10:25:35 -04:00
trop[bot]
78569e9b91 docs: Update notifications (renderer) docs (#29564)
* remove version information from html

* change format for readability

* clarify which console the message should appear in

* minor changes to renderer.md

* update UI on click instead of developer console

* remove node-integration and fix md

* update content

* chore: remove ****

Co-authored-by: Jeremy Foster <jeremy.foster@live.com>
Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
Co-authored-by: Cheng Zhao <github@zcbenz.com>
2021-06-07 14:43:42 +09:00
trop[bot]
07b8b2ffdd docs: Updated "recent documents" fiddle tutorial (#29561)
* Port recent-documents fiddle to 12-x-y.

* Update recent-documents tutorial.

* update for review comments

Co-authored-by: Kevin Hartman <kevin@hart.mn>
Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
2021-06-07 14:42:58 +09:00
trop[bot]
2d18829b43 build: Improve squirrel.mac BUILD.gn xcrun_action error (#29513)
Right now, if executing `xcrun` fails, then the error message prints the
second argument to the `xcrun.py` script, which is the first argument to
the tool that `xcrun` is executing, making the whole error message quite
confusing.

Consider the following error:

```
python ../../third_party/squirrel.mac/build/xcrun.py dtrace -h -s /private/tmp/20210531211008-def376dc/src/third_party/squirrel.mac/vendor/ReactiveObjC/ReactiveObjC/RACSignalProvider.d -o /private/tmp/20210531211008-def376dc/src/out/release/gen/third_party/squirrel.mac/dtrace/RACSignalProvider.h
xcrun script '-h' failed with code '71':
xcrun: error: can't exec '/tmp/20210531211008-def376dc/dtrace' (errno=Permission denied)
```

The command that `xcrun` is executing is `dtrace`, but the error just
mentions the `-h` flag.

Notes: none
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>

Co-authored-by: Juan Cruz Viotti <jv@jviotti.com>
2021-06-07 10:23:51 +09:00
trop[bot]
f0a9e56741 chore: return early on promise rejection (#29538)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-07 10:17:15 +09:00
Samuel Attard
314e627df1 Revert "Revert "fix: change ASAR archive cache to per-process to fix leak (#29535)""
This reverts commit 0dcc660794.
2021-06-04 10:29:42 -07:00
103 changed files with 1037 additions and 575 deletions

View File

@@ -57,6 +57,16 @@ parameters:
type: boolean
default: false
# Executors
executors:
linux-arm:
resource_class: electronjs/linux-arm
machine: true
linux-arm64:
resource_class: electronjs/linux-arm64
machine: true
# The config expects the following environment variables to be set:
# - "SLACK_WEBHOOK" Slack hook URL to send notifications.
#
@@ -239,7 +249,14 @@ step-maybe-cleanup-arm64-mac: &step-maybe-cleanup-arm64-mac
killall Safari || echo "No Safari processes left running"
rm -rf ~/Library/Application\ Support/Electron*
rm -rf ~/Library/Application\ Support/electron*
elif [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
XVFB=/usr/bin/Xvfb
/sbin/start-stop-daemon --stop --exec $XVFB || echo "Xvfb not running"
pkill electron || echo "electron not running"
rm -rf ~/.config/Electron*
rm -rf ~/.config/electron*
fi
when: always
step-checkout-electron: &step-checkout-electron
@@ -763,7 +780,7 @@ step-verify-mksnapshot: &step-verify-mksnapshot
command: |
if [ "$IS_ASAN" != "1" ]; then
cd src
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots
else
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
@@ -908,28 +925,6 @@ step-maybe-cross-arch-snapshot-store: &step-maybe-cross-arch-snapshot-store
path: src/cross-arch-snapshots
destination: cross-arch-snapshots
step-maybe-trigger-arm-test: &step-maybe-trigger-arm-test
run:
name: Trigger an arm test on VSTS if applicable
command: |
cd src
# Only run for non-fork prs
if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then
#Trigger VSTS job, passing along CircleCI job number and branch to build
if [ "`uname`" == "Darwin" ]; then
if [ x"$MAS_BUILD" == x"true" ]; then
export DEVOPS_BUILD="electron-mas-arm64-testing"
else
export DEVOPS_BUILD="electron-osx-arm64-testing"
fi
echo "Triggering $DEVOPS_BUILD build on Azure DevOps"
node electron/script/release/ci-release-build.js --job=$DEVOPS_BUILD --ci=DevOps --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
else
echo "Triggering electron-$TARGET_ARCH-testing build on VSTS"
node electron/script/release/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
fi
fi
step-maybe-generate-typescript-defs: &step-maybe-generate-typescript-defs
run:
name: Generate type declarations
@@ -1344,7 +1339,7 @@ steps-tests: &steps-tests
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split)) 2>&1 | $ASAN_SYMBOLIZE
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split)) 2>&1 | $ASAN_SYMBOLIZE
else
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging)
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging)
@@ -1635,9 +1630,6 @@ commands:
steps:
- *step-save-out-cache
# Trigger tests on arm hardware if needed
- *step-maybe-trigger-arm-test
- *step-maybe-notify-slack-failure
electron-publish:
@@ -1981,7 +1973,7 @@ jobs:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
steps:
- electron-build:
persist: false
persist: true
checkout: true
use-out-cache: false
@@ -2040,7 +2032,7 @@ jobs:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
steps:
- electron-build:
persist: false
persist: true
checkout: true
use-out-cache: false
@@ -2437,6 +2429,24 @@ jobs:
<<: *env-send-slack-notifications
<<: *steps-verify-ffmpeg
linux-arm-testing-tests:
executor: linux-arm
environment:
<<: *env-arm
<<: *env-global
<<: *env-headless-testing
<<: *env-stack-dumping
<<: *steps-tests
linux-arm64-testing-tests:
executor: linux-arm64
environment:
<<: *env-arm64
<<: *env-global
<<: *env-headless-testing
<<: *env-stack-dumping
<<: *steps-tests
osx-testing-x64-tests:
<<: *machine-mac-large
environment:
@@ -2689,8 +2699,23 @@ workflows:
- linux-ia32-testing
- linux-arm-testing
- linux-arm-testing-tests:
filters:
branches:
# Do not run this on forked pull requests
ignore: /pull\/[0-9]+/
requires:
- linux-arm-testing
- linux-arm64-testing
- linux-arm64-testing-tests:
filters:
branches:
# Do not run this on forked pull requests
ignore: /pull\/[0-9]+/
requires:
- linux-arm64-testing
- linux-arm64-testing-gn-check:
requires:
- linux-checkout-fast

4
DEPS
View File

@@ -14,13 +14,13 @@ gclient_gn_args = [
vars = {
'chromium_version':
'91.0.4472.77',
'91.0.4472.124',
'node_version':
'v14.16.0',
'nan_version':
'v2.14.2',
'squirrel.mac_version':
'cdc0729c8bf8576bfef18629186e1e9ecf1b0d9f',
'0e5d146ba13101a1302d59ea6e6e0b3cace4ae38',
'pyyaml_version': '3.12',

View File

@@ -1 +1 @@
13.1.1
13.1.5

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python3
from collections import OrderedDict
import json
import os
import sys
@@ -50,7 +51,7 @@ const volatile char kFuseWire[] = { /* sentinel */ {sentinel}, /* fuse_version *
"""
with open(os.path.join(dir_path, "fuses.json5"), 'r') as f:
fuse_defaults = json.loads(''.join(line for line in f.readlines() if not line.strip()[0] == "/"))
fuse_defaults = json.loads(''.join(line for line in f.readlines() if not line.strip()[0] == "/"), object_pairs_hook=OrderedDict)
fuse_version = fuse_defaults['_version']
del fuse_defaults['_version']

View File

@@ -145,6 +145,8 @@ static_library("chrome") {
if (enable_color_chooser) {
sources += [
"//chrome/browser/devtools/devtools_eye_dropper.cc",
"//chrome/browser/devtools/devtools_eye_dropper.h",
"//chrome/browser/platform_util.cc",
"//chrome/browser/platform_util.h",
"//chrome/browser/ui/browser_dialogs.h",

View File

@@ -339,7 +339,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
more details.
* `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 only have
to `true`. The context that the `preload` script runs in will only have
access to its own dedicated `document` and `window` globals, as well as
its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.),
which are all invisible to the loaded content. The Electron API will only
@@ -351,8 +351,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
context in the dev tools by selecting the 'Electron Isolated Context'
entry in the combo box at the top of the Console tab.
* `worldSafeExecuteJavaScript` Boolean (optional) - If true, values returned from `webFrame.executeJavaScript` will be sanitized to ensure JS values
can't unsafely cross between worlds when using `contextIsolation`. The default
is `false`. In Electron 12, the default will be changed to `true`. _Deprecated_
can't unsafely cross between worlds when using `contextIsolation`. Defaults to `true`. _Deprecated_
* `nativeWindowOpen` Boolean (optional) - Whether to use native
`window.open()`. Defaults to `false`. Child windows will always have node
integration disabled unless `nodeIntegrationInSubFrames` is true. **Note:** This option is currently

View File

@@ -24,7 +24,7 @@ The `dialog` module has the following methods:
* `buttonLabel` String (optional) - Custom label for the confirmation button, when
left empty the default label will be used.
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
* `properties` String[] (optional) - Contains which features the dialog should
* `properties` String[]&#32;(optional) - Contains which features the dialog should
use. The following values are supported:
* `openFile` - Allow files to be selected.
* `openDirectory` - Allow directories to be selected.
@@ -87,7 +87,7 @@ dialog.showOpenDialogSync(mainWindow, {
* `buttonLabel` String (optional) - Custom label for the confirmation button, when
left empty the default label will be used.
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
* `properties` String[] (optional) - Contains which features the dialog should
* `properties` String[]&#32;(optional) - Contains which features the dialog should
use. The following values are supported:
* `openFile` - Allow files to be selected.
* `openDirectory` - Allow directories to be selected.
@@ -112,7 +112,7 @@ Returns `Promise<Object>` - Resolve with an object containing the following:
* `canceled` Boolean - whether or not the dialog was canceled.
* `filePaths` String[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array.
* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).)
* `bookmarks` String[]&#32;(optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).)
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
@@ -165,7 +165,7 @@ dialog.showOpenDialog(mainWindow, {
displayed in front of the filename text field.
* `showsTagField` Boolean (optional) _macOS_ - Show the tags input box,
defaults to `true`.
* `properties` String[] (optional)
* `properties` String[]&#32;(optional)
* `showHiddenFiles` - Show hidden files in dialog.
* `createDirectory` _macOS_ - Allow creating new directories from dialog.
* `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders,
@@ -195,7 +195,7 @@ The `filters` specifies an array of file types that can be displayed, see
* `nameFieldLabel` String (optional) _macOS_ - Custom label for the text
displayed in front of the filename text field.
* `showsTagField` Boolean (optional) _macOS_ - Show the tags input box, defaults to `true`.
* `properties` String[] (optional)
* `properties` String[]&#32;(optional)
* `showHiddenFiles` - Show hidden files in dialog.
* `createDirectory` _macOS_ - Allow creating new directories from dialog.
* `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders,
@@ -227,7 +227,7 @@ expanding and collapsing the dialog.
`"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
* `buttons` String[]&#32;(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
be selected by default when the message box opens.
@@ -273,7 +273,7 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case
`"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
* `buttons` String[]&#32;(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
be selected by default when the message box opens.

View File

@@ -62,6 +62,11 @@ Sets the maximum and minimum pinch-to-zoom level.
> webFrame.setVisualZoomLevelLimits(1, 3)
> ```
> **NOTE**: Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom shortcuts are
> controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem roles in the application
> Menu. To disable shortcuts, manually [define the Menu](./menu.md#examples) and omit zoom roles
> from the definition.
### `webFrame.setSpellCheckProvider(language, provider)`
* `language` String

View File

@@ -117,15 +117,18 @@ const mainWindow = new BrowserWindow({
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url === 'about:blank') {
return {
frame: false,
fullscreenable: false,
backgroundColor: 'black',
webPreferences: {
preload: 'my-child-window-preload-script.js'
action: 'allow',
overrideBrowserWindowOptions: {
frame: false,
fullscreenable: false,
backgroundColor: 'black',
webPreferences: {
preload: 'my-child-window-preload-script.js'
}
}
}
}
return false
return { action: 'deny' }
})
```

View File

@@ -22,7 +22,7 @@ function createWindow () {
})
ipcMain.handle('dark-mode:system', () => {
nativeTheme.themeSouce = 'system'
nativeTheme.themeSource = 'system'
})
}

View File

@@ -7,11 +7,9 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<p>After launching this application, you should see the system notification.</p>
<p id="output">Click it to see the effect in this interface.</p>
<script src="renderer.js"></script>
</body>
</html>

View File

@@ -3,10 +3,7 @@ const { app, BrowserWindow } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')

View File

@@ -1,7 +1,6 @@
const myNotification = new Notification('Title', {
body: 'Notification from the Renderer process'
})
const NOTIFICATION_TITLE = 'Title'
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
const CLICK_MESSAGE = 'Notification clicked!'
myNotification.onclick = () => {
console.log('Notification clicked')
}
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
.onclick = () => document.getElementById("output").innerText = CLICK_MESSAGE

View File

@@ -2,15 +2,14 @@
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<title>Recent Documents</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<h1>Recent Documents</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
Right click on the app icon to see recent documents.
You should see `recently-used.md` added to the list of recent files
</p>
</body>
</html>

View File

@@ -5,17 +5,15 @@ const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')
}
const fileName = 'recently-used.md'
fs.writeFile(fileName, 'Lorem Ipsum', () => {
app.addRecentDocument(path.join(process.cwd(), `${fileName}`))
app.addRecentDocument(path.join(__dirname, fileName))
})
app.whenReady().then(createWindow)

View File

@@ -4,13 +4,14 @@
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link rel="stylesheet" type="text/css" href="./styles.css">
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
Click on the title with the <pre>Command</pre> or <pre>Control</pre> key pressed.
You should see a popup with the represented file at the top.
</p>
</body>
</body>
</html>

View File

@@ -4,10 +4,7 @@ const os = require('os');
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')

View File

@@ -16,91 +16,12 @@
<p>
Open the
<a href="https://electronjs.org/docs/api/tray">
full API documentation (opens in new window)
full API documentation
</a>
in your browser.
</p>
</div>
<div>
<div>
<div>
<div>
<button id="put-in-tray">View Demo</button>
<span id="tray-countdown"></span>
</div>
<p>
The demo button sends a message to the main process using the
<code>ipc</code> module. In the main process the app is told to
place an icon, with a context menu, in the tray.
</p>
<p>
In this example the tray icon can be removed by clicking 'Remove' in
the context menu or selecting the demo button again.
</p>
<h5>Main Process</h5>
<pre>
<code>
const path = require('path')
const {ipcMain, app, Menu, Tray} = require('electron')
let appIcon = null
ipcMain.on('put-in-tray', (event) => {
const iconName = process.platform === 'win32' ? 'windows-icon.png' : 'iconTemplate.png'
const iconPath = path.join(__dirname, iconName)
appIcon = new Tray(iconPath)
const contextMenu = Menu.buildFromTemplate([{
label: 'Remove',
click: () => {
event.sender.send('tray-removed')
}
}])
appIcon.setToolTip('Electron Demo in the tray.')
appIcon.setContextMenu(contextMenu)
})
ipcMain.on('remove-tray', () => {
appIcon.destroy()
})
app.on('window-all-closed', () => {
if (appIcon) appIcon.destroy()
})
</code>
</pre>
<h5>Renderer Process</h5>
<pre>
<code>
const ipc = require('electron').ipcRenderer
const trayBtn = document.getElementById('put-in-tray')
let trayOn = false
trayBtn.addEventListener('click', function (event) {
if (trayOn) {
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
ipc.send('remove-tray')
} else {
trayOn = true
const message = 'Click demo again to remove.'
document.getElementById('tray-countdown').innerHTML = message
ipc.send('put-in-tray')
}
})
// Tray removed from context menu on icon
ipc.on('tray-removed', function () {
ipc.send('remove-tray')
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
})
</code>
</pre>
<div>
<h2>ProTip</h2>
<strong>Tray support in Linux.</strong>
@@ -109,7 +30,7 @@ ipc.on('tray-removed', function () {
will need to install <code>libappindicator1</code> to make the
tray icon work. See the
<a href="https://electronjs.org/docs/api/tray">
full API documentation (opens in new window)
full API documentation
</a>
for more details about using Tray on Linux.
</p>

File diff suppressed because one or more lines are too long

View File

@@ -1,35 +0,0 @@
const { ipcRenderer, shell } = require('electron')
const trayBtn = document.getElementById('put-in-tray')
const links = document.querySelectorAll('a[href]')
let trayOn = false
trayBtn.addEventListener('click', function (event) {
if (trayOn) {
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
ipcRenderer.send('remove-tray')
} else {
trayOn = true
const message = 'Click demo again to remove.'
document.getElementById('tray-countdown').innerHTML = message
ipcRenderer.send('put-in-tray')
}
})
// Tray removed from context menu on icon
ipcRenderer.on('tray-removed', function () {
ipcRenderer.send('remove-tray')
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 32 KiB

0
docs/images/versioning-sketch-2.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -159,7 +159,7 @@ function createWindow () {
})
ipcMain.handle('dark-mode:system', () => {
nativeTheme.themeSouce = 'system'
nativeTheme.themeSource = 'system'
})
}

View File

@@ -135,14 +135,18 @@ a text file. A typical cache might look like this:
## Skip binary download
When installing the `electron` NPM package, it automatically downloads the electron binary.
Under the hood, Electron's JavaScript API binds to a binary that contains its
implementations. Because this binary is crucial to the function of any Electron app,
it is downloaded by default in the `postinstall` step every time you install `electron`
from the npm registry.
This can sometimes be unnecessary, e.g. in a CI environment, when testing another component.
However, if you want to install your project's dependencies but don't need to use
Electron functionality, you can set the `ELECTRON_SKIP_BINARY_DOWNLOAD` environment
variable to prevent the binary from being downloaded. For instance, this feature can
be useful in continuous integration environments when running unit tests that mock
out the `electron` module.
To prevent the binary from being downloaded when you install all npm dependencies you can set the environment variable `ELECTRON_SKIP_BINARY_DOWNLOAD`.
E.g.:
```sh
```sh npm2yarn
ELECTRON_SKIP_BINARY_DOWNLOAD=1 npm install
```

View File

@@ -18,7 +18,7 @@ To show notifications in the Main process, you need to use the
### Show notifications in the Renderer process
Assuming you have a working Electron application from the
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following line to the
`index.html` file before the closing `</body>` tag:
@@ -26,26 +26,22 @@ Assuming you have a working Electron application from the
<script src="renderer.js"></script>
```
and add the `renderer.js` file:
...and add the `renderer.js` file:
```javascript fiddle='docs/fiddles/features/notifications/renderer'
const myNotification = new Notification('Title', {
body: 'Notification from the Renderer process'
})
const NOTIFICATION_TITLE = 'Title'
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
const CLICK_MESSAGE = 'Notification clicked'
myNotification.onclick = () => {
console.log('Notification clicked')
}
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
.onclick = () => console.log(CLICK_MESSAGE)
```
After launching the Electron application, you should see the notification:
![Notification in the Renderer process](../images/notification-renderer.png)
If you open the Console and then click the notification, you will see the
message that was generated after triggering the `onclick` event:
![Onclick message for the notification](../images/message-notification-renderer.png)
Additionally, if you click on the notification, the DOM will update to show "Notification clicked!".
### Show notifications in the Main process

View File

@@ -120,9 +120,9 @@ file in the directory you executed it in. Both files can be analyzed using
the Chrome Developer Tools, using the `Performance` and `Memory` tabs
respectively.
![performance-cpu-prof]
![Performance CPU Profile][performance-cpu-prof]
![performance-heap-prof]
![Performance Heap Memory Profile][performance-heap-prof]
In this example, on the author's machine, we saw that loading `request` took
almost half a second, whereas `node-fetch` took dramatically less memory

View File

@@ -138,7 +138,7 @@ way to import Electron's content scripts.
<!-- Note: This guide doesn't take sandboxing into account, which might fundamentally
change the statements here. -->
Preload scripts contain code that executes in a renderer process before its web content
begins loading. These scripts runs within the renderer context, but are granted more
begins loading. These scripts run within the renderer context, but are granted more
privileges by having access to Node.js APIs.
A preload script can be attached to the main process in the `BrowserWindow` constructor's

View File

@@ -13,39 +13,62 @@ __Application dock menu:__
![macOS Dock Menu][dock-menu-image]
To add a file to recent documents, you need to use the
[app.addRecentDocument][addrecentdocument] API.
## Example
### Add an item to recent documents
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following lines to the
`main.js` file:
### Managing recent documents
```javascript fiddle='docs/fiddles/features/recent-documents'
const { app } = require('electron')
const { app, BrowserWindow } = require('electron')
const fs = require('fs')
const path = require('path')
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
const fileName = 'recently-used.md'
fs.writeFile(fileName, 'Lorem Ipsum', () => {
app.addRecentDocument(path.join(__dirname, fileName))
})
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
app.clearRecentDocuments()
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
```
#### Adding a recent document
To add a file to recent documents, use the
[app.addRecentDocument][addrecentdocument] API.
After launching the Electron application, right click the application icon.
You should see the item you just added. In this guide, the item is a Markdown
file located in the root of the project:
In this guide, the item is a Markdown file located in the root of the project.
You should see `recently-used.md` added to the list of recent files:
![Recent document](../images/recent-documents.png)
### Clear the list of recent documents
#### Clearing the list of recent documents
To clear the list of recent documents, you need to use
[app.clearRecentDocuments][clearrecentdocuments] API in the `main.js` file:
```javascript
const { app } = require('electron')
app.clearRecentDocuments()
```
To clear the list of recent documents, use the
[app.clearRecentDocuments][clearrecentdocuments] API.
In this guide, the list of documents is cleared once all windows have been
closed.
## Additional information

View File

@@ -20,23 +20,40 @@ To set the represented file of window, you can use the
## Example
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following lines to the
`main.js` file:
```javascript fiddle='docs/fiddles/features/represented-file'
const { app, BrowserWindow } = require('electron')
const os = require('os');
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600
})
}
app.whenReady().then(() => {
const win = new BrowserWindow()
win.setRepresentedFilename('/etc/passwd')
win.setRepresentedFilename(os.homedir())
win.setDocumentEdited(true)
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
```
After launching the Electron application, click on the title with `Command` or
`Control` key pressed. You should see a popup with the file you just defined:
`Control` key pressed. You should see a popup with the represented file at the top.
In this guide, this is the current user's home directory:
![Represented file](../images/represented-file.png)

83
docs/tutorial/tray.md Normal file
View File

@@ -0,0 +1,83 @@
---
title: Tray
description: This guide will take you through the process of creating
a Tray icon with its own context menu to the system's notification area.
slug: tray
hide_title: true
---
# Tray
## Overview
<!-- ✍ Update this section if you want to provide more details -->
This guide will take you through the process of creating a
[Tray](https://www.electronjs.org/docs/api/tray) icon with
its own context menu to the system's notification area.
On MacOS and Ubuntu, the Tray will be located on the top
right corner of your screen, adjacent to your battery and wifi icons.
On Windows, the Tray will usually be located in the bottom right corner.
## Example
### main.js
First we must import `app`, `Tray`, `Menu`, `nativeImage` from `electron`.
```js
const { app, Tray, Menu, nativeImage } = require('electron')
```
Next we will create our Tray. To do this, we will use a
[`NativeImage`](https://www.electronjs.org/docs/api/native-image) icon,
which can be created through any one of these
[methods](https://www.electronjs.org/docs/api/native-image#methods).
Note that we wrap our Tray creation code within an
[`app.whenReady`](https://www.electronjs.org/docs/api/app#appwhenready)
as we will need to wait for our electron app to finish initializing.
```js title='main.js'
let tray
app.whenReady().then(() => {
const icon = nativeImage.createFromPath('path/to/asset.png')
tray = new Tray(icon)
// note: your contextMenu, Tooltip and Title code will go here!
})
```
Great! Now we can start attaching a context menu to our Tray, like so:
```js
const contextMenu = Menu.buildFromTemplate([
{ label: 'Item1', type: 'radio' },
{ label: 'Item2', type: 'radio' },
{ label: 'Item3', type: 'radio', checked: true },
{ label: 'Item4', type: 'radio' }
])
tray.setContextMenu(contextMenu)
```
The code above will create 4 separate radio-type items in the context menu.
To read more about constructing native menus, click
[here](https://www.electronjs.org/docs/api/menu#menubuildfromtemplatetemplate).
Finally, let's give our tray a tooltip and a title.
```js
tray.setToolTip('This is my application')
tray.setTitle('This is my title')
```
## Conclusion
After you start your electron app, you should see the Tray residing
in either the top or bottom right of your screen, depending on your
operating system.
```fiddle docs/fiddles/native-ui/tray
```

View File

@@ -490,63 +490,83 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
}
};
function fsReadFileAsar (pathArgument: string, options: any, callback: any) {
const pathInfo = splitPath(pathArgument);
if (pathInfo.isAsar) {
const { asarPath, filePath } = pathInfo;
if (typeof options === 'function') {
callback = options;
options = { encoding: null };
} else if (typeof options === 'string') {
options = { encoding: options };
} else if (options === null || options === undefined) {
options = { encoding: null };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
}
const { encoding } = options;
const archive = getOrCreateArchive(asarPath);
if (!archive) {
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
nextTick(callback, [error]);
return;
}
const info = archive.getFileInfo(filePath);
if (!info) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
if (info.size === 0) {
nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]);
return;
}
if (info.unpacked) {
const realPath = archive.copyFileOut(filePath);
return fs.readFile(realPath, options, callback);
}
const buffer = Buffer.alloc(info.size);
const fd = archive.getFd();
if (!(fd >= 0)) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
logASARAccess(asarPath, filePath, info.offset);
fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
callback(error, encoding ? buffer.toString(encoding) : buffer);
});
}
}
const { readFile } = fs;
fs.readFile = function (pathArgument: string, options: any, callback: any) {
const pathInfo = splitPath(pathArgument);
if (!pathInfo.isAsar) return readFile.apply(this, arguments);
const { asarPath, filePath } = pathInfo;
if (typeof options === 'function') {
callback = options;
options = { encoding: null };
} else if (typeof options === 'string') {
options = { encoding: options };
} else if (options === null || options === undefined) {
options = { encoding: null };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
if (!pathInfo.isAsar) {
return readFile.apply(this, arguments);
}
const { encoding } = options;
const archive = getOrCreateArchive(asarPath);
if (!archive) {
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
nextTick(callback, [error]);
return;
}
const info = archive.getFileInfo(filePath);
if (!info) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
if (info.size === 0) {
nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]);
return;
}
if (info.unpacked) {
const realPath = archive.copyFileOut(filePath);
return fs.readFile(realPath, options, callback);
}
const buffer = Buffer.alloc(info.size);
const fd = archive.getFd();
if (!(fd >= 0)) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
logASARAccess(asarPath, filePath, info.offset);
fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
callback(error, encoding ? buffer.toString(encoding) : buffer);
});
return fsReadFileAsar(pathArgument, options, callback);
};
fs.promises.readFile = util.promisify(fs.readFile);
const { readFile: readFilePromise } = fs.promises;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fs.promises.readFile = function (pathArgument: string, options: any) {
const pathInfo = splitPath(pathArgument);
if (!pathInfo.isAsar) {
return readFilePromise.apply(this, arguments);
}
const p = util.promisify(fsReadFileAsar);
return p(pathArgument, options);
};
const { readFileSync } = fs;
fs.readFileSync = function (pathArgument: string, options: any) {

View File

@@ -76,6 +76,7 @@ ipcMainInternal.on(
const referrer: Electron.Referrer = { url: '', policy: 'strict-origin-when-cross-origin' };
const browserWindowOptions = event.sender._callWindowOpenHandler(event, { url, frameName, features, disposition: 'new-window', referrer });
if (event.defaultPrevented) {
event.returnValue = null;
return;
}
const guest = openGuestWindow({

View File

@@ -1,16 +1,32 @@
import { internalContextBridge } from '@electron/internal/renderer/api/context-bridge';
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
import { webFrame } from 'electron/renderer';
import { IPC_MESSAGES } from '../common/ipc-messages';
const { contextIsolationEnabled } = internalContextBridge;
/* Corrects for some Inspector adaptations needed in Electron.
* 1) Use menu API to show context menu.
* 2) Correct for Chromium returning undefined for filesystem.
* 3) Use dialog API to override file chooser dialog.
*/
window.onload = function () {
// Use menu API to show context menu.
window.InspectorFrontendHost!.showContextMenuAtPoint = createMenu;
// correct for Chromium returning undefined for filesystem
window.Persistence!.FileSystemWorkspaceBinding.completeURL = completeURL;
// Use dialog API to override file chooser dialog.
window.UI!.createFileSelectorElement = createFileSelectorElement;
if (contextIsolationEnabled) {
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
'InspectorFrontendHost', 'showContextMenuAtPoint'
], createMenu);
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
'Persistence', 'FileSystemWorkspaceBinding', 'completeURL'
], completeURL);
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
'UI', 'createFileSelectorElement'
], createFileSelectorElement);
} else {
window.InspectorFrontendHost!.showContextMenuAtPoint = createMenu;
window.Persistence!.FileSystemWorkspaceBinding.completeURL = completeURL;
window.UI!.createFileSelectorElement = createFileSelectorElement;
}
};
// Extra / is needed as a result of MacOS requiring absolute paths
@@ -36,9 +52,10 @@ const createMenu = function (x: number, y: number, items: ContextMenuItem[]) {
const isEditMenu = useEditMenuItems(x, y, items);
ipcRendererInternal.invoke<number>(IPC_MESSAGES.INSPECTOR_CONTEXT_MENU, items, isEditMenu).then(id => {
if (typeof id === 'number') {
window.DevToolsAPI!.contextMenuItemSelected(id);
webFrame.executeJavaScript(`window.DevToolsAPI.contextMenuItemSelected(${JSON.stringify(id)})`);
}
window.DevToolsAPI!.contextMenuCleared();
webFrame.executeJavaScript('window.DevToolsAPI.contextMenuCleared()');
});
};

View File

@@ -270,9 +270,7 @@ const warnAboutAllowedPopups = function () {
// Logs a warning message about the remote module
const warnAboutRemoteModuleWithRemoteContent = function (webPreferences?: Electron.WebPreferences) {
if (!webPreferences || isLocalhost()) return;
const remoteModuleEnabled = webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : true;
if (!remoteModuleEnabled) return;
if (!webPreferences || !webPreferences.enableRemoteModule || isLocalhost()) return;
if (getIsRemoteProtocol()) {
const warning = `This renderer process has "enableRemoteModule" enabled
@@ -298,7 +296,9 @@ const logSecurityWarnings = function (
warnAboutEnableBlinkFeatures(webPreferences);
warnAboutInsecureCSP();
warnAboutAllowedPopups();
warnAboutRemoteModuleWithRemoteContent(webPreferences);
if (BUILDFLAG(ENABLE_REMOTE_MODULE)) {
warnAboutRemoteModuleWithRemoteContent(webPreferences);
}
};
const getWebPreferences = async function () {

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "13.1.1",
"version": "13.1.5",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {

View File

@@ -113,3 +113,4 @@ build_libc_as_static_library.patch
cherry-pick-3299d70b7d0f.patch
support_runtime_configurable_key_storage_on_linux_os_crypto.patch
make_keychain_service_account_optionally_configurable_at_runtime.patch
don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch

View File

@@ -1,16 +1,16 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cheng Zhao <zcbenz@gmail.com>
Date: Thu, 4 Oct 2018 14:57:02 -0700
Subject: accelerator.patch
Subject: fix: improve shortcut text of Accelerator
This patch makes three changes to Accelerator::GetShortcutText to improve shortcut display text in menus:
1. Ctrl-Alt-<Key> accelerators show as Ctrl-Alt-<Key> instead of as Ctrl-<Key>
2. F2-F24 accelerators show up as such
3. Ctrl-Shift-= should show as Ctrl-+
3. Ctrl-Shift-= and Ctrl-Plus show up as such
diff --git a/ui/base/accelerators/accelerator.cc b/ui/base/accelerators/accelerator.cc
index c44f3d3752025bd3f11db790a97a48e8ba856034..8e0c1446315823a391614b19aa2c4ba2e5faed0d 100644
index c44f3d3752025bd3f11db790a97a48e8ba856034..8b1859b18aa7ebcecf4c2a90b4ced0186d258ddc 100644
--- a/ui/base/accelerators/accelerator.cc
+++ b/ui/base/accelerators/accelerator.cc
@@ -11,6 +11,7 @@
@@ -21,61 +21,39 @@ index c44f3d3752025bd3f11db790a97a48e8ba856034..8e0c1446315823a391614b19aa2c4ba2
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -27,9 +28,7 @@
#include <windows.h>
@@ -209,6 +210,11 @@ std::u16string Accelerator::GetShortcutText() const {
#endif
-#if !defined(OS_WIN) && (defined(USE_AURA) || defined(OS_MAC))
#include "ui/events/keycodes/keyboard_code_conversion.h"
-#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/ui_base_features.h"
@@ -208,7 +207,15 @@ std::u16string Accelerator::GetShortcutText() const {
shortcut = KeyCodeToName();
#endif
+ unsigned int flags = 0;
if (shortcut.empty()) {
+ const uint16_t c = DomCodeToUsLayoutCharacter(
+ UsLayoutKeyboardCodeToDomCode(key_code_), flags);
+ if (c != 0) {
+ shortcut =
+ static_cast<std::u16string::value_type>(
+ base::ToUpperASCII(static_cast<char16_t>(c)));
+ }
+ // When a shifted char is explicitly specified, for example Ctrl+Plus,
+ // use the shifted char directly.
+ if (shifted_char) {
+ shortcut += *shifted_char;
+ } else {
#if defined(OS_WIN)
// Our fallback is to try translate the key code to a regular character
// unless it is one of digits (VK_0 to VK_9). Some keyboard
@@ -217,21 +224,14 @@ std::u16string Accelerator::GetShortcutText() const {
// accent' for '0'). For display in the menu (e.g. Ctrl-0 for the
// default zoom level), we leave VK_[0-9] alone without translation.
wchar_t key;
- if (base::IsAsciiDigit(key_code_))
+ if (base::IsAsciiDigit(key_code_)) {
key = static_cast<wchar_t>(key_code_);
- else
- key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR));
- // If there is no translation for the given |key_code_| (e.g.
- // VKEY_UNKNOWN), |::MapVirtualKeyW| returns 0.
- if (key != 0)
- shortcut += key;
-#elif defined(USE_AURA) || defined(OS_MAC) || defined(OS_ANDROID)
- const uint16_t c = DomCodeToUsLayoutCharacter(
- UsLayoutKeyboardCodeToDomCode(key_code_), false);
- if (c != 0)
- shortcut +=
- static_cast<std::u16string::value_type>(base::ToUpperASCII(c));
+ shortcut = key;
+ }
@@ -232,6 +238,10 @@ std::u16string Accelerator::GetShortcutText() const {
shortcut +=
static_cast<std::u16string::value_type>(base::ToUpperASCII(c));
#endif
+ }
+ if (key_code_ > VKEY_F1 && key_code_ <= VKEY_F24)
+ shortcut = base::UTF8ToUTF16(
+ base::StringPrintf("F%d", key_code_ - VKEY_F1 + 1));
}
#if defined(OS_MAC)
@@ -427,7 +427,7 @@ std::u16string Accelerator::ApplyLongFormModifiers(
@@ -419,7 +429,7 @@ std::u16string Accelerator::ApplyLongFormModifiers(
const std::u16string& shortcut) const {
std::u16string result = shortcut;
- if (IsShiftDown())
+ if (!shifted_char && IsShiftDown())
result = ApplyModifierToAcceleratorString(result, IDS_APP_SHIFT_KEY);
// Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut.
@@ -427,7 +437,7 @@ std::u16string Accelerator::ApplyLongFormModifiers(
// more information.
if (IsCtrlDown())
result = ApplyModifierToAcceleratorString(result, IDS_APP_CTRL_KEY);
@@ -84,3 +62,24 @@ index c44f3d3752025bd3f11db790a97a48e8ba856034..8e0c1446315823a391614b19aa2c4ba2
result = ApplyModifierToAcceleratorString(result, IDS_APP_ALT_KEY);
if (IsCmdDown()) {
diff --git a/ui/base/accelerators/accelerator.h b/ui/base/accelerators/accelerator.h
index 62eacbe23f949cf62b86a775d331459ae3934048..008b753809f34b72d0c1de46916c0d36eb90a8f5 100644
--- a/ui/base/accelerators/accelerator.h
+++ b/ui/base/accelerators/accelerator.h
@@ -16,6 +16,7 @@
#include <utility>
#include "base/component_export.h"
+#include "base/optional.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "ui/events/event_constants.h"
@@ -100,6 +101,8 @@ class COMPONENT_EXPORT(UI_BASE) Accelerator {
return interrupted_by_mouse_event_;
}
+ base::Optional<char16_t> shifted_char;
+
private:
std::u16string ApplyLongFormModifiers(const std::u16string& shortcut) const;
std::u16string ApplyShortFormModifiers(const std::u16string& shortcut) const;

View File

@@ -9,10 +9,10 @@ potentially prevent a window from being created.
TODO(loc): this patch is currently broken.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 08a3eb686360e7a53cca75437cbe5f4d15cb9a17..78d3287ef7a708f44bd8ef0290618ef781f09d9c 100644
index 7f7e6adf57128f1e8b0890aa14102fe4db452cb2..59d855ec17efe9117ee9bca5074b1ab28dfb40fa 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -5440,6 +5440,7 @@ void RenderFrameHostImpl::CreateNewWindow(
@@ -5430,6 +5430,7 @@ void RenderFrameHostImpl::CreateNewWindow(
last_committed_origin_, params->window_container_type,
params->target_url, params->referrer.To<Referrer>(),
params->frame_name, params->disposition, *params->features,

View File

@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Kleinschmidt <jkleinsc@electronjs.org>
Date: Wed, 16 Jun 2021 11:30:28 -0400
Subject: Don't run PCScan functions if PCScan is disabled
PCScan should not be invoked if PCScan is disabled. Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/2916657.
diff --git a/base/allocator/partition_allocator/memory_reclaimer.cc b/base/allocator/partition_allocator/memory_reclaimer.cc
index 76927a8939b2ead660cf25cecb67a4fa095d98ec..7e922a28b8fa67bb971871c0e54ae59d9086db22 100644
--- a/base/allocator/partition_allocator/memory_reclaimer.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer.cc
@@ -7,6 +7,7 @@
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/partition_alloc_config.h"
+#include "base/allocator/partition_allocator/partition_alloc_features.h"
#include "base/allocator/partition_allocator/starscan/pcscan.h"
#include "base/bind.h"
#include "base/location.h"
@@ -121,6 +122,7 @@ void PartitionAllocMemoryReclaimer::Reclaim(int flags) {
AutoLock lock(lock_); // Has to protect from concurrent (Un)Register calls.
TRACE_EVENT0("base", "PartitionAllocMemoryReclaimer::Reclaim()");
+#if PA_ALLOW_PCSCAN
// PCScan quarantines freed slots. Trigger the scan first to let it call
// FreeNoHooksImmediate on slots that pass the quarantine.
//
@@ -130,13 +132,14 @@ void PartitionAllocMemoryReclaimer::Reclaim(int flags) {
//
// Lastly decommit empty slot spans and lastly try to discard unused pages at
// the end of the remaining active slots.
- {
+ if (base::FeatureList::IsEnabled(base::features::kPartitionAllocPCScan)) {
using PCScan = internal::PCScan;
const auto invocation_mode = flags & PartitionPurgeAggressiveReclaim
? PCScan::InvocationMode::kForcedBlocking
: PCScan::InvocationMode::kBlocking;
PCScan::Instance().PerformScanIfNeeded(invocation_mode);
}
+#endif
#if defined(PA_THREAD_CACHE_SUPPORTED)
// Don't completely empty the thread cache outside of low memory situations,

View File

@@ -449,7 +449,7 @@ index 85073b2f5d58d3e071fb6ef30598973b4d00eda8..c81c820d61da3c7d1cfd2c516147c954
NSString * const SQRLUpdaterErrorDomain = @"SQRLUpdaterErrorDomain";
diff --git a/Squirrel/SQRLZipArchiver.m b/Squirrel/SQRLZipArchiver.m
index f84127f642516078249925953e97621909265deb..478509cdd528db4fcfa340c6f93fa58a446957e6 100644
index cbc8fb61c66184c1d76e8b9f52a89292b4e9939c..d0f20f022a4ff392b596bcf0be96ab3e3c835285 100644
--- a/Squirrel/SQRLZipArchiver.m
+++ b/Squirrel/SQRLZipArchiver.m
@@ -7,8 +7,8 @@
@@ -508,7 +508,7 @@ index 0000000000000000000000000000000000000000..bdfaf95f3eca65b3e0831db1b66f651d
+}
diff --git a/build/xcrun.py b/build/xcrun.py
new file mode 100644
index 0000000000000000000000000000000000000000..20d0cdb51cc933f56b7a7193c195457e82500870
index 0000000000000000000000000000000000000000..18ac587f80441106405d00fafd9ee1f25b147772
--- /dev/null
+++ b/build/xcrun.py
@@ -0,0 +1,14 @@
@@ -524,7 +524,7 @@ index 0000000000000000000000000000000000000000..20d0cdb51cc933f56b7a7193c195457e
+try:
+ subprocess.check_output(args, stderr=subprocess.STDOUT)
+except subprocess.CalledProcessError as e:
+ print("xcrun script '" + sys.argv[2] + "' failed with code '" + str(e.returncode) + "':\n" + e.output)
+ print("xcrun script '" + ' '.join(sys.argv[1:]) + "' failed with code '" + str(e.returncode) + "':\n" + e.output)
+ sys.exit(e.returncode)
diff --git a/filenames.gni b/filenames.gni
new file mode 100644

View File

@@ -6,10 +6,10 @@ Subject: fix: ensure that self is retained until the RACSignal is complete
Looks like the clang that Chromium uses is slightly smarter with ARC than whatever Squirrel was built with previously. We now need to keep a reference to self to keep it alive into the "then" of the RACSignal.
diff --git a/Squirrel/SQRLZipArchiver.m b/Squirrel/SQRLZipArchiver.m
index 478509cdd528db4fcfa340c6f93fa58a446957e6..7c279bf73c368453bff4f922d76908c06dc378cd 100644
index d0f20f022a4ff392b596bcf0be96ab3e3c835285..68f5dac8e553638f41306956df9d38eeda18f8f2 100644
--- a/Squirrel/SQRLZipArchiver.m
+++ b/Squirrel/SQRLZipArchiver.m
@@ -134,7 +134,7 @@ - (RACSignal *)launchWithArguments:(NSArray *)arguments {
@@ -135,7 +135,7 @@ - (RACSignal *)launchWithArguments:(NSArray *)arguments {
return [RACSignal
zip:@[ self.taskTerminated, self.standardErrorData ]
reduce:^(NSNumber *exitStatus, NSData *errorData) {

View File

@@ -19,10 +19,10 @@ index 50173de3f145b4febcc29c03080306c137918527..1ac347ede7e51559917f09442ac4824f
isolate->default_microtask_queue()->PerformCheckpoint(this);
}
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index 823d37fd02d0169f0cb2785f9aa3395c5970711e..db6c29b72dd45f625b9876dab0e68ee56c9fae66 100644
index af55137e1f6026f5e97f7b496ee71b78ddeb665b..582fc6302bddc736d71cb650d45d6bf9deafa9b2 100644
--- a/src/heap/heap.cc
+++ b/src/heap/heap.cc
@@ -5600,9 +5600,9 @@ void Heap::TearDown() {
@@ -5607,9 +5607,9 @@ void Heap::TearDown() {
void Heap::AddGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,
GCType gc_type, void* data) {
DCHECK_NOT_NULL(callback);

View File

@@ -230,6 +230,7 @@ async function callAppVeyor (targetBranch, job, options) {
accountName: 'electron-bot',
projectSlug: appVeyorJobs[job],
branch: targetBranch,
commitId: options.commit || undefined,
environmentVariables
}),
method: 'POST'
@@ -365,7 +366,7 @@ if (require.main === module) {
if (args._.length < 1) {
console.log(`Trigger CI to build release builds of electron.
Usage: ci-release-build.js [--job=CI_JOB_NAME] [--ci=CircleCI|AppVeyor|VSTS|DevOps]
[--ghRelease] [--armTest] [--circleBuildNum=xxx] [--appveyorJobId=xxx] TARGET_BRANCH
[--ghRelease] [--armTest] [--circleBuildNum=xxx] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH
`);
process.exit(0);
}

View File

@@ -88,9 +88,9 @@ bool SubprocessNeedsResourceBundle(const std::string& process_type) {
#if defined(OS_MAC)
// Mac needs them too for scrollbar related images and for sandbox
// profiles.
process_type == ::switches::kPpapiPluginProcess ||
process_type == ::switches::kGpuProcess ||
#endif
process_type == ::switches::kPpapiPluginProcess ||
process_type == ::switches::kRendererProcess ||
process_type == ::switches::kUtilityProcess;
}

View File

@@ -536,10 +536,16 @@ void OnClientCertificateSelected(
if (!certs.empty()) {
scoped_refptr<net::X509Certificate> cert(certs[0].get());
for (auto& identity : *identities) {
if (cert->EqualsExcludingChain(identity->certificate())) {
scoped_refptr<net::X509Certificate> identity_cert =
identity->certificate();
// Since |cert| was recreated from |data|, it won't include any
// intermediates. That's fine for checking equality, but once a match is
// found then |identity_cert| should be used since it will include the
// intermediates which would otherwise be lost.
if (cert->EqualsExcludingChain(identity_cert.get())) {
net::ClientCertIdentity::SelfOwningAcquirePrivateKey(
std::move(identity),
base::BindRepeating(&GotPrivateKey, delegate, std::move(cert)));
std::move(identity), base::BindRepeating(&GotPrivateKey, delegate,
std::move(identity_cert)));
break;
}
}

View File

@@ -867,6 +867,10 @@ void BaseWindow::SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value) {
}
#if defined(OS_MAC)
std::string BaseWindow::GetAlwaysOnTopLevel() {
return window_->GetAlwaysOnTopLevel();
}
void BaseWindow::SetWindowButtonVisibility(bool visible) {
window_->SetWindowButtonVisibility(visible);
}
@@ -1253,6 +1257,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("isVisibleOnAllWorkspaces",
&BaseWindow::IsVisibleOnAllWorkspaces)
#if defined(OS_MAC)
.SetMethod("_getAlwaysOnTopLevel", &BaseWindow::GetAlwaysOnTopLevel)
.SetMethod("setAutoHideCursor", &BaseWindow::SetAutoHideCursor)
#endif
.SetMethod("setVibrancy", &BaseWindow::SetVibrancy)

View File

@@ -191,6 +191,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
virtual void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value);
#if defined(OS_MAC)
std::string GetAlwaysOnTopLevel();
void SetWindowButtonVisibility(bool visible);
bool GetWindowButtonVisibility() const;
void SetTrafficLightPosition(const gfx::Point& position);

View File

@@ -393,6 +393,10 @@ void BrowserWindow::ResetBrowserViews() {
#endif
}
void BrowserWindow::OnDevToolsResized() {
UpdateDraggableRegions(draggable_regions_);
}
void BrowserWindow::SetVibrancy(v8::Isolate* isolate,
v8::Local<v8::Value> value) {
std::string type = gin::V8ToString(isolate, value);

View File

@@ -63,9 +63,7 @@ class BrowserWindow : public BaseWindow,
void OnActivateContents() override;
void OnPageTitleUpdated(const std::u16string& title,
bool explicit_set) override;
#if defined(OS_MAC)
void OnDevToolsResized() override;
#endif
// NativeWindowObserver:
void RequestPreferredWidth(int* width) override;
@@ -121,9 +119,7 @@ class BrowserWindow : public BaseWindow,
// it should be cancelled when we can prove that the window is responsive.
base::CancelableClosure window_unresponsive_closure_;
#if defined(OS_MAC)
std::vector<mojom::DraggableRegionPtr> draggable_regions_;
#endif
v8::Global<v8::Value> web_contents_;
base::WeakPtr<api::WebContents> api_web_contents_;

View File

@@ -37,10 +37,6 @@ void BrowserWindow::OverrideNSWindowContentView(
[contentView viewDidMoveToWindow];
}
void BrowserWindow::OnDevToolsResized() {
UpdateDraggableRegions(draggable_regions_);
}
void BrowserWindow::UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) {
if (window_->has_frame())

View File

@@ -5,6 +5,7 @@
#include "shell/browser/api/electron_api_browser_window.h"
#include "shell/browser/native_window_views.h"
#include "ui/aura/window.h"
namespace electron {
@@ -14,8 +15,20 @@ void BrowserWindow::UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) {
if (window_->has_frame())
return;
if (&draggable_regions_ != &regions) {
auto const offset =
web_contents()->GetNativeView()->GetBoundsInRootWindow();
auto snapped_regions = mojo::Clone(regions);
for (auto& snapped_region : snapped_regions) {
snapped_region->bounds.Offset(offset.x(), offset.y());
}
draggable_regions_ = mojo::Clone(snapped_regions);
}
static_cast<NativeWindowViews*>(window_.get())
->UpdateDraggableRegions(regions);
->UpdateDraggableRegions(draggable_regions_);
}
} // namespace api

View File

@@ -293,6 +293,7 @@ v8::Local<v8::Promise> Cookies::Set(v8::Isolate* isolate,
const std::string* url_string = details.FindStringKey("url");
if (!url_string) {
promise.RejectWithErrorMessage("Missing required option 'url'");
return handle;
}
const std::string* name = details.FindStringKey("name");
const std::string* value = details.FindStringKey("value");

View File

@@ -236,11 +236,13 @@ std::u16string Menu::GetToolTipAt(int index) const {
return model_->GetToolTipAt(index);
}
std::u16string Menu::GetAcceleratorTextAt(int index) const {
#if DCHECK_IS_ON()
std::u16string Menu::GetAcceleratorTextAtForTesting(int index) const {
ui::Accelerator accelerator;
model_->GetAcceleratorAtWithParams(index, true, &accelerator);
return accelerator.GetShortcutText();
}
#endif
bool Menu::IsItemCheckedAt(int index) const {
return model_->IsItemCheckedAt(index);
@@ -289,13 +291,15 @@ v8::Local<v8::ObjectTemplate> Menu::FillObjectTemplate(
.SetMethod("getLabelAt", &Menu::GetLabelAt)
.SetMethod("getSublabelAt", &Menu::GetSublabelAt)
.SetMethod("getToolTipAt", &Menu::GetToolTipAt)
.SetMethod("getAcceleratorTextAt", &Menu::GetAcceleratorTextAt)
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
.SetMethod("worksWhenHiddenAt", &Menu::WorksWhenHiddenAt)
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
.SetMethod("popupAt", &Menu::PopupAt)
.SetMethod("closePopupAt", &Menu::ClosePopupAt)
#if DCHECK_IS_ON()
.SetMethod("getAcceleratorTextAt", &Menu::GetAcceleratorTextAtForTesting)
#endif
.Build();
}

View File

@@ -78,6 +78,9 @@ class Menu : public gin::Wrappable<Menu>,
int positioning_item,
base::OnceClosure callback) = 0;
virtual void ClosePopupAt(int32_t window_id) = 0;
#if DCHECK_IS_ON()
virtual std::u16string GetAcceleratorTextAtForTesting(int index) const;
#endif
std::unique_ptr<ElectronMenuModel> model_;
Menu* parent_ = nullptr;
@@ -111,7 +114,6 @@ class Menu : public gin::Wrappable<Menu>,
std::u16string GetLabelAt(int index) const;
std::u16string GetSublabelAt(int index) const;
std::u16string GetToolTipAt(int index) const;
std::u16string GetAcceleratorTextAt(int index) const;
bool IsItemCheckedAt(int index) const;
bool IsEnabledAt(int index) const;
bool IsVisibleAt(int index) const;

View File

@@ -35,11 +35,14 @@ class MenuMac : public Menu {
int positioning_item,
base::OnceClosure callback);
void ClosePopupAt(int32_t window_id) override;
void ClosePopupOnUI(int32_t window_id);
#if DCHECK_IS_ON()
std::u16string GetAcceleratorTextAtForTesting(int index) const override;
#endif
private:
friend class Menu;
void ClosePopupOnUI(int32_t window_id);
void OnClosed(int32_t window_id, base::OnceClosure callback);
scoped_nsobject<ElectronMenuController> menu_controller_;

View File

@@ -127,6 +127,44 @@ void MenuMac::ClosePopupAt(int32_t window_id) {
std::move(close_popup));
}
#if DCHECK_IS_ON()
std::u16string MenuMac::GetAcceleratorTextAtForTesting(int index) const {
// A least effort to get the real shortcut text of NSMenuItem, the code does
// not need to be perfect since it is test only.
base::scoped_nsobject<ElectronMenuController> controller(
[[ElectronMenuController alloc] initWithModel:model()
useDefaultAccelerator:NO]);
NSMenuItem* item = [[controller menu] itemAtIndex:index];
std::u16string text;
NSEventModifierFlags modifiers = [item keyEquivalentModifierMask];
if (modifiers & NSEventModifierFlagControl)
text += u"Ctrl";
if (modifiers & NSEventModifierFlagShift) {
if (!text.empty())
text += u"+";
text += u"Shift";
}
if (modifiers & NSEventModifierFlagOption) {
if (!text.empty())
text += u"+";
text += u"Alt";
}
if (modifiers & NSEventModifierFlagCommand) {
if (!text.empty())
text += u"+";
text += u"Command";
}
if (!text.empty())
text += u"+";
auto key = base::ToUpperASCII(base::SysNSStringToUTF16([item keyEquivalent]));
if (key == u"\t")
text += u"Tab";
else
text += key;
return text;
}
#endif
void MenuMac::ClosePopupOnUI(int32_t window_id) {
auto controller = popup_controllers_.find(window_id);
if (controller != popup_controllers_.end()) {

View File

@@ -3469,6 +3469,30 @@ void WebContents::DevToolsSearchInPath(int request_id,
file_system_path));
}
void WebContents::DevToolsSetEyeDropperActive(bool active) {
auto* web_contents = GetWebContents();
if (!web_contents)
return;
if (active) {
eye_dropper_ = std::make_unique<DevToolsEyeDropper>(
web_contents, base::BindRepeating(&WebContents::ColorPickedInEyeDropper,
base::Unretained(this)));
} else {
eye_dropper_.reset();
}
}
void WebContents::ColorPickedInEyeDropper(int r, int g, int b, int a) {
base::DictionaryValue color;
color.SetInteger("r", r);
color.SetInteger("g", g);
color.SetInteger("b", b);
color.SetInteger("a", a);
inspectable_web_contents_->CallClientFunction(
"DevToolsAPI.eyeDropperPickedColor", &color, nullptr, nullptr);
}
#if defined(TOOLKIT_VIEWS) && !defined(OS_MAC)
gfx::ImageSkia WebContents::GetDevToolsWindowIcon() {
if (!owner_window())

View File

@@ -14,6 +14,7 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "chrome/browser/devtools/devtools_eye_dropper.h"
#include "chrome/browser/devtools/devtools_file_system_indexer.h"
#include "content/common/cursors/webcursor.h"
#include "content/common/frame.mojom.h"
@@ -663,6 +664,7 @@ class WebContents : public gin::Wrappable<WebContents>,
void DevToolsSearchInPath(int request_id,
const std::string& file_system_path,
const std::string& query) override;
void DevToolsSetEyeDropperActive(bool active) override;
// InspectableWebContentsViewDelegate:
#if defined(TOOLKIT_VIEWS) && !defined(OS_MAC)
@@ -676,6 +678,8 @@ class WebContents : public gin::Wrappable<WebContents>,
// Destroy the managed InspectableWebContents object.
void ResetManagedWebContents(bool async);
void ColorPickedInEyeDropper(int r, int g, int b, int a);
// DevTools index event callbacks.
void OnDevToolsIndexingWorkCalculated(int request_id,
const std::string& file_system_path,
@@ -747,6 +751,8 @@ class WebContents : public gin::Wrappable<WebContents>,
scoped_refptr<DevToolsFileSystemIndexer> devtools_file_system_indexer_;
std::unique_ptr<DevToolsEyeDropper> eye_dropper_;
ElectronBrowserContext* browser_context_;
// The stored InspectableWebContents object.

View File

@@ -129,7 +129,7 @@ v8::Local<v8::Value> HttpResponseHeadersToV8(
!value.empty()) {
net::HttpContentDisposition header(value, std::string());
std::string decodedFilename =
header.is_attachment() ? " attachement" : " inline";
header.is_attachment() ? " attachment" : " inline";
decodedFilename += "; filename=" + header.filename();
value = decodedFilename;
}
@@ -214,8 +214,11 @@ void ReadFromResponse(v8::Isolate* isolate,
void ReadFromResponse(v8::Isolate* isolate,
gin::Dictionary* response,
net::HttpRequestHeaders* headers) {
headers->Clear();
response->Get("requestHeaders", headers);
v8::Local<v8::Value> value;
if (response->Get("requestHeaders", &value) && value->IsObject()) {
headers->Clear();
gin::Converter<net::HttpRequestHeaders>::FromV8(isolate, value, headers);
}
}
void ReadFromResponse(v8::Isolate* isolate,

View File

@@ -1107,7 +1107,13 @@ ElectronBrowserClient::GetSystemNetworkContext() {
std::unique_ptr<content::BrowserMainParts>
ElectronBrowserClient::CreateBrowserMainParts(
const content::MainFunctionParams& params) {
return std::make_unique<ElectronBrowserMainParts>(params);
auto browser_main_parts = std::make_unique<ElectronBrowserMainParts>(params);
#if defined(OS_MAC)
browser_main_parts_ = browser_main_parts.get();
#endif
return browser_main_parts;
}
void ElectronBrowserClient::WebNotificationAllowed(
@@ -1817,4 +1823,13 @@ content::BluetoothDelegate* ElectronBrowserClient::GetBluetoothDelegate() {
return bluetooth_delegate_.get();
}
device::GeolocationSystemPermissionManager*
ElectronBrowserClient::GetLocationPermissionManager() {
#if defined(OS_MAC)
return browser_main_parts_->GetLocationPermissionManager();
#else
return nullptr;
#endif
}
} // namespace electron

View File

@@ -33,6 +33,7 @@ class SSLCertRequestInfo;
namespace electron {
class ElectronBrowserMainParts;
class NotificationPresenter;
class PlatformNotificationService;
@@ -89,6 +90,9 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
content::BluetoothDelegate* GetBluetoothDelegate() override;
device::GeolocationSystemPermissionManager* GetLocationPermissionManager()
override;
protected:
void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
content::SpeechRecognitionManagerDelegate*
@@ -342,6 +346,10 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
std::unique_ptr<ElectronSerialDelegate> serial_delegate_;
std::unique_ptr<ElectronBluetoothDelegate> bluetooth_delegate_;
#if defined(OS_MAC)
ElectronBrowserMainParts* browser_main_parts_ = nullptr;
#endif
DISALLOW_COPY_AND_ASSIGN(ElectronBrowserClient);
};

View File

@@ -44,7 +44,6 @@
#include "shell/browser/ui/devtools_manager_delegate.h"
#include "shell/common/api/electron_bindings.h"
#include "shell/common/application_info.h"
#include "shell/common/asar/asar_util.h"
#include "shell/common/electron_paths.h"
#include "shell/common/gin_helper/trackable_object.h"
#include "shell/common/node_bindings.h"
@@ -96,6 +95,7 @@
#endif
#if defined(OS_MAC)
#include "services/device/public/cpp/geolocation/geolocation_system_permission_mac.h"
#include "shell/browser/ui/cocoa/views_delegate_mac.h"
#else
#include "shell/browser/ui/views/electron_views_delegate.h"
@@ -211,9 +211,7 @@ ElectronBrowserMainParts::ElectronBrowserMainParts(
self_ = this;
}
ElectronBrowserMainParts::~ElectronBrowserMainParts() {
asar::ClearArchives();
}
ElectronBrowserMainParts::~ElectronBrowserMainParts() = default;
// static
ElectronBrowserMainParts* ElectronBrowserMainParts::Get() {
@@ -572,6 +570,13 @@ ElectronBrowserMainParts::GetGeolocationControl() {
return geolocation_control_.get();
}
#if defined(OS_MAC)
device::GeolocationSystemPermissionManager*
ElectronBrowserMainParts::GetLocationPermissionManager() {
return location_permission_manager_.get();
}
#endif
IconManager* ElectronBrowserMainParts::GetIconManager() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!icon_manager_.get())

View File

@@ -36,6 +36,10 @@ class GtkUiDelegate;
}
#endif
namespace device {
class GeolocationSystemPermissionManager;
} // namespace device
namespace electron {
class ElectronBrowserContext;
@@ -80,6 +84,10 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
// used to enable the location services once per client.
device::mojom::GeolocationControl* GetGeolocationControl();
#if defined(OS_MAC)
device::GeolocationSystemPermissionManager* GetLocationPermissionManager();
#endif
// Returns handle to the class responsible for extracting file icons.
IconManager* GetIconManager();
@@ -161,6 +169,11 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
mojo::Remote<device::mojom::GeolocationControl> geolocation_control_;
#if defined(OS_MAC)
std::unique_ptr<device::GeolocationSystemPermissionManager>
location_permission_manager_;
#endif
static ElectronBrowserMainParts* self_;
DISALLOW_COPY_AND_ASSIGN(ElectronBrowserMainParts);

View File

@@ -7,6 +7,7 @@
#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/path_service.h"
#include "services/device/public/cpp/geolocation/geolocation_system_permission_mac.h"
#import "shell/browser/mac/electron_application.h"
#include "shell/browser/mac/electron_application_delegate.h"
#include "shell/common/electron_paths.h"
@@ -27,6 +28,9 @@ void ElectronBrowserMainParts::PreMainMessageLoopStart() {
[[NSUserDefaults standardUserDefaults]
setObject:@"NO"
forKey:@"NSTreatUnknownArgumentsAsOpen"];
location_permission_manager_ =
device::GeolocationSystemPermissionManager::Create();
}
void ElectronBrowserMainParts::FreeAppDelegate() {

View File

@@ -10,6 +10,7 @@
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "components/spellcheck/common/spellcheck_features.h"
#include "content/public/common/content_features.h"
#include "electron/buildflags/buildflags.h"
#include "media/base/media_switches.h"
@@ -41,6 +42,13 @@ void InitializeFeatureList() {
#if !BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
disable_features += std::string(",") + media::kPictureInPicture.name;
#endif
#if defined(OS_WIN)
// Disable async spellchecker suggestions for Windows, which causes
// an empty suggestions list to be returned
disable_features +=
std::string(",") + spellcheck::kWinRetrieveSuggestionsOnlyOnDemand.name;
#endif
base::FeatureList::InitializeInstance(enable_features, disable_features);
}

View File

@@ -60,6 +60,7 @@ void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) {
event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
break;
case AdapterPresence::POWERED_ON:
rescan_ = true;
break;
}
}
@@ -92,7 +93,7 @@ void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
case DiscoveryState::DISCOVERING:
// The first time this state fires is due to a rescan triggering so set a
// flag to ignore devices
if (!refreshing_) {
if (rescan_ && !refreshing_) {
refreshing_ = true;
} else {
// The second time this state fires we are now safe to pick a device

View File

@@ -42,6 +42,7 @@ class BluetoothChooser : public content::BluetoothChooser {
EventHandler event_handler_;
int num_retries_ = 0;
bool refreshing_ = false;
bool rescan_ = false;
DISALLOW_COPY_AND_ASSIGN(BluetoothChooser);
};

View File

@@ -201,6 +201,7 @@ class NativeWindow : public base::SupportsUserData,
// Traffic Light API
#if defined(OS_MAC)
virtual std::string GetAlwaysOnTopLevel() = 0;
virtual void SetWindowButtonVisibility(bool visible) = 0;
virtual bool GetWindowButtonVisibility() const = 0;
virtual void SetTrafficLightPosition(base::Optional<gfx::Point> position) = 0;

View File

@@ -79,6 +79,7 @@ class NativeWindowMac : public NativeWindow,
void SetAlwaysOnTop(ui::ZOrderLevel z_order,
const std::string& level,
int relative_level) override;
std::string GetAlwaysOnTopLevel() override;
ui::ZOrderLevel GetZOrderLevel() override;
void Center() override;
void Invalidate() override;
@@ -152,6 +153,9 @@ class NativeWindowMac : public NativeWindow,
void NotifyWindowWillEnterFullScreen();
void NotifyWindowWillLeaveFullScreen();
// Ensure the buttons view are always floated on the top.
void ReorderButtonsView();
// Cleanup observers when window is getting closed. Note that the destructor
// can be called much later after window gets closed, so we should not do
// cleanup in destructor.

View File

@@ -458,11 +458,8 @@ void NativeWindowMac::SetContentView(views::View* view) {
set_content_view(view);
root_view->AddChildView(content_view());
if (buttons_view_) {
// Ensure the buttons view are always floated on the top.
[buttons_view_ removeFromSuperview];
[[window_ contentView] addSubview:buttons_view_];
}
if (buttons_view_)
ReorderButtonsView();
root_view->Layout();
}
@@ -554,6 +551,15 @@ void NativeWindowMac::Hide() {
return;
}
// Hide all children of the current window before hiding the window.
// components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
// expects this when window visibility changes.
if ([window_ childWindows]) {
for (NSWindow* child in [window_ childWindows]) {
[child orderOut:nil];
}
}
// Deattach the window from the parent before.
if (parent())
InternalSetParentWindow(parent(), false);
@@ -869,6 +875,31 @@ void NativeWindowMac::SetAlwaysOnTop(ui::ZOrderLevel z_order,
SetWindowLevel(level + relative_level);
}
std::string NativeWindowMac::GetAlwaysOnTopLevel() {
std::string level_name = "normal";
int level = [window_ level];
if (level == NSFloatingWindowLevel) {
level_name = "floating";
} else if (level == NSTornOffMenuWindowLevel) {
level_name = "torn-off-menu";
} else if (level == NSModalPanelWindowLevel) {
level_name = "modal-panel";
} else if (level == NSMainMenuWindowLevel) {
level_name = "main-menu";
} else if (level == NSStatusWindowLevel) {
level_name = "status";
} else if (level == NSPopUpMenuWindowLevel) {
level_name = "pop-up-menu";
} else if (level == NSScreenSaverWindowLevel) {
level_name = "screen-saver";
} else if (level == NSDockWindowLevel) {
level_name = "dock";
}
return level_name;
}
void NativeWindowMac::SetWindowLevel(int unbounded_level) {
int level = std::min(
std::max(unbounded_level, CGWindowLevelForKey(kCGMinimumWindowLevelKey)),
@@ -1143,6 +1174,8 @@ void NativeWindowMac::AddBrowserView(NativeBrowserView* view) {
}
[CATransaction commit];
ReorderButtonsView();
}
void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
@@ -1184,6 +1217,8 @@ void NativeWindowMac::SetTopBrowserView(NativeBrowserView* view) {
}
[CATransaction commit];
ReorderButtonsView();
}
void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
@@ -1352,8 +1387,6 @@ void NativeWindowMac::SetVibrancy(const std::string& type) {
return;
}
vibrancy_type_ = type;
NSVisualEffectView* effect_view = (NSVisualEffectView*)vibrant_view;
if (effect_view == nil) {
effect_view = [[[NSVisualEffectView alloc]
@@ -1382,7 +1415,7 @@ void NativeWindowMac::SetVibrancy(const std::string& type) {
node::Environment* env =
node::Environment::GetCurrent(JavascriptEnvironment::GetIsolate());
NSVisualEffectMaterial vibrancyType;
NSVisualEffectMaterial vibrancyType{};
if (type == "appearance-based") {
EmitWarning(env, "NSVisualEffectMaterialAppearanceBased" + dep_warn,
"electron");
@@ -1439,8 +1472,10 @@ void NativeWindowMac::SetVibrancy(const std::string& type) {
}
}
if (vibrancyType)
if (vibrancyType) {
vibrancy_type_ = type;
[effect_view setMaterial:vibrancyType];
}
}
void NativeWindowMac::SetWindowButtonVisibility(bool visible) {
@@ -1636,6 +1671,13 @@ void NativeWindowMac::NotifyWindowWillLeaveFullScreen() {
UpdateVibrancyRadii(false);
}
void NativeWindowMac::ReorderButtonsView() {
if (buttons_view_) {
[buttons_view_ removeFromSuperview];
[[window_ contentView] addSubview:buttons_view_];
}
}
void NativeWindowMac::Cleanup() {
DCHECK(!IsClosed());
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
@@ -1786,10 +1828,15 @@ void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,
// Set new parent window.
// Note that this method will force the window to become visible.
if (parent && attach)
if (parent && attach) {
// Attaching a window as a child window resets its window level, so
// save and restore it afterwards.
NSInteger level = window_.level;
[parent->GetNativeWindow().GetNativeNSWindow()
addChildWindow:window_
ordered:NSWindowAbove];
[window_ setLevel:level];
}
}
void NativeWindowMac::SetForwardMouseMessages(bool forward) {

View File

@@ -13,6 +13,7 @@
#include "extensions/browser/extension_navigation_ui_data.h"
#include "net/base/completion_repeating_callback.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/cpp/features.h"
@@ -313,6 +314,14 @@ void ProxyingURLLoaderFactory::InProgressRequest::OnComplete(
void ProxyingURLLoaderFactory::InProgressRequest::OnLoaderCreated(
mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
// When CORS is involved there may be multiple network::URLLoader associated
// with this InProgressRequest, because CorsURLLoader may create a new
// network::URLLoader for the same request id in redirect handling - see
// CorsURLLoader::FollowRedirect. In such a case the old network::URLLoader
// is going to be detached fairly soon, so we don't need to take care of it.
// We need this explicit reset to avoid a DCHECK failure in mojo::Receiver.
header_client_receiver_.reset();
header_client_receiver_.Bind(std::move(receiver));
if (for_cors_preflight_) {
// In this case we don't have |target_loader_| and
@@ -555,13 +564,17 @@ void ProxyingURLLoaderFactory::InProgressRequest::
override_headers_ = nullptr;
if (for_cors_preflight_) {
// If this is for CORS preflight, there is no associated client. We notify
// the completion here, and deletes |this|.
// If this is for CORS preflight, there is no associated client.
info_->AddResponseInfoFromResourceResponse(*current_response_);
// Do not finish proxied preflight requests that require proxy auth.
// The request is not finished yet, give control back to network service
// which will start authentication process.
if (info_->response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED)
return;
// We notify the completion here, and delete |this|.
factory_->web_request_api()->OnResponseStarted(&info_.value(), request_);
factory_->web_request_api()->OnCompleted(&info_.value(), request_, net::OK);
// Deletes |this|.
factory_->RemoveRequest(network_service_request_id_, request_id_);
return;
}

View File

@@ -85,7 +85,7 @@ void URLPipeLoader::OnDataReceived(base::StringPiece string_piece,
producer_->Write(
std::make_unique<mojo::StringDataSource>(
string_piece, mojo::StringDataSource::AsyncWritingMode::
STRING_STAYS_VALID_UNTIL_COMPLETION),
STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION),
base::BindOnce(&URLPipeLoader::OnWrite, weak_factory_.GetWeakPtr(),
std::move(resume)));
}

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 13,1,1,0
PRODUCTVERSION 13,1,1,0
FILEVERSION 13,1,5,0
PRODUCTVERSION 13,1,5,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "13.1.1"
VALUE "FileVersion", "13.1.5"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "13.1.1"
VALUE "ProductVersion", "13.1.5"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -31,10 +31,10 @@ bool StringToAccelerator(const std::string& shortcut,
// Now, parse it into an accelerator.
int modifiers = ui::EF_NONE;
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
base::Optional<char16_t> shifted_char;
for (const auto& token : tokens) {
bool shifted = false;
ui::KeyboardCode code = electron::KeyboardCodeFromStr(token, &shifted);
if (shifted)
ui::KeyboardCode code = electron::KeyboardCodeFromStr(token, &shifted_char);
if (shifted_char)
modifiers |= ui::EF_SHIFT_DOWN;
switch (code) {
// The token can be a modifier.
@@ -65,6 +65,7 @@ bool StringToAccelerator(const std::string& shortcut,
}
*accelerator = ui::Accelerator(key, modifiers);
accelerator->shifted_char = shifted_char;
return true;
}

View File

@@ -160,13 +160,12 @@
// Switch to new state.
devtools_docked_ = docked;
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
auto* devToolsWebContents =
inspectable_web_contents->GetDevToolsWebContents();
auto devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
if (!docked) {
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
auto* devToolsWebContents =
inspectable_web_contents->GetDevToolsWebContents();
auto devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
auto styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
NSMiniaturizableWindowMask | NSWindowStyleMaskResizable |
NSTexturedBackgroundWindowMask |
@@ -189,6 +188,9 @@
devToolsView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[contentView addSubview:devToolsView];
[devToolsView setMouseDownCanMoveWindow:NO];
} else {
[devToolsView setMouseDownCanMoveWindow:YES];
}
[self setDevToolsVisible:YES activate:activate];
}

View File

@@ -21,9 +21,9 @@
#include "shell/browser/ui/electron_menu_model.h"
#include "shell/browser/window_list.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
#include "ui/gfx/image/image.h"
#include "ui/strings/grit/ui_strings.h"
@@ -394,11 +394,31 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
ui::Accelerator accelerator;
if (model->GetAcceleratorAtWithParams(index, useDefaultAccelerator_,
&accelerator)) {
NSString* key_equivalent;
NSUInteger modifier_mask;
GetKeyEquivalentAndModifierMaskFromAccelerator(
accelerator, &key_equivalent, &modifier_mask);
[item setKeyEquivalent:key_equivalent];
// Note that we are not using Chromium's
// GetKeyEquivalentAndModifierMaskFromAccelerator API,
// because it will convert Shift+Character to ShiftedCharacter, for
// example Shift+/ would be converted to ?, which is against macOS HIG.
// See also https://github.com/electron/electron/issues/21790.
NSUInteger modifier_mask = 0;
if (accelerator.IsCtrlDown())
modifier_mask |= NSEventModifierFlagControl;
if (accelerator.IsAltDown())
modifier_mask |= NSEventModifierFlagOption;
if (accelerator.IsCmdDown())
modifier_mask |= NSEventModifierFlagCommand;
unichar character;
if (accelerator.shifted_char) {
// When a shifted char is explicitly specified, for example Ctrl+Plus,
// use the shifted char directly.
character = static_cast<unichar>(*accelerator.shifted_char);
} else {
// Otherwise use the unshifted combinations, for example Ctrl+Shift+=.
if (accelerator.IsShiftDown())
modifier_mask |= NSEventModifierFlagShift;
ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), modifier_mask,
nullptr, &character);
}
[item setKeyEquivalent:[NSString stringWithFormat:@"%C", character]];
[item setKeyEquivalentModifierMask:modifier_mask];
}

View File

@@ -784,7 +784,10 @@ void InspectableWebContents::SearchInPath(int request_id,
void InspectableWebContents::SetWhitelistedShortcuts(
const std::string& message) {}
void InspectableWebContents::SetEyeDropperActive(bool active) {}
void InspectableWebContents::SetEyeDropperActive(bool active) {
if (delegate_)
delegate_->DevToolsSetEyeDropperActive(active);
}
void InspectableWebContents::ShowCertificateViewer(
const std::string& cert_chain) {}

View File

@@ -35,6 +35,7 @@ class InspectableWebContentsDelegate {
virtual void DevToolsSearchInPath(int request_id,
const std::string& file_system_path,
const std::string& query) {}
virtual void DevToolsSetEyeDropperActive(bool active) {}
};
} // namespace electron

View File

@@ -38,6 +38,13 @@ int FramelessView::ResizingBorderHitTest(const gfx::Point& point) {
bool can_ever_resize = frame_->widget_delegate()
? frame_->widget_delegate()->CanResize()
: false;
// https://github.com/electron/electron/issues/611
// If window isn't resizable, we should always return HTCLIENT, otherwise the
// hover state of DOM will not be cleared probably.
if (!can_ever_resize)
return HTCLIENT;
// Don't allow overlapping resize handles when the window is maximized or
// fullscreen, as it can't be resized in those states.
int resize_border = frame_->IsMaximized() || frame_->IsFullscreen()

View File

@@ -128,6 +128,10 @@ void InspectableWebContentsViewViews::ShowDevTools(bool activate) {
} else {
devtools_window_->ShowInactive();
}
// Update draggable regions to account for the new dock position.
if (GetDelegate())
GetDelegate()->DevToolsResized();
} else {
devtools_web_view_->SetVisible(true);
devtools_web_view_->SetWebContents(
@@ -228,6 +232,9 @@ void InspectableWebContentsViewViews::Layout() {
devtools_web_view_->SetBoundsRect(new_devtools_bounds);
contents_web_view_->SetBoundsRect(new_contents_bounds);
if (GetDelegate())
GetDelegate()->DevToolsResized();
}
} // namespace electron

View File

@@ -107,7 +107,7 @@ bool IsSameOrigin(const GURL& l, const GURL& r) {
return url::Origin::Create(l).IsSameOriginWith(url::Origin::Create(r));
}
#ifdef DCHECK_IS_ON
#if DCHECK_IS_ON()
std::vector<v8::Global<v8::Value>> weakly_tracked_values;
void WeaklyTrackValue(v8::Isolate* isolate, v8::Local<v8::Value> value) {
@@ -157,7 +157,7 @@ void Initialize(v8::Local<v8::Object> exports,
dict.SetMethod("requestGarbageCollectionForTesting",
&RequestGarbageCollectionForTesting);
dict.SetMethod("isSameOrigin", &IsSameOrigin);
#ifdef DCHECK_IS_ON
#if DCHECK_IS_ON()
dict.SetMethod("triggerFatalErrorForTesting", &TriggerFatalErrorForTesting);
dict.SetMethod("getWeaklyTrackedValues", &GetWeaklyTrackedValues);
dict.SetMethod("clearWeaklyTrackedValues", &ClearWeaklyTrackedValues);

View File

@@ -8,6 +8,7 @@
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
@@ -118,7 +119,7 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
} // namespace
Archive::Archive(const base::FilePath& path)
: path_(path), file_(base::File::FILE_OK) {
: initialized_(false), path_(path), file_(base::File::FILE_OK) {
base::ThreadRestrictions::ScopedAllowIO allow_io;
file_.Initialize(path_, base::File::FLAG_OPEN | base::File::FLAG_READ);
#if defined(OS_WIN)
@@ -141,6 +142,10 @@ Archive::~Archive() {
}
bool Archive::Init() {
// Should only be initialized once
CHECK(!initialized_);
initialized_ = true;
if (!file_.IsValid()) {
if (file_.error_details() != base::File::FILE_ERROR_NOT_FOUND) {
LOG(WARNING) << "Opening " << path_.value() << ": "
@@ -198,7 +203,7 @@ bool Archive::Init() {
return true;
}
bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) {
bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) const {
if (!header_)
return false;
@@ -213,7 +218,7 @@ bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) {
return FillFileInfoWithNode(info, header_size_, node);
}
bool Archive::Stat(const base::FilePath& path, Stats* stats) {
bool Archive::Stat(const base::FilePath& path, Stats* stats) const {
if (!header_)
return false;
@@ -237,7 +242,7 @@ bool Archive::Stat(const base::FilePath& path, Stats* stats) {
}
bool Archive::Readdir(const base::FilePath& path,
std::vector<base::FilePath>* files) {
std::vector<base::FilePath>* files) const {
if (!header_)
return false;
@@ -257,7 +262,8 @@ bool Archive::Readdir(const base::FilePath& path,
return true;
}
bool Archive::Realpath(const base::FilePath& path, base::FilePath* realpath) {
bool Archive::Realpath(const base::FilePath& path,
base::FilePath* realpath) const {
if (!header_)
return false;
@@ -276,6 +282,11 @@ bool Archive::Realpath(const base::FilePath& path, base::FilePath* realpath) {
}
bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
if (!header_)
return false;
base::AutoLock auto_lock(external_files_lock_);
auto it = external_files_.find(path.value());
if (it != external_files_.end()) {
*out = it->second->path();

View File

@@ -11,6 +11,7 @@
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/synchronization/lock.h"
namespace base {
class DictionaryValue;
@@ -21,7 +22,7 @@ namespace asar {
class ScopedTemporaryFile;
// This class represents an asar package, and provides methods to read
// information from it.
// information from it. It is thread-safe after |Init| has been called.
class Archive {
public:
struct FileInfo {
@@ -46,16 +47,17 @@ class Archive {
bool Init();
// Get the info of a file.
bool GetFileInfo(const base::FilePath& path, FileInfo* info);
bool GetFileInfo(const base::FilePath& path, FileInfo* info) const;
// Fs.stat(path).
bool Stat(const base::FilePath& path, Stats* stats);
bool Stat(const base::FilePath& path, Stats* stats) const;
// Fs.readdir(path).
bool Readdir(const base::FilePath& path, std::vector<base::FilePath>* files);
bool Readdir(const base::FilePath& path,
std::vector<base::FilePath>* files) const;
// Fs.realpath(path).
bool Realpath(const base::FilePath& path, base::FilePath* realpath);
bool Realpath(const base::FilePath& path, base::FilePath* realpath) const;
// Copy the file into a temporary file, and return the new path.
// For unpacked file, this method will return its real path.
@@ -65,16 +67,17 @@ class Archive {
int GetFD() const;
base::FilePath path() const { return path_; }
base::DictionaryValue* header() const { return header_.get(); }
private:
base::FilePath path_;
bool initialized_;
const base::FilePath path_;
base::File file_;
int fd_ = -1;
uint32_t header_size_ = 0;
std::unique_ptr<base::DictionaryValue> header_;
// Cached external temporary files.
base::Lock external_files_lock_;
std::unordered_map<base::FilePath::StringType,
std::unique_ptr<ScopedTemporaryFile>>
external_files_;

View File

@@ -6,11 +6,14 @@
#include <map>
#include <string>
#include <utility>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
#include "shell/common/asar/archive.h"
@@ -19,30 +22,41 @@ namespace asar {
namespace {
// The global instance of ArchiveMap, will be destroyed on exit.
typedef std::map<base::FilePath, std::shared_ptr<Archive>> ArchiveMap;
base::LazyInstance<base::ThreadLocalPointer<ArchiveMap>>::Leaky
g_archive_map_tls = LAZY_INSTANCE_INITIALIZER;
const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar");
std::map<base::FilePath, bool> g_is_directory_cache;
bool IsDirectoryCached(const base::FilePath& path) {
auto it = g_is_directory_cache.find(path);
if (it != g_is_directory_cache.end()) {
static base::NoDestructor<std::map<base::FilePath, bool>>
s_is_directory_cache;
static base::NoDestructor<base::Lock> lock;
base::AutoLock auto_lock(*lock);
auto& is_directory_cache = *s_is_directory_cache;
auto it = is_directory_cache.find(path);
if (it != is_directory_cache.end()) {
return it->second;
}
base::ThreadRestrictions::ScopedAllowIO allow_io;
return g_is_directory_cache[path] = base::DirectoryExists(path);
return is_directory_cache[path] = base::DirectoryExists(path);
}
} // namespace
ArchiveMap& GetArchiveCache() {
static base::NoDestructor<ArchiveMap> s_archive_map;
return *s_archive_map;
}
base::Lock& GetArchiveCacheLock() {
static base::NoDestructor<base::Lock> lock;
return *lock;
}
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path) {
if (!g_archive_map_tls.Pointer()->Get())
g_archive_map_tls.Pointer()->Set(new ArchiveMap);
ArchiveMap& map = *g_archive_map_tls.Pointer()->Get();
base::AutoLock auto_lock(GetArchiveCacheLock());
ArchiveMap& map = GetArchiveCache();
// if we have it, return it
const auto lower = map.lower_bound(path);
@@ -61,8 +75,10 @@ std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path) {
}
void ClearArchives() {
if (g_archive_map_tls.Pointer()->Get())
delete g_archive_map_tls.Pointer()->Get();
base::AutoLock auto_lock(GetArchiveCacheLock());
ArchiveMap& map = GetArchiveCache();
map.clear();
}
bool GetAsarArchivePath(const base::FilePath& full_path,

View File

@@ -16,7 +16,7 @@ namespace asar {
class Archive;
// Gets or creates a new Archive from the path.
// Gets or creates and caches a new Archive from the path.
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path);
// Destroy cached Archive objects.

View File

@@ -187,10 +187,10 @@ bool Converter<blink::WebKeyboardEvent>::FromV8(v8::Isolate* isolate,
if (!dict.Get("keyCode", &str))
return false;
bool shifted = false;
ui::KeyboardCode keyCode = electron::KeyboardCodeFromStr(str, &shifted);
base::Optional<char16_t> shifted_char;
ui::KeyboardCode keyCode = electron::KeyboardCodeFromStr(str, &shifted_char);
out->windows_key_code = keyCode;
if (shifted)
if (shifted_char)
out->SetModifiers(out->GetModifiers() |
blink::WebInputEvent::Modifiers::kShiftKey);

View File

@@ -15,8 +15,9 @@ namespace electron {
namespace {
// Return key code represented by |str|.
ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& s,
bool* shifted) {
ui::KeyboardCode KeyboardCodeFromKeyIdentifier(
const std::string& s,
base::Optional<char16_t>* shifted_char) {
std::string str = base::ToLowerASCII(s);
if (str == "ctrl" || str == "control") {
return ui::VKEY_CONTROL;
@@ -36,7 +37,7 @@ ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& s,
} else if (str == "altgr") {
return ui::VKEY_ALTGR;
} else if (str == "plus") {
*shifted = true;
shifted_char->emplace('+');
return ui::VKEY_OEM_PLUS;
} else if (str == "capslock") {
return ui::VKEY_CAPITAL;
@@ -319,11 +320,17 @@ ui::KeyboardCode KeyboardCodeFromCharCode(char16_t c, bool* shifted) {
}
}
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted) {
if (str.size() == 1)
return KeyboardCodeFromCharCode(str[0], shifted);
else
return KeyboardCodeFromKeyIdentifier(str, shifted);
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str,
base::Optional<char16_t>* shifted_char) {
if (str.size() == 1) {
bool shifted = false;
auto ret = KeyboardCodeFromCharCode(str[0], &shifted);
if (shifted)
shifted_char->emplace(str[0]);
return ret;
} else {
return KeyboardCodeFromKeyIdentifier(str, shifted_char);
}
}
} // namespace electron

View File

@@ -7,6 +7,7 @@
#include <string>
#include "base/optional.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace electron {
@@ -15,9 +16,11 @@ namespace electron {
// pressed.
ui::KeyboardCode KeyboardCodeFromCharCode(char16_t c, bool* shifted);
// Return key code of the |str|, and also determine whether the SHIFT key is
// Return key code of the |str|, if the original key is a shifted character,
// for example + and /, set it in |shifted_char|.
// pressed.
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted);
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str,
base::Optional<char16_t>* shifted_char);
} // namespace electron

View File

@@ -489,9 +489,13 @@ node::Environment* NodeBindings::CreateEnvironment(
// Node.js requires that microtask checkpoints be explicitly invoked.
is.policy = v8::MicrotasksPolicy::kExplicit;
} else {
// Match Blink's behavior by allowing microtasks invocation to be controlled
// by MicrotasksScope objects.
is.policy = v8::MicrotasksPolicy::kScoped;
// Blink expects the microtasks policy to be kScoped, but Node.js expects it
// to be kExplicit. In the renderer, there can be many contexts within the
// same isolate, so we don't want to change the existing policy here, which
// could be either kExplicit or kScoped depending on whether we're executing
// from within a Node.js or a Blink entrypoint. Instead, the policy is
// toggled to kExplicit when entering Node.js through UvRunOnce.
is.policy = context->GetIsolate()->GetMicrotasksPolicy();
// We do not want to use Node.js' message listener as it interferes with
// Blink's.

View File

@@ -688,7 +688,7 @@ void Initialize(v8::Local<v8::Object> exports,
&electron::api::OverrideGlobalPropertyFromIsolatedWorld);
dict.SetMethod("_isCalledFromMainWorld",
&electron::api::IsCalledFromMainWorld);
#ifdef DCHECK_IS_ON
#if DCHECK_IS_ON()
dict.Set("_isDebug", true);
#endif
}

View File

@@ -11,7 +11,6 @@
#include "content/public/renderer/render_frame.h"
#include "electron/buildflags/buildflags.h"
#include "shell/common/api/electron_bindings.h"
#include "shell/common/asar/asar_util.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/event_emitter_caller.h"
#include "shell/common/node_bindings.h"
@@ -40,9 +39,7 @@ ElectronRendererClient::ElectronRendererClient()
NodeBindings::Create(NodeBindings::BrowserEnvironment::kRenderer)),
electron_bindings_(new ElectronBindings(node_bindings_->uv_loop())) {}
ElectronRendererClient::~ElectronRendererClient() {
asar::ClearArchives();
}
ElectronRendererClient::~ElectronRendererClient() = default;
void ElectronRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {

View File

@@ -7,7 +7,6 @@
#include "base/lazy_instance.h"
#include "base/threading/thread_local.h"
#include "shell/common/api/electron_bindings.h"
#include "shell/common/asar/asar_util.h"
#include "shell/common/gin_helper/event_emitter_caller.h"
#include "shell/common/node_bindings.h"
#include "shell/common/node_includes.h"
@@ -39,7 +38,6 @@ WebWorkerObserver::~WebWorkerObserver() {
lazy_tls.Pointer()->Set(nullptr);
node::FreeEnvironment(node_bindings_->uv_env());
node::FreeIsolateData(node_bindings_->isolate_data());
asar::ClearArchives();
}
void WebWorkerObserver::WorkerScriptReadyForEvaluation(

View File

@@ -1418,15 +1418,12 @@ describe('BrowserWindow module', () => {
describe('BrowserWindow.setAlwaysOnTop(flag, level)', () => {
let w = null as unknown as BrowserWindow;
afterEach(closeAllWindows);
beforeEach(() => {
w = new BrowserWindow({ show: true });
});
afterEach(async () => {
await closeWindow(w);
w = null as unknown as BrowserWindow;
});
it('sets the window as always on top', () => {
expect(w.isAlwaysOnTop()).to.be.false('is alwaysOnTop');
w.setAlwaysOnTop(true, 'screen-saver');
@@ -1454,6 +1451,16 @@ describe('BrowserWindow module', () => {
const [, alwaysOnTop] = await alwaysOnTopChanged;
expect(alwaysOnTop).to.be.true('is not alwaysOnTop');
});
ifit(process.platform === 'darwin')('honors the alwaysOnTop level of a child window', () => {
w = new BrowserWindow({ show: false });
const c = new BrowserWindow({ parent: w });
c.setAlwaysOnTop(true, 'screen-saver');
expect(w.isAlwaysOnTop()).to.be.false();
expect(c.isAlwaysOnTop()).to.be.true('child is not always on top');
expect((c as any)._getAlwaysOnTopLevel()).to.equal('screen-saver');
});
});
describe('preconnect feature', () => {
@@ -1597,6 +1604,13 @@ describe('BrowserWindow module', () => {
w.setVibrancy('' as any);
}).to.not.throw();
});
it('does not crash if vibrancy is set to an invalid value', () => {
const w = new BrowserWindow({ show: false });
expect(() => {
w.setVibrancy('i-am-not-a-valid-vibrancy-type' as any);
}).to.not.throw();
});
});
ifdescribe(process.platform === 'darwin')('trafficLightPosition', () => {

View File

@@ -462,9 +462,9 @@ describe('MenuItems', () => {
{ label: 'text', accelerator: 'Alt+A' }
]);
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? 'A' : 'Ctrl+A');
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⇧A' : 'Shift+A');
expect(menu.getAcceleratorTextAt(2)).to.equal(isDarwin() ? '⌥A' : 'Alt+A');
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? 'Command+A' : 'Ctrl+A');
expect(menu.getAcceleratorTextAt(1)).to.equal('Shift+A');
expect(menu.getAcceleratorTextAt(2)).to.equal('Alt+A');
});
it('should display modifiers correctly for special keys', () => {
@@ -474,9 +474,9 @@ describe('MenuItems', () => {
{ label: 'text', accelerator: 'Alt+Tab' }
]);
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? '⌘⇥' : 'Ctrl+Tab');
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⇧⇥' : 'Shift+Tab');
expect(menu.getAcceleratorTextAt(2)).to.equal(isDarwin() ? '⌥⇥' : 'Alt+Tab');
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? 'Command+Tab' : 'Ctrl+Tab');
expect(menu.getAcceleratorTextAt(1)).to.equal('Shift+Tab');
expect(menu.getAcceleratorTextAt(2)).to.equal('Alt+Tab');
});
it('should not display modifiers twice', () => {
@@ -485,18 +485,26 @@ describe('MenuItems', () => {
{ label: 'text', accelerator: 'Shift+Shift+Tab' }
]);
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? '⇧A' : 'Shift+A');
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⇧⇥' : 'Shift+Tab');
expect(menu.getAcceleratorTextAt(0)).to.equal('Shift+A');
expect(menu.getAcceleratorTextAt(1)).to.equal('Shift+Tab');
});
it('should display correctly for edge cases', () => {
it('should display correctly for shifted keys', () => {
const menu = Menu.buildFromTemplate([
{ label: 'text', accelerator: 'Control+Shift+=' },
{ label: 'text', accelerator: 'Control+Plus' }
{ label: 'text', accelerator: 'Control+Plus' },
{ label: 'text', accelerator: 'Control+Shift+3' },
{ label: 'text', accelerator: 'Control+#' },
{ label: 'text', accelerator: 'Control+Shift+/' },
{ label: 'text', accelerator: 'Control+?' }
]);
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? '⌃⇧=' : 'Ctrl+Shift+=');
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⌃⇧=' : 'Ctrl+Shift+=');
expect(menu.getAcceleratorTextAt(0)).to.equal('Ctrl+Shift+=');
expect(menu.getAcceleratorTextAt(1)).to.equal('Ctrl++');
expect(menu.getAcceleratorTextAt(2)).to.equal('Ctrl+Shift+3');
expect(menu.getAcceleratorTextAt(3)).to.equal('Ctrl+#');
expect(menu.getAcceleratorTextAt(4)).to.equal('Ctrl+Shift+/');
expect(menu.getAcceleratorTextAt(5)).to.equal('Ctrl+?');
});
});
});

View File

@@ -18,7 +18,7 @@ describe('webRequest module', () => {
res.setHeader('Location', 'http://' + req.rawHeaders[1]);
res.end();
} else if (req.url === '/contentDisposition') {
res.setHeader('content-disposition', [' attachement; filename=aa%E4%B8%ADaa.txt']);
res.setHeader('content-disposition', [' attachment; filename=aa%E4%B8%ADaa.txt']);
const content = req.url;
res.end(content);
} else {
@@ -214,6 +214,18 @@ describe('webRequest module', () => {
await ajax(defaultURL);
});
it('leaves headers unchanged when no requestHeaders in callback', async () => {
let originalRequestHeaders: Record<string, string>;
ses.webRequest.onBeforeSendHeaders((details, callback) => {
originalRequestHeaders = details.requestHeaders;
callback({});
});
ses.webRequest.onSendHeaders((details) => {
expect(details.requestHeaders).to.deep.equal(originalRequestHeaders);
});
await ajax(defaultURL);
});
it('works with file:// protocol', async () => {
const requestHeaders = {
Test: 'header'
@@ -306,11 +318,11 @@ describe('webRequest module', () => {
it('does not change content-disposition header by default', async () => {
ses.webRequest.onHeadersReceived((details, callback) => {
expect(details.responseHeaders!['content-disposition']).to.deep.equal([' attachement; filename=aa中aa.txt']);
expect(details.responseHeaders!['content-disposition']).to.deep.equal([' attachment; filename=aa中aa.txt']);
callback({});
});
const { data, headers } = await ajax(defaultURL + 'contentDisposition');
expect(headers).to.match(/^content-disposition: attachement; filename=aa%E4%B8%ADaa.txt$/m);
expect(headers).to.match(/^content-disposition: attachment; filename=aa%E4%B8%ADaa.txt$/m);
expect(data).to.equal('/contentDisposition');
});

View File

@@ -0,0 +1,21 @@
<html>
<body>
<script>
// `setImmediate` schedules a function to be run on the next UV tick, which
// ensures that `window.open` is run from `UvRunOnce()`.
setImmediate(async () => {
if (!location.hash) {
const p = new Promise(resolve => {
window.addEventListener('message', resolve, { once: true });
});
window.open('#foo', '', 'nodeIntegration=no,show=no');
const e = await p;
window.close();
} else {
window.opener.postMessage('foo', '*');
}
});
</script>
</body>
</html>

View File

@@ -0,0 +1,21 @@
const { app, BrowserWindow } = require('electron');
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
nativeWindowOpen: true
}
});
mainWindow.on('close', () => {
app.quit();
});
mainWindow.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
});

File diff suppressed because one or more lines are too long

View File

@@ -263,6 +263,12 @@ describe('webContents.setWindowOpenHandler', () => {
browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
});
it('does not hang parent window when denying window.open', async () => {
browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' }));
browserWindow.webContents.executeJavaScript("window.open('https://127.0.0.1')");
expect(await browserWindow.webContents.executeJavaScript('42')).to.equal(42);
});
});
}
});

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