mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
233 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e64966641c | ||
|
|
3bb36a62cb | ||
|
|
e58a04ea5a | ||
|
|
5e32f51cf6 | ||
|
|
75349f58ad | ||
|
|
879b98c922 | ||
|
|
9d34c83089 | ||
|
|
8d8949ac60 | ||
|
|
acb2209668 | ||
|
|
4bd655a093 | ||
|
|
9c976b4f3d | ||
|
|
d70c5d1e6a | ||
|
|
d93629321e | ||
|
|
b505de0765 | ||
|
|
4c4d29eb73 | ||
|
|
993ecb5bdd | ||
|
|
d0ba8d1f69 | ||
|
|
d03fd85a90 | ||
|
|
2387d10956 | ||
|
|
558350e4bf | ||
|
|
4d960873a4 | ||
|
|
dfcb2afffd | ||
|
|
221fd9d6ce | ||
|
|
ecad7c2441 | ||
|
|
a9acc050ee | ||
|
|
29311b7d1d | ||
|
|
949ec0c7c9 | ||
|
|
91b1c0162e | ||
|
|
e20eab42d3 | ||
|
|
fe44e01dbb | ||
|
|
bc987209f8 | ||
|
|
7c2889d93a | ||
|
|
fa46c67bd3 | ||
|
|
82679f4335 | ||
|
|
75f366f4d0 | ||
|
|
1d531f29ee | ||
|
|
f75b755f21 | ||
|
|
a2929226d2 | ||
|
|
6655694cc7 | ||
|
|
1ac4d27e22 | ||
|
|
681d02a77d | ||
|
|
14eefd58c1 | ||
|
|
2beec61a50 | ||
|
|
e1ae36210b | ||
|
|
e74eac61ae | ||
|
|
f8a5c3d8ee | ||
|
|
efd18b09ca | ||
|
|
cd062ac26e | ||
|
|
a3e47196f7 | ||
|
|
1930d972fc | ||
|
|
0c4ac78dea | ||
|
|
5771f3826a | ||
|
|
a55bc6a870 | ||
|
|
dcb311d5c9 | ||
|
|
e5935eaff9 | ||
|
|
d927f1dc02 | ||
|
|
ca1cae64d9 | ||
|
|
69df216a9c | ||
|
|
2917eb1589 | ||
|
|
ec282ff385 | ||
|
|
5d98e5e78a | ||
|
|
251e7bb227 | ||
|
|
d4881625b8 | ||
|
|
348f991563 | ||
|
|
6308fc4c4e | ||
|
|
7fb719f261 | ||
|
|
d7d9d58c8b | ||
|
|
acc861dbaf | ||
|
|
18de6be607 | ||
|
|
1ae50bbeff | ||
|
|
7d129ac5c9 | ||
|
|
2cca38c036 | ||
|
|
f616c85061 | ||
|
|
393045a7e5 | ||
|
|
4a7dd267ec | ||
|
|
f2275ec32e | ||
|
|
e70c39ed60 | ||
|
|
db12e7f08b | ||
|
|
6a1c6f8d7f | ||
|
|
7bd6479573 | ||
|
|
c2de2eaaa0 | ||
|
|
62b3a6b724 | ||
|
|
c3d8337058 | ||
|
|
b3eff8ef13 | ||
|
|
6cef0d9118 | ||
|
|
65d03deacd | ||
|
|
39e55225a0 | ||
|
|
bb83758378 | ||
|
|
2716a25fcf | ||
|
|
2745d70d25 | ||
|
|
b6ffa799c5 | ||
|
|
c9bb6cd134 | ||
|
|
ac2515dd0d | ||
|
|
49436f298b | ||
|
|
542874d13b | ||
|
|
2a8e1a6de1 | ||
|
|
f5bffae462 | ||
|
|
9f80f4aa76 | ||
|
|
736150672c | ||
|
|
7434547d97 | ||
|
|
0436a27d4f | ||
|
|
6627bebdbd | ||
|
|
4a24a28467 | ||
|
|
390ed798f0 | ||
|
|
cdd2176bb6 | ||
|
|
e57b74858f | ||
|
|
3805e3c0fc | ||
|
|
5fb34249c6 | ||
|
|
06997edc3a | ||
|
|
e2b961d73c | ||
|
|
867ea38cd0 | ||
|
|
2e8f2a2f51 | ||
|
|
4da1162ffe | ||
|
|
9d3ebb1888 | ||
|
|
0b8971dec2 | ||
|
|
c8ab43a766 | ||
|
|
64c6737bb2 | ||
|
|
30b6330189 | ||
|
|
177bdd207c | ||
|
|
77fbad0333 | ||
|
|
971ec77b96 | ||
|
|
1b0c15f742 | ||
|
|
52cddbcd92 | ||
|
|
6d0feb8b79 | ||
|
|
2e096ac6bc | ||
|
|
3afe390805 | ||
|
|
d5097dd2e6 | ||
|
|
257b214cb5 | ||
|
|
945ecdd709 | ||
|
|
cb614d15aa | ||
|
|
5fbcee074d | ||
|
|
dc14161a98 | ||
|
|
299fa3a3c4 | ||
|
|
d09e7f851b | ||
|
|
84eea6fa79 | ||
|
|
0cd80cd424 | ||
|
|
78f037f639 | ||
|
|
fc75bf0a9e | ||
|
|
ddc44e1af4 | ||
|
|
5ab2749acc | ||
|
|
642c458c31 | ||
|
|
2195890a46 | ||
|
|
3413e89572 | ||
|
|
7bf69ce4ee | ||
|
|
49f5006ef0 | ||
|
|
fea59c5601 | ||
|
|
6feed17387 | ||
|
|
ec0fa836d2 | ||
|
|
56a34d3b10 | ||
|
|
bde3d403a8 | ||
|
|
8779a3ac0f | ||
|
|
b465ee721e | ||
|
|
50b0750df3 | ||
|
|
1a3da54563 | ||
|
|
fa3767564a | ||
|
|
85db7e7077 | ||
|
|
9b1d2d5b88 | ||
|
|
e8621de3f5 | ||
|
|
9942b2ba80 | ||
|
|
2bf125f82a | ||
|
|
69493ac51e | ||
|
|
6504c4bbc8 | ||
|
|
5c1e1ee5ec | ||
|
|
f39ac0764d | ||
|
|
252805ddb4 | ||
|
|
df27597c05 | ||
|
|
fa683ef8b7 | ||
|
|
16b09a676f | ||
|
|
301108ece4 | ||
|
|
5d36cdf485 | ||
|
|
c94ab729dd | ||
|
|
b35f904e58 | ||
|
|
b143042c7f | ||
|
|
10c238c0ea | ||
|
|
ad2f34491c | ||
|
|
d6c51bc456 | ||
|
|
f313d00083 | ||
|
|
2ef55e1e9e | ||
|
|
62402870fd | ||
|
|
7b2a4c9984 | ||
|
|
7958f3efbb | ||
|
|
3e90aff6fd | ||
|
|
192fc3ee2c | ||
|
|
e0e7b14bdc | ||
|
|
4cecc87c55 | ||
|
|
46e7511af9 | ||
|
|
72733bae8a | ||
|
|
38fce95417 | ||
|
|
54de33464d | ||
|
|
6c4c66d2cd | ||
|
|
839dcbbbdb | ||
|
|
05ae55d131 | ||
|
|
d7736e5924 | ||
|
|
30921548ed | ||
|
|
9059a50f93 | ||
|
|
78569e9b91 | ||
|
|
07b8b2ffdd | ||
|
|
2d18829b43 | ||
|
|
f0a9e56741 | ||
|
|
314e627df1 | ||
|
|
b5c79632ef | ||
|
|
0dcc660794 | ||
|
|
0753e4911c | ||
|
|
ff2a0a4bd3 | ||
|
|
5860b70189 | ||
|
|
d84b7fc4d4 | ||
|
|
1873d8ec81 | ||
|
|
0c19db01d9 | ||
|
|
2156a9064f | ||
|
|
6e169089f0 | ||
|
|
6855004aa5 | ||
|
|
93d9aaa99c | ||
|
|
e4a3f064de | ||
|
|
9265390164 | ||
|
|
8e6819ae71 | ||
|
|
f95d2bdfd1 | ||
|
|
737b08d130 | ||
|
|
b44024d660 | ||
|
|
d0d6e88e5a | ||
|
|
c647007ccc | ||
|
|
134c8b7ed3 | ||
|
|
4f203eee4a | ||
|
|
bb065beaa6 | ||
|
|
8481e5c08a | ||
|
|
7276a1fd8c | ||
|
|
7d18988317 | ||
|
|
68afcd16e4 | ||
|
|
72e336445a | ||
|
|
3e658c4782 | ||
|
|
e7d3b43db0 | ||
|
|
6683606449 | ||
|
|
7bcc2a2762 | ||
|
|
c04fa30944 |
@@ -57,6 +57,16 @@ parameters:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Executors
|
||||
executors:
|
||||
linux-arm:
|
||||
resource_class: electronjs/linux-arm
|
||||
machine: true
|
||||
|
||||
linux-arm64:
|
||||
resource_class: electronjs/linux-arm64
|
||||
machine: true
|
||||
|
||||
# The config expects the following environment variables to be set:
|
||||
# - "SLACK_WEBHOOK" Slack hook URL to send notifications.
|
||||
#
|
||||
@@ -239,7 +249,14 @@ step-maybe-cleanup-arm64-mac: &step-maybe-cleanup-arm64-mac
|
||||
killall Safari || echo "No Safari processes left running"
|
||||
rm -rf ~/Library/Application\ Support/Electron*
|
||||
rm -rf ~/Library/Application\ Support/electron*
|
||||
elif [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
|
||||
XVFB=/usr/bin/Xvfb
|
||||
/sbin/start-stop-daemon --stop --exec $XVFB || echo "Xvfb not running"
|
||||
pkill electron || echo "electron not running"
|
||||
rm -rf ~/.config/Electron*
|
||||
rm -rf ~/.config/electron*
|
||||
fi
|
||||
|
||||
when: always
|
||||
|
||||
step-checkout-electron: &step-checkout-electron
|
||||
@@ -325,6 +342,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
npm install
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
export GOMA_FALLBACK_ON_AUTH_FAILURE=true
|
||||
third_party/goma/goma_ctl.py ensure_start
|
||||
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
|
||||
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
@@ -531,6 +549,7 @@ step-electron-build: &step-electron-build
|
||||
ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
ninja -C out/Default tools/v8_context_snapshot -j $NUMBER_OF_NINJA_PROCESSES
|
||||
gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
|
||||
(cd out/Default; zip mksnapshot.zip mksnapshot_args clang_x64_v8_arm64/gen/v8/embedded.S)
|
||||
rm -rf out/Default/clang_x64_v8_arm64/gen
|
||||
rm -rf out/Default/clang_x64_v8_arm64/obj
|
||||
rm -rf out/Default/clang_x64/obj
|
||||
@@ -762,7 +781,7 @@ step-verify-mksnapshot: &step-verify-mksnapshot
|
||||
command: |
|
||||
if [ "$IS_ASAN" != "1" ]; then
|
||||
cd src
|
||||
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
|
||||
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots
|
||||
else
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
|
||||
@@ -907,28 +926,6 @@ step-maybe-cross-arch-snapshot-store: &step-maybe-cross-arch-snapshot-store
|
||||
path: src/cross-arch-snapshots
|
||||
destination: cross-arch-snapshots
|
||||
|
||||
step-maybe-trigger-arm-test: &step-maybe-trigger-arm-test
|
||||
run:
|
||||
name: Trigger an arm test on VSTS if applicable
|
||||
command: |
|
||||
cd src
|
||||
# Only run for non-fork prs
|
||||
if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then
|
||||
#Trigger VSTS job, passing along CircleCI job number and branch to build
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
if [ x"$MAS_BUILD" == x"true" ]; then
|
||||
export DEVOPS_BUILD="electron-mas-arm64-testing"
|
||||
else
|
||||
export DEVOPS_BUILD="electron-osx-arm64-testing"
|
||||
fi
|
||||
echo "Triggering $DEVOPS_BUILD build on Azure DevOps"
|
||||
node electron/script/release/ci-release-build.js --job=$DEVOPS_BUILD --ci=DevOps --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
|
||||
else
|
||||
echo "Triggering electron-$TARGET_ARCH-testing build on VSTS"
|
||||
node electron/script/release/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
|
||||
fi
|
||||
fi
|
||||
|
||||
step-maybe-generate-typescript-defs: &step-maybe-generate-typescript-defs
|
||||
run:
|
||||
name: Generate type declarations
|
||||
@@ -1343,7 +1340,7 @@ steps-tests: &steps-tests
|
||||
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split)) 2>&1 | $ASAN_SYMBOLIZE
|
||||
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split)) 2>&1 | $ASAN_SYMBOLIZE
|
||||
else
|
||||
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
|
||||
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
|
||||
export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true
|
||||
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging)
|
||||
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging)
|
||||
@@ -1634,9 +1631,6 @@ commands:
|
||||
steps:
|
||||
- *step-save-out-cache
|
||||
|
||||
# Trigger tests on arm hardware if needed
|
||||
- *step-maybe-trigger-arm-test
|
||||
|
||||
- *step-maybe-notify-slack-failure
|
||||
|
||||
electron-publish:
|
||||
@@ -1980,7 +1974,7 @@ jobs:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
steps:
|
||||
- electron-build:
|
||||
persist: false
|
||||
persist: true
|
||||
checkout: true
|
||||
use-out-cache: false
|
||||
|
||||
@@ -2039,7 +2033,7 @@ jobs:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
steps:
|
||||
- electron-build:
|
||||
persist: false
|
||||
persist: true
|
||||
checkout: true
|
||||
use-out-cache: false
|
||||
|
||||
@@ -2436,6 +2430,24 @@ jobs:
|
||||
<<: *env-send-slack-notifications
|
||||
<<: *steps-verify-ffmpeg
|
||||
|
||||
linux-arm-testing-tests:
|
||||
executor: linux-arm
|
||||
environment:
|
||||
<<: *env-arm
|
||||
<<: *env-global
|
||||
<<: *env-headless-testing
|
||||
<<: *env-stack-dumping
|
||||
<<: *steps-tests
|
||||
|
||||
linux-arm64-testing-tests:
|
||||
executor: linux-arm64
|
||||
environment:
|
||||
<<: *env-arm64
|
||||
<<: *env-global
|
||||
<<: *env-headless-testing
|
||||
<<: *env-stack-dumping
|
||||
<<: *steps-tests
|
||||
|
||||
osx-testing-x64-tests:
|
||||
<<: *machine-mac-large
|
||||
environment:
|
||||
@@ -2688,8 +2700,23 @@ workflows:
|
||||
- linux-ia32-testing
|
||||
|
||||
- linux-arm-testing
|
||||
- linux-arm-testing-tests:
|
||||
filters:
|
||||
branches:
|
||||
# Do not run this on forked pull requests
|
||||
ignore: /pull\/[0-9]+/
|
||||
requires:
|
||||
- linux-arm-testing
|
||||
|
||||
- linux-arm64-testing
|
||||
- linux-arm64-testing-tests:
|
||||
filters:
|
||||
branches:
|
||||
# Do not run this on forked pull requests
|
||||
ignore: /pull\/[0-9]+/
|
||||
requires:
|
||||
- linux-arm64-testing
|
||||
|
||||
- linux-arm64-testing-gn-check:
|
||||
requires:
|
||||
- linux-checkout-fast
|
||||
|
||||
8
BUILD.gn
8
BUILD.gn
@@ -1,6 +1,7 @@
|
||||
import("//build/config/locales.gni")
|
||||
import("//build/config/ui.gni")
|
||||
import("//build/config/win/manifest.gni")
|
||||
import("//components/os_crypt/features.gni")
|
||||
import("//components/spellcheck/spellcheck_build_features.gni")
|
||||
import("//content/public/app/mac_helpers.gni")
|
||||
import("//extensions/buildflags/buildflags.gni")
|
||||
@@ -292,7 +293,7 @@ templated_file("electron_version_header") {
|
||||
action("electron_fuses") {
|
||||
script = "build/fuses/build.py"
|
||||
|
||||
inputs = [ "build/fuses/fuses.json" ]
|
||||
inputs = [ "build/fuses/fuses.json5" ]
|
||||
|
||||
outputs = [
|
||||
"$target_gen_dir/fuses.h",
|
||||
@@ -331,6 +332,7 @@ source_set("electron_lib") {
|
||||
"//components/network_hints/common:mojo_bindings",
|
||||
"//components/network_hints/renderer",
|
||||
"//components/network_session_configurator/common",
|
||||
"//components/os_crypt",
|
||||
"//components/pref_registry",
|
||||
"//components/prefs",
|
||||
"//components/upload_list",
|
||||
@@ -678,6 +680,10 @@ source_set("electron_lib") {
|
||||
]
|
||||
libs += [ "uxtheme.lib" ]
|
||||
}
|
||||
|
||||
if (allow_runtime_configurable_key_storage) {
|
||||
defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ]
|
||||
}
|
||||
}
|
||||
|
||||
electron_paks("packed_resources") {
|
||||
|
||||
@@ -22,7 +22,7 @@ Issues are created [here](https://github.com/electron/electron/issues/new).
|
||||
|
||||
### Issue Closure
|
||||
|
||||
Bug reports will be closed if the issue has been inactive and the latest affected version no longer receives support. At the moment, Electron maintains its three latest major versions, with a new major version being released every 12 weeks. (For more information on Electron's release cadence, see [this blog post](https://electronjs.org/blog/12-week-cadence).)
|
||||
Bug reports will be closed if the issue has been inactive and the latest affected version no longer receives support. At the moment, Electron maintains its three latest major versions, with a new major version being released every 8 weeks. (For more information on Electron's release cadence, see [this blog post](https://electronjs.org/blog/8-week-cadence).)
|
||||
|
||||
_If an issue has been closed and you still feel it's relevant, feel free to ping a maintainer or add a comment!_
|
||||
|
||||
|
||||
7
DEPS
7
DEPS
@@ -10,17 +10,18 @@ gclient_gn_args = [
|
||||
'checkout_openxr',
|
||||
'checkout_google_benchmark',
|
||||
'mac_xcode_version',
|
||||
'generate_location_tags',
|
||||
]
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'91.0.4472.69',
|
||||
'91.0.4472.164',
|
||||
'node_version':
|
||||
'v14.16.0',
|
||||
'nan_version':
|
||||
'v2.14.2',
|
||||
'squirrel.mac_version':
|
||||
'cdc0729c8bf8576bfef18629186e1e9ecf1b0d9f',
|
||||
'0e5d146ba13101a1302d59ea6e6e0b3cace4ae38',
|
||||
|
||||
'pyyaml_version': '3.12',
|
||||
|
||||
@@ -52,6 +53,8 @@ vars = {
|
||||
|
||||
'mac_xcode_version': 'default',
|
||||
|
||||
'generate_location_tags': False,
|
||||
|
||||
# To allow running hooks without parsing the DEPS tree
|
||||
'process_deps': True,
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
13.0.1
|
||||
13.5.1
|
||||
@@ -28,3 +28,8 @@ libcxx_abi_unstable = false
|
||||
enable_pseudolocales = false
|
||||
|
||||
is_cfi = false
|
||||
|
||||
# Make application name configurable at runtime for cookie crypto
|
||||
allow_runtime_configurable_key_storage = true
|
||||
|
||||
enable_cet_shadow_stack = false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from collections import OrderedDict
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
@@ -49,8 +50,8 @@ const volatile char kFuseWire[] = { /* sentinel */ {sentinel}, /* fuse_version *
|
||||
}
|
||||
"""
|
||||
|
||||
with open(os.path.join(dir_path, "fuses.json"), 'r') as f:
|
||||
fuse_defaults = json.load(f)
|
||||
with open(os.path.join(dir_path, "fuses.json5"), 'r') as f:
|
||||
fuse_defaults = json.loads(''.join(line for line in f.readlines() if not line.strip()[0] == "/"), object_pairs_hook=OrderedDict)
|
||||
|
||||
fuse_version = fuse_defaults['_version']
|
||||
del fuse_defaults['_version']
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
"_comment": "Modifying the fuse schema in any breaking way should result in the _version prop being incremented. NEVER remove a fuse or change its meaning, instead mark it as removed with 'r'",
|
||||
"_schema": "0 == off, 1 == on, r == removed fuse",
|
||||
"_version": 1,
|
||||
"run_as_node": "1"
|
||||
"run_as_node": "1",
|
||||
"cookie_encryption": "0"
|
||||
}
|
||||
@@ -16,5 +16,5 @@ try:
|
||||
subprocess.check_output(args, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_msg = "NPM script '{}' failed with code '{}':\n".format(sys.argv[2], e.returncode)
|
||||
print(error_msg + e.output.decode('ascii'))
|
||||
print(error_msg + e.output.decode('utf8'))
|
||||
sys.exit(e.returncode)
|
||||
|
||||
@@ -66,8 +66,11 @@ static_library("chrome") {
|
||||
"//chrome/browser/extensions/global_shortcut_listener_win.cc",
|
||||
"//chrome/browser/extensions/global_shortcut_listener_win.h",
|
||||
"//chrome/browser/icon_loader_win.cc",
|
||||
"//chrome/browser/ui/frame/window_frame_util.h",
|
||||
"//chrome/browser/ui/view_ids.h",
|
||||
"//chrome/browser/win/chrome_process_finder.cc",
|
||||
"//chrome/browser/win/chrome_process_finder.h",
|
||||
"//chrome/browser/win/titlebar_config.h",
|
||||
"//chrome/child/v8_crashpad_support_win.cc",
|
||||
"//chrome/child/v8_crashpad_support_win.h",
|
||||
]
|
||||
@@ -145,6 +148,8 @@ static_library("chrome") {
|
||||
|
||||
if (enable_color_chooser) {
|
||||
sources += [
|
||||
"//chrome/browser/devtools/devtools_eye_dropper.cc",
|
||||
"//chrome/browser/devtools/devtools_eye_dropper.h",
|
||||
"//chrome/browser/platform_util.cc",
|
||||
"//chrome/browser/platform_util.h",
|
||||
"//chrome/browser/ui/browser_dialogs.h",
|
||||
@@ -345,17 +350,13 @@ source_set("plugins") {
|
||||
sources += [
|
||||
"//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc",
|
||||
"//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.cc",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.h",
|
||||
"//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc",
|
||||
"//chrome/renderer/pepper/pepper_shared_memory_message_filter.h",
|
||||
]
|
||||
if (enable_pdf_viewer) {
|
||||
sources += [
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.cc",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.h",
|
||||
]
|
||||
if (enable_pdf_viewer) {
|
||||
deps += [ "//components/pdf/renderer" ]
|
||||
}
|
||||
deps += [ "//components/pdf/renderer" ]
|
||||
}
|
||||
deps += [
|
||||
"//components/strings",
|
||||
|
||||
@@ -1193,8 +1193,8 @@ badge.
|
||||
|
||||
On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher.
|
||||
|
||||
**Note:** Unity launcher requires the existence of a `.desktop` file to work,
|
||||
for more information please read [Desktop Environment Integration][unity-requirement].
|
||||
**Note:** Unity launcher requires a `.desktop` file to work. For more information,
|
||||
please read the [Unity integration documentation][unity-requirement].
|
||||
|
||||
### `app.getBadgeCount()` _Linux_ _macOS_
|
||||
|
||||
@@ -1432,8 +1432,8 @@ An `Integer` property that returns the badge count for current app. Setting the
|
||||
|
||||
On macOS, setting this with any nonzero integer shows on the dock icon. On Linux, this property only works for Unity launcher.
|
||||
|
||||
**Note:** Unity launcher requires the existence of a `.desktop` file to work,
|
||||
for more information please read [Desktop Environment Integration][unity-requirement].
|
||||
**Note:** Unity launcher requires a `.desktop` file to work. For more information,
|
||||
please read the [Unity integration documentation][unity-requirement].
|
||||
|
||||
**Note:** On macOS, you need to ensure that your application has the permission
|
||||
to display notifications for this property to take effect.
|
||||
@@ -1461,7 +1461,7 @@ A `Boolean` property that returns `true` if the app is packaged, `false` otherw
|
||||
[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme
|
||||
[handoff]: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html
|
||||
[activity-type]: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType
|
||||
[unity-requirement]: ../tutorial/desktop-environment-integration.md#unity-launcher
|
||||
[unity-requirement]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
|
||||
[mas-builds]: ../tutorial/mac-app-store-submission-guide.md
|
||||
[Squirrel-Windows]: https://github.com/Squirrel/Squirrel.Windows
|
||||
[JumpListBeginListMSDN]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378398(v=vs.85).aspx
|
||||
|
||||
@@ -43,7 +43,7 @@ The installer generated with Squirrel will create a shortcut icon with an
|
||||
same ID for your app with `app.setAppUserModelId` API, otherwise Windows will
|
||||
not be able to pin your app properly in task bar.
|
||||
|
||||
Unlike Squirrel.Mac, Windows can host updates on S3 or any other static file host.
|
||||
Like Squirrel.Mac, Windows can host updates on S3 or any other static file host.
|
||||
You can read the documents of [Squirrel.Windows][squirrel-windows] to get more details
|
||||
about how Squirrel.Windows works.
|
||||
|
||||
|
||||
@@ -187,9 +187,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
* `parent` BrowserWindow (optional) - Specify parent window. Default is `null`.
|
||||
* `modal` Boolean (optional) - Whether this is a modal window. This only works when the
|
||||
window is a child window. Default is `false`.
|
||||
* `acceptFirstMouse` Boolean (optional) - Whether the web view accepts a single
|
||||
mouse-down event that simultaneously activates the window. Default is
|
||||
`false`.
|
||||
* `acceptFirstMouse` Boolean (optional) - Whether clicking an inactive window will also
|
||||
click through to the web contents. Default is `false` on macOS. This option is not
|
||||
configurable on other platforms.
|
||||
* `disableAutoHideCursor` Boolean (optional) - Whether to hide cursor when typing.
|
||||
Default is `false`.
|
||||
* `autoHideMenuBar` Boolean (optional) - Auto hide the menu bar unless the `Alt`
|
||||
@@ -213,16 +213,13 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
* `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default.
|
||||
* `active` - The backdrop should always appear active.
|
||||
* `inactive` - The backdrop should always appear inactive.
|
||||
* `titleBarStyle` String (optional) - The style of window title bar.
|
||||
* `titleBarStyle` String (optional) _macOS_ _Windows_ - The style of window title bar.
|
||||
Default is `default`. Possible values are:
|
||||
* `default` - Results in the standard gray opaque Mac title
|
||||
bar.
|
||||
* `hidden` - Results in a hidden title bar and a full size content window, yet
|
||||
the title bar still has the standard window controls ("traffic lights") in
|
||||
the top left.
|
||||
* `hiddenInset` - Results in a hidden title bar with an alternative look
|
||||
* `default` - Results in the standard title bar for macOS or Windows respectively.
|
||||
* `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (“traffic lights”) in the top left. On Windows, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown.
|
||||
* `hiddenInset` - Only on macOS, results in a hidden title bar with an alternative look
|
||||
where the traffic light buttons are slightly more inset from the window edge.
|
||||
* `customButtonsOnHover` - Results in a hidden title bar and a full size
|
||||
* `customButtonsOnHover` - Only on macOS, results in a hidden title bar and a full size
|
||||
content window, the traffic light buttons will display when being hovered
|
||||
over in the top left of the window. **Note:** This option is currently
|
||||
experimental.
|
||||
@@ -339,7 +336,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
more details.
|
||||
* `contextIsolation` Boolean (optional) - Whether to run Electron APIs and
|
||||
the specified `preload` script in a separate JavaScript context. Defaults
|
||||
to `false`. The context that the `preload` script runs in will only have
|
||||
to `true`. The context that the `preload` script runs in will only have
|
||||
access to its own dedicated `document` and `window` globals, as well as
|
||||
its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.),
|
||||
which are all invisible to the loaded content. The Electron API will only
|
||||
@@ -351,8 +348,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
context in the dev tools by selecting the 'Electron Isolated Context'
|
||||
entry in the combo box at the top of the Console tab.
|
||||
* `worldSafeExecuteJavaScript` Boolean (optional) - If true, values returned from `webFrame.executeJavaScript` will be sanitized to ensure JS values
|
||||
can't unsafely cross between worlds when using `contextIsolation`. The default
|
||||
is `false`. In Electron 12, the default will be changed to `true`. _Deprecated_
|
||||
can't unsafely cross between worlds when using `contextIsolation`. Defaults to `true`. _Deprecated_
|
||||
* `nativeWindowOpen` Boolean (optional) - Whether to use native
|
||||
`window.open()`. Defaults to `false`. Child windows will always have node
|
||||
integration disabled unless `nodeIntegrationInSubFrames` is true. **Note:** This option is currently
|
||||
@@ -404,6 +400,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
contain the layout of the document—without requiring scrolling. Enabling
|
||||
this will cause the `preferred-size-changed` event to be emitted on the
|
||||
`WebContents` when the preferred size changes. Default is `false`.
|
||||
* `titleBarOverlay` [OverlayOptions](structures/overlay-options.md) | Boolean (optional) - When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`. On Windows, the [OverlayOptions](structures/overlay-options.md) can be used instead of a boolean to specify colors for the overlay.
|
||||
|
||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||
@@ -986,7 +983,7 @@ the player itself we would call this function with arguments of 16/9 and
|
||||
are within the content view--only that they exist. Sum any extra width and
|
||||
height areas you have within the overall content view.
|
||||
|
||||
The aspect ratio is not respected when window is resized programmingly with
|
||||
The aspect ratio is not respected when window is resized programmatically with
|
||||
APIs like `win.setSize`.
|
||||
|
||||
#### `win.setBackgroundColor(backgroundColor)`
|
||||
@@ -1810,3 +1807,5 @@ removed in future Electron releases.
|
||||
[window-levels]: https://developer.apple.com/documentation/appkit/nswindow/level
|
||||
[chrome-content-scripts]: https://developer.chrome.com/extensions/content_scripts#execution-environment
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
|
||||
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
|
||||
|
||||
@@ -71,7 +71,7 @@ const request = net.request({
|
||||
|
||||
Returns:
|
||||
|
||||
* `response` IncomingMessage - An object representing the HTTP response message.
|
||||
* `response` [IncomingMessage](incoming-message.md) - An object representing the HTTP response message.
|
||||
|
||||
#### Event: 'login'
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ When `contextIsolation` is enabled in your `webPreferences` (this is the default
|
||||
|
||||
The `contextBridge` module has the following methods:
|
||||
|
||||
### `contextBridge.exposeInMainWorld(apiKey, api)` _Experimental_
|
||||
### `contextBridge.exposeInMainWorld(apiKey, api)`
|
||||
|
||||
* `apiKey` String - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`.
|
||||
* `api` any - Your API, more information on what this API can be and how it works is available below.
|
||||
@@ -50,7 +50,7 @@ The `contextBridge` module has the following methods:
|
||||
|
||||
### API
|
||||
|
||||
The `api` provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api-experimental) must be a `Function`, `String`, `Number`, `Array`, `Boolean`, or an object
|
||||
The `api` provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api) must be a `Function`, `String`, `Number`, `Array`, `Boolean`, or 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**. Any data / primitives sent in
|
||||
|
||||
@@ -24,7 +24,7 @@ The `dialog` module has the following methods:
|
||||
* `buttonLabel` String (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
* `properties` String[] (optional) - Contains which features the dialog should
|
||||
* `properties` String[] (optional) - Contains which features the dialog should
|
||||
use. The following values are supported:
|
||||
* `openFile` - Allow files to be selected.
|
||||
* `openDirectory` - Allow directories to be selected.
|
||||
@@ -87,7 +87,7 @@ dialog.showOpenDialogSync(mainWindow, {
|
||||
* `buttonLabel` String (optional) - Custom label for the confirmation button, when
|
||||
left empty the default label will be used.
|
||||
* `filters` [FileFilter[]](structures/file-filter.md) (optional)
|
||||
* `properties` String[] (optional) - Contains which features the dialog should
|
||||
* `properties` String[] (optional) - Contains which features the dialog should
|
||||
use. The following values are supported:
|
||||
* `openFile` - Allow files to be selected.
|
||||
* `openDirectory` - Allow directories to be selected.
|
||||
@@ -112,7 +112,7 @@ Returns `Promise<Object>` - Resolve with an object containing the following:
|
||||
|
||||
* `canceled` Boolean - whether or not the dialog was canceled.
|
||||
* `filePaths` String[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array.
|
||||
* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).)
|
||||
* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).)
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
@@ -165,7 +165,7 @@ dialog.showOpenDialog(mainWindow, {
|
||||
displayed in front of the filename text field.
|
||||
* `showsTagField` Boolean (optional) _macOS_ - Show the tags input box,
|
||||
defaults to `true`.
|
||||
* `properties` String[] (optional)
|
||||
* `properties` String[] (optional)
|
||||
* `showHiddenFiles` - Show hidden files in dialog.
|
||||
* `createDirectory` _macOS_ - Allow creating new directories from dialog.
|
||||
* `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders,
|
||||
@@ -195,7 +195,7 @@ The `filters` specifies an array of file types that can be displayed, see
|
||||
* `nameFieldLabel` String (optional) _macOS_ - Custom label for the text
|
||||
displayed in front of the filename text field.
|
||||
* `showsTagField` Boolean (optional) _macOS_ - Show the tags input box, defaults to `true`.
|
||||
* `properties` String[] (optional)
|
||||
* `properties` String[] (optional)
|
||||
* `showHiddenFiles` - Show hidden files in dialog.
|
||||
* `createDirectory` _macOS_ - Allow creating new directories from dialog.
|
||||
* `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders,
|
||||
@@ -227,7 +227,7 @@ expanding and collapsing the dialog.
|
||||
`"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless
|
||||
you set an icon using the `"icon"` option. On macOS, both `"warning"` and
|
||||
`"error"` display the same warning icon.
|
||||
* `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array
|
||||
* `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array
|
||||
will result in one button labeled "OK".
|
||||
* `defaultId` Integer (optional) - Index of the button in the buttons array which will
|
||||
be selected by default when the message box opens.
|
||||
@@ -273,7 +273,7 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case
|
||||
`"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless
|
||||
you set an icon using the `"icon"` option. On macOS, both `"warning"` and
|
||||
`"error"` display the same warning icon.
|
||||
* `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array
|
||||
* `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array
|
||||
will result in one button labeled "OK".
|
||||
* `defaultId` Integer (optional) - Index of the button in the buttons array which will
|
||||
be selected by default when the message box opens.
|
||||
|
||||
@@ -18,17 +18,17 @@ const win = new BrowserWindow({ width: 800, height: 600, frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Alternatives on macOS
|
||||
### Alternatives
|
||||
|
||||
There's an alternative way to specify a chromeless window.
|
||||
There's an alternative way to specify a chromeless window on macOS and Windows.
|
||||
Instead of setting `frame` to `false` which disables both the titlebar and window controls,
|
||||
you may want to have the title bar hidden and your content extend to the full window size,
|
||||
yet still preserve the window controls ("traffic lights") for standard window actions.
|
||||
yet still preserve the window controls ("traffic lights" on macOS) for standard window actions.
|
||||
You can do so by specifying the `titleBarStyle` option:
|
||||
|
||||
#### `hidden`
|
||||
|
||||
Results in a hidden title bar and a full size content window, yet the title bar still has the standard window controls (“traffic lights”) in the top left.
|
||||
Results in a hidden title bar and a full size content window. On macOS, the title bar still has the standard window controls (“traffic lights”) in the top left.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
@@ -36,6 +36,8 @@ const win = new BrowserWindow({ titleBarStyle: 'hidden' })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Alternatives on macOS
|
||||
|
||||
#### `hiddenInset`
|
||||
|
||||
Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge.
|
||||
@@ -61,6 +63,35 @@ const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: fa
|
||||
win.show()
|
||||
```
|
||||
|
||||
## Windows Control Overlay
|
||||
|
||||
When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS, using one of the `titleBarStyle`s as described above so
|
||||
that the traffic lights are visible, or using `titleBarStyle: hidden` on Windows, you can access the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and
|
||||
[CSS Environment Variables][overlay-css-env-vars] by setting the `titleBarOverlay` option to true. Specifying `true` will result in an overlay with default system colors.
|
||||
|
||||
On Windows, you can also specify the color of the overlay and its symbols by setting `titleBarOverlay` to an object with the options `color` and `symbolColor`. If an option is not specified, the color will default to its system color for the window control buttons:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: true
|
||||
})
|
||||
win.show()
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: {
|
||||
color: '#2f3241',
|
||||
symbolColor: '#74b1be'
|
||||
}
|
||||
})
|
||||
win.show()
|
||||
```
|
||||
|
||||
## Transparent window
|
||||
|
||||
By setting the `transparent` option to `true`, you can also make the frameless
|
||||
@@ -186,3 +217,5 @@ behave correctly on all platforms you should never use a custom context menu on
|
||||
draggable areas.
|
||||
|
||||
[ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore-options
|
||||
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
|
||||
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
|
||||
|
||||
@@ -162,7 +162,7 @@ const template = [
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideothers' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
|
||||
@@ -531,7 +531,7 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
|
||||
#### `ses.setPermissionCheckHandler(handler)`
|
||||
|
||||
* `handler` Function\<Boolean> | null
|
||||
* `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. Cross origin sub frames making permission checks will pass a `null` webContents to this handler. You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively.
|
||||
* `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. All cross origin sub frames making permission checks will pass a `null` webContents to this handler, while certain other permission checks such as `notifications` checks will always pass `null`. You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively.
|
||||
* `permission` String - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, or `serial`.
|
||||
* `requestingOrigin` String - The origin URL of the permission check
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
|
||||
4
docs/api/structures/overlay-options.md
Normal file
4
docs/api/structures/overlay-options.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# OverlayOptions Object
|
||||
|
||||
* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
|
||||
@@ -14,7 +14,7 @@ Process: [Main](../glossary.md#main-process)
|
||||
* `highlightedIndex` Integer - The index of the item the user touched.
|
||||
* `selectedStyle` String (optional) - Selected item style. Can be `background`, `outline` or `none`. Defaults to `none`.
|
||||
* `overlayStyle` String (optional) - Selected overlay item style. Can be `background`, `outline` or `none`. Defaults to `none`.
|
||||
* `showArrowButtons` Boolean (optional) - Defaults to `false`.
|
||||
* `showArrowButtons` Boolean (optional) - Whether to show arrow buttons. Defaults to `false` and is only shown if `items` is non-empty.
|
||||
* `mode` String (optional) - Can be `fixed` or `free`. The default is `free`.
|
||||
* `continuous` Boolean (optional) - Defaults to `true`.
|
||||
|
||||
|
||||
@@ -45,6 +45,26 @@ returns `null`.
|
||||
Returns `WebContents` | undefined - A WebContents instance with the given ID, or
|
||||
`undefined` if there is no WebContents associated with the given ID.
|
||||
|
||||
### `webContents.fromDevToolsTargetId(targetId)`
|
||||
|
||||
* `targetId` String - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance.
|
||||
|
||||
Returns `WebContents` | undefined - A WebContents instance with the given TargetID, or
|
||||
`undefined` if there is no WebContents associated with the given TargetID.
|
||||
|
||||
When communicating with the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/),
|
||||
it can be useful to lookup a WebContents instance based on its assigned TargetID.
|
||||
|
||||
```js
|
||||
async function lookupTargetId (browserWindow) {
|
||||
const wc = browserWindow.webContents
|
||||
await wc.debugger.attach('1.3')
|
||||
const { targetInfo } = await wc.debugger.sendCommand('Target.getTargetInfo')
|
||||
const { targetId } = targetInfo
|
||||
const targetWebContents = await webContents.fromDevToolsTargetId(targetId)
|
||||
}
|
||||
```
|
||||
|
||||
## Class: WebContents
|
||||
|
||||
> Render and control the contents of a BrowserWindow instance.
|
||||
|
||||
@@ -62,6 +62,11 @@ Sets the maximum and minimum pinch-to-zoom level.
|
||||
> webFrame.setVisualZoomLevelLimits(1, 3)
|
||||
> ```
|
||||
|
||||
> **NOTE**: Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom shortcuts are
|
||||
> controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem roles in the application
|
||||
> Menu. To disable shortcuts, manually [define the Menu](./menu.md#examples) and omit zoom roles
|
||||
> from the definition.
|
||||
|
||||
### `webFrame.setSpellCheckProvider(language, provider)`
|
||||
|
||||
* `language` String
|
||||
|
||||
@@ -154,7 +154,6 @@ response are visible by the time this listener is fired.
|
||||
* `timestamp` Double
|
||||
* `statusLine` String
|
||||
* `statusCode` Integer
|
||||
* `requestHeaders` Record<string, string>
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `callback` Function
|
||||
* `headersReceivedResponse` Object
|
||||
|
||||
@@ -151,12 +151,16 @@ browser plugins. Plugins are disabled by default.
|
||||
### `preload`
|
||||
|
||||
```html
|
||||
<!-- from a file -->
|
||||
<webview src="https://www.github.com/" preload="./test.js"></webview>
|
||||
<!-- or if you want to load from an asar archive -->
|
||||
<webview src="https://www.github.com/" preload="./app.asar/test.js"></webview>
|
||||
```
|
||||
|
||||
A `String` that specifies a script that will be loaded before other scripts run in the guest
|
||||
page. The protocol of script's URL must be either `file:` or `asar:`, because it
|
||||
will be loaded by `require` in guest page under the hood.
|
||||
page. The protocol of script's URL must be `file:` (even when using `asar:` archives) because
|
||||
it will be loaded by Node's `require` under the hood, which treats `asar:` archives as virtual
|
||||
directories.
|
||||
|
||||
When the guest page doesn't have node integration this script will still have
|
||||
access to all Node APIs, but global objects injected by Node will be deleted
|
||||
@@ -718,6 +722,10 @@ Corresponds to the points in time when the spinner of the tab starts spinning.
|
||||
|
||||
Corresponds to the points in time when the spinner of the tab stops spinning.
|
||||
|
||||
### Event: 'did-attach'
|
||||
|
||||
Fired when attached to the embedder web contents.
|
||||
|
||||
### Event: 'dom-ready'
|
||||
|
||||
Fired when document in the given frame is loaded.
|
||||
@@ -838,6 +846,19 @@ this purpose.
|
||||
|
||||
Calling `event.preventDefault()` does __NOT__ have any effect.
|
||||
|
||||
### Event: 'did-start-navigation'
|
||||
|
||||
Returns:
|
||||
|
||||
* `url` String
|
||||
* `isInPlace` Boolean
|
||||
* `isMainFrame` Boolean
|
||||
* `frameProcessId` Integer
|
||||
* `frameRoutingId` Integer
|
||||
|
||||
Emitted when any frame (including main) starts navigating. `isInPlace` will be
|
||||
`true` for in-page navigations.
|
||||
|
||||
### Event: 'did-navigate'
|
||||
|
||||
Returns:
|
||||
@@ -850,6 +871,23 @@ This event is not emitted for in-page navigations, such as clicking anchor links
|
||||
or updating the `window.location.hash`. Use `did-navigate-in-page` event for
|
||||
this purpose.
|
||||
|
||||
### Event: 'did-frame-navigate'
|
||||
|
||||
Returns:
|
||||
|
||||
* `url` String
|
||||
* `httpResponseCode` Integer - -1 for non HTTP navigations
|
||||
* `httpStatusText` String - empty for non HTTP navigations,
|
||||
* `isMainFrame` Boolean
|
||||
* `frameProcessId` Integer
|
||||
* `frameRoutingId` Integer
|
||||
|
||||
Emitted when any frame navigation is done.
|
||||
|
||||
This event is not emitted for in-page navigations, such as clicking anchor links
|
||||
or updating the `window.location.hash`. Use `did-navigate-in-page` event for
|
||||
this purpose.
|
||||
|
||||
### Event: 'did-navigate-in-page'
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -117,15 +117,18 @@ const mainWindow = new BrowserWindow({
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (url === 'about:blank') {
|
||||
return {
|
||||
frame: false,
|
||||
fullscreenable: false,
|
||||
backgroundColor: 'black',
|
||||
webPreferences: {
|
||||
preload: 'my-child-window-preload-script.js'
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
frame: false,
|
||||
fullscreenable: false,
|
||||
backgroundColor: 'black',
|
||||
webPreferences: {
|
||||
preload: 'my-child-window-preload-script.js'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
return { action: 'deny' }
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ files, you need to have built Electron so that it knows which compiler flags
|
||||
were used. There is one required option for the script `--output-dir`, which
|
||||
tells the script which build directory to pull the compilation information
|
||||
from. A typical usage would be:
|
||||
`npm run lint:clang-tiy --out-dir ../out/Testing`
|
||||
`npm run lint:clang-tidy --out-dir ../out/Testing`
|
||||
|
||||
With no filenames provided, all C/C++/Objective-C files will be checked.
|
||||
You can provide a list of files to be checked by passing the filenames after
|
||||
the options:
|
||||
`npm run lint:clang-tiy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc`
|
||||
`npm run lint:clang-tidy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc`
|
||||
|
||||
While `clang-tidy` has a
|
||||
[long list](https://clang.llvm.org/extra/clang-tidy/checks/list.html)
|
||||
|
||||
@@ -25,7 +25,7 @@ You can run `npm run lint` to show any style issues detected by `cpplint` and
|
||||
## C++ and Python
|
||||
|
||||
For C++ and Python, we follow Chromium's [Coding
|
||||
Style](https://www.chromium.org/developers/coding-style). You can use
|
||||
Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md). You can use
|
||||
[clang-format](clang-format.md) to format the C++ code automatically. There is
|
||||
also a script `script/cpplint.py` to check whether all files conform.
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ you prefer a graphical interface.
|
||||
* **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped.
|
||||
|
||||
```text
|
||||
command script import ~/electron/src/tools/lldb/lldbinit.py
|
||||
# e.g: ['~/electron/src/tools/lldb']
|
||||
script sys.path[:0] = ['<...path/to/electron/src/tools/lldb>']
|
||||
script import lldbinit
|
||||
```
|
||||
|
||||
## Attaching to and Debugging Electron
|
||||
|
||||
@@ -22,7 +22,7 @@ function createWindow () {
|
||||
})
|
||||
|
||||
ipcMain.handle('dark-mode:system', () => {
|
||||
nativeTheme.themeSouce = 'system'
|
||||
nativeTheme.themeSource = 'system'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
<p>After launching this application, you should see the system notification.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,21 +3,17 @@ const { app, BrowserWindow, Notification } = require('electron')
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const NOTIFICATION_TITLE = 'Basic Notification'
|
||||
const NOTIFICATION_BODY = 'Notification from the Main process'
|
||||
|
||||
function showNotification () {
|
||||
const notification = {
|
||||
title: 'Basic Notification',
|
||||
body: 'Notification from the Main process'
|
||||
}
|
||||
new Notification(notification).show()
|
||||
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow).then(showNotification)
|
||||
|
||||
@@ -7,11 +7,9 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
<p>After launching this application, you should see the system notification.</p>
|
||||
<p id="output">Click it to see the effect in this interface.</p>
|
||||
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,10 +3,7 @@ const { app, BrowserWindow } = require('electron')
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const myNotification = new Notification('Title', {
|
||||
body: 'Notification from the Renderer process'
|
||||
})
|
||||
const NOTIFICATION_TITLE = 'Title'
|
||||
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
|
||||
const CLICK_MESSAGE = 'Notification clicked!'
|
||||
|
||||
myNotification.onclick = () => {
|
||||
console.log('Notification clicked')
|
||||
}
|
||||
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
|
||||
.onclick = () => document.getElementById("output").innerText = CLICK_MESSAGE
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
<p>Keep an eye on the dock (Mac) or taskbar (Windows, Unity) for this application!</p>
|
||||
<p>It should indicate a progress that advances from 0 to 100%.</p>
|
||||
<p>It should then show indeterminate (Windows) or pin at 100% (other operating systems)
|
||||
briefly and then loop.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,21 +1,39 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let progressInterval
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
win.setProgressBar(0.5)
|
||||
}
|
||||
|
||||
const INCREMENT = 0.03
|
||||
const INTERVAL_DELAY = 100 // ms
|
||||
|
||||
let c = 0
|
||||
progressInterval = setInterval(() => {
|
||||
// update progress bar to next value
|
||||
// values between 0 and 1 will show progress, >1 will show indeterminate or stick at 100%
|
||||
win.setProgressBar(c)
|
||||
|
||||
// increment or reset progress bar
|
||||
if (c < 2) {
|
||||
c += INCREMENT
|
||||
} else {
|
||||
c = (-INCREMENT * 5) // reset to a bit less than 0 to show reset state
|
||||
}
|
||||
}, INTERVAL_DELAY)
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// before the app is terminated, clear both timers
|
||||
app.on('before-quit', () => {
|
||||
clearInterval(progressInterval)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<title>Recent Documents</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<h1>Recent Documents</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
Right click on the app icon to see recent documents.
|
||||
You should see `recently-used.md` added to the list of recent files
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,17 +5,15 @@ const path = require('path')
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const fileName = 'recently-used.md'
|
||||
fs.writeFile(fileName, 'Lorem Ipsum', () => {
|
||||
app.addRecentDocument(path.join(process.cwd(), `${fileName}`))
|
||||
app.addRecentDocument(path.join(__dirname, fileName))
|
||||
})
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
<link rel="stylesheet" type="text/css" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
Click on the title with the <pre>Command</pre> or <pre>Control</pre> key pressed.
|
||||
You should see a popup with the represented file at the top.
|
||||
</p>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,10 +4,7 @@ const os = require('os');
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
|
||||
@@ -16,91 +16,12 @@
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://electronjs.org/docs/api/tray">
|
||||
full API documentation (opens in new window)
|
||||
full API documentation
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<button id="put-in-tray">View Demo</button>
|
||||
<span id="tray-countdown"></span>
|
||||
</div>
|
||||
<p>
|
||||
The demo button sends a message to the main process using the
|
||||
<code>ipc</code> module. In the main process the app is told to
|
||||
place an icon, with a context menu, in the tray.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this example the tray icon can be removed by clicking 'Remove' in
|
||||
the context menu or selecting the demo button again.
|
||||
</p>
|
||||
<h5>Main Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const path = require('path')
|
||||
const {ipcMain, app, Menu, Tray} = require('electron')
|
||||
|
||||
let appIcon = null
|
||||
|
||||
ipcMain.on('put-in-tray', (event) => {
|
||||
const iconName = process.platform === 'win32' ? 'windows-icon.png' : 'iconTemplate.png'
|
||||
const iconPath = path.join(__dirname, iconName)
|
||||
appIcon = new Tray(iconPath)
|
||||
|
||||
const contextMenu = Menu.buildFromTemplate([{
|
||||
label: 'Remove',
|
||||
click: () => {
|
||||
event.sender.send('tray-removed')
|
||||
}
|
||||
}])
|
||||
|
||||
appIcon.setToolTip('Electron Demo in the tray.')
|
||||
appIcon.setContextMenu(contextMenu)
|
||||
})
|
||||
|
||||
ipcMain.on('remove-tray', () => {
|
||||
appIcon.destroy()
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (appIcon) appIcon.destroy()
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre>
|
||||
<code>
|
||||
const ipc = require('electron').ipcRenderer
|
||||
|
||||
const trayBtn = document.getElementById('put-in-tray')
|
||||
let trayOn = false
|
||||
|
||||
trayBtn.addEventListener('click', function (event) {
|
||||
if (trayOn) {
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
ipc.send('remove-tray')
|
||||
} else {
|
||||
trayOn = true
|
||||
const message = 'Click demo again to remove.'
|
||||
document.getElementById('tray-countdown').innerHTML = message
|
||||
ipc.send('put-in-tray')
|
||||
}
|
||||
})
|
||||
// Tray removed from context menu on icon
|
||||
ipc.on('tray-removed', function () {
|
||||
ipc.send('remove-tray')
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
})
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Tray support in Linux.</strong>
|
||||
@@ -109,7 +30,7 @@ ipc.on('tray-removed', function () {
|
||||
will need to install <code>libappindicator1</code> to make the
|
||||
tray icon work. See the
|
||||
<a href="https://electronjs.org/docs/api/tray">
|
||||
full API documentation (opens in new window)
|
||||
full API documentation
|
||||
</a>
|
||||
for more details about using Tray on Linux.
|
||||
</p>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,35 +0,0 @@
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const trayBtn = document.getElementById('put-in-tray')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let trayOn = false
|
||||
|
||||
trayBtn.addEventListener('click', function (event) {
|
||||
if (trayOn) {
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
ipcRenderer.send('remove-tray')
|
||||
} else {
|
||||
trayOn = true
|
||||
const message = 'Click demo again to remove.'
|
||||
document.getElementById('tray-countdown').innerHTML = message
|
||||
ipcRenderer.send('put-in-tray')
|
||||
}
|
||||
})
|
||||
// Tray removed from context menu on icon
|
||||
ipcRenderer.on('tray-removed', function () {
|
||||
ipcRenderer.send('remove-tray')
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,92 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>app.setAsDefaultProtocol Demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section>
|
||||
<header>
|
||||
<h1>
|
||||
Protocol Handler
|
||||
</h1>
|
||||
<h3>The <code>app</code> module provides methods for handling protocols.</h3>
|
||||
<p>These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a browser asks to be your default for viewing web pages.</p>
|
||||
<h1>App Default Protocol Demo</h1>
|
||||
|
||||
<p>Open the <a href="https://electronjs.org/docs/api/app">full app API documentation<span class="u-visible-to-screen-reader">(opens in new window)</span></a> in your browser.</p>
|
||||
</header>
|
||||
<p>The protocol API allows us to register a custom protocol and intercept existing protocol requests.</p>
|
||||
<p>These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a
|
||||
browser asks to be your default for viewing web pages.</p>
|
||||
|
||||
<div >
|
||||
<button id="open-in-browser" class="js-container-target demo-toggle-button">Launch current page in browser
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<section id='open-app-link'>
|
||||
<a href="electron-api-demos://open">Now... launch the app from a web link</a>
|
||||
</section>
|
||||
<div >
|
||||
<p>You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app as the default for <code>electron-api-demos://</code>. The demo button above will launch a page in your default browser with a link. Click that link and it will re-launch this app.</p>
|
||||
<h5>Packaging</h5>
|
||||
<p>This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS <code>plist</code> for the app is updated to include the new protocol handler. If you're using <code>electron-packager</code> then you can add the flag <code>--extend-info</code> with a path to the <code>plist</code> you've created. The one for this app is below.</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code>
|
||||
const {shell} = require('electron')
|
||||
const path = require('path')
|
||||
const protocolHandlerBtn = document.getElementById('protocol-handler')
|
||||
protocolHandlerBtn.addEventListener('click', () => {
|
||||
const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
|
||||
const pagePath = path.join('file://', pageDirectory, '../../sections/system/protocol-link.html')
|
||||
shell.openExternal(pagePath)
|
||||
})
|
||||
</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code>
|
||||
const {app, dialog} = require('electron')
|
||||
const path = require('path')
|
||||
<p>Open the <a href="https://www.electronjs.org/docs/api/protocol">full protocol API documentation</a> in your
|
||||
browser.</p>
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos')
|
||||
}
|
||||
-----
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
<h3>Demo</h3>
|
||||
<p>
|
||||
First: Launch current page in browser
|
||||
<button id="open-in-browser" class="js-container-target demo-toggle-button">
|
||||
Click to Launch Browser
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</code></pre>
|
||||
<h5>macOS plist</h5>
|
||||
<pre><code>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
require('./renderer.js')
|
||||
</script>
|
||||
</section>
|
||||
<p>
|
||||
Then: Launch the app from a web link!
|
||||
<a href="electron-fiddle://open">Click here to launch the app</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
<p>You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app
|
||||
as the default for <code>electron-fiddle://</code>. The demo button above will launch a page in your default
|
||||
browser with a link. Click that link and it will re-launch this app.</p>
|
||||
|
||||
|
||||
<h3>Packaging</h3>
|
||||
<p>This feature will only work on macOS when your app is packaged. It will not work when you're launching it in
|
||||
development from the command-line. When you package your app you'll need to make sure the macOS <code>plist</code>
|
||||
for the app is updated to include the new protocol handler. If you're using <code>electron-packager</code> then you
|
||||
can add the flag <code>--extend-info</code> with a path to the <code>plist</code> you've created. The one for this
|
||||
app is below:</p>
|
||||
|
||||
<p>
|
||||
<h5>macOS plist</h5>
|
||||
<pre><code>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
|
||||
<!-- You can also require other files to run in this process -->
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,10 +1,39 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, dialog } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, shell } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
let mainWindow;
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle')
|
||||
}
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||
mainWindow.focus()
|
||||
}
|
||||
})
|
||||
|
||||
// Create mainWindow, load the rest of the app, etc...
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
}
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
@@ -12,58 +41,23 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-api-demos')
|
||||
}
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
// Handle window controls via IPC
|
||||
ipcMain.on('shell:open', () => {
|
||||
const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
|
||||
const pagePath = path.join('file://', pageDirectory, 'index.html')
|
||||
shell.openExternal(pagePath)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// All of the Node.js APIs are available in the preload process.
|
||||
// It has the same sandbox as a Chrome extension.
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
|
||||
// Set up context bridge between the renderer process and the main process
|
||||
contextBridge.exposeInMainWorld(
|
||||
'shell',
|
||||
{
|
||||
open: () => ipcRenderer.send('shell:open'),
|
||||
}
|
||||
)
|
||||
@@ -1,14 +1,8 @@
|
||||
const { shell } = require('electron')
|
||||
const path = require('path')
|
||||
// This file is required by the index.html file and will
|
||||
// be executed in the renderer process for that window.
|
||||
// All APIs exposed by the context bridge are available here.
|
||||
|
||||
const openInBrowserButton = document.getElementById('open-in-browser')
|
||||
const openAppLink = document.getElementById('open-app-link')
|
||||
// Hides openAppLink when loaded inside Electron
|
||||
openAppLink.style.display = 'none'
|
||||
|
||||
openInBrowserButton.addEventListener('click', () => {
|
||||
console.log('clicked')
|
||||
const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
|
||||
const pagePath = path.join('file://', pageDirectory, 'index.html')
|
||||
shell.openExternal(pagePath)
|
||||
})
|
||||
// Binds the buttons to the context bridge API.
|
||||
document.getElementById('open-in-browser').addEventListener('click', () => {
|
||||
shell.open();
|
||||
});
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 32 KiB |
0
docs/images/versioning-sketch-2.png
Executable file → Normal file
0
docs/images/versioning-sketch-2.png
Executable file → Normal file
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
@@ -88,14 +88,15 @@ without meaning any harm:
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
Note that up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required
|
||||
as well. However, it should not be used anymore if it can be avoided.
|
||||
|
||||
To see all of this in action, check out Electron Fiddle's source code,
|
||||
[especially its `electron-forge` configuration
|
||||
file](https://github.com/electron/fiddle/blob/master/forge.config.js).
|
||||
@@ -133,7 +134,7 @@ are likely using [`electron-packager`], which includes [`electron-osx-sign`] and
|
||||
|
||||
If you're using Packager's API, you can pass [in configuration that both signs
|
||||
and notarizes your
|
||||
application](https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html).
|
||||
application](https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html).
|
||||
|
||||
```js
|
||||
const packager = require('electron-packager')
|
||||
@@ -165,14 +166,15 @@ without meaning any harm:
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
Up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required
|
||||
as well. However, it should not be used anymore if it can be avoided.
|
||||
|
||||
## Mac App Store
|
||||
|
||||
See the [Mac App Store Guide].
|
||||
|
||||
@@ -159,7 +159,7 @@ function createWindow () {
|
||||
})
|
||||
|
||||
ipcMain.handle('dark-mode:system', () => {
|
||||
nativeTheme.themeSouce = 'system'
|
||||
nativeTheme.themeSource = 'system'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -200,6 +200,6 @@ Run the example using Electron Fiddle and then click the "Toggle Dark Mode" butt
|
||||
[system-wide-dark-mode]: https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/dark-mode/
|
||||
[electron-forge]: https://www.electronforge.io/
|
||||
[electron-packager]: https://github.com/electron/electron-packager
|
||||
[packager-darwindarkmode-api]: https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html#darwindarkmodesupport
|
||||
[packager-darwindarkmode-api]: https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html#darwindarkmodesupport
|
||||
[prefers-color-scheme]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
|
||||
[event-listeners]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# Desktop Environment Integration
|
||||
|
||||
Different operating systems provide different features for integrating desktop
|
||||
applications into their desktop environments. For example, on Windows,
|
||||
applications can put shortcuts in the JumpList of task bar, and on Mac,
|
||||
applications can put a custom menu in the dock menu.
|
||||
|
||||
This guide explains how to integrate your application into those desktop
|
||||
environments with Electron APIs.
|
||||
|
||||
## Notifications
|
||||
|
||||
See the [Notifications documentation](notifications.md).
|
||||
|
||||
## Recent Documents
|
||||
|
||||
See [Recent Documents documentation](recent-documents.md).
|
||||
|
||||
## Progress Bar
|
||||
|
||||
See the [Progress Bar documentation](progress-bar.md).
|
||||
|
||||
## Unity Launcher
|
||||
|
||||
See the [Unity Launcher documentation][unity-launcher].
|
||||
|
||||
## Represented File for macOS Window
|
||||
|
||||
See the [Represented File documentation](represented-file.md).
|
||||
|
||||
## Dragging files out of the window
|
||||
|
||||
See the [Native File Drag & Drop documentation](native-file-drag-drop.md).
|
||||
|
||||
[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
|
||||
@@ -1,22 +1,27 @@
|
||||
# Electron Release Timelines
|
||||
|
||||
Special notes:
|
||||
|
||||
* The `-beta.1` and `stable` dates are our solid release dates.
|
||||
* We strive for weekly beta releases, however we often release more betas than scheduled.
|
||||
* All dates are our goals but there may be reasons for adjusting the stable deadline, such as security bugs.
|
||||
* Take a look at the [5.0.0 Timeline blog post](https://electronjs.org/blog/electron-5-0-timeline) for info about publicizing our release dates.
|
||||
* Since Electron 6.0, we've been targeting every other Chromium version and releasing our stable on the same day as Chrome stable. You can reference Chromium's release schedule [here](https://chromiumdash.appspot.com/schedule). See [Electron's new release cadence blog post](https://www.electronjs.org/blog/12-week-cadence) for more details on our release schedule.
|
||||
* Electron 15.0 only will include a special Alpha release. Starting in Electron 16.0, we will release on an 8-week cadence. See [Electron's new 8-week cadence blog post](https://www.electronjs.org/blog/8-week-cadence) for more details.
|
||||
|
||||
| Version | -beta.1 | Stable | Chrome | Node |
|
||||
| ------- | ------- | ------ | ------ | ---- |
|
||||
| 2.0.0 | 2018-02-21 | 2018-05-01 | M61 | v8.9 |
|
||||
| 3.0.0 | 2018-06-21 | 2018-09-18 | M66 | v10.2 |
|
||||
| 4.0.0 | 2018-10-11 | 2018-12-20 | M69 | v10.11 |
|
||||
| 5.0.0 | 2019-01-22 | 2019-04-24 | M73 | v12.0 |
|
||||
| 6.0.0 | 2019-05-01 | 2019-07-30 | M76 | v12.4 |
|
||||
| 7.0.0 | 2019-08-01 | 2019-10-22 | M78 | v12.8 |
|
||||
| 8.0.0 | 2019-10-24 | 2020-02-04 | M80 | v12.13 |
|
||||
| 9.0.0 | 2020-02-06 | 2020-05-19 | M83 | v12.14 |
|
||||
| 10.0.0 | 2020-05-21 | 2020-08-25 | M85 | v12.16 |
|
||||
| 11.0.0 | 2020-08-27 | 2020-11-17 | M87 | v12.18 |
|
||||
| 12.0.0 | 2020-11-19 | 2021-03-02 | M89 | v14.16 |
|
||||
| 13.0.0 | 2021-03-04 | 2021-05-25 | M91 | v14.x |
|
||||
| Electron | Alpha | Beta | Stable | Chrome | Node |
|
||||
| ------- | ----- | ------- | ------ | ------ | ---- |
|
||||
| 2.0.0 | -- | 2018-Feb-21 | 2018-May-01 | M61 | v8.9 |
|
||||
| 3.0.0 | -- | 2018-Jun-21 | 2018-Sep-18 | M66 | v10.2 |
|
||||
| 4.0.0 | -- | 2018-Oct-11 | 2018-Dec-20 | M69 | v10.11 |
|
||||
| 5.0.0 | -- | 2019-Jan-22 | 2019-Apr-24 | M73 | v12.0 |
|
||||
| 6.0.0 | -- | 2019-May-01 | 2019-Jul-30 | M76 | v12.4 |
|
||||
| 7.0.0 | -- | 2019-Aug-01 | 2019-Oct-22 | M78 | v12.8 |
|
||||
| 8.0.0 | -- | 2019-Oct-24 | 2020-Feb-04 | M80 | v12.13 |
|
||||
| 9.0.0 | -- | 2020-Feb-06 | 2020-May-19 | M83 | v12.14 |
|
||||
| 10.0.0 | -- | 2020-May-21 | 2020-Aug-25 | M85 | v12.16 |
|
||||
| 11.0.0 | -- | 2020-Aug-27 | 2020-Nov-17 | M87 | v12.18 |
|
||||
| 12.0.0 | -- | 2020-Nov-19 | 2021-Mar-02 | M89 | v14.16 |
|
||||
| 13.0.0 | -- | 2021-Mar-04 | 2021-May-25 | M91 | v14.16 |
|
||||
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | TBD |
|
||||
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | TBD |
|
||||
|
||||
@@ -51,4 +51,4 @@ Somewhere in the Electron binary there will be a sequence of bytes that look lik
|
||||
|
||||
To flip a fuse you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like.
|
||||
|
||||
You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json).
|
||||
You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json5).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# In-App Purchase (macOS)
|
||||
# In-App Purchases (macOS)
|
||||
|
||||
## Preparing
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Installation
|
||||
# Advanced Installation Instructions
|
||||
|
||||
To install prebuilt Electron binaries, use [`npm`][npm].
|
||||
The preferred method is to install Electron as a development dependency in your
|
||||
@@ -135,14 +135,18 @@ a text file. A typical cache might look like this:
|
||||
|
||||
## Skip binary download
|
||||
|
||||
When installing the `electron` NPM package, it automatically downloads the electron binary.
|
||||
Under the hood, Electron's JavaScript API binds to a binary that contains its
|
||||
implementations. Because this binary is crucial to the function of any Electron app,
|
||||
it is downloaded by default in the `postinstall` step every time you install `electron`
|
||||
from the npm registry.
|
||||
|
||||
This can sometimes be unnecessary, e.g. in a CI environment, when testing another component.
|
||||
However, if you want to install your project's dependencies but don't need to use
|
||||
Electron functionality, you can set the `ELECTRON_SKIP_BINARY_DOWNLOAD` environment
|
||||
variable to prevent the binary from being downloaded. For instance, this feature can
|
||||
be useful in continuous integration environments when running unit tests that mock
|
||||
out the `electron` module.
|
||||
|
||||
To prevent the binary from being downloaded when you install all npm dependencies you can set the environment variable `ELECTRON_SKIP_BINARY_DOWNLOAD`.
|
||||
E.g.:
|
||||
|
||||
```sh
|
||||
```sh npm2yarn
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD=1 npm install
|
||||
```
|
||||
|
||||
|
||||
@@ -49,11 +49,11 @@ is a great place to get advice from other Electron app developers.
|
||||
the [GitHub issue tracker][issue-tracker] to see if any existing issues match your
|
||||
problem. If not, feel free to fill out our bug report template and submit a new issue.
|
||||
|
||||
[chromium](https://www.chromium.org/)
|
||||
[node](https://nodejs.org/)
|
||||
[mdn-guide](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web)
|
||||
[node-guide](https://nodejs.dev/learn)
|
||||
[comic](https://www.google.com/googlebooks/chrome/)
|
||||
[fiddle](https://electronjs.org/fiddle)
|
||||
[issue-tracker](https://github.com/electron/electron/issues)
|
||||
[discord](https://discord.gg/electron)
|
||||
[chromium]: https://www.chromium.org/
|
||||
[node]: https://nodejs.org/
|
||||
[mdn-guide]: https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web
|
||||
[node-guide]: https://nodejs.dev/learn
|
||||
[comic]: https://www.google.com/googlebooks/chrome/
|
||||
[fiddle]: https://electronjs.org/fiddle
|
||||
[issue-tracker]: https://github.com/electron/electron/issues
|
||||
[discord]: https://discord.gg/electron
|
||||
|
||||
169
docs/tutorial/launch-app-from-url-in-another-app.md
Normal file
169
docs/tutorial/launch-app-from-url-in-another-app.md
Normal file
@@ -0,0 +1,169 @@
|
||||
---
|
||||
title: launch-app-from-URL-in-another-app
|
||||
description: This guide will take you through the process of setting your electron app as the default handler for a specific protocol.
|
||||
slug: launch-app-from-url-in-another-app
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Launching Your Electron App From A URL In Another App
|
||||
|
||||
## Overview
|
||||
|
||||
<!-- ✍ Update this section if you want to provide more details -->
|
||||
|
||||
This guide will take you through the process of setting your electron app as the default
|
||||
handler for a specific [protocol](https://www.electronjs.org/docs/api/protocol).
|
||||
|
||||
By the end of this tutorial, we will have set our app to intercept and handle
|
||||
any clicked URLs that start with a specific protocol. In this guide, the protocol
|
||||
we will use will be "`electron-fiddle://`".
|
||||
|
||||
## Examples
|
||||
|
||||
### Main Process (main.js)
|
||||
|
||||
First we will import the required modules from `electron`. These modules help control our application life and create a native browser window.
|
||||
|
||||
```js
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
```
|
||||
|
||||
Next, we will proceed to register our application to handle all "`electron-fiddle://`" protocols.
|
||||
|
||||
```js
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle')
|
||||
}
|
||||
```
|
||||
|
||||
We will now define the function in charge of creating our browser window and load our application's `index.html` file.
|
||||
|
||||
```js
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
```
|
||||
|
||||
In this next step, we will create our `BrowserWindow` and tell our application how to handle an event in which an external protocol is clicked.
|
||||
|
||||
This code will be different in WindowsOS compared to MacOS and Linux. This is due to Windows requiring additional code in order to open the contents of the protocol link within the same electron instance. Read more about this [here](https://www.electronjs.org/docs/api/app#apprequestsingleinstancelock).
|
||||
|
||||
### Windows code:
|
||||
|
||||
```js
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||
mainWindow.focus()
|
||||
}
|
||||
})
|
||||
|
||||
// Create mainWindow, load the rest of the app, etc...
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### MacOS and Linux code:
|
||||
|
||||
```js
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
```
|
||||
|
||||
Finally, we will add some additional code to handle when someone closes our application
|
||||
|
||||
```js
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
```
|
||||
|
||||
## Important Note:
|
||||
|
||||
### Packaging
|
||||
|
||||
This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS `plist` for the app is updated to include the new protocol handler. If you're using [`electron-packager`](https://github.com/electron/electron-packager) then you
|
||||
can add the flag `--extend-info` with a path to the `plist` you've created. The one for this app is below:
|
||||
|
||||
### Plist
|
||||
|
||||
```XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
After you start your electron app, you can now enter in a URL in your browser that contains the custom protocol, for example `"electron-fiddle://open"` and observe that the application will respond and show an error dialog box.
|
||||
|
||||
<!--
|
||||
Because Electron examples usually require multiple files (HTML, CSS, JS
|
||||
for the main and renderer process, etc.), we use this custom code block
|
||||
for Fiddle (https://www.electronjs.org/fiddle).
|
||||
Please modify any of the files in the referenced folder to fit your
|
||||
example.
|
||||
The content in this codeblock will not be rendered in the website so you
|
||||
can leave it empty.
|
||||
-->
|
||||
|
||||
```fiddle docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app
|
||||
|
||||
```
|
||||
|
||||
<!-- ✍ Explanation of the code below -->
|
||||
@@ -1,4 +1,4 @@
|
||||
# Custom Linux Desktop Launcher Actions
|
||||
# Desktop Launcher Actions (Linux)
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Configuring the macOS Dock
|
||||
# Dock (macOS)
|
||||
|
||||
Electron has APIs to configure the app's icon in the macOS Dock. A macOS-only
|
||||
API exists to create a custom dock menu, but Electron also uses the app dock
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Notifications (Windows, Linux, macOS)
|
||||
# Notifications
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -18,7 +18,7 @@ To show notifications in the Main process, you need to use the
|
||||
|
||||
### Show notifications in the Renderer process
|
||||
|
||||
Assuming you have a working Electron application from the
|
||||
Starting with a working application from the
|
||||
[Quick Start Guide](quick-start.md), add the following line to the
|
||||
`index.html` file before the closing `</body>` tag:
|
||||
|
||||
@@ -26,26 +26,22 @@ Assuming you have a working Electron application from the
|
||||
<script src="renderer.js"></script>
|
||||
```
|
||||
|
||||
and add the `renderer.js` file:
|
||||
...and add the `renderer.js` file:
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/notifications/renderer'
|
||||
const myNotification = new Notification('Title', {
|
||||
body: 'Notification from the Renderer process'
|
||||
})
|
||||
const NOTIFICATION_TITLE = 'Title'
|
||||
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
|
||||
const CLICK_MESSAGE = 'Notification clicked'
|
||||
|
||||
myNotification.onclick = () => {
|
||||
console.log('Notification clicked')
|
||||
}
|
||||
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
|
||||
.onclick = () => console.log(CLICK_MESSAGE)
|
||||
```
|
||||
|
||||
After launching the Electron application, you should see the notification:
|
||||
|
||||

|
||||
|
||||
If you open the Console and then click the notification, you will see the
|
||||
message that was generated after triggering the `onclick` event:
|
||||
|
||||

|
||||
Additionally, if you click on the notification, the DOM will update to show "Notification clicked!".
|
||||
|
||||
### Show notifications in the Main process
|
||||
|
||||
@@ -55,18 +51,17 @@ Starting with a working application from the
|
||||
```javascript fiddle='docs/fiddles/features/notifications/main'
|
||||
const { Notification } = require('electron')
|
||||
|
||||
const NOTIFICATION_TITLE = 'Basic Notification'
|
||||
const NOTIFICATION_BODY = 'Notification from the Main process'
|
||||
|
||||
function showNotification () {
|
||||
const notification = {
|
||||
title: 'Basic Notification',
|
||||
body: 'Notification from the Main process'
|
||||
}
|
||||
new Notification(notification).show()
|
||||
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow).then(showNotification)
|
||||
```
|
||||
|
||||
After launching the Electron application, you should see the notification:
|
||||
After launching the Electron application, you should see the system notification:
|
||||
|
||||

|
||||
|
||||
@@ -135,14 +130,6 @@ if you exceed that limit.
|
||||
|
||||
[apple-notification-guidelines]: https://developer.apple.com/macos/human-interface-guidelines/system-capabilities/notifications/
|
||||
|
||||
#### Advanced Notifications
|
||||
|
||||
Later versions of macOS allow for notifications with an input field, allowing the user
|
||||
to quickly reply to a notification. In order to send notifications with an input field,
|
||||
use the userland module [node-mac-notifier][node-mac-notifier].
|
||||
|
||||
[node-mac-notifier]: https://github.com/CharlieHess/node-mac-notifier
|
||||
|
||||
#### Do not disturb / Session State
|
||||
|
||||
To detect whether or not you're allowed to send a notification, use the userland module
|
||||
|
||||
@@ -120,9 +120,9 @@ file in the directory you executed it in. Both files can be analyzed using
|
||||
the Chrome Developer Tools, using the `Performance` and `Memory` tabs
|
||||
respectively.
|
||||
|
||||
![performance-cpu-prof]
|
||||
![Performance CPU Profile][performance-cpu-prof]
|
||||
|
||||
![performance-heap-prof]
|
||||
![Performance Heap Memory Profile][performance-heap-prof]
|
||||
|
||||
In this example, on the author's machine, we saw that loading `request` took
|
||||
almost half a second, whereas `node-fetch` took dramatically less memory
|
||||
|
||||
@@ -138,7 +138,7 @@ way to import Electron's content scripts.
|
||||
<!-- Note: This guide doesn't take sandboxing into account, which might fundamentally
|
||||
change the statements here. -->
|
||||
Preload scripts contain code that executes in a renderer process before its web content
|
||||
begins loading. These scripts runs within the renderer context, but are granted more
|
||||
begins loading. These scripts run within the renderer context, but are granted more
|
||||
privileges by having access to Node.js APIs.
|
||||
|
||||
A preload script can be attached to the main process in the `BrowserWindow` constructor's
|
||||
@@ -148,7 +148,9 @@ A preload script can be attached to the main process in the `BrowserWindow` cons
|
||||
const { BrowserWindow } = require('electron')
|
||||
//...
|
||||
const win = new BrowserWindow({
|
||||
preload: 'path/to/preload.js'
|
||||
webPreferences: {
|
||||
preload: 'path/to/preload.js'
|
||||
}
|
||||
})
|
||||
//...
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Progress Bar in Taskbar (Windows, macOS, Unity)
|
||||
# Taskbar Progress Bar (Windows & macOS)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -31,30 +31,70 @@ currently at 63% towards completion, you would call it as
|
||||
`setProgressBar(0.63)`.
|
||||
|
||||
Setting the parameter to negative values (e.g. `-1`) will remove the progress
|
||||
bar, whereas setting it to values greater than `1` (e.g. `2`) will switch the
|
||||
progress bar to indeterminate mode (Windows-only -- it will clamp to 100%
|
||||
otherwise). In this mode, a progress bar remains active but does not show an
|
||||
actual percentage. Use this mode for situations when you do not know how long
|
||||
an operation will take to complete.
|
||||
bar. Setting it to a value greater than `1` will indicate an indeterminate progress bar
|
||||
in Windows or clamp to 100% in other operating systems. An indeterminate progress bar
|
||||
remains active but does not show an actual percentage, and is used for situations when
|
||||
you do not know how long an operation will take to complete.
|
||||
|
||||
See the [API documentation for more options and modes][setprogressbar].
|
||||
|
||||
## Example
|
||||
|
||||
Starting with a working application from the
|
||||
[Quick Start Guide](quick-start.md), add the following lines to the
|
||||
`main.js` file:
|
||||
In this example, we add a progress bar to the main window that increments over time
|
||||
using Node.js timers.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/progress-bar'
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
win.setProgressBar(0.5)
|
||||
let progressInterval
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
|
||||
const INCREMENT = 0.03
|
||||
const INTERVAL_DELAY = 100 // ms
|
||||
|
||||
let c = 0
|
||||
progressInterval = setInterval(() => {
|
||||
// update progress bar to next value
|
||||
// values between 0 and 1 will show progress, >1 will show indeterminate or stick at 100%
|
||||
win.setProgressBar(c)
|
||||
|
||||
// increment or reset progress bar
|
||||
if (c < 2) c += INCREMENT
|
||||
else c = 0
|
||||
}, INTERVAL_DELAY)
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// before the app is terminated, clear both timers
|
||||
app.on('before-quit', () => {
|
||||
clearInterval(progressInterval)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
After launching the Electron application, you should see the bar in
|
||||
the dock (macOS) or taskbar (Windows, Unity), indicating the progress
|
||||
percentage you just defined.
|
||||
After launching the Electron application, the dock (macOS) or taskbar (Windows, Unity)
|
||||
should show a progress bar that starts at zero and progresses through 100% to completion.
|
||||
It should then show indeterminate (Windows) or pin to 100% (other operating systems)
|
||||
briefly and then loop.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ app.on('window-all-closed', function () {
|
||||
|
||||
[node-platform]: https://nodejs.org/api/process.html#process_process_platform
|
||||
[window-all-closed]: ../api/app.md#event-window-all-closed
|
||||
[window-all-closed]: ../api/app.md#appquit
|
||||
[app-quit]: ../api/app.md#appquit
|
||||
|
||||
#### Open a window if none are open (macOS)
|
||||
|
||||
@@ -299,7 +299,9 @@ function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
@@ -440,7 +442,7 @@ window.addEventListener('DOMContentLoaded', () => {
|
||||
</html>
|
||||
```
|
||||
|
||||
```fiddle docs/fiddles/quickstart
|
||||
```fiddle docs/fiddles/quick-start
|
||||
```
|
||||
|
||||
To summarize all the steps we've done:
|
||||
|
||||
@@ -13,39 +13,62 @@ __Application dock menu:__
|
||||
|
||||
![macOS Dock Menu][dock-menu-image]
|
||||
|
||||
To add a file to recent documents, you need to use the
|
||||
[app.addRecentDocument][addrecentdocument] API.
|
||||
|
||||
## Example
|
||||
|
||||
### Add an item to recent documents
|
||||
|
||||
Starting with a working application from the
|
||||
[Quick Start Guide](quick-start.md), add the following lines to the
|
||||
`main.js` file:
|
||||
### Managing recent documents
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/recent-documents'
|
||||
const { app } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const fileName = 'recently-used.md'
|
||||
fs.writeFile(fileName, 'Lorem Ipsum', () => {
|
||||
app.addRecentDocument(path.join(__dirname, fileName))
|
||||
})
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
app.clearRecentDocuments()
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### Adding a recent document
|
||||
|
||||
To add a file to recent documents, use the
|
||||
[app.addRecentDocument][addrecentdocument] API.
|
||||
|
||||
After launching the Electron application, right click the application icon.
|
||||
You should see the item you just added. In this guide, the item is a Markdown
|
||||
file located in the root of the project:
|
||||
In this guide, the item is a Markdown file located in the root of the project.
|
||||
You should see `recently-used.md` added to the list of recent files:
|
||||
|
||||

|
||||
|
||||
### Clear the list of recent documents
|
||||
#### Clearing the list of recent documents
|
||||
|
||||
To clear the list of recent documents, you need to use
|
||||
[app.clearRecentDocuments][clearrecentdocuments] API in the `main.js` file:
|
||||
|
||||
```javascript
|
||||
const { app } = require('electron')
|
||||
|
||||
app.clearRecentDocuments()
|
||||
```
|
||||
To clear the list of recent documents, use the
|
||||
[app.clearRecentDocuments][clearrecentdocuments] API.
|
||||
In this guide, the list of documents is cleared once all windows have been
|
||||
closed.
|
||||
|
||||
## Additional information
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Represented File for macOS BrowserWindows
|
||||
# Representing Files in a BrowserWindow (macOS)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -20,23 +20,40 @@ To set the represented file of window, you can use the
|
||||
|
||||
## Example
|
||||
|
||||
Starting with a working application from the
|
||||
[Quick Start Guide](quick-start.md), add the following lines to the
|
||||
`main.js` file:
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/represented-file'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const os = require('os');
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.setRepresentedFilename('/etc/passwd')
|
||||
win.setRepresentedFilename(os.homedir())
|
||||
win.setDocumentEdited(true)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
After launching the Electron application, click on the title with `Command` or
|
||||
`Control` key pressed. You should see a popup with the file you just defined:
|
||||
`Control` key pressed. You should see a popup with the represented file at the top.
|
||||
In this guide, this is the current user's home directory:
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Snapcraft Guide (Ubuntu Software Center & More)
|
||||
# Snapcraft Guide (Linux)
|
||||
|
||||
This guide provides information on how to package your Electron application
|
||||
for any Snapcraft environment, including the Ubuntu Software Center.
|
||||
|
||||
@@ -16,7 +16,6 @@ you can interact with the community in these locations:
|
||||
* Sharing ideas with other Electron app developers
|
||||
* And more!
|
||||
* [`electron`](https://discuss.atom.io/c/electron) category on the Atom forums
|
||||
* `#atom-shell` channel on Freenode
|
||||
* `#electron` channel on [Atom's Slack](https://discuss.atom.io/t/join-us-on-slack/16638?source_topic_id=25406)
|
||||
* [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
|
||||
* [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
||||
@@ -38,6 +37,13 @@ tools and resources.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
_**Note:** Beginning in September 2021 with Electron 15, the Electron team
|
||||
will temporarily support the latest **four** stable major versions. This
|
||||
extended support is intended to help Electron developers transition to
|
||||
the [new eight week release cadence](https://electronjs.org/blog/8-week-cadence), and will continue until May 2022, with
|
||||
the release of Electron 19. At that time, the Electron team will drop support
|
||||
back to the latest three stable major versions._
|
||||
|
||||
The latest three *stable* major versions are supported by the Electron team.
|
||||
For example, if the latest release is 6.1.x, then the 5.0.x as well
|
||||
as the 4.2.x series are supported. We only support the latest minor release
|
||||
@@ -64,9 +70,9 @@ until the maintainers feel the maintenance burden is too high to continue doing
|
||||
|
||||
### Currently supported versions
|
||||
|
||||
* 13.x.y
|
||||
* 12.x.y
|
||||
* 11.x.y
|
||||
* 10.x.y
|
||||
|
||||
### End-of-life
|
||||
|
||||
|
||||
83
docs/tutorial/tray.md
Normal file
83
docs/tutorial/tray.md
Normal file
@@ -0,0 +1,83 @@
|
||||
---
|
||||
title: Tray
|
||||
description: This guide will take you through the process of creating
|
||||
a Tray icon with its own context menu to the system's notification area.
|
||||
slug: tray
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Tray
|
||||
|
||||
## Overview
|
||||
|
||||
<!-- ✍ Update this section if you want to provide more details -->
|
||||
|
||||
This guide will take you through the process of creating a
|
||||
[Tray](https://www.electronjs.org/docs/api/tray) icon with
|
||||
its own context menu to the system's notification area.
|
||||
|
||||
On MacOS and Ubuntu, the Tray will be located on the top
|
||||
right corner of your screen, adjacent to your battery and wifi icons.
|
||||
On Windows, the Tray will usually be located in the bottom right corner.
|
||||
|
||||
## Example
|
||||
|
||||
### main.js
|
||||
|
||||
First we must import `app`, `Tray`, `Menu`, `nativeImage` from `electron`.
|
||||
|
||||
```js
|
||||
const { app, Tray, Menu, nativeImage } = require('electron')
|
||||
```
|
||||
|
||||
Next we will create our Tray. To do this, we will use a
|
||||
[`NativeImage`](https://www.electronjs.org/docs/api/native-image) icon,
|
||||
which can be created through any one of these
|
||||
[methods](https://www.electronjs.org/docs/api/native-image#methods).
|
||||
Note that we wrap our Tray creation code within an
|
||||
[`app.whenReady`](https://www.electronjs.org/docs/api/app#appwhenready)
|
||||
as we will need to wait for our electron app to finish initializing.
|
||||
|
||||
```js title='main.js'
|
||||
let tray
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const icon = nativeImage.createFromPath('path/to/asset.png')
|
||||
tray = new Tray(icon)
|
||||
|
||||
// note: your contextMenu, Tooltip and Title code will go here!
|
||||
})
|
||||
```
|
||||
|
||||
Great! Now we can start attaching a context menu to our Tray, like so:
|
||||
|
||||
```js
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: 'Item1', type: 'radio' },
|
||||
{ label: 'Item2', type: 'radio' },
|
||||
{ label: 'Item3', type: 'radio', checked: true },
|
||||
{ label: 'Item4', type: 'radio' }
|
||||
])
|
||||
|
||||
tray.setContextMenu(contextMenu)
|
||||
```
|
||||
|
||||
The code above will create 4 separate radio-type items in the context menu.
|
||||
To read more about constructing native menus, click
|
||||
[here](https://www.electronjs.org/docs/api/menu#menubuildfromtemplatetemplate).
|
||||
|
||||
Finally, let's give our tray a tooltip and a title.
|
||||
|
||||
```js
|
||||
tray.setToolTip('This is my application')
|
||||
tray.setTitle('This is my title')
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
After you start your electron app, you should see the Tray residing
|
||||
in either the top or bottom right of your screen, depending on your
|
||||
operating system.
|
||||
|
||||
```fiddle docs/fiddles/native-ui/tray
|
||||
```
|
||||
@@ -49,7 +49,7 @@ update server.
|
||||
Depending on your needs, you can choose from one of these:
|
||||
|
||||
- [Hazel][hazel] – Update server for private or open-source apps which can be
|
||||
deployed for free on [Now][now]. It pulls from [GitHub Releases][gh-releases]
|
||||
deployed for free on [Vercel][vercel]. It pulls from [GitHub Releases][gh-releases]
|
||||
and leverages the power of GitHub's CDN.
|
||||
- [Nuts][nuts] – Also uses [GitHub Releases][gh-releases], but caches app
|
||||
updates on disk and supports private repositories.
|
||||
@@ -64,7 +64,7 @@ to minify server cost.
|
||||
Once you've deployed your update server, continue with importing the required
|
||||
modules in your code. The following code might vary for different server
|
||||
software, but it works like described when using
|
||||
[Hazel](https://github.com/zeit/hazel).
|
||||
[Hazel][hazel].
|
||||
|
||||
**Important:** Please ensure that the code below will only be executed in
|
||||
your packaged app, and not in development. You can use
|
||||
@@ -136,8 +136,8 @@ autoUpdater.on('error', message => {
|
||||
|
||||
Because the requests made by Auto Update aren't under your direct control, you may find situations that are difficult to handle (such as if the update server is behind authentication). The `url` field does support files, which means that with some effort, you can sidestep the server-communication aspect of the process. [Here's an example of how this could work](https://github.com/electron/electron/issues/5020#issuecomment-477636990).
|
||||
|
||||
[now]: https://zeit.co/now
|
||||
[hazel]: https://github.com/zeit/hazel
|
||||
[vercel]: https://vercel.com
|
||||
[hazel]: https://github.com/vercel/hazel
|
||||
[nuts]: https://github.com/GitbookIO/nuts
|
||||
[gh-releases]: https://help.github.com/articles/creating-releases/
|
||||
[electron-release-server]: https://github.com/ArekSredzki/electron-release-server
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Using Native Node Modules
|
||||
# Native Node Modules
|
||||
|
||||
Native Node.js modules are supported by Electron, but since Electron has a different
|
||||
[application binary interface (ABI)][abi] from a given Node.js binary (due to
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Using Pepper Flash Plugin
|
||||
# Pepper Flash Plugin
|
||||
|
||||
Electron no longer supports the Pepper Flash plugin, as Chrome has removed support.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Using Selenium and WebDriver
|
||||
# Selenium and WebDriver
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Web embeds
|
||||
# Web Embeds
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Windows 10 on Arm
|
||||
# Windows on ARM
|
||||
|
||||
If your app runs with Electron 6.0.8 or later, you can now build it for Windows 10 on Arm. This considerably improves performance, but requires recompilation of any native modules used in your app. It may also require small fixups to your build and packaging scripts.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Windows Taskbar
|
||||
# Taskbar Customization (Windows)
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<grit-part>
|
||||
<!-- Windows Caption Buttons -->
|
||||
<message name="IDS_APP_ACCNAME_CLOSE" desc="The accessible name for the Close button.">
|
||||
Close
|
||||
</message>
|
||||
<message name="IDS_APP_ACCNAME_MINIMIZE" desc="The accessible name for the Minimize button.">
|
||||
Minimize
|
||||
</message>
|
||||
<message name="IDS_APP_ACCNAME_MAXIMIZE" desc="The accessible name for the Maximize button.">
|
||||
Maximize
|
||||
</message>
|
||||
<message name="IDS_APP_ACCNAME_RESTORE" desc="The accessible name for the Restore button.">
|
||||
Restore
|
||||
</message>
|
||||
|
||||
<!-- Printing Service -->
|
||||
<message name="IDS_UTILITY_PROCESS_PRINTING_SERVICE_NAME" desc="The name of the utility process used for printing conversions.">
|
||||
Printing Service
|
||||
|
||||
@@ -101,6 +101,7 @@ auto_filenames = {
|
||||
"docs/api/structures/new-window-web-contents-event.md",
|
||||
"docs/api/structures/notification-action.md",
|
||||
"docs/api/structures/notification-response.md",
|
||||
"docs/api/structures/overlay-options.md",
|
||||
"docs/api/structures/point.md",
|
||||
"docs/api/structures/post-body.md",
|
||||
"docs/api/structures/printer-info.md",
|
||||
|
||||
@@ -90,6 +90,10 @@ filenames = {
|
||||
"shell/browser/ui/views/electron_views_delegate_win.cc",
|
||||
"shell/browser/ui/views/win_frame_view.cc",
|
||||
"shell/browser/ui/views/win_frame_view.h",
|
||||
"shell/browser/ui/views/win_caption_button.cc",
|
||||
"shell/browser/ui/views/win_caption_button.h",
|
||||
"shell/browser/ui/views/win_caption_button_container.cc",
|
||||
"shell/browser/ui/views/win_caption_button_container.h",
|
||||
"shell/browser/ui/win/dialog_thread.cc",
|
||||
"shell/browser/ui/win/dialog_thread.h",
|
||||
"shell/browser/ui/win/electron_desktop_native_widget_aura.cc",
|
||||
@@ -180,8 +184,8 @@ filenames = {
|
||||
"shell/browser/ui/cocoa/root_view_mac.mm",
|
||||
"shell/browser/ui/cocoa/views_delegate_mac.h",
|
||||
"shell/browser/ui/cocoa/views_delegate_mac.mm",
|
||||
"shell/browser/ui/cocoa/window_buttons_view.h",
|
||||
"shell/browser/ui/cocoa/window_buttons_view.mm",
|
||||
"shell/browser/ui/cocoa/window_buttons_proxy.h",
|
||||
"shell/browser/ui/cocoa/window_buttons_proxy.mm",
|
||||
"shell/browser/ui/drag_util_mac.mm",
|
||||
"shell/browser/ui/file_dialog_mac.mm",
|
||||
"shell/browser/ui/inspectable_web_contents_view_mac.h",
|
||||
|
||||
@@ -490,63 +490,83 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
}
|
||||
};
|
||||
|
||||
function fsReadFileAsar (pathArgument: string, options: any, callback: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (pathInfo.isAsar) {
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = { encoding: null };
|
||||
} else if (typeof options === 'string') {
|
||||
options = { encoding: options };
|
||||
} else if (options === null || options === undefined) {
|
||||
options = { encoding: null };
|
||||
} else if (typeof options !== 'object') {
|
||||
throw new TypeError('Bad arguments');
|
||||
}
|
||||
|
||||
const { encoding } = options;
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const info = archive.getFileInfo(filePath);
|
||||
if (!info) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.size === 0) {
|
||||
nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.readFile(realPath, options, callback);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
if (!(fd >= 0)) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
|
||||
callback(error, encoding ? buffer.toString(encoding) : buffer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const { readFile } = fs;
|
||||
fs.readFile = function (pathArgument: string, options: any, callback: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return readFile.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = { encoding: null };
|
||||
} else if (typeof options === 'string') {
|
||||
options = { encoding: options };
|
||||
} else if (options === null || options === undefined) {
|
||||
options = { encoding: null };
|
||||
} else if (typeof options !== 'object') {
|
||||
throw new TypeError('Bad arguments');
|
||||
if (!pathInfo.isAsar) {
|
||||
return readFile.apply(this, arguments);
|
||||
}
|
||||
|
||||
const { encoding } = options;
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
const info = archive.getFileInfo(filePath);
|
||||
if (!info) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.size === 0) {
|
||||
nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.readFile(realPath, options, callback);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
if (!(fd >= 0)) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
return;
|
||||
}
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
|
||||
callback(error, encoding ? buffer.toString(encoding) : buffer);
|
||||
});
|
||||
return fsReadFileAsar(pathArgument, options, callback);
|
||||
};
|
||||
|
||||
fs.promises.readFile = util.promisify(fs.readFile);
|
||||
const { readFile: readFilePromise } = fs.promises;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
fs.promises.readFile = function (pathArgument: string, options: any) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) {
|
||||
return readFilePromise.apply(this, arguments);
|
||||
}
|
||||
|
||||
const p = util.promisify(fsReadFileAsar);
|
||||
return p(pathArgument, options);
|
||||
};
|
||||
|
||||
const { readFileSync } = fs;
|
||||
fs.readFileSync = function (pathArgument: string, options: any) {
|
||||
|
||||
@@ -20,20 +20,6 @@ BrowserWindow.prototype._init = function (this: BWT) {
|
||||
nativeSetBounds.call(this, bounds, ...opts);
|
||||
};
|
||||
|
||||
// Sometimes the webContents doesn't get focus when window is shown, so we
|
||||
// have to force focusing on webContents in this case. The safest way is to
|
||||
// focus it when we first start to load URL, if we do it earlier it won't
|
||||
// have effect, if we do it later we might move focus in the page.
|
||||
//
|
||||
// Though this hack is only needed on macOS when the app is launched from
|
||||
// Finder, we still do it on all platforms in case of other bugs we don't
|
||||
// know.
|
||||
if (this.webContents._initiallyShown) {
|
||||
this.webContents.once('load-url' as any, function (this: WebContents) {
|
||||
this.focus();
|
||||
});
|
||||
}
|
||||
|
||||
// Redirect focus/blur event to app instance too.
|
||||
this.on('blur', (event: Event) => {
|
||||
app.emit('browser-window-blur', event, this);
|
||||
|
||||
@@ -723,6 +723,10 @@ export function fromId (id: string) {
|
||||
return binding.fromId(id);
|
||||
}
|
||||
|
||||
export function fromDevToolsTargetId (targetId: string) {
|
||||
return binding.fromDevToolsTargetId(targetId);
|
||||
}
|
||||
|
||||
export function getFocusedWebContents () {
|
||||
let focused = null;
|
||||
for (const contents of binding.getAllWebContents()) {
|
||||
|
||||
@@ -76,6 +76,7 @@ ipcMainInternal.on(
|
||||
const referrer: Electron.Referrer = { url: '', policy: 'strict-origin-when-cross-origin' };
|
||||
const browserWindowOptions = event.sender._callWindowOpenHandler(event, { url, frameName, features, disposition: 'new-window', referrer });
|
||||
if (event.defaultPrevented) {
|
||||
event.returnValue = null;
|
||||
return;
|
||||
}
|
||||
const guest = openGuestWindow({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { app } from 'electron/main';
|
||||
import type { WebContents } from 'electron/main';
|
||||
import { clipboard, nativeImage } from 'electron/common';
|
||||
import { clipboard } from 'electron/common';
|
||||
import * as fs from 'fs';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
@@ -119,7 +119,3 @@ ipcMainInternal.on(IPC_MESSAGES.NAVIGATION_CONTROLLER_LENGTH, function (event) {
|
||||
ipcMainInternal.on(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, function (event, preloadPath: string, error: Error) {
|
||||
event.sender.emit('preload-error', event, preloadPath, error);
|
||||
});
|
||||
|
||||
ipcMainInternal.handle(IPC_MESSAGES.NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH, async (_, path: string, size: Electron.Size) => {
|
||||
return typeUtils.serialize(await nativeImage.createThumbnailFromPath(path, size));
|
||||
});
|
||||
|
||||
@@ -39,5 +39,4 @@ export const enum IPC_MESSAGES {
|
||||
INSPECTOR_SELECT_FILE = 'INSPECTOR_SELECT_FILE',
|
||||
|
||||
DESKTOP_CAPTURER_GET_SOURCES = 'DESKTOP_CAPTURER_GET_SOURCES',
|
||||
NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH = 'NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH',
|
||||
}
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import { deserialize } from '@electron/internal/common/type-utils';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const { nativeImage } = process._linkedBinding('electron_common_native_image');
|
||||
|
||||
nativeImage.createThumbnailFromPath = async (path: string, size: Electron.Size) => {
|
||||
return deserialize(await ipcRendererInternal.invoke(IPC_MESSAGES.NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH, path, size));
|
||||
};
|
||||
|
||||
export default nativeImage;
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
import { internalContextBridge } from '@electron/internal/renderer/api/context-bridge';
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
import { webFrame } from 'electron/renderer';
|
||||
import { IPC_MESSAGES } from '../common/ipc-messages';
|
||||
|
||||
const { contextIsolationEnabled } = internalContextBridge;
|
||||
|
||||
/* Corrects for some Inspector adaptations needed in Electron.
|
||||
* 1) Use menu API to show context menu.
|
||||
* 2) Correct for Chromium returning undefined for filesystem.
|
||||
* 3) Use dialog API to override file chooser dialog.
|
||||
*/
|
||||
window.onload = function () {
|
||||
// Use menu API to show context menu.
|
||||
window.InspectorFrontendHost!.showContextMenuAtPoint = createMenu;
|
||||
|
||||
// correct for Chromium returning undefined for filesystem
|
||||
window.Persistence!.FileSystemWorkspaceBinding.completeURL = completeURL;
|
||||
|
||||
// Use dialog API to override file chooser dialog.
|
||||
window.UI!.createFileSelectorElement = createFileSelectorElement;
|
||||
if (contextIsolationEnabled) {
|
||||
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
|
||||
'InspectorFrontendHost', 'showContextMenuAtPoint'
|
||||
], createMenu);
|
||||
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
|
||||
'Persistence', 'FileSystemWorkspaceBinding', 'completeURL'
|
||||
], completeURL);
|
||||
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
|
||||
'UI', 'createFileSelectorElement'
|
||||
], createFileSelectorElement);
|
||||
} else {
|
||||
window.InspectorFrontendHost!.showContextMenuAtPoint = createMenu;
|
||||
window.Persistence!.FileSystemWorkspaceBinding.completeURL = completeURL;
|
||||
window.UI!.createFileSelectorElement = createFileSelectorElement;
|
||||
}
|
||||
};
|
||||
|
||||
// Extra / is needed as a result of MacOS requiring absolute paths
|
||||
@@ -36,9 +52,10 @@ const createMenu = function (x: number, y: number, items: ContextMenuItem[]) {
|
||||
const isEditMenu = useEditMenuItems(x, y, items);
|
||||
ipcRendererInternal.invoke<number>(IPC_MESSAGES.INSPECTOR_CONTEXT_MENU, items, isEditMenu).then(id => {
|
||||
if (typeof id === 'number') {
|
||||
window.DevToolsAPI!.contextMenuItemSelected(id);
|
||||
webFrame.executeJavaScript(`window.DevToolsAPI.contextMenuItemSelected(${JSON.stringify(id)})`);
|
||||
}
|
||||
window.DevToolsAPI!.contextMenuCleared();
|
||||
|
||||
webFrame.executeJavaScript('window.DevToolsAPI.contextMenuCleared()');
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -104,10 +104,14 @@ const warnAboutInsecureResources = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
const isLocal = (url: URL): boolean =>
|
||||
['localhost', '127.0.0.1', '[::1]', ''].includes(url.hostname);
|
||||
const isInsecure = (url: URL): boolean =>
|
||||
['http:', 'ftp:'].includes(url.protocol) && !isLocal(url);
|
||||
|
||||
const resources = window.performance
|
||||
.getEntriesByType('resource')
|
||||
.filter(({ name }) => /^(http|ftp):/gi.test(name || ''))
|
||||
.filter(({ name }) => new URL(name).hostname !== 'localhost')
|
||||
.filter(({ name }) => isInsecure(new URL(name)))
|
||||
.map(({ name }) => `- ${name}`)
|
||||
.join('\n');
|
||||
|
||||
@@ -270,9 +274,7 @@ const warnAboutAllowedPopups = function () {
|
||||
// Logs a warning message about the remote module
|
||||
|
||||
const warnAboutRemoteModuleWithRemoteContent = function (webPreferences?: Electron.WebPreferences) {
|
||||
if (!webPreferences || isLocalhost()) return;
|
||||
const remoteModuleEnabled = webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : true;
|
||||
if (!remoteModuleEnabled) return;
|
||||
if (!webPreferences || !webPreferences.enableRemoteModule || isLocalhost()) return;
|
||||
|
||||
if (getIsRemoteProtocol()) {
|
||||
const warning = `This renderer process has "enableRemoteModule" enabled
|
||||
@@ -298,7 +300,9 @@ const logSecurityWarnings = function (
|
||||
warnAboutEnableBlinkFeatures(webPreferences);
|
||||
warnAboutInsecureCSP();
|
||||
warnAboutAllowedPopups();
|
||||
warnAboutRemoteModuleWithRemoteContent(webPreferences);
|
||||
if (BUILDFLAG(ENABLE_REMOTE_MODULE)) {
|
||||
warnAboutRemoteModuleWithRemoteContent(webPreferences);
|
||||
}
|
||||
};
|
||||
|
||||
const getWebPreferences = async function () {
|
||||
|
||||
@@ -12,6 +12,9 @@ require('../common/reset-search-paths');
|
||||
// Import common settings.
|
||||
require('@electron/internal/common/init');
|
||||
|
||||
// Process command line arguments.
|
||||
const { hasSwitch, getSwitchValue } = process._linkedBinding('electron_common_command_line');
|
||||
|
||||
// Export node bindings to global.
|
||||
const { makeRequireFunction } = __non_webpack_require__('internal/modules/cjs/helpers') // eslint-disable-line
|
||||
global.module = new Module('electron/js2c/worker_init');
|
||||
@@ -32,4 +35,10 @@ if (self.location.protocol === 'file:') {
|
||||
// For backwards compatibility we fake these two paths here
|
||||
global.__filename = path.join(process.resourcesPath, 'electron.asar', 'worker', 'init.js');
|
||||
global.__dirname = path.join(process.resourcesPath, 'electron.asar', 'worker');
|
||||
|
||||
const appPath = hasSwitch('app-path') ? getSwitchValue('app-path') : null;
|
||||
if (appPath) {
|
||||
// Search for module under the app directory.
|
||||
global.module.paths = Module._nodeModulePaths(appPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "13.0.1",
|
||||
"version": "13.5.1",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
4
patches/angle/.patches
Normal file
4
patches/angle/.patches
Normal file
@@ -0,0 +1,4 @@
|
||||
cherry-pick-d8cb996.patch
|
||||
cherry-pick-1fb846c.patch
|
||||
cherry-pick-72473550f6ff.patch
|
||||
webgl_make_unsuccessful_links_fail_subsequent_draw_calls.patch
|
||||
90
patches/angle/cherry-pick-1fb846c.patch
Normal file
90
patches/angle/cherry-pick-1fb846c.patch
Normal file
@@ -0,0 +1,90 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Alexey Knyazev <lexa.knyazev@gmail.com>
|
||||
Date: Tue, 3 Aug 2021 01:57:49 +0400
|
||||
Subject: Validate texStorage dimensions with compressed formats
|
||||
|
||||
Bug: angleproject:6230
|
||||
Change-Id: I501ec1e6974bdc7e6731dcb88045edb0aa22b888
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3067329
|
||||
Commit-Queue: Alexey Knyazev <lexa.knyazev@gmail.com>
|
||||
Reviewed-by: Kenneth Russell <kbr@chromium.org>
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
|
||||
index 53e1afd6e26ef8cc099e51c66457a968ca82b1c8..5c69d568ee45b9e8bf1d4d0da7b9a48b123a47c0 100644
|
||||
--- a/src/libANGLE/validationES3.cpp
|
||||
+++ b/src/libANGLE/validationES3.cpp
|
||||
@@ -1339,17 +1339,26 @@ bool ValidateES3TexStorageParametersBase(const Context *context,
|
||||
return false;
|
||||
}
|
||||
|
||||
- if (formatInfo.compressed && target == TextureType::Rectangle)
|
||||
+ if (formatInfo.compressed)
|
||||
{
|
||||
- context->validationError(GL_INVALID_ENUM, kRectangleTextureCompressed);
|
||||
- return false;
|
||||
- }
|
||||
+ if (target == TextureType::Rectangle)
|
||||
+ {
|
||||
+ context->validationError(GL_INVALID_ENUM, kRectangleTextureCompressed);
|
||||
+ return false;
|
||||
+ }
|
||||
|
||||
- if (formatInfo.compressed && target == TextureType::_3D)
|
||||
- {
|
||||
- if (!ValidateES3CompressedFormatForTexture3D(context, formatInfo.internalFormat))
|
||||
+ if (target == TextureType::_3D)
|
||||
{
|
||||
- // Error already generated.
|
||||
+ if (!ValidateES3CompressedFormatForTexture3D(context, formatInfo.internalFormat))
|
||||
+ {
|
||||
+ // Error already generated.
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!ValidCompressedImageSize(context, formatInfo.internalFormat, 0, width, height, depth))
|
||||
+ {
|
||||
+ context->validationError(GL_INVALID_OPERATION, kInvalidCompressedImageSize);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
diff --git a/src/tests/gl_tests/SRGBTextureTest.cpp b/src/tests/gl_tests/SRGBTextureTest.cpp
|
||||
index 271fe6dbaa1d5684f7c2e16bdef18bce30943e8b..a0eab1af9e34a5de75e226efef9c0af4a50c63ff 100644
|
||||
--- a/src/tests/gl_tests/SRGBTextureTest.cpp
|
||||
+++ b/src/tests/gl_tests/SRGBTextureTest.cpp
|
||||
@@ -340,7 +340,7 @@ TEST_P(SRGBTextureTestES3, SRGBOverrideFormats)
|
||||
{
|
||||
GLTexture tex;
|
||||
glBindTexture(GL_TEXTURE_2D, tex.get());
|
||||
- glTexStorage2D(GL_TEXTURE_2D, 1, format, 1, 1);
|
||||
+ glTexStorage2D(GL_TEXTURE_2D, 1, format, 4, 4);
|
||||
GLenum error = glGetError();
|
||||
if (error == GL_INVALID_ENUM)
|
||||
{
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index fabaefbe33c94a048ec7c974951ac9ef886826ef..efbd9ebdb2bb29cf9673750e1e3e7b492bfbf87e 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -5073,6 +5073,21 @@ void WebGLCompatibilityTest::testCompressedTexLevelDimension(GLenum format,
|
||||
{
|
||||
EXPECT_GL_ERROR(expectedError) << explanation;
|
||||
}
|
||||
+
|
||||
+ if (level == 0 && width > 0 && getClientMajorVersion() >= 3)
|
||||
+ {
|
||||
+ GLTexture sourceTextureStorage;
|
||||
+ glBindTexture(GL_TEXTURE_2D, sourceTextureStorage);
|
||||
+ glTexStorage2D(GL_TEXTURE_2D, 1, format, width, height);
|
||||
+ if (expectedError == 0)
|
||||
+ {
|
||||
+ EXPECT_GL_NO_ERROR() << explanation << " (texStorage)";
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ EXPECT_GL_ERROR(expectedError) << explanation << " (texStorage)";
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
void WebGLCompatibilityTest::testCompressedTexImage(GLenum format)
|
||||
69
patches/angle/cherry-pick-72473550f6ff.patch
Normal file
69
patches/angle/cherry-pick-72473550f6ff.patch
Normal file
@@ -0,0 +1,69 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Wed, 1 Sep 2021 12:17:26 -0400
|
||||
Subject: D3D11: Fix overflow in GenerateInitialTextureData.
|
||||
|
||||
Our use of unchecked math was causing OOB accesses with very large
|
||||
textures. Unfortunately it's not easy to make a passing test that
|
||||
reproduces this OOB access.
|
||||
|
||||
Bug: chromium:1241036
|
||||
Change-Id: Icd2749f5b3116bb51390ce769fef22c49a11f307
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3136733
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
(cherry picked from commit 794b13ce9f874d472729ebd69897bc7ab9340a4b)
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3149277
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
index 3915a89de6fd161fa72519d4b9b6e82db68c6c66..6d721bd6e72d21454a868965993d930fe138b58c 100644
|
||||
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
@@ -2181,28 +2181,35 @@ angle::Result GenerateInitialTextureData(
|
||||
const d3d11::DXGIFormatSize &dxgiFormatInfo =
|
||||
d3d11::GetDXGIFormatSizeInfo(d3dFormatInfo.texFormat);
|
||||
|
||||
- unsigned int rowPitch = dxgiFormatInfo.pixelBytes * width;
|
||||
- unsigned int depthPitch = rowPitch * height;
|
||||
- unsigned int maxImageSize = depthPitch * depth;
|
||||
+ using CheckedSize = angle::CheckedNumeric<size_t>;
|
||||
+ CheckedSize rowPitch = CheckedSize(dxgiFormatInfo.pixelBytes) * CheckedSize(width);
|
||||
+ CheckedSize depthPitch = rowPitch * CheckedSize(height);
|
||||
+ CheckedSize maxImageSize = depthPitch * CheckedSize(depth);
|
||||
+
|
||||
+ Context11 *context11 = GetImplAs<Context11>(context);
|
||||
+ ANGLE_CHECK_GL_ALLOC(context11, maxImageSize.IsValid());
|
||||
|
||||
angle::MemoryBuffer *scratchBuffer = nullptr;
|
||||
- ANGLE_CHECK_GL_ALLOC(GetImplAs<Context11>(context),
|
||||
- context->getScratchBuffer(maxImageSize, &scratchBuffer));
|
||||
+ ANGLE_CHECK_GL_ALLOC(context11,
|
||||
+ context->getScratchBuffer(maxImageSize.ValueOrDie(), &scratchBuffer));
|
||||
|
||||
- d3dFormatInfo.dataInitializerFunction(width, height, depth, scratchBuffer->data(), rowPitch,
|
||||
- depthPitch);
|
||||
+ d3dFormatInfo.dataInitializerFunction(width, height, depth, scratchBuffer->data(),
|
||||
+ rowPitch.ValueOrDie(), depthPitch.ValueOrDie());
|
||||
|
||||
for (unsigned int i = 0; i < mipLevels; i++)
|
||||
{
|
||||
unsigned int mipWidth = std::max(width >> i, 1U);
|
||||
unsigned int mipHeight = std::max(height >> i, 1U);
|
||||
|
||||
- unsigned int mipRowPitch = dxgiFormatInfo.pixelBytes * mipWidth;
|
||||
- unsigned int mipDepthPitch = mipRowPitch * mipHeight;
|
||||
+ using CheckedUINT = angle::CheckedNumeric<UINT>;
|
||||
+ CheckedUINT mipRowPitch = CheckedUINT(dxgiFormatInfo.pixelBytes) * CheckedUINT(mipWidth);
|
||||
+ CheckedUINT mipDepthPitch = mipRowPitch * CheckedUINT(mipHeight);
|
||||
+
|
||||
+ ANGLE_CHECK_GL_ALLOC(context11, mipRowPitch.IsValid() && mipDepthPitch.IsValid());
|
||||
|
||||
outSubresourceData->at(i).pSysMem = scratchBuffer->data();
|
||||
- outSubresourceData->at(i).SysMemPitch = mipRowPitch;
|
||||
- outSubresourceData->at(i).SysMemSlicePitch = mipDepthPitch;
|
||||
+ outSubresourceData->at(i).SysMemPitch = mipRowPitch.ValueOrDie();
|
||||
+ outSubresourceData->at(i).SysMemSlicePitch = mipDepthPitch.ValueOrDie();
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
300
patches/angle/cherry-pick-d8cb996.patch
Normal file
300
patches/angle/cherry-pick-d8cb996.patch
Normal file
@@ -0,0 +1,300 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kenneth Russell <kbr@chromium.org>
|
||||
Date: Wed, 4 Aug 2021 18:15:51 -0700
|
||||
Subject: In WebGL, constrain base level of compressed textures.
|
||||
|
||||
Enforce that if a mipmap level > 0 is specified for a compressed
|
||||
texture, that it implies that the size of the base level of the
|
||||
texture is a multiple of the format's block size.
|
||||
|
||||
Makes the test changes in
|
||||
https://github.com/KhronosGroup/WebGL/pull/3304 largely pass. There
|
||||
are some needed follow-on fixes to that PR, and this CL changes a
|
||||
sub-test result in the existing S3TC and S3TC-sRGB tests which will
|
||||
need to be suppressed Chromium-side first.
|
||||
|
||||
Bug: angleproject:6245
|
||||
Change-Id: I7723d7882091b78a353d8d273e80b819dd384021
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3072568
|
||||
Commit-Queue: Kenneth Russell <kbr@chromium.org>
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
|
||||
index 656e51f17724af9e0959fcd741ceeebf25ee0f24..412b9aa0f1d75c40ce02522589c53e943d049228 100644
|
||||
--- a/src/libANGLE/validationES.cpp
|
||||
+++ b/src/libANGLE/validationES.cpp
|
||||
@@ -1006,6 +1006,15 @@ bool ValidCompressedDimension(GLsizei size, GLuint blockSize, GLint level)
|
||||
return (level > 0) || (size % blockSize == 0);
|
||||
}
|
||||
|
||||
+bool ValidCompressedBaseLevelForWebGL(GLsizei size, GLuint blockSize, GLint level)
|
||||
+{
|
||||
+ // Avoid C++ undefined behavior.
|
||||
+ constexpr int maxValidShifts = 31;
|
||||
+ if (level > maxValidShifts)
|
||||
+ return false;
|
||||
+ return ((size << level) % blockSize) == 0;
|
||||
+}
|
||||
+
|
||||
bool ValidCompressedImageSize(const Context *context,
|
||||
GLenum internalFormat,
|
||||
GLint level,
|
||||
@@ -1043,11 +1052,27 @@ bool ValidCompressedImageSize(const Context *context,
|
||||
|
||||
if (CompressedTextureFormatRequiresExactSize(internalFormat))
|
||||
{
|
||||
- if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth, level) ||
|
||||
- !ValidCompressedDimension(height, formatInfo.compressedBlockHeight, level) ||
|
||||
- !ValidCompressedDimension(depth, formatInfo.compressedBlockDepth, level))
|
||||
+ // In WebGL compatibility mode, enforce that the base level implied
|
||||
+ // by the compressed texture's mip level would conform to the block
|
||||
+ // size. This is more strict than the non-WebGL check.
|
||||
+ if (context->getExtensions().webglCompatibility)
|
||||
{
|
||||
- return false;
|
||||
+ if (!ValidCompressedBaseLevelForWebGL(width, formatInfo.compressedBlockWidth, level) ||
|
||||
+ !ValidCompressedBaseLevelForWebGL(height, formatInfo.compressedBlockHeight,
|
||||
+ level) ||
|
||||
+ !ValidCompressedBaseLevelForWebGL(depth, formatInfo.compressedBlockDepth, level))
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth, level) ||
|
||||
+ !ValidCompressedDimension(height, formatInfo.compressedBlockHeight, level) ||
|
||||
+ !ValidCompressedDimension(depth, formatInfo.compressedBlockDepth, level))
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index 40c9a02e3eafe9d437e20e72a391bad73c783516..fabaefbe33c94a048ec7c974951ac9ef886826ef 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -296,6 +296,16 @@ void main()
|
||||
GLsizei blockSize,
|
||||
const std::string &extName,
|
||||
bool subImageAllowed);
|
||||
+
|
||||
+ GLint expectedByteLength(GLenum format, GLsizei width, GLsizei height);
|
||||
+ void testCompressedTexLevelDimension(GLenum format,
|
||||
+ GLint level,
|
||||
+ GLsizei width,
|
||||
+ GLsizei height,
|
||||
+ GLsizei expectedByteLength,
|
||||
+ GLenum expectedError,
|
||||
+ const char *explanation);
|
||||
+ void testCompressedTexImage(GLenum format);
|
||||
};
|
||||
|
||||
class WebGL2CompatibilityTest : public WebGLCompatibilityTest
|
||||
@@ -3040,6 +3050,84 @@ TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
|
||||
ASSERT_GL_ERROR(GL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
+// Test WebGL-specific constraints on sizes of S3TC textures' mipmap levels.
|
||||
+TEST_P(WebGLCompatibilityTest, CompressedTexImageS3TC)
|
||||
+{
|
||||
+ const char *extensions[] = {
|
||||
+ "GL_EXT_texture_compression_dxt1",
|
||||
+ "GL_ANGLE_texture_compression_dxt3",
|
||||
+ "GL_ANGLE_texture_compression_dxt5",
|
||||
+ };
|
||||
+
|
||||
+ for (const char *extension : extensions)
|
||||
+ {
|
||||
+ if (IsGLExtensionRequestable(extension))
|
||||
+ {
|
||||
+ glRequestExtensionANGLE(extension);
|
||||
+ }
|
||||
+
|
||||
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(extension));
|
||||
+ }
|
||||
+
|
||||
+ // Ported from WebGL conformance suite:
|
||||
+ // sdk/tests/conformance/extensions/s3tc-and-srgb.html
|
||||
+ constexpr GLenum formats[] = {
|
||||
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
|
||||
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
|
||||
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
|
||||
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
|
||||
+ };
|
||||
+
|
||||
+ for (GLenum format : formats)
|
||||
+ {
|
||||
+ testCompressedTexImage(format);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// Test WebGL-specific constraints on sizes of RGTC textures' mipmap levels.
|
||||
+TEST_P(WebGLCompatibilityTest, CompressedTexImageRGTC)
|
||||
+{
|
||||
+ if (IsGLExtensionRequestable("GL_EXT_texture_compression_rgtc"))
|
||||
+ {
|
||||
+ glRequestExtensionANGLE("GL_EXT_texture_compression_rgtc");
|
||||
+ }
|
||||
+
|
||||
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_rgtc"));
|
||||
+
|
||||
+ // Ported from WebGL conformance suite:
|
||||
+ // sdk/tests/conformance/extensions/ext-texture-compression-rgtc.html
|
||||
+ constexpr GLenum formats[] = {GL_COMPRESSED_RED_RGTC1_EXT, GL_COMPRESSED_SIGNED_RED_RGTC1_EXT,
|
||||
+ GL_COMPRESSED_RED_GREEN_RGTC2_EXT,
|
||||
+ GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT};
|
||||
+
|
||||
+ for (GLenum format : formats)
|
||||
+ {
|
||||
+ testCompressedTexImage(format);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// Test WebGL-specific constraints on sizes of BPTC textures' mipmap levels.
|
||||
+TEST_P(WebGLCompatibilityTest, CompressedTexImageBPTC)
|
||||
+{
|
||||
+ if (IsGLExtensionRequestable("GL_EXT_texture_compression_bptc"))
|
||||
+ {
|
||||
+ glRequestExtensionANGLE("GL_EXT_texture_compression_bptc");
|
||||
+ }
|
||||
+
|
||||
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc"));
|
||||
+
|
||||
+ // Ported from WebGL conformance suite:
|
||||
+ // sdk/tests/conformance/extensions/ext-texture-compression-bptc.html
|
||||
+ constexpr GLenum formats[] = {
|
||||
+ GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT,
|
||||
+ GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT};
|
||||
+
|
||||
+ for (GLenum format : formats)
|
||||
+ {
|
||||
+ testCompressedTexImage(format);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
TEST_P(WebGLCompatibilityTest, L32FTextures)
|
||||
{
|
||||
constexpr float textureData[] = {15.1f, 0.0f, 0.0f, 0.0f};
|
||||
@@ -4937,6 +5025,119 @@ void WebGLCompatibilityTest::validateCompressedTexImageExtensionFormat(GLenum fo
|
||||
}
|
||||
}
|
||||
|
||||
+GLint WebGLCompatibilityTest::expectedByteLength(GLenum format, GLsizei width, GLsizei height)
|
||||
+{
|
||||
+ switch (format)
|
||||
+ {
|
||||
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
||||
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
+ case GL_COMPRESSED_RED_RGTC1_EXT:
|
||||
+ case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
|
||||
+ return ((width + 3) / 4) * ((height + 3) / 4) * 8;
|
||||
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
+ case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
|
||||
+ case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
|
||||
+ case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT:
|
||||
+ case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:
|
||||
+ case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT:
|
||||
+ case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT:
|
||||
+ return ((width + 3) / 4) * ((height + 3) / 4) * 16;
|
||||
+ }
|
||||
+
|
||||
+ UNREACHABLE();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void WebGLCompatibilityTest::testCompressedTexLevelDimension(GLenum format,
|
||||
+ GLint level,
|
||||
+ GLsizei width,
|
||||
+ GLsizei height,
|
||||
+ GLsizei expectedByteLength,
|
||||
+ GLenum expectedError,
|
||||
+ const char *explanation)
|
||||
+{
|
||||
+ std::vector<uint8_t> tempVector(expectedByteLength, 0);
|
||||
+
|
||||
+ EXPECT_GL_NO_ERROR();
|
||||
+
|
||||
+ GLTexture sourceTexture;
|
||||
+ glBindTexture(GL_TEXTURE_2D, sourceTexture);
|
||||
+ glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, expectedByteLength,
|
||||
+ tempVector.data());
|
||||
+ if (expectedError == 0)
|
||||
+ {
|
||||
+ EXPECT_GL_NO_ERROR() << explanation;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ EXPECT_GL_ERROR(expectedError) << explanation;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void WebGLCompatibilityTest::testCompressedTexImage(GLenum format)
|
||||
+{
|
||||
+ struct TestCase
|
||||
+ {
|
||||
+ GLint level;
|
||||
+ GLsizei width;
|
||||
+ GLsizei height;
|
||||
+ GLenum expectedError;
|
||||
+ const char *explanation;
|
||||
+ };
|
||||
+
|
||||
+ constexpr TestCase testCases[] = {
|
||||
+ {0, 4, 3, GL_INVALID_OPERATION, "level is 0, height is not a multiple of 4"},
|
||||
+ {0, 3, 4, GL_INVALID_OPERATION, "level is 0, width is not a multiple of 4"},
|
||||
+ {0, 2, 2, GL_INVALID_OPERATION, "level is 0, width is not a multiple of 4"},
|
||||
+ {0, 4, 4, GL_NO_ERROR, "is valid"},
|
||||
+ {1, 1, 1, GL_INVALID_OPERATION, "implied base mip 2x2 is invalid"},
|
||||
+ {1, 1, 2, GL_INVALID_OPERATION, "implied base mip 2x4 is invalid"},
|
||||
+ {1, 2, 1, GL_INVALID_OPERATION, "implied base mip 4x2 is invalid"},
|
||||
+ {1, 2, 2, GL_NO_ERROR, "implied base mip 4x4 is valid"},
|
||||
+ };
|
||||
+
|
||||
+ constexpr TestCase webgl2TestCases[] = {
|
||||
+ {0, 0, 0, GL_NO_ERROR, "0: 0x0 is valid"},
|
||||
+ {0, 1, 1, GL_INVALID_OPERATION, "0: 1x1 is invalid"},
|
||||
+ {0, 2, 2, GL_INVALID_OPERATION, "0: 2x2 is invalid"},
|
||||
+ {0, 3, 3, GL_INVALID_OPERATION, "0: 3x3 is invalid"},
|
||||
+ {0, 10, 10, GL_INVALID_OPERATION, "0: 10x10 is invalid"},
|
||||
+ {0, 11, 11, GL_INVALID_OPERATION, "0: 11x11 is invalid"},
|
||||
+ {0, 11, 12, GL_INVALID_OPERATION, "0: 11x12 is invalid"},
|
||||
+ {0, 12, 11, GL_INVALID_OPERATION, "0: 12x11 is invalid"},
|
||||
+ {0, 12, 12, GL_NO_ERROR, "0: 12x12 is valid"},
|
||||
+ {1, 0, 0, GL_NO_ERROR, "1: 0x0 is valid"},
|
||||
+ {1, 3, 3, GL_INVALID_OPERATION, "1: 3x3 is invalid"},
|
||||
+ {1, 5, 5, GL_INVALID_OPERATION, "1: 5x5 is invalid"},
|
||||
+ {1, 5, 6, GL_INVALID_OPERATION, "1: 5x6 is invalid"},
|
||||
+ {1, 6, 5, GL_INVALID_OPERATION, "1: 6x5 is invalid"},
|
||||
+ {1, 6, 6, GL_NO_ERROR, "1: 6x6 is valid"},
|
||||
+ {2, 0, 0, GL_NO_ERROR, "2: 0x0 is valid"},
|
||||
+ {2, 3, 3, GL_NO_ERROR, "2: 3x3 is valid"},
|
||||
+ {3, 1, 3, GL_NO_ERROR, "3: 1x3 is valid"},
|
||||
+ {3, 1, 1, GL_NO_ERROR, "3: 1x1 is valid"},
|
||||
+ {2, 1, 3, GL_NO_ERROR, "implied base mip 4x12 is valid"},
|
||||
+ };
|
||||
+
|
||||
+ for (const TestCase &test : testCases)
|
||||
+ {
|
||||
+ testCompressedTexLevelDimension(format, test.level, test.width, test.height,
|
||||
+ expectedByteLength(format, test.width, test.height),
|
||||
+ test.expectedError, test.explanation);
|
||||
+ }
|
||||
+
|
||||
+ if (getClientMajorVersion() >= 3)
|
||||
+ {
|
||||
+ for (const TestCase &test : webgl2TestCases)
|
||||
+ {
|
||||
+ testCompressedTexLevelDimension(format, test.level, test.width, test.height,
|
||||
+ expectedByteLength(format, test.width, test.height),
|
||||
+ test.expectedError, test.explanation);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
// Test enabling GL_EXT_texture_compression_dxt1 for GL_COMPRESSED_RGB_S3TC_DXT1_EXT
|
||||
TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1RGB)
|
||||
{
|
||||
@@ -0,0 +1,34 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Fri, 3 Sep 2021 09:34:10 -0400
|
||||
Subject: WebGL: Make unsuccessful links fail subsequent draw calls.
|
||||
|
||||
This protects against incomplete state updates during a failed
|
||||
link call that can interfere with draw calls.
|
||||
|
||||
Bug: angleproject:6358
|
||||
Bug: chromium:1241123
|
||||
Change-Id: Ie892654c3a58c69d6e35ba3c41758ab6269d8193
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3140496
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Commit-Queue: Yuly Novikov <ynovikov@chromium.org>
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3152556
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
|
||||
index 412b9aa0f1d75c40ce02522589c53e943d049228..7826233f206b2ae7b926cd2564c887c726b79930 100644
|
||||
--- a/src/libANGLE/validationES.cpp
|
||||
+++ b/src/libANGLE/validationES.cpp
|
||||
@@ -3958,6 +3958,12 @@ const char *ValidateDrawStates(const Context *context)
|
||||
{
|
||||
return kVertexBufferBoundForTransformFeedback;
|
||||
}
|
||||
+
|
||||
+ // Validate that we are rendering with a linked program.
|
||||
+ if (!program->isLinked())
|
||||
+ {
|
||||
+ return kProgramNotLinked;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
expose_ripemd160.patch
|
||||
expose_aes-cfb.patch
|
||||
expose_des-ede3.patch
|
||||
enable_x509_v_flag_trusted_first_flag.patch
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Juan Cruz Viotti <jv@jviotti.com>
|
||||
Date: Thu, 30 Sep 2021 13:39:23 -0400
|
||||
Subject: Enable X509_V_FLAG_TRUSTED_FIRST flag
|
||||
|
||||
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
|
||||
|
||||
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
|
||||
index d8d1efe883321510e4da1aab2cd78378e395c2b2..a371d611dbb2ea7a287a3cb117c3e3d0e1a925b6 100644
|
||||
--- a/crypto/x509/x509_vpm.c
|
||||
+++ b/crypto/x509/x509_vpm.c
|
||||
@@ -548,7 +548,7 @@ static const X509_VERIFY_PARAM default_table[] = {
|
||||
(char *)"default", /* X509 default parameters */
|
||||
0, /* Check time */
|
||||
0, /* internal flags */
|
||||
- 0, /* flags */
|
||||
+ X509_V_FLAG_TRUSTED_FIRST, /* flags */
|
||||
0, /* purpose */
|
||||
0, /* trust */
|
||||
100, /* depth */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user