mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
251 Commits
dawn-patch
...
v7.1.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1409056baf | ||
|
|
72cb493023 | ||
|
|
1e7f26e5fd | ||
|
|
383e75796a | ||
|
|
1edfffae25 | ||
|
|
96e7b443fc | ||
|
|
8f728af13a | ||
|
|
281b0741f7 | ||
|
|
38c43ab48f | ||
|
|
d1d3d1bd1f | ||
|
|
89a7bdb566 | ||
|
|
09d59f2b83 | ||
|
|
ebec22045d | ||
|
|
a2c4000b84 | ||
|
|
9010838f21 | ||
|
|
6fe40ca797 | ||
|
|
101b971f36 | ||
|
|
6156254886 | ||
|
|
d0e4bd3fc9 | ||
|
|
3e5213b4e9 | ||
|
|
7ba8855ac1 | ||
|
|
c3e0ae9646 | ||
|
|
4b456bf3cb | ||
|
|
2a4bdfff98 | ||
|
|
c4baee0dab | ||
|
|
15688c6d6e | ||
|
|
aa4d7f1799 | ||
|
|
0476eb67ab | ||
|
|
69aebc05e5 | ||
|
|
98d06f6e5c | ||
|
|
7d321a90aa | ||
|
|
cfddc0a125 | ||
|
|
ade70463c1 | ||
|
|
4cb983ed40 | ||
|
|
79b3fcb2ab | ||
|
|
4cfa7be79d | ||
|
|
67bcc2a972 | ||
|
|
449bdcfda2 | ||
|
|
e70adc8f83 | ||
|
|
a6ae1ca755 | ||
|
|
b6fb8d3a63 | ||
|
|
5462a2c197 | ||
|
|
de428e9a7a | ||
|
|
fbe36e2365 | ||
|
|
5ac12c9e44 | ||
|
|
8d11391cb4 | ||
|
|
e82f453f71 | ||
|
|
abc187d651 | ||
|
|
913ef7890f | ||
|
|
bcb24bcdd1 | ||
|
|
d7ce600503 | ||
|
|
d16f29f7fc | ||
|
|
3b77af7ac3 | ||
|
|
0a241479cb | ||
|
|
1c8177c542 | ||
|
|
3f148fc3aa | ||
|
|
dd2310df48 | ||
|
|
9bc81be9d0 | ||
|
|
dc90c1153e | ||
|
|
7beb7b9a12 | ||
|
|
b6198b1648 | ||
|
|
16ff7b17a0 | ||
|
|
0d8be47c0f | ||
|
|
c4ab79e7ae | ||
|
|
49d91c7fc8 | ||
|
|
2b84b1ea43 | ||
|
|
4bb6f57657 | ||
|
|
db47a846da | ||
|
|
a3c951b14b | ||
|
|
c5abb17569 | ||
|
|
1b0ba71973 | ||
|
|
8dd004235b | ||
|
|
55955c3d79 | ||
|
|
5b33e9d9b7 | ||
|
|
6871b448ad | ||
|
|
7a1b3c5f2d | ||
|
|
2e8349c520 | ||
|
|
d63150502b | ||
|
|
daa61688b1 | ||
|
|
0a3b0391f4 | ||
|
|
1b66c03e41 | ||
|
|
92362da082 | ||
|
|
16e468137f | ||
|
|
b27a34eb91 | ||
|
|
18176b48b4 | ||
|
|
317f0cec68 | ||
|
|
49009236d9 | ||
|
|
976c7d122a | ||
|
|
ef548b6592 | ||
|
|
37c1df6ce1 | ||
|
|
d9068b7175 | ||
|
|
cac0a4fe3c | ||
|
|
e6807b387c | ||
|
|
f6f73a5a78 | ||
|
|
7bad919bee | ||
|
|
667db6fa67 | ||
|
|
022ee3793b | ||
|
|
5c0e8c5fd3 | ||
|
|
961436f300 | ||
|
|
e2c7e4b1ad | ||
|
|
d12b0eefe0 | ||
|
|
8dfb8c5589 | ||
|
|
57bb08e084 | ||
|
|
03e0905519 | ||
|
|
b6717a6644 | ||
|
|
41b32cf5d9 | ||
|
|
176f4728d7 | ||
|
|
0de78019c8 | ||
|
|
1926169c91 | ||
|
|
25b3ee29cf | ||
|
|
2228e5ac65 | ||
|
|
92cace3998 | ||
|
|
7dc858be02 | ||
|
|
7ffa127f0f | ||
|
|
f423312090 | ||
|
|
4cacd15730 | ||
|
|
37eeaf32ad | ||
|
|
b97c3aca2d | ||
|
|
2e07877c28 | ||
|
|
d8bd7654c6 | ||
|
|
f979e0cfbc | ||
|
|
1582824d33 | ||
|
|
71009fd61e | ||
|
|
055b5d274e | ||
|
|
1841742586 | ||
|
|
3841ac9b6d | ||
|
|
ed1c2a47f1 | ||
|
|
bcc4f67784 | ||
|
|
771d4dc374 | ||
|
|
b1fb7c7bfb | ||
|
|
725dac35ab | ||
|
|
6e32da3798 | ||
|
|
32ac551ca5 | ||
|
|
b90ac55d2d | ||
|
|
e797639d6d | ||
|
|
a31d041f03 | ||
|
|
6b70f0e8e6 | ||
|
|
b1357ab12b | ||
|
|
ffdec7a661 | ||
|
|
50822bc8d4 | ||
|
|
85164223cb | ||
|
|
5cb6ba2883 | ||
|
|
e23030b69e | ||
|
|
d417bbdcfd | ||
|
|
e6f92f3f30 | ||
|
|
3b59f12495 | ||
|
|
3083693e67 | ||
|
|
2a2f7e7090 | ||
|
|
f4c697d7a1 | ||
|
|
944690e79b | ||
|
|
ae303ade7d | ||
|
|
19162f4bac | ||
|
|
ee53f8cef6 | ||
|
|
4463715714 | ||
|
|
f6894da715 | ||
|
|
1657908fa8 | ||
|
|
26d059b3ea | ||
|
|
49aaa2fe96 | ||
|
|
0a9b201c34 | ||
|
|
e17cd837ef | ||
|
|
981208b66c | ||
|
|
77af675511 | ||
|
|
a92ee9443d | ||
|
|
23a52c02a3 | ||
|
|
8536f62826 | ||
|
|
312f14ee88 | ||
|
|
1f660c67c6 | ||
|
|
325bdfaf23 | ||
|
|
e3dcdba2db | ||
|
|
6b5a2c550a | ||
|
|
21e702a563 | ||
|
|
f79cfae3c2 | ||
|
|
51ffe25f45 | ||
|
|
0a0d7a8202 | ||
|
|
421490c6b3 | ||
|
|
068e12d909 | ||
|
|
d251642c83 | ||
|
|
27ceeb5e94 | ||
|
|
4ac616b681 | ||
|
|
fc677b7cf6 | ||
|
|
d25e511fc0 | ||
|
|
b4ba2f6d55 | ||
|
|
f967d73a13 | ||
|
|
c923aa2fde | ||
|
|
dec2078e54 | ||
|
|
2d16034854 | ||
|
|
4ce431829f | ||
|
|
430b355258 | ||
|
|
638ca05702 | ||
|
|
9e7cce3d2b | ||
|
|
c7a3142bab | ||
|
|
b6f5e26eab | ||
|
|
3330647834 | ||
|
|
bb8c7dfc7e | ||
|
|
4dea193854 | ||
|
|
080c2c9218 | ||
|
|
182f63d3a3 | ||
|
|
d3e0c461f6 | ||
|
|
b09a1c7607 | ||
|
|
7cc1efd2e6 | ||
|
|
324096aa37 | ||
|
|
d780a16d78 | ||
|
|
005ef96ac0 | ||
|
|
4f74be084a | ||
|
|
b7c2188d09 | ||
|
|
192326c7c5 | ||
|
|
1af064a144 | ||
|
|
6061fcce40 | ||
|
|
e68a9486da | ||
|
|
dd8bcb67ba | ||
|
|
27661d8e7b | ||
|
|
94ddcc4742 | ||
|
|
2515087322 | ||
|
|
36a5ba0d4d | ||
|
|
241b2a98af | ||
|
|
9b2e3d1d0b | ||
|
|
67cb05b435 | ||
|
|
3f5222b047 | ||
|
|
28e7e6492d | ||
|
|
23f7f63405 | ||
|
|
99eaa0d1bb | ||
|
|
543dbaf412 | ||
|
|
5901293628 | ||
|
|
30543cec74 | ||
|
|
66aeeac8df | ||
|
|
b03bc4de83 | ||
|
|
601c3f97ea | ||
|
|
d01a8eaa39 | ||
|
|
54e1c11b2b | ||
|
|
c1ad66b104 | ||
|
|
a905259646 | ||
|
|
356045ff57 | ||
|
|
a9f69bf732 | ||
|
|
3e181b8efc | ||
|
|
171c76e3cb | ||
|
|
0299f69fd1 | ||
|
|
0bdb7b164c | ||
|
|
ea9cfc127c | ||
|
|
0afb1a8188 | ||
|
|
f154dbda40 | ||
|
|
c3013d2e9f | ||
|
|
3272564eac | ||
|
|
a0f4632461 | ||
|
|
8ddf837d49 | ||
|
|
9822953d31 | ||
|
|
c6061cce41 | ||
|
|
a9602682c5 | ||
|
|
b7e5213afc | ||
|
|
9b70d9aa68 | ||
|
|
d9bfac32e3 | ||
|
|
9e815afc02 |
@@ -41,6 +41,7 @@ env-release-build: &env-release-build
|
||||
GN_CONFIG: //electron/build/args/release.gn
|
||||
STRIP_BINARIES: true
|
||||
GENERATE_SYMBOLS: true
|
||||
CHECK_DIST_MANIFEST: '1'
|
||||
|
||||
env-headless-testing: &env-headless-testing
|
||||
DISPLAY: ':99.0'
|
||||
@@ -91,13 +92,19 @@ env-linux-medium: &env-linux-medium
|
||||
NUMBER_OF_NINJA_PROCESSES: 3
|
||||
|
||||
env-linux-2xlarge: &env-linux-2xlarge
|
||||
NUMBER_OF_NINJA_PROCESSES: 18
|
||||
NUMBER_OF_NINJA_PROCESSES: 34
|
||||
|
||||
env-linux-2xlarge-release: &env-linux-2xlarge-release
|
||||
NUMBER_OF_NINJA_PROCESSES: 16
|
||||
|
||||
env-machine-mac: &env-machine-mac
|
||||
NUMBER_OF_NINJA_PROCESSES: 6
|
||||
|
||||
env-mac-large: &env-mac-large
|
||||
NUMBER_OF_NINJA_PROCESSES: 10
|
||||
NUMBER_OF_NINJA_PROCESSES: 18
|
||||
|
||||
env-mac-large-release: &env-mac-large-release
|
||||
NUMBER_OF_NINJA_PROCESSES: 8
|
||||
|
||||
env-disable-crash-reporter-tests: &env-disable-crash-reporter-tests
|
||||
DISABLE_CRASH_REPORTER_TESTS: true
|
||||
@@ -174,7 +181,7 @@ step-setup-env-for-build: &step-setup-env-for-build
|
||||
echo 'export SCCACHE_PATH="'"$SCCACHE_PATH"'"' >> $BASH_ENV
|
||||
if [ "$CIRCLE_PR_NUMBER" != "" ]; then
|
||||
#if building a fork set readonly access to sccache
|
||||
echo 'export SCCACHE_BUCKET="electronjs-sccache"' >> $BASH_ENV
|
||||
echo 'export SCCACHE_BUCKET="electronjs-sccache-ci"' >> $BASH_ENV
|
||||
echo 'export SCCACHE_TWO_TIER=true' >> $BASH_ENV
|
||||
fi
|
||||
fi
|
||||
@@ -186,6 +193,13 @@ step-restore-brew-cache: &step-restore-brew-cache
|
||||
keys:
|
||||
- v1-brew-cache-{{ arch }}
|
||||
|
||||
step-save-brew-cache: &step-save-brew-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
key: v1-brew-cache-{{ arch }}
|
||||
name: Persisting brew cache
|
||||
|
||||
step-get-more-space-on-mac: &step-get-more-space-on-mac
|
||||
run:
|
||||
name: Free up space on MacOS
|
||||
@@ -278,9 +292,18 @@ step-maybe-electron-dist-strip: &step-maybe-electron-dist-strip
|
||||
run:
|
||||
name: Strip electron binaries
|
||||
command: |
|
||||
if [ "$STRIP_BINARIES" == "true" ] && [ "`uname`" != "Darwin" ]; then
|
||||
if [ "$STRIP_BINARIES" == "true" ] && [ "`uname`" == "Linux" ]; then
|
||||
if [ x"$TARGET_ARCH" == x ]; then
|
||||
target_cpu=x64
|
||||
elif [ "$TARGET_ARCH" == "ia32" ]; then
|
||||
target_cpu=x86
|
||||
else
|
||||
target_cpu="$TARGET_ARCH"
|
||||
fi
|
||||
cd src
|
||||
electron/script/strip-binaries.py --target-cpu="$TARGET_ARCH"
|
||||
electron/script/copy-debug-symbols.py --target-cpu="$target_cpu" --out-dir=out/Default/debug --compress
|
||||
electron/script/strip-binaries.py --target-cpu="$target_cpu"
|
||||
electron/script/add-debug-link.py --target-cpu="$target_cpu" --debug-dir=out/Default/debug
|
||||
fi
|
||||
|
||||
step-electron-dist-build: &step-electron-dist-build
|
||||
@@ -535,6 +558,93 @@ step-ninja-summary: &step-ninja-summary
|
||||
command: |
|
||||
python depot_tools/post_build_ninja_summary.py -C src/out/Default
|
||||
|
||||
# Checkout Steps
|
||||
step-generate-deps-hash: &step-generate-deps-hash
|
||||
run:
|
||||
name: Generate DEPS Hash
|
||||
command: node src/electron/script/generate-deps-hash.js
|
||||
|
||||
step-touch-sync-done: &step-touch-sync-done
|
||||
run:
|
||||
name: Touch Sync Done
|
||||
command: touch src/electron/.circle-sync-done
|
||||
|
||||
# Restore exact src cache based on the hash of DEPS and patches/*
|
||||
# If no cache is matched EXACTLY then the .circle-sync-done file is empty
|
||||
# If a cache is matched EXACTLY then the .circle-sync-done file contains "done"
|
||||
step-maybe-restore-src-cache: &step-maybe-restore-src-cache
|
||||
restore_cache:
|
||||
paths:
|
||||
- ./src
|
||||
keys:
|
||||
- v5-src-cache-{{ arch }}-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache
|
||||
|
||||
# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done
|
||||
# If the src cache was restored above then this will match an empty cache
|
||||
# If the src cache was not restored above then this will match a close git cache
|
||||
step-maybe-restore-git-cache: &step-maybe-restore-git-cache
|
||||
restore_cache:
|
||||
paths:
|
||||
- ~/.gclient-cache
|
||||
keys:
|
||||
- v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
|
||||
- v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}
|
||||
name: Conditionally restoring git cache
|
||||
|
||||
step-set-git-cache-path: &step-set-git-cache-path
|
||||
run:
|
||||
name: Set GIT_CACHE_PATH to make gclient to use the cache
|
||||
command: |
|
||||
# CircleCI does not support interpolation when setting environment variables.
|
||||
# https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-shell-command
|
||||
echo 'export GIT_CACHE_PATH="$HOME/.gclient-cache"' >> $BASH_ENV
|
||||
|
||||
# Persist the git cache based on the hash of DEPS and .circle-sync-done
|
||||
# If the src cache was restored above then this will persist an empty cache
|
||||
step-save-git-cache: &step-save-git-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- ~/.gclient-cache
|
||||
key: v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
|
||||
name: Persisting git cache
|
||||
|
||||
step-run-electron-only-hooks: &step-run-electron-only-hooks
|
||||
run:
|
||||
name: Run Electron Only Hooks
|
||||
command: gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
|
||||
|
||||
step-generate-deps-hash-cleanly: &step-generate-deps-hash-cleanly
|
||||
run:
|
||||
name: Generate DEPS Hash
|
||||
command: (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js
|
||||
|
||||
# Mark the sync as done for future cache saving
|
||||
step-mark-sync-done: &step-mark-sync-done
|
||||
run:
|
||||
name: Mark Sync Done
|
||||
command: echo DONE > src/electron/.circle-sync-done
|
||||
|
||||
# Minimize the size of the cache
|
||||
step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-checkout
|
||||
run:
|
||||
name: Remove some unused data to avoid storing it in the workspace/cache
|
||||
command: |
|
||||
rm -rf src/android_webview
|
||||
rm -rf src/ios
|
||||
rm -rf src/third_party/blink/web_tests
|
||||
rm -rf src/third_party/blink/perf_tests
|
||||
rm -rf src/third_party/hunspell_dictionaries
|
||||
rm -rf src/third_party/WebKit/LayoutTests
|
||||
|
||||
# Save the src cache based on the deps hash
|
||||
step-save-src-cache: &step-save-src-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- ./src
|
||||
key: v5-src-cache-{{ arch }}-{{ checksum "src/electron/.depshash" }}
|
||||
name: Persisting src cache
|
||||
|
||||
# Lists of steps.
|
||||
steps-lint: &steps-lint
|
||||
steps:
|
||||
@@ -580,7 +690,7 @@ steps-lint: &steps-lint
|
||||
node script/yarn install --frozen-lockfile
|
||||
node script/yarn lint
|
||||
|
||||
steps-checkout: &steps-checkout
|
||||
steps-checkout-fast: &steps-checkout-fast
|
||||
steps:
|
||||
- *step-checkout-electron
|
||||
- *step-depot-tools-get
|
||||
@@ -589,88 +699,57 @@ steps-checkout: &steps-checkout
|
||||
- *step-get-more-space-on-mac
|
||||
- *step-install-gnutar-on-mac
|
||||
|
||||
- run:
|
||||
name: Generate DEPS Hash
|
||||
command: node src/electron/script/generate-deps-hash.js
|
||||
- run:
|
||||
name: Touch Sync Done
|
||||
command: touch src/electron/.circle-sync-done
|
||||
# Restore exact src cache based on the hash of DEPS and patches/*
|
||||
# If no cache is matched EXACTLY then the .circle-sync-done file is empty
|
||||
# If a cache is matched EXACTLY then the .circle-sync-done file contains "done"
|
||||
- restore_cache:
|
||||
paths:
|
||||
- ./src
|
||||
keys:
|
||||
- v5-src-cache-{{ arch }}-{{ checksum "src/electron/.depshash" }}
|
||||
name: Restoring src cache
|
||||
# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done
|
||||
# If the src cache was restored above then this will match an empty cache
|
||||
# If the src cache was not restored above then this will match a close git cache
|
||||
- restore_cache:
|
||||
paths:
|
||||
- ~/.gclient-cache
|
||||
keys:
|
||||
- v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
|
||||
- v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}
|
||||
name: Conditionally restoring git cache
|
||||
- run:
|
||||
name: Set GIT_CACHE_PATH to make gclient to use the cache
|
||||
command: |
|
||||
# CircleCI does not support interpolation when setting environment variables.
|
||||
# https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-shell-command
|
||||
echo 'export GIT_CACHE_PATH="$HOME/.gclient-cache"' >> $BASH_ENV
|
||||
- *step-generate-deps-hash
|
||||
- *step-touch-sync-done
|
||||
- *step-maybe-restore-src-cache
|
||||
- *step-maybe-restore-git-cache
|
||||
- *step-set-git-cache-path
|
||||
# This sync call only runs if .circle-sync-done is an EMPTY file
|
||||
- *step-gclient-sync
|
||||
# Persist the git cache based on the hash of DEPS and .circle-sync-done
|
||||
# If the src cache was restored above then this will persist an empty cache
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.gclient-cache
|
||||
key: v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
|
||||
name: Persisting git cache
|
||||
# These next few steps reset Electron to the correct commit regardless of which cache was restored
|
||||
- run:
|
||||
name: Wipe Electron
|
||||
command: rm -rf src/electron
|
||||
- *step-checkout-electron
|
||||
- run:
|
||||
name: Run Electron Only Hooks
|
||||
command: gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
|
||||
- run:
|
||||
name: Generate DEPS Hash
|
||||
command: (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js
|
||||
# Mark the sync as done for future cache saving
|
||||
- run:
|
||||
name: Mark Sync Done
|
||||
command: echo DONE > src/electron/.circle-sync-done
|
||||
# Minimize the size of the cache
|
||||
- run:
|
||||
name: Remove some unused data to avoid storing it in the workspace/cache
|
||||
command: |
|
||||
rm -rf src/android_webview
|
||||
rm -rf src/ios
|
||||
rm -rf src/third_party/blink/web_tests
|
||||
rm -rf src/third_party/blink/perf_tests
|
||||
rm -rf src/third_party/hunspell_dictionaries
|
||||
rm -rf src/third_party/WebKit/LayoutTests
|
||||
# Save the src cache based on the deps hash
|
||||
- save_cache:
|
||||
paths:
|
||||
- ./src
|
||||
key: v5-src-cache-{{ arch }}-{{ checksum "src/electron/.depshash" }}
|
||||
name: Persisting src cache
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
key: v1-brew-cache-{{ arch }}
|
||||
name: Persisting brew cache
|
||||
- *step-run-electron-only-hooks
|
||||
- *step-generate-deps-hash-cleanly
|
||||
- *step-mark-sync-done
|
||||
- *step-minimize-workspace-size-from-checkout
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- depot_tools
|
||||
- src
|
||||
|
||||
steps-checkout-and-save-cache: &steps-checkout-and-save-cache
|
||||
steps:
|
||||
- *step-checkout-electron
|
||||
- *step-depot-tools-get
|
||||
- *step-depot-tools-add-to-path
|
||||
- *step-restore-brew-cache
|
||||
- *step-get-more-space-on-mac
|
||||
- *step-install-gnutar-on-mac
|
||||
|
||||
- *step-generate-deps-hash
|
||||
- *step-touch-sync-done
|
||||
- *step-maybe-restore-src-cache
|
||||
- *step-maybe-restore-git-cache
|
||||
- *step-set-git-cache-path
|
||||
# This sync call only runs if .circle-sync-done is an EMPTY file
|
||||
- *step-gclient-sync
|
||||
- *step-save-git-cache
|
||||
# These next few steps reset Electron to the correct commit regardless of which cache was restored
|
||||
- run:
|
||||
name: Wipe Electron
|
||||
command: rm -rf src/electron
|
||||
- *step-checkout-electron
|
||||
- *step-run-electron-only-hooks
|
||||
- *step-generate-deps-hash-cleanly
|
||||
- *step-mark-sync-done
|
||||
- *step-minimize-workspace-size-from-checkout
|
||||
- *step-save-src-cache
|
||||
- *step-save-brew-cache
|
||||
|
||||
steps-electron-gn-check: &steps-electron-gn-check
|
||||
steps:
|
||||
- attach_workspace:
|
||||
@@ -707,9 +786,11 @@ steps-electron-build-for-tests: &steps-electron-build-for-tests
|
||||
- *step-depot-tools-add-to-path
|
||||
- *step-setup-env-for-build
|
||||
- *step-restore-brew-cache
|
||||
- *step-get-more-space-on-mac
|
||||
- *step-install-npm-deps-on-mac
|
||||
- *step-fix-sync-on-mac
|
||||
- *step-gn-gen-default
|
||||
- *step-delete-git-directories
|
||||
|
||||
# Electron app
|
||||
- *step-electron-build
|
||||
@@ -947,33 +1028,47 @@ jobs:
|
||||
<<: *steps-lint
|
||||
|
||||
# Layer 1: Checkout.
|
||||
linux-checkout:
|
||||
linux-checkout-fast:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
<<: *steps-checkout
|
||||
<<: *steps-checkout-fast
|
||||
|
||||
linux-checkout-and-save-cache:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
<<: *steps-checkout-and-save-cache
|
||||
|
||||
linux-checkout-for-native-tests:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_pyyaml=True'
|
||||
<<: *steps-checkout
|
||||
<<: *steps-checkout-fast
|
||||
|
||||
linux-checkout-for-native-tests-with-no-patches:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=apply_patches=False --custom-var=checkout_pyyaml=True'
|
||||
<<: *steps-checkout
|
||||
<<: *steps-checkout-fast
|
||||
|
||||
mac-checkout:
|
||||
mac-checkout-fast:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
<<: *steps-checkout
|
||||
<<: *steps-checkout-fast
|
||||
|
||||
mac-checkout-and-save-cache:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
<<: *steps-checkout-and-save-cache
|
||||
|
||||
# Layer 2: Builds.
|
||||
linux-x64-debug:
|
||||
@@ -1040,7 +1135,7 @@ jobs:
|
||||
linux-x64-publish:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
<<: *env-linux-2xlarge-release
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
<<: *env-release-build
|
||||
<<: *steps-electron-build-for-publish
|
||||
@@ -1089,7 +1184,7 @@ jobs:
|
||||
linux-ia32-publish:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
<<: *env-linux-2xlarge-release
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
<<: *env-ia32
|
||||
<<: *env-release-build
|
||||
@@ -1140,7 +1235,7 @@ jobs:
|
||||
linux-arm-publish:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
<<: *env-linux-2xlarge-release
|
||||
<<: *env-arm
|
||||
<<: *env-release-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
@@ -1207,7 +1302,7 @@ jobs:
|
||||
linux-arm64-publish:
|
||||
<<: *machine-linux-2xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
<<: *env-linux-2xlarge-release
|
||||
<<: *env-arm64
|
||||
<<: *env-release-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm64=True --custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
@@ -1222,6 +1317,15 @@ jobs:
|
||||
<<: *env-ninja-status
|
||||
<<: *steps-electron-build-for-tests
|
||||
|
||||
osx-debug:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-debug-build
|
||||
<<: *env-enable-sccache
|
||||
<<: *env-ninja-status
|
||||
<<: *steps-electron-build-for-tests
|
||||
|
||||
osx-debug-gn-check:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
@@ -1257,7 +1361,7 @@ jobs:
|
||||
osx-publish:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-release-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
<<: *steps-electron-build-for-publish
|
||||
@@ -1272,6 +1376,16 @@ jobs:
|
||||
<<: *env-ninja-status
|
||||
<<: *steps-electron-build-for-tests
|
||||
|
||||
mas-debug:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-mas
|
||||
<<: *env-debug-build
|
||||
<<: *env-enable-sccache
|
||||
<<: *env-ninja-status
|
||||
<<: *steps-electron-build-for-tests
|
||||
|
||||
mas-debug-gn-check:
|
||||
<<: *machine-mac
|
||||
environment:
|
||||
@@ -1310,7 +1424,7 @@ jobs:
|
||||
mas-publish:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-mas
|
||||
<<: *env-release-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
|
||||
@@ -1575,23 +1689,24 @@ workflows:
|
||||
|
||||
build-linux:
|
||||
jobs:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-checkout-and-save-cache
|
||||
|
||||
- linux-x64-debug:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-x64-debug-gn-check:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-x64-testing:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-x64-testing-no-run-as-node:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-x64-testing-gn-check:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-x64-testing-tests:
|
||||
requires:
|
||||
- linux-x64-testing
|
||||
@@ -1604,10 +1719,10 @@ workflows:
|
||||
|
||||
- linux-ia32-debug:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-ia32-testing:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-ia32-testing-tests:
|
||||
requires:
|
||||
- linux-ia32-testing
|
||||
@@ -1620,37 +1735,44 @@ workflows:
|
||||
|
||||
- linux-arm-debug:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-arm-testing:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
|
||||
- linux-arm64-debug:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-arm64-debug-gn-check:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-arm64-testing:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
- linux-arm64-testing-gn-check:
|
||||
requires:
|
||||
- linux-checkout
|
||||
- linux-checkout-fast
|
||||
|
||||
build-mac:
|
||||
jobs:
|
||||
- mac-checkout
|
||||
- mac-checkout-fast
|
||||
- mac-checkout-and-save-cache
|
||||
|
||||
- osx-testing:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mac-checkout-fast
|
||||
|
||||
- osx-debug:
|
||||
requires:
|
||||
- mac-checkout-fast
|
||||
|
||||
- osx-debug-gn-check:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mac-checkout-fast
|
||||
|
||||
- osx-testing-gn-check:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mac-checkout-fast
|
||||
|
||||
- osx-testing-tests:
|
||||
requires:
|
||||
@@ -1658,14 +1780,19 @@ workflows:
|
||||
|
||||
- mas-testing:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mac-checkout-fast
|
||||
|
||||
- mas-debug:
|
||||
requires:
|
||||
- mac-checkout-fast
|
||||
|
||||
- mas-debug-gn-check:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mac-checkout-fast
|
||||
|
||||
- mas-testing-gn-check:
|
||||
requires:
|
||||
- mac-checkout
|
||||
- mac-checkout-fast
|
||||
|
||||
- mas-testing-tests:
|
||||
requires:
|
||||
|
||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -11,6 +11,7 @@
|
||||
|
||||
# Upgrades WG
|
||||
/patches/ @electron/wg-upgrades
|
||||
DEPS @electron/wg-upgrades
|
||||
|
||||
# Docs & Tooling WG
|
||||
/default_app/ @electron/wg-docs-tools
|
||||
|
||||
30
BUILD.gn
30
BUILD.gn
@@ -26,6 +26,7 @@ if (is_mac) {
|
||||
import("//third_party/icu/config.gni")
|
||||
import("//ui/gl/features.gni")
|
||||
import("//v8/gni/v8.gni")
|
||||
import("build/rules.gni")
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
@@ -300,14 +301,6 @@ source_set("manifests") {
|
||||
"//printing/buildflags",
|
||||
"//services/service_manager/public/cpp",
|
||||
]
|
||||
|
||||
if (enable_basic_printing) {
|
||||
deps += [ "//components/services/pdf_compositor/public/cpp:manifest" ]
|
||||
}
|
||||
|
||||
if (enable_print_preview) {
|
||||
deps += [ "//chrome/services/printing/public/cpp:manifest" ]
|
||||
}
|
||||
}
|
||||
|
||||
npm_action("electron_version_args") {
|
||||
@@ -354,8 +347,11 @@ source_set("electron_lib") {
|
||||
"//base:base_static",
|
||||
"//base/allocator:buildflags",
|
||||
"//chrome/app/resources:platform_locale_settings",
|
||||
"//chrome/services/printing/public/mojom",
|
||||
"//components/certificate_transparency",
|
||||
"//components/net_log",
|
||||
"//components/network_hints/common",
|
||||
"//components/network_hints/renderer",
|
||||
"//components/network_session_configurator/common",
|
||||
"//components/prefs",
|
||||
"//components/spellcheck/renderer",
|
||||
@@ -371,7 +367,7 @@ source_set("electron_lib") {
|
||||
"//device/bluetooth/public/cpp",
|
||||
"//gin",
|
||||
"//media/capture/mojom:video_capture",
|
||||
"//media/mojo/interfaces",
|
||||
"//media/mojo/mojom",
|
||||
"//net:extras",
|
||||
"//net:net_resources",
|
||||
"//net:net_with_v8",
|
||||
@@ -384,7 +380,7 @@ source_set("electron_lib") {
|
||||
"//services/device/public/mojom",
|
||||
"//services/proxy_resolver:lib",
|
||||
"//services/video_capture/public/mojom:constants",
|
||||
"//services/viz/privileged/interfaces/compositing",
|
||||
"//services/viz/privileged/mojom/compositing",
|
||||
"//skia",
|
||||
"//third_party/blink/public:blink",
|
||||
"//third_party/boringssl",
|
||||
@@ -579,15 +575,16 @@ source_set("electron_lib") {
|
||||
]
|
||||
deps += [
|
||||
"//components/viz/service",
|
||||
"//services/viz/public/interfaces",
|
||||
"//services/viz/public/mojom",
|
||||
"//ui/compositor",
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_desktop_capturer) {
|
||||
if (is_component_build && is_win) {
|
||||
if (is_component_build && !is_linux) {
|
||||
# On windows the implementation relies on unexported
|
||||
# DxgiDuplicatorController class.
|
||||
# DxgiDuplicatorController class. On macOS the implementation
|
||||
# relies on unexported webrtc::GetWindowOwnerPid method.
|
||||
deps += [ "//third_party/webrtc/modules/desktop_capture" ]
|
||||
}
|
||||
sources += [
|
||||
@@ -659,6 +656,12 @@ if (is_mac) {
|
||||
electron_framework_version = "A"
|
||||
electron_version = read_file("ELECTRON_VERSION", "trim string")
|
||||
|
||||
mac_xib_bundle_data("electron_xibs") {
|
||||
sources = [
|
||||
"shell/common/resources/mac/MainMenu.xib",
|
||||
]
|
||||
}
|
||||
|
||||
bundle_data("electron_framework_resources") {
|
||||
public_deps = [
|
||||
":packed_resources",
|
||||
@@ -773,6 +776,7 @@ if (is_mac) {
|
||||
":electron_framework_libraries",
|
||||
":electron_framework_resources",
|
||||
":electron_swiftshader_library",
|
||||
":electron_xibs",
|
||||
]
|
||||
if (!is_mas_build) {
|
||||
deps += [ ":electron_crashpad_helper" ]
|
||||
|
||||
11
DEPS
11
DEPS
@@ -5,14 +5,15 @@ gclient_gn_args = [
|
||||
'checkout_android_native_support',
|
||||
'checkout_libaom',
|
||||
'checkout_nacl',
|
||||
'checkout_oculus_sdk'
|
||||
'checkout_oculus_sdk',
|
||||
'checkout_openxr'
|
||||
]
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'9eecb7a9f652bbf84f6437b49c70922b65b38bf3',
|
||||
'78.0.3904.130',
|
||||
'node_version':
|
||||
'v12.6.0',
|
||||
'v12.8.1',
|
||||
'nan_version':
|
||||
'2ee313aaca52e2b478965ac50eb5082520380d1b',
|
||||
|
||||
@@ -60,6 +61,8 @@ vars = {
|
||||
True,
|
||||
'checkout_oculus_sdk':
|
||||
False,
|
||||
'checkout_openxr':
|
||||
False,
|
||||
'build_with_chromium':
|
||||
True,
|
||||
'checkout_android':
|
||||
@@ -111,7 +114,7 @@ hooks = [
|
||||
'pattern': 'src/electron/script/update-external-binaries.py',
|
||||
'condition': 'download_external_binaries',
|
||||
'action': [
|
||||
'python',
|
||||
'python3',
|
||||
'src/electron/script/update-external-binaries.py',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1 +1 @@
|
||||
7.0.0-nightly.20190731
|
||||
7.1.5
|
||||
10
appveyor.yml
10
appveyor.yml
@@ -60,7 +60,7 @@ build_script:
|
||||
- ps: $env:SCCACHE_PATH="$pwd\src\electron\external_binaries\sccache.exe"
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
$env:GCLIENT_EXTRA_ARGS="--custom-var=checkout_boto=True --custom-var=checkout_requests=True"
|
||||
$env:GCLIENT_EXTRA_ARGS="$env:GCLIENT_EXTRA_ARGS --custom-var=checkout_boto=True --custom-var=checkout_requests=True"
|
||||
} else {
|
||||
$env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] "
|
||||
}
|
||||
@@ -89,6 +89,10 @@ build_script:
|
||||
- appveyor PushArtifact out/Default/dist.zip
|
||||
- appveyor PushArtifact out/Default/chromedriver.zip
|
||||
- appveyor PushArtifact out/ffmpeg/ffmpeg.zip
|
||||
- 7z a node_headers.zip out\Default\gen\node_headers
|
||||
- appveyor PushArtifact node_headers.zip
|
||||
- appveyor PushArtifact out/Default/mksnapshot.zip
|
||||
- appveyor PushArtifact out/Default/electron.lib
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -eq 'release') {
|
||||
# Needed for msdia140.dll on 64-bit windows
|
||||
@@ -105,7 +109,7 @@ test_script:
|
||||
# Workaround for https://github.com/appveyor/ci/issues/2420
|
||||
- set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core"
|
||||
- ps: >-
|
||||
if ((-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) {
|
||||
if ((-Not (Test-Path Env:\TEST_WOA)) -And (-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) {
|
||||
$env:RUN_TESTS="true"
|
||||
}
|
||||
- ps: >-
|
||||
@@ -133,4 +137,6 @@ deploy_script:
|
||||
Write-Output "Uploading Electron release distribution to github releases"
|
||||
& python script\release\uploaders\upload.py
|
||||
}
|
||||
} elseif (Test-Path Env:\TEST_WOA) {
|
||||
node script/release/ci-release-build.js --job=electron-woa-testing --ci=VSTS --armTest --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH
|
||||
}
|
||||
|
||||
84
azure-pipelines-woa.yml
Normal file
84
azure-pipelines-woa.yml
Normal file
@@ -0,0 +1,84 @@
|
||||
steps:
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy Files to: src\electron'
|
||||
inputs:
|
||||
TargetFolder: src\electron
|
||||
|
||||
- script: |
|
||||
cd src\electron
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
displayName: 'Yarn install'
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$pwd\dist.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/dist.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\Default -y $localArtifactPath
|
||||
displayName: 'Download and extract dist.zip for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$pwd\ffmpeg.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/ffmpeg.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\ffmpeg $localArtifactPath
|
||||
displayName: 'Download and extract ffmpeg.zip for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$pwd\src\node_headers.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/node_headers.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
cd src
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y node_headers.zip
|
||||
displayName: 'Download node headers for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
$localArtifactPath = "$pwd\src\out\Default\electron.lib"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/electron.lib"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
displayName: 'Download electron.lib for test'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
New-Item src\out\Default\gen\node_headers\Release -Type directory
|
||||
Copy-Item -path src\out\Default\electron.lib -destination src\out\Default\gen\node_headers\Release\node.lib
|
||||
displayName: 'Setup node headers'
|
||||
|
||||
- script: |
|
||||
cd src
|
||||
set npm_config_nodedir=%cd%\out\Default\gen\node_headers
|
||||
set npm_config_arch=arm64
|
||||
cd electron
|
||||
node script/yarn test -- --ci --enable-logging --verbose
|
||||
displayName: 'Run Electron tests'
|
||||
env:
|
||||
ELECTRON_OUT_DIR: Default
|
||||
IGNORE_YARN_INSTALL_ERROR: 1
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results'
|
||||
inputs:
|
||||
testResultsFiles: '*.xml'
|
||||
searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/'
|
||||
condition: always()
|
||||
|
||||
- script: |
|
||||
cd src
|
||||
echo "Verifying non proprietary ffmpeg"
|
||||
python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg
|
||||
displayName: 'Verify ffmpeg'
|
||||
|
||||
- powershell: |
|
||||
Get-Process | Where Name –Like "electron*" | Stop-Process
|
||||
Get-Process | Where Name –Like "MicrosoftEdge*" | Stop-Process
|
||||
displayName: 'Kill processes left running from last test run'
|
||||
condition: always()
|
||||
@@ -6,6 +6,8 @@ is_official_build = false
|
||||
dcheck_always_on = true
|
||||
symbol_level = 1
|
||||
|
||||
strip_absolute_paths_from_debug_symbols = false
|
||||
|
||||
# This may be guarded behind is_chrome_branded alongside
|
||||
# proprietary_codecs https://webrtc-review.googlesource.com/c/src/+/36321,
|
||||
# explicitly override here to build OpenH264 encoder/FFmpeg decoder.
|
||||
|
||||
57
build/rules.gni
Normal file
57
build/rules.gni
Normal file
@@ -0,0 +1,57 @@
|
||||
import("//build/config/mac/mac_sdk.gni")
|
||||
|
||||
# This is imported from /ios becuase this functionality was moved
|
||||
# after Chromium stopped using xib files for macOS menu functionality
|
||||
# See https://chromium-review.googlesource.com/c/chromium/src/+/1648695
|
||||
import("//build/config/ios/rules.gni")
|
||||
|
||||
# Template is copied here from Chromium but was removed in
|
||||
# https://chromium-review.googlesource.com/c/chromium/src/+/1637981
|
||||
# Template to compile and package Mac XIB files as bundle data.
|
||||
# Arguments
|
||||
# sources:
|
||||
# list of string, sources to comiple
|
||||
# output_path:
|
||||
# (optional) string, the path to use for the outputs list in the
|
||||
# bundle_data step. If unspecified, defaults to bundle_resources_dir.
|
||||
template("mac_xib_bundle_data") {
|
||||
_target_name = target_name
|
||||
_compile_target_name = _target_name + "_compile_ibtool"
|
||||
|
||||
compile_ib_files(_compile_target_name) {
|
||||
forward_variables_from(invoker, [ "testonly" ])
|
||||
visibility = [ ":$_target_name" ]
|
||||
sources = invoker.sources
|
||||
output_extension = "nib"
|
||||
ibtool_flags = [
|
||||
"--minimum-deployment-target",
|
||||
mac_deployment_target,
|
||||
|
||||
# TODO(rsesek): Enable this once all the bots are on Xcode 7+.
|
||||
# "--target-device",
|
||||
# "mac",
|
||||
]
|
||||
}
|
||||
|
||||
bundle_data(_target_name) {
|
||||
forward_variables_from(invoker,
|
||||
[
|
||||
"testonly",
|
||||
"visibility",
|
||||
])
|
||||
|
||||
public_deps = [
|
||||
":$_compile_target_name",
|
||||
]
|
||||
sources = get_target_outputs(":$_compile_target_name")
|
||||
|
||||
_output_path = "{{bundle_resources_dir}}"
|
||||
if (defined(invoker.output_path)) {
|
||||
_output_path = invoker.output_path
|
||||
}
|
||||
|
||||
outputs = [
|
||||
"$_output_path/{{source_file_part}}",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,10 @@ module.exports = ({
|
||||
global: ['@electron/internal/renderer/webpack-provider', '_global'],
|
||||
Buffer: ['@electron/internal/renderer/webpack-provider', 'Buffer'],
|
||||
})
|
||||
] : [])
|
||||
] : []),
|
||||
new webpack.ProvidePlugin({
|
||||
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise'],
|
||||
}),
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ PATHS_TO_SKIP = [
|
||||
'./libVkICD_mock_', #Skipping because these are outputs that we don't need
|
||||
'./VkICD_mock_', #Skipping because these are outputs that we don't need
|
||||
|
||||
# Skipping because its an output of create_bundle from //build/config/mac/rules.gni
|
||||
# that we don't need
|
||||
'Electron.dSYM',
|
||||
|
||||
# //chrome/browser:resources depends on this via
|
||||
# //chrome/browser/resources/ssl/ssl_error_assistant, but we don't need to
|
||||
# ship it.
|
||||
@@ -51,14 +55,13 @@ def main(argv):
|
||||
with open(runtime_deps) as f:
|
||||
for dep in f.readlines():
|
||||
dep = dep.strip()
|
||||
dist_files.add(dep)
|
||||
if not skip_path(dep, dist_zip, target_cpu):
|
||||
dist_files.add(dep)
|
||||
if sys.platform == 'darwin':
|
||||
execute(['zip', '-r', '-y', dist_zip] + list(dist_files))
|
||||
else:
|
||||
with zipfile.ZipFile(dist_zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as z:
|
||||
for dep in dist_files:
|
||||
if skip_path(dep, dist_zip, target_cpu):
|
||||
continue
|
||||
if os.path.isdir(dep):
|
||||
for root, dirs, files in os.walk(dep):
|
||||
for file in files:
|
||||
|
||||
@@ -18,6 +18,7 @@ buildflag_header("buildflags") {
|
||||
"ENABLE_TTS=$enable_tts",
|
||||
"ENABLE_COLOR_CHOOSER=$enable_color_chooser",
|
||||
"ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions",
|
||||
"ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture",
|
||||
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ declare_args() {
|
||||
|
||||
enable_color_chooser = true
|
||||
|
||||
enable_picture_in_picture = true
|
||||
|
||||
# Provide a fake location provider for mocking
|
||||
# the geolocation responses. Disable it if you
|
||||
# need to test with chromium's location provider.
|
||||
|
||||
@@ -37,6 +37,12 @@ static_library("chrome") {
|
||||
"//chrome/browser/net/proxy_config_monitor.h",
|
||||
"//chrome/browser/net/proxy_service_factory.cc",
|
||||
"//chrome/browser/net/proxy_service_factory.h",
|
||||
"//chrome/browser/predictors/preconnect_manager.cc",
|
||||
"//chrome/browser/predictors/preconnect_manager.h",
|
||||
"//chrome/browser/predictors/proxy_lookup_client_impl.cc",
|
||||
"//chrome/browser/predictors/proxy_lookup_client_impl.h",
|
||||
"//chrome/browser/predictors/resolve_host_client_impl.cc",
|
||||
"//chrome/browser/predictors/resolve_host_client_impl.h",
|
||||
"//chrome/browser/ssl/security_state_tab_helper.cc",
|
||||
"//chrome/browser/ssl/security_state_tab_helper.h",
|
||||
"//chrome/browser/ui/autofill/popup_view_common.cc",
|
||||
@@ -55,6 +61,7 @@ static_library("chrome") {
|
||||
"//content/public/browser",
|
||||
]
|
||||
deps = [
|
||||
"//chrome/browser:resource_prefetch_predictor_proto",
|
||||
"//components/feature_engagement:buildflags",
|
||||
]
|
||||
|
||||
@@ -126,10 +133,6 @@ static_library("chrome") {
|
||||
sources += [
|
||||
"//chrome/browser/speech/tts_controller_delegate_impl.cc",
|
||||
"//chrome/browser/speech/tts_controller_delegate_impl.h",
|
||||
"//chrome/browser/speech/tts_message_filter.cc",
|
||||
"//chrome/browser/speech/tts_message_filter.h",
|
||||
"//chrome/renderer/tts_dispatcher.cc",
|
||||
"//chrome/renderer/tts_dispatcher.h",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -159,17 +162,21 @@ static_library("chrome") {
|
||||
"//chrome/browser/printing/printer_query.h",
|
||||
"//chrome/browser/printing/printing_message_filter.cc",
|
||||
"//chrome/browser/printing/printing_message_filter.h",
|
||||
"//chrome/browser/printing/printing_service.cc",
|
||||
"//chrome/browser/printing/printing_service.h",
|
||||
]
|
||||
|
||||
public_deps += [
|
||||
"//chrome/services/printing:lib",
|
||||
"//components/printing/browser",
|
||||
"//components/printing/renderer",
|
||||
"//components/services/pdf_compositor/public/cpp:factory",
|
||||
"//components/services/pdf_compositor",
|
||||
"//components/services/pdf_compositor/public/cpp",
|
||||
"//components/services/pdf_compositor/public/mojom",
|
||||
]
|
||||
|
||||
deps += [
|
||||
"//components/printing/common",
|
||||
"//components/services/pdf_compositor",
|
||||
"//printing",
|
||||
]
|
||||
|
||||
@@ -182,4 +189,30 @@ static_library("chrome") {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_picture_in_picture) {
|
||||
sources += [
|
||||
"//chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc",
|
||||
"//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h",
|
||||
"//chrome/browser/ui/views/overlay/back_to_tab_image_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/back_to_tab_image_button.h",
|
||||
"//chrome/browser/ui/views/overlay/close_image_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/close_image_button.h",
|
||||
"//chrome/browser/ui/views/overlay/overlay_window_views.cc",
|
||||
"//chrome/browser/ui/views/overlay/overlay_window_views.h",
|
||||
"//chrome/browser/ui/views/overlay/playback_image_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/playback_image_button.h",
|
||||
"//chrome/browser/ui/views/overlay/resize_handle_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/resize_handle_button.h",
|
||||
"//chrome/browser/ui/views/overlay/skip_ad_label_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/skip_ad_label_button.h",
|
||||
"//chrome/browser/ui/views/overlay/track_image_button.cc",
|
||||
"//chrome/browser/ui/views/overlay/track_image_button.h",
|
||||
]
|
||||
|
||||
deps += [
|
||||
"//chrome/app/vector_icons",
|
||||
"//components/vector_icons:vector_icons",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ component("pepper_flash") {
|
||||
"//chrome/browser/renderer_host/pepper/monitor_finder_mac.h",
|
||||
"//chrome/browser/renderer_host/pepper/monitor_finder_mac.mm",
|
||||
]
|
||||
libs = [ "CoreGraphics.framework" ]
|
||||
}
|
||||
if (is_linux) {
|
||||
deps += [ "//components/services/font/public/cpp" ]
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
<head>
|
||||
<title>Electron</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; connect-src 'self'" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'sha256-6PH54BfkNq/EMMhUY7nhHf3c+AxloOwfy7hWyT01CM8='; style-src 'self'; img-src 'self'; connect-src 'self'" />
|
||||
<link href="./styles.css" type="text/css" rel="stylesheet" />
|
||||
<link href="./octicon/build.css" type="text/css" rel="stylesheet" />
|
||||
<script defer src="./index.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -84,6 +83,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
window.electronDefaultApp.initialize()
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,30 +0,0 @@
|
||||
async function getOcticonSvg (name: string) {
|
||||
try {
|
||||
const response = await fetch(`octicon/${name}.svg`)
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = await response.text()
|
||||
return div
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSVG (element: HTMLSpanElement) {
|
||||
for (const cssClass of element.classList) {
|
||||
if (cssClass.startsWith('octicon-')) {
|
||||
const icon = await getOcticonSvg(cssClass.substr(8))
|
||||
if (icon) {
|
||||
for (const elemClass of element.classList) {
|
||||
icon.classList.add(elemClass)
|
||||
}
|
||||
element.before(icon)
|
||||
element.remove()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const element of document.querySelectorAll<HTMLSpanElement>('.octicon')) {
|
||||
loadSVG(element)
|
||||
}
|
||||
@@ -1,4 +1,31 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { ipcRenderer, contextBridge } from 'electron'
|
||||
|
||||
async function getOcticonSvg (name: string) {
|
||||
try {
|
||||
const response = await fetch(`octicon/${name}.svg`)
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = await response.text()
|
||||
return div
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSVG (element: HTMLSpanElement) {
|
||||
for (const cssClass of element.classList) {
|
||||
if (cssClass.startsWith('octicon-')) {
|
||||
const icon = await getOcticonSvg(cssClass.substr(8))
|
||||
if (icon) {
|
||||
for (const elemClass of element.classList) {
|
||||
icon.classList.add(elemClass)
|
||||
}
|
||||
element.before(icon)
|
||||
element.remove()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function initialize () {
|
||||
const electronPath = await ipcRenderer.invoke('bootstrap')
|
||||
@@ -15,6 +42,12 @@ async function initialize () {
|
||||
replaceText('.node-version', `Node v${process.versions.node}`)
|
||||
replaceText('.v8-version', `v8 v${process.versions.v8}`)
|
||||
replaceText('.command-example', `${electronPath} path-to-app`)
|
||||
|
||||
for (const element of document.querySelectorAll<HTMLSpanElement>('.octicon')) {
|
||||
loadSVG(element)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initialize)
|
||||
contextBridge.exposeInMainWorld('electronDefaultApp', {
|
||||
initialize
|
||||
})
|
||||
|
||||
@@ -39,6 +39,7 @@ an issue:
|
||||
* [Using Electron's APIs](tutorial/application-architecture.md#using-electron-apis)
|
||||
* [Using Node.js APIs](tutorial/application-architecture.md#using-nodejs-apis)
|
||||
* [Using Native Node.js Modules](tutorial/using-native-node-modules.md)
|
||||
* [Performance Strategies](tutorial/performance.md)
|
||||
* Adding Features to Your App
|
||||
* [Notifications](tutorial/notifications.md)
|
||||
* [Recent Documents](tutorial/recent-documents.md)
|
||||
|
||||
@@ -32,7 +32,7 @@ In most cases, you should do everything in the `ready` event handler.
|
||||
|
||||
Returns:
|
||||
|
||||
* `launchInfo` Object _macOS_
|
||||
* `launchInfo` unknown _macOS_
|
||||
|
||||
Emitted when Electron has finished initializing. On macOS, `launchInfo` holds
|
||||
the `userInfo` of the `NSUserNotification` that was used to open the application,
|
||||
@@ -146,7 +146,7 @@ Returns:
|
||||
* `event` Event
|
||||
* `type` String - A string identifying the activity. Maps to
|
||||
[`NSUserActivity.activityType`][activity-type].
|
||||
* `userInfo` Object - Contains app-specific state stored by the activity on
|
||||
* `userInfo` unknown - Contains app-specific state stored by the activity on
|
||||
another device.
|
||||
|
||||
Emitted during [Handoff][handoff] when an activity from a different device wants
|
||||
@@ -189,7 +189,7 @@ Returns:
|
||||
* `event` Event
|
||||
* `type` String - A string identifying the activity. Maps to
|
||||
[`NSUserActivity.activityType`][activity-type].
|
||||
* `userInfo` Object - Contains app-specific state stored by the activity.
|
||||
* `userInfo` unknown - Contains app-specific state stored by the activity.
|
||||
|
||||
Emitted during [Handoff][handoff] after an activity from this device was successfully
|
||||
resumed on another one.
|
||||
@@ -201,7 +201,7 @@ Returns:
|
||||
* `event` Event
|
||||
* `type` String - A string identifying the activity. Maps to
|
||||
[`NSUserActivity.activityType`][activity-type].
|
||||
* `userInfo` Object - Contains app-specific state stored by the activity.
|
||||
* `userInfo` unknown - Contains app-specific state stored by the activity.
|
||||
|
||||
Emitted when [Handoff][handoff] is about to be resumed on another device. If you need to update the state to be transferred, you should call `event.preventDefault()` immediately, construct a new `userInfo` dictionary and call `app.updateCurrentActiviy()` in a timely manner. Otherwise, the operation will fail and `continue-activity-error` will be called.
|
||||
|
||||
@@ -314,10 +314,8 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
* `request` Object
|
||||
* `method` String
|
||||
* `authenticationResponseDetails` Object
|
||||
* `url` URL
|
||||
* `referrer` URL
|
||||
* `authInfo` Object
|
||||
* `isProxy` Boolean
|
||||
* `scheme` String
|
||||
@@ -325,8 +323,8 @@ Returns:
|
||||
* `port` Integer
|
||||
* `realm` String
|
||||
* `callback` Function
|
||||
* `username` String
|
||||
* `password` String
|
||||
* `username` String (optional)
|
||||
* `password` String (optional)
|
||||
|
||||
Emitted when `webContents` wants to do basic auth.
|
||||
|
||||
@@ -337,12 +335,16 @@ should prevent the default behavior with `event.preventDefault()` and call
|
||||
```javascript
|
||||
const { app } = require('electron')
|
||||
|
||||
app.on('login', (event, webContents, request, authInfo, callback) => {
|
||||
app.on('login', (event, webContents, details, authInfo, callback) => {
|
||||
event.preventDefault()
|
||||
callback('username', 'secret')
|
||||
})
|
||||
```
|
||||
|
||||
If `callback` is called without a username or password, the authentication
|
||||
request will be cancelled and the authentication error will be returned to the
|
||||
page.
|
||||
|
||||
### Event: 'gpu-info-update'
|
||||
|
||||
Emitted whenever there is a GPU info update.
|
||||
@@ -582,7 +584,7 @@ them.
|
||||
|
||||
Sets or creates a directory your app's logs which can then be manipulated with `app.getPath()` or `app.setPath(pathName, newPath)`.
|
||||
|
||||
Calling `app.setAppLogsPath()` without a `path` parameter will result in this directory being set to `/Library/Logs/YourAppName` on _macOS_, and inside the `userData` directory on _Linux_ and _Windows_.
|
||||
Calling `app.setAppLogsPath()` without a `path` parameter will result in this directory being set to `~/Library/Logs/YourAppName` on _macOS_, and inside the `userData` directory on _Linux_ and _Windows_.
|
||||
|
||||
### `app.getAppPath()`
|
||||
|
||||
@@ -614,6 +616,8 @@ Returns `String` - The current application directory.
|
||||
Returns `String` - A path to a special directory or file associated with `name`. On
|
||||
failure, an `Error` is thrown.
|
||||
|
||||
If `app.getPath('logs')` is called without called `app.setAppLogsPath()` being called first, a default log directory will be created equivalent to calling `app.setAppLogsPath()` without a `path` parameter.
|
||||
|
||||
### `app.getFileIcon(path[, options])`
|
||||
|
||||
* `path` String
|
||||
@@ -949,7 +953,7 @@ allow multiple instances of the application to once again run side by side.
|
||||
|
||||
* `type` String - Uniquely identifies the activity. Maps to
|
||||
[`NSUserActivity.activityType`][activity-type].
|
||||
* `userInfo` Object - App-specific state to store for use by another device.
|
||||
* `userInfo` any - App-specific state to store for use by another device.
|
||||
* `webpageURL` String (optional) - The webpage to load in a browser if no suitable app is
|
||||
installed on the resuming device. The scheme must be `http` or `https`.
|
||||
|
||||
@@ -972,7 +976,7 @@ Marks the current [Handoff][handoff] user activity as inactive without invalidat
|
||||
|
||||
* `type` String - Uniquely identifies the activity. Maps to
|
||||
[`NSUserActivity.activityType`][activity-type].
|
||||
* `userInfo` Object - App-specific state to store for use by another device.
|
||||
* `userInfo` any - App-specific state to store for use by another device.
|
||||
|
||||
Updates the current activity if its type matches `type`, merging the entries from
|
||||
`userInfo` into its current `userInfo` dictionary.
|
||||
|
||||
@@ -103,7 +103,7 @@ The `autoUpdater` object has the following methods:
|
||||
|
||||
* `options` Object
|
||||
* `url` String
|
||||
* `headers` Object (optional) _macOS_ - HTTP request headers.
|
||||
* `headers` Record<String, String> (optional) _macOS_ - HTTP request headers.
|
||||
* `serverType` String (optional) _macOS_ - Either `json` or `default`, see the [Squirrel.Mac][squirrel-mac]
|
||||
README for more information.
|
||||
|
||||
|
||||
@@ -68,6 +68,40 @@ webFrame.setIsolatedWorldInfo(
|
||||
|
||||
This property was removed in Chromium 77, and as such is no longer available.
|
||||
|
||||
### `webkitdirectory` attribute for `<input type="file"/>`
|
||||

|
||||
The `webkitdirectory` property on HTML file inputs allows them to select folders.
|
||||
Previous versions of Electron had an incorrect implementation where the `event.target.files`
|
||||
of the input returned a `FileList` that returned one `File` corresponding to the selected folder.
|
||||

|
||||
As of Electron 7, that `FileList` is now list of all files contained within
|
||||
the folder, similarly to Chrome, Firefox, and Edge
|
||||
([link to MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory)).
|
||||

|
||||
As an illustration, take a folder with this structure:
|
||||
```console
|
||||
folder
|
||||
├── file1
|
||||
├── file2
|
||||
└── file3
|
||||
```
|
||||

|
||||
In Electron <=6, this would return a `FileList` with a `File` object for:
|
||||
```console
|
||||
path/to/folder
|
||||
```
|
||||

|
||||
In Electron 7, this now returns a `FileList` with a `File` object for:
|
||||
```console
|
||||
/path/to/folder/file3
|
||||
/path/to/folder/file2
|
||||
/path/to/folder/file1
|
||||
```
|
||||

|
||||
Note that `webkitdirectory` no longer exposes the path to the selected folder.
|
||||
If you require the path to the selected folder rather than the folder contents,
|
||||
see the `dialog.showOpenDialog` API ([link](https://github.com/electron/electron/blob/master/docs/api/dialog.md#dialogshowopendialogbrowserwindow-options)).
|
||||
|
||||
## Planned Breaking API Changes (6.0)
|
||||
|
||||
### `win.setMenu(null)`
|
||||
@@ -197,7 +231,7 @@ A new API, `protocol.registerSchemesAsPrivileged` has been added and should be u
|
||||
### webFrame Isolated World APIs
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
// Removed in Electron 7.0
|
||||
webFrame.setIsolatedWorldContentSecurityPolicy(worldId, csp)
|
||||
webFrame.setIsolatedWorldHumanReadableName(worldId, name)
|
||||
webFrame.setIsolatedWorldSecurityOrigin(worldId, securityOrigin)
|
||||
|
||||
@@ -51,6 +51,9 @@ This event is usually emitted after the `did-finish-load` event, but for
|
||||
pages with many remote resources, it may be emitted before the `did-finish-load`
|
||||
event.
|
||||
|
||||
Please note that using this event implies that the renderer will be considered "visible" and
|
||||
paint even though `show` is false. This event will never fire if you use `paintWhenInitiallyHidden: false`
|
||||
|
||||
## Setting `backgroundColor`
|
||||
|
||||
For a complex app, the `ready-to-show` event could be emitted too late, making
|
||||
@@ -184,6 +187,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
leave it undefined so the executable's icon will be used.
|
||||
* `show` Boolean (optional) - Whether window should be shown when created. Default is
|
||||
`true`.
|
||||
* `paintWhenInitiallyHidden` Boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`.
|
||||
* `frame` Boolean (optional) - Specify `false` to create a
|
||||
[Frameless Window](frameless-window.md). Default is `true`.
|
||||
* `parent` BrowserWindow (optional) - Specify parent window. Default is `null`.
|
||||
@@ -485,6 +489,9 @@ Emitted when the window is hidden.
|
||||
Emitted when the web page has been rendered (while not being shown) and window can be displayed without
|
||||
a visual flash.
|
||||
|
||||
Please note that using this event implies that the renderer will be considered "visible" and
|
||||
paint even though `show` is false. This event will never fire if you use `paintWhenInitiallyHidden: false`
|
||||
|
||||
#### Event: 'maximize'
|
||||
|
||||
Emitted when window is maximized.
|
||||
@@ -506,7 +513,7 @@ Emitted when the window is restored from a minimized state.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `newBounds` [`Rectangle`](structures/rectangle.md) - Size the window is being resized to.
|
||||
* `newBounds` [Rectangle](structures/rectangle.md) - Size the window is being resized to.
|
||||
|
||||
Emitted before the window is resized. Calling `event.preventDefault()` will prevent the window from being resized.
|
||||
|
||||
@@ -521,7 +528,7 @@ Emitted after the window has been resized.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `newBounds` [`Rectangle`](structures/rectangle.md) - Location the window is being moved to.
|
||||
* `newBounds` [Rectangle](structures/rectangle.md) - Location the window is being moved to.
|
||||
|
||||
Emitted before the window is moved. Calling `event.preventDefault()` will prevent the window from being moved.
|
||||
|
||||
@@ -691,7 +698,7 @@ is emitted.
|
||||
|
||||
#### `BrowserWindow.getExtensions()`
|
||||
|
||||
Returns `Object` - The keys are the extension names and each value is
|
||||
Returns `Record<String, ExtensionInfo>` - The keys are the extension names and each value is
|
||||
an Object containing `name` and `version` properties.
|
||||
|
||||
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||
@@ -724,7 +731,7 @@ is emitted.
|
||||
|
||||
#### `BrowserWindow.getDevToolsExtensions()`
|
||||
|
||||
Returns `Object` - The keys are the extension names and each value is
|
||||
Returns `Record<string, ExtensionInfo>` - The keys are the extension names and each value is
|
||||
an Object containing `name` and `version` properties.
|
||||
|
||||
To check if a DevTools extension is installed you can run the following:
|
||||
@@ -1381,7 +1388,7 @@ win.loadURL('http://localhost:8000/post', {
|
||||
|
||||
* `filePath` String
|
||||
* `options` Object (optional)
|
||||
* `query` Object (optional) - Passed to `url.format()`.
|
||||
* `query` Record<String, String> (optional) - Passed to `url.format()`.
|
||||
* `search` String (optional) - Passed to `url.format()`.
|
||||
* `hash` String (optional) - Passed to `url.format()`.
|
||||
|
||||
@@ -1437,29 +1444,27 @@ screen readers
|
||||
Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to
|
||||
convey some sort of application status or to passively notify the user.
|
||||
|
||||
#### `win.setHasShadow(hasShadow)` _macOS_
|
||||
#### `win.setHasShadow(hasShadow)`
|
||||
|
||||
* `hasShadow` Boolean
|
||||
|
||||
Sets whether the window should have a shadow. On Windows and Linux does
|
||||
nothing.
|
||||
Sets whether the window should have a shadow.
|
||||
|
||||
#### `win.hasShadow()` _macOS_
|
||||
#### `win.hasShadow()`
|
||||
|
||||
Returns `Boolean` - Whether the window has a shadow.
|
||||
|
||||
On Windows and Linux always returns
|
||||
`true`.
|
||||
|
||||
#### `win.setOpacity(opacity)` _Windows_ _macOS_
|
||||
|
||||
* `opacity` Number - between 0.0 (fully transparent) and 1.0 (fully opaque)
|
||||
|
||||
Sets the opacity of the window. On Linux does nothing.
|
||||
Sets the opacity of the window. On Linux, does nothing. Out of bound number
|
||||
values are clamped to the [0, 1] range.
|
||||
|
||||
#### `win.getOpacity()` _Windows_ _macOS_
|
||||
#### `win.getOpacity()`
|
||||
|
||||
Returns `Number` - between 0.0 (fully transparent) and 1.0 (fully opaque)
|
||||
Returns `Number` - between 0.0 (fully transparent) and 1.0 (fully opaque). On
|
||||
Linux, always returns 1.
|
||||
|
||||
#### `win.setShape(rects)` _Windows_ _Linux_ _Experimental_
|
||||
|
||||
@@ -1548,7 +1553,7 @@ Same as `webContents.showDefinitionForSelection()`.
|
||||
|
||||
#### `win.setIcon(icon)` _Windows_ _Linux_
|
||||
|
||||
* `icon` [NativeImage](native-image.md)
|
||||
* `icon` [NativeImage](native-image.md) | String
|
||||
|
||||
Changes window icon.
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ following properties:
|
||||
method.
|
||||
* `url` String (optional) - The request URL. Must be provided in the absolute
|
||||
form with the protocol scheme specified as http or https.
|
||||
* `session` Object (optional) - The [`Session`](session.md) instance with
|
||||
* `session` Session (optional) - The [`Session`](session.md) instance with
|
||||
which the request is associated.
|
||||
* `partition` String (optional) - The name of the [`partition`](session.md)
|
||||
with which the request is associated. Defaults to the empty string. The
|
||||
@@ -32,8 +32,8 @@ the hostname and the port number 'hostname:port'.
|
||||
* `redirect` String (optional) - The redirect mode for this request. Should be
|
||||
one of `follow`, `error` or `manual`. Defaults to `follow`. When mode is `error`,
|
||||
any redirection will be aborted. When mode is `manual` the redirection will be
|
||||
deferred until [`request.followRedirect`](#requestfollowredirect) is invoked. Listen for the [`redirect`](#event-redirect) event in
|
||||
this mode to get more details about the redirect request.
|
||||
cancelled unless [`request.followRedirect`](#requestfollowredirect) is invoked
|
||||
synchronously during the [`redirect`](#event-redirect) event.
|
||||
|
||||
`options` properties such as `protocol`, `host`, `hostname`, `port` and `path`
|
||||
strictly follow the Node.js model as described in the
|
||||
@@ -70,8 +70,8 @@ Returns:
|
||||
* `port` Integer
|
||||
* `realm` String
|
||||
* `callback` Function
|
||||
* `username` String
|
||||
* `password` String
|
||||
* `username` String (optional)
|
||||
* `password` String (optional)
|
||||
|
||||
Emitted when an authenticating proxy is asking for user credentials.
|
||||
|
||||
@@ -134,10 +134,13 @@ Returns:
|
||||
* `statusCode` Integer
|
||||
* `method` String
|
||||
* `redirectUrl` String
|
||||
* `responseHeaders` Object
|
||||
* `responseHeaders` Record<String, String[]>
|
||||
|
||||
Emitted when there is redirection and the mode is `manual`. Calling
|
||||
[`request.followRedirect`](#requestfollowredirect) will continue with the redirection.
|
||||
Emitted when the server returns a redirect response (e.g. 301 Moved
|
||||
Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will
|
||||
continue with the redirection. If this event is handled,
|
||||
[`request.followRedirect`](#requestfollowredirect) must be called
|
||||
**synchronously**, otherwise the request will be cancelled.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
@@ -158,7 +161,7 @@ internally buffered inside Electron process memory.
|
||||
#### `request.setHeader(name, value)`
|
||||
|
||||
* `name` String - An extra HTTP header name.
|
||||
* `value` Object - An extra HTTP header value.
|
||||
* `value` String - An extra HTTP header value.
|
||||
|
||||
Adds an extra HTTP header. The header name will be issued as-is without
|
||||
lowercasing. It can be called only before first write. Calling this method after
|
||||
@@ -169,7 +172,7 @@ the first write will throw an error. If the passed value is not a `String`, its
|
||||
|
||||
* `name` String - Specify an extra header name.
|
||||
|
||||
Returns `Object` - The value of a previously set extra header name.
|
||||
Returns `String` - The value of a previously set extra header name.
|
||||
|
||||
#### `request.removeHeader(name)`
|
||||
|
||||
@@ -214,7 +217,8 @@ response object,it will emit the `aborted` event.
|
||||
|
||||
#### `request.followRedirect()`
|
||||
|
||||
Continues any deferred redirection request when the redirection mode is `manual`.
|
||||
Continues any pending redirection. Can only be called during a `'redirect'`
|
||||
event.
|
||||
|
||||
#### `request.getUploadProgress()`
|
||||
|
||||
|
||||
@@ -4,18 +4,12 @@
|
||||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
The following example shows how to write a string to the clipboard:
|
||||
|
||||
```javascript
|
||||
const { clipboard } = require('electron')
|
||||
clipboard.writeText('Example String')
|
||||
```
|
||||
|
||||
On Linux, there is also a `selection` clipboard. To manipulate it
|
||||
you need to pass `selection` to each method:
|
||||
|
||||
```javascript
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeText('Example String', 'selection')
|
||||
console.log(clipboard.readText('selection'))
|
||||
```
|
||||
@@ -28,56 +22,106 @@ The `clipboard` module has the following methods:
|
||||
|
||||
### `clipboard.readText([type])`
|
||||
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Returns `String` - The content in the clipboard as plain text.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeText('hello i am a bit of text!')
|
||||
|
||||
const text = clipboard.readText()
|
||||
console.log(text)
|
||||
// hello i am a bit of text!'
|
||||
```
|
||||
|
||||
### `clipboard.writeText(text[, type])`
|
||||
|
||||
* `text` String
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Writes the `text` into the clipboard as plain text.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const text = 'hello i am a bit of text!'
|
||||
clipboard.writeText(text)
|
||||
```
|
||||
|
||||
### `clipboard.readHTML([type])`
|
||||
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Returns `String` - The content in the clipboard as markup.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeHTML('<b>Hi</b>')
|
||||
const html = clipboard.readHTML()
|
||||
|
||||
console.log(html)
|
||||
// <meta charset='utf-8'><b>Hi</b>
|
||||
```
|
||||
|
||||
### `clipboard.writeHTML(markup[, type])`
|
||||
|
||||
* `markup` String
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Writes `markup` to the clipboard.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeHTML('<b>Hi</b')
|
||||
```
|
||||
|
||||
### `clipboard.readImage([type])`
|
||||
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Returns [`NativeImage`](native-image.md) - The image content in the clipboard.
|
||||
|
||||
### `clipboard.writeImage(image[, type])`
|
||||
|
||||
* `image` [NativeImage](native-image.md)
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Writes `image` to the clipboard.
|
||||
|
||||
### `clipboard.readRTF([type])`
|
||||
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Returns `String` - The content in the clipboard as RTF.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeRTF('{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}')
|
||||
|
||||
const rtf = clipboard.readRTF()
|
||||
console.log(rtf)
|
||||
// {\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}
|
||||
```
|
||||
|
||||
### `clipboard.writeRTF(text[, type])`
|
||||
|
||||
* `text` String
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Writes the `text` into the clipboard in RTF.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const rtf = '{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}'
|
||||
clipboard.writeRTF(rtf)
|
||||
```
|
||||
|
||||
### `clipboard.readBookmark()` _macOS_ _Windows_
|
||||
|
||||
Returns `Object`:
|
||||
@@ -93,7 +137,7 @@ bookmark is unavailable.
|
||||
|
||||
* `title` String
|
||||
* `url` String
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Writes the `title` and `url` into the clipboard as a bookmark.
|
||||
|
||||
@@ -102,7 +146,9 @@ you can use `clipboard.write` to write both a bookmark and fallback text to the
|
||||
clipboard.
|
||||
|
||||
```js
|
||||
clipboard.write({
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeBookmark({
|
||||
text: 'https://electronjs.org',
|
||||
bookmark: 'Electron Homepage'
|
||||
})
|
||||
@@ -110,39 +156,50 @@ clipboard.write({
|
||||
|
||||
### `clipboard.readFindText()` _macOS_
|
||||
|
||||
Returns `String` - The text on the find pasteboard. This method uses synchronous
|
||||
IPC when called from the renderer process. The cached value is reread from the
|
||||
find pasteboard whenever the application is activated.
|
||||
Returns `String` - The text on the find pasteboard, which is the pasteboard that holds information about the current state of the active application’s find panel.
|
||||
|
||||
This method uses synchronous IPC when called from the renderer process.
|
||||
The cached value is reread from the find pasteboard whenever the application is activated.
|
||||
|
||||
### `clipboard.writeFindText(text)` _macOS_
|
||||
|
||||
* `text` String
|
||||
|
||||
Writes the `text` into the find pasteboard as plain text. This method uses
|
||||
synchronous IPC when called from the renderer process.
|
||||
Writes the `text` into the find pasteboard (the pasteboard that holds information about the current state of the active application’s find panel) as plain text. This method uses synchronous IPC when called from the renderer process.
|
||||
|
||||
### `clipboard.clear([type])`
|
||||
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Clears the clipboard content.
|
||||
|
||||
### `clipboard.availableFormats([type])`
|
||||
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Returns `String[]` - An array of supported formats for the clipboard `type`.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const formats = clipboard.availableFormats()
|
||||
console.log(formats)
|
||||
// [ 'text/plain', 'text/html' ]
|
||||
```
|
||||
|
||||
### `clipboard.has(format[, type])` _Experimental_
|
||||
|
||||
* `format` String
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Returns `Boolean` - Whether the clipboard supports the specified `format`.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
console.log(clipboard.has('<p>selection</p>'))
|
||||
|
||||
const hasFormat = clipboard.has('<p>selection</p>')
|
||||
console.log(hasFormat)
|
||||
// 'true' or 'false
|
||||
```
|
||||
|
||||
### `clipboard.read(format)` _Experimental_
|
||||
@@ -157,14 +214,33 @@ Returns `String` - Reads `format` type from the clipboard.
|
||||
|
||||
Returns `Buffer` - Reads `format` type from the clipboard.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const buffer = Buffer.from('this is binary', 'utf8')
|
||||
clipboard.writeBuffer('public.utf8-plain-text', buffer)
|
||||
|
||||
const ret = clipboard.readBuffer('public.utf8-plain-text')
|
||||
|
||||
console.log(buffer.equals(out))
|
||||
// true
|
||||
```
|
||||
|
||||
### `clipboard.writeBuffer(format, buffer[, type])` _Experimental_
|
||||
|
||||
* `format` String
|
||||
* `buffer` Buffer
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Writes the `buffer` into the clipboard as `format`.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const buffer = Buffer.from('writeBuffer', 'utf8')
|
||||
clipboard.writeBuffer('public.utf8-plain-text', buffer)
|
||||
```
|
||||
|
||||
### `clipboard.write(data[, type])`
|
||||
|
||||
* `data` Object
|
||||
@@ -173,10 +249,29 @@ Writes the `buffer` into the clipboard as `format`.
|
||||
* `image` [NativeImage](native-image.md) (optional)
|
||||
* `rtf` String (optional)
|
||||
* `bookmark` String (optional) - The title of the URL at `text`.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`. `selection` is only available on Linux.
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
```javascript
|
||||
const { clipboard } = require('electron')
|
||||
clipboard.write({ text: 'test', html: '<b>test</b>' })
|
||||
```
|
||||
Writes `data` to the clipboard.
|
||||
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.write({
|
||||
text: 'test',
|
||||
html: '<b>Hi</b>',
|
||||
rtf: '{\\rtf1\\utf8 text}',
|
||||
bookmark: 'a title'
|
||||
})
|
||||
|
||||
console.log(clipboard.readText())
|
||||
// 'test'
|
||||
|
||||
console.log(clipboard.readHTML())
|
||||
// <meta charset='utf-8'><b>Hi</b>
|
||||
|
||||
console.log(clipboard.readRTF())
|
||||
// '{\\rtf1\\utf8 text}'
|
||||
|
||||
console.log(clipboard.readBookmark())
|
||||
// { title: 'a title', url: 'test' }
|
||||
```
|
||||
|
||||
@@ -74,6 +74,9 @@ will be returned in the promise.
|
||||
|
||||
Returns `Promise<Object>` - Resolves with an object containing the `value` and `percentage` of trace buffer maximum usage
|
||||
|
||||
* `value` Number
|
||||
* `percentage` Number
|
||||
|
||||
Get the maximum usage across processes of trace buffer as a percentage of the
|
||||
full state.
|
||||
|
||||
|
||||
111
docs/api/context-bridge.md
Normal file
111
docs/api/context-bridge.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# contextBridge
|
||||
|
||||
> Create a safe, bi-directional, synchronous bridge across isolated contexts
|
||||
|
||||
Process: [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
An example of exposing an API to a renderer from an isolated preload script is given below:
|
||||
|
||||
```javascript
|
||||
// Preload (Isolated World)
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
|
||||
contextBridge.exposeInMainWorld(
|
||||
'electron',
|
||||
{
|
||||
doThing: () => ipcRenderer.send('do-a-thing')
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Renderer (Main World)
|
||||
|
||||
window.electron.doThing()
|
||||
```
|
||||
|
||||
## Glossary
|
||||
|
||||
### Main World
|
||||
|
||||
The "Main World" is the javascript context that your main renderer code runs in. By default the page you load in your renderer
|
||||
executes code in this world.
|
||||
|
||||
### Isolated World
|
||||
|
||||
When `contextIsolation` is enabled in your `webPreferences` your `preload` scripts run in an "Isolated World". You can read more about
|
||||
context isolation and what it affects in the [BrowserWindow](browser-window.md) docs.
|
||||
|
||||
## Methods
|
||||
|
||||
The `contextBridge` module has the following methods:
|
||||
|
||||
### `contextBridge.exposeInMainWorld(apiKey, api)` _Experimental_
|
||||
|
||||
* `apiKey` String - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`.
|
||||
* `api` Record<String, any> - Your API object, more information on what this API can be and how it works is available below.
|
||||
|
||||
## Usage
|
||||
|
||||
### API Objects
|
||||
|
||||
The `api` object provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api-experimental) must be an object
|
||||
whose keys are strings and values are a `Function`, `String`, `Number`, `Array`, `Boolean` or another nested object that meets the same conditions.
|
||||
|
||||
`Function` values are proxied to the other context and all other values are **copied** and **frozen**. I.e. Any data / primitives sent in
|
||||
the API object become immutable and updates on either side of the bridge do not result in an update on the other side.
|
||||
|
||||
An example of a complex API object is shown below.
|
||||
|
||||
```javascript
|
||||
const { contextBridge } = require('electron')
|
||||
|
||||
contextBridge.exposeInMainWorld(
|
||||
'electron',
|
||||
{
|
||||
doThing: () => ipcRenderer.send('do-a-thing'),
|
||||
myPromises: [Promise.resolve(), Promise.reject(new Error('whoops'))],
|
||||
anAsyncFunction: async () => 123,
|
||||
data: {
|
||||
myFlags: ['a', 'b', 'c'],
|
||||
bootTime: 1234
|
||||
},
|
||||
nestedAPI: {
|
||||
evenDeeper: {
|
||||
youCanDoThisAsMuchAsYouWant: {
|
||||
fn: () => ({
|
||||
returnData: 123
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### API Functions
|
||||
|
||||
`Function` values that you bind through the `contextBridge` are proxied through Electron to ensure that contexts remain isolated. This
|
||||
results in some key limitations that we've outlined below.
|
||||
|
||||
#### Parameter / Error / Return Type support
|
||||
|
||||
Because parameters, errors and return values are **copied** when they are sent over the bridge there are only certain types that can be used.
|
||||
At a high level if the type you want to use can be serialized and un-serialized into the same object it will work. A table of type support
|
||||
has been included below for completeness.
|
||||
|
||||
| Type | Complexity | Parameter Support | Return Value Support | Limitations |
|
||||
| ---- | ---------- | ----------------- | -------------------- | ----------- |
|
||||
| `String` | Simple | ✅ | ✅ | N/A |
|
||||
| `Number` | Simple | ✅ | ✅ | N/A |
|
||||
| `Boolean` | Simple | ✅ | ✅ | N/A |
|
||||
| `Object` | Complex | ✅ | ✅ | Keys must be supported "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. |
|
||||
| `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type |
|
||||
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context |
|
||||
| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are a the return value or exact parameter. Promises nested in arrays or obejcts will be dropped. |
|
||||
| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. |
|
||||
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types |
|
||||
| `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped |
|
||||
|
||||
|
||||
If the type you care about is not in the above table it is probably not supported.
|
||||
@@ -48,7 +48,7 @@ The `crashReporter` module has the following methods:
|
||||
* `productName` String (optional) - Defaults to `app.name`.
|
||||
* `uploadToServer` Boolean (optional) - Whether crash reports should be sent to the server. Default is `true`.
|
||||
* `ignoreSystemCrashHandler` Boolean (optional) - Default is `false`.
|
||||
* `extra` Object (optional) - An object you can define that will be sent along with the
|
||||
* `extra` Record<String, String> (optional) - An object you can define that will be sent along with the
|
||||
report. Only string properties are sent correctly. Nested objects are not
|
||||
supported. When using Windows, the property names and values must be fewer than 64 characters.
|
||||
* `crashesDirectory` String (optional) - Directory to store the crash reports temporarily (only used when the crash reporter is started via `process.crashReporter.start`).
|
||||
|
||||
@@ -50,7 +50,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `method` String - Method name.
|
||||
* `params` Object - Event parameters defined by the 'parameters'
|
||||
* `params` unknown - Event parameters defined by the 'parameters'
|
||||
attribute in the remote debugging protocol.
|
||||
|
||||
Emitted whenever the debugging target issues an instrumentation event.
|
||||
@@ -78,7 +78,7 @@ Detaches the debugger from the `webContents`.
|
||||
|
||||
* `method` String - Method name, should be one of the methods defined by the
|
||||
[remote debugging protocol][rdp].
|
||||
* `commandParams` Object (optional) - JSON object with request parameters.
|
||||
* `commandParams` any (optional) - JSON object with request parameters.
|
||||
|
||||
Returns `Promise<any>` - A promise that resolves with the response defined by
|
||||
the 'returns' attribute of the command description in the remote debugging protocol
|
||||
|
||||
@@ -52,6 +52,8 @@ The `dialog` module has the following methods:
|
||||
boxes.
|
||||
* `securityScopedBookmarks` Boolean (optional) _macOS_ _mas_ - Create [security scoped bookmarks](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store.
|
||||
|
||||
Returns `String[] | undefined`, the file paths chosen by the user; if the dialog is cancelled it returns `undefined`.
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
The `filters` specifies an array of file types that can be displayed or
|
||||
@@ -227,7 +229,7 @@ expanding and collapsing the dialog.
|
||||
include a checkbox with the given label.
|
||||
* `checkboxChecked` Boolean (optional) - Initial checked state of the
|
||||
checkbox. `false` by default.
|
||||
* `icon` [NativeImage](native-image.md) (optional)
|
||||
* `icon` ([NativeImage](native-image.md) | String) (optional)
|
||||
* `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via
|
||||
the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the
|
||||
label. If no such labeled buttons exist and this option is not set, `0` will be used as the
|
||||
|
||||
@@ -18,6 +18,8 @@ app.dock.bounce()
|
||||
* `type` String (optional) - Can be `critical` or `informational`. The default is
|
||||
`informational`
|
||||
|
||||
Returns `Integer` - an ID representing the request.
|
||||
|
||||
When `critical` is passed, the dock icon will bounce until either the
|
||||
application becomes active or the request is canceled.
|
||||
|
||||
@@ -25,7 +27,7 @@ When `informational` is passed, the dock icon will bounce for one second.
|
||||
However, the request remains active until either the application becomes active
|
||||
or the request is canceled.
|
||||
|
||||
Returns `Integer` an ID representing the request.
|
||||
**Nota Bene:** This method can only be used while the app is not focused; when the app is focused it will return -1.
|
||||
|
||||
#### `dock.cancelBounce(id)` _macOS_
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ A `String` representing the HTTP status message.
|
||||
|
||||
#### `response.headers`
|
||||
|
||||
An `Object` representing the response HTTP headers. The `headers` object is
|
||||
An `Record<string, string[]>` representing the response HTTP headers. The `headers` object is
|
||||
formatted as follows:
|
||||
|
||||
* All header names are lowercased.
|
||||
|
||||
@@ -77,6 +77,7 @@ only the next time a message is sent to `channel`, after which it is removed.
|
||||
|
||||
* `channel` String
|
||||
* `listener` Function
|
||||
* `...args` any[]
|
||||
|
||||
Removes the specified `listener` from the listener array for the specified
|
||||
`channel`.
|
||||
@@ -90,7 +91,7 @@ Removes listeners of the specified `channel`.
|
||||
### `ipcMain.handle(channel, listener)`
|
||||
|
||||
* `channel` String
|
||||
* `listener` Function<Promise> | Function<any>
|
||||
* `listener` Function<Promise<void> | any>
|
||||
* `event` IpcMainInvokeEvent
|
||||
* `...args` any[]
|
||||
|
||||
@@ -122,7 +123,7 @@ WebContents is the source of the invoke request.
|
||||
### `ipcMain.handleOnce(channel, listener)`
|
||||
|
||||
* `channel` String
|
||||
* `listener` Function<Promise> | Function<any>
|
||||
* `listener` Function<Promise<void> | any>
|
||||
* `event` IpcMainInvokeEvent
|
||||
* `...args` any[]
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ See [`Menu`](menu.md) for examples.
|
||||
* `menuItem` MenuItem
|
||||
* `browserWindow` [BrowserWindow](browser-window.md)
|
||||
* `event` [KeyboardEvent](structures/keyboard-event.md)
|
||||
* `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteandmatchstyle`, `delete`, `selectall`, `reload`, `forcereload`, `toggledevtools`, `resetzoom`, `zoomin`, `zoomout`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideothers`, `unhide`, `quit`, `startspeaking`, `stopspeaking`, `close`, `minimize`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu` or `windowMenu` - Define the action of the menu item, when specified the
|
||||
* `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `close`, `minimize`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the
|
||||
`click` property will be ignored. See [roles](#roles).
|
||||
* `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or
|
||||
`radio`.
|
||||
@@ -82,7 +82,7 @@ The `role` property can have following values:
|
||||
* `reload` - Reload the current window.
|
||||
* `forceReload` - Reload the current window ignoring the cache.
|
||||
* `toggleDevTools` - Toggle developer tools in the current window.
|
||||
* `toggleFullScreen` - Toggle full screen mode on the current window.
|
||||
* `togglefullscreen` - Toggle full screen mode on the current window.
|
||||
* `resetZoom` - Reset the focused page's zoom level to the original size.
|
||||
* `zoomIn` - Zoom in the focused page by 10%.
|
||||
* `zoomOut` - Zoom out the focused page by 10%.
|
||||
@@ -152,7 +152,7 @@ A `String` indicating the type of the item. Can be `normal`, `separator`, `subme
|
||||
|
||||
#### `menuItem.role`
|
||||
|
||||
A `String` (optional) indicating the item's role, if set. Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteandmatchstyle`, `delete`, `selectall`, `reload`, `forcereload`, `toggledevtools`, `resetzoom`, `zoomin`, `zoomout`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideothers`, `unhide`, `quit`, `startspeaking`, `stopspeaking`, `close`, `minimize`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu` or `windowMenu`
|
||||
A `String` (optional) indicating the item's role, if set. Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `close`, `minimize`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu`
|
||||
|
||||
#### `menuItem.accelerator`
|
||||
|
||||
|
||||
@@ -328,9 +328,9 @@ can be called on empty images.
|
||||
|
||||
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
|
||||
|
||||
## Properties
|
||||
### Instance Properties
|
||||
|
||||
### `nativeImage.isMacTemplateImage` _macOS_
|
||||
#### `nativeImage.isMacTemplateImage` _macOS_
|
||||
|
||||
A `Boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template).
|
||||
|
||||
|
||||
66
docs/api/native-theme.md
Normal file
66
docs/api/native-theme.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# nativeTheme
|
||||
|
||||
> Read and respond to changes in Chromium's native color theme.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
## Events
|
||||
|
||||
The `nativeTheme` module emits the following events:
|
||||
|
||||
### Event: 'updated'
|
||||
|
||||
Emitted when something in the underlying NativeTheme has changed. This normally
|
||||
means that either the value of `shouldUseDarkColors`,
|
||||
`shouldUseHighContrastColors` or `shouldUseInvertedColorScheme` has changed.
|
||||
You will have to check them to determine which one has changed.
|
||||
|
||||
## Properties
|
||||
|
||||
The `nativeTheme` module has the following properties:
|
||||
|
||||
### `nativeTheme.shouldUseDarkColors` _Readonly_
|
||||
|
||||
A `Boolean` for if the OS / Chromium currently has a dark mode enabled or is
|
||||
being instructed to show a dark-style UI. If you want to modify this value you
|
||||
should use `themeSource` below.
|
||||
|
||||
### `nativeTheme.themeSource`
|
||||
|
||||
A `String` property that can be `system`, `light` or `dark`. It is used to override and supercede
|
||||
the value that Chromium has chosen to use internally.
|
||||
|
||||
Setting this property to `system` will remove the override and
|
||||
everything will be reset to the OS default. By default `themeSource` is `system`.
|
||||
|
||||
Settings this property to `dark` will have the following effects:
|
||||
* `nativeTheme.shouldUseDarkColors` will be `true` when accessed
|
||||
* Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the dark UI.
|
||||
* Any UI the OS renders on macOS including menus, window frames, etc. will use the dark UI.
|
||||
* The [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS query will match `dark` mode.
|
||||
* The `updated` event will be emitted
|
||||
|
||||
Settings this property to `light` will have the following effects:
|
||||
* `nativeTheme.shouldUseDarkColors` will be `false` when accessed
|
||||
* Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the light UI.
|
||||
* Any UI the OS renders on macOS including menus, window frames, etc. will use the light UI.
|
||||
* The [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS query will match `light` mode.
|
||||
* The `updated` event will be emitted
|
||||
|
||||
The usage of this property should align with a classic "dark mode" state machine in your application
|
||||
where the user has three options.
|
||||
* `Follow OS` --> `themeSource = 'system'`
|
||||
* `Dark Mode` --> `themeSource = 'dark'`
|
||||
* `Light Mode` --> `themeSource = 'light'`
|
||||
|
||||
Your application should then always use `shouldUseDarkColors` to determine what CSS to apply.
|
||||
|
||||
### `nativeTheme.shouldUseHighContrastColors` _macOS_ _Windows_ _Readonly_
|
||||
|
||||
A `Boolean` for if the OS / Chromium currently has high-contrast mode enabled
|
||||
or is being instructed to show a high-constrast UI.
|
||||
|
||||
### `nativeTheme.shouldUseInvertedColorScheme` _macOS_ _Windows_ _Readonly_
|
||||
|
||||
A `Boolean` for if the OS / Chromium currently has an inverted color scheme
|
||||
or is being instructed to use an inverted color scheme.
|
||||
@@ -54,7 +54,7 @@ The `net` module has the following methods:
|
||||
|
||||
### `net.request(options)`
|
||||
|
||||
* `options` (Object | String) - The `ClientRequest` constructor options.
|
||||
* `options` (ClientRequestConstructorOptions | String) - The `ClientRequest` constructor options.
|
||||
|
||||
Returns [`ClientRequest`](./client-request.md)
|
||||
|
||||
|
||||
@@ -217,11 +217,15 @@ that all statistics are reported in Kilobytes.
|
||||
|
||||
Returns `String` - The version of the host operating system.
|
||||
|
||||
Examples:
|
||||
Example:
|
||||
|
||||
* `macOS` -> `10.13.6`
|
||||
* `Windows` -> `10.0.17763`
|
||||
* `Linux` -> `4.15.0-45-generic`
|
||||
```js
|
||||
const version = process.getSystemVersion()
|
||||
console.log(version)
|
||||
// On macOS -> '10.13.6'
|
||||
// On Windows -> '10.0.17763'
|
||||
// On Linux -> '4.15.0-45-generic'
|
||||
```
|
||||
|
||||
**Note:** It returns the actual operating system version instead of kernel version on macOS unlike `os.release()`.
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ should be called with either a `String` or an object that has the `data`,
|
||||
* `redirectRequest` Object
|
||||
* `url` String
|
||||
* `method` String (optional)
|
||||
* `session` Object (optional)
|
||||
* `session` Session | null (optional)
|
||||
* `uploadData` [ProtocolResponseUploadData](structures/protocol-response-upload-data.md) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
@@ -388,10 +388,8 @@ which sends a `Buffer` as a response.
|
||||
* `redirectRequest` Object
|
||||
* `url` String
|
||||
* `method` String (optional)
|
||||
* `session` Object | null (optional)
|
||||
* `uploadData` Object (optional)
|
||||
* `contentType` String - MIME type of the content.
|
||||
* `data` String - Content to be sent.
|
||||
* `session` Session | null (optional)
|
||||
* `uploadData` [ProtocolResponseUploadData](structures/protocol-response-upload-data.md) (optional)
|
||||
* `completion` Function (optional)
|
||||
* `error` Error
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ property, so writing `let { screen } = require('electron')` will not work.
|
||||
|
||||
An example of creating a window that fills the whole screen:
|
||||
|
||||
```javascript
|
||||
```javascript fiddle='docs/fiddles/screen/fit-screen'
|
||||
const { app, BrowserWindow, screen } = require('electron')
|
||||
|
||||
let win
|
||||
|
||||
@@ -91,6 +91,20 @@ session.defaultSession.on('will-download', (event, item, webContents) => {
|
||||
})
|
||||
```
|
||||
|
||||
#### Event: 'preconnect' _Experimental_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `preconnectUrl` String - The URL being requested for preconnection by the
|
||||
renderer.
|
||||
* `allowCredentials` Boolean - True if the renderer is requesting that the
|
||||
connection include credentials (see the
|
||||
[spec](https://w3c.github.io/resource-hints/#preconnect) for more details.)
|
||||
|
||||
Emitted when a render process requests preconnection to a URL, generally due to
|
||||
a [resource hint](https://w3c.github.io/resource-hints/).
|
||||
|
||||
### Instance Methods
|
||||
|
||||
The following methods are available on instances of `Session`:
|
||||
@@ -238,6 +252,14 @@ window.webContents.session.enableNetworkEmulation({
|
||||
window.webContents.session.enableNetworkEmulation({ offline: true })
|
||||
```
|
||||
|
||||
#### `ses.preconnect(options)` _Experimental_
|
||||
|
||||
* `options` Object
|
||||
* `url` String - URL for preconnect. Only the origin is relevant for opening the socket.
|
||||
* `numSockets` Number (optional) - number of sockets to preconnect. Must be between 1 and 6. Defaults to 1.
|
||||
|
||||
Preconnects the given number of sockets to an origin.
|
||||
|
||||
#### `ses.disableNetworkEmulation()`
|
||||
|
||||
Disables any network emulation already active for the `session`. Resets to
|
||||
|
||||
4
docs/api/structures/extension-info.md
Normal file
4
docs/api/structures/extension-info.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# ExtensionInfo Object
|
||||
|
||||
* `name` String
|
||||
* `version` String
|
||||
@@ -1,4 +1,4 @@
|
||||
# ProtocolResponseUploadData Object
|
||||
|
||||
* `contentType` String - MIME type of the content.
|
||||
* `data` String - Content to be sent.
|
||||
* `data` String | Buffer - Content to be sent.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
include in the trace. If not specified, trace all processes.
|
||||
* `histogram_names` String[] (optional) - a list of [histogram][] names to report
|
||||
with the trace.
|
||||
* `memory_dump_config` Object (optional) - if the
|
||||
* `memory_dump_config` Record<String, any> (optional) - if the
|
||||
`disabled-by-default-memory-infra` category is enabled, this contains
|
||||
optional additional configuration for data collection. See the [Chromium
|
||||
memory-infra docs][memory-infra docs] for more information.
|
||||
|
||||
@@ -27,28 +27,34 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
### Event: 'inverted-color-scheme-changed' _Windows_
|
||||
### Event: 'inverted-color-scheme-changed' _Windows_ _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `invertedColorScheme` Boolean - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is being used, `false` otherwise.
|
||||
|
||||
### Event: 'high-contrast-color-scheme-changed' _Windows_
|
||||
**Deprecated:** Should use the new [`updated`](native-theme.md#event-updated) event on the `nativeTheme` module.
|
||||
|
||||
### Event: 'high-contrast-color-scheme-changed' _Windows_ _Deprecated_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `highContrastColorScheme` Boolean - `true` if a high contrast theme is being used, `false` otherwise.
|
||||
|
||||
**Deprecated:** Should use the new [`updated`](native-theme.md#event-updated) event on the `nativeTheme` module.
|
||||
|
||||
## Methods
|
||||
|
||||
### `systemPreferences.isDarkMode()` _macOS_ _Windows_
|
||||
### `systemPreferences.isDarkMode()` _macOS_ _Windows_ _Deprecated_
|
||||
|
||||
Returns `Boolean` - Whether the system is in Dark Mode.
|
||||
|
||||
**Note:** On macOS 10.15 Catalina in order for this API to return the correct value when in the "automatic" dark mode setting you must either have `NSRequiresAquaSystemAppearance=false` in your `Info.plist` or be on Electron `>=7.0.0`. See the [dark mode guide](../tutorial/mojave-dark-mode-guide.md) for more information.
|
||||
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseDarkColors`](native-theme.md#nativethemeshouldusedarkcolors-readonly) API.
|
||||
|
||||
### `systemPreferences.isSwipeTrackingFromScrollEventsEnabled()` _macOS_
|
||||
|
||||
Returns `Boolean` - Whether the Swipe between pages setting is on.
|
||||
@@ -56,7 +62,7 @@ Returns `Boolean` - Whether the Swipe between pages setting is on.
|
||||
### `systemPreferences.postNotification(event, userInfo[, deliverImmediately])` _macOS_
|
||||
|
||||
* `event` String
|
||||
* `userInfo` Object
|
||||
* `userInfo` Record<String, any>
|
||||
* `deliverImmediately` Boolean (optional) - `true` to post notifications immediately even when the subscribing app is inactive.
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
@@ -65,7 +71,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
### `systemPreferences.postLocalNotification(event, userInfo)` _macOS_
|
||||
|
||||
* `event` String
|
||||
* `userInfo` Object
|
||||
* `userInfo` Record<String, any>
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
that contains the user information dictionary sent along with the notification.
|
||||
@@ -73,7 +79,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
### `systemPreferences.postWorkspaceNotification(event, userInfo)` _macOS_
|
||||
|
||||
* `event` String
|
||||
* `userInfo` Object
|
||||
* `userInfo` Record<String, any>
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
that contains the user information dictionary sent along with the notification.
|
||||
@@ -83,7 +89,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
* `event` String
|
||||
* `callback` Function
|
||||
* `event` String
|
||||
* `userInfo` Object
|
||||
* `userInfo` Record<String, unknown>
|
||||
* `object` String
|
||||
|
||||
Returns `Number` - The ID of this subscription
|
||||
@@ -110,7 +116,7 @@ example values of `event` are:
|
||||
* `event` String
|
||||
* `callback` Function
|
||||
* `event` String
|
||||
* `userInfo` Object
|
||||
* `userInfo` Record<String, unknown>
|
||||
* `object` String
|
||||
|
||||
Returns `Number` - The ID of this subscription
|
||||
@@ -123,7 +129,7 @@ This is necessary for events such as `NSUserDefaultsDidChangeNotification`.
|
||||
* `event` String
|
||||
* `callback` Function
|
||||
* `event` String
|
||||
* `userInfo` Object
|
||||
* `userInfo` Record<String, unknown>
|
||||
* `object` String
|
||||
|
||||
Same as `subscribeNotification`, but uses `NSWorkspace.sharedWorkspace.notificationCenter`.
|
||||
@@ -149,7 +155,7 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSWorkspace.
|
||||
|
||||
### `systemPreferences.registerDefaults(defaults)` _macOS_
|
||||
|
||||
* `defaults` Object - a dictionary of (`key: value`) user defaults
|
||||
* `defaults` Record<String, String | Boolean | Number> - a dictionary of (`key: value`) user defaults
|
||||
|
||||
Add the specified defaults to your application's `NSUserDefaults`.
|
||||
|
||||
@@ -342,14 +348,18 @@ Returns `String` - The standard system color formatted as `#RRGGBBAA`.
|
||||
|
||||
Returns one of several standard system colors that automatically adapt to vibrancy and changes in accessibility settings like 'Increase contrast' and 'Reduce transparency'. See [Apple Documentation](https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#system-colors) for more details.
|
||||
|
||||
### `systemPreferences.isInvertedColorScheme()` _Windows_
|
||||
### `systemPreferences.isInvertedColorScheme()` _Windows_ _Deprecated_
|
||||
|
||||
Returns `Boolean` - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is active, `false` otherwise.
|
||||
|
||||
### `systemPreferences.isHighContrastColorScheme()` _macOS_ _Windows_
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseInvertedColorScheme`](native-theme.md#nativethemeshoulduseinvertedcolorscheme-macos-windows-readonly) API.
|
||||
|
||||
### `systemPreferences.isHighContrastColorScheme()` _macOS_ _Windows_ _Deprecated_
|
||||
|
||||
Returns `Boolean` - `true` if a high contrast theme is active, `false` otherwise.
|
||||
|
||||
**Depreacted:** Should use the new [`nativeTheme.shouldUseHighContrastColors`](native-theme.md#nativethemeshouldusehighcontrastcolors-macos-windows-readonly) API.
|
||||
|
||||
### `systemPreferences.getEffectiveAppearance()` _macOS_
|
||||
|
||||
Returns `String` - Can be `dark`, `light` or `unknown`.
|
||||
@@ -365,7 +375,9 @@ using `electron-packager` or `electron-forge` just set the `enableDarwinDarkMode
|
||||
packager option to `true`. See the [Electron Packager API](https://github.com/electron/electron-packager/blob/master/docs/api.md#darwindarkmodesupport)
|
||||
for more details.
|
||||
|
||||
### `systemPreferences.getAppLevelAppearance()` _macOS_
|
||||
**[Deprecated](modernization/property-updates.md)**
|
||||
|
||||
### `systemPreferences.getAppLevelAppearance()` _macOS_ _Deprecated_
|
||||
|
||||
Returns `String` | `null` - Can be `dark`, `light` or `unknown`.
|
||||
|
||||
@@ -375,7 +387,7 @@ You can use the `setAppLevelAppearance` API to set this value.
|
||||
|
||||
**[Deprecated](modernization/property-updates.md)**
|
||||
|
||||
### `systemPreferences.setAppLevelAppearance(appearance)` _macOS_
|
||||
### `systemPreferences.setAppLevelAppearance(appearance)` _macOS_ _Deprecated_
|
||||
|
||||
* `appearance` String | null - Can be `dark` or `light`
|
||||
|
||||
@@ -450,10 +462,25 @@ Returns an object with system animation settings.
|
||||
|
||||
### `systemPreferences.appLevelAppearance` _macOS_
|
||||
|
||||
A `String` property that determines the macOS appearance setting for
|
||||
A `String` property that can be `dark`, `light` or `unknown`. It determines the macOS appearance setting for
|
||||
your application. This maps to values in: [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). Setting this will override the
|
||||
system default as well as the value of `getEffectiveAppearance`.
|
||||
|
||||
Possible values that can be set are `dark` and `light`, and possible return values are `dark`, `light`, and `unknown`.
|
||||
|
||||
This property is only available on macOS 10.14 Mojave or newer.
|
||||
|
||||
### `systemPreferences.effectiveAppearance` _macOS_ _Readonly_
|
||||
|
||||
A `String` property that can be `dark`, `light` or `unknown`.
|
||||
|
||||
Returns the macOS appearance setting that is currently applied to your application,
|
||||
maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc)
|
||||
|
||||
Please note that until Electron is built targeting the 10.14 SDK, your application's
|
||||
`effectiveAppearance` will default to 'light' and won't inherit the OS preference. In
|
||||
the interim in order for your application to inherit the OS preference you must set the
|
||||
`NSRequiresAquaSystemAppearance` key in your apps `Info.plist` to `false`. If you are
|
||||
using `electron-packager` or `electron-forge` just set the `enableDarwinDarkMode`
|
||||
packager option to `true`. See the [Electron Packager API](https://github.com/electron/electron-packager/blob/master/docs/api.md#darwindarkmodesupport)
|
||||
for more details.
|
||||
|
||||
@@ -143,7 +143,7 @@ Returns:
|
||||
* `frameName` String
|
||||
* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`,
|
||||
`new-window`, `save-to-disk` and `other`.
|
||||
* `options` Object - The options which will be used for creating the new
|
||||
* `options` BrowserWindowConstructorOptions - The options which will be used for creating the new
|
||||
[`BrowserWindow`](browser-window.md).
|
||||
* `additionalFeatures` String[] - The non-standard features (features not handled
|
||||
by Chromium or Electron) given to `window.open()`.
|
||||
@@ -454,10 +454,8 @@ The usage is the same with [the `select-client-certificate` event of
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `request` Object
|
||||
* `method` String
|
||||
* `authenticationResponseDetails` Object
|
||||
* `url` URL
|
||||
* `referrer` URL
|
||||
* `authInfo` Object
|
||||
* `isProxy` Boolean
|
||||
* `scheme` String
|
||||
@@ -465,8 +463,8 @@ Returns:
|
||||
* `port` Integer
|
||||
* `realm` String
|
||||
* `callback` Function
|
||||
* `username` String
|
||||
* `password` String
|
||||
* `username` String (optional)
|
||||
* `password` String (optional)
|
||||
|
||||
Emitted when `webContents` wants to do basic auth.
|
||||
|
||||
@@ -481,7 +479,7 @@ Returns:
|
||||
* `requestId` Integer
|
||||
* `activeMatchOrdinal` Integer - Position of the active match.
|
||||
* `matches` Integer - Number of Matches.
|
||||
* `selectionArea` Object - Coordinates of first match region.
|
||||
* `selectionArea` Rectangle - Coordinates of first match region.
|
||||
* `finalUpdate` Boolean
|
||||
|
||||
Emitted when a result is available for
|
||||
@@ -669,10 +667,10 @@ Emitted when the devtools window instructs the webContents to reload
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webPreferences` Object - The web preferences that will be used by the guest
|
||||
* `webPreferences` WebPreferences - The web preferences that will be used by the guest
|
||||
page. This object can be modified to adjust the preferences for the guest
|
||||
page.
|
||||
* `params` Object - The other `<webview>` parameters such as the `src` URL.
|
||||
* `params` Record<string, string> - The other `<webview>` parameters such as the `src` URL.
|
||||
This object can be modified to adjust the parameters of the guest page.
|
||||
|
||||
Emitted when a `<webview>`'s web contents is being attached to this web
|
||||
@@ -842,7 +840,7 @@ webContents.loadURL('https://github.com', options)
|
||||
|
||||
* `filePath` String
|
||||
* `options` Object (optional)
|
||||
* `query` Object (optional) - Passed to `url.format()`.
|
||||
* `query` Record<String, String> (optional) - Passed to `url.format()`.
|
||||
* `search` String (optional) - Passed to `url.format()`.
|
||||
* `hash` String (optional) - Passed to `url.format()`.
|
||||
|
||||
@@ -1238,7 +1236,7 @@ Captures a snapshot of the page within `rect`. Omitting `rect` will capture the
|
||||
|
||||
Get the system printer list.
|
||||
|
||||
Returns [`PrinterInfo[]`](structures/printer-info.md).
|
||||
Returns [`PrinterInfo[]`](structures/printer-info.md)
|
||||
|
||||
#### `contents.print([options], [callback])`
|
||||
|
||||
@@ -1269,11 +1267,7 @@ Returns [`PrinterInfo[]`](structures/printer-info.md).
|
||||
* `failureReason` String - Called back if the print fails; can be `cancelled` or `failed`.
|
||||
|
||||
Prints window's web page. When `silent` is set to `true`, Electron will pick
|
||||
the system's default printer if `deviceName` is empty and the default settings
|
||||
for printing.
|
||||
|
||||
Calling `window.print()` in web page is equivalent to calling
|
||||
`webContents.print({ silent: false, printBackground: false, deviceName: '' })`.
|
||||
the system's default printer if `deviceName` is empty and the default settings for printing.
|
||||
|
||||
Use `page-break-before: always;` CSS style to force to print to a new page.
|
||||
|
||||
@@ -1563,13 +1557,6 @@ Disable device emulation enabled by `webContents.enableDeviceEmulation`.
|
||||
#### `contents.sendInputEvent(inputEvent)`
|
||||
|
||||
* `inputEvent` [MouseInputEvent](structures/mouse-input-event.md) | [MouseWheelInputEvent](structures/mouse-wheel-input-event.md) | [KeyboardInputEvent](structures/keyboard-input-event.md)
|
||||
* `type` String (**required**) - The type of the event, can be `mouseDown`,
|
||||
`mouseUp`, `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel`,
|
||||
`mouseMove`, `keyDown`, `keyUp` or `char`.
|
||||
* `modifiers` String[] - An array of modifiers of the event, can
|
||||
include `shift`, `control`, `alt`, `meta`, `isKeypad`, `isAutoRepeat`,
|
||||
`leftButtonDown`, `middleButtonDown`, `rightButtonDown`, `capsLock`,
|
||||
`numLock`, `left`, `right`.
|
||||
|
||||
Sends an input `event` to the page.
|
||||
**Note:** The [`BrowserWindow`](browser-window.md) containing the contents needs to be focused for
|
||||
|
||||
@@ -99,16 +99,16 @@ Some examples of valid `urls`:
|
||||
* `timestamp` Double
|
||||
* `requestHeaders` Record<string, string>
|
||||
* `callback` Function
|
||||
* `response` Object
|
||||
* `beforeSendResponse` Object
|
||||
* `cancel` Boolean (optional)
|
||||
* `requestHeaders` Record<string, string> (optional) - When provided, request will be made
|
||||
* `requestHeaders` Record<string, string | string[]> (optional) - When provided, request will be made
|
||||
with these headers.
|
||||
|
||||
The `listener` will be called with `listener(details, callback)` before sending
|
||||
an HTTP request, once the request headers are available. This may occur after a
|
||||
TCP connection is made to the server, but before any http data is sent.
|
||||
|
||||
The `callback` has to be called with an `response` object.
|
||||
The `callback` has to be called with a `response` object.
|
||||
|
||||
#### `webRequest.onSendHeaders([filter, ]listener)`
|
||||
|
||||
@@ -148,9 +148,9 @@ response are visible by the time this listener is fired.
|
||||
* `statusCode` Integer
|
||||
* `responseHeaders` Record<string, string> (optional)
|
||||
* `callback` Function
|
||||
* `response` Object
|
||||
* `headersReceivedResponse` Object
|
||||
* `cancel` Boolean (optional)
|
||||
* `responseHeaders` Record<string, string> (optional) - When provided, the server is assumed
|
||||
* `responseHeaders` Record<string, string | string[]> (optional) - When provided, the server is assumed
|
||||
to have responded with these headers.
|
||||
* `statusLine` String (optional) - Should be provided when overriding
|
||||
`responseHeaders` to change header status otherwise original response
|
||||
@@ -159,7 +159,7 @@ response are visible by the time this listener is fired.
|
||||
The `listener` will be called with `listener(details, callback)` when HTTP
|
||||
response headers of a request have been received.
|
||||
|
||||
The `callback` has to be called with an `response` object.
|
||||
The `callback` has to be called with a `response` object.
|
||||
|
||||
#### `webRequest.onResponseStarted([filter, ]listener)`
|
||||
|
||||
@@ -201,6 +201,7 @@ and response headers are available.
|
||||
* `timestamp` Double
|
||||
* `redirectURL` String
|
||||
* `statusCode` Integer
|
||||
* `statusLine` String
|
||||
* `ip` String (optional) - The server IP address that the request was
|
||||
actually sent to.
|
||||
* `fromCache` Boolean
|
||||
|
||||
@@ -593,7 +593,7 @@ examples.
|
||||
|
||||
### `<webview>.sendInputEvent(event)`
|
||||
|
||||
* `event` Object
|
||||
* `event` [MouseInputEvent](structures/mouse-input-event.md) | [MouseWheelInputEvent](structures/mouse-wheel-input-event.md) | [KeyboardInputEvent](structures/keyboard-input-event.md)
|
||||
|
||||
Returns `Promise<void>`
|
||||
|
||||
@@ -767,7 +767,7 @@ Returns:
|
||||
* `requestId` Integer
|
||||
* `activeMatchOrdinal` Integer - Position of the active match.
|
||||
* `matches` Integer - Number of Matches.
|
||||
* `selectionArea` Object - Coordinates of first match region.
|
||||
* `selectionArea` Rectangle - Coordinates of first match region.
|
||||
* `finalUpdate` Boolean
|
||||
|
||||
Fired when a result is available for
|
||||
@@ -791,7 +791,7 @@ Returns:
|
||||
* `frameName` String
|
||||
* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`,
|
||||
`new-window`, `save-to-disk` and `other`.
|
||||
* `options` Object - The options which should be used for creating the new
|
||||
* `options` BrowserWindowConstructorOptions - The options which should be used for creating the new
|
||||
[`BrowserWindow`](browser-window.md).
|
||||
|
||||
Fired when the guest page attempts to open a new browser window.
|
||||
@@ -872,7 +872,7 @@ webview.addEventListener('close', () => {
|
||||
Returns:
|
||||
|
||||
* `channel` String
|
||||
* `args` Array
|
||||
* `args` any[]
|
||||
|
||||
Fired when the guest page has sent an asynchronous message to embedder page.
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ You can avoid much of the wait by reusing Electron CI's build output via
|
||||
optional steps (listed below) and these two environment variables:
|
||||
|
||||
```sh
|
||||
export SCCACHE_BUCKET="electronjs-sccache"
|
||||
export SCCACHE_BUCKET="electronjs-sccache-ci"
|
||||
export SCCACHE_TWO_TIER=true
|
||||
```
|
||||
|
||||
|
||||
20
docs/fiddles/screen/fit-screen/main.js
Normal file
20
docs/fiddles/screen/fit-screen/main.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// Retrieve information about screen size, displays, cursor position, etc.
|
||||
//
|
||||
// For more info, see:
|
||||
// https://electronjs.org/docs/api/screen
|
||||
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let mainWindow = null
|
||||
|
||||
app.on('ready', () => {
|
||||
// We cannot require the screen module until the app is ready.
|
||||
const { screen } = require('electron')
|
||||
|
||||
// Create a window that fills the screen's available work area.
|
||||
const primaryDisplay = screen.getPrimaryDisplay()
|
||||
const { width, height } = primaryDisplay.workAreaSize
|
||||
|
||||
mainWindow = new BrowserWindow({ width, height })
|
||||
mainWindow.loadURL('https://electronjs.org')
|
||||
})
|
||||
BIN
docs/images/performance-cpu-prof.png
Normal file
BIN
docs/images/performance-cpu-prof.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 868 KiB |
BIN
docs/images/performance-heap-prof.png
Normal file
BIN
docs/images/performance-heap-prof.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -38,11 +38,15 @@ npm install --platform=win32 electron
|
||||
|
||||
## Proxies
|
||||
|
||||
If you need to use an HTTP proxy you can [set these environment variables][proxy-env].
|
||||
If you need to use an HTTP proxy, you need to set the `ELECTRON_GET_USE_PROXY` variable to any
|
||||
value, plus additional environment variables depending on your host system's Node version:
|
||||
|
||||
* [Node 10 and above][proxy-env-10]
|
||||
* [Before Node 10][proxy-env]
|
||||
|
||||
## Custom Mirrors and Caches
|
||||
During installation, the `electron` module will call out to
|
||||
[`electron-download`][electron-download] to download prebuilt binaries of
|
||||
[`@electron/get`][electron-get] to download prebuilt binaries of
|
||||
Electron for your platform. It will do so by contacting GitHub's
|
||||
release download page (`https://github.com/electron/electron/releases/tag/v$VERSION`,
|
||||
where `$VERSION` is the exact version of Electron).
|
||||
@@ -146,7 +150,8 @@ If you need to force a re-download of the asset and the SHASUM file set the
|
||||
[npm]: https://docs.npmjs.com
|
||||
[versioning]: ./electron-versioning.md
|
||||
[releases]: https://github.com/electron/electron/releases
|
||||
[proxy-env]: https://github.com/request/request/tree/f0c4ec061141051988d1216c24936ad2e7d5c45d#controlling-proxy-behaviour-using-environment-variables
|
||||
[electron-download]: https://github.com/electron-userland/electron-download
|
||||
[proxy-env-10]: https://github.com/gajus/global-agent/blob/v2.1.5/README.md#environment-variables
|
||||
[proxy-env]: https://github.com/np-maintain/global-tunnel/blob/v2.7.1/README.md#auto-config
|
||||
[electron-get]: https://github.com/electron/get
|
||||
[npm-permissions]: https://docs.npmjs.com/getting-started/fixing-npm-permissions
|
||||
[unsafe-perm]: https://docs.npmjs.com/misc/config#unsafe-perm
|
||||
|
||||
431
docs/tutorial/performance.md
Normal file
431
docs/tutorial/performance.md
Normal file
@@ -0,0 +1,431 @@
|
||||
# Performance
|
||||
|
||||
Developers frequently ask about strategies to optimize the performance of
|
||||
Electron applications. Software engineers, consumers, and framework developers
|
||||
do not always agree on one single definition of what "performance" means. This
|
||||
document outlines some of the Electron maintainers' favorite ways to reduce the
|
||||
amount of memory, CPU, and disk resources being used while ensuring that your
|
||||
app is responsive to user input and completes operations as quickly as
|
||||
possible. Furthermore, we want all performance strategies to maintain a high
|
||||
standard for your app's security.
|
||||
|
||||
Wisdom and information about how to build performant websites with JavaScript
|
||||
generally applies to Electron apps, too. To a certain extent, resources
|
||||
discussing how to build performant Node.js applications also apply, but be
|
||||
careful to understand that the term "performance" means different things for
|
||||
a Node.js backend than it does for an application running on a client.
|
||||
|
||||
This list is provided for your convenience – and is, much like our
|
||||
[security checklist][security] – not meant to exhaustive. It is probably possible
|
||||
to build a slow Electron app that follows all the steps outlined below. Electron
|
||||
is a powerful development platform that enables you, the developer, to do more
|
||||
or less whatever you want. All that freedom means that performance is largely
|
||||
your responsibility.
|
||||
|
||||
## Measure, Measure, Measure
|
||||
|
||||
The list below contains a number of steps that are fairly straightforward and
|
||||
easy to implement. However, building the most performant version of your app
|
||||
will require you to go beyond a number of steps. Instead, you will have to
|
||||
closely examine all the code running in your app by carefully profiling and
|
||||
measuring. Where are the bottlenecks? When the user clicks a button, what
|
||||
operations take up the brunt of the time? While the app is simply idling, which
|
||||
objects take up the most memory?
|
||||
|
||||
Time and time again, we have seen that the most successful strategy for building
|
||||
a performant Electron app is to profile the running code, find the most
|
||||
resource-hungry piece of it, and to optimize it. Repeating this seemingly
|
||||
laborious process over and over again will dramatically increase your app's
|
||||
performance. Experience from working with major apps like Visual Studio Code or
|
||||
Slack has shown that this practice is by far the most reliable strategy to
|
||||
improve performance.
|
||||
|
||||
To learn more about how to profile your app's code, familiarize yourself with
|
||||
the Chrome Developer Tools. For advanced analysis looking at multiple processes
|
||||
at once, consider the [Chrome Tracing] tool.
|
||||
|
||||
### Recommended Reading
|
||||
|
||||
* [Get Started With Analyzing Runtime Performance][chrome-devtools-tutorial]
|
||||
* [Talk: "Visual Studio Code - The First Second"][vscode-first-second]
|
||||
|
||||
## Checklist
|
||||
|
||||
Chances are that your app could be a little leaner, faster, and generally less
|
||||
resource-hungry if you attempt these steps.
|
||||
|
||||
1. [Carelessly including modules](#1-carelessly-including-modules)
|
||||
2. [Loading and running code too soon](#2-loading-and-running-code-too-soon)
|
||||
3. [Blocking the main process](#3-blocking-the-main-process)
|
||||
4. [Blocking the renderer process](#4-blocking-the-renderer-process)
|
||||
5. [Unnecessary polyfills](#5-unnecessary-polyfills)
|
||||
6. [Unnecessary or blocking network requests](#6-unnecessary-or-blocking-network-requests)
|
||||
7. [Bundle your code](#7-bundle-your-code)
|
||||
|
||||
## 1) Carelessly including modules
|
||||
|
||||
Before adding a Node.js module to your application, examine said module. How
|
||||
many dependencies does that module include? What kind of resources does
|
||||
it need to simply be called in a `require()` statement? You might find
|
||||
that the module with the most downloads on the NPM package registry or the most stars on GitHub
|
||||
is not in fact the leanest or smallest one available.
|
||||
|
||||
### Why?
|
||||
|
||||
The reasoning behind this recommendation is best illustrated with a real-world
|
||||
example. During the early days of Electron, reliable detection of network
|
||||
connectivity was a problem, resulting many apps to use a module that exposed a
|
||||
simple `isOnline()` method.
|
||||
|
||||
That module detected your network connectivity by attempting to reach out to a
|
||||
number of well-known endpoints. For the list of those endpoints, it depended on
|
||||
a different module, which also contained a list of well-known ports. This
|
||||
dependency itself relied on a module containing information about ports, which
|
||||
came in the form of a JSON file with more than 100,000 lines of content.
|
||||
Whenever the module was loaded (usually in a `require('module')` statement),
|
||||
it would load all its dependencies and eventually read and parse this JSON
|
||||
file. Parsing many thousands lines of JSON is a very expensive operation. On
|
||||
a slow machine it can take up whole seconds of time.
|
||||
|
||||
In many server contexts, startup time is virtually irrelevant. A Node.js server
|
||||
that requires information about all ports is likely actually "more performant"
|
||||
if it loads all required information into memory whenever the server boots at
|
||||
the benefit of serving requests faster. The module discussed in this example is
|
||||
not a "bad" module. Electron apps, however, should not be loading, parsing, and
|
||||
storing in memory information that it does not actually need.
|
||||
|
||||
In short, a seemingly excellent module written primarily for Node.js servers
|
||||
running Linux might be bad news for your app's performance. In this particular
|
||||
example, the correct solution was to use no module at all, and to instead use
|
||||
connectivity checks included in later versions of Chromium.
|
||||
|
||||
### How?
|
||||
|
||||
When considering a module, we recommend that you check:
|
||||
|
||||
1. the size of dependencies included
|
||||
2) the resources required to load (`require()`) it
|
||||
3. the resources required to perform the action you're interested in
|
||||
|
||||
Generating a CPU profile and a heap memory profile for loading a module can be done
|
||||
with a single command on the command line. In the example below, we're looking at
|
||||
the popular module `request`.
|
||||
|
||||
```sh
|
||||
node --cpu-prof --heap-prof -e "require('request')"
|
||||
```
|
||||
|
||||
Executing this command results in a `.cpuprofile` file and a `.heapprofile`
|
||||
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-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
|
||||
and less than 50ms.
|
||||
|
||||
## 2) Loading and running code too soon
|
||||
|
||||
If you have expensive setup operations, consider deferring those. Inspect all
|
||||
the work being executed right after the application starts. Instead of firing
|
||||
off all operations right away, consider staggering them in a sequence more
|
||||
closely aligned with the user's journey.
|
||||
|
||||
In traditional Node.js development, we're used to putting all our `require()`
|
||||
statements at the top. If you're currently writing your Electron application
|
||||
using the same strategy _and_ are using sizable modules that you do not
|
||||
immediately need, apply the same strategy and defer loading to a more
|
||||
opportune time.
|
||||
|
||||
### Why?
|
||||
|
||||
Loading modules is a surprisingly expensive operation, especially on Windows.
|
||||
When your app starts, it should not make users wait for operations that are
|
||||
currently not necessary.
|
||||
|
||||
This might seem obvious, but many applications tend to do a large amount of
|
||||
work immediately after the app has launched - like checking for updates,
|
||||
downloading content used in a later flow, or performing heavy disk I/O
|
||||
operations.
|
||||
|
||||
Let's consider Visual Studio Code as an example. When you open a file, it will
|
||||
immediately display the file to you without any code highlighting, prioritizing
|
||||
your ability to interact with the text. Once it has done that work, it will
|
||||
move on to code highlighting.
|
||||
|
||||
### How?
|
||||
|
||||
Let's consider an example and assume that your application is parsing files
|
||||
in the fictitious `.foo` format. In order to do that, it relies on the
|
||||
equally fictitious `foo-parser` module. In traditional Node.js development,
|
||||
you might write code that eagerly loads dependencies:
|
||||
|
||||
```js
|
||||
const fs = require('fs')
|
||||
const fooParser = require('foo-parser')
|
||||
|
||||
class Parser {
|
||||
constructor () {
|
||||
this.files = fs.readdirSync('.')
|
||||
}
|
||||
|
||||
getParsedFiles () {
|
||||
return fooParser.parse(this.files)
|
||||
}
|
||||
}
|
||||
|
||||
const parser = new Parser()
|
||||
|
||||
module.exports = { parser }
|
||||
```
|
||||
|
||||
In the above example, we're doing a lot of work that's being executed as soon
|
||||
as the file is loaded. Do we need to get parsed files right away? Could we
|
||||
do this work a little later, when `getParsedFiles()` is actually called?
|
||||
|
||||
```js
|
||||
// "fs" is likely already being loaded, so the `require()` call is cheap
|
||||
const fs = require('fs')
|
||||
|
||||
class Parser {
|
||||
async getFiles () {
|
||||
// Touch the disk as soon as `getFiles` is called, not sooner.
|
||||
// Also, ensure that we're not blocking other operations by using
|
||||
// the asynchronous version.
|
||||
this.files = this.files || await fs.readdir('.')
|
||||
|
||||
return this.files
|
||||
}
|
||||
|
||||
async getParsedFiles () {
|
||||
// Our fictitious foo-parser is a big and expensive module to load, so
|
||||
// defer that work until we actually need to parse files.
|
||||
// Since `require()` comes with a module cache, the `require()` call
|
||||
// will only be expensive once - subsequent calls of `getParsedFiles()`
|
||||
// will be faster.
|
||||
const fooParser = require('foo-parser')
|
||||
const files = await this.getFiles()
|
||||
|
||||
return fooParser.parse(files)
|
||||
}
|
||||
}
|
||||
|
||||
// This operation is now a lot cheaper than in our previous example
|
||||
const parser = new Parser()
|
||||
|
||||
module.exports = { parser }
|
||||
```
|
||||
|
||||
In short, allocate resources "just in time" rather than allocating them all
|
||||
when your app starts.
|
||||
|
||||
## 3) Blocking the main process
|
||||
|
||||
Electron's main process (sometimes called "browser process") is special: It is
|
||||
the parent process to all your app's other processes and the primary process
|
||||
the operating system interacts with. It handles windows, interactions, and the
|
||||
communication between various components inside your app. It also houses the
|
||||
UI thread.
|
||||
|
||||
Under no circumstances should you block this process and the UI thread with
|
||||
long-running operations. Blocking the UI thread means that your entire app
|
||||
will freeze until the main process is ready to continue processing.
|
||||
|
||||
### Why?
|
||||
|
||||
The main process and its UI thread are essentially the control tower for major
|
||||
operations inside your app. When the operating system tells your app about a
|
||||
mouse click, it'll go through the main process before it reaches your window.
|
||||
If your window is rendering a buttery-smooth animation, it'll need to talk to
|
||||
the GPU process about that – once again going through the main process.
|
||||
|
||||
Electron and Chromium are careful to put heavy disk I/O and CPU-bound operations
|
||||
onto new threads to avoid blocking the UI thread. You should do the same.
|
||||
|
||||
### How?
|
||||
|
||||
Electron's powerful multi-process architecture stands ready to assist you with
|
||||
your long-running tasks, but also includes a small number of performance traps.
|
||||
|
||||
1) For long running CPU-heavy tasks, make use of
|
||||
[worker threads][worker-threads], consider moving them to the BrowserWindow, or
|
||||
(as a last resort) spawn a dedicated process.
|
||||
|
||||
2) Avoid using the synchronous IPC and the `remote` module as much as possible.
|
||||
While there are legitimate use cases, it is far too easy to unknowingly block
|
||||
the UI thread using the `remote` module.
|
||||
|
||||
3) Avoid using blocking I/O operations in the main process. In short, whenever
|
||||
core Node.js modules (like `fs` or `child_process`) offer a synchronous or an
|
||||
asynchronous version, you should prefer the asynchronous and non-blocking
|
||||
variant.
|
||||
|
||||
|
||||
## 4) Blocking the renderer process
|
||||
|
||||
Since Electron ships with a current version of Chrome, you can make use of the
|
||||
latest and greatest features the Web Platform offers to defer or offload heavy
|
||||
operations in a way that keeps your app smooth and responsive.
|
||||
|
||||
### Why?
|
||||
|
||||
Your app probably has a lot of JavaScript to run in the renderer process. The
|
||||
trick is to execute operations as quickly as possible without taking away
|
||||
resources needed to keep scrolling smooth, respond to user input, or animations
|
||||
at 60fps.
|
||||
|
||||
Orchestrating the flow of operations in your renderer's code is
|
||||
particularly useful if users complain about your app sometimes "stuttering".
|
||||
|
||||
### How?
|
||||
|
||||
Generally speaking, all advice for building performant web apps for modern
|
||||
browsers apply to Electron's renderers, too. The two primary tools at your
|
||||
disposal are currently `requestIdleCallback()` for small operations and
|
||||
`Web Workers` for long-running operations.
|
||||
|
||||
*`requestIdleCallback()`* allows developers to queue up a function to be
|
||||
executed as soon as the process is entering an idle period. It enables you to
|
||||
perform low-priority or background work without impacting the user experience.
|
||||
For more information about how to use it,
|
||||
[check out its documentation on MDN][request-idle-callback].
|
||||
|
||||
*Web Workers* are a powerful tool to run code on a separate thread. There are
|
||||
some caveats to consider – consult Electron's
|
||||
[multithreading documentation][multithreading] and the
|
||||
[MDN documentation for Web Workers][web-workers]. They're an ideal solution
|
||||
for any operation that requires a lot of CPU power for an extended period of
|
||||
time.
|
||||
|
||||
|
||||
## 5) Unnecessary polyfills
|
||||
|
||||
One of Electron's great benefits is that you know exactly which engine will
|
||||
parse your JavaScript, HTML, and CSS. If you're re-purposing code that was
|
||||
written for the web at large, make sure to not polyfill features included in
|
||||
Electron.
|
||||
|
||||
### Why?
|
||||
|
||||
When building a web application for today's Internet, the oldest environments
|
||||
dictate what features you can and cannot use. Even though Electron supports
|
||||
well-performing CSS filters and animations, an older browser might not. Where
|
||||
you could use WebGL, your developers may have chosen a more resource-hungry
|
||||
solution to support older phones.
|
||||
|
||||
When it comes to JavaScript, you may have included toolkit libraries like
|
||||
jQuery for DOM selectors or polyfills like the `regenerator-runtime` to support
|
||||
`async/await`.
|
||||
|
||||
It is rare for a JavaScript-based polyfill to be faster than the equivalent
|
||||
native feature in Electron. Do not slow down your Electron app by shipping your
|
||||
own version of standard web platform features.
|
||||
|
||||
### How?
|
||||
|
||||
Operate under the assumption that polyfills in current versions of Electron
|
||||
are unnecessary. If you have doubts, check [caniuse.com][https://caniuse.com/]
|
||||
and check if the [version of Chromium used in your Electron version](../api/process.md#processversionschrome-readonly)
|
||||
supports the feature you desire.
|
||||
|
||||
In addition, carefully examine the libraries you use. Are they really necessary?
|
||||
`jQuery`, for example, was such a success that many of its features are now part
|
||||
of the [standard JavaScript feature set available][jquery-need].
|
||||
|
||||
If you're using a transpiler/compiler like TypeScript, examine its configuration
|
||||
and ensure that you're targeting the latest ECMAScript version supported by
|
||||
Electron.
|
||||
|
||||
|
||||
## 6) Unnecessary or blocking network requests
|
||||
|
||||
Avoid fetching rarely changing resources from the internet if they could easily
|
||||
be bundled with your application.
|
||||
|
||||
### Why?
|
||||
|
||||
Many users of Electron start with an entirely web-based app that they're
|
||||
turning into a desktop application. As web developers, we are used to loading
|
||||
resources from a variety of content delivery networks. Now that you are
|
||||
shipping a proper desktop application, attempt to "cut the cord" where possible
|
||||
- and avoid letting your users wait for resources that never change and could
|
||||
easily be included in your app.
|
||||
|
||||
A typical example is Google Fonts. Many developers make use of Google's
|
||||
impressive collection of free fonts, which comes with a content delivery
|
||||
network. The pitch is straightforward: Include a few lines of CSS and Google
|
||||
will take care of the rest.
|
||||
|
||||
When building an Electron app, your users are better served if you download
|
||||
the fonts and include them in your app's bundle.
|
||||
|
||||
### How?
|
||||
|
||||
In an ideal world, your application wouldn't need the network to operate at
|
||||
all. To get there, you must understand what resources your app is downloading
|
||||
\- and how large those resources are.
|
||||
|
||||
To do so, open up the developer tools. Navigate to the `Network` tab and check
|
||||
the `Disable cache` option. Then, reload your renderer. Unless your app
|
||||
prohibits such reloads, you can usually trigger a reload by hitting `Cmd + R`
|
||||
or `Ctrl + R` with the developer tools in focus.
|
||||
|
||||
The tools will now meticulously record all network requests. In a first pass,
|
||||
take stock of all the resources being downloaded, focusing on the larger files
|
||||
first. Are any of them images, fonts, or media files that don't change and
|
||||
could be included with your bundle? If so, include them.
|
||||
|
||||
As a next step, enable `Network Throttling`. Find the drop-down that currently
|
||||
reads `Online` and select a slower speed such as `Fast 3G`. Reload your
|
||||
renderer and see if there are any resources that your app is unnecessarily
|
||||
waiting for. In many cases, an app will wait for a network request to complete
|
||||
despite not actually needing the involved resource.
|
||||
|
||||
As a tip, loading resources from the Internet that you might want to change
|
||||
without shipping an application update is a powerful strategy. For advanced
|
||||
control over how resources are being loaded, consider investing in
|
||||
[Service Workers][service-workers].
|
||||
|
||||
## 7) Bundle your code
|
||||
|
||||
As already pointed out in
|
||||
"[Loading and running code too soon](#2-loading-and-running-code-too-soon)",
|
||||
calling `require()` is an expensive operation. If you are able to do so,
|
||||
bundle your application's code into a single file.
|
||||
|
||||
### Why?
|
||||
|
||||
Modern JavaScript development usually involves many files and modules. While
|
||||
that's perfectly fine for developing with Electron, we heavily recommend that
|
||||
you bundle all your code into one single file to ensure that the overhead
|
||||
included in calling `require()` is only paid once when your application loads.
|
||||
|
||||
### How?
|
||||
|
||||
There are numerous JavaScript bundlers out there and we know better than to
|
||||
anger the community by recommending one tool over another. We do however
|
||||
recommend that you use a bundler that is able to handle Electron's unique
|
||||
environment that needs to handle both Node.js and browser environments.
|
||||
|
||||
As of writing this article, the popular choices include [Webpack][webpack],
|
||||
[Parcel][parcel], and [rollup.js][rollup].
|
||||
|
||||
[security]: ./security.md
|
||||
[performance-cpu-prof]: ../images/performance-cpu-prof.png
|
||||
[performance-heap-prof]: ../images/performance-heap-prof.png
|
||||
[chrome-devtools-tutorial]: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/
|
||||
[worker-threads]: https://nodejs.org/api/worker_threads.html
|
||||
[web-workers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
|
||||
[request-idle-callback]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
|
||||
[multithreading]: ./multithreading.md
|
||||
[caniuse]: https://caniuse.com/
|
||||
[jquery-need]: http://youmightnotneedjquery.com/
|
||||
[service-workers]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
|
||||
[webpack]: https://webpack.js.org/
|
||||
[parcel]: https://parceljs.org/
|
||||
[rollup]: https://rollupjs.org/
|
||||
[vscode-first-second]: https://www.youtube.com/watch?v=r0OeHRUCCb4
|
||||
@@ -27,18 +27,8 @@ see [SECURITY.md](https://github.com/electron/electron/tree/master/SECURITY.md)
|
||||
|
||||
## Chromium Security Issues and Upgrades
|
||||
|
||||
While Electron strives to support new versions of Chromium as soon as possible,
|
||||
developers should be aware that upgrading is a serious undertaking - involving
|
||||
hand-editing dozens or even hundreds of files. Given the resources and
|
||||
contributions available today, Electron will often not be on the very latest
|
||||
version of Chromium, lagging behind by several weeks or a few months.
|
||||
|
||||
We feel that our current system of updating the Chromium component strikes an
|
||||
appropriate balance between the resources we have available and the needs of
|
||||
the majority of applications built on top of the framework. We definitely are
|
||||
interested in hearing more about specific use cases from the people that build
|
||||
things on top of Electron. Pull requests and contributions supporting this
|
||||
effort are always very welcome.
|
||||
Electron keeps up to date with alternating Chromium releases. For more information,
|
||||
see the [Electron Release Cadence blog post](https://electronjs.org/blog/12-week-cadence).
|
||||
|
||||
## Security Is Everyone's Responsibility
|
||||
|
||||
|
||||
@@ -13,9 +13,60 @@
|
||||
|
||||
<!-- Desktop Capturer API -->
|
||||
<message name="IDS_DESKTOP_MEDIA_PICKER_SINGLE_SCREEN_NAME" desc="Name for screens in the desktop media picker UI when there is only one monitor.">
|
||||
Entire screen
|
||||
Entire Screen
|
||||
</message>
|
||||
<message name="IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME" desc="Name for screens in the desktop media picker UI when there are multiple monitors.">
|
||||
{SCREEN_INDEX, plural, =1{Screen #} other{Screen #}}
|
||||
</message>
|
||||
|
||||
<!-- Picture-in-Picture -->
|
||||
<if expr="is_macosx">
|
||||
<message name="IDS_PICTURE_IN_PICTURE_TITLE_TEXT" desc="Title of the Picture-in-Picture window. This appears in the system tray and window header.">
|
||||
Picture in Picture
|
||||
</message>
|
||||
</if>
|
||||
<if expr="not is_macosx">
|
||||
<message name="IDS_PICTURE_IN_PICTURE_TITLE_TEXT" desc="Title of the Picture-in-Picture window. This appears in the system tray and window header.">
|
||||
Picture in picture
|
||||
</message>
|
||||
</if>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_PAUSE_CONTROL_TEXT" desc="Text label of the pause control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently playing.">
|
||||
Pause
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_PLAY_CONTROL_TEXT" desc="Text label of the play control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently paused.">
|
||||
Play
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_REPLAY_CONTROL_TEXT" desc="Text label of the replay control button. The button appears when the user hovers over the Picture-in-Picture window and the video is ended.">
|
||||
Play from the beginning
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_BACK_TO_TAB_CONTROL_TEXT" desc="Text label of the back to tab control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Back to video player
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_TEXT" desc="Text label of the mute control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently unmuted.">
|
||||
Mute
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_UNMUTE_CONTROL_TEXT" desc="Text label of the mute control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently muted.">
|
||||
Unmute
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_SKIP_AD_CONTROL_TEXT" desc="Text label of the skip ad control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Skip Ad
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_CLOSE_CONTROL_TEXT" desc="Text label of the close control button. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Close
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_RESIZE_HANDLE_TEXT" desc="Text label of the resize handle. The button appears when the user hovers over the Picture-in-Picture window.">
|
||||
Resize
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles between play and pause controls.">
|
||||
Toggle video to play or pause
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles mute state.">
|
||||
Toggle mute
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes next track action.">
|
||||
Next track
|
||||
</message>
|
||||
<message name="IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes previous track action.">
|
||||
Previous track
|
||||
</message>
|
||||
</grit-part>
|
||||
|
||||
@@ -14,6 +14,7 @@ auto_filenames = {
|
||||
"docs/api/clipboard.md",
|
||||
"docs/api/command-line.md",
|
||||
"docs/api/content-tracing.md",
|
||||
"docs/api/context-bridge.md",
|
||||
"docs/api/cookies.md",
|
||||
"docs/api/crash-reporter.md",
|
||||
"docs/api/debugger.md",
|
||||
@@ -34,6 +35,7 @@ auto_filenames = {
|
||||
"docs/api/menu.md",
|
||||
"docs/api/modernization",
|
||||
"docs/api/native-image.md",
|
||||
"docs/api/native-theme.md",
|
||||
"docs/api/net-log.md",
|
||||
"docs/api/net.md",
|
||||
"docs/api/notification.md",
|
||||
@@ -76,6 +78,7 @@ auto_filenames = {
|
||||
"docs/api/structures/desktop-capturer-source.md",
|
||||
"docs/api/structures/display.md",
|
||||
"docs/api/structures/event.md",
|
||||
"docs/api/structures/extension-info.md",
|
||||
"docs/api/structures/file-filter.md",
|
||||
"docs/api/structures/file-path-with-headers.md",
|
||||
"docs/api/structures/gpu-feature-status.md",
|
||||
@@ -132,12 +135,14 @@ auto_filenames = {
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/buffer-utils.ts",
|
||||
"lib/common/clipboard-utils.ts",
|
||||
"lib/common/crash-reporter.js",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/error-utils.ts",
|
||||
"lib/common/is-promise.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.js",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/ipc-renderer.js",
|
||||
@@ -172,6 +177,7 @@ auto_filenames = {
|
||||
isolated_bundle_deps = [
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/error-utils.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/isolated_renderer/init.js",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
"lib/renderer/ipc-renderer-internal.ts",
|
||||
@@ -186,6 +192,7 @@ auto_filenames = {
|
||||
content_script_bundle_deps = [
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/error-utils.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/content_script/init.js",
|
||||
"lib/renderer/chrome-api.ts",
|
||||
"lib/renderer/extensions/event.ts",
|
||||
@@ -220,6 +227,7 @@ auto_filenames = {
|
||||
"lib/browser/api/menu-utils.js",
|
||||
"lib/browser/api/menu.js",
|
||||
"lib/browser/api/module-list.js",
|
||||
"lib/browser/api/native-theme.ts",
|
||||
"lib/browser/api/net-log.js",
|
||||
"lib/browser/api/net.js",
|
||||
"lib/browser/api/notification.js",
|
||||
@@ -228,7 +236,7 @@ auto_filenames = {
|
||||
"lib/browser/api/protocol.ts",
|
||||
"lib/browser/api/screen.ts",
|
||||
"lib/browser/api/session.js",
|
||||
"lib/browser/api/system-preferences.js",
|
||||
"lib/browser/api/system-preferences.ts",
|
||||
"lib/browser/api/top-level-window.js",
|
||||
"lib/browser/api/touch-bar.js",
|
||||
"lib/browser/api/tray.js",
|
||||
@@ -263,7 +271,6 @@ auto_filenames = {
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/buffer-utils.ts",
|
||||
"lib/common/clipboard-utils.ts",
|
||||
"lib/common/crash-reporter.js",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/error-utils.ts",
|
||||
@@ -271,7 +278,9 @@ auto_filenames = {
|
||||
"lib/common/is-promise.ts",
|
||||
"lib/common/parse-features-string.js",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
"lib/renderer/ipc-renderer-internal.ts",
|
||||
"package.json",
|
||||
@@ -288,14 +297,16 @@ auto_filenames = {
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/buffer-utils.ts",
|
||||
"lib/common/clipboard-utils.ts",
|
||||
"lib/common/crash-reporter.js",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/error-utils.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/is-promise.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.js",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/exports/electron.js",
|
||||
@@ -338,13 +349,15 @@ auto_filenames = {
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/buffer-utils.ts",
|
||||
"lib/common/clipboard-utils.ts",
|
||||
"lib/common/crash-reporter.js",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/error-utils.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/is-promise.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.js",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/exports/electron.js",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
filenames = {
|
||||
default_app_ts_sources = [
|
||||
"default_app/default_app.ts",
|
||||
"default_app/index.ts",
|
||||
"default_app/main.ts",
|
||||
"default_app/preload.ts",
|
||||
]
|
||||
@@ -47,6 +46,8 @@ filenames = {
|
||||
"shell/browser/api/atom_api_content_tracing.cc",
|
||||
"shell/browser/api/atom_api_cookies.cc",
|
||||
"shell/browser/api/atom_api_cookies.h",
|
||||
"shell/browser/api/atom_api_data_pipe_holder.cc",
|
||||
"shell/browser/api/atom_api_data_pipe_holder.h",
|
||||
"shell/browser/api/atom_api_debugger.cc",
|
||||
"shell/browser/api/atom_api_debugger.h",
|
||||
"shell/browser/api/atom_api_dialog.cc",
|
||||
@@ -63,6 +64,9 @@ filenames = {
|
||||
"shell/browser/api/atom_api_menu_mac.mm",
|
||||
"shell/browser/api/atom_api_menu_views.cc",
|
||||
"shell/browser/api/atom_api_menu_views.h",
|
||||
"shell/browser/api/atom_api_native_theme.cc",
|
||||
"shell/browser/api/atom_api_native_theme.h",
|
||||
"shell/browser/api/atom_api_native_theme_mac.mm",
|
||||
"shell/browser/api/atom_api_net.cc",
|
||||
"shell/browser/api/atom_api_net.h",
|
||||
"shell/browser/api/atom_api_net_log.cc",
|
||||
@@ -75,8 +79,6 @@ filenames = {
|
||||
"shell/browser/api/atom_api_power_monitor.h",
|
||||
"shell/browser/api/atom_api_power_save_blocker.cc",
|
||||
"shell/browser/api/atom_api_power_save_blocker.h",
|
||||
"shell/browser/api/atom_api_protocol.cc",
|
||||
"shell/browser/api/atom_api_protocol.h",
|
||||
"shell/browser/api/atom_api_protocol_ns.cc",
|
||||
"shell/browser/api/atom_api_protocol_ns.h",
|
||||
"shell/browser/api/atom_api_screen.cc",
|
||||
@@ -91,10 +93,8 @@ filenames = {
|
||||
"shell/browser/api/atom_api_top_level_window.h",
|
||||
"shell/browser/api/atom_api_tray.cc",
|
||||
"shell/browser/api/atom_api_tray.h",
|
||||
"shell/browser/api/atom_api_url_request.cc",
|
||||
"shell/browser/api/atom_api_url_request.h",
|
||||
"shell/browser/api/atom_api_url_request_ns.cc",
|
||||
"shell/browser/api/atom_api_url_request_ns.h",
|
||||
"shell/browser/api/atom_api_url_loader.cc",
|
||||
"shell/browser/api/atom_api_url_loader.h",
|
||||
"shell/browser/api/atom_api_view.cc",
|
||||
"shell/browser/api/atom_api_view.h",
|
||||
"shell/browser/api/atom_api_web_contents.cc",
|
||||
@@ -103,8 +103,6 @@ filenames = {
|
||||
"shell/browser/api/atom_api_web_contents_mac.mm",
|
||||
"shell/browser/api/atom_api_web_contents_view.cc",
|
||||
"shell/browser/api/atom_api_web_contents_view.h",
|
||||
"shell/browser/api/atom_api_web_request.cc",
|
||||
"shell/browser/api/atom_api_web_request.h",
|
||||
"shell/browser/api/atom_api_web_request_ns.cc",
|
||||
"shell/browser/api/atom_api_web_request_ns.h",
|
||||
"shell/browser/api/atom_api_web_view_manager.cc",
|
||||
@@ -116,8 +114,6 @@ filenames = {
|
||||
"shell/browser/api/event.h",
|
||||
"shell/browser/api/event_emitter.cc",
|
||||
"shell/browser/api/event_emitter.h",
|
||||
"shell/browser/api/stream_subscriber.cc",
|
||||
"shell/browser/api/stream_subscriber.h",
|
||||
"shell/browser/api/trackable_object.cc",
|
||||
"shell/browser/api/trackable_object.h",
|
||||
"shell/browser/api/frame_subscriber.cc",
|
||||
@@ -133,8 +129,6 @@ filenames = {
|
||||
"shell/browser/auto_updater.cc",
|
||||
"shell/browser/auto_updater.h",
|
||||
"shell/browser/auto_updater_mac.mm",
|
||||
"shell/browser/atom_blob_reader.cc",
|
||||
"shell/browser/atom_blob_reader.h",
|
||||
"shell/browser/atom_browser_client.cc",
|
||||
"shell/browser/atom_browser_client.h",
|
||||
"shell/browser/atom_browser_context.cc",
|
||||
@@ -176,8 +170,6 @@ filenames = {
|
||||
"shell/browser/common_web_contents_delegate.h",
|
||||
"shell/browser/cookie_change_notifier.cc",
|
||||
"shell/browser/cookie_change_notifier.h",
|
||||
"shell/browser/io_thread.cc",
|
||||
"shell/browser/io_thread.h",
|
||||
"shell/browser/javascript_environment.cc",
|
||||
"shell/browser/javascript_environment.h",
|
||||
"shell/browser/lib/bluetooth_chooser.cc",
|
||||
@@ -185,8 +177,6 @@ filenames = {
|
||||
"shell/browser/lib/power_observer.h",
|
||||
"shell/browser/lib/power_observer_linux.h",
|
||||
"shell/browser/lib/power_observer_linux.cc",
|
||||
"shell/browser/loader/layered_resource_handler.cc",
|
||||
"shell/browser/loader/layered_resource_handler.h",
|
||||
"shell/browser/login_handler.cc",
|
||||
"shell/browser/login_handler.h",
|
||||
"shell/browser/mac/atom_application.h",
|
||||
@@ -223,58 +213,26 @@ filenames = {
|
||||
"shell/browser/media/media_device_id_salt.h",
|
||||
"shell/browser/media/media_stream_devices_controller.cc",
|
||||
"shell/browser/media/media_stream_devices_controller.h",
|
||||
"shell/browser/net/about_protocol_handler.cc",
|
||||
"shell/browser/net/about_protocol_handler.h",
|
||||
"shell/browser/net/asar/asar_protocol_handler.cc",
|
||||
"shell/browser/net/asar/asar_protocol_handler.h",
|
||||
"shell/browser/net/asar/asar_url_loader.cc",
|
||||
"shell/browser/net/asar/asar_url_loader.h",
|
||||
"shell/browser/net/asar/url_request_asar_job.cc",
|
||||
"shell/browser/net/asar/url_request_asar_job.h",
|
||||
"shell/browser/net/atom_cert_verifier.cc",
|
||||
"shell/browser/net/atom_cert_verifier.h",
|
||||
"shell/browser/net/atom_network_delegate.cc",
|
||||
"shell/browser/net/atom_network_delegate.h",
|
||||
"shell/browser/net/atom_url_loader_factory.cc",
|
||||
"shell/browser/net/atom_url_loader_factory.h",
|
||||
"shell/browser/net/atom_url_request.cc",
|
||||
"shell/browser/net/atom_url_request.h",
|
||||
"shell/browser/net/atom_url_request_job_factory.cc",
|
||||
"shell/browser/net/atom_url_request_job_factory.h",
|
||||
"shell/browser/net/http_protocol_handler.cc",
|
||||
"shell/browser/net/http_protocol_handler.h",
|
||||
"shell/browser/net/cert_verifier_client.cc",
|
||||
"shell/browser/net/cert_verifier_client.h",
|
||||
"shell/browser/net/proxying_url_loader_factory.cc",
|
||||
"shell/browser/net/proxying_url_loader_factory.h",
|
||||
"shell/browser/net/js_asker.cc",
|
||||
"shell/browser/net/js_asker.h",
|
||||
"shell/browser/net/network_context_service_factory.cc",
|
||||
"shell/browser/net/network_context_service_factory.h",
|
||||
"shell/browser/net/network_context_service.cc",
|
||||
"shell/browser/net/network_context_service.h",
|
||||
"shell/browser/net/node_stream_loader.cc",
|
||||
"shell/browser/net/node_stream_loader.h",
|
||||
"shell/browser/net/require_ct_delegate.cc",
|
||||
"shell/browser/net/require_ct_delegate.h",
|
||||
"shell/browser/net/resolve_proxy_helper.cc",
|
||||
"shell/browser/net/resolve_proxy_helper.h",
|
||||
"shell/browser/net/system_network_context_manager.cc",
|
||||
"shell/browser/net/system_network_context_manager.h",
|
||||
"shell/browser/net/url_pipe_loader.cc",
|
||||
"shell/browser/net/url_pipe_loader.h",
|
||||
"shell/browser/net/url_request_about_job.cc",
|
||||
"shell/browser/net/url_request_about_job.h",
|
||||
"shell/browser/net/url_request_async_asar_job.cc",
|
||||
"shell/browser/net/url_request_async_asar_job.h",
|
||||
"shell/browser/net/url_request_string_job.cc",
|
||||
"shell/browser/net/url_request_string_job.h",
|
||||
"shell/browser/net/url_request_buffer_job.cc",
|
||||
"shell/browser/net/url_request_buffer_job.h",
|
||||
"shell/browser/net/url_request_context_getter.cc",
|
||||
"shell/browser/net/url_request_context_getter.h",
|
||||
"shell/browser/net/url_request_fetch_job.cc",
|
||||
"shell/browser/net/url_request_fetch_job.h",
|
||||
"shell/browser/net/url_request_stream_job.cc",
|
||||
"shell/browser/net/url_request_stream_job.h",
|
||||
"shell/browser/notifications/linux/libnotify_notification.cc",
|
||||
"shell/browser/notifications/linux/libnotify_notification.h",
|
||||
"shell/browser/notifications/linux/notification_presenter_linux.cc",
|
||||
@@ -316,6 +274,8 @@ filenames = {
|
||||
"shell/browser/relauncher_win.cc",
|
||||
"shell/browser/relauncher.cc",
|
||||
"shell/browser/relauncher.h",
|
||||
"shell/browser/renderer_host/electron_render_message_filter.cc",
|
||||
"shell/browser/renderer_host/electron_render_message_filter.h",
|
||||
"shell/browser/session_preferences.cc",
|
||||
"shell/browser/session_preferences.h",
|
||||
"shell/browser/special_storage_policy.cc",
|
||||
@@ -364,6 +324,8 @@ filenames = {
|
||||
"shell/browser/ui/file_dialog_gtk.cc",
|
||||
"shell/browser/ui/file_dialog_mac.mm",
|
||||
"shell/browser/ui/file_dialog_win.cc",
|
||||
"shell/browser/ui/util_gtk.cc",
|
||||
"shell/browser/ui/util_gtk.h",
|
||||
"shell/browser/ui/inspectable_web_contents.cc",
|
||||
"shell/browser/ui/inspectable_web_contents.h",
|
||||
"shell/browser/ui/inspectable_web_contents_delegate.h",
|
||||
@@ -391,6 +353,7 @@ filenames = {
|
||||
"shell/browser/ui/tray_icon_observer.h",
|
||||
"shell/browser/ui/tray_icon_win.cc",
|
||||
"shell/browser/ui/views/atom_views_delegate.cc",
|
||||
"shell/browser/ui/views/atom_views_delegate_win.cc",
|
||||
"shell/browser/ui/views/atom_views_delegate.h",
|
||||
"shell/browser/ui/views/autofill_popup_view.cc",
|
||||
"shell/browser/ui/views/autofill_popup_view.h",
|
||||
@@ -508,6 +471,11 @@ filenames = {
|
||||
"shell/common/crash_reporter/linux/crash_dump_handler.h",
|
||||
"shell/common/crash_reporter/win/crash_service_main.cc",
|
||||
"shell/common/crash_reporter/win/crash_service_main.h",
|
||||
"shell/common/gin_converters/callback_converter_gin_adapter.h",
|
||||
"shell/common/gin_converters/gurl_converter_gin_adapter.h",
|
||||
"shell/common/gin_converters/net_converter_gin_adapter.h",
|
||||
"shell/common/gin_converters/std_converter.h",
|
||||
"shell/common/gin_converters/value_converter_gin_adapter.h",
|
||||
"shell/common/gin_util.h",
|
||||
"shell/common/heap_snapshot.cc",
|
||||
"shell/common/heap_snapshot.h",
|
||||
@@ -569,6 +537,10 @@ filenames = {
|
||||
"shell/common/promise_util.cc",
|
||||
"shell/common/skia_util.h",
|
||||
"shell/common/skia_util.cc",
|
||||
"shell/renderer/api/context_bridge/render_frame_context_bridge_store.cc",
|
||||
"shell/renderer/api/context_bridge/render_frame_context_bridge_store.h",
|
||||
"shell/renderer/api/atom_api_context_bridge.cc",
|
||||
"shell/renderer/api/atom_api_context_bridge.h",
|
||||
"shell/renderer/api/atom_api_renderer_ipc.cc",
|
||||
"shell/renderer/api/atom_api_spell_check_client.cc",
|
||||
"shell/renderer/api/atom_api_spell_check_client.h",
|
||||
|
||||
@@ -105,9 +105,9 @@ if (process.platform === 'linux') {
|
||||
}
|
||||
|
||||
// Routes the events to webContents.
|
||||
const events = ['login', 'certificate-error', 'select-client-certificate']
|
||||
const events = ['certificate-error', 'select-client-certificate']
|
||||
for (const name of events) {
|
||||
app.on(name as 'login', (event, webContents, ...args: any[]) => {
|
||||
app.on(name as 'certificate-error', (event, webContents, ...args: any[]) => {
|
||||
webContents.emit(name, event, ...args)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ BrowserWindow.prototype._init = function () {
|
||||
|
||||
// Hide the auto-hide menu when webContents is focused.
|
||||
this.webContents.on('activate', () => {
|
||||
if (process.platform !== 'darwin' && this.isMenuBarAutoHide() && this.isMenuBarVisible()) {
|
||||
if (process.platform !== 'darwin' && this.autoHideMenuBar && this.isMenuBarVisible()) {
|
||||
this.setMenuBarVisibility(false)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -141,6 +141,7 @@ const messageBox = (sync, window, options) => {
|
||||
defaultId = -1,
|
||||
detail = '',
|
||||
icon = null,
|
||||
noLink = false,
|
||||
message = '',
|
||||
title = '',
|
||||
type = 'none'
|
||||
@@ -151,11 +152,15 @@ const messageBox = (sync, window, options) => {
|
||||
if (!Array.isArray(buttons)) throw new TypeError('Buttons must be an array')
|
||||
if (options.normalizeAccessKeys) buttons = buttons.map(normalizeAccessKey)
|
||||
if (typeof title !== 'string') throw new TypeError('Title must be a string')
|
||||
if (typeof noLink !== 'boolean') throw new TypeError('noLink must be a boolean')
|
||||
if (typeof message !== 'string') throw new TypeError('Message must be a string')
|
||||
if (typeof detail !== 'string') throw new TypeError('Detail must be a string')
|
||||
if (typeof checkboxLabel !== 'string') throw new TypeError('checkboxLabel must be a string')
|
||||
|
||||
checkboxChecked = !!checkboxChecked
|
||||
if (checkboxChecked && !checkboxLabel) {
|
||||
throw new Error('checkboxChecked requires that checkboxLabel also be passed')
|
||||
}
|
||||
|
||||
// Choose a default button to get selected when dialog is cancelled.
|
||||
if (cancelId == null) {
|
||||
@@ -170,15 +175,13 @@ const messageBox = (sync, window, options) => {
|
||||
}
|
||||
}
|
||||
|
||||
const flags = options.noLink ? messageBoxOptions.noLink : 0
|
||||
|
||||
const settings = {
|
||||
window,
|
||||
messageBoxType,
|
||||
buttons,
|
||||
defaultId,
|
||||
cancelId,
|
||||
flags,
|
||||
noLink,
|
||||
title,
|
||||
message,
|
||||
detail,
|
||||
|
||||
@@ -178,7 +178,7 @@ const roles = {
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideothers' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
@@ -209,8 +209,8 @@ const roles = {
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [
|
||||
{ role: 'startspeaking' },
|
||||
{ role: 'stopspeaking' }
|
||||
{ role: 'startSpeaking' },
|
||||
{ role: 'stopSpeaking' }
|
||||
]
|
||||
}
|
||||
] : [
|
||||
@@ -225,12 +225,12 @@ const roles = {
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ role: 'forcereload' },
|
||||
{ role: 'toggledevtools' },
|
||||
{ role: 'forceReload' },
|
||||
{ role: 'toggleDevTools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetzoom' },
|
||||
{ role: 'zoomin' },
|
||||
{ role: 'zoomout' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
|
||||
@@ -21,6 +21,7 @@ module.exports = [
|
||||
{ name: 'inAppPurchase' },
|
||||
{ name: 'Menu' },
|
||||
{ name: 'MenuItem' },
|
||||
{ name: 'nativeTheme' },
|
||||
{ name: 'net' },
|
||||
{ name: 'netLog' },
|
||||
{ name: 'Notification' },
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = [
|
||||
{ name: 'inAppPurchase', loader: () => require('./in-app-purchase') },
|
||||
{ name: 'Menu', loader: () => require('./menu') },
|
||||
{ name: 'MenuItem', loader: () => require('./menu-item') },
|
||||
{ name: 'nativeTheme', loader: () => require('./native-theme') },
|
||||
{ name: 'net', loader: () => require('./net') },
|
||||
{ name: 'netLog', loader: () => require('./net-log') },
|
||||
{ name: 'Notification', loader: () => require('./notification') },
|
||||
|
||||
8
lib/browser/api/native-theme.ts
Normal file
8
lib/browser/api/native-theme.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { EventEmitter } from 'events'
|
||||
|
||||
const { NativeTheme, nativeTheme } = process.electronBinding('native_theme')
|
||||
|
||||
Object.setPrototypeOf(NativeTheme.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(nativeTheme as any)
|
||||
|
||||
module.exports = nativeTheme
|
||||
@@ -2,17 +2,13 @@
|
||||
|
||||
const url = require('url')
|
||||
const { EventEmitter } = require('events')
|
||||
const { Readable } = require('stream')
|
||||
const { Readable, Writable } = require('stream')
|
||||
const { app } = require('electron')
|
||||
const { Session } = process.electronBinding('session')
|
||||
const { net, Net } = process.electronBinding('net')
|
||||
const { URLRequest } = net
|
||||
const { net, Net, _isValidHeaderName, _isValidHeaderValue } = process.electronBinding('net')
|
||||
const { URLLoader } = net
|
||||
|
||||
// Net is an EventEmitter.
|
||||
Object.setPrototypeOf(Net.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(net)
|
||||
|
||||
Object.setPrototypeOf(URLRequest.prototype, EventEmitter.prototype)
|
||||
Object.setPrototypeOf(URLLoader.prototype, EventEmitter.prototype)
|
||||
|
||||
const kSupportedProtocols = new Set(['http:', 'https:'])
|
||||
|
||||
@@ -40,32 +36,24 @@ const discardableDuplicateHeaders = new Set([
|
||||
])
|
||||
|
||||
class IncomingMessage extends Readable {
|
||||
constructor (urlRequest) {
|
||||
constructor (responseHead) {
|
||||
super()
|
||||
this.urlRequest = urlRequest
|
||||
this.shouldPush = false
|
||||
this.data = []
|
||||
this.urlRequest.on('data', (event, chunk) => {
|
||||
this._storeInternalData(chunk)
|
||||
this._pushInternalData()
|
||||
})
|
||||
this.urlRequest.on('end', () => {
|
||||
this._storeInternalData(null)
|
||||
this._pushInternalData()
|
||||
})
|
||||
this._shouldPush = false
|
||||
this._data = []
|
||||
this._responseHead = responseHead
|
||||
}
|
||||
|
||||
get statusCode () {
|
||||
return this.urlRequest.statusCode
|
||||
return this._responseHead.statusCode
|
||||
}
|
||||
|
||||
get statusMessage () {
|
||||
return this.urlRequest.statusMessage
|
||||
return this._responseHead.statusMessage
|
||||
}
|
||||
|
||||
get headers () {
|
||||
const filteredHeaders = {}
|
||||
const rawHeaders = this.urlRequest.rawResponseHeaders
|
||||
const rawHeaders = this._responseHead.headers
|
||||
Object.keys(rawHeaders).forEach(header => {
|
||||
if (header in filteredHeaders && discardableDuplicateHeaders.has(header)) {
|
||||
// do nothing with discardable duplicate headers
|
||||
@@ -88,11 +76,11 @@ class IncomingMessage extends Readable {
|
||||
}
|
||||
|
||||
get httpVersionMajor () {
|
||||
return this.urlRequest.httpVersionMajor
|
||||
return this._responseHead.httpVersion.major
|
||||
}
|
||||
|
||||
get httpVersionMinor () {
|
||||
return this.urlRequest.httpVersionMinor
|
||||
return this._responseHead.httpVersion.minor
|
||||
}
|
||||
|
||||
get rawTrailers () {
|
||||
@@ -104,181 +92,197 @@ class IncomingMessage extends Readable {
|
||||
}
|
||||
|
||||
_storeInternalData (chunk) {
|
||||
this.data.push(chunk)
|
||||
this._data.push(chunk)
|
||||
this._pushInternalData()
|
||||
}
|
||||
|
||||
_pushInternalData () {
|
||||
while (this.shouldPush && this.data.length > 0) {
|
||||
const chunk = this.data.shift()
|
||||
this.shouldPush = this.push(chunk)
|
||||
while (this._shouldPush && this._data.length > 0) {
|
||||
const chunk = this._data.shift()
|
||||
this._shouldPush = this.push(chunk)
|
||||
}
|
||||
}
|
||||
|
||||
_read () {
|
||||
this.shouldPush = true
|
||||
this._shouldPush = true
|
||||
this._pushInternalData()
|
||||
}
|
||||
}
|
||||
|
||||
URLRequest.prototype._emitRequestEvent = function (isAsync, ...rest) {
|
||||
if (isAsync) {
|
||||
process.nextTick(() => {
|
||||
this.clientRequest.emit(...rest)
|
||||
})
|
||||
} else {
|
||||
this.clientRequest.emit(...rest)
|
||||
}
|
||||
}
|
||||
|
||||
URLRequest.prototype._emitResponseEvent = function (isAsync, ...rest) {
|
||||
if (isAsync) {
|
||||
process.nextTick(() => {
|
||||
this._response.emit(...rest)
|
||||
})
|
||||
} else {
|
||||
this._response.emit(...rest)
|
||||
}
|
||||
}
|
||||
|
||||
class ClientRequest extends EventEmitter {
|
||||
constructor (options, callback) {
|
||||
/** Writable stream that buffers up everything written to it. */
|
||||
class SlurpStream extends Writable {
|
||||
constructor () {
|
||||
super()
|
||||
this._data = Buffer.alloc(0)
|
||||
}
|
||||
_write (chunk, encoding, callback) {
|
||||
this._data = Buffer.concat([this._data, chunk])
|
||||
callback()
|
||||
}
|
||||
data () { return this._data }
|
||||
}
|
||||
|
||||
class ChunkedBodyStream extends Writable {
|
||||
constructor (clientRequest) {
|
||||
super()
|
||||
this._clientRequest = clientRequest
|
||||
}
|
||||
|
||||
_write (chunk, encoding, callback) {
|
||||
if (this._downstream) {
|
||||
this._downstream.write(chunk).then(callback, callback)
|
||||
} else {
|
||||
// the contract of _write is that we won't be called again until we call
|
||||
// the callback, so we're good to just save a single chunk.
|
||||
this._pendingChunk = chunk
|
||||
this._pendingCallback = callback
|
||||
|
||||
// The first write to a chunked body stream begins the request.
|
||||
this._clientRequest._startRequest()
|
||||
}
|
||||
}
|
||||
|
||||
_final (callback) {
|
||||
this._downstream.done()
|
||||
callback()
|
||||
}
|
||||
|
||||
startReading (pipe) {
|
||||
if (this._downstream) {
|
||||
throw new Error('two startReading calls???')
|
||||
}
|
||||
this._downstream = pipe
|
||||
if (this._pendingChunk) {
|
||||
const doneWriting = (maybeError) => {
|
||||
const cb = this._pendingCallback
|
||||
delete this._pendingCallback
|
||||
delete this._pendingChunk
|
||||
cb(maybeError)
|
||||
}
|
||||
this._downstream.write(this._pendingChunk).then(doneWriting, doneWriting)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseOptions (options) {
|
||||
if (typeof options === 'string') {
|
||||
options = url.parse(options)
|
||||
} else {
|
||||
options = { ...options }
|
||||
}
|
||||
|
||||
const method = (options.method || 'GET').toUpperCase()
|
||||
let urlStr = options.url
|
||||
|
||||
if (!urlStr) {
|
||||
const urlObj = {}
|
||||
const protocol = options.protocol || 'http:'
|
||||
if (!kSupportedProtocols.has(protocol)) {
|
||||
throw new Error('Protocol "' + protocol + '" not supported')
|
||||
}
|
||||
urlObj.protocol = protocol
|
||||
|
||||
if (options.host) {
|
||||
urlObj.host = options.host
|
||||
} else {
|
||||
if (options.hostname) {
|
||||
urlObj.hostname = options.hostname
|
||||
} else {
|
||||
urlObj.hostname = 'localhost'
|
||||
}
|
||||
|
||||
if (options.port) {
|
||||
urlObj.port = options.port
|
||||
}
|
||||
}
|
||||
|
||||
if (options.path && / /.test(options.path)) {
|
||||
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
||||
// with an additional rule for ignoring percentage-escaped characters
|
||||
// but that's a) hard to capture in a regular expression that performs
|
||||
// well, and b) possibly too restrictive for real-world usage. That's
|
||||
// why it only scans for spaces because those are guaranteed to create
|
||||
// an invalid request.
|
||||
throw new TypeError('Request path contains unescaped characters')
|
||||
}
|
||||
const pathObj = url.parse(options.path || '/')
|
||||
urlObj.pathname = pathObj.pathname
|
||||
urlObj.search = pathObj.search
|
||||
urlObj.hash = pathObj.hash
|
||||
urlStr = url.format(urlObj)
|
||||
}
|
||||
|
||||
const redirectPolicy = options.redirect || 'follow'
|
||||
if (!['follow', 'error', 'manual'].includes(redirectPolicy)) {
|
||||
throw new Error('redirect mode should be one of follow, error or manual')
|
||||
}
|
||||
|
||||
if (options.headers != null && typeof options.headers !== 'object') {
|
||||
throw new TypeError('headers must be an object')
|
||||
}
|
||||
|
||||
const urlLoaderOptions = {
|
||||
method: method,
|
||||
url: urlStr,
|
||||
redirectPolicy,
|
||||
extraHeaders: options.headers || {}
|
||||
}
|
||||
for (const [name, value] of Object.entries(urlLoaderOptions.extraHeaders)) {
|
||||
if (!_isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`)
|
||||
}
|
||||
if (!_isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`)
|
||||
}
|
||||
}
|
||||
if (options.session) {
|
||||
if (options.session instanceof Session) {
|
||||
urlLoaderOptions.session = options.session
|
||||
} else {
|
||||
throw new TypeError('`session` should be an instance of the Session class')
|
||||
}
|
||||
} else if (options.partition) {
|
||||
if (typeof options.partition === 'string') {
|
||||
urlLoaderOptions.partition = options.partition
|
||||
} else {
|
||||
throw new TypeError('`partition` should be a string')
|
||||
}
|
||||
}
|
||||
return urlLoaderOptions
|
||||
}
|
||||
|
||||
class ClientRequest extends Writable {
|
||||
constructor (options, callback) {
|
||||
super({ autoDestroy: true })
|
||||
|
||||
if (!app.isReady()) {
|
||||
throw new Error('net module can only be used after app is ready')
|
||||
}
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = url.parse(options)
|
||||
} else {
|
||||
options = Object.assign({}, options)
|
||||
}
|
||||
|
||||
const method = (options.method || 'GET').toUpperCase()
|
||||
let urlStr = options.url
|
||||
|
||||
if (!urlStr) {
|
||||
const urlObj = {}
|
||||
const protocol = options.protocol || 'http:'
|
||||
if (!kSupportedProtocols.has(protocol)) {
|
||||
throw new Error('Protocol "' + protocol + '" not supported')
|
||||
}
|
||||
urlObj.protocol = protocol
|
||||
|
||||
if (options.host) {
|
||||
urlObj.host = options.host
|
||||
} else {
|
||||
if (options.hostname) {
|
||||
urlObj.hostname = options.hostname
|
||||
} else {
|
||||
urlObj.hostname = 'localhost'
|
||||
}
|
||||
|
||||
if (options.port) {
|
||||
urlObj.port = options.port
|
||||
}
|
||||
}
|
||||
|
||||
if (options.path && / /.test(options.path)) {
|
||||
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
||||
// with an additional rule for ignoring percentage-escaped characters
|
||||
// but that's a) hard to capture in a regular expression that performs
|
||||
// well, and b) possibly too restrictive for real-world usage. That's
|
||||
// why it only scans for spaces because those are guaranteed to create
|
||||
// an invalid request.
|
||||
throw new TypeError('Request path contains unescaped characters')
|
||||
}
|
||||
const pathObj = url.parse(options.path || '/')
|
||||
urlObj.pathname = pathObj.pathname
|
||||
urlObj.search = pathObj.search
|
||||
urlObj.hash = pathObj.hash
|
||||
urlStr = url.format(urlObj)
|
||||
}
|
||||
|
||||
const redirectPolicy = options.redirect || 'follow'
|
||||
if (!['follow', 'error', 'manual'].includes(redirectPolicy)) {
|
||||
throw new Error('redirect mode should be one of follow, error or manual')
|
||||
}
|
||||
|
||||
const urlRequestOptions = {
|
||||
method: method,
|
||||
url: urlStr,
|
||||
redirect: redirectPolicy
|
||||
}
|
||||
if (options.session) {
|
||||
if (options.session instanceof Session) {
|
||||
urlRequestOptions.session = options.session
|
||||
} else {
|
||||
throw new TypeError('`session` should be an instance of the Session class')
|
||||
}
|
||||
} else if (options.partition) {
|
||||
if (typeof options.partition === 'string') {
|
||||
urlRequestOptions.partition = options.partition
|
||||
} else {
|
||||
throw new TypeError('`partition` should be a string')
|
||||
}
|
||||
}
|
||||
|
||||
const urlRequest = new URLRequest(urlRequestOptions)
|
||||
|
||||
// Set back and forward links.
|
||||
this.urlRequest = urlRequest
|
||||
urlRequest.clientRequest = this
|
||||
|
||||
// This is a copy of the extra headers structure held by the native
|
||||
// net::URLRequest. The main reason is to keep the getHeader API synchronous
|
||||
// after the request starts.
|
||||
this.extraHeaders = {}
|
||||
|
||||
if (options.headers) {
|
||||
for (const key in options.headers) {
|
||||
this.setHeader(key, options.headers[key])
|
||||
}
|
||||
}
|
||||
|
||||
// Set when the request uses chunked encoding. Can be switched
|
||||
// to true only once and never set back to false.
|
||||
this.chunkedEncodingEnabled = false
|
||||
|
||||
urlRequest.on('response', () => {
|
||||
const response = new IncomingMessage(urlRequest)
|
||||
urlRequest._response = response
|
||||
this.emit('response', response)
|
||||
})
|
||||
|
||||
urlRequest.on('login', (event, authInfo, callback) => {
|
||||
this.emit('login', authInfo, (username, password) => {
|
||||
// If null or undefined username/password, force to empty string.
|
||||
if (username === null || username === undefined) {
|
||||
username = ''
|
||||
}
|
||||
if (typeof username !== 'string') {
|
||||
throw new Error('username must be a string')
|
||||
}
|
||||
if (password === null || password === undefined) {
|
||||
password = ''
|
||||
}
|
||||
if (typeof password !== 'string') {
|
||||
throw new Error('password must be a string')
|
||||
}
|
||||
callback(username, password)
|
||||
})
|
||||
})
|
||||
|
||||
if (callback) {
|
||||
this.once('response', callback)
|
||||
}
|
||||
}
|
||||
|
||||
get chunkedEncoding () {
|
||||
return this.chunkedEncodingEnabled
|
||||
const { redirectPolicy, ...urlLoaderOptions } = parseOptions(options)
|
||||
this._urlLoaderOptions = urlLoaderOptions
|
||||
this._redirectPolicy = redirectPolicy
|
||||
this._started = false
|
||||
}
|
||||
|
||||
set chunkedEncoding (value) {
|
||||
if (!this.urlRequest.notStarted) {
|
||||
throw new Error('Can\'t set the transfer encoding, headers have been sent')
|
||||
if (this._started) {
|
||||
throw new Error('chunkedEncoding can only be set before the request is started')
|
||||
}
|
||||
if (typeof this._chunkedEncoding !== 'undefined') {
|
||||
throw new Error('chunkedEncoding can only be set once')
|
||||
}
|
||||
this._chunkedEncoding = !!value
|
||||
if (this._chunkedEncoding) {
|
||||
this._body = new ChunkedBodyStream(this)
|
||||
this._urlLoaderOptions.body = (pipe) => {
|
||||
this._body.startReading(pipe)
|
||||
}
|
||||
}
|
||||
this.chunkedEncodingEnabled = value
|
||||
}
|
||||
|
||||
setHeader (name, value) {
|
||||
@@ -288,13 +292,18 @@ class ClientRequest extends EventEmitter {
|
||||
if (value == null) {
|
||||
throw new Error('`value` required in setHeader("' + name + '", value)')
|
||||
}
|
||||
if (!this.urlRequest.notStarted) {
|
||||
if (this._started || this._firstWrite) {
|
||||
throw new Error('Can\'t set headers after they are sent')
|
||||
}
|
||||
if (!_isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`)
|
||||
}
|
||||
if (!_isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`)
|
||||
}
|
||||
|
||||
const key = name.toLowerCase()
|
||||
this.extraHeaders[key] = value
|
||||
this.urlRequest.setExtraHeader(name, value.toString())
|
||||
this._urlLoaderOptions.extraHeaders[key] = value
|
||||
}
|
||||
|
||||
getHeader (name) {
|
||||
@@ -302,12 +311,8 @@ class ClientRequest extends EventEmitter {
|
||||
throw new Error('`name` is required for getHeader(name)')
|
||||
}
|
||||
|
||||
if (!this.extraHeaders) {
|
||||
return
|
||||
}
|
||||
|
||||
const key = name.toLowerCase()
|
||||
return this.extraHeaders[key]
|
||||
return this._urlLoaderOptions.extraHeaders[key]
|
||||
}
|
||||
|
||||
removeHeader (name) {
|
||||
@@ -315,93 +320,144 @@ class ClientRequest extends EventEmitter {
|
||||
throw new Error('`name` is required for removeHeader(name)')
|
||||
}
|
||||
|
||||
if (!this.urlRequest.notStarted) {
|
||||
if (this._started || this._firstWrite) {
|
||||
throw new Error('Can\'t remove headers after they are sent')
|
||||
}
|
||||
|
||||
const key = name.toLowerCase()
|
||||
delete this.extraHeaders[key]
|
||||
this.urlRequest.removeExtraHeader(name)
|
||||
delete this._urlLoaderOptions.extraHeaders[key]
|
||||
}
|
||||
|
||||
_write (chunk, encoding, callback, isLast) {
|
||||
const chunkIsString = typeof chunk === 'string'
|
||||
const chunkIsBuffer = chunk instanceof Buffer
|
||||
if (!chunkIsString && !chunkIsBuffer) {
|
||||
throw new TypeError('First argument must be a string or Buffer')
|
||||
_write (chunk, encoding, callback) {
|
||||
this._firstWrite = true
|
||||
if (!this._body) {
|
||||
this._body = new SlurpStream()
|
||||
this._body.on('finish', () => {
|
||||
this._urlLoaderOptions.body = this._body.data()
|
||||
this._startRequest()
|
||||
})
|
||||
}
|
||||
|
||||
if (chunkIsString) {
|
||||
// We convert all strings into binary buffers.
|
||||
chunk = Buffer.from(chunk, encoding)
|
||||
}
|
||||
|
||||
// Since writing to the network is asynchronous, we conservatively
|
||||
// assume that request headers are written after delivering the first
|
||||
// buffer to the network IO thread.
|
||||
if (this.urlRequest.notStarted) {
|
||||
this.urlRequest.setChunkedUpload(this.chunkedEncoding)
|
||||
}
|
||||
|
||||
// Headers are assumed to be sent on first call to _writeBuffer,
|
||||
// i.e. after the first call to write or end.
|
||||
const result = this.urlRequest.write(chunk, isLast)
|
||||
|
||||
// The write callback is fired asynchronously to mimic Node.js.
|
||||
if (callback) {
|
||||
process.nextTick(callback)
|
||||
}
|
||||
|
||||
return result
|
||||
// TODO: is this the right way to forward to another stream?
|
||||
this._body.write(chunk, encoding, callback)
|
||||
}
|
||||
|
||||
write (data, encoding, callback) {
|
||||
if (this.urlRequest.finished) {
|
||||
const error = new Error('Write after end')
|
||||
process.nextTick(writeAfterEndNT, this, error, callback)
|
||||
return true
|
||||
_final (callback) {
|
||||
if (this._body) {
|
||||
// TODO: is this the right way to forward to another stream?
|
||||
this._body.end(callback)
|
||||
} else {
|
||||
// end() called without a body, go ahead and start the request
|
||||
this._startRequest()
|
||||
callback()
|
||||
}
|
||||
|
||||
return this._write(data, encoding, callback, false)
|
||||
}
|
||||
|
||||
end (data, encoding, callback) {
|
||||
if (this.urlRequest.finished) {
|
||||
return false
|
||||
_startRequest () {
|
||||
this._started = true
|
||||
const stringifyValues = (obj) => {
|
||||
const ret = {}
|
||||
for (const k in obj) {
|
||||
ret[k] = obj[k].toString()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
const opts = { ...this._urlLoaderOptions, extraHeaders: stringifyValues(this._urlLoaderOptions.extraHeaders) }
|
||||
this._urlLoader = new URLLoader(opts)
|
||||
this._urlLoader.on('response-started', (event, finalUrl, responseHead) => {
|
||||
const response = this._response = new IncomingMessage(responseHead)
|
||||
this.emit('response', response)
|
||||
})
|
||||
this._urlLoader.on('data', (event, data) => {
|
||||
this._response._storeInternalData(Buffer.from(data))
|
||||
})
|
||||
this._urlLoader.on('complete', () => {
|
||||
if (this._response) { this._response._storeInternalData(null) }
|
||||
})
|
||||
this._urlLoader.on('error', (event, netErrorString) => {
|
||||
const error = new Error(netErrorString)
|
||||
if (this._response) this._response.destroy(error)
|
||||
this._die(error)
|
||||
})
|
||||
|
||||
if (typeof data === 'function') {
|
||||
callback = data
|
||||
encoding = null
|
||||
data = null
|
||||
} else if (typeof encoding === 'function') {
|
||||
callback = encoding
|
||||
encoding = null
|
||||
}
|
||||
this._urlLoader.on('login', (event, authInfo, callback) => {
|
||||
const handled = this.emit('login', authInfo, callback)
|
||||
if (!handled) {
|
||||
// If there were no listeners, cancel the authentication request.
|
||||
callback()
|
||||
}
|
||||
})
|
||||
|
||||
data = data || ''
|
||||
this._urlLoader.on('redirect', (event, redirectInfo, headers) => {
|
||||
const { statusCode, newMethod, newUrl } = redirectInfo
|
||||
if (this._redirectPolicy === 'error') {
|
||||
this._die(new Error(`Attempted to redirect, but redirect policy was 'error'`))
|
||||
} else if (this._redirectPolicy === 'manual') {
|
||||
let _followRedirect = false
|
||||
this._followRedirectCb = () => { _followRedirect = true }
|
||||
try {
|
||||
this.emit('redirect', statusCode, newMethod, newUrl, headers)
|
||||
} finally {
|
||||
this._followRedirectCb = null
|
||||
if (!_followRedirect) {
|
||||
this._die(new Error('Redirect was cancelled'))
|
||||
}
|
||||
}
|
||||
} else if (this._redirectPolicy === 'follow') {
|
||||
// Calling followRedirect() when the redirect policy is 'follow' is
|
||||
// allowed but does nothing. (Perhaps it should throw an error
|
||||
// though...? Since the redirect will happen regardless.)
|
||||
try {
|
||||
this._followRedirectCb = () => {}
|
||||
this.emit('redirect', statusCode, newMethod, newUrl, headers)
|
||||
} finally {
|
||||
this._followRedirectCb = null
|
||||
}
|
||||
} else {
|
||||
this._die(new Error(`Unexpected redirect policy '${this._redirectPolicy}'`))
|
||||
}
|
||||
})
|
||||
|
||||
return this._write(data, encoding, callback, true)
|
||||
this._urlLoader.on('upload-progress', (event, position, total) => {
|
||||
this._uploadProgress = { active: true, started: true, current: position, total }
|
||||
this.emit('upload-progress', position, total) // Undocumented, for now
|
||||
})
|
||||
|
||||
this._urlLoader.on('download-progress', (event, current) => {
|
||||
if (this._response) {
|
||||
this._response.emit('download-progress', current) // Undocumented, for now
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
followRedirect () {
|
||||
this.urlRequest.followRedirect()
|
||||
if (this._followRedirectCb) {
|
||||
this._followRedirectCb()
|
||||
} else {
|
||||
throw new Error('followRedirect() called, but was not waiting for a redirect')
|
||||
}
|
||||
}
|
||||
|
||||
abort () {
|
||||
this.urlRequest.cancel()
|
||||
if (!this._aborted) {
|
||||
process.nextTick(() => { this.emit('abort') })
|
||||
}
|
||||
this._aborted = true
|
||||
this._die()
|
||||
}
|
||||
|
||||
_die (err) {
|
||||
this.destroy(err)
|
||||
if (this._urlLoader) {
|
||||
this._urlLoader.cancel()
|
||||
if (this._response) this._response.destroy(err)
|
||||
}
|
||||
}
|
||||
|
||||
getUploadProgress () {
|
||||
return this.urlRequest.getUploadProgress()
|
||||
return this._uploadProgress ? { ...this._uploadProgress } : { active: false }
|
||||
}
|
||||
}
|
||||
|
||||
function writeAfterEndNT (self, error, callback) {
|
||||
self.emit('error', error)
|
||||
if (callback) callback(error)
|
||||
}
|
||||
|
||||
Net.prototype.request = function (options, callback) {
|
||||
return new ClientRequest(options, callback)
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const { deprecate } = require('electron')
|
||||
const { systemPreferences, SystemPreferences } = process.electronBinding('system_preferences')
|
||||
|
||||
// SystemPreferences is an EventEmitter.
|
||||
Object.setPrototypeOf(SystemPreferences.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(systemPreferences)
|
||||
|
||||
if ('appLevelAppearance' in systemPreferences) {
|
||||
deprecate.fnToProperty(SystemPreferences.prototype, 'appLevelAppearance', '_getAppLevelAppearance', '_setAppLevelAppearance')
|
||||
}
|
||||
|
||||
module.exports = systemPreferences
|
||||
42
lib/browser/api/system-preferences.ts
Normal file
42
lib/browser/api/system-preferences.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { EventEmitter } from 'events'
|
||||
import { deprecate } from 'electron'
|
||||
const { systemPreferences, SystemPreferences } = process.electronBinding('system_preferences')
|
||||
|
||||
// SystemPreferences is an EventEmitter.
|
||||
Object.setPrototypeOf(SystemPreferences.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(systemPreferences)
|
||||
|
||||
if ('appLevelAppearance' in systemPreferences) {
|
||||
deprecate.fnToProperty(
|
||||
SystemPreferences.prototype,
|
||||
'appLevelAppearance',
|
||||
'_getAppLevelAppearance',
|
||||
'_setAppLevelAppearance'
|
||||
)
|
||||
}
|
||||
|
||||
if ('effectiveAppearance' in systemPreferences) {
|
||||
deprecate.fnToProperty(
|
||||
SystemPreferences.prototype,
|
||||
'effectiveAppearance',
|
||||
'_getEffectiveAppearance'
|
||||
)
|
||||
}
|
||||
|
||||
SystemPreferences.prototype.isDarkMode = deprecate.moveAPI(
|
||||
SystemPreferences.prototype.isDarkMode,
|
||||
'systemPreferences.isDarkMode()',
|
||||
'nativeTheme.shouldUseDarkColors'
|
||||
)
|
||||
SystemPreferences.prototype.isInvertedColorScheme = deprecate.moveAPI(
|
||||
SystemPreferences.prototype.isInvertedColorScheme,
|
||||
'systemPreferences.isInvertedColorScheme()',
|
||||
'nativeTheme.shouldUseInvertedColorScheme'
|
||||
)
|
||||
SystemPreferences.prototype.isHighContrastColorScheme = deprecate.moveAPI(
|
||||
SystemPreferences.prototype.isHighContrastColorScheme,
|
||||
'systemPreferences.isHighContrastColorScheme()',
|
||||
'nativeTheme.shouldUseHighContrastColors'
|
||||
)
|
||||
|
||||
module.exports = systemPreferences
|
||||
@@ -72,7 +72,6 @@ const defaultPrintingSetting = {
|
||||
headerFooterEnabled: false,
|
||||
marginsType: 0,
|
||||
isFirstRequest: false,
|
||||
requestID: getNextId(),
|
||||
previewUIID: 0,
|
||||
previewModifiable: true,
|
||||
printToPDF: true,
|
||||
@@ -205,7 +204,10 @@ WebContents.prototype.executeJavaScript = function (code, hasUserGesture) {
|
||||
|
||||
// Translate the options of printToPDF.
|
||||
WebContents.prototype.printToPDF = function (options) {
|
||||
const printingSetting = Object.assign({}, defaultPrintingSetting)
|
||||
const printingSetting = {
|
||||
...defaultPrintingSetting,
|
||||
requestID: getNextId()
|
||||
}
|
||||
if (options.landscape) {
|
||||
printingSetting.landscape = options.landscape
|
||||
}
|
||||
@@ -264,6 +266,7 @@ WebContents.prototype.getPrinters = function () {
|
||||
return this._getPrinters()
|
||||
} else {
|
||||
console.error('Error: Printing feature is disabled.')
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,6 +416,10 @@ WebContents.prototype._init = function () {
|
||||
})
|
||||
}
|
||||
|
||||
this.on('login', (event, ...args) => {
|
||||
app.emit('login', event, this, ...args)
|
||||
})
|
||||
|
||||
const event = process.electronBinding('event').createEmpty()
|
||||
app.emit('web-contents-created', event, this)
|
||||
}
|
||||
|
||||
@@ -427,11 +427,7 @@ const chromeExtensionHandler = function (request, callback) {
|
||||
}
|
||||
|
||||
app.on('session-created', function (ses) {
|
||||
ses.protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler, function (error) {
|
||||
if (error) {
|
||||
console.error(`Unable to register chrome-extension protocol: ${error}`)
|
||||
}
|
||||
})
|
||||
ses.protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler)
|
||||
})
|
||||
|
||||
// The persistent path of "DevTools Extensions" preference file.
|
||||
|
||||
@@ -19,7 +19,13 @@ export const getSources = (event: Electron.IpcMainEvent, options: ElectronIntern
|
||||
}
|
||||
|
||||
const getSources = new Promise<ElectronInternal.GetSourcesResult[]>((resolve, reject) => {
|
||||
let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer()
|
||||
|
||||
const stopRunning = () => {
|
||||
if (capturer) {
|
||||
capturer.emit = null
|
||||
capturer = null
|
||||
}
|
||||
// Remove from currentlyRunning once we resolve or reject
|
||||
currentlyRunning = currentlyRunning.filter(running => running.options !== options)
|
||||
}
|
||||
@@ -42,19 +48,13 @@ export const getSources = (event: Electron.IpcMainEvent, options: ElectronIntern
|
||||
})))
|
||||
})
|
||||
|
||||
let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer()
|
||||
|
||||
capturer.emit = emitter.emit.bind(emitter)
|
||||
capturer.startHandling(options.captureWindow, options.captureScreen, options.thumbnailSize, options.fetchWindowIcons)
|
||||
|
||||
// If the WebContents is destroyed before receiving result, just remove the
|
||||
// reference to emit and the capturer itself so that it never dispatches
|
||||
// back to the renderer
|
||||
event.sender.once('destroyed', () => {
|
||||
capturer!.emit = null
|
||||
capturer = null
|
||||
stopRunning()
|
||||
})
|
||||
event.sender.once('destroyed', () => stopRunning())
|
||||
})
|
||||
|
||||
currentlyRunning.push({
|
||||
|
||||
@@ -40,9 +40,9 @@ const getEditMenuItems = function (): Electron.MenuItemConstructorOptions[] {
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
{ role: 'pasteandmatchstyle' },
|
||||
{ role: 'pasteAndMatchStyle' },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectall' }
|
||||
{ role: 'selectAll' }
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-interna
|
||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils')
|
||||
const parseFeaturesString = require('@electron/internal/common/parse-features-string')
|
||||
const { syncMethods, asyncMethods } = require('@electron/internal/common/web-view-methods')
|
||||
const { serialize } = require('@electron/internal/common/type-utils')
|
||||
|
||||
// Doesn't exist in early initialization.
|
||||
let webViewManager = null
|
||||
@@ -188,7 +189,7 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
||||
nodeIntegrationInSubFrames: params.nodeintegrationinsubframes != null ? params.nodeintegrationinsubframes : false,
|
||||
enableRemoteModule: params.enableremotemodule,
|
||||
plugins: params.plugins,
|
||||
zoomFactor: embedder.getZoomFactor(),
|
||||
zoomFactor: embedder.zoomFactor,
|
||||
disablePopups: !params.allowpopups,
|
||||
webSecurity: !params.disablewebsecurity,
|
||||
enableBlinkFeatures: params.blinkfeatures,
|
||||
@@ -356,6 +357,12 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CALL', function (event, guestInstance
|
||||
return guest[method](...args)
|
||||
})
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CAPTURE_PAGE', async function (event, guestInstanceId, args) {
|
||||
const guest = getGuestForWebContents(guestInstanceId, event.sender)
|
||||
|
||||
return serialize(await guest.capturePage(...args))
|
||||
})
|
||||
|
||||
// Returns WebContents from its guest id hosted in given webContents.
|
||||
const getGuestForWebContents = function (guestInstanceId, contents) {
|
||||
const guest = getGuest(guestInstanceId)
|
||||
|
||||
@@ -34,7 +34,7 @@ const mergeOptions = function (child, parent, visited) {
|
||||
if (key in child && key !== 'webPreferences') continue
|
||||
|
||||
const value = parent[key]
|
||||
if (typeof value === 'object') {
|
||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
||||
child[key] = mergeOptions(child[key] || {}, value, visited)
|
||||
} else {
|
||||
child[key] = value
|
||||
|
||||
@@ -187,13 +187,14 @@ app.on('window-all-closed', () => {
|
||||
}
|
||||
})
|
||||
|
||||
Promise.all([
|
||||
import('@electron/internal/browser/default-menu'),
|
||||
app.whenReady()
|
||||
]).then(([{ setDefaultApplicationMenu }]) => {
|
||||
// Create default menu
|
||||
setDefaultApplicationMenu()
|
||||
})
|
||||
const { setDefaultApplicationMenu } = require('@electron/internal/browser/default-menu')
|
||||
|
||||
// Create default menu.
|
||||
//
|
||||
// Note that the task must be added before loading any app, so we can make sure
|
||||
// the call is maded before any user window is created, otherwise the default
|
||||
// menu may show even when user explicitly hides the menu.
|
||||
app.once('ready', setDefaultApplicationMenu)
|
||||
|
||||
if (packagePath) {
|
||||
// Finally load app's main.js and transfer control to C++.
|
||||
|
||||
@@ -152,7 +152,8 @@ const NavigationController = (function () {
|
||||
NavigationController.prototype.reloadIgnoringCache = function () {
|
||||
this.pendingIndex = this.currentIndex
|
||||
return this.webContents._loadURL(this.getURL(), {
|
||||
extraHeaders: 'pragma: no-cache\n'
|
||||
extraHeaders: 'pragma: no-cache\n',
|
||||
reloadIgnoringCache: true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -127,6 +127,10 @@ class ObjectsRegistry {
|
||||
this.clear(webContents, contextId)
|
||||
}
|
||||
}
|
||||
// Note that the "render-view-deleted" event may not be emitted on time when
|
||||
// the renderer process get destroyed because of navigation, we rely on the
|
||||
// renderer process to send "ELECTRON_BROWSER_CONTEXT_RELEASE" message to
|
||||
// guard this situation.
|
||||
webContents.on('render-view-deleted', listener)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const objectsRegistry = require('@electron/internal/browser/objects-registry')
|
||||
const guestViewManager = require('@electron/internal/browser/guest-view-manager')
|
||||
const bufferUtils = require('@electron/internal/common/buffer-utils')
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
const clipboardUtils = require('@electron/internal/common/clipboard-utils')
|
||||
const typeUtils = require('@electron/internal/common/type-utils')
|
||||
const { isPromise } = require('@electron/internal/common/is-promise')
|
||||
|
||||
const hasProp = {}.hasOwnProperty
|
||||
@@ -231,7 +231,7 @@ const unwrapArgs = function (sender, frameId, contextId, args) {
|
||||
v8Util.setHiddenValue(callIntoRenderer, 'location', meta.location)
|
||||
Object.defineProperty(callIntoRenderer, 'length', { value: meta.length })
|
||||
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, contextId, meta.id, sender)
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, frameId, contextId, meta.id, sender)
|
||||
rendererFunctions.set(objectId, callIntoRenderer)
|
||||
return callIntoRenderer
|
||||
}
|
||||
@@ -444,7 +444,6 @@ handleRemoteCommand('ELECTRON_BROWSER_DEREFERENCE', function (event, contextId,
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_CONTEXT_RELEASE', (event, contextId) => {
|
||||
objectsRegistry.clear(event.sender, contextId)
|
||||
return null
|
||||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, contextId, guestInstanceId) {
|
||||
@@ -497,7 +496,7 @@ ipcMainUtils.handle('ELECTRON_BROWSER_CLIPBOARD', function (event, method, ...ar
|
||||
throw new Error(`Invalid method: ${method}`)
|
||||
}
|
||||
|
||||
return clipboardUtils.serialize(electron.clipboard[method](...clipboardUtils.deserialize(args)))
|
||||
return typeUtils.serialize(electron.clipboard[method](...typeUtils.deserialize(args)))
|
||||
})
|
||||
|
||||
if (features.isDesktopCapturerEnabled()) {
|
||||
|
||||
@@ -4,13 +4,13 @@ const clipboard = process.electronBinding('clipboard')
|
||||
|
||||
if (process.type === 'renderer') {
|
||||
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils')
|
||||
const clipboardUtils = require('@electron/internal/common/clipboard-utils')
|
||||
const typeUtils = require('@electron/internal/common/type-utils')
|
||||
|
||||
const makeRemoteMethod = function (method) {
|
||||
return (...args) => {
|
||||
args = clipboardUtils.serialize(args)
|
||||
args = typeUtils.serialize(args)
|
||||
const result = ipcRendererUtils.invokeSync('ELECTRON_BROWSER_CLIPBOARD', method, ...args)
|
||||
return clipboardUtils.deserialize(result)
|
||||
return typeUtils.deserialize(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,15 @@ const deprecate: ElectronInternal.DeprecationUtil = {
|
||||
const warn = warnOnce(`${fn.name} function`, `${newName} function`)
|
||||
return function (this: any) {
|
||||
warn()
|
||||
fn.apply(this, arguments)
|
||||
return fn.apply(this, arguments)
|
||||
}
|
||||
},
|
||||
|
||||
moveAPI: (fn: Function, oldUsage: string, newUsage: string) => {
|
||||
const warn = warnOnce(oldUsage, newUsage)
|
||||
return function (this: any) {
|
||||
warn()
|
||||
return fn.apply(this, arguments)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -69,7 +77,7 @@ const deprecate: ElectronInternal.DeprecationUtil = {
|
||||
},
|
||||
|
||||
// deprecate a getter/setter function pair in favor of a property
|
||||
fnToProperty: (prototype: any, prop: string, getter: string, setter: string) => {
|
||||
fnToProperty: (prototype: any, prop: string, getter: string, setter?: string) => {
|
||||
const withWarnOnce = function (obj: any, key: any, oldName: string, newName: string) {
|
||||
const warn = warnOnce(oldName, newName)
|
||||
const method = obj[key]
|
||||
@@ -80,7 +88,9 @@ const deprecate: ElectronInternal.DeprecationUtil = {
|
||||
}
|
||||
|
||||
prototype[getter.substr(1)] = withWarnOnce(prototype, getter, `${getter.substr(1)} function`, `${prop} property`)
|
||||
prototype[setter.substr(1)] = withWarnOnce(prototype, setter, `${setter.substr(1)} function`, `${prop} property`)
|
||||
if (setter) {
|
||||
prototype[setter.substr(1)] = withWarnOnce(prototype, setter, `${setter.substr(1)} function`, `${prop} property`)
|
||||
}
|
||||
},
|
||||
|
||||
// remove a property with no replacement
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
const path = require('path')
|
||||
const util = require('util')
|
||||
|
||||
const Promise = global.Promise
|
||||
|
||||
const envNoAsar = process.env.ELECTRON_NO_ASAR &&
|
||||
process.type !== 'browser' &&
|
||||
process.type !== 'renderer'
|
||||
@@ -40,8 +42,6 @@
|
||||
return newArchive
|
||||
}
|
||||
|
||||
const ASAR_EXTENSION = '.asar'
|
||||
|
||||
// Separate asar package's path from full path.
|
||||
const splitPath = archivePathOrBuffer => {
|
||||
// Shortcut for disabled asar.
|
||||
@@ -54,22 +54,7 @@
|
||||
}
|
||||
if (typeof archivePath !== 'string') return { isAsar: false }
|
||||
|
||||
if (archivePath.endsWith(ASAR_EXTENSION)) {
|
||||
return { isAsar: true, asarPath: archivePath, filePath: '' }
|
||||
}
|
||||
|
||||
archivePath = path.normalize(archivePath)
|
||||
const index = archivePath.lastIndexOf(`${ASAR_EXTENSION}${path.sep}`)
|
||||
if (index === -1) return { isAsar: false }
|
||||
|
||||
// E.g. for "//some/path/to/archive.asar/then/internal.file"...
|
||||
return {
|
||||
isAsar: true,
|
||||
// "//some/path/to/archive.asar"
|
||||
asarPath: archivePath.substr(0, index + ASAR_EXTENSION.length),
|
||||
// "then/internal.file" (with a path separator excluded)
|
||||
filePath: archivePath.substr(index + ASAR_EXTENSION.length + 1)
|
||||
}
|
||||
return asar.splitPath(path.normalize(archivePath))
|
||||
}
|
||||
|
||||
// Convert asar archive's Stats object to fs's Stats object.
|
||||
|
||||
@@ -52,7 +52,6 @@ export const syncMethods = new Set([
|
||||
|
||||
export const asyncMethods = new Set([
|
||||
'loadURL',
|
||||
'capturePage',
|
||||
'executeJavaScript',
|
||||
'insertCSS',
|
||||
'insertText',
|
||||
|
||||
8
lib/common/webpack-globals-provider.ts
Normal file
8
lib/common/webpack-globals-provider.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// Captures original globals into a scope to ensure that userland modifications do
|
||||
// not impact Electron. Note that users doing:
|
||||
//
|
||||
// global.Promise.resolve = myFn
|
||||
//
|
||||
// Will mutate this captured one as well and that is OK.
|
||||
|
||||
export const Promise = global.Promise
|
||||
20
lib/renderer/api/context-bridge.ts
Normal file
20
lib/renderer/api/context-bridge.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
const { hasSwitch } = process.electronBinding('command_line')
|
||||
const binding = process.electronBinding('context_bridge')
|
||||
|
||||
const contextIsolationEnabled = hasSwitch('context-isolation')
|
||||
|
||||
const checkContextIsolationEnabled = () => {
|
||||
if (!contextIsolationEnabled) throw new Error('contextBridge API can only be used when contextIsolation is enabled')
|
||||
}
|
||||
|
||||
const contextBridge = {
|
||||
exposeInMainWorld: (key: string, api: Record<string, any>) => {
|
||||
checkContextIsolationEnabled()
|
||||
return binding.exposeAPIInMainWorld(key, api)
|
||||
},
|
||||
debugGC: () => binding._debugGCMaps({})
|
||||
}
|
||||
|
||||
if (!binding._debugGCMaps) delete contextBridge.debugGC
|
||||
|
||||
export default contextBridge
|
||||
@@ -8,6 +8,7 @@ const enableRemoteModule = v8Util.getHiddenValue(global, 'enableRemoteModule')
|
||||
// Renderer side modules, please sort alphabetically.
|
||||
// A module is `enabled` if there is no explicit condition defined.
|
||||
module.exports = [
|
||||
{ name: 'contextBridge', loader: () => require('./context-bridge') },
|
||||
{ name: 'crashReporter', loader: () => require('./crash-reporter') },
|
||||
{ name: 'ipcRenderer', loader: () => require('./ipc-renderer') },
|
||||
{ name: 'webFrame', loader: () => require('./web-frame') }
|
||||
|
||||
@@ -20,7 +20,7 @@ const contextId = v8Util.getHiddenValue(global, 'contextId')
|
||||
// to guard that situation.
|
||||
process.on('exit', () => {
|
||||
const command = 'ELECTRON_BROWSER_CONTEXT_RELEASE'
|
||||
ipcRendererInternal.sendSync(command, contextId)
|
||||
ipcRendererInternal.send(command, contextId)
|
||||
})
|
||||
|
||||
// Convert the arguments object into an array of meta data.
|
||||
|
||||
@@ -116,7 +116,11 @@ export function injectTo (extensionId: string, context: any) {
|
||||
let targetExtensionId = extensionId
|
||||
let connectInfo = { name: '' }
|
||||
if (args.length === 1) {
|
||||
targetExtensionId = args[0]
|
||||
if (typeof args[0] === 'string') {
|
||||
targetExtensionId = args[0]
|
||||
} else {
|
||||
connectInfo = args[0]
|
||||
}
|
||||
} else if (args.length === 2) {
|
||||
[targetExtensionId, connectInfo] = args
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ v8Util.setHiddenValue(global, 'ipcNative', {
|
||||
onMessage (internal: boolean, channel: string, args: any[], senderId: number) {
|
||||
const sender = internal ? ipcInternalEmitter : ipcEmitter
|
||||
sender.emit(channel, { sender, senderId }, ...args)
|
||||
process.activateUvLoop()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -189,6 +188,8 @@ if (nodeIntegration) {
|
||||
delete global.setImmediate
|
||||
delete global.clearImmediate
|
||||
delete global.global
|
||||
delete global.root
|
||||
delete global.GLOBAL
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-inte
|
||||
import * as guestViewInternal from '@electron/internal/renderer/web-view/guest-view-internal'
|
||||
import { WEB_VIEW_CONSTANTS } from '@electron/internal/renderer/web-view/web-view-constants'
|
||||
import { syncMethods, asyncMethods } from '@electron/internal/common/web-view-methods'
|
||||
import { deserialize } from '@electron/internal/common/type-utils'
|
||||
|
||||
const v8Util = process.electronBinding('v8_util')
|
||||
|
||||
@@ -260,6 +261,10 @@ export const setupMethods = (WebViewElement: typeof ElectronInternal.WebViewElem
|
||||
for (const method of asyncMethods) {
|
||||
(WebViewElement.prototype as Record<string, any>)[method] = createNonBlockHandler(method)
|
||||
}
|
||||
|
||||
WebViewElement.prototype.capturePage = async function (...args) {
|
||||
return deserialize(await ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_CAPTURE_PAGE', this.getWebContentsId(), args))
|
||||
}
|
||||
}
|
||||
|
||||
export const webViewImplModule = {
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
const features = process.electronBinding('features')
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
name: 'contextBridge',
|
||||
load: () => require('@electron/internal/renderer/api/context-bridge')
|
||||
},
|
||||
{
|
||||
name: 'crashReporter',
|
||||
load: () => require('@electron/internal/renderer/api/crash-reporter')
|
||||
|
||||
@@ -94,6 +94,8 @@ Object.defineProperty(preloadProcess, 'noDeprecation', {
|
||||
|
||||
process.on('loaded', () => preloadProcess.emit('loaded'))
|
||||
process.on('exit', () => preloadProcess.emit('exit'))
|
||||
process.on('document-start', () => preloadProcess.emit('document-start'))
|
||||
process.on('document-end', () => preloadProcess.emit('document-end'))
|
||||
|
||||
// This is the `require` function that will be visible to the preload script
|
||||
function preloadRequire (module) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/optional.h"
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace mate {
|
||||
@@ -26,7 +27,7 @@ class Arguments {
|
||||
|
||||
template <typename T>
|
||||
bool GetHolder(T* out) {
|
||||
return ConvertFromV8(isolate_, info_->Holder(), out);
|
||||
return mate::ConvertFromV8(isolate_, info_->Holder(), out);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -34,6 +35,17 @@ class Arguments {
|
||||
return ConvertFromV8(isolate_, info_->Data(), out);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool GetNext(base::Optional<T>* out) {
|
||||
if (next_ >= info_->Length())
|
||||
return true;
|
||||
v8::Local<v8::Value> val = (*info_)[next_];
|
||||
bool success = ConvertFromV8(isolate_, val, out);
|
||||
if (success)
|
||||
next_++;
|
||||
return success;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool GetNext(T* out) {
|
||||
if (next_ >= info_->Length()) {
|
||||
@@ -41,7 +53,7 @@ class Arguments {
|
||||
return false;
|
||||
}
|
||||
v8::Local<v8::Value> val = (*info_)[next_];
|
||||
bool success = ConvertFromV8(isolate_, val, out);
|
||||
bool success = mate::ConvertFromV8(isolate_, val, out);
|
||||
if (success)
|
||||
next_++;
|
||||
return success;
|
||||
|
||||
@@ -40,6 +40,12 @@ class Dictionary {
|
||||
|
||||
static Dictionary CreateEmpty(v8::Isolate* isolate);
|
||||
|
||||
bool Has(base::StringPiece key) const {
|
||||
v8::Local<v8::Context> context = isolate_->GetCurrentContext();
|
||||
v8::Local<v8::String> v8_key = StringToV8(isolate_, key);
|
||||
return internal::IsTrue(GetHandle()->Has(context, v8_key));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Get(base::StringPiece key, T* out) const {
|
||||
// Check for existence before getting, otherwise this method will always
|
||||
@@ -102,6 +108,17 @@ class Dictionary {
|
||||
return !result.IsNothing() && result.FromJust();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SetReadOnlyNonConfigurable(base::StringPiece key, T val) {
|
||||
v8::Local<v8::Value> v8_value;
|
||||
if (!TryConvertToV8(isolate_, val, &v8_value))
|
||||
return false;
|
||||
v8::Maybe<bool> result = GetHandle()->DefineOwnProperty(
|
||||
isolate_->GetCurrentContext(), StringToV8(isolate_, key), v8_value,
|
||||
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
|
||||
return !result.IsNothing() && result.FromJust();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SetMethod(base::StringPiece key, const T& callback) {
|
||||
return GetHandle()
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef NATIVE_MATE_NATIVE_MATE_FUNCTION_TEMPLATE_H_
|
||||
#define NATIVE_MATE_NATIVE_MATE_FUNCTION_TEMPLATE_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/logging.h"
|
||||
#include "native_mate/arguments.h"
|
||||
@@ -197,7 +199,8 @@ class Invoker<IndicesHolder<indices...>, ArgTypes...>
|
||||
void DispatchToCallback(base::Callback<ReturnType(ArgTypes...)> callback) {
|
||||
v8::MicrotasksScope script_scope(args_->isolate(),
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
args_->Return(callback.Run(ArgumentHolder<indices, ArgTypes>::value...));
|
||||
args_->Return(
|
||||
callback.Run(std::move(ArgumentHolder<indices, ArgTypes>::value)...));
|
||||
}
|
||||
|
||||
// In C++, you can declare the function foo(void), but you can't pass a void
|
||||
@@ -206,7 +209,7 @@ class Invoker<IndicesHolder<indices...>, ArgTypes...>
|
||||
void DispatchToCallback(base::Callback<void(ArgTypes...)> callback) {
|
||||
v8::MicrotasksScope script_scope(args_->isolate(),
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
callback.Run(ArgumentHolder<indices, ArgTypes>::value...);
|
||||
callback.Run(std::move(ArgumentHolder<indices, ArgTypes>::value)...);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "7.0.0-nightly.20190731",
|
||||
"version": "7.1.5",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
"@electron/docs-parser": "^0.4.1",
|
||||
"@electron/typescript-definitions": "^8.5.0",
|
||||
"@electron/docs-parser": "^0.4.2",
|
||||
"@electron/typescript-definitions": "^8.6.4",
|
||||
"@octokit/rest": "^16.3.2",
|
||||
"@primer/octicons": "^9.1.1",
|
||||
"@types/chai": "^4.1.7",
|
||||
@@ -14,6 +14,7 @@
|
||||
"@types/fs-extra": "^5.0.5",
|
||||
"@types/mocha": "^5.2.6",
|
||||
"@types/node": "^12.0.10",
|
||||
"@types/semver": "^6.0.1",
|
||||
"@types/split": "^1.0.0",
|
||||
"@types/webpack": "^4.4.32",
|
||||
"@types/webpack-env": "^1.13.9",
|
||||
|
||||
1
patches/angle/.patches
Normal file
1
patches/angle/.patches
Normal file
@@ -0,0 +1 @@
|
||||
gles2_use_constant_initialization_for_g_mutex.patch
|
||||
@@ -0,0 +1,60 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jaime Bernardo <jaime@janeasystems.com>
|
||||
Date: Mon, 30 Sep 2019 17:53:56 +0100
|
||||
Subject: GLES2: Use require_constant_initialization for g_Mutex
|
||||
|
||||
A static assert to verify that the global mutex g_Mutex is trivially
|
||||
constructed fails to compile with clang when using the STL shipped
|
||||
with Visual Studio 2019.
|
||||
|
||||
Use __attribute__((require_constant_initialization)) instead to verify
|
||||
for constant initialization.
|
||||
|
||||
BUG=angleproject:3936
|
||||
|
||||
Change-Id: I5969762ad5a99033143513d7c4992344da276b1a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1832164
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Commit-Queue: Geoff Lang <geofflang@chromium.org>
|
||||
|
||||
diff --git a/AUTHORS b/AUTHORS
|
||||
index ab39ee01a47c15da57b531d2c711649f1685091b..7a0f3b32b101b34195c57637b227062d9b173d6a 100644
|
||||
--- a/AUTHORS
|
||||
+++ b/AUTHORS
|
||||
@@ -58,3 +58,4 @@ Jérôme Duval
|
||||
Thomas Miller
|
||||
Till Rathmann
|
||||
Nick Shaforostov
|
||||
+Jaime Bernardo
|
||||
diff --git a/src/common/angleutils.h b/src/common/angleutils.h
|
||||
index 131d5796da4399df1144bc349c506cde8220973a..3a1391e29b72e7ec356e44c7ced202cc29773fb3 100644
|
||||
--- a/src/common/angleutils.h
|
||||
+++ b/src/common/angleutils.h
|
||||
@@ -345,4 +345,10 @@ std::string ToString(const T &value)
|
||||
# define ANGLE_MAYBE_UNUSED
|
||||
#endif // __has_cpp_attribute(maybe_unused)
|
||||
|
||||
+#if __has_cpp_attribute(require_constant_initialization)
|
||||
+# define ANGLE_REQUIRE_CONSTANT_INIT [[require_constant_initialization]]
|
||||
+#else
|
||||
+# define ANGLE_REQUIRE_CONSTANT_INIT
|
||||
+#endif // __has_cpp_attribute(require_constant_initialization)
|
||||
+
|
||||
#endif // COMMON_ANGLEUTILS_H_
|
||||
diff --git a/src/libGLESv2/global_state.cpp b/src/libGLESv2/global_state.cpp
|
||||
index 8ea912eea045c912ef64dfedcfd8f07db4337a9d..c8c9a732fbad5cc50ed2a7fc4b5387a30274435b 100644
|
||||
--- a/src/libGLESv2/global_state.cpp
|
||||
+++ b/src/libGLESv2/global_state.cpp
|
||||
@@ -35,9 +35,8 @@ namespace
|
||||
{
|
||||
static TLSIndex threadTLS = TLS_INVALID_INDEX;
|
||||
Debug *g_Debug = nullptr;
|
||||
-std::atomic<std::mutex *> g_Mutex;
|
||||
-static_assert(std::is_trivially_constructible<decltype(g_Mutex)>::value,
|
||||
- "global mutex is not trivially constructible");
|
||||
+
|
||||
+ANGLE_REQUIRE_CONSTANT_INIT std::atomic<std::mutex *> g_Mutex(nullptr);
|
||||
static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value,
|
||||
"global mutex is not trivially destructible");
|
||||
|
||||
@@ -35,15 +35,11 @@ mas-cfisobjc.patch
|
||||
mas-cgdisplayusesforcetogray.patch
|
||||
mas-audiodeviceduck.patch
|
||||
mas-lssetapplicationlaunchservicesserverconnectionstatus.patch
|
||||
allow_webview_file_url.patch
|
||||
ignore_rc_check.patch
|
||||
enable_widevine.patch
|
||||
chrome_key_systems.patch
|
||||
allow_nested_error_trackers.patch
|
||||
blink_initialization_order.patch
|
||||
ssl_security_state_tab_helper.patch
|
||||
exclude-a-few-test-files-from-build.patch
|
||||
expose-net-observer-api.patch
|
||||
desktop_media_list.patch
|
||||
proxy_config_monitor.patch
|
||||
gritsettings_resource_ids.patch
|
||||
@@ -60,7 +56,6 @@ autofill_size_calculation.patch
|
||||
fix_disable_usage_of_abort_report_np_in_mas_builds.patch
|
||||
fix_disable_usage_of_pthread_fchdir_np_and_pthread_chdir_np_in_mas.patch
|
||||
fix_disable_usage_of_setapplicationisdaemon_and.patch
|
||||
disable_network_services_by_default.patch
|
||||
unsandboxed_ppapi_processes_skip_zygote.patch
|
||||
patch_the_ensure_gn_version_py_script_to_work_on_mac_ci.patch
|
||||
build_add_electron_tracing_category.patch
|
||||
@@ -69,11 +64,25 @@ feat_offscreen_rendering_with_viz_compositor.patch
|
||||
worker_context_will_destroy.patch
|
||||
fix_breakpad_symbol_generation_on_linux_arm.patch
|
||||
frame_host_manager.patch
|
||||
cross_site_document_resource_handler.patch
|
||||
crashpad_pid_check.patch
|
||||
chore_add_debounce_on_the_updatewebcontentsvisibility_method_to.patch
|
||||
preconnect_feature.patch
|
||||
network_service_allow_remote_certificate_verification_logic.patch
|
||||
put_back_deleted_colors_for_autofill.patch
|
||||
build_win_disable_zc_twophase.patch
|
||||
disable_color_correct_rendering.patch
|
||||
add_contentgpuclient_precreatemessageloop_callback.patch
|
||||
fix_disabling_compositor_recycling.patch
|
||||
picture-in-picture.patch
|
||||
allow_new_privileges_in_unsandboxed_child_processes.patch
|
||||
ssl_security_state_tab_helper.patch
|
||||
revert_cleanup_remove_menu_subtitles_sublabels.patch
|
||||
expose_setuseragent_on_networkcontext.patch
|
||||
net_avoid_vector_const_elements.patch
|
||||
feat_add_set_theme_source_to_allow_apps_to.patch
|
||||
build_fix_when_building_with_enable_plugins_false.patch
|
||||
x11_and_ozone_move_closing_logic_to_dwthplatform.patch
|
||||
add_trustedauthclient_to_urlloaderfactory.patch
|
||||
make_autocorrect_off_and_spellcheck_false_disable_touch_bar_typing.patch
|
||||
fix_focusowningwebcontents_to_handle_renderwidgethosts_for_oopifs.patch
|
||||
feat_allow_disbaling_blink_scheduler_throttling_per_renderview.patch
|
||||
accessible_pane_view.patch
|
||||
|
||||
32
patches/chromium/accessible_pane_view.patch
Normal file
32
patches/chromium/accessible_pane_view.patch
Normal file
@@ -0,0 +1,32 @@
|
||||
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: fix: add back virtual methods in AccessiblePaneView
|
||||
|
||||
Mark SetPaneFocus and RemovePaneFocus as virtual in AccessiblePaneView, as we
|
||||
need to override them in MenuBar.
|
||||
|
||||
Pending upstream patch: https://crrev.com/c/1959189
|
||||
|
||||
diff --git a/ui/views/accessible_pane_view.h b/ui/views/accessible_pane_view.h
|
||||
index 813fd13860a8..990c905e8f19 100644
|
||||
--- a/ui/views/accessible_pane_view.h
|
||||
+++ b/ui/views/accessible_pane_view.h
|
||||
@@ -35,7 +35,7 @@ class VIEWS_EXPORT AccessiblePaneView : public View,
|
||||
// If |initial_focus| is not NULL, that control will get
|
||||
// the initial focus, if it's enabled and focusable. Returns true if
|
||||
// the pane was able to receive focus.
|
||||
- bool SetPaneFocus(View* initial_focus);
|
||||
+ virtual bool SetPaneFocus(View* initial_focus);
|
||||
|
||||
bool pane_has_focus() const { return pane_has_focus_; }
|
||||
|
||||
@@ -83,7 +83,7 @@ class VIEWS_EXPORT AccessiblePaneView : public View,
|
||||
bool ContainsForFocusSearch(View* root, const View* v);
|
||||
|
||||
// Remove pane focus.
|
||||
- void RemovePaneFocus();
|
||||
+ virtual void RemovePaneFocus();
|
||||
|
||||
View* GetFirstFocusableChild();
|
||||
View* GetLastFocusableChild();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user