Compare commits

..

38 Commits

Author SHA1 Message Date
Sudowoodo Release Bot
33670ac928 Bump v20.0.0-alpha.7 2022-06-20 06:31:05 -07:00
trop[bot]
8ecbc11aa2 chore: fix BrowserView painting when origin updated (#34643)
chore: fix View painting when origin updated

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-20 16:41:42 +09:00
trop[bot]
4ab3b1d624 refactor: use stubs for gdk-pixbuf dependency (#34635)
* refactor: use stubs for gdk-pixbuf dependency

* Adjust build file

* Add includes

* Merge gdk_pixbuf stubs into gtk stubs

* Split pixbuf sigs into own file again

* Add initialization check

* Apply PR feedback

Co-authored-by: Raymond Zhao <raymondzhao@microsoft.com>
Co-authored-by: Raymond Zhao <7199958+rzhao271@users.noreply.github.com>
2022-06-20 16:40:12 +09:00
trop[bot]
bce95c4886 test: add missing page-title-updated event spec for webview (#34544)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2022-06-20 13:33:33 +09:00
trop[bot]
5b583c8808 feat: add immersive dark mode on windows (#34549)
feat: add immersive dark mode on windows (#33624)

* feat: add immersive dark mode

* fix syntax and add header

* add me

* Update fuses.json5

* fix: redraw title bar on dark mode change

* chore: SetWindowTheme doesn't seem to be needed

* chore: separate out Win 10 dark mode implementation

* final touches

* final touches

* chore: limit Win 10 to >= 20H1 and drop fuse

* fix types

* fix lint

Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

Co-authored-by: Michaela Laurencin <35157522+mlaurencin@users.noreply.github.com>
Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-06-20 13:33:01 +09:00
trop[bot]
c20d6e54c5 fix: draggable regions updating on bounds change (#34612)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-20 13:30:39 +09:00
trop[bot]
ff7f2a5091 fix: make preload calculation identical between sandbox & non-sandboxed (#34585)
* fix: make preload calculation identical between sandbox & non-sandboxed

* fix test

* split IPCs

* fix ipc constant

* fix unneeded async function

* remove unused preloads blink preferences

* fix typings

Co-authored-by: Jeremy Rose <japthorp@slack-corp.com>
2022-06-20 10:02:49 +09:00
trop[bot]
10062c9a5b chore: warn when using the deprecated new-window event (#34593)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2022-06-20 10:00:10 +09:00
Sudowoodo Release Bot
82a6e9bd5a Bump v20.0.0-alpha.6 2022-06-16 06:31:00 -07:00
trop[bot]
10131e36f3 fix: crash when setWindowOpenHandler callback throws (#34547)
* fix: crash when setWindowOpenHandler throws

* refactor: throw as process uncaughtException event

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-15 14:25:41 +09:00
trop[bot]
37078297c6 fix: all files selection logic on linux (#34516)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-14 12:36:02 -04:00
trop[bot]
48f4ef65ed refactor: move duplicate code to RendererClientBase::ShouldLoadPreload helper (#34520)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2022-06-13 17:37:28 -04:00
trop[bot]
e174aac845 fix: make navigator.userAgentData non-empty (#34524)
fix: make navigator.userAgentData non-empty (#34481)

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-06-13 16:04:47 -04:00
trop[bot]
dd1a692aba chore: remove unused proxy-window-open.snapshot.txt (#34521)
chore: remove unused spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt

Co-authored-by: Milan Burda <milan.burda@gmail.com>
2022-06-13 16:21:57 +02:00
Sudowoodo Release Bot
aa05c43994 Bump v20.0.0-alpha.5 2022-06-13 06:30:54 -07:00
trop[bot]
16561d08ae fix: update normal bounds prior to minimizing (#34486)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-13 11:17:42 +02:00
trop[bot]
edc0a47c89 fix: don't require glibc 2.29+ on linux arm64 builds (#34503)
* build: use sid sysroot for linux arm64

* try this

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-06-10 20:55:44 -04:00
Sudowoodo Release Bot
018e2aee8d Bump v20.0.0-alpha.4 2022-06-09 06:30:35 -07:00
trop[bot]
dd10a5ebf2 build: update clang-format script (#34479)
* build: fix clang-format script

* chore: remove python2 cases

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-09 11:13:57 +09:00
trop[bot]
2fe7d59437 chore: fix nan spec runner on macOS (#34462)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-09 09:54:58 +09:00
trop[bot]
a4a9210d2d chore: use --root instead of --project_root for cpplint (#34474)
--root has been improved upstream in depot_tools to better handle Windows:
https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/3648533

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-06-08 12:17:41 -04:00
trop[bot]
69179bbfe7 fix: html fullscreen transitions stacking (#34468)
* fix: html fullscreen transitions stacking

* spec: move webview test to spec-main

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-06-08 11:33:17 +02:00
trop[bot]
b64b87a8d6 test: fix for flaky renderer crash test (#34454)
Co-authored-by: samuelmaddock <samuel.maddock@gmail.com>
2022-06-08 16:44:06 +09:00
trop[bot]
7bdc9d8039 fix: fullscreen windows aren't resizable on macOS (#34433)
* fix: fullscreen windows aren't resizable on macOS

* chore: GetStyleMask -> HasStyleMask

* chore: depreacate style names

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-06-06 15:03:51 -04:00
trop[bot]
cbe2a458c9 docs: fix did-frame-navigate example in webFrameMain docs (#34446)
docs: fix did-frame-navigate example in webFrameMain docs

Co-authored-by: Will Anderson <will@itsananderson.com>
2022-06-06 11:18:56 -04:00
Sudowoodo Release Bot
d20e547316 Bump v20.0.0-alpha.3 2022-06-06 06:30:51 -07:00
trop[bot]
bde27c7e6b fix: render process crash handling (#34432)
* fix: crash when renderer process is reused

Could occur when a renderer crashes and the same-origin URL is loaded again
which leads to reusing the renderer process.

* test: renderer process crash recovery

* fix: handle case which leads to render frame DCHECK

* fix: lint

Co-authored-by: samuelmaddock <samuel.maddock@gmail.com>
2022-06-02 19:53:12 -07:00
Sudowoodo Release Bot
d0d5e20efb Bump v20.0.0-alpha.2 2022-06-02 15:59:51 -07:00
trop[bot]
dc452de295 chore: increase timeout for electron-build step (#34429)
Co-authored-by: VerteDinde <vertedinde@electronjs.org>
2022-06-02 15:58:10 -07:00
trop[bot]
ade2b02e1c build: disable 32-bit Windows symbol generation (#34426)
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
2022-06-02 11:14:04 -07:00
trop[bot]
73e3c29c94 fix: crash in WebFrameMain mojo connection when RenderFrameHost is nullptr (#34417)
* fix: crash when RenderFrameHost is nullptr

* chore: lint fix

Co-authored-by: samuelmaddock <samuel.maddock@gmail.com>
2022-06-02 09:44:10 -07:00
Sudowoodo Release Bot
24df260185 Revert "Bump v20.0.0-alpha.2"
This reverts commit 4fe31bd1aa.
2022-06-02 08:49:30 -07:00
Sudowoodo Release Bot
4fe31bd1aa Bump v20.0.0-alpha.2 2022-06-02 06:30:59 -07:00
electron-roller[bot]
948949f83d chore: bump chromium to 104.0.5073.0 (20-x-y) (#34352) 2022-06-02 10:54:37 +02:00
trop[bot]
bba63609f2 ci: cache python install to better deal with download errors. (#34409)
* ci: cache python install to better deal with download errors.

* chore: use our CDN to download python2

* build: DRY up the python install steps

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Samuel Attard <sattard@salesforce.com>
2022-06-02 15:16:46 +09:00
trop[bot]
4b793692ea fix: zombie windows when fullscreening and closing (#34393)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-05-31 13:15:31 -04:00
trop[bot]
f3da81cb77 fix: hide content protected windows during screen capture with ScreenCaptureKitMac (#34384)
fix: hide content protected windows during screen capture

Co-authored-by: Samuel Attard <sattard@salesforce.com>
2022-05-31 15:33:17 +09:00
Sudowoodo Release Bot
6f8bf917f7 Bump v20.0.0-alpha.1 2022-05-25 06:26:17 -07:00
580 changed files with 7557 additions and 11184 deletions

View File

@@ -53,8 +53,14 @@ executors:
description: "macOS executor size"
type: enum
enum: ["macos.x86.medium.gen2", "large"]
xcode:
description: "xcode version"
default: 13.3.0
type: enum
enum: ["12.4.0", "13.3.0"]
macos:
xcode: 13.3.0
xcode: << parameters.xcode >>
resource_class: << parameters.size >>
# Electron Runners
@@ -119,9 +125,6 @@ env-apple-silicon: &env-apple-silicon
USE_PREBUILT_V8_CONTEXT_SNAPSHOT: 1
npm_config_arch: arm64
env-runner: &env-runner
IS_ELECTRON_RUNNER: 1
env-arm64: &env-arm64
GN_EXTRA_ARGS: 'target_cpu = "arm64" fatal_linker_warnings = false enable_linux_installer = false'
MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm64
@@ -346,7 +349,7 @@ step-wait-for-goma: &step-wait-for-goma
sleep 5
done
echo "Goma ready"
no_output_timeout: 5m
no_output_timeout: 2m
step-restore-brew-cache: &step-restore-brew-cache
restore_cache:
@@ -508,7 +511,6 @@ step-install-signing-cert-on-mac: &step-install-signing-cert-on-mac
name: Import and trust self-signed codesigning cert on MacOS
command: |
if [ "$TARGET_ARCH" != "arm64" ] && [ "`uname`" == "Darwin" ]; then
sudo security authorizationdb write com.apple.trust-settings.admin allow
cd src/electron
./script/codesign/generate-identity.sh
fi
@@ -635,9 +637,9 @@ step-electron-publish: &step-electron-publish
cd src/electron
if [ "$UPLOAD_TO_STORAGE" == "1" ]; then
echo 'Uploading Electron release distribution to Azure'
script/release/uploaders/upload.py --verbose --upload_to_storage
script/release/uploaders/upload.py --verbose --UPLOAD_TO_STORAGE
else
echo 'Uploading Electron release distribution to GitHub releases'
echo 'Uploading Electron release distribution to Github releases'
script/release/uploaders/upload.py --verbose
fi
@@ -661,7 +663,6 @@ step-persist-data-for-tests: &step-persist-data-for-tests
- src/buildtools/third_party/libc++
- src/buildtools/third_party/libc++abi
- src/out/Default/obj/buildtools/third_party
- src/v8/tools/builtins-pgo
step-electron-dist-unzip: &step-electron-dist-unzip
run:
@@ -1007,17 +1008,9 @@ steps-electron-gn-check: &steps-electron-gn-check
- *step-generate-deps-hash
- *step-touch-sync-done
- maybe-restore-portaled-src-cache
- run:
name: Ensure src checkout worked
command: |
if [ ! -d "src/third_party/blink" ]; then
echo src cache was not restored for an unknown reason
exit 1
fi
- run:
name: Wipe Electron
command: rm -rf src/electron
- *step-checkout-electron
- *step-wait-for-goma
- *step-gn-gen-default
- *step-gn-check
steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-change
steps:
@@ -1039,7 +1032,6 @@ steps-tests: &steps-tests
- *step-setup-linux-for-headless-testing
- *step-restore-brew-cache
- *step-fix-known-hosts-linux
- install-python2-mac
- *step-install-signing-cert-on-mac
- run:
@@ -1138,7 +1130,7 @@ commands:
- run:
name: Install python2 on macos
command: |
if [ "`uname`" == "Darwin" ] && [ "$IS_ELECTRON_RUNNER" != "1" ]; then
if [ "`uname`" == "Darwin" ]; then
if [ ! -f "python-downloads/python-2.7.18-macosx10.9.pkg" ]; then
mkdir python-downloads
echo 'Downloading Python 2.7.18'
@@ -2052,6 +2044,7 @@ jobs:
osx-testing-x64-tests:
executor:
name: macos
xcode: 12.4.0
size: macos.x86.medium.gen2
environment:
<<: *env-mac-large
@@ -2065,12 +2058,12 @@ jobs:
<<: *env-mac-large
<<: *env-stack-dumping
<<: *env-apple-silicon
<<: *env-runner
<<: *steps-tests
mas-testing-x64-tests:
executor:
name: macos
xcode: 12.4.0
size: macos.x86.medium.gen2
environment:
<<: *env-mac-large
@@ -2084,7 +2077,6 @@ jobs:
<<: *env-mac-large
<<: *env-stack-dumping
<<: *env-apple-silicon
<<: *env-runner
<<: *steps-tests
# List all workflows

View File

@@ -1,178 +0,0 @@
name: Electron WOA Testing
on:
push:
branches: '**'
workflow_dispatch:
inputs:
appveyor_job_id:
description: 'Job Id of Appveyor WOA job to test'
type: text
required: true
jobs:
electron-woa-init:
if: ${{ github.event_name == 'push' && github.repository == 'electron/electron' }}
runs-on: ubuntu-latest
steps:
- name: Dummy step for push event
run: |
echo "This job is a needed initialization step for Electron WOA testing. Another test result will appear once the electron-woa-testing build is done."
electron-woa-testing:
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'electron/electron' }}
runs-on: [self-hosted, woa]
permissions:
checks: write
pull-requests: write
steps:
- uses: LouisBrunner/checks-action@v1.1.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: electron-woa-testing
status: in_progress
details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
output: |
{"summary":"Test In Progress","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}
- name: Clean Workspace
run: |
Remove-Item * -Recurse -Force
shell: powershell
- name: Checkout
uses: actions/checkout@v3
with:
path: src\electron
fetch-depth: 0
- name: Yarn install
run: |
cd src\electron
node script/yarn.js install --frozen-lockfile
- name: Download and extract dist.zip for test
run: |
$localArtifactPath = "$pwd\dist.zip"
$serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/dist.zip"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" }
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\Default -y $localArtifactPath
shell: powershell
- name: Download and extract native test executables for test
run: |
$localArtifactPath = "src\out\Default\shell_browser_ui_unittests.exe"
$serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/shell_browser_ui_unittests.exe"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" }
shell: powershell
- name: Download and extract ffmpeg.zip for test
run: |
$localArtifactPath = "$pwd\ffmpeg.zip"
$serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/ffmpeg.zip"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" }
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\ffmpeg $localArtifactPath
shell: powershell
- name: Download node headers for test
run: |
$localArtifactPath = "src\node_headers.zip"
$serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/node_headers.zip"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" }
cd src
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y node_headers.zip
shell: powershell
- name: Download electron.lib for test
run: |
$localArtifactPath = "src\out\Default\electron.lib"
$serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/electron.lib"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" }
shell: powershell
# Uncomment the following block if pdb files are needed to debug issues
# - name: Download pdb files for detailed stacktraces
# if: ${{ github.event_name == 'workflow_dispatch' }}
# run: |
# try {
# $localArtifactPath = "src\pdb.zip"
# $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/pdb.zip"
# Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" }
# cd src
# & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y pdb.zip
# } catch {
# Write-Host "There was an exception encountered while downloading pdb files:" $_.Exception.Message
# } finally {
# $global:LASTEXITCODE = 0
# }
# shell: powershell
- name: Setup node headers
run: |
New-Item src\out\Default\gen\node_headers\Release -Type directory
Copy-Item -path src\out\Default\electron.lib -destination src\out\Default\gen\node_headers\Release\node.lib
shell: powershell
- name: Run Electron Main process tests
run: |
cd src
set npm_config_nodedir=%cd%\out\Default\gen\node_headers
set npm_config_arch=arm64
cd electron
node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion
env:
ELECTRON_ENABLE_STACK_DUMPING: true
ELECTRON_OUT_DIR: Default
IGNORE_YARN_INSTALL_ERROR: 1
ELECTRON_TEST_RESULTS_DIR: junit
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
MOCHA_REPORTER: mocha-multi-reporters
ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
- name: Run Electron Remote based tests
if: ${{ success() || failure() }}
run: |
cd src
set npm_config_nodedir=%cd%\out\Default\gen\node_headers
set npm_config_arch=arm64
cd electron
node script/yarn test --runners=remote --enable-logging --disable-features=CalculateNativeWinOcclusion
env:
ELECTRON_OUT_DIR: Default
IGNORE_YARN_INSTALL_ERROR: 1
ELECTRON_TEST_RESULTS_DIR: junit
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
MOCHA_REPORTER: mocha-multi-reporters
ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
- name: Verify ffmpeg
run: |
cd src
echo "Verifying non proprietary ffmpeg"
python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg
shell: cmd
- name: Kill processes left running from last test run
if: ${{ always() }}
run: |
Get-Process | Where Name -Like "electron*" | Stop-Process
Get-Process | Where Name -Like "msedge*" | Stop-Process
shell: powershell
- name: Delete user app data directories
if: ${{ always() }}
run: |
Remove-Item -path $env:APPDATA/Electron* -Recurse -Force -ErrorAction Ignore
shell: powershell
- uses: LouisBrunner/checks-action@v1.1.1
if: ${{ success() }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: electron-woa-testing
conclusion: "${{ job.status }}"
details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
output: |
{"summary":"${{ job.status }}","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}
- uses: LouisBrunner/checks-action@v1.1.1
if: ${{ success() }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: electron-woa-testing
conclusion: "${{ job.status }}"
details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
output: |
{"summary":"Job Succeeded","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}
- uses: LouisBrunner/checks-action@v1.1.1
if: ${{ ! success() }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: electron-woa-testing
conclusion: "${{ job.status }}"
details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
output: |
{"summary":"Job Failed","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}

View File

@@ -1,31 +0,0 @@
name: Trigger Major Release Dependency Updates
on:
release:
types: [published]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
check_tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check Tag
run: |
if [[ ${{ github.event.ref }} =~ ^refs/tags/v[0-9]+\.0\.0$ ]]; then
echo ::set-output name=should_release::true
fi
trigger:
runs-on: ubuntu-latest
needs: check_tag
if: jobs.check_tag.outputs.should_release == 'true'
steps:
- uses: actions/checkout@v3
- name: Trigger New chromedriver Release
run: |
gh api /repos/:owner/chromedriver/actions/workflows/release.yml/dispatches --input - <<< '{"ref":"main","inputs":{"version":"${{ github.event.release.tag_name }}"}}'
- name: Trigger New mksnapshot Release
run: |
gh api /repos/:owner/mksnapshot/actions/workflows/release.yml/dispatches --input - <<< '{"ref":"main","inputs":{"version":"${{ github.event.release.tag_name }}"}}'

1
.husky/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
_

View File

@@ -23,5 +23,7 @@
"br_spaces": 0
},
"single-h1": false,
"no-inline-html": false
"no-inline-html": {
"allowed_elements": ["br"]
}
}

View File

@@ -135,7 +135,7 @@ config("electron_lib_config") {
include_dirs = [ "." ]
}
# We generate the definitions twice here, once in //electron/electron.d.ts
# We geneate the definitions twice here, once in //electron/electron.d.ts
# and once in $target_gen_dir
# The one in $target_gen_dir is used for the actual TSC build later one
# and the one in //electron/electron.d.ts is used by your IDE (vscode)
@@ -233,7 +233,6 @@ action("electron_js2c") {
action("generate_config_gypi") {
outputs = [ "$root_gen_dir/config.gypi" ]
script = "script/generate-config-gypi.py"
inputs = [ "//third_party/electron_node/configure.py" ]
args = rebase_path(outputs) + [ target_cpu ]
}
@@ -391,7 +390,6 @@ source_set("electron_lib") {
"//components/user_prefs",
"//components/viz/host",
"//components/viz/service",
"//components/webrtc",
"//content/public/browser",
"//content/public/child",
"//content/public/gpu",
@@ -567,9 +565,8 @@ source_set("electron_lib") {
"//ui/base/ime/linux",
"//ui/events/devices/x11",
"//ui/events/platform/x11",
"//ui/linux:linux_ui",
"//ui/linux:linux_ui_factory",
"//ui/views/controls/webview",
"//ui/views/linux_ui:linux_ui_factory",
"//ui/wm",
]
if (ozone_platform_x11) {
@@ -674,6 +671,8 @@ source_set("electron_lib") {
if (enable_basic_printing) {
sources += [
"shell/browser/printing/print_preview_message_handler.cc",
"shell/browser/printing/print_preview_message_handler.h",
"shell/browser/printing/print_view_manager_electron.cc",
"shell/browser/printing/print_view_manager_electron.h",
"shell/renderer/printing/print_render_frame_helper_delegate.cc",
@@ -901,13 +900,6 @@ if (is_mac) {
"@executable_path/../../../../../..",
]
}
# For component ffmpeg under non-component build, it is linked from
# @loader_path. However the ffmpeg.dylib is moved to a different place
# when generating app bundle, and we should change to link from @rpath.
if (is_component_ffmpeg && !is_component_build) {
ldflags += [ "-Wcrl,installnametool,-change,@loader_path/libffmpeg.dylib,@rpath/libffmpeg.dylib" ]
}
}
template("electron_helper_app") {

4
DEPS
View File

@@ -2,9 +2,9 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'106.0.5216.0',
'104.0.5073.0',
'node_version':
'v16.16.0',
'v16.15.0',
'nan_version':
'16fa32231e2ccd89d2804b3f765319128b20c4ac',
'squirrel.mac_version':

View File

@@ -1 +1 @@
21.0.0-beta.1
20.0.0-alpha.7

View File

@@ -2,7 +2,7 @@
[![CircleCI Build Status](https://circleci.com/gh/electron/electron/tree/main.svg?style=shield)](https://circleci.com/gh/electron/electron/tree/main)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/main?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/main)
[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.gg/electronjs)
[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.com/invite/APGC3k5yaH)
:memo: Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪.
View these docs in other languages at [electron/i18n](https://github.com/electron/i18n/tree/master/content/).

View File

@@ -3,7 +3,7 @@
# - "GN_EXTRA_ARGS" Additional gn arguments for a build config,
# e.g. 'target_cpu="x86"' to build for a 32bit platform.
# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordningly
# if you pass a custom value for 'target_cpu'.
# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success.
# - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules.
@@ -12,7 +12,7 @@
# Is used in some publishing scripts, but does NOT affect the Electron binary.
# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value.
# - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket.
# Otherwise the release will be uploaded to the GitHub Releases.
# Otherwise the release will be uploaded to the Github Releases.
# (The value is only checked if "ELECTRON_RELEASE" is defined.)
#
# The publishing scripts expect access tokens to be defined as env vars,
@@ -34,6 +34,16 @@ environment:
MOCHA_REPORTER: mocha-multi-reporters
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
GOMA_FALLBACK_ON_AUTH_FAILURE: true
notifications:
- provider: Webhook
url: https://electron-mission-control.herokuapp.com/rest/appveyor-hook
method: POST
headers:
x-mission-control-secret:
secure: 90BLVPcqhJPG7d24v0q/RRray6W3wDQ8uVQlQjOHaBWkw1i8FoA1lsjr2C/v1dVok+tS2Pi6KxDctPUkwIb4T27u4RhvmcPzQhVpfwVJAG9oNtq+yKN7vzHfg7k/pojEzVdJpQLzeJGcSrZu7VY39Q==
on_build_success: false
on_build_failure: true
on_build_status_changed: false
build_script:
- ps: >-
if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) {
@@ -170,16 +180,19 @@ build_script:
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
- 7z a node_headers.zip out\Default\gen\node_headers
# Temporarily disable symbol generation on 32-bit Windows due to failures
- ps: >-
if ($env:GN_CONFIG -eq 'release') {
if ($env:GN_CONFIG -eq 'release' -And $env:TARGET_ARCH -ne 'ia32') {
# Needed for msdia140.dll on 64-bit windows
$env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin"
ninja -C out/Default electron:electron_symbols
}
- ps: >-
if ($env:GN_CONFIG -eq 'release') {
python electron\script\zip-symbols.py
appveyor-retry appveyor PushArtifact out/Default/symbols.zip
if ($env:TARGET_ARCH -ne 'ia32') {
python electron\script\zip-symbols.py
appveyor-retry appveyor PushArtifact out/Default/symbols.zip
}
} else {
# It's useful to have pdb files when debugging testing builds that are
# built on CI.
@@ -201,9 +214,10 @@ test_script:
echo "Skipping tests for $env:GN_CONFIG build"
}
- cd electron
- if "%RUN_TESTS%"=="true" ( echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log )
- if "%RUN_TESTS%"=="true" ( echo Running remote test suite & node script/yarn test -- --trace-uncaught --runners=remote --runTestFilesSeparately --enable-logging=file --log-file=%cd%\electron.log )
- if "%RUN_TESTS%"=="true" ( echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log )
# CalculateNativeWinOcclusion is disabled due to https://bugs.chromium.org/p/chromium/issues/detail?id=1139022
- if "%RUN_TESTS%"=="true" ( echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion )
- if "%RUN_TESTS%"=="true" ( echo Running remote test suite & node script/yarn test -- --trace-uncaught --runners=remote --runTestFilesSeperately --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion )
- if "%RUN_TESTS%"=="true" ( echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion )
- cd ..
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
- echo "About to verify mksnapshot"
@@ -223,7 +237,7 @@ deploy_script:
& python script\release\uploaders\upload.py --verbose
}
} elseif (Test-Path Env:\TEST_WOA) {
node script/release/ci-release-build.js --job=electron-woa-testing --ci=GHA --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH
node script/release/ci-release-build.js --job=electron-woa-testing --ci=VSTS --armTest --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH
}
on_finish:
# Uncomment this lines to enable RDP

121
azure-pipelines-arm.yml Normal file
View File

@@ -0,0 +1,121 @@
steps:
- task: CopyFiles@2
displayName: 'Copy Files to: src/electron'
inputs:
TargetFolder: src/electron
- bash: |
cd src/electron
node script/yarn.js install --frozen-lockfile
displayName: 'Yarn install'
- bash: |
export ZIP_DEST=$PWD/src/out/Default
echo "##vso[task.setvariable variable=ZIP_DEST]$ZIP_DEST"
mkdir -p $ZIP_DEST
cd src/electron
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=dist.zip --dest=$ZIP_DEST
cd $ZIP_DEST
unzip -o dist.zip
xattr -cr Electron.app
displayName: 'Download and unzip dist files for test'
env:
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
- bash: |
export FFMPEG_ZIP_DEST=$PWD/src/out/ffmpeg
mkdir -p $FFMPEG_ZIP_DEST
cd src/electron
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=ffmpeg.zip --dest=$FFMPEG_ZIP_DEST
cd $FFMPEG_ZIP_DEST
unzip -o ffmpeg.zip
displayName: 'Download and unzip ffmpeg for test'
env:
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
- bash: |
export NODE_HEADERS_DEST=$PWD/src/out/Default/gen
mkdir -p $NODE_HEADERS_DEST
cd src/electron
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=node_headers.tar.gz --dest=$NODE_HEADERS_DEST
cd $NODE_HEADERS_DEST
tar xzf node_headers.tar.gz
displayName: 'Download and untar node header files for test'
env:
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
- bash: |
export CROSS_ARCH_SNAPSHOTS=$PWD/src/out/Default/cross-arch-snapshots
mkdir -p $CROSS_ARCH_SNAPSHOTS
cd src/electron
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/snapshot_blob.bin --dest=$CROSS_ARCH_SNAPSHOTS
node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=cross-arch-snapshots/v8_context_snapshot.arm64.bin --dest=$CROSS_ARCH_SNAPSHOTS
displayName: 'Download cross arch snapshot files'
env:
CIRCLE_TOKEN: $(CIRCLECI_TOKEN)
- bash: |
cd src
export ELECTRON_OUT_DIR=Default
export npm_config_arch=arm64
(cd electron && node script/yarn test --enable-logging --runners main)
displayName: 'Run Electron main tests'
timeoutInMinutes: 20
env:
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
IGNORE_YARN_INSTALL_ERROR: 1
ELECTRON_TEST_RESULTS_DIR: junit
- bash: |
cd src
export ELECTRON_OUT_DIR=Default
export npm_config_arch=arm64
(cd electron && node script/yarn test --enable-logging --runners remote)
displayName: 'Run Electron remote tests'
timeoutInMinutes: 20
condition: succeededOrFailed()
env:
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
IGNORE_YARN_INSTALL_ERROR: 1
ELECTRON_TEST_RESULTS_DIR: junit
- bash: |
cd src
python electron/script/verify-ffmpeg.py --source-root "$PWD" --build-dir out/Default --ffmpeg-path out/ffmpeg
displayName: Verify non proprietary ffmpeg
timeoutInMinutes: 5
condition: succeededOrFailed()
env:
TARGET_ARCH: arm64
- bash: |
cd src
echo Verify cross arch snapshot
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/out/Default/cross-arch-snapshots
displayName: Verify cross arch snapshot
timeoutInMinutes: 5
condition: succeededOrFailed()
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFiles: '*.xml'
searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/'
condition: succeededOrFailed()
- bash: killall Electron || echo "No Electron processes left running"
displayName: 'Kill processes left running from last test run'
condition: always()
- bash: |
rm -rf ~/Library/Application\ Support/Electron*
rm -rf ~/Library/Application\ Support/electron*
displayName: 'Delete user app data directories'
condition: always()
- task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3
displayName: 'Clean Agent Directories'
condition: always()

130
azure-pipelines-woa.yml Normal file
View File

@@ -0,0 +1,130 @@
workspace:
clean: all
steps:
- checkout: self
path: src\electron
- script: |
node script/yarn.js install --frozen-lockfile
displayName: 'Yarn install'
- powershell: |
$localArtifactPath = "$pwd\dist.zip"
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/dist.zip"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -o$(Pipeline.Workspace)\src\out\Default -y $localArtifactPath
displayName: 'Download and extract dist.zip for test'
env:
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
- powershell: |
$localArtifactPath = "$(Pipeline.Workspace)\src\out\Default\shell_browser_ui_unittests.exe"
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/shell_browser_ui_unittests.exe"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
displayName: 'Download and extract native test executables for test'
env:
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
- powershell: |
$localArtifactPath = "$pwd\ffmpeg.zip"
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/ffmpeg.zip"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -o$(Pipeline.Workspace)\src\out\ffmpeg $localArtifactPath
displayName: 'Download and extract ffmpeg.zip for test'
env:
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
- powershell: |
$localArtifactPath = "$(Pipeline.Workspace)\src\node_headers.zip"
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/node_headers.zip"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
cd $(Pipeline.Workspace)\src
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y node_headers.zip
displayName: 'Download node headers for test'
env:
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
- powershell: |
$localArtifactPath = "$(Pipeline.Workspace)\src\out\Default\electron.lib"
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/electron.lib"
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
displayName: 'Download electron.lib for test'
env:
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
# Uncomment the following block if pdb files are needed to debug issues
# - powershell: |
# try {
# $localArtifactPath = "$(Pipeline.Workspace)\src\pdb.zip"
# $serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/pdb.zip"
# Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
# cd $(Pipeline.Workspace)\src
# & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y pdb.zip
# } catch {
# Write-Host "There was an exception encountered while downloading pdb files:" $_.Exception.Message
# } finally {
# $global:LASTEXITCODE = 0
# }
# displayName: 'Download pdb files for detailed stacktraces'
# env:
# APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
- powershell: |
New-Item $(Pipeline.Workspace)\src\out\Default\gen\node_headers\Release -Type directory
Copy-Item -path $(Pipeline.Workspace)\src\out\Default\electron.lib -destination $(Pipeline.Workspace)\src\out\Default\gen\node_headers\Release\node.lib
displayName: 'Setup node headers'
- script: |
cd $(Pipeline.Workspace)\src
set npm_config_nodedir=%cd%\out\Default\gen\node_headers
set npm_config_arch=arm64
cd electron
node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion
displayName: 'Run Electron Main process tests'
env:
ELECTRON_ENABLE_STACK_DUMPING: true
ELECTRON_OUT_DIR: Default
IGNORE_YARN_INSTALL_ERROR: 1
ELECTRON_TEST_RESULTS_DIR: junit
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
MOCHA_REPORTER: mocha-multi-reporters
- script: |
cd $(Pipeline.Workspace)\src
set npm_config_nodedir=%cd%\out\Default\gen\node_headers
set npm_config_arch=arm64
cd electron
node script/yarn test --runners=remote --enable-logging --disable-features=CalculateNativeWinOcclusion
displayName: 'Run Electron Remote based tests'
env:
ELECTRON_OUT_DIR: Default
IGNORE_YARN_INSTALL_ERROR: 1
ELECTRON_TEST_RESULTS_DIR: junit
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
MOCHA_REPORTER: mocha-multi-reporters
condition: succeededOrFailed()
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFiles: '*.xml'
searchFolder: '$(Pipeline.Workspace)/src/junit/'
condition: always()
- script: |
cd $(Pipeline.Workspace)\src
echo "Verifying non proprietary ffmpeg"
python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg
displayName: 'Verify ffmpeg'
- powershell: |
Get-Process | Where Name Like "electron*" | Stop-Process
Get-Process | Where Name Like "msedge*" | Stop-Process
displayName: 'Kill processes left running from last test run'
condition: always()
- powershell: |
Remove-Item -path $env:APPDATA/Electron* -Recurse -Force -ErrorAction Ignore
displayName: 'Delete user app data directories'
condition: always()

View File

@@ -2,7 +2,7 @@ is_electron_build = true
root_extra_deps = [ "//electron" ]
# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json
node_module_version = 109
node_module_version = 107
v8_promise_internal_field_count = 1
v8_embedder_string = "-electron.0"
@@ -45,3 +45,5 @@ enable_cet_shadow_stack = false
# V8 in the browser process.
# Ref: https://source.chromium.org/chromium/chromium/src/+/45fba672185aae233e75d6ddc81ea1e0b30db050:v8/BUILD.gn;l=281
is_cfi = false
v8_enable_sandboxed_pointers = false

View File

@@ -1,22 +1,33 @@
template("node_action") {
assert(defined(invoker.script), "Need script path to run")
assert(defined(invoker.args), "Need script arguments")
import("node.gni")
# TODO(MarshallOfSound): Move to electron/node, this is the only place it is used now
# Run an action with a given working directory. Behaves identically to the
# action() target type, with the exception that it changes directory before
# running the script.
#
# Parameters:
# cwd [required]: Directory to change to before running the script.
template("chdir_action") {
action(target_name) {
forward_variables_from(invoker,
"*",
[
"deps",
"public_deps",
"sources",
"inputs",
"outputs",
"script",
"args",
])
if (!defined(inputs)) {
inputs = []
assert(defined(cwd), "Need cwd in $target_name")
script = "//electron/build/run-in-dir.py"
if (defined(sources)) {
sources += [ invoker.script ]
} else {
assert(defined(inputs))
inputs += [ invoker.script ]
}
inputs += [ invoker.script ]
script = "//electron/build/run-node.py"
args = [ rebase_path(invoker.script) ] + invoker.args
args = [
rebase_path(cwd),
rebase_path(invoker.script),
]
args += invoker.args
}
}

View File

@@ -1,3 +1,23 @@
config("build_time_executable") {
configs = []
if (is_electron_build && !is_component_build) {
# The executables which have this config applied are dependent on ffmpeg,
# which is always a shared library in an Electron build. However, in the
# non-component build, executables don't have rpath set to search for
# libraries in the executable's directory, so ffmpeg cannot be found. So
# let's make sure rpath is set here.
# See '//build/config/gcc/BUILD.gn' for details on the rpath setting.
if (is_linux) {
configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
}
if (is_mac) {
ldflags = [ "-Wl,-rpath,@loader_path/." ]
}
}
}
# For MAS build, we force defining "MAS_BUILD".
config("mas_build") {
if (is_mas_build) {

View File

@@ -24,11 +24,7 @@ template("extract_symbols") {
assert(defined(invoker.binary), "Need binary to dump")
assert(defined(invoker.symbol_dir), "Need directory for symbol output")
if (host_os == "win" && target_cpu == "x86") {
dump_syms_label = "//third_party/breakpad:dump_syms(//build/toolchain/win:win_clang_x64)"
} else {
dump_syms_label = "//third_party/breakpad:dump_syms($host_toolchain)"
}
dump_syms_label = "//third_party/breakpad:dump_syms($host_toolchain)"
dump_syms_binary = get_label_info(dump_syms_label, "root_out_dir") +
"/dump_syms$_host_executable_suffix"

View File

@@ -19,13 +19,17 @@ TEMPLATE_H = """
#define FUSE_EXPORT __attribute__((visibility("default")))
#endif
namespace electron::fuses {
namespace electron {
namespace fuses {
extern const volatile char kFuseWire[];
{getters}
} // namespace electron::fuses
} // namespace fuses
} // namespace electron
#endif // ELECTRON_FUSES_H_
"""
@@ -33,13 +37,17 @@ extern const volatile char kFuseWire[];
TEMPLATE_CC = """
#include "electron/fuses.h"
namespace electron::fuses {
namespace electron {
namespace fuses {
const volatile char kFuseWire[] = { /* sentinel */ {sentinel}, /* fuse_version */ {fuse_version}, /* fuse_wire_length */ {fuse_wire_length}, /* fuse_wire */ {initial_config}};
{getters}
} // namespace electron:fuses
}
}
"""
with open(os.path.join(dir_path, "fuses.json5"), 'r') as f:

View File

@@ -8,7 +8,9 @@ TEMPLATE = """
#include "node_native_module.h"
#include "node_internals.h"
namespace node::native_module {{
namespace node {{
namespace native_module {{
{definitions}
@@ -16,7 +18,9 @@ void NativeModuleLoader::LoadEmbedderJavaScriptSource() {{
{initializers}
}}
}} // namespace node::native_module
}} // namespace native_module
}} // namespace node
"""
def main():

View File

@@ -4,7 +4,7 @@
# Cocoa .app bundle. The presence of these empty directories is sufficient to
# convince Cocoa that the application supports the named localization, even if
# an InfoPlist.strings file is not provided. Chrome uses these empty locale
# directories for its helper executable bundles, which do not otherwise
# directoires for its helper executable bundles, which do not otherwise
# require any direct Cocoa locale support.
import os

21
build/node.gni Normal file
View File

@@ -0,0 +1,21 @@
template("node_action") {
assert(defined(invoker.script), "Need script path to run")
assert(defined(invoker.args), "Need script argumets")
action(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"sources",
"inputs",
"outputs",
])
if (!defined(inputs)) {
inputs = []
}
inputs += [ invoker.script ]
script = "//electron/build/run-node.py"
args = [ rebase_path(invoker.script) ] + invoker.args
}
}

View File

@@ -1,7 +1,7 @@
template("npm_action") {
assert(defined(invoker.script),
"Need script name to run (must be defined in package.json)")
assert(defined(invoker.args), "Need script arguments")
assert(defined(invoker.args), "Need script argumets")
action("npm_pre_flight_" + target_name) {
inputs = [

View File

@@ -51,7 +51,7 @@ template("compile_ib_files") {
# Template to compile and package Mac XIB files as bundle data.
# Arguments
# sources:
# list of string, sources to compile
# list of string, sources to comiple
# output_path:
# (optional) string, the path to use for the outputs list in the
# bundle_data step. If unspecified, defaults to bundle_resources_dir.

View File

@@ -55,14 +55,6 @@ static_library("chrome") {
"//chrome/browser/process_singleton.h",
"//chrome/browser/process_singleton_internal.cc",
"//chrome/browser/process_singleton_internal.h",
"//chrome/browser/themes/browser_theme_pack.cc",
"//chrome/browser/themes/browser_theme_pack.h",
"//chrome/browser/themes/custom_theme_supplier.cc",
"//chrome/browser/themes/custom_theme_supplier.h",
"//chrome/browser/themes/theme_properties.cc",
"//chrome/browser/themes/theme_properties.h",
"//chrome/browser/ui/color/chrome_color_mixers.cc",
"//chrome/browser/ui/color/chrome_color_mixers.h",
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.cc",
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h",
"//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc",
@@ -77,11 +69,7 @@ static_library("chrome") {
"//chrome/browser/ui/exclusive_access/keyboard_lock_controller.h",
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.cc",
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.h",
"//chrome/browser/ui/frame/window_frame_util.cc",
"//chrome/browser/ui/frame/window_frame_util.h",
"//chrome/browser/ui/native_window_tracker.h",
"//chrome/browser/ui/ui_features.cc",
"//chrome/browser/ui/ui_features.h",
"//chrome/browser/ui/views/eye_dropper/eye_dropper.cc",
"//chrome/browser/ui/views/eye_dropper/eye_dropper.h",
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view.cc",
@@ -104,7 +92,6 @@ static_library("chrome") {
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h",
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm",
"//chrome/browser/media/webrtc/window_icon_util_mac.mm",
"//chrome/browser/platform_util_mac.mm",
"//chrome/browser/process_singleton_mac.mm",
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.h",
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.mm",
@@ -122,8 +109,6 @@ static_library("chrome") {
"//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.cc",
"//chrome/browser/win/titlebar_config.h",
"//chrome/browser/win/titlebar_config.h",
"//chrome/child/v8_crashpad_support_win.cc",
"//chrome/child/v8_crashpad_support_win.h",
@@ -145,7 +130,6 @@ static_library("chrome") {
public_deps = [
"//chrome/browser:dev_ui_browser_resources",
"//chrome/browser/ui/color:mixers",
"//chrome/common",
"//chrome/common:version_header",
"//components/keyed_service/content",
@@ -232,8 +216,6 @@ static_library("chrome") {
"//chrome/browser/printing/printer_query.h",
"//chrome/browser/printing/printing_service.cc",
"//chrome/browser/printing/printing_service.h",
"//components/printing/browser/print_to_pdf/pdf_print_utils.cc",
"//components/printing/browser/print_to_pdf/pdf_print_utils.h",
]
if (enable_oop_printing) {
@@ -403,19 +385,14 @@ source_set("chrome_spellchecker") {
"//chrome/browser/spellchecker/spellcheck_factory.h",
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc",
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h",
"//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.cc",
"//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.h",
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.cc",
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.h",
"//chrome/browser/spellchecker/spellcheck_service.cc",
"//chrome/browser/spellchecker/spellcheck_service.h",
]
if (!is_mac) {
sources += [
"//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.cc",
"//chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.h",
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.cc",
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.h",
]
}
if (has_spellcheck_panel) {
sources += [
"//chrome/browser/spellchecker/spell_check_panel_host_impl.cc",

View File

@@ -69,6 +69,9 @@ an issue:
* [Windows Store](tutorial/windows-store-guide.md)
* [Snapcraft](tutorial/snapcraft.md)
* [Updates](tutorial/updates.md)
* [Deploying an Update Server](tutorial/updates.md#deploying-an-update-server)
* [Implementing Updates in Your App](tutorial/updates.md#implementing-updates-in-your-app)
* [Applying Updates](tutorial/updates.md#applying-updates)
* [Getting Support](tutorial/support.md)
## Detailed Tutorials

View File

@@ -130,11 +130,6 @@ set `NSPrincipalClass` to `AtomApplication`.
You should call `event.preventDefault()` if you want to handle this event.
As with the `open-file` event, be sure to register a listener for the `open-url`
event early in your application startup to detect if the the application being
is being opened to handle a URL. If you register the listener in response to a
`ready` event, you'll miss URLs that trigger the launch of your application.
### Event: 'activate' _macOS_
Returns:
@@ -1386,7 +1381,7 @@ method returns false. If we fail to perform the copy, then this method will
throw an error. The message in the error should be informative and tell
you exactly what went wrong.
By default, if an app of the same name as the one being moved exists in the Applications directory and is _not_ running, the existing app will be trashed and the active app moved into its place. If it _is_ running, the preexisting running app will assume focus and the previously active app will quit itself. This behavior can be changed by providing the optional conflict handler, where the boolean returned by the handler determines whether or not the move conflict is resolved with default behavior. i.e. returning `false` will ensure no further action is taken, returning `true` will result in the default behavior and the method continuing.
By default, if an app of the same name as the one being moved exists in the Applications directory and is _not_ running, the existing app will be trashed and the active app moved into its place. If it _is_ running, the pre-existing running app will assume focus and the previously active app will quit itself. This behavior can be changed by providing the optional conflict handler, where the boolean returned by the handler determines whether or not the move conflict is resolved with default behavior. i.e. returning `false` will ensure no further action is taken, returning `true` will result in the default behavior and the method continuing.
For example:

View File

@@ -246,8 +246,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
* `trafficLightPosition` [Point](structures/point.md) (optional) _macOS_ -
Set a custom position for the traffic light buttons in frameless windows.
* `roundedCorners` boolean (optional) _macOS_ - Whether frameless window
should have rounded corners on macOS. Default is `true`. Setting this property
to `false` will prevent the window from being fullscreenable.
should have rounded corners on macOS. Default is `true`.
* `fullscreenWindowTitle` boolean (optional) _macOS_ _Deprecated_ - Shows
the title in the title bar in full screen mode on macOS for `hiddenInset`
titleBarStyle. Default is `false`.
@@ -426,17 +425,13 @@ Possible values are:
* On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`,
`notification`.
* On macOS, possible types are `desktop`, `textured`, `panel`.
* On macOS, possible types are `desktop`, `textured`.
* The `textured` type adds metal gradient appearance
(`NSWindowStyleMaskTexturedBackground`).
* The `desktop` type places the window at the desktop background window level
(`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive
focus, keyboard or mouse events, but you can use `globalShortcut` to receive
input sparingly.
* The `panel` type enables the window to float on top of full-screened apps
by adding the `NSWindowStyleMaskNonactivatingPanel` style mask,normally
reserved for NSPanel, at runtime. Also, the window will appear on all
spaces (desktops).
* On Windows, possible type is `toolbar`.
### Instance Events
@@ -1324,7 +1319,7 @@ win.setSheetOffset(toolbarRect.height)
Starts or stops flashing the window to attract user's attention.
#### `win.setSkipTaskbar(skip)` _macOS_ _Windows_
#### `win.setSkipTaskbar(skip)`
* `skip` boolean

View File

@@ -139,7 +139,8 @@ green and non-draggable regions will be colored red to aid debugging.
### `ELECTRON_DEBUG_NOTIFICATIONS`
Adds extra logs to [`Notification`](./notification.md) lifecycles on macOS to aid in debugging. Extra logging will be displayed when new Notifications are created or activated. They will also be displayed when common actions are taken: a notification is shown, dismissed, its button is clicked, or it is replied to.
Adds extra logs to [`Notification`](./notification.md) lifecycles on macOS to aid in debugging. Extra logging will be displayed when new Notifications are created or activated. They will also be displayed when common a
tions are taken: a notification is shown, dismissed, its button is clicked, or it is replied to.
Sample output:

View File

@@ -149,7 +149,7 @@ console.log(image)
* `options` Object
* `width` Integer
* `height` Integer
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns `NativeImage`
@@ -162,7 +162,7 @@ pixel data returned by `toBitmap()`. The specific format is platform-dependent.
* `options` Object (optional)
* `width` Integer (optional) - Required for bitmap buffers.
* `height` Integer (optional) - Required for bitmap buffers.
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns `NativeImage`
@@ -225,7 +225,7 @@ The following methods are available on instances of the `NativeImage` class:
#### `image.toPNG([options])`
* `options` Object (optional)
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns `Buffer` - A [Buffer][buffer] that contains the image's `PNG` encoded data.
@@ -238,7 +238,7 @@ Returns `Buffer` - A [Buffer][buffer] that contains the image's `JPEG` encoded d
#### `image.toBitmap([options])`
* `options` Object (optional)
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns `Buffer` - A [Buffer][buffer] that contains a copy of the image's raw bitmap pixel
data.
@@ -246,14 +246,14 @@ data.
#### `image.toDataURL([options])`
* `options` Object (optional)
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns `string` - The data URL of the image.
#### `image.getBitmap([options])`
* `options` Object (optional)
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns `Buffer` - A [Buffer][buffer] that contains the image's raw bitmap pixel data.
@@ -276,7 +276,7 @@ Returns `boolean` - Whether the image is empty.
#### `image.getSize([scaleFactor])`
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns [`Size`](structures/size.md).
@@ -317,20 +317,20 @@ will be preserved in the resized image.
#### `image.getAspectRatio([scaleFactor])`
* `scaleFactor` Number (optional) - Defaults to 1.0.
* `scaleFactor` Double (optional) - Defaults to 1.0.
Returns `Number` - The image's aspect ratio.
Returns `Float` - The image's aspect ratio.
If `scaleFactor` is passed, this will return the aspect ratio corresponding to the image representation most closely matching the passed value.
#### `image.getScaleFactors()`
Returns `Number[]` - An array of all scale factors corresponding to representations for a given nativeImage.
Returns `Float[]` - An array of all scale factors corresponding to representations for a given nativeImage.
#### `image.addRepresentation(options)`
* `options` Object
* `scaleFactor` Number (optional) - The scale factor to add the image representation for.
* `scaleFactor` Double - The scale factor to add the image representation for.
* `width` Integer (optional) - Defaults to 0. Required if a bitmap buffer
is specified as `buffer`.
* `height` Integer (optional) - Defaults to 0. Required if a bitmap buffer

View File

@@ -1,48 +0,0 @@
# pushNotifications
Process: [Main](../glossary.md#main-process)
> Register for and receive notifications from remote push notification services
For example, when registering for push notifications via Apple push notification services (APNS):
```javascript
const { pushNotifications, Notification } = require('electron')
pushNotifications.registerForAPNSNotifications().then((token) => {
// forward token to your remote notification server
})
pushNotifications.on('received-apns-notification', (event, userInfo) => {
// generate a new Notification object with the relevant userInfo fields
})
```
## Events
The `pushNotification` module emits the following events:
#### Event: 'received-apns-notification' _macOS_
Returns:
* `userInfo` Record<String, any>
Emitted when the app receives a remote notification while running.
See: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428430-application?language=objc
## Methods
The `pushNotification` module has the following methods:
### `pushNotifications.registerForAPNSNotifications()` _macOS_
Returns `Promise<string>`
Registers the app with Apple Push Notification service (APNS) to receive [Badge, Sound, and Alert](https://developer.apple.com/documentation/appkit/sremotenotificationtype?language=objc) notifications. If registration is successful, the promise will be resolved with the APNS device token. Otherwise, the promise will be rejected with an error message.
See: https://developer.apple.com/documentation/appkit/nsapplication/1428476-registerforremotenotificationtyp?language=objc
### `pushNotifications.unregisterForAPNSNotifications()` _macOS_
Unregisters the app from notifications received from APNS.
See: https://developer.apple.com/documentation/appkit/nsapplication/1428747-unregisterforremotenotifications?language=objc

View File

@@ -281,7 +281,7 @@ Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `origin` string (optional) - The origin that the device has been revoked from.
* `frame` [WebFrameMain](web-frame-main.md)
Emitted after `HIDDevice.forget()` has been called. This event can be used
to help maintain persistent storage of permissions when
@@ -635,7 +635,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
* `notifications` - Request notification creation and the ability to display them in the user's system tray.
* `midi` - Request MIDI access in the `webmidi` API.
* `midiSysex` - Request the use of system exclusive messages in the `webmidi` API.
* `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more. These requests always appear to originate from the main frame.
* `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more.
* `fullscreen` - Request for the app to enter fullscreen mode.
* `openExternal` - Request to open links in external applications.
* `unknown` - An unrecognized permission request
@@ -705,6 +705,7 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
* `deviceType` string - The type of device that permission is being requested on, can be `hid` or `serial`.
* `origin` string - The origin URL of the device permission check.
* `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md)- the device that permission is being requested for.
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
Sets the handler which can be used to respond to device permission checks for the `session`.
Returning `true` will allow the device to be permitted and `false` will reject it.
@@ -712,8 +713,8 @@ To clear the handler, call `setDevicePermissionHandler(null)`.
This handler can be used to provide default permissioning to devices without first calling for permission
to devices (eg via `navigator.hid.requestDevice`). If this handler is not defined, the default device
permissions as granted through device selection (eg via `navigator.hid.requestDevice`) will be used.
Additionally, the default behavior of Electron is to store granted device permision in memory.
If longer term storage is needed, a developer can store granted device
Additionally, the default behavior of Electron is to store granted device permision through the lifetime
of the corresponding WebContents. If longer term storage is needed, a developer can store granted device
permissions (eg when handling the `select-hid-device` event) and then read from that storage with `setDevicePermissionHandler`.
```javascript
@@ -1049,7 +1050,7 @@ is emitted.
#### `ses.getStoragePath()`
Returns `string | null` - The absolute file system path where data for this
A `string | null` indicating the absolute file system path where data for this
session is persisted on disk. For in memory sessions this returns `null`.
### Instance Properties

View File

@@ -25,20 +25,15 @@ app.whenReady().then(() => {
})
```
__Platform Considerations__
If you want to keep exact same behaviors on all platforms, you should not
rely on the `click` event; instead, always attach a context menu to the tray icon.
__Linux__
__Platform limitations:__
* On Linux the app indicator will be used if it is supported, otherwise
`GtkStatusIcon` will be used instead.
* On Linux distributions that only have app indicator support, you have to
install `libappindicator1` to make the tray icon work.
* The app indicator will be used if it is supported, otherwise
`GtkStatusIcon` will be used instead.
* App indicator will only be shown when it has a context menu.
* The `click` event is ignored when using the app indicator.
* In order for changes made to individual `MenuItem`s to take effect,
* When app indicator is used on Linux, the `click` event is ignored.
* On Linux in order for changes made to individual `MenuItem`s to take effect,
you have to call `setContextMenu` again. For example:
```javascript
@@ -60,16 +55,10 @@ app.whenReady().then(() => {
})
```
__MacOS__
* On Windows it is recommended to use `ICO` icons to get best visual effects.
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image).
* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi.
* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image.
* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons.
__Windows__
* It is recommended to use `ICO` icons to get best visual effects.
If you want to keep exact same behaviors on all platforms, you should not
rely on the `click` event and always attach a context menu to the tray icon.
### `new Tray(image, [guid])`

View File

@@ -862,8 +862,6 @@ Returns:
Emitted when the renderer process sends an asynchronous message via `ipcRenderer.send()`.
See also [`webContents.ipc`](#contentsipc-readonly), which provides an [`IpcMain`](ipc-main.md)-like interface for responding to IPC messages specifically from this WebContents.
#### Event: 'ipc-message-sync'
Returns:
@@ -874,8 +872,6 @@ Returns:
Emitted when the renderer process sends a synchronous message via `ipcRenderer.sendSync()`.
See also [`webContents.ipc`](#contentsipc-readonly), which provides an [`IpcMain`](ipc-main.md)-like interface for responding to IPC messages specifically from this WebContents.
#### Event: 'preferred-size-changed'
Returns:
@@ -1432,7 +1428,7 @@ Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/
* `header` string (optional) - string to be printed as page header.
* `footer` string (optional) - string to be printed as page footer.
* `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A3`,
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`.
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`.
* `callback` Function (optional)
* `success` boolean - Indicates success of the print call.
* `failureReason` string - Error description called back if the print fails.
@@ -1463,28 +1459,43 @@ win.webContents.print(options, (success, errorType) => {
#### `contents.printToPDF(options)`
* `options` Object
* `landscape` boolean (optional) - Paper orientation.`true` for landscape, `false` for portrait. Defaults to false.
* `displayHeaderFooter` boolean (optional) - Whether to display header and footer. Defaults to false.
* `printBackground` boolean (optional) - Whether to print background graphics. Defaults to false.
* `scale` number(optional) - Scale of the webpage rendering. Defaults to 1.
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`,
`A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing `height` and `width` in inches. Defaults to `Letter`.
* `margins` Object (optional)
* `top` number (optional) - Top margin in inches. Defaults to 1cm (~0.4 inches).
* `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches).
* `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches).
* `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches).
* `pageRanges` string (optional) - Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages.
* `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title.
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
* `headerFooter` Record<string, string> (optional) - the header and footer for the PDF.
* `title` string - The title for the PDF header.
* `url` string - the url for the PDF footer.
* `landscape` boolean (optional) - `true` for landscape, `false` for portrait.
* `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for
default margin, 1 for no margin, and 2 for minimum margin.
* `scaleFactor` number (optional) - The scale factor of the web page. Can range from 0 to 100.
* `pageRanges` Record<string, number> (optional) - The page range to print.
* `from` number - Index of the first page to print (0-based).
* `to` number - Index of the last page to print (inclusive) (0-based).
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A3`,
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width` in microns.
* `printBackground` boolean (optional) - Whether to print CSS backgrounds.
* `printSelectionOnly` boolean (optional) - Whether to print selection only.
Returns `Promise<Buffer>` - Resolves with the generated PDF data.
Prints the window's web page as PDF.
Prints window's web page as PDF with Chromium's preview printing custom
settings.
The `landscape` will be ignored if `@page` CSS at-rule is used in the web page.
By default, an empty `options` will be regarded as:
```javascript
{
marginsType: 0,
printBackground: false,
printSelectionOnly: false,
landscape: false,
pageSize: 'A4',
scaleFactor: 100
}
```
Use `page-break-before: always;` CSS style to force to print to a new page.
An example of `webContents.printToPDF`:
```javascript
@@ -1493,7 +1504,7 @@ const fs = require('fs')
const path = require('path')
const os = require('os')
const win = new BrowserWindow()
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL('http://github.com')
win.webContents.on('did-finish-load', () => {
@@ -1510,8 +1521,6 @@ win.webContents.on('did-finish-load', () => {
})
```
See [Page.printToPdf](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF) for more information.
#### `contents.addWorkSpace(path)`
* `path` string
@@ -1989,35 +1998,6 @@ This corresponds to the [animationPolicy][] accessibility feature in Chromium.
### Instance Properties
#### `contents.ipc` _Readonly_
An [`IpcMain`](ipc-main.md) scoped to just IPC messages sent from this
WebContents.
IPC messages sent with `ipcRenderer.send`, `ipcRenderer.sendSync` or
`ipcRenderer.postMessage` will be delivered in the following order:
1. `contents.on('ipc-message')`
2. `contents.mainFrame.on(channel)`
3. `contents.ipc.on(channel)`
4. `ipcMain.on(channel)`
Handlers registered with `invoke` will be checked in the following order. The
first one that is defined will be called, the rest will be ignored.
1. `contents.mainFrame.handle(channel)`
2. `contents.handle(channel)`
3. `ipcMain.handle(channel)`
A handler or event listener registered on the WebContents will receive IPC
messages sent from any frame, including child frames. In most cases, only the
main frame can send IPC messages. However, if the `nodeIntegrationInSubFrames`
option is enabled, it is possible for child frames to send IPC messages also.
In that case, handlers should check the `senderFrame` property of the IPC event
to ensure that the message is coming from the expected frame. Alternatively,
register handlers on the appropriate frame directly using the
[`WebFrameMain.ipc`](web-frame-main.md#frameipc-readonly) interface.
#### `contents.audioMuted`
A `boolean` property that determines whether this page is muted.

View File

@@ -140,31 +140,6 @@ ipcRenderer.on('port', (e, msg) => {
### Instance Properties
#### `frame.ipc` _Readonly_
An [`IpcMain`](ipc-main.md) instance scoped to the frame.
IPC messages sent with `ipcRenderer.send`, `ipcRenderer.sendSync` or
`ipcRenderer.postMessage` will be delivered in the following order:
1. `contents.on('ipc-message')`
2. `contents.mainFrame.on(channel)`
3. `contents.ipc.on(channel)`
4. `ipcMain.on(channel)`
Handlers registered with `invoke` will be checked in the following order. The
first one that is defined will be called, the rest will be ignored.
1. `contents.mainFrame.handle(channel)`
2. `contents.handle(channel)`
3. `ipcMain.handle(channel)`
In most cases, only the main frame of a WebContents can send or receive IPC
messages. However, if the `nodeIntegrationInSubFrames` option is enabled, it is
possible for child frames to send and receive IPC messages also. The
[`WebContents.ipc`](web-contents.md#contentsipc-readonly) interface may be more
convenient when `nodeIntegrationInSubFrames` is not enabled.
#### `frame.url` _Readonly_
A `string` representing the current URL of the frame.

View File

@@ -565,21 +565,21 @@ Prints `webview`'s web page. Same as `webContents.print([options])`.
### `<webview>.printToPDF(options)`
* `options` Object
* `landscape` boolean (optional) - Paper orientation.`true` for landscape, `false` for portrait. Defaults to false.
* `displayHeaderFooter` boolean (optional) - Whether to display header and footer. Defaults to false.
* `printBackground` boolean (optional) - Whether to print background graphics. Defaults to false.
* `scale` number(optional) - Scale of the webpage rendering. Defaults to 1.
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`,
`A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing `height` and `width` in inches. Defaults to `Letter`.
* `margins` Object (optional)
* `top` number (optional) - Top margin in inches. Defaults to 1cm (~0.4 inches).
* `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches).
* `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches).
* `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches).
* `pageRanges` string (optional) - Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages.
* `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title.
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
* `headerFooter` Record<string, string> (optional) - the header and footer for the PDF.
* `title` string - The title for the PDF header.
* `url` string - the url for the PDF footer.
* `landscape` boolean (optional) - `true` for landscape, `false` for portrait.
* `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for
default margin, 1 for no margin, and 2 for minimum margin.
and `width` in microns.
* `scaleFactor` number (optional) - The scale factor of the web page. Can range from 0 to 100.
* `pageRanges` Record<string, number> (optional) - The page range to print. On macOS, only the first range is honored.
* `from` number - Index of the first page to print (0-based).
* `to` number - Index of the last page to print (inclusive) (0-based).
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A3`,
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`
* `printBackground` boolean (optional) - Whether to print CSS backgrounds.
* `printSelectionOnly` boolean (optional) - Whether to print selection only.
Returns `Promise<Uint8Array>` - Resolves with the generated PDF data.

View File

@@ -14,68 +14,6 @@ This document uses the following convention to categorize breaking changes:
## Planned Breaking API Changes (20.0)
### Behavior Changed: V8 Memory Cage enabled
The V8 memory cage has been enabled, which has implications for native modules
which wrap non-V8 memory with `ArrayBuffer` or `Buffer`. See the [blog post
about the V8 memory cage](https://www.electronjs.org/blog/v8-memory-cage) for
more details.
### API Changed: `webContents.printToPDF()`
`webContents.printToPDF()` has been modified to conform to [`Page.printToPDF`](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF) in the Chrome DevTools Protocol. This has been changes in order to
address changes upstream that made our previous implementation untenable and rife with bugs.
**Arguments Changed**
* `pageRanges`
**Arguments Removed**
* `printSelectionOnly`
* `marginsType`
* `headerFooter`
* `scaleFactor`
**Arguments Added**
* `headerTemplate`
* `footerTemplate`
* `displayHeaderFooter`
* `margins`
* `scale`
* `preferCSSPageSize`
```js
// Main process
const { webContents } = require('electron')
webContents.printToPDF({
landscape: true,
displayHeaderFooter: true,
printBackground: true,
scale: 2,
pageSize: 'Ledger',
margins: {
top: 2,
bottom: 2,
left: 2,
right: 2
},
pageRanges: '1-5, 8, 11-13',
headerTemplate: '<h1>Title</h1>',
footerTemplate: '<div><span class="pageNumber"></span></div>',
preferCSSPageSize: true
}).then(data => {
fs.writeFile(pdfPath, data, (error) => {
if (error) throw error
console.log(`Wrote PDF successfully to ${pdfPath}`)
})
}).catch(error => {
console.log(`Failed to write PDF to ${pdfPath}: `, error)
})
```
### Default Changed: renderers without `nodeIntegration: true` are sandboxed by default
Previously, renderers that specified a preload script defaulted to being
@@ -96,19 +34,9 @@ window manager. There is not a direct equivalent for Wayland, and the known
workarounds have unacceptable tradeoffs (e.g. Window.is_skip_taskbar in GNOME
requires unsafe mode), so Electron is unable to support this feature on Linux.
### API Changed: `session.setDevicePermissionHandler(handler)`
The handler invoked when `session.setDevicePermissionHandler(handler)` is used
has a change to its arguments. This handler no longer is passed a frame
`[WebFrameMain](api/web-frame-main.md)`, but instead is passed the `origin`, which
is the origin that is checking for device permission.
## Planned Breaking API Changes (19.0)
### Removed: IA32 Linux binaries
This is a result of Chromium 102.0.4999.0 dropping support for IA32 Linux.
This concludes the [removal of support for IA32 Linux](#removed-ia32-linux-support).
None
## Planned Breaking API Changes (18.0)
@@ -1275,10 +1203,6 @@ not present, then the native module will fail to load on Windows, with an error
message like `Cannot find module`. See the [native module
guide](/docs/tutorial/using-native-node-modules.md) for more.
### Removed: IA32 Linux support
Electron 18 will no longer run on 32-bit Linux systems. See [discontinuing support for 32-bit Linux](https://www.electronjs.org/blog/linux-32bit-support) for more information.
## Breaking API Changes (3.0)
The following list includes the breaking API changes in Electron 3.0.

View File

@@ -64,7 +64,7 @@ If you want to add a new API module to Electron, you'll want to look in [creatin
Electron has a fully-fledged governance system that oversees activity in Electron and whose working groups are responsible for areas like APIs, releases, and upgrades to Electron's dependencies including Chromium and Node.js. Depending on how frequently and to what end you want to contribute, you may want to consider joining a working group.
Details about each group and their responsibilities can be found in the [governance repo](https://github.com/electron/governance).
Details about each group and their reponsibilities can be found in the [governance repo](https://github.com/electron/governance).
## Patches in Electron

View File

@@ -47,10 +47,10 @@ $ sudo yum install clang dbus-devel gtk3-devel libnotify-devel \
On Fedora, install the following libraries:
```sh
$ sudo dnf install clang dbus-devel gperf gtk3-devel \
libnotify-devel libgnome-keyring-devel libcap-devel \
$ sudo dnf install clang dbus-devel gtk3-devel libnotify-devel \
libgnome-keyring-devel xorg-x11-server-utils libcap-devel \
cups-devel libXtst-devel alsa-lib-devel libXrandr-devel \
nss-devel python-dbusmock
nss-devel python-dbusmock openjdk-8-jre
```
On Arch Linux / Manjaro, install the following libraries:

View File

@@ -9,7 +9,7 @@ Some of the more common approaches are outlined below.
Chromium contains logging macros which can aid debugging by printing information to console in C++ and Objective-C++.
You might use this to print out variable values, function names, and line numbers, amongst other things.
You might use this to print out variable values, function names, and line numbers, amonst other things.
Some examples:
@@ -25,7 +25,7 @@ See [logging.h](https://chromium.googlesource.com/chromium/src/base/+/refs/heads
## Printing Stacktraces
Chromium contains a helper to print stack traces to console without interrupting the program.
Chromium contains a helper to print stack traces to console without interrrupting the program.
```cpp
#include "base/debug/stack_trace.h"

View File

@@ -1,4 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron')
const path = require('path')
contextBridge.exposeInMainWorld('electron', {
startDrag: (fileName) => {

View File

@@ -1,21 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<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>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
</body>
<script src="./renderer.js"></script>
</html>

View File

@@ -1,26 +0,0 @@
const { app, BrowserWindow } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
});
win.loadFile('index.html');
};
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});

View File

@@ -1,21 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<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>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
</body>
<script src="./renderer.js"></script>
</html>

View File

@@ -1,30 +0,0 @@
const { app, BrowserWindow } = require('electron');
const path = require('path');
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
});
win.loadFile('index.html');
};
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});

View File

@@ -1,7 +0,0 @@
const { contextBridge } = require('electron');
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
});

View File

@@ -1,2 +0,0 @@
const information = document.getElementById('info');
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

View File

@@ -1,26 +1,26 @@
---
title: 'Application Packaging'
description: 'To distribute your app with Electron, you need to package and rebrand it. To do this, you can either use specialized tooling or manual approaches.'
slug: application-distribution
hide_title: false
---
# Application Distribution
To distribute your app with Electron, you need to package and rebrand it. To do this, you
can either use specialized tooling or manual approaches.
## Overview
To distribute your app with Electron, you need to package and rebrand it.
To do this, you can either use specialized tooling or manual approaches.
## With tooling
There are a couple tools out there that exist to package and distribute your Electron app.
We recommend using [Electron Forge](https://www.electronforge.io). You can check out
its documentation directly, or refer to the [Packaging and Distribution](./tutorial-5-packaging.md)
part of the Electron tutorial.
You can use the following tools to distribute your application:
## Manual packaging
* [electron-forge](https://github.com/electron-userland/electron-forge)
* [electron-builder](https://github.com/electron-userland/electron-builder)
* [electron-packager](https://github.com/electron/electron-packager)
If you prefer the manual approach, there are 2 ways to distribute your application:
These tools will take care of all the steps you need to take to end up with a
distributable Electron application, such as bundling your application,
rebranding the executable, and setting the right icons.
- With prebuilt binaries
- With an app source code archive
You can check the example of how to package your app with `electron-forge` in
the [Quick Start guide](quick-start.md#package-and-distribute-your-application).
## Manual distribution
### With prebuilt binaries
@@ -29,19 +29,21 @@ binaries](https://github.com/electron/electron/releases). Next, the folder
containing your app should be named `app` and placed in Electron's resources
directory as shown in the following examples.
:::note
The location of Electron's prebuilt binaries is indicated
> *NOTE:* the location of Electron's prebuilt binaries is indicated
with `electron/` in the examples below.
:::
```plain title='macOS'
*On macOS:*
```plaintext
electron/Electron.app/Contents/Resources/app/
├── package.json
├── main.js
└── index.html
```
```plain title='Windows and Linux'
*On Windows and Linux:*
```plaintext
electron/resources/app
├── package.json
├── main.js
@@ -52,7 +54,7 @@ Then execute `Electron.app` on macOS, `electron` on Linux, or `electron.exe`
on Windows, and Electron will start as your app. The `electron` directory
will then be your distribution to deliver to users.
### With an app source code archive (asar)
### With an app source code archive
Instead of shipping your app by copying all of its source files, you can
package your app into an [asar] archive to improve the performance of reading
@@ -63,12 +65,16 @@ To use an `asar` archive to replace the `app` folder, you need to rename the
archive to `app.asar`, and put it under Electron's resources directory like
below, and Electron will then try to read the archive and start from it.
```plain title='macOS'
*On macOS:*
```plaintext
electron/Electron.app/Contents/Resources/
└── app.asar
```
```plain title='Windows'
*On Windows and Linux:*
```plaintext
electron/resources/
└── app.asar
```
@@ -81,44 +87,47 @@ You can find more details on how to use `asar` in the
After bundling your app into Electron, you will want to rebrand Electron
before distributing it to users.
- **Windows:** You can rename `electron.exe` to any name you like, and edit
its icon and other information with tools like [rcedit](https://github.com/electron/rcedit).
- **Linux:** You can rename the `electron` executable to any name you like.
- **macOS:** You can rename `Electron.app` to any name you want, and you also have to rename
the `CFBundleDisplayName`, `CFBundleIdentifier` and `CFBundleName` fields in the
following files:
#### macOS
- `Electron.app/Contents/Info.plist`
- `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist`
You can rename `Electron.app` to any name you want, and you also have to rename
the `CFBundleDisplayName`, `CFBundleIdentifier` and `CFBundleName` fields in the
following files:
You can also rename the helper app to avoid showing `Electron Helper` in the
Activity Monitor, but make sure you have renamed the helper app's executable
file's name.
* `Electron.app/Contents/Info.plist`
* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist`
The structure of a renamed app would be like:
You can also rename the helper app to avoid showing `Electron Helper` in the
Activity Monitor, but make sure you have renamed the helper app's executable
file's name.
```plain
The structure of a renamed app would be like:
```plaintext
MyApp.app/Contents
├── Info.plist
├── MacOS/
└── MyApp
│   └── MyApp
└── Frameworks/
└── MyApp Helper.app
├── Info.plist
└── MacOS/
└── MyApp Helper
   └── MyApp Helper
```
:::note
#### Windows
it is also possible to rebrand Electron by changing the product name and
You can rename `electron.exe` to any name you like, and edit its icon and other
information with tools like [rcedit](https://github.com/electron/rcedit).
#### Linux
You can rename the `electron` executable to any name you like.
### Rebranding by rebuilding Electron from source
It is also possible to rebrand Electron by changing the product name and
building it from source. To do this you need to set the build argument
corresponding to the product name (`electron_product_name = "YourProductName"`)
in the `args.gn` file and rebuild.
Keep in mind this is not recommended as setting up the environment to compile
from source is not trivial and takes significant time.
:::
[asar]: https://github.com/electron/asar

View File

@@ -1,20 +1,14 @@
---
title: 'Code Signing'
description: 'Code signing is a security technology that you use to certify that an app was created by you.'
slug: code-signing
hide_title: false
---
# Code Signing
Code signing is a security technology that you use to certify that an app was
created by you. You should sign your application so it does not trigger any
operating system security checks.
created by you.
On macOS, the system can detect any change to the app, whether the change is
On macOS the system can detect any change to the app, whether the change is
introduced accidentally or by malicious code.
On Windows, the system assigns a trust level to your code signing certificate
which if you don't have, or if your trust level is low, will cause security
dialogs to appear when users start using your application. Trust level builds
dialogs to appear when users start using your application. Trust level builds
over time so it's better to start code signing as early as possible.
While it is possible to distribute unsigned apps, it is not recommended. Both
@@ -22,19 +16,20 @@ Windows and macOS will, by default, prevent either the download or the execution
of unsigned applications. Starting with macOS Catalina (version 10.15), users
have to go through multiple manual steps to open unsigned applications.
![macOS Catalina Gatekeeper warning: The app cannot be opened because the developer cannot be verified](../images/gatekeeper.png)
![macOS Catalina Gatekeeper warning: The app cannot be opened because the
developer cannot be verified](../images/gatekeeper.png)
As you can see, users get two options: Move the app straight to the trash or
cancel running it. You don't want your users to see that dialog.
If you are building an Electron app that you intend to package and distribute,
it should be code signed.
it should be code-signed.
## Signing & notarizing macOS builds
# Signing & notarizing macOS builds
Properly preparing macOS applications for release requires two steps. First, the
app needs to be code signed. Then, the app needs to be uploaded to Apple for a
process called **notarization**, where automated systems will further verify that
Properly preparing macOS applications for release requires two steps: First, the
app needs to be code-signed. Then, the app needs to be uploaded to Apple for a
process called "notarization", where automated systems will further verify that
your app isn't doing anything to endanger its users.
To start the process, ensure that you fulfill the requirements for signing and
@@ -47,18 +42,18 @@ notarizing your app:
Electron's ecosystem favors configuration and freedom, so there are multiple
ways to get your application signed and notarized.
### Using Electron Forge
## `electron-forge`
If you're using Electron's favorite build tool, getting your application signed
and notarized requires a few additions to your configuration. [Forge](https://electronforge.io) is a
collection of the official Electron tools, using [`electron-packager`],
[`electron-osx-sign`], and [`electron-notarize`] under the hood.
Let's take a look at an example `package.json` configuration with all required fields. Not all of them are
required: the tools will be clever enough to automatically find a suitable `identity`, for instance,
but we recommend that you are explicit.
Let's take a look at an example configuration with all required fields. Not all
of them are required: the tools will be clever enough to automatically find a
suitable `identity`, for instance, but we recommend that you are explicit.
```json title="package.json" {7}
```json
{
"name": "my-app",
"version": "0.0.1",
@@ -74,7 +69,7 @@ but we recommend that you are explicit.
},
"osxNotarize": {
"appleId": "felix@felix.fun",
"appleIdPassword": "my-apple-id-password"
"appleIdPassword": "my-apple-id-password",
}
}
}
@@ -82,11 +77,11 @@ but we recommend that you are explicit.
}
```
The `entitlements.plist` file referenced here needs the following macOS-specific entitlements
The `plist` file referenced here needs the following macOS-specific entitlements
to assure the Apple security mechanisms that your app is doing these things
without meaning any harm:
```xml title="entitlements.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">
@@ -109,7 +104,7 @@ file](https://github.com/electron/fiddle/blob/master/forge.config.js).
If you plan to access the microphone or camera within your app using Electron's APIs, you'll also
need to add the following entitlements:
```xml title="entitlements.plist"
```xml
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
@@ -118,26 +113,28 @@ need to add the following entitlements:
If these are not present in your app's entitlements when you invoke, for example:
```js title="main.js"
```js
const { systemPreferences } = require('electron')
const microphone = systemPreferences.askForMediaAccess('microphone')
```
Your app may crash. See the Resource Access section in [Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime) for more information and entitlements you may need.
### Using Electron Builder
## `electron-builder`
Electron Builder comes with a custom solution for signing your application. You
can find [its documentation here](https://www.electron.build/code-signing).
### Using Electron Packager
## `electron-packager`
If you're not using an integrated build pipeline like Forge or Builder, you
are likely using [`electron-packager`], which includes [`electron-osx-sign`] and
[`electron-notarize`].
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/main/interfaces/electronpackager.options.html).
and notarizes your
application](https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html).
```js
const packager = require('electron-packager')
@@ -158,11 +155,11 @@ packager({
})
```
The `entitlements.plist` file referenced here needs the following macOS-specific entitlements
The `plist` file referenced here needs the following macOS-specific entitlements
to assure the Apple security mechanisms that your app is doing these things
without meaning any harm:
```xml title="entitlements.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">
@@ -178,11 +175,11 @@ without meaning any harm:
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.
### Signing Mac App Store applications
## Mac App Store
See the [Mac App Store Guide].
## Signing Windows builds
# Signing Windows builds
Before signing Windows builds, you must do the following:
@@ -193,140 +190,31 @@ Before signing Windows builds, you must do the following:
You can get a code signing certificate from a lot of resellers. Prices vary, so
it may be worth your time to shop around. Popular resellers include:
- [digicert](https://www.digicert.com/code-signing/microsoft-authenticode.htm)
- [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing)
- Amongst others, please shop around to find one that suits your needs! 😄
* [digicert](https://www.digicert.com/code-signing/microsoft-authenticode.htm)
* [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing)
* Amongst others, please shop around to find one that suits your needs, Google
is your friend 😄
:::caution Keep your certificate password private
Your certificate password should be a **secret**. Do not share it publicly or
commit it to your source code.
:::
There are a number of tools for signing your packaged app:
### Using Electron Forge
* [`electron-winstaller`] will generate an installer for windows and sign it for
you
* [`electron-forge`] can sign installers it generates through the
Squirrel.Windows or MSI targets.
* [`electron-builder`] can sign some of its windows targets
Once you have a code signing certificate file (`.pfx`), you can sign
[Squirrel.Windows][maker-squirrel] and [MSI][maker-msi] installers in Electron Forge
with the `certificateFile` and `certificatePassword` fields in their respective
configuration objects.
For example, if you keep your Forge config in your `package.json` file and are
creating a Squirrel.Windows installer:
```json {9-15} title='package.json'
{
"name": "my-app",
"version": "0.0.1",
//...
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "@electron-forge/maker-squirrel",
"config": {
"certificateFile": "./cert.pfx",
"certificatePassword": "this-is-a-secret"
}
}
]
}
}
//...
}
```
### Using electron-winstaller (Squirrel.Windows)
[`electron-winstaller`] is a package that can generate Squirrel.Windows installers for your
Electron app. This is the tool used under the hood by Electron Forge's
[Squirrel.Windows Maker][maker-squirrel]. If you're not using Electron Forge and want to use
`electron-winstaller` directly, use the `certificateFile` and `certificatePassword` configuration
options when creating your installer.
```js {10-11}
const electronInstaller = require('electron-winstaller')
// NB: Use this syntax within an async function, Node does not have support for
// top-level await as of Node 12.
try {
await electronInstaller.createWindowsInstaller({
appDirectory: '/tmp/build/my-app-64',
outputDirectory: '/tmp/build/installer64',
authors: 'My App Inc.',
exe: 'myapp.exe',
certificateFile: './cert.pfx',
certificatePassword: 'this-is-a-secret',
})
console.log('It worked!')
} catch (e) {
console.log(`No dice: ${e.message}`)
}
```
For full configuration options, check out the [`electron-winstaller`] repository!
### Using electron-wix-msi (WiX MSI)
[`electron-wix-msi`] is a package that can generate MSI installers for your
Electron app. This is the tool used under the hood by Electron Forge's [MSI Maker][maker-msi].
If you're not using Electron Forge and want to use `electron-wix-msi` directly, use the
`certificateFile` and `certificatePassword` configuration options
or pass in parameters directly to [SignTool.exe] with the `signWithParams` option.
```js {12-13}
import { MSICreator } from 'electron-wix-msi'
// Step 1: Instantiate the MSICreator
const msiCreator = new MSICreator({
appDirectory: '/path/to/built/app',
description: 'My amazing Kitten simulator',
exe: 'kittens',
name: 'Kittens',
manufacturer: 'Kitten Technologies',
version: '1.1.2',
outputDirectory: '/path/to/output/folder',
certificateFile: './cert.pfx',
certificatePassword: 'this-is-a-secret',
})
// Step 2: Create a .wxs template file
const supportBinaries = await msiCreator.create()
// 🆕 Step 2a: optionally sign support binaries if you
// sign you binaries as part of of your packaging script
supportBinaries.forEach(async (binary) => {
// Binaries are the new stub executable and optionally
// the Squirrel auto updater.
await signFile(binary)
})
// Step 3: Compile the template to a .msi file
await msiCreator.compile()
```
For full configuration options, check out the [`electron-wix-msi`] repository!
### Using Electron Builder
Electron Builder comes with a custom solution for signing your application. You
can find [its documentation here](https://www.electron.build/code-signing).
### Signing Windows Store applications
## Windows Store
See the [Windows Store Guide].
[apple developer program]: https://developer.apple.com/programs/
[Apple Developer Program]: https://developer.apple.com/programs/
[`electron-builder`]: https://github.com/electron-userland/electron-builder
[`electron-forge`]: https://github.com/electron-userland/electron-forge
[`electron-osx-sign`]: https://github.com/electron-userland/electron-osx-sign
[`electron-packager`]: https://github.com/electron/electron-packager
[`electron-notarize`]: https://github.com/electron/electron-notarize
[`electron-winstaller`]: https://github.com/electron/windows-installer
[`electron-wix-msi`]: https://github.com/felixrieseberg/electron-wix-msi
[xcode]: https://developer.apple.com/xcode
[Xcode]: https://developer.apple.com/xcode
[signing certificates]: https://github.com/electron/electron-osx-sign/wiki/1.-Getting-Started#certificates
[mac app store guide]: ./mac-app-store-submission-guide.md
[windows store guide]: ./windows-store-guide.md
[maker-squirrel]: https://www.electronforge.io/config/makers/squirrel.windows
[maker-msi]: https://www.electronforge.io/config/makers/wix-msi
[signtool.exe]: https://docs.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
[Mac App Store Guide]: mac-app-store-submission-guide.md
[Windows Store Guide]: windows-store-guide.md

View File

@@ -43,7 +43,7 @@ the WebHID API:
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
can be used to provide default permissioning to devices without first calling
for permission to devices via `navigator.hid.requestDevice`. Additionally,
the default behavior of Electron is to store granted device permission through
the default behavior of Electron is to store granted device permision through
the lifetime of the corresponding WebContents. If longer term storage is
needed, a developer can store granted device permissions (eg when handling
the `select-hid-device` event) and then read from that storage with
@@ -92,7 +92,7 @@ There are several additional APIs for working with the Web Serial API:
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
can be used to provide default permissioning to devices without first calling
for permission to devices via `navigator.serial.requestPort`. Additionally,
the default behavior of Electron is to store granted device permission through
the default behavior of Electron is to store granted device permision through
the lifetime of the corresponding WebContents. If longer term storage is
needed, a developer can store granted device permissions (eg when handling
the `select-serial-port` event) and then read from that storage with

View File

@@ -1,54 +0,0 @@
---
title: 'Distribution Overview'
description: 'To distribute your app with Electron, you need to package and rebrand it. To do this, you can either use specialized tooling or manual approaches.'
slug: distribution-overview
hide_title: false
---
Once your app is ready for production, there are a couple steps you need to take before
you can deliver it to your users.
## Packaging
To distribute your app with Electron, you need to package all your resources and assets
into an executable and rebrand it. To do this, you can either use specialized tooling
or do it manually. See the [Application Packaging][application-packaging] tutorial
for more information.
## Code signing
Code signing is a security technology that you use to certify that an app was
created by you. You should sign your application so it does not trigger the
security checks of your user's operating system.
To get started with each operating system's code signing process, please read the
[Code Signing][code-signing] docs.
## Publishing
Once your app is packaged and signed, you can freely distribute your app directly
to users by uploading your installers online.
To reach more users, you can also choose to upload your app to each operating system's
digital distribution platform (i.e. app store). These require another build step aside
from your direct download app. For more information, check out each individual app store guide:
- [Mac App Store][mac-app]
- [Windows Store][windows-store]
- [Snapcraft (Linux)][snapcraft]
## Updating
Electron's auto-updater allows you to deliver application updates to users
without forcing them to manually download new versions of your application.
Check out the [Updating Applications][updates] guide for details on implementing automatic updates
with Electron.
<!-- Link labels -->
[application-packaging]: ./application-distribution.md
[code-signing]: ./code-signing.md
[mac-app]: ./mac-app-store-submission-guide.md
[windows-store]: ./windows-store-guide.md
[snapcraft]: ./snapcraft.md
[updates]: ./updates.md

View File

@@ -24,11 +24,10 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | v14.17 | 🚫 |
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | v16.5 | 🚫 |
| 16.0.0 | 2021-Sep-23 | 2021-Oct-20 | 2021-Nov-16 | M96 | v16.9 | 🚫 |
| 17.0.0 | 2021-Nov-18 | 2022-Jan-06 | 2022-Feb-01 | M98 | v16.13 | 🚫 |
| 17.0.0 | 2021-Nov-18 | 2022-Jan-06 | 2022-Feb-01 | M98 | v16.13 | |
| 18.0.0 | 2022-Feb-03 | 2022-Mar-03 | 2022-Mar-29 | M100 | v16.13 | ✅ |
| 19.0.0 | 2022-Mar-31 | 2022-Apr-26 | 2022-May-24 | M102 | v16.14 | ✅ |
| 20.0.0 | 2022-May-26 | 2022-Jun-21 | 2022-Aug-02 | M104 | v16.15 | ✅ |
| 21.0.0 | 2022-Aug-04 | 2022-Aug-30 | 2022-Sep-27 | M106 | TBD | ✅ |
| 20.0.0 | 2022-May-26 | 2022-Jun-21 | 2022-Aug-02 | M104 | TBD | ✅ |
**Notes:**

View File

@@ -18,7 +18,7 @@ npm install --save-dev electron@latest
There are several major changes from our 1.x strategy outlined below. Each change is intended to satisfy the needs and priorities of developers/maintainers and app developers.
1. Strict use of the [SemVer](#semver) spec
1. Strict use of the the [SemVer](#semver) spec
2. Introduction of semver-compliant `-beta` tags
3. Introduction of [conventional commit messages](https://conventionalcommits.org/)
4. Well-defined stabilization branches

View File

@@ -1,56 +0,0 @@
---
title: 'Examples Overview'
description: 'A set of examples for common Electron features'
slug: examples
hide_title: false
---
# Examples Overview
In this section, we have collected a set of guides for common features
that you may want to implement in your Electron application. Each guide
contains a practical example in a minimal, self-contained example app.
The easiest way to run these examples is by downloading [Electron Fiddle][fiddle].
Once Fiddle is installed, you can press on the "Open in Fiddle" button that you
will find below code samples like the following one:
```fiddle docs/fiddles/quick-start
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
})
```
If there is still something that you do not know how to do, please take a look at the [API][app]
as there is a chance it might be documented just there (and also open an issue requesting the
guide!).
<!-- guide-table-start -->
| Guide | Description |
| :-------------------- | ------------------------------------------------------------------------------------------------------------------- |
| [Message ports] | This guide provides some examples of how you might use MessagePorts in your app to communicate different processes. |
| [Device access] | Learn how to access the device hardware (Bluetooth, USB, Serial). |
| [Keyboard shortcuts] | Configure local and global keyboard shortcuts for your Electron application. |
| [Multithreading] | With Web Workers, it is possible to run JavaScript in OS-level threads |
| [Offscreen rendering] | Offscreen rendering lets you obtain the content of a BrowserWindow in a bitmap, so it can be rendered anywhere. |
| [Spellchecker] | Learn how to use the built-in spellchecker, set languages, etc. |
| [Web embeds] | Discover the different ways to embed third-party web content in your application. |
<!-- guide-table-end -->
## How to...?
You can find the full list of "How to?" in the sidebar. If there is
something that you would like to do that is not documented, please join
our [Discord server][discord] and let us know!
[discord]: https://discord.gg/electronjs
[fiddle]: https://www.electronjs.org/fiddle

View File

@@ -1,11 +1,10 @@
---
title: 'Introduction'
description: 'Welcome to the Electron documentation! If this is your first time developing an Electron app, read through this Getting Started section to get familiar with the basics. Otherwise, feel free to explore our guides and API documentation!'
slug: /latest/
hide_title: false
---
# Introduction
# What is Electron?
Welcome to the Electron documentation! If this is your first time developing
an Electron app, read through this Getting Started section to get familiar with the
basics. Otherwise, feel free to explore our guides and API documentation!
## What is Electron?
Electron is a framework for building desktop applications using JavaScript,
HTML, and CSS. By embedding [Chromium][chromium] and [Node.js][node] into its
@@ -13,12 +12,20 @@ binary, Electron allows you to maintain one JavaScript codebase and create
cross-platform apps that work on Windows, macOS, and Linux — no native development
experience required.
## Getting started
## Prerequisites
We recommend you to start with the [tutorial], which guides you through the
process of developing an Electron app and distributing it to users.
The [examples] and [API documentation] are also good places to browse around
and discover new things.
These docs operate under the assumption that the reader is familiar with both
Node.js and general web development. If you need to get more comfortable with
either of these areas, we recommend the following resources:
* [Getting started with the Web (MDN)][mdn-guide]
* [Introduction to Node.js][node-guide]
Moreover, you'll have a better time understanding how Electron works if you get
acquainted with Chromium's process model. You can get a brief overview of
Chrome architecture with the [Chrome comic][comic], which was released alongside
Chrome's launch back in 2008. Although it's been over a decade since then, the
core principles introduced in the comic remain helpful to understand Electron.
## Running examples with Electron Fiddle
@@ -32,45 +39,21 @@ a code block. If you have Fiddle installed, this button will open a
`fiddle.electronjs.org` link that will automatically load the example into Fiddle,
no copy-pasting required.
```fiddle docs/fiddles/quick-start
```
## What is in the docs?
All the official documentation is available from the sidebar. These
are the different categories and what you can expect on each one:
- **Tutorial**: An end-to-end guide on how to create and publish your first Electron
application.
- **Processes in Electron**: In-depth reference on Electron processes and how to work with them.
- **Best Practices**: Important checklists to keep in mind when developing an Electron app.
- **Examples**: Quick references to add features to your Electron app.
- **Development**: Miscellaneous development guides.
- **Distribution**: Learn how to distribute your app to end users.
- **Testing And Debugging**: How to debug JavaScript, write tests, and other tools used
to create quality Electron applications.
- **References**: Useful links to better understand how the Electron project works
and is organized.
- **Contributing**: Compiling Electron and making contributions can be daunting.
We try to make it easier in this section.
## Getting help
Are you getting stuck anywhere? Here are a few links to places to look:
- If you need help with developing your app, our [community Discord server][discord]
is a great place to get advice from other Electron app developers.
- If you suspect you're running into a bug with the `electron` package, please check
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.
* If you need help with developing your app, our [community Discord server][discord]
is a great place to get advice from other Electron app developers.
* If you suspect you're running into a bug with the `electron` package, please check
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.
<!-- Links -->
[tutorial]: tutorial-1-prerequisites.md
[api documentation]: ../api/app.md
[chromium]: https://www.chromium.org/
[discord]: https://discord.gg/electronjs
[examples]: examples.md
[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
[node]: https://nodejs.org/
[discord]: https://discord.gg/electronjs

View File

@@ -8,7 +8,8 @@ your app.
Here is a very brief example of what a MessagePort is and how it works:
```js title='renderer.js (Renderer Process)'
```js
// renderer.js ///////////////////////////////////////////////////////////////
// MessagePorts are created in pairs. A connected pair of message ports is
// called a channel.
const channel = new MessageChannel()
@@ -27,7 +28,8 @@ port2.postMessage({ answer: 42 })
ipcRenderer.postMessage('port', null, [port1])
```
```js title='main.js (Main Process)'
```js
// main.js ///////////////////////////////////////////////////////////////////
// In the main process, we receive the port.
ipcMain.on('port', (event) => {
// When we receive a MessagePort in the main process, it becomes a
@@ -82,84 +84,14 @@ process, you can listen for the `close` event by calling `port.on('close',
## Example use cases
### Setting up a MessageChannel between two renderers
In this example, the main process sets up a MessageChannel, then sends each port
to a different renderer. This allows renderers to send messages to each other
without needing to use the main process as an in-between.
```js title='main.js (Main Process)'
const { BrowserWindow, app, MessageChannelMain } = require('electron')
app.whenReady().then(async () => {
// create the windows.
const mainWindow = new BrowserWindow({
show: false,
webPreferences: {
contextIsolation: false,
preload: 'preloadMain.js'
}
})
const secondaryWindow = BrowserWindow({
show: false,
webPreferences: {
contextIsolation: false,
preload: 'preloadSecondary.js'
}
})
// set up the channel.
const { port1, port2 } = new MessageChannelMain()
// once the webContents are ready, send a port to each webContents with postMessage.
mainWindow.once('ready-to-show', () => {
mainWindow.webContents.postMessage('port', null, [port1])
})
secondaryWindow.once('ready-to-show', () => {
secondaryWindow.webContents.postMessage('port', null, [port2])
})
})
```
Then, in your preload scripts you receive the port through IPC and set up the
listeners.
```js title='preloadMain.js and preloadSecondary.js (Preload scripts)'
const { ipcRenderer } = require('electron')
ipcRenderer.on('port', e => {
// port received, make it globally available.
window.electronMessagePort = e.ports[0]
window.electronMessagePort.onmessage = messageEvent => {
// handle message
}
})
```
In this example messagePort is bound to the `window` object directly. It is better
to use `contextIsolation` and set up specific contextBridge calls for each of your
expected messages, but for the simplicity of this example we don't. You can find an
example of context isolation further down this page at [Communicating directly between the main process and the main world of a context-isolated page](#communicating-directly-between-the-main-process-and-the-main-world-of-a-context-isolated-page)
That means window.messagePort is globally available and you can call
`postMessage` on it from anywhere in your app to send a message to the other
renderer.
```js title='renderer.js (Renderer Process)'
// elsewhere in your code to send a message to the other renderers message handler
window.electronMessagePort.postmessage('ping')
```
### Worker process
In this example, your app has a worker process implemented as a hidden window.
You want the app page to be able to communicate directly with the worker
process, without the performance overhead of relaying via the main process.
```js title='main.js (Main Process)'
```js
// main.js ///////////////////////////////////////////////////////////////////
const { BrowserWindow, app, ipcMain, MessageChannelMain } = require('electron')
app.whenReady().then(async () => {
@@ -197,7 +129,8 @@ app.whenReady().then(async () => {
})
```
```html title='worker.html'
```html
<!-- worker.html ------------------------------------------------------------>
<script>
const { ipcRenderer } = require('electron')
@@ -220,7 +153,8 @@ ipcRenderer.on('new-client', (event) => {
</script>
```
```html title='app.html'
```html
<!-- app.html --------------------------------------------------------------->
<script>
const { ipcRenderer } = require('electron')
@@ -248,7 +182,9 @@ Electron's built-in IPC methods only support two modes: fire-and-forget
can implement a "response stream", where a single request responds with a
stream of data.
```js title='renderer.js (Renderer Process)'
```js
// renderer.js ///////////////////////////////////////////////////////////////
const makeStreamingRequest = (element, callback) => {
// MessageChannels are lightweight--it's cheap to create a new one for each
// request.
@@ -277,7 +213,9 @@ makeStreamingRequest(42, (data) => {
// We will see "got response data: 42" 10 times.
```
```js title='main.js (Main Process)'
```js
// main.js ///////////////////////////////////////////////////////////////////
ipcMain.on('give-me-a-stream', (event, msg) => {
// The renderer has sent us a MessagePort that it wants us to send our
// response over.
@@ -304,7 +242,8 @@ the renderer are delivered to the isolated world, rather than to the main
world. Sometimes you want to deliver messages to the main world directly,
without having to step through the isolated world.
```js title='main.js (Main Process)'
```js
// main.js ///////////////////////////////////////////////////////////////////
const { BrowserWindow, app, MessageChannelMain } = require('electron')
const path = require('path')
@@ -339,7 +278,8 @@ app.whenReady().then(async () => {
})
```
```js title='preload.js (Preload Script)'
```js
// preload.js ////////////////////////////////////////////////////////////////
const { ipcRenderer } = require('electron')
// We need to wait until the main world is ready to receive the message before
@@ -357,7 +297,8 @@ ipcRenderer.on('main-world-port', async (event) => {
})
```
```html title='index.html'
```html
<!-- index.html ------------------------------------------------------------->
<script>
window.onmessage = (event) => {
// event.source === window means the message is coming from the preload

View File

@@ -22,6 +22,7 @@ In `preload.js` use the [`contextBridge`] to inject a method `window.electron.st
```js
const { contextBridge, ipcRenderer } = require('electron')
const path = require('path')
contextBridge.exposeInMainWorld('electron', {
startDrag: (fileName) => {

View File

@@ -1,17 +1,10 @@
---
title: 'Process Model'
description: 'Electron inherits its multi-process architecture from Chromium, which makes the framework architecturally very similar to a modern web browser. This guide will expand on the concepts applied in the tutorial.'
slug: process-model
hide_title: false
---
# Process Model
Electron inherits its multi-process architecture from Chromium, which makes the framework
architecturally very similar to a modern web browser. This guide will expand on the
concepts applied in the [Tutorial][tutorial].
architecturally very similar to a modern web browser. In this guide, we'll expound on
the conceptual knowledge of Electron that we applied in the minimal [quick start app][].
[tutorial]: ./tutorial-1-prerequisites.md
[quick start app]: ./quick-start.md
## Why not a single process?
@@ -34,10 +27,10 @@ visualizes this model:
![Chrome's multi-process architecture](../images/chrome-processes.png)
Electron applications are structured very similarly. As an app developer, you control
two types of processes: [main](#the-main-process) and [renderer](#the-renderer-process).
These are analogous to Chrome's own browser and renderer processes outlined above.
two types of processes: main and renderer. These are analogous to Chrome's own browser
and renderer processes outlined above.
[chrome comic]: https://www.google.com/googlebooks/chrome/
[Chrome Comic]: https://www.google.com/googlebooks/chrome/
## The main process
@@ -47,7 +40,7 @@ to `require` modules and use all of Node.js APIs.
### Window management
The main process' primary purpose is to create and manage application windows with the
The primary purpose of the main process is to create and manage application windows with the
[`BrowserWindow`][browser-window] module.
Each instance of the `BrowserWindow` class creates an application window that loads
@@ -75,7 +68,7 @@ When a `BrowserWindow` instance is destroyed, its corresponding renderer process
terminated as well.
[browser-window]: ../api/browser-window.md
[web-embed]: ../tutorial/web-embeds.md
[web-embed]: ./web-embeds.md
[web-contents]: ../api/web-contents.md
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
@@ -83,7 +76,7 @@ terminated as well.
The main process also controls your application's lifecycle through Electron's
[`app`][app] module. This module provides a large set of events and methods
that you can use to add custom application behaviour (for instance, programmatically
that you can use to add custom application behaviour (for instance, programatically
quitting your application, modifying the application dock, or showing an About panel).
As a practical example, the app shown in the [quick start guide][quick-start-lifecycle]
@@ -97,7 +90,7 @@ app.on('window-all-closed', () => {
```
[app]: ../api/app.md
[quick-start-lifecycle]: ../tutorial/quick-start.md#manage-your-windows-lifecycle
[quick-start-lifecycle]: ./quick-start.md#manage-your-windows-lifecycle
### Native APIs
@@ -112,7 +105,7 @@ For a full list of Electron's main process modules, check out our API documentat
Each Electron app spawns a separate renderer process for each open `BrowserWindow`
(and each web embed). As its name implies, a renderer is responsible for
_rendering_ web content. For all intents and purposes, code ran in renderer processes
*rendering* web content. For all intents and purposes, code ran in renderer processes
should behave according to web standards (insofar as Chromium does, at least).
Therefore, all user interfaces and app functionality within a single browser
@@ -122,22 +115,18 @@ web.
Although explaining every web spec is out of scope for this guide, the bare minimum
to understand is:
- An HTML file is your entry point for the renderer process.
- UI styling is added through Cascading Style Sheets (CSS).
- Executable JavaScript code can be added through `<script>` elements.
* An HTML file is your entry point for the renderer process.
* UI styling is added through Cascading Style Sheets (CSS).
* Executable JavaScript code can be added through `<script>` elements.
Moreover, this also means that the renderer has no direct access to `require`
or other Node.js APIs. In order to directly include NPM modules in the renderer,
you must use the same bundler toolchains (for example, `webpack` or `parcel`) that you
use on the web.
:::warning
Renderer processes can be spawned with a full Node.js environment for ease of
development. Historically, this used to be the default, but this feature was disabled
for security reasons.
:::
> Note: Renderer processes can be spawned with a full Node.js environment for ease of
> development. Historically, this used to be the default, but this feature was disabled
> for security reasons.
At this point, you might be wondering how your renderer process user interfaces
can interact with Node.js and Electron's native desktop functionality if these
@@ -146,9 +135,8 @@ way to import Electron's content scripts.
## Preload scripts
<!-- Note: This guide doesn't take sandboxing into account, which might fundamentally
<!-- 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 run within the renderer context, but are granted more
privileges by having access to Node.js APIs.
@@ -161,8 +149,8 @@ const { BrowserWindow } = require('electron')
//...
const win = new BrowserWindow({
webPreferences: {
preload: 'path/to/preload.js',
},
preload: 'path/to/preload.js'
}
})
//...
```
@@ -177,7 +165,7 @@ the [`contextIsolation`][context-isolation] default.
```js title='preload.js'
window.myAPI = {
desktop: true,
desktop: true
}
```
@@ -196,7 +184,7 @@ securely:
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true,
desktop: true
})
```
@@ -207,15 +195,14 @@ console.log(window.myAPI)
This feature is incredibly useful for two main purposes:
- By exposing [`ipcRenderer`][ipcrenderer] helpers to the renderer, you can use
* By exposing [`ipcRenderer`][ipcRenderer] helpers to the renderer, you can use
inter-process communication (IPC) to trigger main process tasks from the
renderer (and vice-versa).
- If you're developing an Electron wrapper for an existing web app hosted on a remote
* If you're developing an Electron wrapper for an existing web app hosted on a remote
URL, you can add custom properties onto the renderer's `window` global that can
be used for desktop-only logic on the web client's side.
[window-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window
[context-isolation]: ./context-isolation.md
[context-bridge]: ../api/context-bridge.md
[ipcrenderer]: ../api/ipc-renderer.md
[tutorial]: ./tutorial-1-prerequisites.md
[ipcRenderer]: ../api/ipc-renderer.md

View File

@@ -1,143 +0,0 @@
---
title: 'Prerequisites'
description: 'This guide will step you through the process of creating a barebones Hello World app in Electron, similar to electron/electron-quick-start.'
slug: tutorial-prerequisites
hide_title: false
---
:::info Follow along the tutorial
This is **part 1** of the Electron tutorial.
1. **[Prerequisites][prerequisites]**
1. [Building your First App][building your first app]
1. [Using Preload Scripts][preload]
1. [Adding Features][features]
1. [Packaging Your Application][packaging]
1. [Publishing and Updating][updates]
:::
Electron is a framework for building desktop applications using JavaScript,
HTML, and CSS. By embedding [Chromium][chromium] and [Node.js][node] into a
single binary file, Electron allows you to create cross-platform apps that
work on Windows, macOS, and Linux with a single JavaScript codebase.
This tutorial will guide you through the process of developing a desktop
application with Electron and distributing it to end users.
## Assumptions
Electron is a native wrapper layer for web apps and is run in a Node.js environment.
Therefore, this tutorial assumes you are generally familiar with Node and
front-end web development basics. If you need to do some background reading before
continuing, we recommend the following resources:
- [Getting started with the Web (MDN Web Docs)][mdn-guide]
- [Introduction to Node.js][node-guide]
## Required tools
### Code editor
You will need a text editor to write your code. We recommend using [Visual Studio Code],
although you can choose whichever one you prefer.
### Command line
Throughout the tutorial, we will ask you to use various command-line interfaces (CLIs). You can
type these commands into your system's default terminal:
- Windows: Command Prompt or PowerShell
- macOS: Terminal
- Linux: varies depending on distribution (e.g. GNOME Terminal, Konsole)
Most code editors also come with an integrated terminal, which you can also use.
### Git and GitHub
Git is a commonly-used version control system for source code, and GitHub is a collaborative
development platform built on top of it. Although neither is strictly necessary to building
an Electron application, we will use GitHub releases to set up automatic updates later
on in the tutorial. Therefore, we'll require you to:
- [Create a GitHub account](https://github.com/join)
- [Install Git](https://github.com/git-guides/install-git)
If you're unfamiliar with how Git works, we recommend reading GitHub's [Git guides]. You can also
use the [GitHub Desktop] app if you prefer using a visual interface over the command line.
We recommend that you create a local Git repository and publish it to GitHub before starting
the tutorial, and commit your code after every step.
:::info Installing Git via GitHub Desktop
GitHub Desktop will install the latest version of Git on your system if you don't already have
it installed.
:::
### Node.js and npm
To begin developing an Electron app, you need to install the [Node.js][node-download]
runtime and its bundled npm package manager onto your system. We recommend that you
use the latest long-term support (LTS) version.
:::tip
Please install Node.js using pre-built installers for your platform.
You may encounter incompatibility issues with different development tools otherwise.
If you are using macOS, we recommend using a package manager like [Homebrew] or
[nvm] to avoid any directory permission issues.
:::
To check that Node.js was installed correctly, you can use the `-v` flag when
running the `node` and `npm` commands. These should print out the installed
versions.
```sh
$ node -v
v16.14.2
$ npm -v
8.7.0
```
:::caution
Although you need Node.js installed locally to scaffold an Electron project,
Electron **does not use your system's Node.js installation to run its code**. Instead, it
comes bundled with its own Node.js runtime. This means that your end users do not
need to install Node.js themselves as a prerequisite to running your app.
To check which version of Node.js is running in your app, you can access the global
[`process.versions`] variable in the main process or preload script. You can also reference
the list of versions in the [electron/releases] repository.
:::
<!-- Links -->
[chromium]: https://www.chromium.org/
[electron/releases]: https://github.com/electron/releases/blob/master/readme.md#releases
[homebrew]: https://brew.sh/
[mdn-guide]: https://developer.mozilla.org/en-US/docs/Learn/
[node]: https://nodejs.org/
[node-guide]: https://nodejs.dev/learn
[node-download]: https://nodejs.org/en/download/
[nvm]: https://github.com/nvm-sh/nvm
[process-model]: ./process-model.md
[`process.versions`]: https://nodejs.org/api/process.html#processversions
[github]: https://github.com/
[git guides]: https://github.com/git-guides/
[github desktop]: https://desktop.github.com/
[visual studio code]: https://code.visualstudio.com/
<!-- Tutorial links -->
[prerequisites]: tutorial-1-prerequisites.md
[building your first app]: tutorial-2-first-app.md
[preload]: tutorial-3-preload.md
[features]: tutorial-4-adding-features.md
[packaging]: tutorial-5-packaging.md
[updates]: tutorial-6-publishing-updating.md

View File

@@ -1,480 +0,0 @@
---
title: 'Building your First App'
description: 'This guide will step you through the process of creating a barebones Hello World app in Electron, similar to electron/electron-quick-start.'
slug: tutorial-first-app
hide_title: false
---
:::info Follow along the tutorial
This is **part 2** of the Electron tutorial.
1. [Prerequisites][prerequisites]
1. **[Building your First App][building your first app]**
1. [Using Preload Scripts][preload]
1. [Adding Features][features]
1. [Packaging Your Application][packaging]
1. [Publishing and Updating][updates]
:::
## Learning goals
In this part of the tutorial, you will learn how to set up your Electron project
and write a minimal starter application. By the end of this section,
you should be able to run a working Electron app in development mode from
your terminal.
## Setting up your project
:::caution Avoid WSL
If you are on a Windows machine, please do not use [Windows Subsystem for Linux][wsl] (WSL)
when following this tutorial as you will run into issues when trying to execute the
application.
<!--https://www.electronforge.io/guides/developing-with-wsl-->
:::
### Initializing your npm project
Electron apps are scaffolded using npm, with the package.json file
as an entry point. Start by creating a folder and initializing an npm package
within it with `npm init`.
```sh npm2yarn
mkdir my-electron-app && cd my-electron-app
npm init
```
This command will prompt you to configure some fields in your package.json.
There are a few rules to follow for the purposes of this tutorial:
- _entry point_ should be `main.js` (you will be creating that file soon).
- _author_, _license_, and _description_ can be any value, but will be necessary for
[packaging][packaging] later on.
Then, install Electron into your app's **devDependencies**, which is the list of external
development-only package dependencies not required in production.
:::info Why is Electron a devDependency?
This may seem counter-intuitive since your production code is running Electron APIs.
However, packaged apps will come bundled with the Electron binary, eliminating the need to specify
it as a production dependency.
:::
```sh npm2yarn
npm install electron --save-dev
```
Your package.json file should look something like this after initializing your package
and installing Electron. You should also now have a `node_modules` folder containing
the Electron executable, as well as a `package-lock.json` lockfile that specifies
the exact dependency versions to install.
```json title='package.json'
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "19.0.0"
}
}
```
:::info Advanced Electron installation steps
If installing Electron directly fails, please refer to our [Advanced Installation][installation]
documentation for instructions on download mirrors, proxies, and troubleshooting steps.
:::
### Adding a .gitignore
The [`.gitignore`][gitignore] file specifies which files and directories to avoid tracking
with Git. You should place a copy of [GitHub's Node.js gitignore template][gitignore-template]
into your project's root folder to avoid committing your project's `node_modules` folder.
## Running an Electron app
:::tip Further reading
Read [Electron's process model][process-model] documentation to better
understand how Electron's multiple processes work together.
:::
The [`main`][package-json-main] script you defined in package.json is the entry point of any
Electron application. This script controls the **main process**, which runs in a Node.js
environment and is responsible for controlling your app's lifecycle, displaying native
interfaces, performing privileged operations, and managing renderer processes
(more on that later).
Before creating your first Electron app, you will first use a trivial script to ensure your
main process entry point is configured correctly. Create a `main.js` file in the root folder
of your project with a single line of code:
```js title='main.js'
console.log(`Hello from Electron 👋`)
```
Because Electron's main process is a Node.js runtime, you can execute arbitrary Node.js code
with the `electron` command (you can even use it as a [REPL]). To execute this script,
add `electron .` to the `start` command in the [`scripts`][package-scripts]
field of your package.json. This command will tell the Electron executable to look for the main
script in the current directory and run it in dev mode.
```json {8-10} title='package.json'
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"author": "Jane Doe",
"license": "MIT",
"scripts": {
"start": "electron ."
},
"devDependencies": {
"electron": "^19.0.0"
}
}
```
```sh npm2yarn
npm run start
```
Your terminal should print out `Hello from Electron 👋`. Congratulations,
you have executed your first line of code in Electron! Next, you will learn
how to create user interfaces with HTML and load that into a native window.
## Loading a web page into a BrowserWindow
In Electron, each window displays a web page that can be loaded either from a local HTML
file or a remote web address. For this example, you will be loading in a local file. Start
by creating a barebones web page in an `index.html` file in the root folder of your project:
```html title='index.html'
<!DOCTYPE html>
<html>
<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>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
</body>
</html>
```
Now that you have a web page, you can load it into an Electron [BrowserWindow][browser-window].
Replace the contents your `main.js` file with the following code. We will explain each
highlighted block separately.
```js {1,3-10,12-14} title='main.js' showLineNumbers
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
```
### Importing modules
```js title='main.js (Line 1)'
const { app, BrowserWindow } = require('electron')
```
In the first line, we are importing two Electron modules
with CommonJS module syntax:
- [app][app], which controls your application's event lifecycle.
- [BrowserWindow][browser-window], which creates and manages app windows.
:::info Capitalization conventions
You might have noticed the capitalization difference between the **a**pp
and **B**rowser**W**indow modules. Electron follows typical JavaScript conventions here,
where PascalCase modules are instantiable class constructors (e.g. BrowserWindow, Tray,
Notification) whereas camelCase modules are not instantiable (e.g. app, ipcRenderer, webContents).
:::
:::warning ES Modules in Electron
[ECMAScript modules](https://nodejs.org/api/esm.html) (i.e. using `import` to load a module)
are currently not directly supported in Electron. You can find more information about the
state of ESM in Electron in [electron/electron#21457](https://github.com/electron/electron/issues/21457).
:::
### Writing a reusable function to instantiate windows
The `createWindow()` function loads your web page into a new BrowserWindow instance:
```js title='main.js (Lines 3-10)'
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
})
win.loadFile('index.html')
}
```
### Calling your function when the app is ready
```js title='main.js (Lines 12-14)'
app.whenReady().then(() => {
createWindow()
})
```
Many of Electron's core modules are Node.js [event emitters] that adhere to Node's asynchronous
event-driven architecture. The app module is one of these emitters.
In Electron, BrowserWindows can only be created after the app module's [`ready`][app-ready] event
is fired. You can wait for this event by using the [`app.whenReady()`][app-when-ready] API and
calling `createWindow()` once its promise is fulfilled.
:::info
You typically listen to Node.js events by using an emitter's `.on` function.
```diff
+ app.on('ready').then(() => {
- app.whenReady().then(() => {
createWindow()
})
```
However, Electron exposes `app.whenReady()` as a helper specifically for the `ready` event to
avoid subtle pitfalls with directly listening to that event in particular.
See [electron/electron#21972](https://github.com/electron/electron/pull/21972) for details.
:::
At this point, running your Electron application's `start` command should successfully
open a window that displays your web page!
Each web page your app displays in a window will run in a separate process called a
**renderer** process (or simply _renderer_ for short). Renderer processes have access
to the same JavaScript APIs and tooling you use for typical front-end web
development, such as using [webpack] to bundle and minify your code or [React][react]
to build your user interfaces.
## Managing your app's window lifecycle
Application windows behave differently on each operating system. Rather than
enforce these conventions by default, Electron gives you the choice to implement
them in your app code if you wish to follow them. You can implement basic window
conventions by listening for events emitted by the app and BrowserWindow modules.
:::tip Process-specific control flow
Checking against Node's [`process.platform`][node-platform] variable can help you
to run code conditionally on certain platforms. Note that there are only three
possible platforms that Electron can run in: `win32` (Windows), `linux` (Linux),
and `darwin` (macOS).
:::
### Quit the app when all windows are closed (Windows & Linux)
On Windows and Linux, closing all windows will generally quit an application entirely.
To implement this pattern in your Electron app, listen for the app module's
[`window-all-closed`][window-all-closed] event, and call [`app.quit()`][app-quit]
to exit your app if the user is not on macOS.
```js
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
```
### Open a window if none are open (macOS)
In contrast, macOS apps generally continue running even without any windows open.
Activating the app when no windows are available should open a new one.
To implement this feature, listen for the app module's [`activate`][activate]
event, and call your existing `createWindow()` method if no BrowserWindows are open.
Because windows cannot be created before the `ready` event, you should only listen for
`activate` events after your app is initialized. Do this by only listening for activate
events inside your existing `whenReady()` callback.
```js
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
```
## Final starter code
```fiddle docs/fiddles/tutorial-first-app
```
## Optional: Debugging from VS Code
If you want to debug your application using VS Code, you need to attach VS Code to
both the main and renderer processes. Here is a sample configuration for you to
run. Create a launch.json configuration in a new `.vscode` folder in your project:
```json title='.vscode/launch.json'
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "pwa-chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "pwa-node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}
```
The "Main + renderer" option will appear when you select "Run and Debug"
from the sidebar, allowing you to set breakpoints and inspect all the variables among
other things in both the main and renderer processes.
What we have done in the `launch.json` file is to create 3 configurations:
- `Main` is used to start the main process and also expose port 9222 for remote debugging
(`--remote-debugging-port=9222`). This is the port that we will use to attach the debugger
for the `Renderer`. Because the main process is a Node.js process, the type is set to
`pwa-node` (`pwa-` is the prefix that tells VS Code to use the latest JavaScript debugger).
- `Renderer` is used to debug the renderer process. Because the main process is the one
that creates the process, we have to "attach" to it (`"request": "attach"`) instead of
creating a new one.
The renderer process is a web one, so the debugger we have to use is `pwa-chrome`.
- `Main + renderer` is a [compound task] that executes the previous ones simultaneously.
:::caution
Because we are attaching to a process in `Renderer`, it is possible that the first lines of
your code will be skipped as the debugger will not have had enough time to connect before they are
being executed.
You can work around this by refreshing the page or setting a timeout before executing the code
in development mode.
:::
:::info Further reading
If you want to dig deeper in the debugging area, the following guides provide more information:
- [Application Debugging]
- [DevTools Extensions][devtools extension]
:::
## Summary
Electron applications are set up using npm packages. The Electron executable should be installed
in your project's `devDependencies` and can be run in development mode using a script in your
package.json file.
The executable runs the JavaScript entry point found in the `main` property of your package.json.
This file controls Electron's **main process**, which runs an instance of Node.js and is
responsible for your app's lifecycle, displaying native interfaces, performing privileged operations,
and managing renderer processes.
**Renderer processes** (or renderers for short) are responsible for display graphical content. You can
load a web page into a renderer by pointing it to either a web address or a local HTML file.
Renderers behave very similarly to regular web pages and have access to the same web APIs.
In the next section of the tutorial, we will be learning how to augment the renderer process with
privileged APIs and how to communicate between processes.
<!-- Links -->
[activate]: ../api/app.md#event-activate-macos
[advanced-installation]: installation.md
[app]: ../api/app.md
[app-quit]: ../api/app.md#appquit
[app-ready]: ../api/app.md#event-ready
[app-when-ready]: ../api/app.md#appwhenready
[application debugging]: ./application-debugging.md
[browser-window]: ../api/browser-window.md
[commonjs]: https://nodejs.org/docs/../api/modules.html#modules_modules_commonjs_modules
[compound task]: https://code.visualstudio.com/Docs/editor/tasks#_compound-tasks
[devtools extension]: ./devtools-extension.md
[event emitters]: https://nodejs.org/api/events.html#events
[gitignore]: https://git-scm.com/docs/gitignore
[gitignore-template]: https://github.com/github/gitignore/blob/main/Node.gitignore
[installation]: ./installation.md
[node-platform]: https://nodejs.org/api/process.html#process_process_platform
[package-json-main]: https://docs.npmjs.com/cli/v7/configuring-npm/package-json#main
[package-scripts]: https://docs.npmjs.com/cli/v7/using-npm/scripts
[process-model]: process-model.md
[react]: https://reactjs.org
[repl]: ./repl.md
[sandbox]: ./sandbox.md
[webpack]: https://webpack.js.org
[window-all-closed]: ../api/app.md#event-window-all-closed
[wsl]: https://docs.microsoft.com/en-us/windows/wsl/about#what-is-wsl-2
<!-- Tutorial links -->
[prerequisites]: tutorial-1-prerequisites.md
[building your first app]: tutorial-2-first-app.md
[preload]: tutorial-3-preload.md
[features]: tutorial-4-adding-features.md
[packaging]: tutorial-5-packaging.md
[updates]: tutorial-6-publishing-updating.md

View File

@@ -1,271 +0,0 @@
---
title: 'Using Preload Scripts'
description: 'This guide will step you through the process of creating a barebones Hello World app in Electron, similar to electron/electron-quick-start.'
slug: tutorial-preload
hide_title: false
---
:::info Follow along the tutorial
This is **part 3** of the Electron tutorial.
1. [Prerequisites][prerequisites]
1. [Building your First App][building your first app]
1. **[Using Preload Scripts][preload]**
1. [Adding Features][features]
1. [Packaging Your Application][packaging]
1. [Publishing and Updating][updates]
:::
## Learning goals
In this part of the tutorial, you will learn what a preload script is and how to use one
to securely expose privileged APIs into the renderer process. You will also learn how to
communicate between main and renderer processes with Electron's inter-process
communication (IPC) modules.
## What is a preload script?
Electron's main process is a Node.js environment that has full operating system access.
On top of [Electron modules][modules], you can also access [Node.js built-ins][node-api],
as well as any packages installed via npm. On the other hand, renderer processes run web
pages and do not run Node.js by default for security reasons.
To bridge Electron's different process types together, we will need to use a special script
called a **preload**.
## Augmenting the renderer with a preload script
A BrowserWindow's preload script runs in a context that has access to both the HTML DOM
and a Node.js environment. Preload scripts are injected before a web page loads in the renderer,
similar to a Chrome extension's [content scripts][content-script]. To add features to your renderer
that require privileged access, you can define [global] objects through the
[contextBridge][contextbridge] API.
To demonstrate this concept, you will create a preload script that exposes your app's
versions of Chrome, Node, and Electron into the renderer.
Add a new `preload.js` script that exposes selected properties of Electron's `process.versions`
object to the renderer process in a `versions` global variable.
```js title="preload.js"
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
// we can also expose variables, not just functions
})
```
To attach this script to your renderer process, pass its path to the
`webPreferences.preload` option in the BrowserWindow constructor:
```js {8-10} title="main.js"
const { app, BrowserWindow } = require('electron')
const path = require('path')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
```
:::info
There are two Node.js concepts that are used here:
- The [`__dirname`][dirname] string points to the path of the currently executing script
(in this case, your project's root folder).
- The [`path.join`][path-join] API joins multiple path segments together, creating a
combined path string that works across all platforms.
:::
At this point, the renderer has access to the `versions` global, so let's display that
information in the window. This variable can be accessed via `window.versions` or simply
`versions`. Create a `renderer.js` script that uses the [`document.getElementById`]
DOM API to replace the displayed text for the HTML element with `info` as its `id` property.
```js title="renderer.js"
const information = document.getElementById('info')
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`
```
Then, modify your `index.html` by adding a new element with `info` as its `id` property,
and attach your `renderer.js` script:
```html {18,20} title="index.html"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<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>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
</body>
<script src="./renderer.js"></script>
</html>
```
After following the above steps, your app should look something like this:
![Electron app showing This app is using Chrome (v102.0.5005.63), Node.js (v16.14.2), and Electron (v19.0.3)](../images/preload-example.png)
And the code should look like this:
```fiddle docs/fiddles/tutorial-preload
```
## Communicating between processes
As we have mentioned above, Electron's main and renderer process have distinct responsibilities
and are not interchangeable. This means it is not possible to access the Node.js APIs directly
from the renderer process, nor the HTML Document Object Model (DOM) from the main process.
The solution for this problem is to use Electron's `ipcMain` and `ipcRenderer` modules for
inter-process communication (IPC). To send a message from your web page to the main process,
you can set up a main process handler with `ipcMain.handle` and
then expose a function that calls `ipcRenderer.invoke` to trigger the handler in your preload script.
To illustrate, we will add a global function to the renderer called `ping()`
that will return a string from the main process.
First, set up the `invoke` call in your preload script:
```js {1,7} title="preload.js"
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
ping: () => ipcRenderer.invoke('ping'),
// we can also expose variables, not just functions
})
```
:::caution IPC security
Notice how we wrap the `ipcRenderer.invoke('ping')` call in a helper function rather
than expose the `ipcRenderer` module directly via context bridge. You **never** want to
directly expose the entire `ipcRenderer` module via preload. This would give your renderer
the ability to send arbitrary IPC messages to the main process, which becomes a powerful
attack vector for malicious code.
:::
Then, set up your `handle` listener in the main process. We do this _before_
loading the HTML file so that the handler is guaranteed to be ready before
you send out the `invoke` call from the renderer.
```js {1,11} title="main.js"
const { ipcMain } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
ipcMain.handle('ping', () => 'pong')
win.loadFile('index.html')
}
```
Once you have the sender and receiver set up, you can now send messages from the renderer
to the main process through the `'ping'` channel you just defined.
```js title='renderer.js'
const func = async () => {
const response = await window.versions.ping()
console.log(response) // prints out 'pong'
}
func()
```
:::info
For more in-depth explanations on using the `ipcRenderer` and `ipcMain` modules,
check out the full [Inter-Process Communication][ipc] guide.
:::
## Summary
A preload script contains code that runs before your web page is loaded into the browser
window. It has access to both DOM APIs and Node.js environment, and is often used to
expose privileged APIs to the renderer via the `contextBridge` API.
Because the main and renderer processes have very different responsibilities, Electron
apps often use the preload script to set up inter-process communication (IPC) interfaces
to pass arbitrary messages between the two kinds of processes.
In the next part of the tutorial, we will be showing you resources on adding more
functionality to your app, then teaching you distributing your app to users.
<!-- Links -->
[advanced-installation]: ./installation.md
[application debugging]: ./application-debugging.md
[app]: ../api/app.md
[app-ready]: ../api/app.md#event-ready
[app-when-ready]: ../api/app.md#appwhenready
[browser-window]: ../api/browser-window.md
[commonjs]: https://nodejs.org/docs/latest/api/modules.html#modules_modules_commonjs_modules
[compound task]: https://code.visualstudio.com/Docs/editor/tasks#_compound-tasks
[content-script]: https://developer.chrome.com/docs/extensions/mv3/content_scripts/
[contextbridge]: ../api/context-bridge.md
[context-isolation]: ./context-isolation.md
[`document.getelementbyid`]: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
[devtools-extension]: ./devtools-extension.md
[dirname]: https://nodejs.org/api/modules.html#modules_dirname
[global]: https://developer.mozilla.org/en-US/docs/Glossary/Global_object
[ipc]: ./ipc.md
[mdn-csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
[modules]: ../api/app.md
[node-api]: https://nodejs.org/dist/latest/docs/api/
[package-json-main]: https://docs.npmjs.com/cli/v7/configuring-npm/package-json#main
[package-scripts]: https://docs.npmjs.com/cli/v7/using-npm/scripts
[path-join]: https://nodejs.org/api/path.html#path_path_join_paths
[process-model]: ./process-model.md
[react]: https://reactjs.org
[sandbox]: ./sandbox.md
[webpack]: https://webpack.js.org
<!-- Tutorial links -->
[prerequisites]: tutorial-1-prerequisites.md
[building your first app]: tutorial-2-first-app.md
[preload]: tutorial-3-preload.md
[features]: tutorial-4-adding-features.md
[packaging]: tutorial-5-packaging.md
[updates]: tutorial-6-publishing-updating.md

View File

@@ -1,77 +0,0 @@
---
title: 'Adding Features'
description: 'In this step of the tutorial, we will share some resources you should read to add features to your application'
slug: tutorial-adding-features
hide_title: false
---
:::info Follow along the tutorial
This is **part 4** of the Electron tutorial.
1. [Prerequisites][prerequisites]
1. [Building your First App][building your first app]
1. [Using Preload Scripts][preload]
1. **[Adding Features][features]**
1. [Packaging Your Application][packaging]
1. [Publishing and Updating][updates]
:::
## Adding application complexity
If you have been following along, you should have a functional Electron application
with a static user interface. From this starting point, you can generally progress
in developing your app in two broad directions:
1. Adding complexity to your renderer process' web app code
1. Deeper integrations with the operating system and Node.js
It is important to understand the distinction between these two broad concepts. For the
first point, Electron-specific resources are not necessary. Building a pretty to-do
list in Electron is just pointing your Electron BrowserWindow to a pretty
to-do list web app. Ultimately, you are building your renderer's UI using the same tools
(HTML, CSS, JavaScript) that you would on the web. Therefore, Electron's docs will
not go in-depth on how to use standard web tools.
On the other hand, Electron also provides a rich set of tools that allow
you to integrate with the desktop environment, from creating tray icons to adding
global shortcuts to displaying native menus. It also gives you all the power of a
Node.js environment in the main process. This set of capabilities separates
Electron applications from running a website in a browser tab, and are the
focus of Electron's documentation.
## How-to examples
Electron's documentation has many tutorials to help you with more advanced topics
and deeper operating system integrations. To get started, check out the
[How-To Examples][how-to] doc.
:::note Let us know if something is missing!
If you can't find what you are looking for, please let us know on [GitHub] or in
our [Discord server][discord]!
:::
## What's next?
For the rest of the tutorial, we will be shifting away from application code
and giving you a look at how you can get your app from your developer machine
into end users' hands.
<!-- Link labels -->
[discord]: https://discord.gg/electronjs
[github]: https://github.com/electron/electronjs.org-new/issues/new
[how-to]: ./examples.md
[node-platform]: https://nodejs.org/api/process.html#process_process_platform
<!-- Tutorial links -->
[prerequisites]: tutorial-1-prerequisites.md
[building your first app]: tutorial-2-first-app.md
[preload]: tutorial-3-preload.md
[features]: tutorial-4-adding-features.md
[packaging]: tutorial-5-packaging.md
[updates]: tutorial-6-publishing-updating.md

View File

@@ -1,225 +0,0 @@
---
title: 'Packaging Your Application'
description: 'To distribute your app with Electron, you need to package it and create installers.'
slug: tutorial-packaging
hide_title: false
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
:::info Follow along the tutorial
This is **part 5** of the Electron tutorial.
1. [Prerequisites][prerequisites]
1. [Building your First App][building your first app]
1. [Using Preload Scripts][preload]
1. [Adding Features][features]
1. **[Packaging Your Application][packaging]**
1. [Publishing and Updating][updates]
:::
## Learning goals
In this part of the tutorial, we'll be going over the basics of packaging and distributing
your app with [Electron Forge].
## Using Electron Forge
Electron does not have any tooling for packaging and distribution bundled into its core
modules. Once you have a working Electron app in dev mode, you need to use
additional tooling to create a packaged app you can distribute to your users (also known
as a **distributable**). Distributables can be either installers (e.g. MSI on Windows) or
portable executable files (e.g. `.app` on macOS).
Electron Forge is an all-in-one tool that handles the packaging and distribution of Electron
apps. Under the hood, it combines a lot of existing Electron tools (e.g. [`electron-packager`],
[`@electron/osx-sign`], [`electron-winstaller`], etc.) into a single interface so you do not
have to worry about wiring them all together.
### Importing your project into Forge
You can install Electron Forge's CLI in your project's `devDependencies` and import your
existing project with a handy conversion script.
```sh npm2yarn
npm install --save-dev @electron-forge/cli
npx electron-forge import
```
Once the conversion script is done, Forge should have added a few scripts
to your `package.json` file.
```json title='package.json'
//...
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
},
//...
```
:::info CLI documentation
For more information on `make` and other Forge APIs, check out
the [Electron Forge CLI documentation].
:::
You should also notice that your package.json now has a few more packages installed
under your `devDependencies`, and contains an added `config.forge` field with an array
of makers configured. **Makers** are Forge plugins that create distributables from
your source code. You should see multiple makers in the pre-populated configuration,
one for each target platform.
### Creating a distributable
To create a distributable, use your project's new `make` script, which runs the
`electron-forge make` command.
```sh npm2yarn
npm run make
```
This `make` command contains two steps:
1. It will first run `electron-forge package` under the hood, which bundles your app
code together with the Electron binary. The packaged code is generated into a folder.
1. It will then use this packaged app folder to create a separate distributable for each
configured maker.
After the script runs, you should see an `out` folder containing both the distributable
and a folder containing the packaged application code.
```plain title='macOS output example'
out/
├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip
├── ...
└── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app
```
The distributable in the `out/make` folder should be ready to launch! You have now
created your first bundled Electron application.
:::tip Distributable formats
Electron Forge can be configured to create distributables in different OS-specific formats
(e.g. DMG, deb, MSI, etc.). See Forge's [Makers] documentation for all configuration options.
:::
:::note Packaging without Electron Forge
If you want to manually package your code, or if you're just interested understanding the
mechanics behind packaging an Electron app, check out the full [Application Packaging]
documentation.
:::
## Important: signing your code
In order to distribute desktop applications to end users, we _highly recommended_ for you
to **code sign** your Electron app. Code signing is an important part of shipping
desktop applications, and is mandatory for the auto-update step in the final part
of the tutorial.
Code signing is a security technology that you use to certify that a desktop app was
created by a known source. Windows and macOS have their own OS-specific code signing
systems that will make it difficult for users to download or launch unsigned applications.
If you already have code signing certificates for Windows and macOS, you can set your
credentials in your Forge configuration. Otherwise, please refer to the full
[Code Signing] documentation to learn how to purchase a certificate and for more information
on the desktop app code signing process.
On macOS, code signing is done at the app packaging level. On Windows, distributable installers
are signed instead.
<Tabs>
<TabItem value="macos" label="macOS" default>
```json title='package.json' {6-18}
{
//...
"config": {
"forge": {
//...
"packagerConfig": {
"osxSign": {
"identity": "Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)",
"hardened-runtime": true,
"entitlements": "entitlements.plist",
"entitlements-inherit": "entitlements.plist",
"signature-flags": "library"
},
"osxNotarize": {
"appleId": "felix@felix.fun",
"appleIdPassword": "this-is-a-secret"
}
}
//...
}
}
//...
}
```
</TabItem>
<TabItem value="windows" label="Windows">
```json title='package.json' {6-14}
{
//...
"config": {
"forge": {
//...
"makers": [
{
"name": "@electron-forge/maker-squirrel",
"config": {
"certificateFile": "./cert.pfx",
"certificatePassword": "this-is-a-secret"
}
}
]
//...
}
}
//...
}
```
</TabItem>
</Tabs>
## Summary
Electron applications need to be packaged to be distributed to users. In this tutorial,
you imported your app into Electron Forge and configured it to package your app and
generate installers.
In order for your application to be trusted by the user's system, you need to digitally
certify that the distributable is authentic and untampered by code signing it. Your app
can be signed through Forge once you configure it to use your code signing certificate
information.
[`@electron/osx-sign`]: https://github.com/electron/osx-sign
[application packaging]: ./application-distribution.md
[code signing]: ./code-signing.md
[`electron-packager`]: https://github.com/electron/electron-packager
[`electron-winstaller`]: https://github.com/electron/windows-installer
[electron forge]: https://www.electronforge.io
[electron forge cli documentation]: https://www.electronforge.io/cli#commands
[makers]: https://www.electronforge.io/config/makers
<!-- Tutorial links -->
[prerequisites]: tutorial-1-prerequisites.md
[building your first app]: tutorial-2-first-app.md
[preload]: tutorial-3-preload.md
[features]: tutorial-4-adding-features.md
[packaging]: tutorial-5-packaging.md
[updates]: tutorial-6-publishing-updating.md

View File

@@ -1,251 +0,0 @@
---
title: 'Publishing and Updating'
description: "There are several ways to update an Electron application. The easiest and officially supported one is taking advantage of the built-in Squirrel framework and Electron's autoUpdater module."
slug: tutorial-publishing-updating
hide_title: false
---
:::info Follow along the tutorial
This is **part 6** of the Electron tutorial.
1. [Prerequisites][prerequisites]
1. [Building your First App][building your first app]
1. [Using Preload Scripts][preload]
1. [Adding Features][features]
1. [Packaging Your Application][packaging]
1. **[Publishing and Updating][updates]**
:::
## Learning goals
If you've been following along, this is the last step of the tutorial! In this part,
you will publish your app to GitHub releases and integrate automatic updates
into your app code.
## Using update.electronjs.org
The Electron maintainers provide a free auto-updating service for open-source apps
at [https://update.electronjs.org](https://update.electronjs.org). Its requirements are:
- Your app runs on macOS or Windows
- Your app has a public GitHub repository
- Builds are published to [GitHub releases]
- Builds are [code signed][code-signed]
At this point, we'll assume that you have already pushed all your
code to a public GitHub repository.
:::info Alternative update services
If you're using an alternate repository host (e.g. GitLab or Bitbucket) or if
you need to keep your code repository private, please refer to our
[step-by-step guide][update-server] on hosting your own Electron update server.
:::
## Publishing a GitHub release
Electron Forge has [Publisher] plugins that can automate the distribution
of your packaged application to various sources. In this tutorial, we will
be using the GitHub Publisher, which will allow us to publish
our code to GitHub releases.
### Generating a personal access token
Forge cannot publish to any repository on GitHub without permission. You
need to pass in an authenticated token that gives Forge access to
your GitHub releases. The easiest way to do this is to
[create a new personal access token (PAT)][new-pat]
with the `public_repo` scope, which gives write access to your public repositories.
**Make sure to keep this token a secret.**
### Setting up the GitHub Publisher
#### Installing the module
Forge's [GitHub Publisher] is a plugin that
needs to be installed in your project's `devDependencies`:
```sh npm2yarn
npm install --save-dev @electron-forge/publisher-github
```
#### Configuring the publisher in Forge
Once you have it installed, you need to set it up in your Forge
configuration. A full list of options is documented in the Forge's
[`PublisherGitHubConfig`] API docs.
```json title='package.json' {6-16}
{
//...
"config": {
"forge": {
"publishers": [
{
"name": "@electron-forge/publisher-github",
"config": {
"repository": {
"owner": "github-user-name",
"name": "github-repo-name"
},
"prerelease": false,
"draft": true
}
}
]
}
}
//...
}
```
:::tip Drafting releases before publishing
Notice that you have configured Forge to publish your release as a draft.
This will allow you to see the release with its generated artifacts
without actually publishing it to your end users. You can manually
publish your releases via GitHub after writing release notes and
double-checking that your distributables work.
:::
#### Setting up your authentication token
You also need to make the Publisher aware of your authentication token.
By default, it will use the value stored in the `GITHUB_TOKEN` environment
variable.
### Running the publish command
Add Forge's [publish command] to your npm scripts.
```json {6} title='package.json'
//...
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish"
},
//...
```
This command will run your configured makers and publish the output distributables to a new
GitHub release.
```sh npm2yarn
npm run publish
```
By default, this will only publish a single distributable for your host operating system and
architecture. You can publish for different architectures by passing in the `--arch` flag to your
Forge commands.
The name of this release will correspond to the `version` field in your project's package.json file.
:::tip Tagging releases
Optionally, you can also [tag your releases in Git][git-tag] so that your
release is associated with a labeled point in your code history. npm comes
with a handy [`npm version`](https://docs.npmjs.com/cli/v8/commands/npm-version)
command that can handle the version bumping and tagging for you.
:::
#### Bonus: Publishing in GitHub Actions
Publishing locally can be painful, especially because you can only create distributables
for your host operating system (i.e. you can't publish a Window `.exe` file from macOS).
A solution for this would be to publish your app via automation workflows
such as [GitHub Actions], which can run tasks in the
cloud on Ubuntu, macOS, and Windows. This is the exact approach taken by [Electron Fiddle].
You can refer to Fiddle's [Build and Release pipeline][fiddle-build]
and [Forge configuration][fiddle-forge-config]
for more details.
## Instrumenting your updater code
Now that we have a functional release system via GitHub releases, we now need to tell our
Electron app to download an update whenever a new release is out. Electron apps do this
via the [autoUpdater] module, which reads from an update server feed to check if a new version
is available for download.
The update.electronjs.org service provides an updater-compatible feed. For example, Electron
Fiddle v0.28.0 will check the endpoint at https://update.electronjs.org/electron/fiddle/darwin/v0.28.0
to see if a newer GitHub release is available.
After your release is published to GitHub, the update.electronjs.org service should work
for your application. The only step left is to configure the feed with the autoUpdater module.
To make this process easier, the Electron team maintains the [`update-electron-app`] module,
which sets up the autoUpdater boilerplate for update.electronjs.org in one function
call — no configuration required. This module will search for the update.electronjs.org
feed that matches your project's package.json `"repository"` field.
First, install the module as a runtime dependency.
```sh npm2yarn
npm install update-electron-app
```
Then, import the module and call it immediately in the main process.
```js title='main.js'
require('update-electron-app')()
```
And that is all it takes! Once your application is packaged, it will update itself for each new
GitHub release that you publish.
## Summary
In this tutorial, we configured Electron Forge's GitHub Publisher to upload your app's
distributables to GitHub releases. Since distributables cannot always be generated
between platforms, we recommend setting up your building and publishing flow
in a Continuous Integration pipeline if you do not have access to machines.
Electron applications can self-update by pointing the autoUpdater module to an update server feed.
update.electronjs.org is a free update server provided by Electron for open-source applications
published on GitHub releases. Configuring your Electron app to use this service is as easy as
installing and importing the `update-electron-app` module.
If your application is not eligible for update.electronjs.org, you should instead deploy your
own update server and configure the autoUpdater module yourself.
:::info 🌟 You're done!
From here, you have officially completed our tutorial to Electron. Feel free to explore the
rest of our docs and happy developing! If you have questions, please stop by our community
[Discord server].
:::
[autoupdater]: ../api/auto-updater.md
[code-signed]: ./code-signing.md
[discord server]: https://discord.gg/electronjs
[electron fiddle]: https://electronjs.org/fiddle
[fiddle-build]: https://github.com/electron/fiddle/blob/master/.github/workflows/build.yaml
[fiddle-forge-config]: https://github.com/electron/fiddle/blob/master/forge.config.js
[github actions]: https://github.com/features/actions
[github publisher]: https://www.electronforge.io/config/publishers/github
[github releases]: https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository
[git tag]: https://git-scm.com/book/en/v2/Git-Basics-Tagging
[new-pat]: https://github.com/settings/tokens/new
[publish command]: https://www.electronforge.io/cli#publish
[publisher]: https://www.electronforge.io/config/publishers
[`publishergithubconfig`]: https://js.electronforge.io/publisher/github/interfaces/publishergithubconfig
[`update-electron-app`]: https://github.com/electron/update-electron-app
[update-server]: ./updates.md
<!-- Tutorial links -->
[prerequisites]: tutorial-1-prerequisites.md
[building your first app]: tutorial-2-first-app.md
[preload]: tutorial-3-preload.md
[features]: tutorial-4-adding-features.md
[packaging]: tutorial-5-packaging.md
[updates]: tutorial-6-publishing-updating.md

View File

@@ -1,16 +1,11 @@
---
title: 'Updating Applications'
description: "There are several ways to update an Electron application. The easiest and officially supported one is taking advantage of the built-in Squirrel framework and Electron's autoUpdater module."
slug: updates
hide_title: false
---
# Updating Applications
There are several ways to provide automatic updates to your Electron application.
The easiest and officially supported one is taking advantage of the built-in
There are several ways to update an Electron application. The easiest and
officially supported one is taking advantage of the built-in
[Squirrel](https://github.com/Squirrel) framework and
Electron's [autoUpdater](../api/auto-updater.md) module.
## Using update.electronjs.org
## Using `update.electronjs.org`
The Electron team maintains [update.electronjs.org], a free and open-source
webservice that Electron apps can use to self-update. The service is designed
@@ -18,77 +13,72 @@ for Electron apps that meet the following criteria:
- App runs on macOS or Windows
- App has a public GitHub repository
- Builds are published to [GitHub Releases][gh-releases]
- Builds are [code-signed](./code-signing.md)
- Builds are published to GitHub Releases
- Builds are code-signed
The easiest way to use this service is by installing [update-electron-app],
a Node.js module preconfigured for use with update.electronjs.org.
Install the module using your Node.js package manager of choice:
Install the module:
```sh npm2yarn
```sh
npm install update-electron-app
```
Then, invoke the updater from your app's main process file:
Invoke the updater from your app's main process file:
```js title="main.js"
```js
require('update-electron-app')()
```
By default, this module will check for updates at app startup, then every ten
minutes. When an update is found, it will automatically be downloaded in the background.
When the download completes, a dialog is displayed allowing the user to restart the app.
minutes. When an update is found, it will automatically be downloaded in the background. When the download completes, a dialog is displayed allowing the user
to restart the app.
If you need to customize your configuration, you can
[pass options to update-electron-app][update-electron-app]
[pass options to `update-electron-app`][update-electron-app]
or
[use the update service directly][update.electronjs.org].
## Using other update services
## Deploying an Update Server
If you're developing a private Electron application, or if you're not
publishing releases to GitHub Releases, it may be necessary to run your own
update server.
### Step 1: Deploying an 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 [Vercel][vercel]. It pulls from [GitHub Releases][gh-releases]
and leverages the power of GitHub's CDN.
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.
updates on disk and supports private repositories.
- [electron-release-server][electron-release-server] Provides a dashboard for
handling releases and does not require releases to originate on GitHub.
handling releases and does not require releases to originate on GitHub.
- [Nucleus][nucleus] A complete update server for Electron apps maintained by
Atlassian. Supports multiple applications and channels; uses a static file store
to minify server cost.
Atlassian. Supports multiple applications and channels; uses a static file store
to minify server cost.
Once you've deployed your update server, you can instrument your app code to receive and
apply the updates with Electron's [autoUpdater] module.
## Implementing Updates in Your App
### Step 2: Receiving updates in your app
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][hazel].
First, import the required modules in your main process code. The following code might
vary for different server software, but it works like described when using [Hazel][hazel].
**Important:** Please ensure that the code below will only be executed in
your packaged app, and not in development. You can use
[electron-is-dev](https://github.com/sindresorhus/electron-is-dev) to check for
the environment.
:::warning Check your execution environment!
Please ensure that the code below will only be executed in your packaged app, and not in development.
You can use the [app.isPackaged](../api/app.md#appispackaged-readonly) API to check the environment.
:::
```javascript title='main.js'
```javascript
const { app, autoUpdater, dialog } = require('electron')
```
Next, construct the URL of the update server feed and tell
Next, construct the URL of the update server and tell
[autoUpdater](../api/auto-updater.md) about it:
```javascript title='main.js'
```javascript
const server = 'https://your-deployment-url.com'
const url = `${server}/update/${process.platform}/${app.getVersion()}`
@@ -97,32 +87,32 @@ autoUpdater.setFeedURL({ url })
As the final step, check for updates. The example below will check every minute:
```javascript title='main.js'
```javascript
setInterval(() => {
autoUpdater.checkForUpdates()
}, 60000)
```
Once your application is [packaged](./application-distribution.md),
Once your application is [packaged](../tutorial/application-distribution.md),
it will receive an update for each new
[GitHub Release](https://help.github.com/articles/creating-releases/) that you
publish.
### Step 3: Notifying users when updates are available
## Applying Updates
Now that you've configured the basic update mechanism for your application, you
need to ensure that the user will get notified when there's an update. This
can be achieved using the [autoUpdater API events](../api/auto-updater.md#events):
can be achieved using the autoUpdater API
[events](../api/auto-updater.md#events):
```javascript title="main.js"
```javascript
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {
const dialogOpts = {
type: 'info',
buttons: ['Restart', 'Later'],
title: 'Application Update',
message: process.platform === 'win32' ? releaseNotes : releaseName,
detail:
'A new version has been downloaded. Restart the application to apply the updates.',
detail: 'A new version has been downloaded. Restart the application to apply the updates.'
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
@@ -135,22 +125,16 @@ Also make sure that errors are
[being handled](../api/auto-updater.md#event-error). Here's an example
for logging them to `stderr`:
```javascript title="main.js"
autoUpdater.on('error', (message) => {
```javascript
autoUpdater.on('error', message => {
console.error('There was a problem updating the application')
console.error(message)
})
```
:::info Handling updates manually
## Handling Updates Manually
Because the requests made by autoUpdate 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 supports the `file://` protocol, which means that with some effort, you can sidestep the
server-communication aspect of the process by loading your update from a local directory.
[Here's an example of how this could work](https://github.com/electron/electron/issues/5020#issuecomment-477636990).
:::
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).
[vercel]: https://vercel.com
[hazel]: https://github.com/vercel/hazel

View File

@@ -115,7 +115,7 @@ const win = new BrowserWindow({
})
```
On either platform `titleBarOverlay` can also be an object. On both macOS and Windows, the height of the overlay can be specified with the `height` property. On Windows, the color of the overlay and its symbols can be specified using the `color` and `symbolColor` properties respectively.
On Windows, you can also specify additional parameters. The color of the overlay and its symbols can be specified by setting `titleBarOverlay` to an object and using the `color` and `symbolColor` properties respectively. The height of the overlay can also be specified with the `height` property.
If a color option is not specified, the color will default to its system color for the window control buttons. Similarly, if the height option is not specified it will default to the default height:

View File

@@ -41,9 +41,10 @@ as quoted from [MSDN][msdn-jumplist]:
> confuse the user who does not expect that portion of the destination list to
> change.
![Taskbar JumpList](../images/windows-taskbar-jumplist.png)
![IE](https://i-msdn.sec.s-msft.com/dynimg/IC420539.png)
> NOTE: The screenshot above is an example of general tasks for Microsoft Edge
> NOTE: The screenshot above is an example of general tasks of
Internet Explorer
Unlike the dock menu in macOS which is a real menu, user tasks in Windows work
like application shortcuts. For example, when a user clicks a task, the program
@@ -108,7 +109,7 @@ As quoted from [MSDN][msdn-thumbnail]:
> For example, Windows Media Player might offer standard media transport controls
> such as play, pause, mute, and stop.
![Thumbnail toolbar](../images/windows-taskbar-thumbnail-toolbar.png)
![player](https://i-msdn.sec.s-msft.com/dynimg/IC420540.png)
> NOTE: The screenshot above is an example of thumbnail toolbar of Windows
Media Player
@@ -175,7 +176,7 @@ As quoted from [MSDN][msdn-icon-overlay]:
> network status, messenger status, or new mail. The user should not be
> presented with constantly changing overlays or animations.
![Overlay on taskbar button](../images/windows-taskbar-icon-overlay.png)
![Overlay on taskbar button](https://i-msdn.sec.s-msft.com/dynimg/IC420441.png)
> NOTE: The screenshot above is an example of overlay on a taskbar button

View File

@@ -40,7 +40,6 @@ auto_filenames = {
"docs/api/power-save-blocker.md",
"docs/api/process.md",
"docs/api/protocol.md",
"docs/api/push-notifications.md",
"docs/api/safe-storage.md",
"docs/api/screen.md",
"docs/api/service-workers.md",
@@ -213,7 +212,6 @@ auto_filenames = {
"lib/browser/api/power-monitor.ts",
"lib/browser/api/power-save-blocker.ts",
"lib/browser/api/protocol.ts",
"lib/browser/api/push-notifications.ts",
"lib/browser/api/safe-storage.ts",
"lib/browser/api/screen.ts",
"lib/browser/api/session.ts",

View File

@@ -23,7 +23,6 @@ filenames = {
lib_sources_linux = [
"shell/browser/browser_linux.cc",
"shell/browser/electron_browser_main_parts_linux.cc",
"shell/browser/lib/power_observer_linux.cc",
"shell/browser/lib/power_observer_linux.h",
"shell/browser/linux/unity_service.cc",
@@ -86,8 +85,6 @@ filenames = {
"shell/browser/ui/message_box_win.cc",
"shell/browser/ui/tray_icon_win.cc",
"shell/browser/ui/views/electron_views_delegate_win.cc",
"shell/browser/ui/views/win_icon_painter.cc",
"shell/browser/ui/views/win_icon_painter.h",
"shell/browser/ui/views/win_frame_view.cc",
"shell/browser/ui/views/win_frame_view.h",
"shell/browser/ui/views/win_caption_button.cc",
@@ -129,7 +126,6 @@ filenames = {
"shell/browser/api/electron_api_menu_mac.mm",
"shell/browser/api/electron_api_native_theme_mac.mm",
"shell/browser/api/electron_api_power_monitor_mac.mm",
"shell/browser/api/electron_api_push_notifications_mac.mm",
"shell/browser/api/electron_api_system_preferences_mac.mm",
"shell/browser/api/electron_api_web_contents_mac.mm",
"shell/browser/auto_updater_mac.mm",
@@ -171,8 +167,6 @@ filenames = {
"shell/browser/ui/cocoa/electron_native_widget_mac.mm",
"shell/browser/ui/cocoa/electron_ns_window_delegate.h",
"shell/browser/ui/cocoa/electron_ns_window_delegate.mm",
"shell/browser/ui/cocoa/electron_ns_panel.h",
"shell/browser/ui/cocoa/electron_ns_panel.mm",
"shell/browser/ui/cocoa/electron_ns_window.h",
"shell/browser/ui/cocoa/electron_ns_window.mm",
"shell/browser/ui/cocoa/electron_preview_item.h",
@@ -297,8 +291,6 @@ filenames = {
"shell/browser/api/electron_api_printing.cc",
"shell/browser/api/electron_api_protocol.cc",
"shell/browser/api/electron_api_protocol.h",
"shell/browser/api/electron_api_push_notifications.cc",
"shell/browser/api/electron_api_push_notifications.h",
"shell/browser/api/electron_api_safe_storage.cc",
"shell/browser/api/electron_api_safe_storage.h",
"shell/browser/api/electron_api_screen.cc",
@@ -416,6 +408,8 @@ filenames = {
"shell/browser/media/media_capture_devices_dispatcher.h",
"shell/browser/media/media_device_id_salt.cc",
"shell/browser/media/media_device_id_salt.h",
"shell/browser/media/media_stream_devices_controller.cc",
"shell/browser/media/media_stream_devices_controller.h",
"shell/browser/microtasks_runner.cc",
"shell/browser/microtasks_runner.h",
"shell/browser/native_browser_view.cc",
@@ -647,6 +641,8 @@ filenames = {
"shell/common/process_util.h",
"shell/common/skia_util.cc",
"shell/common/skia_util.h",
"shell/common/v8_value_converter.cc",
"shell/common/v8_value_converter.h",
"shell/common/v8_value_serializer.cc",
"shell/common/v8_value_serializer.h",
"shell/common/world_ids.h",

View File

@@ -1,495 +1,64 @@
libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/CMakeLists.txt",
"//buildtools/third_party/libc++/trunk/include/__algorithm/adjacent_find.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/algorithm_family.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/all_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/any_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/binary_search.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/clamp.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/comp.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/comp_ref_type.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/copy_backward.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/copy_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/copy_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/count.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/count_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/equal.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/equal_range.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/fill.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/fill_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/find.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/find_end.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/find_first_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/find_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/find_if_not.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/for_each.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/for_each_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/generate.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/generate_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/half_positive.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/in_found_result.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/in_fun_result.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/in_in_out_result.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/in_in_result.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/in_out_out_result.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/in_out_result.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/includes.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/inplace_merge.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/is_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/is_heap_until.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/is_partitioned.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/is_permutation.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/is_sorted.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/is_sorted_until.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/iter_swap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/iterator_operations.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/lexicographical_compare.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/lower_bound.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/make_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/make_projected.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/max.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/max_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/merge.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/min.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/min_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/min_max_result.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/minmax.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/minmax_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/mismatch.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/move.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/move_backward.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/next_permutation.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/none_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/nth_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/partial_sort.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/partial_sort_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/partition.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/partition_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/partition_point.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/pop_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/prev_permutation.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/push_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_adjacent_find.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_all_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_any_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_binary_search.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_copy_backward.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_copy_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_copy_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_count.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_count_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_equal.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_equal_range.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_fill.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_fill_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_find.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_find_end.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_find_first_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_find_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_find_if_not.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_for_each.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_for_each_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_generate.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_generate_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_includes.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_inplace_merge.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_is_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_is_heap_until.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_is_partitioned.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_is_sorted.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_is_sorted_until.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_iterator_concept.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_lexicographical_compare.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_lower_bound.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_make_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_max.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_max_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_merge.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_min.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_min_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_minmax.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_minmax_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_mismatch.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_move.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_move_backward.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_none_of.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_nth_element.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_partial_sort.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_partial_sort_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_partition.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_partition_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_partition_point.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_pop_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_push_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_remove.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_remove_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_remove_copy_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_remove_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_replace.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_replace_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_replace_copy_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_replace_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_reverse.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_reverse_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_rotate_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_search.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_search_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_set_difference.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_set_intersection.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_set_symmetric_difference.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_set_union.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_shuffle.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_sort.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_sort_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_stable_partition.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_stable_sort.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_swap_ranges.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_transform.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_unique.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_unique_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_upper_bound.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/remove.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/remove_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/remove_copy_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/remove_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/replace.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/replace_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/replace_copy_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/replace_if.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/reverse.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/reverse_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/rotate.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/rotate_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/sample.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/search.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/search_n.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/set_difference.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/set_intersection.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/set_symmetric_difference.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/set_union.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/shift_left.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/shift_right.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/shuffle.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/sift_down.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/sort.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/sort_heap.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/stable_partition.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/stable_sort.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/swap_ranges.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/transform.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/unique.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/unique_copy.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/unwrap_iter.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/unwrap_range.h",
"//buildtools/third_party/libc++/trunk/include/__algorithm/upper_bound.h",
"//buildtools/third_party/libc++/trunk/include/__assert",
"//buildtools/third_party/libc++/trunk/include/__availability",
"//buildtools/third_party/libc++/trunk/include/__bit/bit_cast.h",
"//buildtools/third_party/libc++/trunk/include/__bit/byteswap.h",
"//buildtools/third_party/libc++/trunk/include/__bit_reference",
"//buildtools/third_party/libc++/trunk/include/__bits",
"//buildtools/third_party/libc++/trunk/include/__bsd_locale_defaults.h",
"//buildtools/third_party/libc++/trunk/include/__bsd_locale_fallbacks.h",
"//buildtools/third_party/libc++/trunk/include/__charconv/chars_format.h",
"//buildtools/third_party/libc++/trunk/include/__charconv/from_chars_result.h",
"//buildtools/third_party/libc++/trunk/include/__charconv/tables.h",
"//buildtools/third_party/libc++/trunk/include/__charconv/to_chars_base_10.h",
"//buildtools/third_party/libc++/trunk/include/__charconv/to_chars_result.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/calendar.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/convert_to_timespec.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/day.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/duration.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/file_clock.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/hh_mm_ss.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/high_resolution_clock.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/literals.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/month.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/month_weekday.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/monthday.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/steady_clock.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/system_clock.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/time_point.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/weekday.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/year.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/year_month.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/year_month_day.h",
"//buildtools/third_party/libc++/trunk/include/__chrono/year_month_weekday.h",
"//buildtools/third_party/libc++/trunk/include/__compare/common_comparison_category.h",
"//buildtools/third_party/libc++/trunk/include/__compare/compare_partial_order_fallback.h",
"//buildtools/third_party/libc++/trunk/include/__compare/compare_strong_order_fallback.h",
"//buildtools/third_party/libc++/trunk/include/__compare/compare_three_way.h",
"//buildtools/third_party/libc++/trunk/include/__compare/compare_three_way_result.h",
"//buildtools/third_party/libc++/trunk/include/__compare/compare_weak_order_fallback.h",
"//buildtools/third_party/libc++/trunk/include/__compare/is_eq.h",
"//buildtools/third_party/libc++/trunk/include/__compare/ordering.h",
"//buildtools/third_party/libc++/trunk/include/__compare/partial_order.h",
"//buildtools/third_party/libc++/trunk/include/__compare/strong_order.h",
"//buildtools/third_party/libc++/trunk/include/__compare/synth_three_way.h",
"//buildtools/third_party/libc++/trunk/include/__compare/three_way_comparable.h",
"//buildtools/third_party/libc++/trunk/include/__compare/weak_order.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/arithmetic.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/assignable.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/boolean_testable.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/class_or_enum.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/common_reference_with.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/common_with.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/constructible.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/convertible_to.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/copyable.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/derived_from.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/destructible.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/different_from.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/equality_comparable.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/invocable.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/movable.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/predicate.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/regular.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/relation.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/same_as.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/semiregular.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/swappable.h",
"//buildtools/third_party/libc++/trunk/include/__concepts/totally_ordered.h",
"//buildtools/third_party/libc++/trunk/include/__config",
"//buildtools/third_party/libc++/trunk/include/__config_site.in",
"//buildtools/third_party/libc++/trunk/include/__coroutine/coroutine_handle.h",
"//buildtools/third_party/libc++/trunk/include/__coroutine/coroutine_traits.h",
"//buildtools/third_party/libc++/trunk/include/__coroutine/noop_coroutine_handle.h",
"//buildtools/third_party/libc++/trunk/include/__coroutine/trivial_awaitables.h",
"//buildtools/third_party/libc++/trunk/include/__debug",
"//buildtools/third_party/libc++/trunk/include/__debug_utils/randomize_range.h",
"//buildtools/third_party/libc++/trunk/include/__errc",
"//buildtools/third_party/libc++/trunk/include/__filesystem/copy_options.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/directory_entry.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/directory_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/directory_options.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/file_status.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/file_time_type.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/file_type.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/filesystem_error.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/operations.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/path.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/path_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/perm_options.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/perms.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/recursive_directory_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/space_info.h",
"//buildtools/third_party/libc++/trunk/include/__filesystem/u8path.h",
"//buildtools/third_party/libc++/trunk/include/__format/buffer.h",
"//buildtools/third_party/libc++/trunk/include/__format/concepts.h",
"//buildtools/third_party/libc++/trunk/include/__format/enable_insertable.h",
"//buildtools/third_party/libc++/trunk/include/__format/extended_grapheme_cluster_table.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_arg.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_arg_store.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_args.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_context.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_error.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_fwd.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_parse_context.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_string.h",
"//buildtools/third_party/libc++/trunk/include/__format/format_to_n_result.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_bool.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_char.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_floating_point.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_integer.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_integral.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_output.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__format/formatter_string.h",
"//buildtools/third_party/libc++/trunk/include/__format/parser_std_format_spec.h",
"//buildtools/third_party/libc++/trunk/include/__format/unicode.h",
"//buildtools/third_party/libc++/trunk/include/__functional/binary_function.h",
"//buildtools/third_party/libc++/trunk/include/__functional/binary_negate.h",
"//buildtools/third_party/libc++/trunk/include/__functional/bind.h",
"//buildtools/third_party/libc++/trunk/include/__functional/bind_back.h",
"//buildtools/third_party/libc++/trunk/include/__functional/bind_front.h",
"//buildtools/third_party/libc++/trunk/include/__functional/binder1st.h",
"//buildtools/third_party/libc++/trunk/include/__functional/binder2nd.h",
"//buildtools/third_party/libc++/trunk/include/__functional/boyer_moore_searcher.h",
"//buildtools/third_party/libc++/trunk/include/__functional/compose.h",
"//buildtools/third_party/libc++/trunk/include/__functional/default_searcher.h",
"//buildtools/third_party/libc++/trunk/include/__functional/function.h",
"//buildtools/third_party/libc++/trunk/include/__functional/hash.h",
"//buildtools/third_party/libc++/trunk/include/__functional/identity.h",
"//buildtools/third_party/libc++/trunk/include/__functional/invoke.h",
"//buildtools/third_party/libc++/trunk/include/__functional/is_transparent.h",
"//buildtools/third_party/libc++/trunk/include/__functional/mem_fn.h",
"//buildtools/third_party/libc++/trunk/include/__functional/mem_fun_ref.h",
"//buildtools/third_party/libc++/trunk/include/__functional/not_fn.h",
"//buildtools/third_party/libc++/trunk/include/__functional/operations.h",
"//buildtools/third_party/libc++/trunk/include/__functional/perfect_forward.h",
"//buildtools/third_party/libc++/trunk/include/__functional/pointer_to_binary_function.h",
"//buildtools/third_party/libc++/trunk/include/__functional/pointer_to_unary_function.h",
"//buildtools/third_party/libc++/trunk/include/__functional/ranges_operations.h",
"//buildtools/third_party/libc++/trunk/include/__functional/reference_wrapper.h",
"//buildtools/third_party/libc++/trunk/include/__functional/unary_function.h",
"//buildtools/third_party/libc++/trunk/include/__functional/unary_negate.h",
"//buildtools/third_party/libc++/trunk/include/__functional/unwrap_ref.h",
"//buildtools/third_party/libc++/trunk/include/__functional/weak_result_type.h",
"//buildtools/third_party/libc++/trunk/include/__fwd/span.h",
"//buildtools/third_party/libc++/trunk/include/__fwd/string_view.h",
"//buildtools/third_party/libc++/trunk/include/__functional_03",
"//buildtools/third_party/libc++/trunk/include/__functional_base",
"//buildtools/third_party/libc++/trunk/include/__functional_base_03",
"//buildtools/third_party/libc++/trunk/include/__hash_table",
"//buildtools/third_party/libc++/trunk/include/__ios/fpos.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/access.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/advance.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/back_insert_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/bounded_iter.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/common_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/concepts.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/counted_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/data.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/default_sentinel.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/distance.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/empty.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/erase_if_container.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/front_insert_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/incrementable_traits.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/indirectly_comparable.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/insert_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/istream_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/istreambuf_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/iter_move.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/iter_swap.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/iterator_traits.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/mergeable.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/move_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/move_sentinel.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/next.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/ostream_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/ostreambuf_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/permutable.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/prev.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/projected.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/readable_traits.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/reverse_access.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/reverse_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/size.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/sortable.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/unreachable_sentinel.h",
"//buildtools/third_party/libc++/trunk/include/__iterator/wrap_iter.h",
"//buildtools/third_party/libc++/trunk/include/__libcpp_version",
"//buildtools/third_party/libc++/trunk/include/__locale",
"//buildtools/third_party/libc++/trunk/include/__mbstate_t.h",
"//buildtools/third_party/libc++/trunk/include/__memory/addressof.h",
"//buildtools/third_party/libc++/trunk/include/__memory/allocate_at_least.h",
"//buildtools/third_party/libc++/trunk/include/__memory/allocation_guard.h",
"//buildtools/third_party/libc++/trunk/include/__memory/allocator.h",
"//buildtools/third_party/libc++/trunk/include/__memory/allocator_arg_t.h",
"//buildtools/third_party/libc++/trunk/include/__memory/allocator_traits.h",
"//buildtools/third_party/libc++/trunk/include/__memory/assume_aligned.h",
"//buildtools/third_party/libc++/trunk/include/__memory/auto_ptr.h",
"//buildtools/third_party/libc++/trunk/include/__memory/compressed_pair.h",
"//buildtools/third_party/libc++/trunk/include/__memory/concepts.h",
"//buildtools/third_party/libc++/trunk/include/__memory/construct_at.h",
"//buildtools/third_party/libc++/trunk/include/__memory/pointer_safety.h",
"//buildtools/third_party/libc++/trunk/include/__memory/pointer_traits.h",
"//buildtools/third_party/libc++/trunk/include/__memory/ranges_construct_at.h",
"//buildtools/third_party/libc++/trunk/include/__memory/ranges_uninitialized_algorithms.h",
"//buildtools/third_party/libc++/trunk/include/__memory/raw_storage_iterator.h",
"//buildtools/third_party/libc++/trunk/include/__memory/shared_ptr.h",
"//buildtools/third_party/libc++/trunk/include/__memory/swap_allocator.h",
"//buildtools/third_party/libc++/trunk/include/__memory/temporary_buffer.h",
"//buildtools/third_party/libc++/trunk/include/__memory/uninitialized_algorithms.h",
"//buildtools/third_party/libc++/trunk/include/__memory/unique_ptr.h",
"//buildtools/third_party/libc++/trunk/include/__memory/uses_allocator.h",
"//buildtools/third_party/libc++/trunk/include/__memory/voidify.h",
"//buildtools/third_party/libc++/trunk/include/__mutex_base",
"//buildtools/third_party/libc++/trunk/include/__node_handle",
"//buildtools/third_party/libc++/trunk/include/__numeric/accumulate.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/adjacent_difference.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/exclusive_scan.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/gcd_lcm.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/inclusive_scan.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/inner_product.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/iota.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/midpoint.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/partial_sum.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/reduce.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/transform_exclusive_scan.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/transform_inclusive_scan.h",
"//buildtools/third_party/libc++/trunk/include/__numeric/transform_reduce.h",
"//buildtools/third_party/libc++/trunk/include/__random/bernoulli_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/binomial_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/cauchy_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/chi_squared_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/clamp_to_integral.h",
"//buildtools/third_party/libc++/trunk/include/__random/default_random_engine.h",
"//buildtools/third_party/libc++/trunk/include/__random/discard_block_engine.h",
"//buildtools/third_party/libc++/trunk/include/__random/discrete_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/exponential_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/extreme_value_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/fisher_f_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/gamma_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/generate_canonical.h",
"//buildtools/third_party/libc++/trunk/include/__random/geometric_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/independent_bits_engine.h",
"//buildtools/third_party/libc++/trunk/include/__random/is_seed_sequence.h",
"//buildtools/third_party/libc++/trunk/include/__random/is_valid.h",
"//buildtools/third_party/libc++/trunk/include/__random/knuth_b.h",
"//buildtools/third_party/libc++/trunk/include/__random/linear_congruential_engine.h",
"//buildtools/third_party/libc++/trunk/include/__random/log2.h",
"//buildtools/third_party/libc++/trunk/include/__random/lognormal_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/mersenne_twister_engine.h",
"//buildtools/third_party/libc++/trunk/include/__random/negative_binomial_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/normal_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/piecewise_constant_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/piecewise_linear_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/poisson_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/random_device.h",
"//buildtools/third_party/libc++/trunk/include/__random/ranlux.h",
"//buildtools/third_party/libc++/trunk/include/__random/seed_seq.h",
"//buildtools/third_party/libc++/trunk/include/__random/shuffle_order_engine.h",
"//buildtools/third_party/libc++/trunk/include/__random/student_t_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/subtract_with_carry_engine.h",
"//buildtools/third_party/libc++/trunk/include/__random/uniform_int_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/uniform_random_bit_generator.h",
"//buildtools/third_party/libc++/trunk/include/__random/uniform_real_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__random/weibull_distribution.h",
"//buildtools/third_party/libc++/trunk/include/__nullptr",
"//buildtools/third_party/libc++/trunk/include/__ranges/access.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/all.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/common_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/concepts.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/copyable_box.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/counted.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/dangling.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/data.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/drop_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/empty.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/empty_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/enable_borrowed_range.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/enable_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/filter_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/iota_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/join_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/lazy_split_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/non_propagating_cache.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/owning_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/range_adaptor.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/rbegin.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/ref_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/rend.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/reverse_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/single_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/size.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/subrange.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/take_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/transform_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/view_interface.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/views.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/zip_view.h",
"//buildtools/third_party/libc++/trunk/include/__ranges/view.h",
"//buildtools/third_party/libc++/trunk/include/__split_buffer",
"//buildtools/third_party/libc++/trunk/include/__std_stream",
"//buildtools/third_party/libc++/trunk/include/__string/char_traits.h",
"//buildtools/third_party/libc++/trunk/include/__string/extern_template_lists.h",
"//buildtools/third_party/libc++/trunk/include/__string",
"//buildtools/third_party/libc++/trunk/include/__support/android/locale_bionic.h",
"//buildtools/third_party/libc++/trunk/include/__support/fuchsia/xlocale.h",
"//buildtools/third_party/libc++/trunk/include/__support/ibm/gettod_zos.h",
"//buildtools/third_party/libc++/trunk/include/__support/ibm/limits.h",
"//buildtools/third_party/libc++/trunk/include/__support/ibm/locale_mgmt_aix.h",
"//buildtools/third_party/libc++/trunk/include/__support/ibm/locale_mgmt_zos.h",
"//buildtools/third_party/libc++/trunk/include/__support/ibm/nanosleep.h",
"//buildtools/third_party/libc++/trunk/include/__support/ibm/support.h",
"//buildtools/third_party/libc++/trunk/include/__support/ibm/xlocale.h",
"//buildtools/third_party/libc++/trunk/include/__support/musl/xlocale.h",
"//buildtools/third_party/libc++/trunk/include/__support/newlib/xlocale.h",
"//buildtools/third_party/libc++/trunk/include/__support/nuttx/xlocale.h",
"//buildtools/third_party/libc++/trunk/include/__support/openbsd/xlocale.h",
"//buildtools/third_party/libc++/trunk/include/__support/solaris/floatingpoint.h",
"//buildtools/third_party/libc++/trunk/include/__support/solaris/wchar.h",
@@ -499,146 +68,11 @@ libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/__support/xlocale/__nop_locale_mgmt.h",
"//buildtools/third_party/libc++/trunk/include/__support/xlocale/__posix_l_fallback.h",
"//buildtools/third_party/libc++/trunk/include/__support/xlocale/__strtonum_fallback.h",
"//buildtools/third_party/libc++/trunk/include/__thread/poll_with_backoff.h",
"//buildtools/third_party/libc++/trunk/include/__thread/timed_backoff_policy.h",
"//buildtools/third_party/libc++/trunk/include/__threading_support",
"//buildtools/third_party/libc++/trunk/include/__tree",
"//buildtools/third_party/libc++/trunk/include/__tuple",
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_const.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_cv.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_lvalue_reference.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_rvalue_reference.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/add_volatile.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/aligned_storage.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/aligned_union.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/alignment_of.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/apply_cv.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/common_reference.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/common_type.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/conditional.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/conjunction.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/copy_cv.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/copy_cvref.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/decay.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/disjunction.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/enable_if.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/extent.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/has_unique_object_representation.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/has_virtual_destructor.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/integral_constant.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_abstract.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_aggregate.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_arithmetic.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_array.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_base_of.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_bounded_array.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_callable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_class.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_compound.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_const.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_constant_evaluated.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_convertible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_copy_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_copy_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_core_convertible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_default_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_destructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_empty.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_enum.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_final.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_floating_point.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_function.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_fundamental.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_integral.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_literal_type.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_member_function_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_member_object_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_member_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_move_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_move_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_convertible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_copy_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_copy_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_default_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_destructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_move_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_nothrow_move_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_null_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_object.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_pod.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_polymorphic.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_primary_template.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_reference.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_reference_wrapper.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_referenceable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_same.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_scalar.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_scoped_enum.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_signed.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_signed_integer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_standard_layout.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivial.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_copy_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_copy_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_copyable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_default_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_destructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_move_assignable.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_trivially_move_constructible.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_unbounded_array.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_union.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_unsigned.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_unsigned_integer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_valid_expansion.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_void.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/is_volatile.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/lazy.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/make_32_64_or_128_bit.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/make_signed.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/make_unsigned.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/nat.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/negation.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/promote.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/rank.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_all_extents.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_const.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_cv.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_cvref.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_extent.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_pointer.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_reference.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/remove_volatile.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/type_identity.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/type_list.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/underlying_type.h",
"//buildtools/third_party/libc++/trunk/include/__type_traits/void_t.h",
"//buildtools/third_party/libc++/trunk/include/__undef_macros",
"//buildtools/third_party/libc++/trunk/include/__utility/as_const.h",
"//buildtools/third_party/libc++/trunk/include/__utility/auto_cast.h",
"//buildtools/third_party/libc++/trunk/include/__utility/cmp.h",
"//buildtools/third_party/libc++/trunk/include/__utility/declval.h",
"//buildtools/third_party/libc++/trunk/include/__utility/exchange.h",
"//buildtools/third_party/libc++/trunk/include/__utility/forward.h",
"//buildtools/third_party/libc++/trunk/include/__utility/in_place.h",
"//buildtools/third_party/libc++/trunk/include/__utility/integer_sequence.h",
"//buildtools/third_party/libc++/trunk/include/__utility/move.h",
"//buildtools/third_party/libc++/trunk/include/__utility/pair.h",
"//buildtools/third_party/libc++/trunk/include/__utility/piecewise_construct.h",
"//buildtools/third_party/libc++/trunk/include/__utility/priority_tag.h",
"//buildtools/third_party/libc++/trunk/include/__utility/rel_ops.h",
"//buildtools/third_party/libc++/trunk/include/__utility/swap.h",
"//buildtools/third_party/libc++/trunk/include/__utility/to_underlying.h",
"//buildtools/third_party/libc++/trunk/include/__utility/transaction.h",
"//buildtools/third_party/libc++/trunk/include/__utility/unreachable.h",
"//buildtools/third_party/libc++/trunk/include/__variant/monostate.h",
"//buildtools/third_party/libc++/trunk/include/algorithm",
"//buildtools/third_party/libc++/trunk/include/any",
"//buildtools/third_party/libc++/trunk/include/array",
@@ -665,7 +99,6 @@ libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/complex.h",
"//buildtools/third_party/libc++/trunk/include/concepts",
"//buildtools/third_party/libc++/trunk/include/condition_variable",
"//buildtools/third_party/libc++/trunk/include/coroutine",
"//buildtools/third_party/libc++/trunk/include/csetjmp",
"//buildtools/third_party/libc++/trunk/include/csignal",
"//buildtools/third_party/libc++/trunk/include/cstdarg",
@@ -678,7 +111,6 @@ libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/ctgmath",
"//buildtools/third_party/libc++/trunk/include/ctime",
"//buildtools/third_party/libc++/trunk/include/ctype.h",
"//buildtools/third_party/libc++/trunk/include/cuchar",
"//buildtools/third_party/libc++/trunk/include/cwchar",
"//buildtools/third_party/libc++/trunk/include/cwctype",
"//buildtools/third_party/libc++/trunk/include/deque",
@@ -690,6 +122,7 @@ libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/experimental/algorithm",
"//buildtools/third_party/libc++/trunk/include/experimental/coroutine",
"//buildtools/third_party/libc++/trunk/include/experimental/deque",
"//buildtools/third_party/libc++/trunk/include/experimental/filesystem",
"//buildtools/third_party/libc++/trunk/include/experimental/forward_list",
"//buildtools/third_party/libc++/trunk/include/experimental/functional",
"//buildtools/third_party/libc++/trunk/include/experimental/iterator",
@@ -734,7 +167,7 @@ libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/map",
"//buildtools/third_party/libc++/trunk/include/math.h",
"//buildtools/third_party/libc++/trunk/include/memory",
"//buildtools/third_party/libc++/trunk/include/module.modulemap.in",
"//buildtools/third_party/libc++/trunk/include/module.modulemap",
"//buildtools/third_party/libc++/trunk/include/mutex",
"//buildtools/third_party/libc++/trunk/include/new",
"//buildtools/third_party/libc++/trunk/include/numbers",
@@ -754,7 +187,6 @@ libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/span",
"//buildtools/third_party/libc++/trunk/include/sstream",
"//buildtools/third_party/libc++/trunk/include/stack",
"//buildtools/third_party/libc++/trunk/include/stdatomic.h",
"//buildtools/third_party/libc++/trunk/include/stdbool.h",
"//buildtools/third_party/libc++/trunk/include/stddef.h",
"//buildtools/third_party/libc++/trunk/include/stdexcept",
@@ -773,7 +205,6 @@ libcxx_headers = [
"//buildtools/third_party/libc++/trunk/include/type_traits",
"//buildtools/third_party/libc++/trunk/include/typeindex",
"//buildtools/third_party/libc++/trunk/include/typeinfo",
"//buildtools/third_party/libc++/trunk/include/uchar.h",
"//buildtools/third_party/libc++/trunk/include/unordered_map",
"//buildtools/third_party/libc++/trunk/include/unordered_set",
"//buildtools/third_party/libc++/trunk/include/utility",

View File

@@ -20,7 +20,7 @@ const spawnUpdate = function (args: string[], detached: boolean, callback: Funct
try {
// Ensure we don't spawn multiple squirrel processes
// Process spawned, same args: Attach events to already running process
// Process spawned, same args: Attach events to alread running process
// Process spawned, different args: Return with error
// No process spawned: Spawn new process
if (spawnedProcess && !isSameArgs(args)) {

View File

@@ -2,4 +2,7 @@ import { IpcMainImpl } from '@electron/internal/browser/ipc-main-impl';
const ipcMain = new IpcMainImpl();
// Do not throw exception when channel name is "error".
ipcMain.on('error', () => {});
export default ipcMain;

View File

@@ -142,7 +142,7 @@ Menu.prototype.insert = function (pos, item) {
if (item.icon) this.setIcon(pos, item.icon);
if (item.role) this.setRole(pos, item.role);
// Make menu accessible to items.
// Make menu accessable to items.
item.overrideReadOnlyProperty('menu', this);
// Remember the items.

View File

@@ -22,7 +22,6 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'Notification', loader: () => require('./notification') },
{ name: 'powerMonitor', loader: () => require('./power-monitor') },
{ name: 'powerSaveBlocker', loader: () => require('./power-save-blocker') },
{ name: 'pushNotifications', loader: () => require('./push-notifications') },
{ name: 'protocol', loader: () => require('./protocol') },
{ name: 'safeStorage', loader: () => require('./safe-storage') },
{ name: 'screen', loader: () => require('./screen') },

View File

@@ -1,3 +1,3 @@
const { nativeTheme } = process._linkedBinding('electron_browser_native_theme');
const { nativeTheme } = process._linkedBinding('electron_common_native_theme');
module.exports = nativeTheme;

View File

@@ -1,7 +1,7 @@
const {
Notification: ElectronNotification,
isSupported
} = process._linkedBinding('electron_browser_notification');
} = process._linkedBinding('electron_common_notification');
ElectronNotification.isSupported = isSupported;

View File

@@ -1,3 +0,0 @@
const { pushNotifications } = process._linkedBinding('electron_browser_push_notifications');
export default pushNotifications;

View File

@@ -1,6 +1,6 @@
import { EventEmitter } from 'events';
const { createScreen } = process._linkedBinding('electron_browser_screen');
const { createScreen } = process._linkedBinding('electron_common_screen');
let _screen: Electron.Screen;

View File

@@ -9,15 +9,12 @@ import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
import { IpcMainImpl } from '@electron/internal/browser/ipc-main-impl';
// session is not used here, the purpose is to make sure session is initialized
// session is not used here, the purpose is to make sure session is initalized
// before the webContents module.
// eslint-disable-next-line
session
const webFrameMainBinding = process._linkedBinding('electron_browser_web_frame_main');
let nextId = 0;
const getNextId = function () {
return ++nextId;
@@ -66,20 +63,6 @@ const PDFPageSizes: Record<string, ElectronInternal.MediaSize> = {
}
} as const;
const paperFormats: Record<string, ElectronInternal.PageSize> = {
letter: { width: 8.5, height: 11 },
legal: { width: 8.5, height: 14 },
tabloid: { width: 11, height: 17 },
ledger: { width: 17, height: 11 },
a0: { width: 33.1, height: 46.8 },
a1: { width: 23.4, height: 33.1 },
a2: { width: 16.54, height: 23.4 },
a3: { width: 11.7, height: 16.54 },
a4: { width: 8.27, height: 11.7 },
a5: { width: 5.83, height: 8.27 },
a6: { width: 4.13, height: 5.83 }
} as const;
// The minimum micron size Chromium accepts is that where:
// Per printing/units.h:
// * kMicronsPerInch - Length of an inch in 0.001mm unit.
@@ -93,6 +76,42 @@ const isValidCustomPageSize = (width: number, height: number) => {
return [width, height].every(x => x > 352);
};
// Default printing setting
const defaultPrintingSetting = {
// Customizable.
pageRange: [] as {from: number, to: number}[],
mediaSize: {} as ElectronInternal.MediaSize,
landscape: false,
headerFooterEnabled: false,
marginsType: 0,
scaleFactor: 100,
shouldPrintBackgrounds: false,
shouldPrintSelectionOnly: false,
// Non-customizable.
printWithCloudPrint: false,
printWithPrivet: false,
printWithExtension: false,
pagesPerSheet: 1,
isFirstRequest: false,
previewUIID: 0,
// True, if the document source is modifiable. e.g. HTML and not PDF.
previewModifiable: true,
printToPDF: true,
deviceName: 'Save as PDF',
generateDraftData: true,
dpiHorizontal: 72,
dpiVertical: 72,
rasterizePDF: false,
duplex: 0,
copies: 1,
// 2 = color - see ColorModel in //printing/print_job_constants.h
color: 2,
collate: true,
printerType: 2,
title: undefined as string | undefined,
url: undefined as string | undefined
} as const;
// JavaScript implementations of WebContents.
const binding = process._linkedBinding('electron_browser_web_contents');
const printing = process._linkedBinding('electron_browser_printing');
@@ -127,6 +146,13 @@ WebContents.prototype.sendToFrame = function (frameId, channel, ...args) {
return true;
};
WebContents.prototype._sendToFrameInternal = function (frameId, channel, ...args) {
const frame = getWebFrame(this, frameId);
if (!frame) return false;
frame._sendInternal(channel, ...args);
return true;
};
// Following methods are mapped to webFrame.
const webFrameMethods = [
'insertCSS',
@@ -167,136 +193,136 @@ WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (worldId
let pendingPromise: Promise<any> | undefined;
WebContents.prototype.printToPDF = async function (options) {
const printSettings: Record<string, any> = {
requestID: getNextId(),
landscape: false,
displayHeaderFooter: false,
headerTemplate: '',
footerTemplate: '',
printBackground: false,
scale: 1,
paperWidth: 8.5,
paperHeight: 11,
marginTop: 0,
marginBottom: 0,
marginLeft: 0,
marginRight: 0,
pageRanges: '',
preferCSSPageSize: false
...defaultPrintingSetting,
requestID: getNextId()
};
if (options.landscape !== undefined) {
if (typeof options.landscape !== 'boolean') {
return Promise.reject(new Error('landscape must be a Boolean'));
const error = new Error('landscape must be a Boolean');
return Promise.reject(error);
}
printSettings.landscape = options.landscape;
}
if (options.displayHeaderFooter !== undefined) {
if (typeof options.displayHeaderFooter !== 'boolean') {
return Promise.reject(new Error('displayHeaderFooter must be a Boolean'));
if (options.scaleFactor !== undefined) {
if (typeof options.scaleFactor !== 'number') {
const error = new Error('scaleFactor must be a Number');
return Promise.reject(error);
}
printSettings.displayHeaderFooter = options.displayHeaderFooter;
printSettings.scaleFactor = options.scaleFactor;
}
if (options.marginsType !== undefined) {
if (typeof options.marginsType !== 'number') {
const error = new Error('marginsType must be a Number');
return Promise.reject(error);
}
printSettings.marginsType = options.marginsType;
}
if (options.printSelectionOnly !== undefined) {
if (typeof options.printSelectionOnly !== 'boolean') {
const error = new Error('printSelectionOnly must be a Boolean');
return Promise.reject(error);
}
printSettings.shouldPrintSelectionOnly = options.printSelectionOnly;
}
if (options.printBackground !== undefined) {
if (typeof options.printBackground !== 'boolean') {
return Promise.reject(new Error('printBackground must be a Boolean'));
const error = new Error('printBackground must be a Boolean');
return Promise.reject(error);
}
printSettings.shouldPrintBackgrounds = options.printBackground;
}
if (options.scale !== undefined) {
if (typeof options.scale !== 'number') {
return Promise.reject(new Error('scale must be a Number'));
}
printSettings.scaleFactor = options.scale;
}
const { pageSize } = options;
if (pageSize !== undefined) {
if (typeof pageSize === 'string') {
const format = paperFormats[pageSize.toLowerCase()];
if (!format) {
return Promise.reject(new Error(`Invalid pageSize ${pageSize}`));
}
printSettings.paperWidth = format.width;
printSettings.paperHeight = format.height;
} else if (typeof options.pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
return Promise.reject(new Error('height and width properties are required for pageSize'));
}
printSettings.paperWidth = pageSize.width;
printSettings.paperHeight = pageSize.height;
} else {
return Promise.reject(new Error('pageSize must be a String or Object'));
}
}
const { margins } = options;
if (margins !== undefined) {
if (typeof margins !== 'object') {
return Promise.reject(new Error('margins must be an Object'));
}
if (margins.top !== undefined) {
if (typeof margins.top !== 'number') {
return Promise.reject(new Error('margins.top must be a Number'));
}
printSettings.marginTop = margins.top;
}
if (margins.bottom !== undefined) {
if (typeof margins.bottom !== 'number') {
return Promise.reject(new Error('margins.bottom must be a Number'));
}
printSettings.marginBottom = margins.bottom;
}
if (margins.left !== undefined) {
if (typeof margins.left !== 'number') {
return Promise.reject(new Error('margins.left must be a Number'));
}
printSettings.marginLeft = margins.left;
}
if (margins.right !== undefined) {
if (typeof margins.right !== 'number') {
return Promise.reject(new Error('margins.right must be a Number'));
}
printSettings.marginRight = margins.right;
}
}
if (options.pageRanges !== undefined) {
if (typeof options.pageRanges !== 'string') {
return Promise.reject(new Error('printBackground must be a String'));
const pageRanges = options.pageRanges;
if (!Object.prototype.hasOwnProperty.call(pageRanges, 'from') || !Object.prototype.hasOwnProperty.call(pageRanges, 'to')) {
const error = new Error('pageRanges must be an Object with \'from\' and \'to\' properties');
return Promise.reject(error);
}
printSettings.pageRanges = options.pageRanges;
if (typeof pageRanges.from !== 'number') {
const error = new Error('pageRanges.from must be a Number');
return Promise.reject(error);
}
if (typeof pageRanges.to !== 'number') {
const error = new Error('pageRanges.to must be a Number');
return Promise.reject(error);
}
// Chromium uses 1-based page ranges, so increment each by 1.
printSettings.pageRange = [{
from: pageRanges.from + 1,
to: pageRanges.to + 1
}];
}
if (options.headerTemplate !== undefined) {
if (typeof options.headerTemplate !== 'string') {
return Promise.reject(new Error('headerTemplate must be a String'));
if (options.headerFooter !== undefined) {
const headerFooter = options.headerFooter;
printSettings.headerFooterEnabled = true;
if (typeof headerFooter === 'object') {
if (!headerFooter.url || !headerFooter.title) {
const error = new Error('url and title properties are required for headerFooter');
return Promise.reject(error);
}
if (typeof headerFooter.title !== 'string') {
const error = new Error('headerFooter.title must be a String');
return Promise.reject(error);
}
printSettings.title = headerFooter.title;
if (typeof headerFooter.url !== 'string') {
const error = new Error('headerFooter.url must be a String');
return Promise.reject(error);
}
printSettings.url = headerFooter.url;
} else {
const error = new Error('headerFooter must be an Object');
return Promise.reject(error);
}
printSettings.headerTemplate = options.headerTemplate;
}
if (options.footerTemplate !== undefined) {
if (typeof options.footerTemplate !== 'string') {
return Promise.reject(new Error('footerTemplate must be a String'));
// Optionally set size for PDF.
if (options.pageSize !== undefined) {
const pageSize = options.pageSize;
if (typeof pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
const error = new Error('height and width properties are required for pageSize');
return Promise.reject(error);
}
// Dimensions in Microns - 1 meter = 10^6 microns
const height = Math.ceil(pageSize.height);
const width = Math.ceil(pageSize.width);
if (!isValidCustomPageSize(width, height)) {
const error = new Error('height and width properties must be minimum 352 microns.');
return Promise.reject(error);
}
printSettings.mediaSize = {
name: 'CUSTOM',
custom_display_name: 'Custom',
height_microns: height,
width_microns: width
};
} else if (Object.prototype.hasOwnProperty.call(PDFPageSizes, pageSize)) {
printSettings.mediaSize = PDFPageSizes[pageSize];
} else {
const error = new Error(`Unsupported pageSize: ${pageSize}`);
return Promise.reject(error);
}
printSettings.footerTemplate = options.footerTemplate;
}
if (options.preferCSSPageSize !== undefined) {
if (typeof options.preferCSSPageSize !== 'boolean') {
return Promise.reject(new Error('footerTemplate must be a String'));
}
printSettings.preferCSSPageSize = options.preferCSSPageSize;
} else {
printSettings.mediaSize = PDFPageSizes.A4;
}
// Chromium expects this in a 0-100 range number, not as float
printSettings.scaleFactor = Math.ceil(printSettings.scaleFactor) % 100;
// PrinterType enum from //printing/print_job_constants.h
printSettings.printerType = 2;
if (this._printToPDF) {
if (pendingPromise) {
pendingPromise = pendingPromise.then(() => this._printToPDF(printSettings));
@@ -559,12 +585,6 @@ WebContents.prototype._init = function () {
this._windowOpenHandler = null;
const ipc = new IpcMainImpl();
Object.defineProperty(this, 'ipc', {
get () { return ipc; },
enumerable: true
});
// Dispatch IPC messages to the ipc module.
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
addSenderFrameToEvent(event);
@@ -573,9 +593,6 @@ WebContents.prototype._init = function () {
} else {
addReplyToEvent(event);
this.emit('ipc-message', event, channel, ...args);
const maybeWebFrame = webFrameMainBinding.fromIdOrNull(event.processId, event.frameId);
maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, ...args);
ipc.emit(channel, event, ...args);
ipcMain.emit(channel, event, ...args);
}
});
@@ -587,10 +604,8 @@ WebContents.prototype._init = function () {
console.error(`Error occurred in handler for '${channel}':`, error);
event.sendReply({ error: error.toString() });
};
const maybeWebFrame = webFrameMainBinding.fromIdOrNull(event.processId, event.frameId);
const targets: (ElectronInternal.IpcMainInternal| undefined)[] = internal ? [ipcMainInternal] : [maybeWebFrame && maybeWebFrame.ipc, ipc, ipcMain];
const target = targets.find(target => target && (target as any)._invokeHandlers.has(channel));
if (target) {
const target = internal ? ipcMainInternal : ipcMain;
if ((target as any)._invokeHandlers.has(channel)) {
(target as any)._invokeHandlers.get(channel)(event, ...args);
} else {
event._throw(`No handler registered for '${channel}'`);
@@ -604,13 +619,10 @@ WebContents.prototype._init = function () {
ipcMainInternal.emit(channel, event, ...args);
} else {
addReplyToEvent(event);
const maybeWebFrame = webFrameMainBinding.fromIdOrNull(event.processId, event.frameId);
if (this.listenerCount('ipc-message-sync') === 0 && ipc.listenerCount(channel) === 0 && ipcMain.listenerCount(channel) === 0 && (!maybeWebFrame || maybeWebFrame.ipc.listenerCount(channel) === 0)) {
if (this.listenerCount('ipc-message-sync') === 0 && ipcMain.listenerCount(channel) === 0) {
console.warn(`WebContents #${this.id} called ipcRenderer.sendSync() with '${channel}' channel without listeners.`);
}
this.emit('ipc-message-sync', event, channel, ...args);
maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, ...args);
ipc.emit(channel, event, ...args);
ipcMain.emit(channel, event, ...args);
}
});
@@ -618,9 +630,6 @@ WebContents.prototype._init = function () {
this.on('-ipc-ports' as any, function (event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) {
addSenderFrameToEvent(event);
event.ports = ports.map(p => new MessagePortMain(p));
const maybeWebFrame = webFrameMainBinding.fromIdOrNull(event.processId, event.frameId);
maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, message);
ipc.emit(channel, event, message);
ipcMain.emit(channel, event, message);
});
@@ -659,7 +668,7 @@ WebContents.prototype._init = function () {
disposition
};
let result: ReturnType<typeof this._callWindowOpenHandler>;
let result;
try {
result = this._callWindowOpenHandler(event, details);
} catch (err) {
@@ -698,7 +707,7 @@ WebContents.prototype._init = function () {
postBody
};
let result: ReturnType<typeof this._callWindowOpenHandler>;
let result;
try {
result = this._callWindowOpenHandler(event, details);
} catch (err) {

View File

@@ -1,16 +1,7 @@
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
import { IpcMainImpl } from '@electron/internal/browser/ipc-main-impl';
const { WebFrameMain, fromId } = process._linkedBinding('electron_browser_web_frame_main');
Object.defineProperty(WebFrameMain.prototype, 'ipc', {
get () {
const ipc = new IpcMainImpl();
Object.defineProperty(this, 'ipc', { value: ipc });
return ipc;
}
});
WebFrameMain.prototype.send = function (channel, ...args) {
if (typeof channel !== 'string') {
throw new Error('Missing required channel argument');

View File

@@ -31,7 +31,7 @@ export const setDefaultApplicationMenu = () => {
{
label: 'Community Discussions',
click: async () => {
await shell.openExternal('https://discord.gg/electronjs');
await shell.openExternal('https://discord.com/invite/APGC3k5yaH');
}
},
{

View File

@@ -7,7 +7,7 @@ import { webViewEvents } from '@electron/internal/browser/web-view-events';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
interface GuestInstance {
elementInstanceId: number;
elementInstanceId?: number;
visibilityState?: VisibilityState;
embedder: Electron.WebContents;
guest: Electron.WebContents;
@@ -46,7 +46,6 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record<stri
webSecurity: !params.disablewebsecurity,
enableBlinkFeatures: params.blinkfeatures,
disableBlinkFeatures: params.disableblinkfeatures,
partition: params.partition,
...parsedWebPreferences
};
@@ -88,26 +87,14 @@ function makeLoadURLOptions (params: Record<string, any>) {
// Create a new guest instance.
const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record<string, any>) {
const webPreferences = makeWebPreferences(embedder, params);
const event = eventBinding.createWithSender(embedder);
const { instanceId } = params;
embedder.emit('will-attach-webview', event, webPreferences, params);
if (event.defaultPrevented) {
return -1;
}
// eslint-disable-next-line no-undef
const guest = (webContents as typeof ElectronInternal.WebContents).create({
...webPreferences,
type: 'webview',
partition: params.partition,
embedder
});
const guestInstanceId = guest.id;
guestInstances.set(guestInstanceId, {
elementInstanceId,
guest,
embedder
});
@@ -121,8 +108,11 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
// Init guest web view after attached.
guest.once('did-attach' as any, function (this: Electron.WebContents, event: Electron.Event) {
const params = this.attachParams!;
delete this.attachParams;
const previouslyAttached = this.viewInstanceId != null;
this.viewInstanceId = instanceId;
this.viewInstanceId = params.instanceId;
// Only load URL and set size on first attach
if (previouslyAttached) {
@@ -130,7 +120,7 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
}
if (params.src) {
this.loadURL(params.src, makeLoadURLOptions(params));
this.loadURL(params.src, params.opts);
}
embedder.emit('did-attach-webview', event, guest);
});
@@ -183,25 +173,78 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
}
});
if (attachGuest(embedder, embedderFrameId, elementInstanceId, guestInstanceId, params)) {
return guestInstanceId;
}
return -1;
};
// Attach the guest to an element of embedder.
const attachGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, guestInstanceId: number, params: Record<string, any>) {
// Destroy the old guest when attaching.
const key = `${embedder.id}-${elementInstanceId}`;
const oldGuestInstanceId = embedderElementsMap.get(key);
if (oldGuestInstanceId != null) {
// Reattachment to the same guest is just a no-op.
if (oldGuestInstanceId === guestInstanceId) {
return false;
}
const oldGuestInstance = guestInstances.get(oldGuestInstanceId);
if (oldGuestInstance) {
oldGuestInstance.guest.detachFromOuterFrame();
}
}
const guestInstance = guestInstances.get(guestInstanceId);
// If this isn't a valid guest instance then do nothing.
if (!guestInstance) {
console.error(new Error(`Guest attach failed: Invalid guestInstanceId ${guestInstanceId}`));
return false;
}
const { guest } = guestInstance;
if (guest.hostWebContents !== embedder) {
console.error(new Error(`Guest attach failed: Access denied to guestInstanceId ${guestInstanceId}`));
return false;
}
const { instanceId } = params;
// If this guest is already attached to an element then remove it
if (guestInstance.elementInstanceId) {
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`;
embedderElementsMap.delete(oldKey);
// Remove guest from embedder if moving across web views
if (guest.viewInstanceId !== instanceId) {
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId);
guestInstance.embedder._sendInternal(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${guest.viewInstanceId}`);
}
}
const webPreferences = makeWebPreferences(embedder, params);
const event = eventBinding.createWithSender(embedder);
embedder.emit('will-attach-webview', event, webPreferences, params);
if (event.defaultPrevented) {
if (guest.viewInstanceId == null) guest.viewInstanceId = instanceId;
guest.destroy();
return false;
}
guest.attachParams = { instanceId, src: params.src, opts: makeLoadURLOptions(params) };
embedderElementsMap.set(key, guestInstanceId);
guest.setEmbedder(embedder);
guestInstance.embedder = embedder;
guestInstance.elementInstanceId = elementInstanceId;
watchEmbedder(embedder);
webViewManager.addGuest(guestInstanceId, embedder, guest, webPreferences);
guest.attachToIframe(embedder, embedderFrameId);
return guestInstanceId;
return true;
};
// Remove an guest-embedder relationship.

View File

@@ -4,13 +4,6 @@ import { IpcMainInvokeEvent } from 'electron/main';
export class IpcMainImpl extends EventEmitter {
private _invokeHandlers: Map<string, (e: IpcMainInvokeEvent, ...args: any[]) => void> = new Map();
constructor () {
super();
// Do not throw exception when channel name is "error".
this.on('error', () => {});
}
handle: Electron.IpcMain['handle'] = (method, fn) => {
if (this._invokeHandlers.has(method)) {
throw new Error(`Attempted to register a second handler for '${method}'`);

View File

@@ -1,3 +1,6 @@
import { IpcMainImpl } from '@electron/internal/browser/ipc-main-impl';
export const ipcMainInternal = new IpcMainImpl() as ElectronInternal.IpcMainInternal;
// Do not throw exception when channel name is "error".
ipcMainInternal.on('error', () => {});

View File

@@ -9,6 +9,7 @@ export const enum IPC_MESSAGES {
GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',
GUEST_VIEW_INTERNAL_DESTROY_GUEST = 'GUEST_VIEW_INTERNAL_DESTROY_GUEST',
GUEST_VIEW_INTERNAL_DISPATCH_EVENT = 'GUEST_VIEW_INTERNAL_DISPATCH_EVENT',
GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST = 'GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST',

View File

@@ -1,8 +1,7 @@
import { webFrame } from 'electron';
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
const { mainFrame: webFrame } = process._linkedBinding('electron_renderer_web_frame');
let shouldLog: boolean | null = null;
const { platform, execPath, env } = process;

View File

@@ -6,15 +6,30 @@ const { mainFrame: webFrame } = process._linkedBinding('electron_renderer_web_fr
export interface GuestViewDelegate {
dispatchEvent (eventName: string, props: Record<string, any>): void;
reset(): void;
}
const DEPRECATED_EVENTS: Record<string, string> = {
'page-title-updated': 'page-title-set'
} as const;
export function registerEvents (viewInstanceId: number, delegate: GuestViewDelegate) {
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`, function () {
delegate.reset();
delegate.dispatchEvent('destroyed', {});
});
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, props) {
if (DEPRECATED_EVENTS[eventName] != null) {
delegate.dispatchEvent(DEPRECATED_EVENTS[eventName], props);
}
delegate.dispatchEvent(eventName, props);
});
}
export function deregisterEvents (viewInstanceId: number) {
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`);
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`);
}

View File

@@ -55,7 +55,8 @@ const defineWebViewElement = (hooks: WebViewImplHooks) => {
}
if (!internal.elementAttached) {
hooks.guestViewInternal.registerEvents(internal.viewInstanceId, {
dispatchEvent: internal.dispatchEvent.bind(internal)
dispatchEvent: internal.dispatchEvent.bind(internal),
reset: internal.reset.bind(internal)
});
internal.elementAttached = true;
(internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse();

View File

@@ -191,7 +191,7 @@ export class WebViewImpl {
attachGuestInstance (guestInstanceId: number) {
if (guestInstanceId === -1) {
this.dispatchEvent('destroyed');
// Do nothing
return;
}

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "21.0.0-beta.1",
"version": "20.0.0-alpha.7",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
@@ -47,8 +47,8 @@
"express": "^4.16.4",
"folder-hash": "^2.1.1",
"fs-extra": "^9.0.1",
"got": "^11.8.5",
"husky": "^8.0.1",
"got": "^6.3.0",
"husky": "^6.0.0",
"klaw": "^3.0.0",
"lint": "^1.1.2",
"lint-staged": "^10.2.11",

View File

@@ -58,10 +58,10 @@ index 852b76bea69988e0b3ac76a17b603128f239dde0..d443f4dc2daea0b7aa86ae75d31d995f
callback(EVP_aes_192_ctr(), "aes-192-ctr", NULL, arg);
callback(EVP_aes_256_ctr(), "aes-256-ctr", NULL, arg);
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
index 380d25d9c2a8efb0636db5749a8e3b1ba6908ad5..7a5aa1c142e15cf06e63882e83d82a93c0d38785 100644
index 2458847e5640fe955a9971aa77c27251e5091db5..a0b3ac5f6b55921a542f27108beca93d6372c6fc 100644
--- a/include/openssl/cipher.h
+++ b/include/openssl/cipher.h
@@ -460,6 +460,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_ecb(void);
@@ -448,6 +448,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_ecb(void);
// EVP_aes_128_cfb128 is only available in decrepit.
OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cfb128(void);

View File

@@ -12,6 +12,7 @@ webview_cross_drag.patch
gin_enable_disable_v8_platform.patch
disable-redraw-lock.patch
enable_reset_aspect_ratio.patch
v8_context_snapshot_generator.patch
boringssl_build_gn.patch
pepper_plugin_support.patch
gtk_visibility.patch
@@ -74,8 +75,10 @@ skip_atk_toolchain_check.patch
worker_feat_add_hook_to_notify_script_ready.patch
chore_provide_iswebcontentscreationoverridden_with_full_params.patch
fix_properly_honor_printing_page_ranges.patch
chore_expose_v8_initialization_isolate_callbacks.patch
export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch
fix_export_zlib_symbols.patch
don_t_use_potentially_null_getwebframe_-_view_when_get_blink.patch
web_contents.patch
webview_fullscreen.patch
disable_unload_metrics.patch
@@ -108,12 +111,3 @@ make_gtk_getlibgtk_public.patch
build_disable_print_content_analysis.patch
custom_protocols_plzserviceworker.patch
feat_filter_out_non-shareable_windows_in_the_current_application_in.patch
fix_allow_guest_webcontents_to_enter_fullscreen.patch
disable_freezing_flags_after_init_in_node.patch
short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch
chore_add_electron_deps_to_gitignores.patch
chore_allow_chromium_to_handle_synthetic_mouse_events_for_touch.patch
add_maximized_parameter_to_linuxui_getwindowframeprovider.patch
revert_spellcheck_fully_launch_spell_check_delayed_initialization.patch
add_electron_deps_to_license_credits_file.patch
feat_add_set_can_resize_mutator.patch

View File

@@ -10,10 +10,10 @@ Allows Electron to restore WER when ELECTRON_DEFAULT_ERROR_MODE is set.
This should be upstreamed.
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index b692a49b71661b8394c1126250fb150653aece97..c087c0f99a15edd3a9c776a68c76b2cf46257123 100644
index e0ff6fae1e96699e7cb54c9e82a3c68a8e95602b..2179a906bb6c93fbfaa8e7b7e64fddfaab034e94 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -239,6 +239,10 @@ int GpuMain(MainFunctionParams parameters) {
@@ -241,6 +241,10 @@ int GpuMain(MainFunctionParams parameters) {
// to the GpuProcessHost once the GpuServiceImpl has started.
viz::GpuServiceImpl::InstallPreInitializeLogHandler();
@@ -24,9 +24,9 @@ index b692a49b71661b8394c1126250fb150653aece97..c087c0f99a15edd3a9c776a68c76b2cf
// We are experiencing what appear to be memory-stomp issues in the GPU
// process. These issues seem to be impacting the task executor and listeners
// registered to it. Create the task executor on the heap to guard against
@@ -337,7 +341,6 @@ int GpuMain(MainFunctionParams parameters) {
ChildProcess gpu_process(io_thread_type);
DCHECK(base::ThreadPoolInstance::Get()->WasStarted());
@@ -347,7 +351,6 @@ int GpuMain(MainFunctionParams parameters) {
GpuProcess gpu_process(io_thread_priority);
#endif
- auto* client = GetContentClient()->gpu();
if (client)

View File

@@ -10,7 +10,7 @@ DidCreateScriptContext is called, not all JS APIs are available in the
context, which can cause some preload scripts to trip.
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
index 5a7d3da58451f491ed6dfabd3bc31a645843bb60..36cbf8c5c01330acc8b3a708bd6481ede21d73be 100644
index d921125d153742dd09e34418c19195a3d61bef1f..5348c3289a94c86bbbc9bb07be26cc56b4986788 100644
--- a/content/public/renderer/render_frame_observer.h
+++ b/content/public/renderer/render_frame_observer.h
@@ -136,6 +136,8 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener,
@@ -23,10 +23,10 @@ index 5a7d3da58451f491ed6dfabd3bc31a645843bb60..36cbf8c5c01330acc8b3a708bd6481ed
int32_t world_id) {}
virtual void DidClearWindowObject() {}
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 33497b7afbe1fa196a596a2cb384a81a973de026..b6b63c182980b09987e82911f72282c275ff0dc6 100644
index 831db39365764d4001b8d602b225f157d3562ca8..4aabe0781d9e4150dddce76a50b993d0b8da8068 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4294,6 +4294,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
@@ -4502,6 +4502,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
observer.DidCreateScriptContext(context, world_id);
}
@@ -40,10 +40,10 @@ index 33497b7afbe1fa196a596a2cb384a81a973de026..b6b63c182980b09987e82911f72282c2
int world_id) {
for (auto& observer : observers_)
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 19eae2c0b98ecf27c6d8196c7accc44bdb24a543..40b2dc79e13080d15094a3db235e2e21760ac96d 100644
index e903ba9ec4f8d32c5d3a6795f0a20f2addf95743..bb9755b981cf96e131e6545f778f73607fabdd02 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -585,6 +585,8 @@ class CONTENT_EXPORT RenderFrameImpl
@@ -604,6 +604,8 @@ class CONTENT_EXPORT RenderFrameImpl
uint32_t ng_call_count) override;
void DidCreateScriptContext(v8::Local<v8::Context> context,
int world_id) override;
@@ -53,10 +53,10 @@ index 19eae2c0b98ecf27c6d8196c7accc44bdb24a543..40b2dc79e13080d15094a3db235e2e21
int world_id) override;
void DidChangeScrollOffset() override;
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 544ea3f5cd705d61dd0b99f2e0f541d98ca75c53..d863681a4297cbf2844469a1baae2a81cb0d1238 100644
index 595441198b5253e5f36f97303e952e642998be39..1b17db7b9285cb874e74abdd896888c12b288565 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -579,6 +579,9 @@ class BLINK_EXPORT WebLocalFrameClient {
@@ -598,6 +598,9 @@ class BLINK_EXPORT WebLocalFrameClient {
virtual void DidCreateScriptContext(v8::Local<v8::Context>,
int32_t world_id) {}
@@ -67,10 +67,10 @@ index 544ea3f5cd705d61dd0b99f2e0f541d98ca75c53..d863681a4297cbf2844469a1baae2a81
virtual void WillReleaseScriptContext(v8::Local<v8::Context>,
int32_t world_id) {}
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
index c8af53d40eaa1dd3a0067948a8cda80d1599cee3..4de918ee52efa7ec27a21aa2f57616d31dfd07d1 100644
index a6ba8411384855c82712960375bc949c5c2bd522..fc86ca807c9c1bda9236160580b094153778e18b 100644
--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
+++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -209,6 +209,7 @@ void LocalWindowProxy::Initialize() {
@@ -207,6 +207,7 @@ void LocalWindowProxy::Initialize() {
}
InstallConditionalFeatures();
@@ -79,10 +79,10 @@ index c8af53d40eaa1dd3a0067948a8cda80d1599cee3..4de918ee52efa7ec27a21aa2f57616d3
if (World().IsMainWorld()) {
GetFrame()->Loader().DispatchDidClearWindowObjectInMainWorld();
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 83a62e23b1d395b0aa545de5b828c24196cccc6d..0ca8163eb9ab87aead27bc8b2ee9e614d7e1d8c7 100644
index 6fb24096d3a5415f59cba2a8a5a6f36fe838dcc1..a4089fb3989ecd37d5b01baeb03c2ac1f4f05b53 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -301,6 +301,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
@@ -298,6 +298,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual void DidCreateScriptContext(v8::Local<v8::Context>,
int32_t world_id) = 0;
@@ -92,7 +92,7 @@ index 83a62e23b1d395b0aa545de5b828c24196cccc6d..0ca8163eb9ab87aead27bc8b2ee9e614
int32_t world_id) = 0;
virtual bool AllowScriptExtensions() = 0;
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index f40f022ff8ff88f1f128d4996f4460b8fdea1d95..480503e245dbb28dffc8ac9d2843d541793db534 100644
index 40042e1fa2622a871d0ed512f1f6fda1cdda56a6..a377548b36712bd4971bae6b4c0afdc5c8fdbdfc 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -273,6 +273,13 @@ void LocalFrameClientImpl::DidCreateScriptContext(
@@ -110,7 +110,7 @@ index f40f022ff8ff88f1f128d4996f4460b8fdea1d95..480503e245dbb28dffc8ac9d2843d541
v8::Local<v8::Context> context,
int32_t world_id) {
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index c974fa2f7c7f9c2aa5f075ec4aeb887d0b104453..b4ed9b2fadcfad7676387045b8581eb8d33e89e8 100644
index 1f929d9535ca19a2c443e13f2bafce179f5870df..fe7605585501fcc1fd515f1d94fda7e27d5ba632 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -80,6 +80,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
@@ -123,10 +123,10 @@ index c974fa2f7c7f9c2aa5f075ec4aeb887d0b104453..b4ed9b2fadcfad7676387045b8581eb8
int32_t world_id) override;
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index d44adfd65bd9a71996cdd323a5220d2dcaa09de2..1011a318a7d79186abe556d03f78badc725c802a 100644
index a9bd5283d3c65728dd3293abe88ffd02d3eee4fc..f5e4a927f2f5114e62d76fec86d6a5d2d2321166 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -366,6 +366,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
@@ -352,6 +352,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
void DidCreateScriptContext(v8::Local<v8::Context>,
int32_t world_id) override {}

View File

@@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Charles Kerr <charles@charleskerr.com>
Date: Tue, 9 Aug 2022 12:35:36 -0500
Subject: add electron deps to license credits file
Ensure that licenses for the dependencies introduced by Electron
are included in `LICENSES.chromium.html`
diff --git a/tools/licenses.py b/tools/licenses.py
index a58dbf44370baabbfa2986c734c96a210cc16f1d..1d6934460f788ab76275710e727fb062f5c92b5b 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -347,6 +347,32 @@ SPECIAL_CASES = {
"License File":
"/third_party/swiftshader/third_party/SPIRV-Headers/LICENSE",
},
+
+ os.path.join('third_party', 'electron_node'): {
+ "Name": "Node.js",
+ "URL": "https://github.com/nodejs/node",
+ "License": "MIT",
+ "License File": "/third_party/electron_node/LICENSE",
+ },
+ os.path.join('third_party', 'squirrel.mac'): {
+ "Name": "Squirrel",
+ "URL": "https://github.com/Squirrel/Squirrel.Mac",
+ "License": "MIT",
+ "License File": "/third_party/squirrel.mac/LICENSE",
+ },
+ os.path.join('third_party', 'squirrel.mac', 'vendor', 'mantle'): {
+ "Name": "Mantle",
+ "URL": "https://github.com/Mantle/Mantle",
+ "License": "MIT",
+ "License File": "/third_party/squirrel.mac/vendor/mantle/LICENSE.md",
+ },
+ os.path.join('third_party', 'squirrel.mac', 'vendor', 'ReactiveObjC'): {
+ "Name": "ReactiveObjC",
+ "URL": "https://github.com/ReactiveCocoa/ReactiveObjC",
+ "License": "MIT",
+ "License File":
+ "/third_party/squirrel.mac/vendor/ReactiveObjC/LICENSE.md",
+ },
}
# Special value for 'License File' field used to indicate that the license file

View File

@@ -1,176 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: msizanoen1 <msizanoen@qtmlabs.xyz>
Date: Tue, 19 Jul 2022 05:11:06 +0200
Subject: Add maximized parameter to LinuxUI::GetWindowFrameProvider
This allows ClientFrameViewLinux to instruct the toolkit to draw the window
decorations in maximized mode where needed, preventing empty space caused
by decoration shadows and rounded titlebars around the window while maximized.
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc
index 1fbb58152c19193d480b437aea123abdd61c24fe..2b7e305d643aa2e0afef4c578688897c3a8832bf 100644
--- a/ui/gtk/gtk_ui.cc
+++ b/ui/gtk/gtk_ui.cc
@@ -500,13 +500,15 @@ std::unique_ptr<ui::NavButtonProvider> GtkUi::CreateNavButtonProvider() {
return nullptr;
}
-ui::WindowFrameProvider* GtkUi::GetWindowFrameProvider(bool solid_frame) {
+ui::WindowFrameProvider* GtkUi::GetWindowFrameProvider(bool solid_frame, bool maximized) {
if (!GtkCheckVersion(3, 14))
return nullptr;
auto& provider =
- solid_frame ? solid_frame_provider_ : transparent_frame_provider_;
+ maximized
+ ? (solid_frame ? solid_maximized_frame_provider_ : transparent_maximized_frame_provider_)
+ : (solid_frame ? solid_frame_provider_ : transparent_frame_provider_);
if (!provider)
- provider = std::make_unique<gtk::WindowFrameProviderGtk>(solid_frame);
+ provider = std::make_unique<gtk::WindowFrameProviderGtk>(solid_frame, maximized);
return provider.get();
}
diff --git a/ui/gtk/gtk_ui.h b/ui/gtk/gtk_ui.h
index e73bbdf28fba1f5b96d326dd7b0fd9aaa33ba221..5a537c8f6291909392824d62fc04209ad662d59a 100644
--- a/ui/gtk/gtk_ui.h
+++ b/ui/gtk/gtk_ui.h
@@ -94,7 +94,7 @@ class GtkUi : public ui::LinuxUiBase {
bool PreferDarkTheme() const override;
bool AnimationsEnabled() const override;
std::unique_ptr<ui::NavButtonProvider> CreateNavButtonProvider() override;
- ui::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame) override;
+ ui::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame, bool maximized) override;
base::flat_map<std::string, std::string> GetKeyboardLayoutMap() override;
std::string GetCursorThemeName() override;
int GetCursorThemeSize() override;
@@ -199,6 +199,8 @@ class GtkUi : public ui::LinuxUiBase {
// while Chrome is running.
std::unique_ptr<ui::WindowFrameProvider> solid_frame_provider_;
std::unique_ptr<ui::WindowFrameProvider> transparent_frame_provider_;
+ std::unique_ptr<ui::WindowFrameProvider> solid_maximized_frame_provider_;
+ std::unique_ptr<ui::WindowFrameProvider> transparent_maximized_frame_provider_;
};
} // namespace gtk
diff --git a/ui/gtk/window_frame_provider_gtk.cc b/ui/gtk/window_frame_provider_gtk.cc
index e4dbdad327eb77994ffd7f068c67336a19897915..d3ae0636455489a7c7443df85cb769952c98aca2 100644
--- a/ui/gtk/window_frame_provider_gtk.cc
+++ b/ui/gtk/window_frame_provider_gtk.cc
@@ -38,16 +38,18 @@ std::string GetThemeName() {
return theme_string;
}
-GtkCssContext WindowContext(bool solid_frame, bool focused) {
+GtkCssContext WindowContext(bool solid_frame, bool maximized, bool focused) {
std::string selector = "#window.background.";
selector += solid_frame ? "solid-csd" : "csd";
+ if (maximized)
+ selector += ".maximized";
if (!focused)
selector += ":inactive";
return AppendCssNodeToStyleContext({}, selector);
}
-GtkCssContext DecorationContext(bool solid_frame, bool focused) {
- auto context = WindowContext(solid_frame, focused);
+GtkCssContext DecorationContext(bool solid_frame, bool maximized, bool focused) {
+ auto context = WindowContext(solid_frame, maximized, focused);
// GTK4 renders the decoration directly on the window.
if (!GtkCheckVersion(4))
context = AppendCssNodeToStyleContext(context, "#decoration");
@@ -64,8 +66,8 @@ GtkCssContext DecorationContext(bool solid_frame, bool focused) {
return context;
}
-GtkCssContext HeaderContext(bool solid_frame, bool focused) {
- auto context = WindowContext(solid_frame, focused);
+GtkCssContext HeaderContext(bool solid_frame, bool maximized, bool focused) {
+ auto context = WindowContext(solid_frame, maximized, focused);
context =
AppendCssNodeToStyleContext(context, "#headerbar.header-bar.titlebar");
if (!focused)
@@ -110,8 +112,8 @@ int ComputeTopCornerRadius() {
// need to experimentally determine the corner radius by rendering a sample.
// Additionally, in GTK4, the headerbar corners get clipped by the window
// rather than the headerbar having its own rounded corners.
- auto context = GtkCheckVersion(4) ? DecorationContext(false, false)
- : HeaderContext(false, false);
+ auto context = GtkCheckVersion(4) ? DecorationContext(false, false, false)
+ : HeaderContext(false, false, false);
ApplyCssToContext(context, R"(window, headerbar {
background-image: none;
background-color: black;
@@ -169,8 +171,8 @@ void WindowFrameProviderGtk::Asset::CloneFrom(
unfocused_bitmap = src.unfocused_bitmap;
}
-WindowFrameProviderGtk::WindowFrameProviderGtk(bool solid_frame)
- : solid_frame_(solid_frame) {}
+WindowFrameProviderGtk::WindowFrameProviderGtk(bool solid_frame, bool maximized)
+ : solid_frame_(solid_frame), maximized_(maximized) {}
WindowFrameProviderGtk::~WindowFrameProviderGtk() = default;
@@ -264,7 +266,7 @@ void WindowFrameProviderGtk::PaintWindowFrame(gfx::Canvas* canvas,
top_area_height_dip * scale - asset.frame_thickness_px.top();
auto header = PaintHeaderbar({client_bounds_px.width(), top_area_height_px},
- HeaderContext(solid_frame_, focused), scale);
+ HeaderContext(solid_frame_, maximized_, focused), scale);
image = gfx::ImageSkia::CreateFrom1xBitmap(header);
// In GTK4, the headerbar gets clipped by the window.
if (GtkCheckVersion(4)) {
@@ -296,7 +298,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
gfx::Rect frame_bounds_dip(kMaxFrameSizeDip, kMaxFrameSizeDip,
2 * kMaxFrameSizeDip, 2 * kMaxFrameSizeDip);
- auto focused_context = DecorationContext(solid_frame_, true);
+ auto focused_context = DecorationContext(solid_frame_, maximized_, true);
frame_bounds_dip.Inset(-GtkStyleContextGetPadding(focused_context));
frame_bounds_dip.Inset(-GtkStyleContextGetBorder(focused_context));
gfx::Size bitmap_size(BitmapSizePx(asset), BitmapSizePx(asset));
@@ -304,7 +306,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) {
PaintBitmap(bitmap_size, frame_bounds_dip, focused_context, scale);
asset.unfocused_bitmap =
PaintBitmap(bitmap_size, frame_bounds_dip,
- DecorationContext(solid_frame_, false), scale);
+ DecorationContext(solid_frame_, maximized_, false), scale);
// In GTK4, there's no way to obtain the frame thickness from CSS values
// directly, so we must determine it experimentally based on the drawn
diff --git a/ui/gtk/window_frame_provider_gtk.h b/ui/gtk/window_frame_provider_gtk.h
index 8370c1cb3f8c3532d94e1265242cbf2397920480..2e0105ba8782dfe0a3ac169850734032c8ab071c 100644
--- a/ui/gtk/window_frame_provider_gtk.h
+++ b/ui/gtk/window_frame_provider_gtk.h
@@ -14,7 +14,7 @@ namespace gtk {
class WindowFrameProviderGtk : public ui::WindowFrameProvider {
public:
- explicit WindowFrameProviderGtk(bool solid_frame);
+ explicit WindowFrameProviderGtk(bool solid_frame, bool maximized);
WindowFrameProviderGtk(const WindowFrameProviderGtk&) = delete;
WindowFrameProviderGtk& operator=(const WindowFrameProviderGtk&) = delete;
@@ -69,6 +69,9 @@ class WindowFrameProviderGtk : public ui::WindowFrameProvider {
// Cached bitmaps and metrics. The scale is rounded to percent.
base::flat_map<int, Asset> assets_;
+
+ // Whether to draw the window decorations as maximized.
+ bool maximized_;
};
} // namespace gtk
diff --git a/ui/linux/linux_ui.h b/ui/linux/linux_ui.h
index dee97740309e29c29d9c9c6c757455cddc817dbb..e5b71cd2b5e9e6252fe13c54bb54e26365347e2a 100644
--- a/ui/linux/linux_ui.h
+++ b/ui/linux/linux_ui.h
@@ -175,7 +175,7 @@ class COMPONENT_EXPORT(LINUX_UI) LinuxUi {
// if transparency is unsupported and the frame should be rendered opaque.
// The returned object is not owned by the caller and will remain alive until
// the process ends.
- virtual WindowFrameProvider* GetWindowFrameProvider(bool solid_frame) = 0;
+ virtual WindowFrameProvider* GetWindowFrameProvider(bool solid_frame, bool maximized) = 0;
// Returns a map of KeyboardEvent code to KeyboardEvent key values.
virtual base::flat_map<std::string, std::string> GetKeyboardLayoutMap() = 0;

View File

@@ -6,10 +6,10 @@ Subject: allow disabling blink scheduler throttling per RenderView
This allows us to disable throttling for hidden windows.
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 00f570d90db1279a486c3c0a34146e59b902c10f..373309f79a97ca58d2d291b6a162891935d5c4b7 100644
index 1f6d9be10432416f591a616805494b5d78975df1..e73f70c62ac2e69c918bdf39bd53f74a47066f4e 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -658,6 +658,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
@@ -665,6 +665,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
GetWidget()->GetAssociatedFrameWidget()->SetBackgroundOpaque(opaque);
}
@@ -48,18 +48,18 @@ index 4d2a4c6746e1dbfc619faf2e16eaa4948d74e372..6c9f190ff595234eca18ff20ca0655da
// This interface should only be implemented inside content.
friend class RenderViewHostImpl;
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index f55211fdb346c8659c93d077ec04ccebdae5b450..19b846f6ccf99423b712f0b589c20c1ab35bdfcf 100644
index 99978b33c294ebe37192baccb29f0a34a25aed17..ef6e9ae24979538b8746aca898d1f302827491d8 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -138,6 +138,8 @@ class CONTENT_EXPORT RenderViewImpl : public blink::WebViewClient {
bool was_created_by_renderer,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ void OnSetSchedulerThrottling(bool allowed);
+
@@ -151,6 +151,8 @@ class CONTENT_EXPORT RenderViewImpl : public blink::WebViewClient,
static WindowOpenDisposition NavigationPolicyToDisposition(
blink::WebNavigationPolicy policy);
+ void OnSetSchedulerThrottling(bool allowed);
+
// ---------------------------------------------------------------------------
// ADDING NEW FUNCTIONS? Please keep private functions alphabetized and put
// it in the same order in the .cc file as it was in the header.
diff --git a/third_party/blink/public/mojom/page/page.mojom b/third_party/blink/public/mojom/page/page.mojom
index 39bfc2200e924d0c589cfd07f085f182ef6853a6..bddff6d5ad3f6d08c4dc48e66ebc5319b1a5ec28 100644
--- a/third_party/blink/public/mojom/page/page.mojom
@@ -73,10 +73,10 @@ index 39bfc2200e924d0c589cfd07f085f182ef6853a6..bddff6d5ad3f6d08c4dc48e66ebc5319
+ SetSchedulerThrottling(bool allowed);
};
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 3af33a4d699b5bbfb0a1abac9408ad322a47a5ac..30bc8aa73fb46a0306ccc837a99cc4d58daef99d 100644
index 5e4032ccf916f969cd669af7d983becddb57c72b..a858c9f2fa609ae756a2e70d0362f2de372dd5be 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -366,6 +366,7 @@ class WebView {
@@ -364,6 +364,7 @@ class WebView {
// Scheduling -----------------------------------------------------------
virtual PageScheduler* Scheduler() const = 0;
@@ -85,10 +85,10 @@ index 3af33a4d699b5bbfb0a1abac9408ad322a47a5ac..30bc8aa73fb46a0306ccc837a99cc4d5
// Visibility -----------------------------------------------------------
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 8f15822dc33a2f8a19971afd7da0ab305f0b48b7..38faafcc7432c2bedead647d4946b7183233b4bc 100644
index 229d9f2112e70f3bbff6e6986ab01c67483a1ae9..0529b4399959a2a2b9b0131dd8736a87fb973b0b 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3758,6 +3758,13 @@ PageScheduler* WebViewImpl::Scheduler() const {
@@ -3711,6 +3711,13 @@ PageScheduler* WebViewImpl::Scheduler() const {
return GetPage()->GetPageScheduler();
}
@@ -102,7 +102,7 @@ index 8f15822dc33a2f8a19971afd7da0ab305f0b48b7..38faafcc7432c2bedead647d4946b718
void WebViewImpl::SetVisibilityState(
mojom::blink::PageVisibilityState visibility_state,
bool is_initial_state) {
@@ -3769,7 +3776,8 @@ void WebViewImpl::SetVisibilityState(
@@ -3722,7 +3729,8 @@ void WebViewImpl::SetVisibilityState(
}
GetPage()->SetVisibilityState(visibility_state, is_initial_state);
GetPage()->GetPageScheduler()->SetPageVisible(
@@ -113,10 +113,10 @@ index 8f15822dc33a2f8a19971afd7da0ab305f0b48b7..38faafcc7432c2bedead647d4946b718
mojom::blink::PageVisibilityState WebViewImpl::GetVisibilityState() {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 1b0e7811c023f795f9f8f8cdf8bf621e54b79855..915348eaa98191c60bddaaa3d146bdc99099e16b 100644
index 2f8e971ab224b36c6e464eb7524dd3d4c6b76f8c..4a9664d0ce5de431d9638e4145a21091cea78fd1 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -416,6 +416,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
@@ -418,6 +418,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
LocalDOMWindow* PagePopupWindow() const;
PageScheduler* Scheduler() const override;
@@ -124,7 +124,7 @@ index 1b0e7811c023f795f9f8f8cdf8bf621e54b79855..915348eaa98191c60bddaaa3d146bdc9
void SetVisibilityState(mojom::blink::PageVisibilityState visibility_state,
bool is_initial_state) override;
mojom::blink::PageVisibilityState GetVisibilityState() override;
@@ -866,6 +867,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
@@ -865,6 +866,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
// If true, we send IPC messages when |preferred_size_| changes.
bool send_preferred_size_changes_ = false;

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