diff --git a/.circleci/config.yml b/.circleci/config.yml index adcf9e502490c..372018b9e2532 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,7 +14,7 @@ parameters: type: boolean default: false - upload-to-s3: + upload-to-storage: type: string default: '1' diff --git a/.circleci/config/base.yml b/.circleci/config/base.yml index f9dd945f63bca..1092fced82811 100644 --- a/.circleci/config/base.yml +++ b/.circleci/config/base.yml @@ -5,7 +5,7 @@ parameters: type: boolean default: false - upload-to-s3: + upload-to-storage: type: string default: '1' @@ -24,7 +24,7 @@ parameters: linux-publish-arch-limit: type: enum default: all - enum: ["all", "arm", "arm64", "x64", "ia32"] + enum: ["all", "arm", "arm64", "x64"] run-macos-publish: type: boolean @@ -53,14 +53,8 @@ executors: description: "macOS executor size" type: enum enum: ["macos.x86.medium.gen2", "large"] - xcode: - description: "xcode version" - default: 13.2.1 - type: enum - enum: ["12.4.0", "13.2.1"] - macos: - xcode: << parameters.xcode >> + xcode: 13.3.0 resource_class: << parameters.size >> # Electron Runners @@ -113,12 +107,6 @@ env-unittests: &env-unittests BUILD_TARGET: electron/spec:chromium_unittests TESTS_CONFIG: src/electron/spec/configs/unittests.yml -# Build targets options. -env-ia32: &env-ia32 - GN_EXTRA_ARGS: 'target_cpu = "x86"' - NPM_CONFIG_ARCH: ia32 - TARGET_ARCH: ia32 - env-arm: &env-arm GN_EXTRA_ARGS: 'target_cpu = "arm"' MKSNAPSHOT_TOOLCHAIN: //build/toolchain/linux:clang_arm @@ -131,6 +119,9 @@ 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 @@ -244,11 +235,20 @@ step-depot-tools-get: &step-depot-tools-get name: Get depot tools command: | git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git - # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems if [ "`uname`" == "Darwin" ]; then + # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja else sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja + # Remove swift-format dep from cipd on macOS until we send a patch upstream. + cd depot_tools + patch gclient.py -R \<<'EOF' + 676,677c676 + < packages = dep_value.get('packages', []) + < for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')): + --- + > for package in dep_value.get('packages', []): + EOF fi step-depot-tools-add-to-path: &step-depot-tools-add-to-path @@ -346,7 +346,7 @@ step-wait-for-goma: &step-wait-for-goma sleep 5 done echo "Goma ready" - no_output_timeout: 2m + no_output_timeout: 5m step-restore-brew-cache: &step-restore-brew-cache restore_cache: @@ -354,14 +354,14 @@ step-restore-brew-cache: &step-restore-brew-cache - /usr/local/Cellar/gnu-tar - /usr/local/bin/gtar keys: - - v4-brew-cache-{{ arch }} + - v5-brew-cache-{{ arch }} step-save-brew-cache: &step-save-brew-cache save_cache: paths: - /usr/local/Cellar/gnu-tar - /usr/local/bin/gtar - key: v4-brew-cache-{{ arch }} + key: v5-brew-cache-{{ arch }} name: Persisting brew cache step-get-more-space-on-mac: &step-get-more-space-on-mac @@ -370,6 +370,7 @@ step-get-more-space-on-mac: &step-get-more-space-on-mac command: | if [ "`uname`" == "Darwin" ]; then sudo mkdir -p $TMPDIR/del-target + tmpify() { if [ -d "$1" ]; then sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1) @@ -441,9 +442,11 @@ step-get-more-space-on-mac: &step-get-more-space-on-mac background: true # On macOS delete all .git directories under src/ expect for -# third_party/angle/ because of build time generation of file +# third_party/angle/ and third_party/dawn/ because of build time generation of files # gen/angle/commit.h depends on third_party/angle/.git/HEAD # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 +# and dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD +# https://dawn-review.googlesource.com/c/dawn/+/83901 # TODO: maybe better to always leave out */.git/HEAD file for all targets ? step-delete-git-directories: &step-delete-git-directories run: @@ -451,7 +454,7 @@ step-delete-git-directories: &step-delete-git-directories command: | if [ "`uname`" == "Darwin" ]; then cd src - ( find . -type d -name ".git" -not -path "./third_party/angle/*" ) | xargs rm -rf + ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" ) | xargs rm -rf fi # On macOS the yarn install command during gclient sync was run on a linux @@ -467,6 +470,13 @@ step-install-npm-deps-on-mac: &step-install-npm-deps-on-mac node script/yarn install fi +step-install-npm-deps: &step-install-npm-deps + run: + name: Install node_modules + command: | + cd src/electron + node script/yarn install --frozen-lockfile + # This step handles the differences between the linux "gclient sync" # and the expected state on macOS step-fix-sync: &step-fix-sync @@ -498,6 +508,7 @@ 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 @@ -536,7 +547,7 @@ step-gn-check: &step-gn-check step-electron-build: &step-electron-build run: name: Electron build - no_output_timeout: 30m + no_output_timeout: 60m command: | # On arm platforms we generate a cross-arch ffmpeg that ninja does not seem # to realize is not correct / should be rebuilt. We delete it here so it is @@ -577,8 +588,6 @@ step-maybe-electron-dist-strip: &step-maybe-electron-dist-strip if [ "$STRIP_BINARIES" == "true" ] && [ "`uname`" == "Linux" ]; then if [ x"$TARGET_ARCH" == x ]; then target_cpu=x64 - elif [ "$TARGET_ARCH" == "ia32" ]; then - target_cpu=x86 else target_cpu="$TARGET_ARCH" fi @@ -624,11 +633,11 @@ step-electron-publish: &step-electron-publish fi cd src/electron - if [ "$UPLOAD_TO_S3" == "1" ]; then - echo 'Uploading Electron release distribution to S3' - script/release/uploaders/upload.py --verbose --upload_to_s3 + if [ "$UPLOAD_TO_STORAGE" == "1" ]; then + echo 'Uploading Electron release distribution to Azure' + 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 @@ -641,6 +650,7 @@ step-persist-data-for-tests: &step-persist-data-for-tests - src/out/Default/mksnapshot.zip - src/out/Default/chromedriver.zip - src/out/Default/gen/node_headers + - src/out/Default/overlapped-checker - src/out/ffmpeg/ffmpeg.zip - src/electron - src/third_party/electron_node @@ -651,6 +661,7 @@ 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: @@ -667,13 +678,6 @@ step-electron-dist-unzip: &step-electron-dist-unzip # passed. unzip -:o dist.zip -step-ffmpeg-unzip: &step-ffmpeg-unzip - run: - name: Unzip ffmpeg.zip - command: | - cd src/out/ffmpeg - unzip -:o ffmpeg.zip - step-mksnapshot-unzip: &step-mksnapshot-unzip run: name: Unzip mksnapshot.zip @@ -702,13 +706,6 @@ step-ffmpeg-build: &step-ffmpeg-build cd src ninja -C out/ffmpeg electron:electron_ffmpeg_zip -j $NUMBER_OF_NINJA_PROCESSES -step-verify-ffmpeg: &step-verify-ffmpeg - run: - name: Verify ffmpeg - command: | - cd src - python electron/script/verify-ffmpeg.py --source-root "$PWD" --build-dir out/Default --ffmpeg-path out/ffmpeg - step-verify-mksnapshot: &step-verify-mksnapshot run: name: Verify mksnapshot @@ -901,7 +898,7 @@ step-restore-out-cache: &step-restore-out-cache paths: - ./src/out/Default keys: - - v9-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} + - v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} name: Restoring out cache step-set-git-cache-path: &step-set-git-cache-path @@ -925,7 +922,7 @@ step-save-out-cache: &step-save-out-cache save_cache: paths: - ./src/out/Default - key: v9-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} + key: v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} name: Persisting out cache step-run-electron-only-hooks: &step-run-electron-only-hooks @@ -987,9 +984,16 @@ step-ts-compile: &step-ts-compile run: name: Run TS/JS compile on doc only change command: | - cd src - ninja -C out/Default electron:default_app_js -j $NUMBER_OF_NINJA_PROCESSES - ninja -C out/Default electron:electron_js2c -j $NUMBER_OF_NINJA_PROCESSES + cd src/electron + node script/yarn create-typescript-definitions + node script/yarn tsc -p tsconfig.default_app.json --noEmit + for f in build/webpack/*.js + do + out="${f:29}" + if [ "$out" != "base.js" ]; then + node script/yarn webpack --config $f --output-filename=$out --output-path=./.tmp --env.mode=development + fi + done # List of all steps. steps-electron-gn-check: &steps-electron-gn-check @@ -997,99 +1001,33 @@ steps-electron-gn-check: &steps-electron-gn-check - *step-checkout-electron - *step-depot-tools-get - *step-depot-tools-add-to-path + - install-python2-mac - *step-setup-env-for-build - *step-setup-goma-for-build - *step-generate-deps-hash - *step-touch-sync-done - maybe-restore-portaled-src-cache - - *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: - # Checkout - Copied from steps-checkout - - *step-checkout-electron - - *step-depot-tools-get - - *step-depot-tools-add-to-path - - *step-restore-brew-cache - - *step-install-gnutar-on-mac - - *step-get-more-space-on-mac - - *step-setup-goma-for-build - - *step-generate-deps-hash - - *step-touch-sync-done - - maybe-restore-portaled-src-cache - - *step-maybe-restore-git-cache - - *step-set-git-cache-path - # This sync call only runs if .circle-sync-done is an EMPTY file - - *step-gclient-sync - # These next few steps reset Electron to the correct commit regardless of which cache was restored + - 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-run-electron-only-hooks - - *step-generate-deps-hash-cleanly - - *step-mark-sync-done - - *step-minimize-workspace-size-from-checkout - - *step-depot-tools-add-to-path - - *step-setup-env-for-build - - *step-wait-for-goma - - *step-get-more-space-on-mac - - *step-install-npm-deps-on-mac - - *step-fix-sync - - *step-gn-gen-default +steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-change + steps: + # Checkout - Copied from steps-checkout + - *step-checkout-electron + - *step-install-npm-deps #Compile ts/js to verify doc change didn't break anything - *step-ts-compile -steps-native-tests: &steps-native-tests - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-setup-env-for-build - - *step-setup-goma-for-build - - *step-wait-for-goma - - *step-gn-gen-default - - - run: - name: Build tests - command: | - cd src - ninja -C out/Default $BUILD_TARGET - - *step-show-goma-stats - - - *step-setup-linux-for-headless-testing - - run: - name: Run tests - command: | - mkdir test_results - python src/electron/script/native-tests.py run \ - --config $TESTS_CONFIG \ - --tests-dir src/out/Default \ - --output-dir test_results \ - $TESTS_ARGS - - - store_artifacts: - path: test_results - destination: test_results # Put it in the root folder. - - store_test_results: - path: test_results - -steps-verify-ffmpeg: &steps-verify-ffmpeg - steps: - - attach_workspace: - at: . - - *step-depot-tools-add-to-path - - *step-electron-dist-unzip - - *step-ffmpeg-unzip - - *step-setup-linux-for-headless-testing - - - *step-verify-ffmpeg - - *step-maybe-notify-slack-failure - steps-tests: &steps-tests steps: - attach_workspace: @@ -1101,6 +1039,7 @@ 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: @@ -1190,6 +1129,31 @@ steps-test-node: &steps-test-node # Command Aliases commands: + install-python2-mac: + steps: + - restore_cache: + keys: + - v2.7.18-python-cache-{{ arch }} + name: Restore python cache + - run: + name: Install python2 on macos + command: | + if [ "`uname`" == "Darwin" ] && [ "$IS_ELECTRON_RUNNER" != "1" ]; then + if [ ! -f "python-downloads/python-2.7.18-macosx10.9.pkg" ]; then + mkdir python-downloads + echo 'Downloading Python 2.7.18' + curl -O https://dev-cdn.electronjs.org/python/python-2.7.18-macosx10.9.pkg + mv python-2.7.18-macosx10.9.pkg python-downloads + else + echo 'Using Python install from cache' + fi + sudo installer -pkg python-downloads/python-2.7.18-macosx10.9.pkg -target / + fi + - save_cache: + paths: + - python-downloads + key: v2.7.18-python-cache-{{ arch }} + name: Persisting python cache maybe-restore-portaled-src-cache: parameters: halt-if-successful: @@ -1245,6 +1209,7 @@ commands: mv_if_exist src/out/Default/hunspell_dictionaries.zip mv_if_exist src/cross-arch-snapshots mv_if_exist src/out/electron_ninja_log + mv_if_exist src/out/Default/.ninja_log when: always - store_artifacts: path: generated_artifacts @@ -1300,8 +1265,6 @@ commands: target_os=linux if [ x"$TARGET_ARCH" == x ]; then target_cpu=x64 - elif [ "$TARGET_ARCH" == "ia32" ]; then - target_cpu=x86 else target_cpu="$TARGET_ARCH" fi @@ -1357,6 +1320,7 @@ commands: - run: rm -rf src/electron - *step-restore-brew-cache - *step-install-gnutar-on-mac + - install-python2-mac - *step-save-brew-cache - when: condition: << parameters.build >> @@ -1471,7 +1435,7 @@ commands: - *step-electron-build - *step-maybe-electron-dist-strip - step-electron-dist-build: - additional-targets: shell_browser_ui_unittests third_party/electron_node:headers electron:hunspell_dictionaries_zip + additional-targets: shell_browser_ui_unittests third_party/electron_node:headers third_party/electron_node:overlapped-checker electron:hunspell_dictionaries_zip - *step-show-goma-stats @@ -1548,6 +1512,7 @@ commands: - *step-depot-tools-get - *step-depot-tools-add-to-path - *step-restore-brew-cache + - install-python2-mac - *step-get-more-space-on-mac - when: condition: << parameters.checkout >> @@ -1607,7 +1572,7 @@ jobs: name: linux-docker size: medium environment: - <<: *env-linux-medium + <<: *env-linux-2xlarge <<: *env-testing-build GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' <<: *steps-electron-ts-compile-for-doc-change @@ -1730,7 +1695,7 @@ jobs: environment: <<: *env-linux-2xlarge-release <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> + UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> <<: *env-ninja-status steps: - run: echo running @@ -1744,44 +1709,6 @@ jobs: attach: false checkout: true - linux-ia32-testing: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-global - <<: *env-ia32 - <<: *env-testing-build - <<: *env-ninja-status - GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' - steps: - - electron-build: - persist: true - checkout: true - use-out-cache: false - - linux-ia32-publish: - executor: - name: linux-docker - size: 2xlarge - environment: - <<: *env-linux-2xlarge-release - <<: *env-ia32 - <<: *env-release-build - <<: *env-32bit-release - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> - <<: *env-ninja-status - steps: - - run: echo running - - when: - condition: - or: - - equal: ["all", << pipeline.parameters.linux-publish-arch-limit >>] - - equal: ["ia32", << pipeline.parameters.linux-publish-arch-limit >>] - steps: - - electron-publish: - attach: false - checkout: true linux-arm-testing: executor: @@ -1812,7 +1739,7 @@ jobs: <<: *env-release-build <<: *env-32bit-release GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> + UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> <<: *env-ninja-status steps: - run: echo running @@ -1865,7 +1792,7 @@ jobs: <<: *env-arm64 <<: *env-release-build GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm64=True' - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> + UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> <<: *env-ninja-status steps: - run: echo running @@ -1906,14 +1833,14 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' <<: *steps-electron-gn-check - osx-publish-x64-skip-checkout: + osx-publish-x64: executor: name: macos size: macos.x86.medium.gen2 environment: <<: *env-mac-large-release <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> + UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> <<: *env-ninja-status steps: - run: echo running @@ -1927,7 +1854,7 @@ jobs: attach: true checkout: false - osx-publish-arm64-skip-checkout: + osx-publish-arm64: executor: name: macos size: macos.x86.medium.gen2 @@ -1935,7 +1862,7 @@ jobs: <<: *env-mac-large-release <<: *env-release-build <<: *env-apple-silicon - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> + UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> <<: *env-ninja-status steps: - run: echo running @@ -1997,7 +1924,7 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac' <<: *steps-electron-gn-check - mas-publish-x64-skip-checkout: + mas-publish-x64: executor: name: macos size: macos.x86.medium.gen2 @@ -2005,7 +1932,7 @@ jobs: <<: *env-mac-large-release <<: *env-mas <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> + UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> steps: - run: echo running - when: @@ -2018,7 +1945,7 @@ jobs: attach: true checkout: false - mas-publish-arm64-skip-checkout: + mas-publish-arm64: executor: name: macos size: macos.x86.medium.gen2 @@ -2026,7 +1953,7 @@ jobs: <<: *env-mac-large-release <<: *env-mas-apple-silicon <<: *env-release-build - UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >> + UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >> <<: *env-ninja-status steps: - run: echo running @@ -2104,61 +2031,6 @@ jobs: <<: *env-stack-dumping <<: *steps-test-node - linux-x64-verify-ffmpeg: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-headless-testing - <<: *env-send-slack-notifications - <<: *steps-verify-ffmpeg - - linux-ia32-testing-tests: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-stack-dumping - parallelism: 3 - <<: *steps-tests - - linux-ia32-testing-nan: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-nan - - linux-ia32-testing-node: - executor: - name: linux-docker - size: xlarge - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-stack-dumping - <<: *steps-test-node - - linux-ia32-verify-ffmpeg: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-ia32 - <<: *env-headless-testing - <<: *env-send-slack-notifications - <<: *steps-verify-ffmpeg - linux-arm-testing-tests: executor: linux-arm environment: @@ -2180,7 +2052,6 @@ jobs: osx-testing-x64-tests: executor: name: macos - xcode: 12.4.0 size: macos.x86.medium.gen2 environment: <<: *env-mac-large @@ -2194,12 +2065,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 @@ -2213,19 +2084,9 @@ jobs: <<: *env-mac-large <<: *env-stack-dumping <<: *env-apple-silicon + <<: *env-runner <<: *steps-tests - # Layer 4: Summary. - linux-release-summary: - executor: - name: linux-docker - size: medium - environment: - <<: *env-linux-medium - <<: *env-send-slack-notifications - steps: - - *step-maybe-notify-slack-success - # List all workflows workflows: docs-only: @@ -2242,8 +2103,6 @@ workflows: jobs: - linux-x64-publish: context: release-env - - linux-ia32-publish: - context: release-env - linux-arm-publish: context: release-env - linux-arm64-publish: @@ -2253,19 +2112,19 @@ workflows: when: << pipeline.parameters.run-macos-publish >> jobs: - mac-checkout - - osx-publish-x64-skip-checkout: + - osx-publish-x64: requires: - mac-checkout context: release-env - - mas-publish-x64-skip-checkout: + - mas-publish-x64: requires: - mac-checkout context: release-env - - osx-publish-arm64-skip-checkout: + - osx-publish-arm64: requires: - mac-checkout context: release-env - - mas-publish-arm64-skip-checkout: + - mas-publish-arm64: requires: - mac-checkout context: release-env @@ -2302,18 +2161,6 @@ workflows: - linux-x64-testing-node: requires: - linux-x64-testing - - linux-ia32-testing: - requires: - - linux-make-src-cache - - linux-ia32-testing-tests: - requires: - - linux-ia32-testing - - linux-ia32-testing-nan: - requires: - - linux-ia32-testing - - linux-ia32-testing-node: - requires: - - linux-ia32-testing - linux-arm-testing: requires: - linux-make-src-cache diff --git a/.eslintrc.json b/.eslintrc.json index 55d0f1712134a..7669da1863675 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,4 +1,5 @@ { + "root": true, "extends": "standard", "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint"], diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000000..198363a8ae8fb --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# Atom --> Electron rename +d9321f4df751fa32813fab1b6387bbd61bd681d0 +34c4c8d5088fa183f56baea28809de6f2a427e02 +# Enable JS Semicolons +5d657dece4102e5e5304d42e8004b6ad64c0fcda diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 706d63103ed76..7ea654e33ecea 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -17,8 +17,11 @@ body: - type: input attributes: label: Electron Version - description: What version of Electron are you using? - placeholder: 12.0.0 + description: | + What version of Electron are you using? + + Note: Please only report issues for [currently supported versions of Electron](https://www.electronjs.org/docs/latest/tutorial/support#currently-supported-versions). + placeholder: 17.0.0 validations: required: true - type: dropdown @@ -53,7 +56,7 @@ body: attributes: label: Last Known Working Electron version description: What is the last version of Electron this worked in, if applicable? - placeholder: 11.0.0 + placeholder: 16.0.0 - type: textarea attributes: label: Expected Behavior diff --git a/.github/semantic.yml b/.github/semantic.yml deleted file mode 100644 index 4168a3cdeed9e..0000000000000 --- a/.github/semantic.yml +++ /dev/null @@ -1,2 +0,0 @@ -# Always validate the PR title, and ignore the commits -titleOnly: true diff --git a/.github/workflows/electron_woa_testing.yml b/.github/workflows/electron_woa_testing.yml new file mode 100644 index 0000000000000..01c2b9a08ca71 --- /dev/null +++ b/.github/workflows/electron_woa_testing.yml @@ -0,0 +1,178 @@ +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 }}"} \ No newline at end of file diff --git a/.github/workflows/release_dependency_versions.yml b/.github/workflows/release_dependency_versions.yml new file mode 100755 index 0000000000000..00db1ba079d59 --- /dev/null +++ b/.github/workflows/release_dependency_versions.yml @@ -0,0 +1,31 @@ +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.release.tag_name }} =~ ^v[0-9]+\.0\.0$ ]]; then + echo ::set-output name=should_release::true + fi + trigger: + runs-on: ubuntu-latest + needs: check_tag + if: needs.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 }}"}}' diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml index 11d62c9d62855..6158b510bb03b 100644 --- a/.github/workflows/semantic.yml +++ b/.github/workflows/semantic.yml @@ -7,8 +7,14 @@ on: - edited - synchronize +permissions: + contents: read + jobs: main: + permissions: + pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs + statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR name: Validate PR Title runs-on: ubuntu-latest steps: diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec138999..0000000000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/.markdownlint.json b/.markdownlint.json index a1628ba622a37..495df656c2cd3 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -23,7 +23,5 @@ "br_spaces": 0 }, "single-h1": false, - "no-inline-html": { - "allowed_elements": ["br"] - } + "no-inline-html": false } diff --git a/.nvmrc b/.nvmrc index 8351c19397f4f..b6a7d89c68e0c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -14 +16 diff --git a/BUILD.gn b/BUILD.gn index fdd0419cf7587..6966cd3c5c9fd 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -37,7 +37,7 @@ if (is_mac) { import("build/rules.gni") assert( - mac_deployment_target == "10.11.0", + mac_deployment_target == "10.13", "Chromium has updated the mac_deployment_target, please update this assert, update the supported versions documentation (docs/tutorial/support.md) and flag this as a breaking change") } @@ -79,8 +79,18 @@ if (is_linux) { ] } + # Generates electron_gtk_stubs.h header which contains + # stubs for extracting function ptrs from the gtk library. + # Function signatures for which stubs are required should be + # declared in electron_gtk.sigs, currently this file contains + # signatures for the functions used with native file chooser + # implementation. In future, this file can be extended to contain + # gtk4 stubs to switch gtk version in runtime. generate_stubs("electron_gtk_stubs") { - sigs = [ "shell/browser/ui/electron_gtk.sigs" ] + sigs = [ + "shell/browser/ui/electron_gdk_pixbuf.sigs", + "shell/browser/ui/electron_gtk.sigs", + ] extra_header = "shell/browser/ui/electron_gtk.fragment" output_name = "electron_gtk_stubs" public_deps = [ "//ui/gtk:gtk_config" ] @@ -125,7 +135,7 @@ config("electron_lib_config") { include_dirs = [ "." ] } -# We geneate the definitions twice here, once in //electron/electron.d.ts +# We generate 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) @@ -223,6 +233,7 @@ 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 ] } @@ -359,10 +370,12 @@ source_set("electron_lib") { "shell/common/api:mojo", "//base:base_static", "//base/allocator:buildflags", + "//chrome:strings", "//chrome/app:command_ids", "//chrome/app/resources:platform_locale_settings", "//components/autofill/core/common:features", "//components/certificate_transparency", + "//components/embedder_support:browser_util", "//components/language/core/browser", "//components/net_log", "//components/network_hints/browser", @@ -378,6 +391,7 @@ source_set("electron_lib") { "//components/user_prefs", "//components/viz/host", "//components/viz/service", + "//components/webrtc", "//content/public/browser", "//content/public/child", "//content/public/gpu", @@ -390,9 +404,6 @@ source_set("electron_lib") { "//media/mojo/mojom", "//net:extras", "//net:net_resources", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/shared_impl", "//printing/buildflags", "//services/device/public/cpp/geolocation", "//services/device/public/cpp/hid", @@ -510,6 +521,8 @@ source_set("electron_lib") { "StoreKit.framework", ] + weak_frameworks = [ "QuickLookThumbnailing.framework" ] + sources += [ "shell/browser/ui/views/autofill_popup_view.cc", "shell/browser/ui/views/autofill_popup_view.h", @@ -551,7 +564,8 @@ source_set("electron_lib") { "//ui/base/ime/linux", "//ui/events/devices/x11", "//ui/events/platform/x11", - "//ui/gtk", + "//ui/linux:linux_ui", + "//ui/linux:linux_ui_factory", "//ui/views/controls/webview", "//ui/wm", ] @@ -608,6 +622,14 @@ source_set("electron_lib") { ] } + if (enable_ppapi) { + deps += [ + "//ppapi/host", + "//ppapi/proxy", + "//ppapi/shared_impl", + ] + } + if (enable_run_as_node) { sources += [ "shell/app/node_main.cc", @@ -657,8 +679,6 @@ 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", @@ -706,7 +726,7 @@ source_set("electron_lib") { "//components/pdf/browser:interceptors", "//components/pdf/common", "//components/pdf/renderer", - "//pdf:pdf_ppapi", + "//pdf", ] sources += [ "shell/browser/electron_pdf_web_contents_helper_client.cc", @@ -716,14 +736,6 @@ source_set("electron_lib") { sources += get_target_outputs(":electron_fuses") - if (is_win && enable_win_dark_mode_window_ui) { - sources += [ - "shell/browser/win/dark_mode.cc", - "shell/browser/win/dark_mode.h", - ] - libs += [ "uxtheme.lib" ] - } - if (allow_runtime_configurable_key_storage) { defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ] } @@ -808,16 +820,11 @@ if (is_mac) { # Add the SwiftShader .dylibs in the Libraries directory of the Framework. bundle_data("electron_swiftshader_binaries") { sources = [ - "$root_out_dir/egl_intermediates/libswiftshader_libEGL.dylib", - "$root_out_dir/egl_intermediates/libswiftshader_libGLESv2.dylib", "$root_out_dir/vk_intermediates/libvk_swiftshader.dylib", "$root_out_dir/vk_intermediates/vk_swiftshader_icd.json", ] outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] - public_deps = [ - "//ui/gl:swiftshader_egl_library_copy", - "//ui/gl:swiftshader_vk_library_copy", - ] + public_deps = [ "//ui/gl:swiftshader_vk_library_copy" ] } } group("electron_angle_library") { @@ -899,6 +906,13 @@ 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") { @@ -906,7 +920,10 @@ if (is_mac) { assert(defined(invoker.helper_name_suffix)) output_name = electron_helper_name + invoker.helper_name_suffix - deps = [ ":electron_framework+link" ] + deps = [ + ":electron_framework+link", + "//base/allocator:early_zone_registration_mac", + ] if (!is_mas_build) { deps += [ "//sandbox/mac:seatbelt" ] } @@ -1014,14 +1031,14 @@ if (is_mac) { action("electron_app_lproj_dirs") { outputs = [] - foreach(locale, locales_as_mac_outputs) { + foreach(locale, locales_as_apple_outputs) { outputs += [ "$target_gen_dir/app_infoplist_strings/$locale.lproj" ] } script = "build/mac/make_locale_dirs.py" args = rebase_path(outputs) } - foreach(locale, locales_as_mac_outputs) { + foreach(locale, locales_as_apple_outputs) { bundle_data("electron_app_strings_${locale}_bundle_data") { sources = [ "$target_gen_dir/app_infoplist_strings/$locale.lproj" ] outputs = [ "{{bundle_resources_dir}}/$locale.lproj" ] @@ -1030,7 +1047,7 @@ if (is_mac) { } group("electron_app_strings_bundle_data") { public_deps = [] - foreach(locale, locales_as_mac_outputs) { + foreach(locale, locales_as_apple_outputs) { public_deps += [ ":electron_app_strings_${locale}_bundle_data" ] } } @@ -1066,6 +1083,7 @@ if (is_mac) { ":electron_app_plist", ":electron_app_resources", ":electron_fuses", + "//base/allocator:early_zone_registration_mac", "//electron/buildflags", ] if (is_mas_build) { @@ -1109,21 +1127,18 @@ if (is_mac) { deps = [ ":electron_app" ] } - extract_symbols("swiftshader_egl_syms") { - binary = "$root_out_dir/libswiftshader_libEGL.dylib" + extract_symbols("egl_syms") { + binary = "$root_out_dir/libEGL.dylib" symbol_dir = "$root_out_dir/breakpad_symbols" - dsym_file = "$root_out_dir/libswiftshader_libEGL.dylib.dSYM/Contents/Resources/DWARF/libswiftshader_libEGL.dylib" - deps = - [ "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL" ] + dsym_file = "$root_out_dir/libEGL.dylib.dSYM/Contents/Resources/DWARF/libEGL.dylib" + deps = [ "//third_party/angle:libEGL" ] } - extract_symbols("swiftshader_gles_syms") { - binary = "$root_out_dir/libswiftshader_libGLESv2.dylib" + extract_symbols("gles_syms") { + binary = "$root_out_dir/libGLESv2.dylib" symbol_dir = "$root_out_dir/breakpad_symbols" - dsym_file = "$root_out_dir/libswiftshader_libGLESv2.dylib.dSYM/Contents/Resources/DWARF/libswiftshader_libGLESv2.dylib" - deps = [ - "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2", - ] + dsym_file = "$root_out_dir/libGLESv2.dylib.dSYM/Contents/Resources/DWARF/libGLESv2.dylib" + deps = [ "//third_party/angle:libGLESv2" ] } extract_symbols("crashpad_handler_syms") { @@ -1135,10 +1150,10 @@ if (is_mac) { group("electron_symbols") { deps = [ + ":egl_syms", ":electron_app_syms", ":electron_framework_syms", - ":swiftshader_egl_syms", - ":swiftshader_gles_syms", + ":gles_syms", ] if (!is_mas_build) { @@ -1297,27 +1312,23 @@ if (is_mac) { deps = [ ":electron_app" ] } - extract_symbols("swiftshader_egl_symbols") { - binary = "$root_out_dir/swiftshader/libEGL$_target_shared_library_suffix" + extract_symbols("egl_symbols") { + binary = "$root_out_dir/libEGL$_target_shared_library_suffix" symbol_dir = "$root_out_dir/breakpad_symbols" - deps = - [ "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL" ] + deps = [ "//third_party/angle:libEGL" ] } - extract_symbols("swiftshader_gles_symbols") { - binary = - "$root_out_dir/swiftshader/libGLESv2$_target_shared_library_suffix" + extract_symbols("gles_symbols") { + binary = "$root_out_dir/libGLESv2$_target_shared_library_suffix" symbol_dir = "$root_out_dir/breakpad_symbols" - deps = [ - "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2", - ] + deps = [ "//third_party/angle:libGLESv2" ] } group("electron_symbols") { deps = [ + ":egl_symbols", ":electron_app_symbols", - ":swiftshader_egl_symbols", - ":swiftshader_gles_symbols", + ":gles_symbols", ] } } diff --git a/DEPS b/DEPS index fa8474c1bfb1f..9498ab6da934a 100644 --- a/DEPS +++ b/DEPS @@ -1,28 +1,12 @@ -gclient_gn_args_file = 'src/build/config/gclient_args.gni' -gclient_gn_args = [ - 'build_with_chromium', - 'checkout_android', - 'checkout_android_native_support', - 'checkout_libaom', - 'checkout_nacl', - 'checkout_pgo_profiles', - 'checkout_oculus_sdk', - 'checkout_openxr', - 'checkout_google_benchmark', - 'mac_xcode_version', - 'generate_location_tags', -] +gclient_gn_args_from = 'src' vars = { 'chromium_version': - '100.0.4896.143', + '106.0.5249.119', 'node_version': - 'v16.13.2', + 'v16.16.0', 'nan_version': - # The following commit hash of NAN is v2.14.2 with *only* changes to the - # test suite. This should be updated to a specific tag when one becomes - # available. - '65b32af46e9d7fab2e4ff657751205b3865f4920', + '16fa32231e2ccd89d2804b3f765319128b20c4ac', 'squirrel.mac_version': '0e5d146ba13101a1302d59ea6e6e0b3cace4ae38', @@ -142,9 +126,9 @@ pre_deps_hooks = [ 'python3', '-c', 'import os; os.makedirs(os.path.join("src", "electron", "third_party", "graphite"));', - ], - }, -] + ], + }, + ] hooks = [ { diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 745b4906543f3..ab3add4d87bc7 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -18.2.1 \ No newline at end of file +21.2.0 \ No newline at end of file diff --git a/README.md b/README.md index f0af41e5940b3..dfb49e1e148b5 100644 --- a/README.md +++ b/README.md @@ -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.com/invite/APGC3k5yaH) +[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.gg/electronjs) :memo: Available Translations: πŸ‡¨πŸ‡³ πŸ‡§πŸ‡· πŸ‡ͺπŸ‡Έ πŸ‡―πŸ‡΅ πŸ‡·πŸ‡Ί πŸ‡«πŸ‡· πŸ‡ΊπŸ‡Έ πŸ‡©πŸ‡ͺ. View these docs in other languages at [electron/i18n](https://github.com/electron/i18n/tree/master/content/). @@ -34,6 +34,17 @@ For more installation options and troubleshooting tips, see [installation](docs/tutorial/installation.md). For info on how to manage Electron versions in your apps, see [Electron versioning](docs/tutorial/electron-versioning.md). +## Platform support + +Each Electron release provides binaries for macOS, Windows, and Linux. + +* macOS (High Sierra and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11. +* Windows (Windows 7 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8. +* Linux: The prebuilt binaries of Electron are built on Ubuntu 20.04. They have also been verified to work on: + * Ubuntu 14.04 and newer + * Fedora 24 and newer + * Debian 8 and newer + ## Quick start & Electron Fiddle Use [`Electron Fiddle`](https://github.com/electron/fiddle) @@ -54,12 +65,10 @@ npm start ## Resources for learning Electron -- [electronjs.org/docs](https://electronjs.org/docs) - All of Electron's documentation -- [electron/fiddle](https://github.com/electron/fiddle) - A tool to build, run, and package small Electron experiments -- [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - A very basic starter Electron app -- [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - Sample starter apps created by the community -- [electron/simple-samples](https://github.com/electron/simple-samples) - Small applications with ideas for taking them further -- [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - An Electron app that teaches you how to use Electron +* [electronjs.org/docs](https://electronjs.org/docs) - All of Electron's documentation +* [electron/fiddle](https://github.com/electron/fiddle) - A tool to build, run, and package small Electron experiments +* [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - A very basic starter Electron app +* [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - Sample starter apps created by the community ## Programmatic usage @@ -80,11 +89,15 @@ const child = proc.spawn(electron) ### Mirrors -- [China](https://npmmirror.com/mirrors/electron) +* [China](https://npmmirror.com/mirrors/electron/) + +See the [Advanced Installation Instructions](https://www.electronjs.org/docs/latest/tutorial/installation#mirror) to learn how to use a custom mirror. -## Documentation Translations +## Documentation translations -Find documentation translations in [electron/i18n](https://github.com/electron/i18n). +We crowdsource translations for our documentation via [Crowdin](https://crowdin.com/project/electron). +We currently accept translations for Chinese (Simplified), French, German, Japanese, Portuguese, +Russian, and Spanish. ## Contributing @@ -93,10 +106,10 @@ If you are interested in reporting/fixing issues and contributing directly to th ## Community Info on reporting bugs, getting help, finding third-party tools and sample apps, -and more can be found in the [support document](docs/tutorial/support.md#finding-support). +and more can be found on the [Community page](https://www.electronjs.org/community). ## License [MIT](https://github.com/electron/electron/blob/main/LICENSE) -When using the Electron or other GitHub logos, be sure to follow the [GitHub logo guidelines](https://github.com/logos). +When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf). diff --git a/appveyor.yml b/appveyor.yml index 7b413faee5c78..574e5edf0419b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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" accordningly +# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly # 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. @@ -11,8 +11,8 @@ # - "TARGET_ARCH" Choose from {'ia32', 'x64', 'arm', 'arm64', 'mips64el'}. # 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_S3" Set it to '1' upload a release to the S3 bucket. -# Otherwise the release will be uploaded to the Github Releases. +# - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket. +# 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, @@ -23,13 +23,9 @@ # https://www.appveyor.com/docs/build-configuration/#secure-variables # https://www.appveyor.com/docs/build-configuration/#custom-environment-variables -# Uncomment these lines to enable RDP -#on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - version: 1.0.{build} build_cloud: electron-16-core -image: vs2019bt-16.6.2 +image: vs2019bt-16.16.11 environment: GIT_CACHE_PATH: C:\Users\electron\libcc_cache ELECTRON_OUT_DIR: Default @@ -38,212 +34,281 @@ 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]) { - Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild - } else { - node script/yarn.js install --frozen-lockfile - $result = node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH - Write-Output $result - if ($result.ExitCode -eq 0) { - Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild + matrix: + + - job_name: Build + + - job_name: Test + job_depends_on: Build + +clone_folder: C:\projects\src\electron + +# the first failed job cancels other jobs and fails entire build +matrix: + fast_finish: true + +for: + + - + matrix: + only: + - job_name: Build + + init: + - ps: >- + if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) { + Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild } - } - - echo "Building $env:GN_CONFIG build" - - git config --global core.longpaths true - - cd .. - - mkdir src - - update_depot_tools.bat - - ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron - - ps: >- - if (Test-Path 'env:RAW_GOMA_AUTH') { - $env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config" - $env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE - } - - git clone https://github.com/electron/build-tools.git - - cd build-tools - - npm install - - mkdir third_party - - ps: >- - node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" - - ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)" - - ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)" - - cd .. - - ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR - - ps: >- - if (Test-Path 'env:RAW_GOMA_AUTH') { - $goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info - if ($goma_login -eq 'Login as Fermi Planck') { - Write-warning "Goma authentication is correct"; - } else { - Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."; - $host.SetShouldExit(1) + + build_script: + - ps: | + node script/yarn.js install --frozen-lockfile + node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH + if ($LASTEXITCODE -eq 0) { + Write-warning "Skipping tests for doc only change"; Exit-AppveyorBuild + } + $global:LASTEXITCODE = 0 + - cd .. + - ps: Write-Host "Building $env:GN_CONFIG build" + - git config --global core.longpaths true + - update_depot_tools.bat + - ps: >- + if (Test-Path 'env:RAW_GOMA_AUTH') { + $env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config" + $env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE + } + - git clone https://github.com/electron/build-tools.git + - cd build-tools + - npm install + - mkdir third_party + - ps: >- + node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" + - ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)" + - ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)" + - cd ..\.. + - ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR + - ps: >- + if (Test-Path 'env:RAW_GOMA_AUTH') { + $goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info + if ($goma_login -eq 'Login as Fermi Planck') { + Write-warning "Goma authentication is correct"; + } else { + Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."; + $host.SetShouldExit(1) + } + } + - ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools" + - ps: >- + if ($env:GN_CONFIG -ne 'release') { + $env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " } - } - - ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools" - - ps: >- - if ($env:GN_CONFIG -ne 'release') { - $env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " - } - - >- - gclient config - --name "src\electron" - --unmanaged - %GCLIENT_EXTRA_ARGS% - "https://github.com/electron/electron" - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - $env:RUN_GCLIENT_SYNC="true" - } else { - cd src\electron - node script\generate-deps-hash.js - $depshash = Get-Content .\.depshash -Raw - $zipfile = "Z:\$depshash.7z" - cd ..\.. - if (Test-Path -Path $zipfile) { - # file exists, unzip and then gclient sync - 7z x -y $zipfile -mmt=30 -aoa - if (-not (Test-Path -Path "src\buildtools")) { - # the zip file must be corrupt - resync + - >- + gclient config + --name "src\electron" + --unmanaged + %GCLIENT_EXTRA_ARGS% + "https://github.com/electron/electron" + - ps: >- + if ($env:GN_CONFIG -eq 'release') { + $env:RUN_GCLIENT_SYNC="true" + } else { + cd src\electron + node script\generate-deps-hash.js + $depshash = Get-Content .\.depshash -Raw + $zipfile = "Z:\$depshash.7z" + cd ..\.. + if (Test-Path -Path $zipfile) { + # file exists, unzip and then gclient sync + 7z x -y $zipfile -mmt=14 -aoa + if (-not (Test-Path -Path "src\buildtools")) { + # the zip file must be corrupt - resync + $env:RUN_GCLIENT_SYNC="true" + if ($env:TARGET_ARCH -ne 'ia32') { + # only save on x64/woa to avoid contention saving + $env:SAVE_GCLIENT_SRC="true" + } + } else { + # update angle + cd src\third_party\angle + git remote set-url origin https://chromium.googlesource.com/angle/angle.git + git fetch + cd ..\..\.. + } + } else { + # file does not exist, gclient sync, then zip $env:RUN_GCLIENT_SYNC="true" if ($env:TARGET_ARCH -ne 'ia32') { # only save on x64/woa to avoid contention saving $env:SAVE_GCLIENT_SRC="true" } - } else { - # update angle - cd src\third_party\angle - git remote set-url origin https://chromium.googlesource.com/angle/angle.git - git fetch - cd ..\..\.. - } - } else { - # file does not exist, gclient sync, then zip - $env:RUN_GCLIENT_SYNC="true" - if ($env:TARGET_ARCH -ne 'ia32') { - # only save on x64/woa to avoid contention saving - $env:SAVE_GCLIENT_SRC="true" } } - } - - if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync ) - - ps: >- - if ($env:SAVE_GCLIENT_SRC -eq 'true') { - # archive current source for future use - # only run on x64/woa to avoid contention saving - $(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\WebKit\LayoutTests! -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30) - if ($LASTEXITCODE -ne 0) { - Write-warning "Could not save source to shared drive; continuing anyway" + - if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync ) + - ps: >- + if ($env:SAVE_GCLIENT_SRC -eq 'true') { + # archive current source for future use + # only run on x64/woa to avoid contention saving + $(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30) + if ($LASTEXITCODE -ne 0) { + Write-warning "Could not save source to shared drive; continuing anyway" + } + # build time generation of file gen/angle/angle_commit.h depends on + # third_party/angle/.git + # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 + $(7z a $zipfile src\third_party\angle\.git) + if ($LASTEXITCODE -ne 0) { + Write-warning "Failed to add third_party\angle\.git; continuing anyway" + } + # build time generation of file dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD + # https://dawn-review.googlesource.com/c/dawn/+/83901 + $(7z a $zipfile src\third_party\dawn\.git) + if ($LASTEXITCODE -ne 0) { + Write-warning "Failed to add third_party\dawn\.git; continuing anyway" + } } - # build time generation of file gen/angle/angle_commit.h depends on - # third_party/angle/.git - # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 - $(7z a $zipfile src\third_party\angle\.git) - if ($LASTEXITCODE -ne 0) { - Write-warning "Failed to add third_party\angle\.git; continuing anyway" + - cd src + - set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn + - gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% " + - gn check out/Default //electron:electron_lib + - gn check out/Default //electron:electron_app + - gn check out/Default //electron/shell/common/api:mojo + - if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app) + - if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default ) + - gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%" + - ninja -C out/ffmpeg electron:electron_ffmpeg_zip + - ninja -C out/Default electron:electron_dist_zip + - ninja -C out/Default shell_browser_ui_unittests + - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args + - ninja -C out/Default electron:electron_mksnapshot_zip + - cd out\Default + - 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S + - cd ..\.. + - ninja -C out/Default electron:hunspell_dictionaries_zip + - ninja -C out/Default electron:electron_chromedriver_zip + - ninja -C out/Default third_party/electron_node:headers + - 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 + - 7z a builtins-pgo.zip v8\tools\builtins-pgo + - ps: >- + if ($env:GN_CONFIG -eq 'release') { + # 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 } - } - - cd src - - set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn - - gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% " - - gn check out/Default //electron:electron_lib - - gn check out/Default //electron:electron_app - - gn check out/Default //electron/shell/common/api:mojo - - if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app) - - if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default ) - - gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%" - - ninja -C out/ffmpeg electron:electron_ffmpeg_zip - - ninja -C out/Default electron:electron_dist_zip - - ninja -C out/Default shell_browser_ui_unittests - - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - - ninja -C out/Default electron:electron_mksnapshot_zip - - cd out\Default - - 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S - - cd ..\.. - - ninja -C out/Default electron:hunspell_dictionaries_zip - - ninja -C out/Default electron:electron_chromedriver_zip - - ninja -C out/Default third_party/electron_node:headers - - python %LOCAL_GOMA_DIR%\goma_ctl.py stat - - python electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json - - appveyor PushArtifact out/Default/windows_toolchain_profile.json - - appveyor PushArtifact out/Default/dist.zip - - appveyor PushArtifact out/Default/shell_browser_ui_unittests.exe - - appveyor PushArtifact out/Default/chromedriver.zip - - appveyor PushArtifact out/ffmpeg/ffmpeg.zip - - 7z a node_headers.zip out\Default\gen\node_headers - - appveyor PushArtifact node_headers.zip - - appveyor PushArtifact out/Default/mksnapshot.zip - - appveyor PushArtifact out/Default/hunspell_dictionaries.zip - - appveyor PushArtifact out/Default/electron.lib - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - # 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 - } else { - # It's useful to have pdb files when debugging testing builds that are - # built on CI. - 7z a pdb.zip out\Default\*.pdb - appveyor-retry appveyor PushArtifact pdb.zip - } - - python electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest -test_script: - # Workaround for https://github.com/appveyor/ci/issues/2420 - - set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core" - - ps: >- - if ((-Not (Test-Path Env:\TEST_WOA)) -And (-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) { - $env:RUN_TESTS="true" - } - - ps: >- - if ($env:RUN_TESTS -eq 'true') { - New-Item .\out\Default\gen\node_headers\Release -Type directory - Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib - } else { - echo "Skipping tests for $env:GN_CONFIG build" - } - - cd electron - # 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" - - if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying mksnapshot" - - if "%RUN_TESTS%"=="true" ( echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying chromedriver" - - if exist %cd%\electron.log ( appveyor-retry appveyor PushArtifact %cd%\electron.log ) -deploy_script: - - cd electron - - ps: >- - if (Test-Path Env:\ELECTRON_RELEASE) { - if (Test-Path Env:\UPLOAD_TO_S3) { - Write-Output "Uploading Electron release distribution to s3" - & python script\release\uploaders\upload.py --verbose --upload_to_s3 + - ps: >- + if ($env:GN_CONFIG -eq 'release') { + python electron\script\zip-symbols.py + appveyor-retry appveyor PushArtifact out/Default/symbols.zip } else { - Write-Output "Uploading Electron release distribution to github releases" - & python script\release\uploaders\upload.py --verbose + # It's useful to have pdb files when debugging testing builds that are + # built on CI. + 7z a pdb.zip out\Default\*.pdb } - } elseif (Test-Path Env:\TEST_WOA) { - node script/release/ci-release-build.js --job=electron-woa-testing --ci=VSTS --armTest --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH - } -on_finish: - - if exist src\electron\electron.log ( appveyor-retry appveyor PushArtifact src\electron\electron.log ) + - python electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest + + deploy_script: + - cd electron + - ps: >- + if (Test-Path Env:\ELECTRON_RELEASE) { + if (Test-Path Env:\UPLOAD_TO_STORAGE) { + Write-Output "Uploading Electron release distribution to azure" + & python script\release\uploaders\upload.py --verbose --upload_to_storage + } else { + Write-Output "Uploading Electron release distribution to github releases" + & 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 + } + on_finish: + # Uncomment this lines to enable RDP + #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - cd C:\projects\src + - if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json ) + - if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip) + - if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe) + - if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip) + - if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip) + - if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip) + - if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip) + - if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip) + - if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib) + - if exist builtins-pgo.zip (appveyor-retry appveyor PushArtifact builtins-pgo.zip) + - ps: >- + if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) { + appveyor-retry appveyor PushArtifact pdb.zip + } + + - + matrix: + only: + - job_name: Test + + init: + - ps: | + if ($env:RUN_TESTS -ne 'true') { + Write-warning "Skipping tests for $env:APPVEYOR_PROJECT_NAME"; Exit-AppveyorBuild + } + if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) { + Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild + } + build_script: + - ps: | + node script/yarn.js install --frozen-lockfile + node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH + if ($LASTEXITCODE -eq 0) { + Write-warning "Skipping tests for doc only change"; Exit-AppveyorBuild + } + $global:LASTEXITCODE = 0 + - ps: | + cd .. + mkdir out\Default + cd .. + # Download build artifacts + $apiUrl = 'https://ci.appveyor.com/api' + $build_info = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/builds/$env:APPVEYOR_BUILD_ID" + $artifacts_to_download = @('dist.zip','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','builtins-pgo.zip') + foreach ($job in $build_info.build.jobs) { + if ($job.name -eq "Build") { + $jobId = $job.jobId + foreach($artifact_name in $artifacts_to_download) { + if ($artifact_name -eq 'shell_browser_ui_unittests.exe' -Or $artifact_name -eq 'electron.lib') { + $outfile = "src\out\Default\$artifact_name" + } else { + $outfile = $artifact_name + } + Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile + } + } + } + - ps: | + $out_default_zips = @('dist.zip','chromedriver.zip','mksnapshot.zip') + foreach($zip_name in $out_default_zips) { + 7z x -y -osrc\out\Default $zip_name + } + - ps: 7z x -y -osrc\out\ffmpeg ffmpeg.zip + - ps: 7z x -y -osrc node_headers.zip + - ps: 7z x -y -osrc builtins-pgo.zip + + test_script: + # Workaround for https://github.com/appveyor/ci/issues/2420 + - set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core" + - ps: | + cd src + New-Item .\out\Default\gen\node_headers\Release -Type directory + Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib + - cd electron + - echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log + - echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log + - cd .. + - 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" + - echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% + - echo "Done verifying mksnapshot" + - echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% + - echo "Done verifying chromedriver" + + on_finish: + - if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log ) \ No newline at end of file diff --git a/azure-pipelines-arm.yml b/azure-pipelines-arm.yml deleted file mode 100644 index 868b7753944e2..0000000000000 --- a/azure-pipelines-arm.yml +++ /dev/null @@ -1,121 +0,0 @@ -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() diff --git a/azure-pipelines-woa.yml b/azure-pipelines-woa.yml deleted file mode 100644 index 9942f97f79dc3..0000000000000 --- a/azure-pipelines-woa.yml +++ /dev/null @@ -1,130 +0,0 @@ -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() diff --git a/build/args/all.gn b/build/args/all.gn index 9dce9730ddaa9..0a02f0c15b27f 100644 --- a/build/args/all.gn +++ b/build/args/all.gn @@ -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 = 103 +node_module_version = 109 v8_promise_internal_field_count = 1 v8_embedder_string = "-electron.0" @@ -21,20 +21,27 @@ proprietary_codecs = true ffmpeg_branding = "Chrome" enable_basic_printing = true + +# Removes DLLs from the build, which are only meant to be used for Chromium development. +# See https://github.com/electron/electron/pull/17985 angle_enable_vulkan_validation_layers = false dawn_enable_vulkan_validation_layers = false -# This breaks native node modules -libcxx_abi_unstable = false - # These are disabled because they cause the zip manifest to differ between # testing and release builds. # See https://chromium-review.googlesource.com/c/chromium/src/+/2774898. enable_pseudolocales = false -is_cfi = false - # Make application name configurable at runtime for cookie crypto allow_runtime_configurable_key_storage = true +# CET shadow stack is incompatible with v8, until v8 is CET compliant +# enabling this flag causes main process crashes where CET is enabled +# Ref: https://source.chromium.org/chromium/chromium/src/+/45fba672185aae233e75d6ddc81ea1e0b30db050:v8/BUILD.gn;l=357 enable_cet_shadow_stack = false + +# For similar reasons, disable CFI, which is not well supported in V8. +# Chromium doesn't have any problems with this because they do not run +# V8 in the browser process. +# Ref: https://source.chromium.org/chromium/chromium/src/+/45fba672185aae233e75d6ddc81ea1e0b30db050:v8/BUILD.gn;l=281 +is_cfi = false diff --git a/build/asar.gni b/build/asar.gni index 3e11845bd59bb..b8b290da2c670 100644 --- a/build/asar.gni +++ b/build/asar.gni @@ -1,33 +1,22 @@ -import("node.gni") +template("node_action") { + assert(defined(invoker.script), "Need script path to run") + assert(defined(invoker.args), "Need script arguments") -# 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, - "*", [ - "script", - "args", + "deps", + "public_deps", + "sources", + "inputs", + "outputs", ]) - 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 ] + if (!defined(inputs)) { + inputs = [] } - args = [ - rebase_path(cwd), - rebase_path(invoker.script), - ] - args += invoker.args + inputs += [ invoker.script ] + script = "//electron/build/run-node.py" + args = [ rebase_path(invoker.script) ] + invoker.args } } diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index e805478b21a86..31ff2dc8bb246 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -1,23 +1,3 @@ -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) { diff --git a/build/extract_symbols.gni b/build/extract_symbols.gni index e3fa2a30f4ca0..2f98aa466ba15 100644 --- a/build/extract_symbols.gni +++ b/build/extract_symbols.gni @@ -24,7 +24,11 @@ template("extract_symbols") { assert(defined(invoker.binary), "Need binary to dump") assert(defined(invoker.symbol_dir), "Need directory for symbol output") - dump_syms_label = "//third_party/breakpad:dump_syms($host_toolchain)" + 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_binary = get_label_info(dump_syms_label, "root_out_dir") + "/dump_syms$_host_executable_suffix" diff --git a/build/fuses/build.py b/build/fuses/build.py index c82e6cfba02af..f5c9b89417a60 100755 --- a/build/fuses/build.py +++ b/build/fuses/build.py @@ -19,17 +19,13 @@ #define FUSE_EXPORT __attribute__((visibility("default"))) #endif -namespace electron { - -namespace fuses { +namespace electron::fuses { extern const volatile char kFuseWire[]; {getters} -} // namespace fuses - -} // namespace electron +} // namespace electron::fuses #endif // ELECTRON_FUSES_H_ """ @@ -37,17 +33,13 @@ TEMPLATE_CC = """ #include "electron/fuses.h" -namespace electron { - -namespace fuses { +namespace electron::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: diff --git a/build/fuses/fuses.json5 b/build/fuses/fuses.json5 index f4984aa2a17b4..e8df5ffd7ab98 100644 --- a/build/fuses/fuses.json5 +++ b/build/fuses/fuses.json5 @@ -7,5 +7,6 @@ "node_options": "1", "node_cli_inspect": "1", "embedded_asar_integrity_validation": "0", - "only_load_app_from_asar": "0" + "only_load_app_from_asar": "0", + "load_browser_process_specific_v8_snapshot": "0" } diff --git a/build/js2c.py b/build/js2c.py index 7024e7391d5bf..4abcdabb58141 100755 --- a/build/js2c.py +++ b/build/js2c.py @@ -8,9 +8,7 @@ #include "node_native_module.h" #include "node_internals.h" -namespace node {{ - -namespace native_module {{ +namespace node::native_module {{ {definitions} @@ -18,9 +16,7 @@ {initializers} }} -}} // namespace native_module - -}} // namespace node +}} // namespace node::native_module """ def main(): diff --git a/build/mac/make_locale_dirs.py b/build/mac/make_locale_dirs.py index 21b220f7d913b..47f3a9f1f661f 100644 --- a/build/mac/make_locale_dirs.py +++ b/build/mac/make_locale_dirs.py @@ -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 -# directoires for its helper executable bundles, which do not otherwise +# directories for its helper executable bundles, which do not otherwise # require any direct Cocoa locale support. import os diff --git a/build/node.gni b/build/node.gni deleted file mode 100644 index a65f718e634ed..0000000000000 --- a/build/node.gni +++ /dev/null @@ -1,21 +0,0 @@ -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 - } -} diff --git a/build/npm.gni b/build/npm.gni index c2a0d1725af75..7790dcece157f 100644 --- a/build/npm.gni +++ b/build/npm.gni @@ -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 argumets") + assert(defined(invoker.args), "Need script arguments") action("npm_pre_flight_" + target_name) { inputs = [ diff --git a/build/rules.gni b/build/rules.gni index c6c383829b1d0..557f0b8193c20 100644 --- a/build/rules.gni +++ b/build/rules.gni @@ -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 comiple +# list of string, sources to compile # output_path: # (optional) string, the path to use for the outputs list in the # bundle_data step. If unspecified, defaults to bundle_resources_dir. diff --git a/buildflags/BUILD.gn b/buildflags/BUILD.gn index 9cbb8227f5f52..a37d752dba360 100644 --- a/buildflags/BUILD.gn +++ b/buildflags/BUILD.gn @@ -19,7 +19,6 @@ buildflag_header("buildflags") { "ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions", "ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker", "ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture", - "ENABLE_WIN_DARK_MODE_WINDOW_UI=$enable_win_dark_mode_window_ui", "OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider", ] } diff --git a/buildflags/buildflags.gni b/buildflags/buildflags.gni index 5adc739ef7bb1..6a6a7d59fefe3 100644 --- a/buildflags/buildflags.gni +++ b/buildflags/buildflags.gni @@ -31,7 +31,4 @@ declare_args() { # Enable Spellchecker support enable_builtin_spellchecker = true - - # Undocumented Windows dark mode API - enable_win_dark_mode_window_ui = false } diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index b49dde05fb9ed..33e7b62541d72 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -6,6 +6,7 @@ import("//build/config/ozone.gni") import("//build/config/ui.gni") import("//components/spellcheck/spellcheck_build_features.gni") import("//electron/buildflags/buildflags.gni") +import("//ppapi/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni") import("//third_party/widevine/cdm/widevine.gni") @@ -55,6 +56,14 @@ 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", @@ -69,6 +78,11 @@ 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", @@ -88,7 +102,10 @@ static_library("chrome") { "//chrome/browser/icon_loader_mac.mm", "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h", "//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm", + "//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", @@ -106,6 +123,8 @@ 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", @@ -119,12 +138,15 @@ static_library("chrome") { if (use_aura) { sources += [ "//chrome/browser/platform_util_aura.cc", + "//chrome/browser/ui/aura/native_window_tracker_aura.cc", + "//chrome/browser/ui/aura/native_window_tracker_aura.h", "//chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura.cc", ] } public_deps = [ "//chrome/browser:dev_ui_browser_resources", + "//chrome/browser/ui/color:mixers", "//chrome/common", "//chrome/common:version_header", "//components/keyed_service/content", @@ -135,10 +157,7 @@ static_library("chrome") { "//services/strings", ] - deps = [ - "//chrome/browser:resource_prefetch_predictor_proto", - "//components/optimization_guide/proto:optimization_guide_proto", - ] + deps = [ "//chrome/browser:resource_prefetch_predictor_proto" ] if (is_linux) { sources += [ "//chrome/browser/icon_loader_auralinux.cc" ] @@ -211,6 +230,10 @@ 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_job.cc", + "//components/printing/browser/print_to_pdf/pdf_print_job.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) { @@ -306,8 +329,6 @@ static_library("chrome") { "//chrome/browser/pdf/pdf_frame_util.h", "//chrome/browser/plugins/pdf_iframe_navigation_throttle.cc", "//chrome/browser/plugins/pdf_iframe_navigation_throttle.h", - "//chrome/renderer/pepper/chrome_pdf_print_client.cc", - "//chrome/renderer/pepper/chrome_pdf_print_client.h", ] deps += [ "//components/pdf/browser", @@ -345,8 +366,6 @@ source_set("plugins") { sources += [ "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc", "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h", - "//chrome/renderer/pepper/pepper_flash_font_file_host.cc", - "//chrome/renderer/pepper/pepper_flash_font_file_host.h", "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", ] @@ -354,15 +373,20 @@ source_set("plugins") { deps += [ "//components/strings", "//media:media_buildflags", - "//ppapi/buildflags", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/proxy:ipc", - "//ppapi/shared_impl", "//services/device/public/mojom", "//skia", "//storage/browser", ] + + if (enable_ppapi) { + deps += [ + "//ppapi/buildflags", + "//ppapi/host", + "//ppapi/proxy", + "//ppapi/proxy:ipc", + "//ppapi/shared_impl", + ] + } } # This source set is just so we don't have to depend on all of //chrome/browser @@ -384,14 +408,19 @@ 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", diff --git a/default_app/default_app.ts b/default_app/default_app.ts index 44bc2ebd9affc..0bac020331730 100644 --- a/default_app/default_app.ts +++ b/default_app/default_app.ts @@ -66,9 +66,9 @@ async function createWindow (backgroundColor?: string) { mainWindow = new BrowserWindow(options); mainWindow.on('ready-to-show', () => mainWindow!.show()); - mainWindow.webContents.on('new-window', (event, url) => { - event.preventDefault(); - shell.openExternal(decorateURL(url)); + mainWindow.webContents.setWindowOpenHandler(details => { + shell.openExternal(decorateURL(details.url)); + return { action: 'deny' }; }); mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, done) => { diff --git a/default_app/main.ts b/default_app/main.ts index f2834624f7430..7defe97f3ecf3 100644 --- a/default_app/main.ts +++ b/default_app/main.ts @@ -83,7 +83,7 @@ function loadApplicationPackage (packagePath: string) { }); try { - // Override app name and version. + // Override app's package.json data. packagePath = path.resolve(packagePath); const packageJsonPath = path.join(packagePath, 'package.json'); let appPath; @@ -104,6 +104,16 @@ function loadApplicationPackage (packagePath: string) { } else if (packageJson.name) { app.name = packageJson.name; } + if (packageJson.desktopName) { + app.setDesktopName(packageJson.desktopName); + } else { + app.setDesktopName(`${app.name}.desktop`); + } + // Set v8 flags, deliberately lazy load so that apps that do not use this + // feature do not pay the price + if (packageJson.v8Flags) { + require('v8').setFlagsFromString(packageJson.v8Flags); + } appPath = packagePath; } diff --git a/docs/README.md b/docs/README.md index 261c67c5941ce..57172020a87d6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -64,15 +64,12 @@ an issue: * [Automated Testing](tutorial/automated-testing.md) * [REPL](tutorial/repl.md) * [Distribution](tutorial/application-distribution.md) - * [Supported Platforms](tutorial/support.md#supported-platforms) * [Code Signing](tutorial/code-signing.md) * [Mac App Store](tutorial/mac-app-store-submission-guide.md) * [Windows Store](tutorial/windows-store-guide.md) * [Snapcraft](tutorial/snapcraft.md) + * [ASAR Archives](tutorial/asar-archives.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 @@ -86,7 +83,6 @@ These individual tutorials expand on topics discussed in the guide above. * Electron Releases & Developer Feedback * [Versioning Policy](tutorial/electron-versioning.md) * [Release Timelines](tutorial/electron-timelines.md) -* [Testing Widevine CDM](tutorial/testing-widevine-cdm.md) --- diff --git a/docs/api/app.md b/docs/api/app.md index a1e9c363c2d79..624c5a1ebb054 100755 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -130,6 +130,11 @@ 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: @@ -484,7 +489,6 @@ Returns: * `argv` string[] - An array of the second instance's command line arguments * `workingDirectory` string - The second instance's working directory * `additionalData` unknown - A JSON object of additional data passed from the second instance -* `ackCallback` unknown - A function that can be used to send data back to the second instance This event will be emitted inside the primary instance of your application when a second instance has been executed and calls `app.requestSingleInstanceLock()`. @@ -496,35 +500,12 @@ non-minimized. **Note:** If the second instance is started by a different user than the first, the `argv` array will not include the arguments. -**Note:** `ackCallback` allows the user to send data back to the -second instance during the `app.requestSingleInstanceLock()` flow. -This callback can be used for cases where the second instance -needs to obtain additional information from the first instance -before quitting. - -Currently, the limit on the message size is kMaxMessageLength, -or around 32kB. To be safe, keep the amount of data passed to 31kB at most. - -In order to call the callback, `event.preventDefault()` must be called, first. -If the callback is not called in either case, `null` will be sent back. -If `event.preventDefault()` is not called, but `ackCallback` is called -by the user in the event, then the behaviour is undefined. - This event is guaranteed to be emitted after the `ready` event of `app` gets emitted. **Note:** Extra command line arguments might be added by Chromium, such as `--original-process-start-time`. -### Event: 'first-instance-ack' - -Returns: - -* `event` Event -* `additionalData` unknown - A JSON object of additional data passed from the first instance, in response to the first instance's `second-instance` event. - -This event will be emitted within the second instance during the call to `app.requestSingleInstanceLock()`, when the first instance calls the `ackCallback` provided by the `second-instance` event handler. - ## Methods The `app` object has the following methods: @@ -606,6 +587,10 @@ You should seek to use the `steal` option as sparingly as possible. Hides all application windows without minimizing them. +### `app.isHidden()` _macOS_ + +Returns `boolean` - `true` if the applicationβ€”including all of its windowsβ€”is hidden (e.g. with `Command-H`), `false` otherwise. + ### `app.show()` _macOS_ Shows application windows after they were hidden. Does not automatically focus @@ -631,9 +616,18 @@ Returns `string` - The current application directory. * `%APPDATA%` on Windows * `$XDG_CONFIG_HOME` or `~/.config` on Linux * `~/Library/Application Support` on macOS - * `userData` The directory for storing your app's configuration files, which by - default it is the `appData` directory appended with your app's name. - * `cache` + * `userData` The directory for storing your app's configuration files, which + by default is the `appData` directory appended with your app's name. By + convention files storing user data should be written to this directory, and + it is not recommended to write large files here because some environments + may backup this directory to cloud storage. + * `sessionData` The directory for storing data generated by `Session`, such + as localStorage, cookies, disk cache, downloaded dictionaries, network + state, devtools files. By default this points to `userData`. Chromium may + write very large disk cache here, so if your app does not rely on browser + storage like localStorage or cookies to save user data, it is recommended + to set this directory to other locations to avoid polluting the `userData` + directory. * `temp` Temporary directory. * `exe` The current executable file. * `module` The `libchromiumcontent` library. @@ -683,9 +677,9 @@ In that case, the directory should be created with `fs.mkdirSync` or similar. You can only override paths of a `name` defined in `app.getPath`. -By default, web pages' cookies and caches will be stored under the `userData` +By default, web pages' cookies and caches will be stored under the `sessionData` directory. If you want to change this location, you have to override the -`userData` path before the `ready` event of the `app` module is emitted. +`sessionData` path before the `ready` event of the `app` module is emitted. ### `app.getVersion()` @@ -714,14 +708,14 @@ Overrides the current application's name. ### `app.getLocale()` Returns `string` - The current application locale, fetched using Chromium's `l10n_util` library. -Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/master:ui/base/l10n/l10n_util.cc). +Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc). To set the locale, you'll want to use a command line switch at app startup, which may be found [here](command-line-switches.md). **Note:** When distributing your packaged app, you have to also ship the `locales` folder. -**Note:** On Windows, you have to call it after the `ready` events gets emitted. +**Note:** This API must be called after the `ready` event is emitted. ### `app.getLocaleCountryCode()` @@ -729,6 +723,12 @@ Returns `string` - User operating system's locale two-letter [ISO 3166](https:// **Note:** When unable to detect locale country code, it returns empty string. +### `app.getSystemLocale()` + +Returns `string` - The current system locale. On Windows and Linux, it is fetched using Chromium's `i18n` library. On macOS, the `NSLocale` object is used instead. + +**Note:** This API must be called after the `ready` event is emitted. + ### `app.addRecentDocument(path)` _macOS_ _Windows_ * `path` string @@ -985,13 +985,6 @@ starts: const { app } = require('electron') let myWindow = null -app.on('first-instance-ack', (event, additionalData) => { - // Print out the ack received from the first instance. - // Note this event handler must come before the requestSingleInstanceLock call. - // Expected output: '{"myAckKey":"myAckValue"}' - console.log(JSON.stringify(additionalData)) -}) - const additionalData = { myKey: 'myValue' } const gotTheLock = app.requestSingleInstanceLock(additionalData) @@ -999,19 +992,14 @@ if (!gotTheLock) { app.quit() } else { app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => { - // We must call preventDefault if we're sending back data. - event.preventDefault() // Print out data received from the second instance. - // Expected output: '{"myKey":"myValue"}' - console.log(JSON.stringify(additionalData)) + console.log(additionalData) // Someone tried to run a second instance, we should focus our window. if (myWindow) { if (myWindow.isMinimized()) myWindow.restore() myWindow.focus() } - const ackData = { myAckKey: 'myAckValue' } - ackCallback(ackData) }) // Create myWindow, load the rest of the app, etc... @@ -1095,7 +1083,7 @@ Activation policy types: Imports the certificate in pkcs12 format into the platform certificate store. `callback` is called with the `result` of import operation, a value of `0` -indicates success while any other value indicates failure according to Chromium [net_error_list](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). +indicates success while any other value indicates failure according to Chromium [net_error_list](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). ### `app.configureHostResolver(options)` @@ -1404,7 +1392,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 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. +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. For example: diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md index ed63f4a4881db..a2c5b03079a06 100644 --- a/docs/api/browser-view.md +++ b/docs/api/browser-view.md @@ -11,6 +11,9 @@ relative to its owning window. It is meant to be an alternative to the Process: [Main](../glossary.md#main-process) +This module cannot be used until the `ready` event of the `app` +module is emitted. + ### Example ```javascript diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index f00d9f2e1a54e..16a005cd35706 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -4,6 +4,9 @@ Process: [Main](../glossary.md#main-process) +This module cannot be used until the `ready` event of the `app` +module is emitted. + ```javascript // In the main process. const { BrowserWindow } = require('electron') @@ -64,7 +67,7 @@ win.loadURL('https://github.com') ``` Note that even for apps that use `ready-to-show` event, it is still recommended -to set `backgroundColor` to make app feel more native. +to set `backgroundColor` to make the app feel more native. Some examples of valid `backgroundColor` values include: @@ -158,20 +161,20 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `useContentSize` boolean (optional) - The `width` and `height` would be used as web page's size, which means the actual window's size will include window frame's size and be slightly larger. Default is `false`. - * `center` boolean (optional) - Show window in the center of the screen. + * `center` boolean (optional) - Show window in the center of the screen. Default is `false`. * `minWidth` Integer (optional) - Window's minimum width. Default is `0`. * `minHeight` Integer (optional) - Window's minimum height. Default is `0`. * `maxWidth` Integer (optional) - Window's maximum width. Default is no limit. * `maxHeight` Integer (optional) - Window's maximum height. Default is no limit. * `resizable` boolean (optional) - Whether window is resizable. Default is `true`. - * `movable` boolean (optional) - Whether window is movable. This is not implemented - on Linux. Default is `true`. - * `minimizable` boolean (optional) - Whether window is minimizable. This is not - implemented on Linux. Default is `true`. - * `maximizable` boolean (optional) - Whether window is maximizable. This is not - implemented on Linux. Default is `true`. - * `closable` boolean (optional) - Whether window is closable. This is not implemented - on Linux. Default is `true`. + * `movable` boolean (optional) _macOS_ _Windows_ - Whether window is + movable. This is not implemented on Linux. Default is `true`. + * `minimizable` boolean (optional) _macOS_ _Windows_ - Whether window is + minimizable. This is not implemented on Linux. Default is `true`. + * `maximizable` boolean (optional) _macOS_ _Windows_ - Whether window is + maximizable. This is not implemented on Linux. Default is `true`. + * `closable` boolean (optional) _macOS_ _Windows_ - Whether window is + closable. This is not implemented on Linux. Default is `true`. * `focusable` boolean (optional) - Whether the window can be focused. Default is `true`. On Windows setting `focusable: false` also implies setting `skipTaskbar: true`. On Linux setting `focusable: false` makes the window @@ -185,9 +188,10 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `fullscreenable` boolean (optional) - Whether the window can be put into fullscreen mode. On macOS, also whether the maximize/zoom button should toggle full screen mode or maximize window. Default is `true`. - * `simpleFullscreen` boolean (optional) - Use pre-Lion fullscreen on macOS. Default is `false`. - * `skipTaskbar` boolean (optional) - Whether to show the window in taskbar. Default is - `false`. + * `simpleFullscreen` boolean (optional) _macOS_ - Use pre-Lion fullscreen on + macOS. Default is `false`. + * `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar. + Default is `false`. * `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`. * `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `` is defined in the HTML file loaded by `loadURL()`, this property will be ignored. * `icon` ([NativeImage](native-image.md) | string) (optional) - The window icon. On Windows it is @@ -201,27 +205,30 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `parent` BrowserWindow (optional) - Specify parent window. Default is `null`. * `modal` boolean (optional) - Whether this is a modal window. This only works when the window is a child window. Default is `false`. - * `acceptFirstMouse` boolean (optional) - Whether clicking an inactive window will also - click through to the web contents. Default is `false` on macOS. This option is not - configurable on other platforms. + * `acceptFirstMouse` boolean (optional) _macOS_ - Whether clicking an + inactive window will also click through to the web contents. Default is + `false` on macOS. This option is not configurable on other platforms. * `disableAutoHideCursor` boolean (optional) - Whether to hide cursor when typing. Default is `false`. * `autoHideMenuBar` boolean (optional) - Auto hide the menu bar unless the `Alt` key is pressed. Default is `false`. - * `enableLargerThanScreen` boolean (optional) - Enable the window to be resized larger - than screen. Only relevant for macOS, as other OSes allow - larger-than-screen windows by default. Default is `false`. + * `enableLargerThanScreen` boolean (optional) _macOS_ - Enable the window to + be resized larger than screen. Only relevant for macOS, as other OSes + allow larger-than-screen windows by default. Default is `false`. * `backgroundColor` string (optional) - The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if `transparent` is set to `true`. Default is `#FFF` (white). See [win.setBackgroundColor](browser-window.md#winsetbackgroundcolorbackgroundcolor) for more information. * `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`. - * `opacity` number (optional) - Set the initial opacity of the window, between 0.0 (fully - transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS. + * `opacity` number (optional) _macOS_ _Windows_ - Set the initial opacity of + the window, between 0.0 (fully transparent) and 1.0 (fully opaque). This + is only implemented on Windows and macOS. * `darkTheme` boolean (optional) - Forces using dark theme for the window, only works on some GTK+3 desktop environments. Default is `false`. * `transparent` boolean (optional) - Makes the window [transparent](../tutorial/window-customization.md#create-transparent-windows). Default is `false`. On Windows, does not work unless the window is frameless. * `type` string (optional) - The type of window, default is normal window. See more about this below. - * `visualEffectState` string (optional) - Specify how the material appearance should reflect window activity state on macOS. Must be used with the `vibrancy` property. Possible values are: + * `visualEffectState` string (optional) _macOS_ - Specify how the material + appearance should reflect window activity state on macOS. Must be used + with the `vibrancy` property. Possible values are: * `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default. * `active` - The backdrop should always appear active. * `inactive` - The backdrop should always appear inactive. @@ -229,36 +236,42 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. Default is `default`. Possible values are: * `default` - Results in the standard title bar for macOS or Windows respectively. * `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (β€œtraffic lights”) in the top left. On Windows, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown. - * `hiddenInset` - Only on macOS, results in a hidden title bar with an alternative look - where the traffic light buttons are slightly more inset from the window edge. - * `customButtonsOnHover` - Only on macOS, results in a hidden title bar and a full size - content window, the traffic light buttons will display when being hovered - over in the top left of the window. **Note:** This option is currently - experimental. - * `trafficLightPosition` [Point](structures/point.md) (optional) - Set a - custom position for the traffic light buttons in frameless windows. - * `roundedCorners` boolean (optional) - Whether frameless window should have - rounded corners on macOS. Default is `true`. - * `fullscreenWindowTitle` boolean (optional) _Deprecated_ - Shows the title in - the title bar in full screen mode on macOS for `hiddenInset` titleBarStyle. - Default is `false`. + * `hiddenInset` _macOS_ - Only on macOS, results in a hidden title bar + with an alternative look where the traffic light buttons are slightly + more inset from the window edge. + * `customButtonsOnHover` _macOS_ - Only on macOS, results in a hidden + title bar and a full size content window, the traffic light buttons will + display when being hovered over in the top left of the window. + **Note:** This option is currently experimental. + * `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. + * `fullscreenWindowTitle` boolean (optional) _macOS_ _Deprecated_ - Shows + the title in the title bar in full screen mode on macOS for `hiddenInset` + titleBarStyle. Default is `false`. * `thickFrame` boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on Windows, which adds standard window frame. Setting it to `false` will remove window shadow and window animations. Default is `true`. - * `vibrancy` string (optional) - Add a type of vibrancy effect to the window, only on - macOS. Can be `appearance-based`, `light`, `dark`, `titlebar`, `selection`, - `menu`, `popover`, `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. Please note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` are deprecated and have been removed in macOS Catalina (10.15). - * `zoomToPageWidth` boolean (optional) - Controls the behavior on macOS when - option-clicking the green stoplight button on the toolbar or by clicking the - Window > Zoom menu item. If `true`, the window will grow to the preferred - width of the web page when zoomed, `false` will cause it to zoom to the - width of the screen. This will also affect the behavior when calling - `maximize()` directly. Default is `false`. - * `tabbingIdentifier` string (optional) - Tab group name, allows opening the - window as a native tab on macOS 10.12+. Windows with the same tabbing - identifier will be grouped together. This also adds a native new tab button - to your window's tab bar and allows your `app` and window to receive the - `new-window-for-tab` event. + * `vibrancy` string (optional) _macOS_ - Add a type of vibrancy effect to + the window, only on macOS. Can be `appearance-based`, `light`, `dark`, + `titlebar`, `selection`, `menu`, `popover`, `sidebar`, `medium-light`, + `ultra-dark`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`, + `tooltip`, `content`, `under-window`, or `under-page`. Please note that + `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` are + deprecated and have been removed in macOS Catalina (10.15). + * `zoomToPageWidth` boolean (optional) _macOS_ - Controls the behavior on + macOS when option-clicking the green stoplight button on the toolbar or by + clicking the Window > Zoom menu item. If `true`, the window will grow to + the preferred width of the web page when zoomed, `false` will cause it to + zoom to the width of the screen. This will also affect the behavior when + calling `maximize()` directly. Default is `false`. + * `tabbingIdentifier` string (optional) _macOS_ - Tab group name, allows + opening the window as a native tab on macOS 10.12+. Windows with the same + tabbing identifier will be grouped together. This also adds a native new + tab button to your window's tab bar and allows your `app` and window to + receive the `new-window-for-tab` event. * `webPreferences` Object (optional) - Settings of web page's features. * `devTools` boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. * `nodeIntegration` boolean (optional) - Whether node integration is enabled. @@ -310,8 +323,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `plugins` boolean (optional) - Whether plugins should be enabled. Default is `false`. * `experimentalFeatures` boolean (optional) - Enables Chromium's experimental features. Default is `false`. - * `scrollBounce` boolean (optional) - Enables scroll bounce (rubber banding) effect on - macOS. Default is `false`. + * `scrollBounce` boolean (optional) _macOS_ - Enables scroll bounce + (rubber banding) effect on macOS. Default is `false`. * `enableBlinkFeatures` string (optional) - A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` to enable. The full list of supported feature strings can be found in the [RuntimeEnabledFeatures.json5][runtime-enabled-features] @@ -413,13 +426,17 @@ Possible values are: * On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`, `notification`. -* On macOS, possible types are `desktop`, `textured`. +* On macOS, possible types are `desktop`, `textured`, `panel`. * The `textured` type adds metal gradient appearance - (`NSTexturedBackgroundWindowMask`). + (`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 @@ -774,7 +791,7 @@ A `boolean` property that determines whether the window is in fullscreen mode. A `boolean` property that determines whether the window is focusable. -#### `win.visibleOnAllWorkspaces` +#### `win.visibleOnAllWorkspaces` _macOS_ _Linux_ A `boolean` property that determines whether the window is visible on all workspaces. @@ -811,13 +828,13 @@ A `string` property that determines the title of the native window. **Note:** The title of the web page can be different from the title of the native window. -#### `win.minimizable` +#### `win.minimizable` _macOS_ _Windows_ A `boolean` property that determines whether the window can be manually minimized by user. On Linux the setter is a no-op, although the getter returns `true`. -#### `win.maximizable` +#### `win.maximizable` _macOS_ _Windows_ A `boolean` property that determines whether the window can be manually maximized by user. @@ -832,13 +849,13 @@ maximizes the window. A `boolean` property that determines whether the window can be manually resized by user. -#### `win.closable` +#### `win.closable` _macOS_ _Windows_ A `boolean` property that determines whether the window can be manually closed by user. On Linux the setter is a no-op, although the getter returns `true`. -#### `win.movable` +#### `win.movable` _macOS_ _Windows_ A `boolean` property that determines Whether the window can be moved by user. @@ -1307,7 +1324,7 @@ win.setSheetOffset(toolbarRect.height) Starts or stops flashing the window to attract user's attention. -#### `win.setSkipTaskbar(skip)` +#### `win.setSkipTaskbar(skip)` _macOS_ _Windows_ * `skip` boolean @@ -1635,7 +1652,7 @@ Changes window icon. Sets whether the window traffic light buttons should be visible. -#### `win.setAutoHideMenuBar(hide)` +#### `win.setAutoHideMenuBar(hide)` _Windows_ _Linux_ * `hide` boolean @@ -1644,7 +1661,7 @@ menu bar will only show when users press the single `Alt` key. If the menu bar is already visible, calling `setAutoHideMenuBar(true)` won't hide it immediately. -#### `win.isMenuBarAutoHide()` +#### `win.isMenuBarAutoHide()` _Windows_ _Linux_ Returns `boolean` - Whether menu bar automatically hides itself. @@ -1654,11 +1671,11 @@ Returns `boolean` - Whether menu bar automatically hides itself. Sets whether the menu bar should be visible. If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key. -#### `win.isMenuBarVisible()` +#### `win.isMenuBarVisible()` _Windows_ _Linux_ Returns `boolean` - Whether the menu bar is visible. -#### `win.setVisibleOnAllWorkspaces(visible[, options])` +#### `win.setVisibleOnAllWorkspaces(visible[, options])` _macOS_ _Linux_ * `visible` boolean * `options` Object (optional) @@ -1676,7 +1693,7 @@ Sets whether the window should be visible on all workspaces. **Note:** This API does nothing on Windows. -#### `win.isVisibleOnAllWorkspaces()` +#### `win.isVisibleOnAllWorkspaces()` _macOS_ _Linux_ Returns `boolean` - Whether the window is visible on all workspaces. diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 12f1ce1157e5b..81410a281816f 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -185,7 +185,7 @@ the first write will throw an error. If the passed value is not a `string`, its Certain headers are restricted from being set by apps. These headers are listed below. More information on restricted headers can be found in -[Chromium's header utils](https://source.chromium.org/chromium/chromium/src/+/master:services/network/public/cpp/header_util.cc;drc=1562cab3f1eda927938f8f4a5a91991fefde66d3;bpv=1;bpt=1;l=22). +[Chromium's header utils](https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/header_util.cc;drc=1562cab3f1eda927938f8f4a5a91991fefde66d3;bpv=1;bpt=1;l=22). * `Content-Length` * `Host` diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index f395379c063fa..d628b0549c1dd 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -274,8 +274,8 @@ By default inspector websocket url is available in stderr and under /json/list e [ready]: app.md#event-ready [play-silent-audio]: https://github.com/atom/atom/pull/9485/files [debugging-main-process]: ../tutorial/debugging-main-process.md -[logging]: https://source.chromium.org/chromium/chromium/src/+/master:base/logging.h +[logging]: https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h [node-cli]: https://nodejs.org/api/cli.html [play-silent-audio]: https://github.com/atom/atom/pull/9485/files [ready]: app.md#event-ready -[severities]: https://source.chromium.org/chromium/chromium/src/+/master:base/logging.h?q=logging::LogSeverity&ss=chromium +[severities]: https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h?q=logging::LogSeverity&ss=chromium diff --git a/docs/api/content-tracing.md b/docs/api/content-tracing.md index 91e3ca43a2560..ec8e3f7979701 100644 --- a/docs/api/content-tracing.md +++ b/docs/api/content-tracing.md @@ -36,7 +36,7 @@ Returns `Promise<string[]>` - resolves with an array of category groups once all Get a set of category groups. The category groups can change as new code paths are reached. See also the [list of built-in tracing -categories](https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/builtin_categories.h). +categories](https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h). > **NOTE:** Electron adds a non-default tracing category called `"electron"`. > This category can be used to capture Electron-specific tracing events. diff --git a/docs/api/context-bridge.md b/docs/api/context-bridge.md index c816b43ab64d8..5d62220bd6070 100644 --- a/docs/api/context-bridge.md +++ b/docs/api/context-bridge.md @@ -35,7 +35,7 @@ page you load in your renderer executes code in this world. When `contextIsolation` is enabled in your `webPreferences` (this is the default behavior since Electron 12.0.0), your `preload` scripts run in an "Isolated World". You can read more about context isolation and what it affects in the -[security](../tutorial/security.md#3-enable-context-isolation-for-remote-content) docs. +[security](../tutorial/security.md#3-enable-context-isolation) docs. ## Methods diff --git a/docs/api/environment-variables.md b/docs/api/environment-variables.md index 09b12e3124fb6..ba3d5cf99e6de 100644 --- a/docs/api/environment-variables.md +++ b/docs/api/environment-variables.md @@ -139,8 +139,7 @@ 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 a -tions 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 actions are taken: a notification is shown, dismissed, its button is clicked, or it is replied to. Sample output: diff --git a/docs/api/ipc-main.md b/docs/api/ipc-main.md index f55e848c16398..e7c9800a25b50 100644 --- a/docs/api/ipc-main.md +++ b/docs/api/ipc-main.md @@ -1,3 +1,10 @@ +--- +title: "ipcMain" +description: "Communicate asynchronously from the main process to renderer processes." +slug: ipc-main +hide_title: false +--- + # ipcMain > Communicate asynchronously from the main process to renderer processes. @@ -9,7 +16,9 @@ process, it handles asynchronous and synchronous messages sent from a renderer process (web page). Messages sent from a renderer will be emitted to this module. -## Sending Messages +For usage examples, check out the [IPC tutorial]. + +## Sending messages It is also possible to send messages from the main process to the renderer process, see [webContents.send][web-contents-send] for more information. @@ -21,36 +30,6 @@ process, see [webContents.send][web-contents-send] for more information. coming from frames that aren't the main frame (e.g. iframes) whereas `event.sender.send(...)` will always send to the main frame. -An example of sending and handling messages between the render and main -processes: - -```javascript -// In main process. -const { ipcMain } = require('electron') -ipcMain.on('asynchronous-message', (event, arg) => { - console.log(arg) // prints "ping" - event.reply('asynchronous-reply', 'pong') -}) - -ipcMain.on('synchronous-message', (event, arg) => { - console.log(arg) // prints "ping" - event.returnValue = 'pong' -}) -``` - -```javascript -// In renderer process (web page). -// NB. Electron APIs are only accessible from preload, unless contextIsolation is disabled. -// See https://www.electronjs.org/docs/tutorial/process-model#preload-scripts for more details. -const { ipcRenderer } = require('electron') -console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong" - -ipcRenderer.on('asynchronous-reply', (event, arg) => { - console.log(arg) // prints "pong" -}) -ipcRenderer.send('asynchronous-message', 'ping') -``` - ## Methods The `ipcMain` module has the following method to listen for events: @@ -59,7 +38,7 @@ The `ipcMain` module has the following method to listen for events: * `channel` string * `listener` Function - * `event` IpcMainEvent + * `event` [IpcMainEvent][ipc-main-event] * `...args` any[] Listens to `channel`, when a new message arrives `listener` would be called with @@ -69,7 +48,7 @@ Listens to `channel`, when a new message arrives `listener` would be called with * `channel` string * `listener` Function - * `event` IpcMainEvent + * `event` [IpcMainEvent][ipc-main-event] * `...args` any[] Adds a one time `listener` function for the event. This `listener` is invoked @@ -93,8 +72,8 @@ Removes listeners of the specified `channel`. ### `ipcMain.handle(channel, listener)` * `channel` string -* `listener` Function<Promise\<void> | any> - * `event` IpcMainInvokeEvent +* `listener` Function<Promise\<void> | any> + * `event` [IpcMainInvokeEvent][ipc-main-invoke-event] * `...args` any[] Adds a handler for an `invoke`able IPC. This handler will be called whenever a @@ -104,14 +83,14 @@ If `listener` returns a Promise, the eventual result of the promise will be returned as a reply to the remote caller. Otherwise, the return value of the listener will be used as the value of the reply. -```js -// Main process +```js title='Main Process' ipcMain.handle('my-invokable-ipc', async (event, ...args) => { const result = await somePromise(...args) return result }) +``` -// Renderer process +```js title='Renderer Process' async () => { const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2) // ... @@ -130,7 +109,7 @@ provided to the renderer process. Please refer to ### `ipcMain.handleOnce(channel, listener)` * `channel` string -* `listener` Function<Promise\<void> | any> +* `listener` Function<Promise\<void> | any> * `event` IpcMainInvokeEvent * `...args` any[] @@ -146,13 +125,16 @@ Removes any handler for `channel`, if present. ## IpcMainEvent object The documentation for the `event` object passed to the `callback` can be found -in the [`ipc-main-event`](structures/ipc-main-event.md) structure docs. +in the [`ipc-main-event`][ipc-main-event] structure docs. ## IpcMainInvokeEvent object The documentation for the `event` object passed to `handle` callbacks can be -found in the [`ipc-main-invoke-event`](structures/ipc-main-invoke-event.md) +found in the [`ipc-main-invoke-event`][ipc-main-invoke-event] structure docs. +[IPC tutorial]: ../tutorial/ipc.md [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter -[web-contents-send]: web-contents.md#contentssendchannel-args +[web-contents-send]: ../api/web-contents.md#contentssendchannel-args +[ipc-main-event]:../api/structures/ipc-main-event.md +[ipc-main-invoke-event]:../api/structures/ipc-main-invoke-event.md diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index 383c7c0857339..dae89527aa42c 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -1,3 +1,10 @@ +--- +title: "ipcRenderer" +description: "Communicate asynchronously from a renderer process to the main process." +slug: ipc-renderer +hide_title: false +--- + # ipcRenderer > Communicate asynchronously from a renderer process to the main process. @@ -9,7 +16,7 @@ methods so you can send synchronous and asynchronous messages from the render process (web page) to the main process. You can also receive replies from the main process. -See [ipcMain](ipc-main.md) for code examples. +See [IPC tutorial](../tutorial/ipc.md) for code examples. ## Methods @@ -70,7 +77,7 @@ throw an exception. > them. Attempting to send such objects over IPC will result in an error. The main process handles it by listening for `channel` with the -[`ipcMain`](ipc-main.md) module. +[`ipcMain`](./ipc-main.md) module. If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRenderer.postMessage`](#ipcrendererpostmessagechannel-message-transfer). @@ -98,7 +105,7 @@ throw an exception. > them. Attempting to send such objects over IPC will result in an error. The main process should listen for `channel` with -[`ipcMain.handle()`](ipc-main.md#ipcmainhandlechannel-listener). +[`ipcMain.handle()`](./ipc-main.md#ipcmainhandlechannel-listener). For example: @@ -124,11 +131,11 @@ If you do not need a response to the message, consider using [`ipcRenderer.send` * `channel` string * `...args` any[] -Returns `any` - The value sent back by the [`ipcMain`](ipc-main.md) handler. +Returns `any` - The value sent back by the [`ipcMain`](./ipc-main.md) handler. Send a message to the main process via `channel` and expect a result synchronously. Arguments will be serialized with the [Structured Clone -Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will not be +Algorithm][SCA], just like [`window.postMessage`], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. @@ -140,13 +147,13 @@ throw an exception. > Electron's IPC to the main process, as the main process would have no way to decode > them. Attempting to send such objects over IPC will result in an error. -The main process handles it by listening for `channel` with [`ipcMain`](ipc-main.md) module, +The main process handles it by listening for `channel` with [`ipcMain`](./ipc-main.md) module, and replies by setting `event.returnValue`. > :warning: **WARNING**: Sending a synchronous message will block the whole > renderer process until the reply is received, so use this method only as a > last resort. It's much better to use the asynchronous version, -> [`invoke()`](ipc-renderer.md#ipcrendererinvokechannel-args). +> [`invoke()`](./ipc-renderer.md#ipcrendererinvokechannel-args). ### `ipcRenderer.postMessage(channel, message, [transfer])` @@ -158,7 +165,7 @@ Send a message to the main process, optionally transferring ownership of zero or more [`MessagePort`][] objects. The transferred `MessagePort` objects will be available in the main process as -[`MessagePortMain`](message-port-main.md) objects by accessing the `ports` +[`MessagePortMain`](./message-port-main.md) objects by accessing the `ports` property of the emitted event. For example: @@ -197,7 +204,7 @@ the host page instead of the main process. ## Event object The documentation for the `event` object passed to the `callback` can be found -in the [`ipc-renderer-event`](structures/ipc-renderer-event.md) structure docs. +in the [`ipc-renderer-event`](./structures/ipc-renderer-event.md) structure docs. [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter [SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm diff --git a/docs/api/native-image.md b/docs/api/native-image.md index a4d969d094e27..0ad349bb081a4 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -149,7 +149,7 @@ console.log(image) * `options` Object * `width` Integer * `height` Integer - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (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` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (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` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (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` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (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` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (optional) - Defaults to 1.0. Returns `string` - The data URL of the image. #### `image.getBitmap([options])` * `options` Object (optional) - * `scaleFactor` Double (optional) - Defaults to 1.0. + * `scaleFactor` Number (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` Double (optional) - Defaults to 1.0. +* `scaleFactor` Number (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` Double (optional) - Defaults to 1.0. +* `scaleFactor` Number (optional) - Defaults to 1.0. -Returns `Float` - The image's aspect ratio. +Returns `Number` - 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 `Float[]` - An array of all scale factors corresponding to representations for a given nativeImage. +Returns `Number[]` - An array of all scale factors corresponding to representations for a given nativeImage. #### `image.addRepresentation(options)` * `options` Object - * `scaleFactor` Double - The scale factor to add the image representation for. + * `scaleFactor` Number (optional) - 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 diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 7a2b334016191..8b0d2fbc89906 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -10,11 +10,12 @@ An example of implementing a protocol that has the same effect as the ```javascript const { app, protocol } = require('electron') const path = require('path') +const url = require('url') app.whenReady().then(() => { protocol.registerFileProtocol('atom', (request, callback) => { - const url = request.url.substr(7) - callback({ path: path.normalize(`${__dirname}/${url}`) }) + const filePath = url.fileURLToPath('file://' + request.url.slice('atom://'.length)) + callback(filePath) }) }) ``` @@ -175,7 +176,7 @@ property. * `handler` Function * `request` [ProtocolRequest](structures/protocol-request.md) * `callback` Function - * `response` ProtocolResponse + * `response` [ProtocolResponse](structures/protocol-response.md) Returns `boolean` - Whether the protocol was successfully registered diff --git a/docs/api/push-notifications.md b/docs/api/push-notifications.md new file mode 100644 index 0000000000000..cad396bc03d56 --- /dev/null +++ b/docs/api/push-notifications.md @@ -0,0 +1,48 @@ +# 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 diff --git a/docs/api/safe-storage.md b/docs/api/safe-storage.md index e96c18bbf0795..471351c9c1cd3 100644 --- a/docs/api/safe-storage.md +++ b/docs/api/safe-storage.md @@ -18,8 +18,8 @@ The `safeStorage` module has the following methods: Returns `boolean` - Whether encryption is available. -On Linux, returns true if the secret key is -available. On MacOS, returns true if Keychain is available. +On Linux, returns true if the app has emitted the `ready` event and the secret key is available. +On MacOS, returns true if Keychain is available. On Windows, returns true once the app has emitted the `ready` event. ### `safeStorage.encryptString(plainText)` diff --git a/docs/api/session.md b/docs/api/session.md index 8bb1ad5ab3c5c..ee1c3e7a8b347 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -253,9 +253,11 @@ Returns: * `device` [HIDDevice[]](structures/hid-device.md) * `frame` [WebFrameMain](web-frame-main.md) -Emitted when a new HID device becomes available. For example, when a new USB device is plugged in. - -This event will only be emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired. +Emitted after `navigator.hid.requestDevice` has been called and +`select-hid-device` has fired if a new device becomes available before +the callback from `select-hid-device` is called. This event is intended for +use when using a UI to ask users to pick a device so that the UI can be updated +with the newly added device. #### Event: 'hid-device-removed' @@ -266,9 +268,24 @@ Returns: * `device` [HIDDevice[]](structures/hid-device.md) * `frame` [WebFrameMain](web-frame-main.md) -Emitted when a HID device has been removed. For example, this event will fire when a USB device is unplugged. +Emitted after `navigator.hid.requestDevice` has been called and +`select-hid-device` has fired if a device has been removed before the callback +from `select-hid-device` is called. This event is intended for use when using +a UI to ask users to pick a device so that the UI can be updated to remove the +specified device. + +#### Event: 'hid-device-revoked' + +Returns: + +* `event` Event +* `details` Object + * `device` [HIDDevice[]](structures/hid-device.md) + * `origin` string (optional) - The origin that the device has been revoked from. -This event will only be emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired. +Emitted after `HIDDevice.forget()` has been called. This event can be used +to help maintain persistent storage of permissions when +`setDevicePermissionHandler` is used. #### Event: 'select-serial-port' @@ -348,7 +365,11 @@ Returns: * `port` [SerialPort](structures/serial-port.md) * `webContents` [WebContents](web-contents.md) -Emitted after `navigator.serial.requestPort` has been called and `select-serial-port` has fired if a new serial port becomes available. For example, this event will fire when a new USB device is plugged in. +Emitted after `navigator.serial.requestPort` has been called and +`select-serial-port` has fired if a new serial port becomes available before +the callback from `select-serial-port` is called. This event is intended for +use when using a UI to ask users to pick a port so that the UI can be updated +with the newly added port. #### Event: 'serial-port-removed' @@ -358,7 +379,11 @@ Returns: * `port` [SerialPort](structures/serial-port.md) * `webContents` [WebContents](web-contents.md) -Emitted after `navigator.serial.requestPort` has been called and `select-serial-port` has fired if a serial port has been removed. For example, this event will fire when a USB device is unplugged. +Emitted after `navigator.serial.requestPort` has been called and +`select-serial-port` has fired if a serial port has been removed before the +callback from `select-serial-port` is called. This event is intended for use +when using a UI to ask users to pick a port so that the UI can be updated +to remove the specified port. ### Instance Methods @@ -567,7 +592,7 @@ the original network configuration. * `errorCode` Integer - Error code. * `callback` Function * `verificationResult` Integer - Value can be one of certificate error codes - from [here](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). + from [here](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). Apart from the certificate error codes, the following special codes can be used. * `0` - Indicates success and disables Certificate Transparency verification. * `-2` - Indicates failure. @@ -610,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. + * `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. * `fullscreen` - Request for the app to enter fullscreen mode. * `openExternal` - Request to open links in external applications. * `unknown` - An unrecognized permission request @@ -680,7 +705,6 @@ 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. @@ -688,8 +712,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 through the lifetime -of the corresponding WebContents. If longer term storage is needed, a developer can store granted device +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 permissions (eg when handling the `select-hid-device` event) and then read from that storage with `setDevicePermissionHandler`. ```javascript @@ -745,6 +769,71 @@ app.whenReady().then(() => { }) ``` +#### `ses.setBluetoothPairingHandler(handler)` _Windows_ _Linux_ + +* `handler` Function | null + * `details` Object + * `deviceId` string + * `pairingKind` string - The type of pairing prompt being requested. + One of the following values: + * `confirm` + This prompt is requesting confirmation that the Bluetooth device should + be paired. + * `confirmPin` + This prompt is requesting confirmation that the provided PIN matches the + pin displayed on the device. + * `providePin` + This prompt is requesting that a pin be provided for the device. + * `frame` [WebFrameMain](web-frame-main.md) + * `pin` string (optional) - The pin value to verify if `pairingKind` is `confirmPin`. + * `callback` Function + * `response` Object + * `confirmed` boolean - `false` should be passed in if the dialog is canceled. + If the `pairingKind` is `confirm` or `confirmPin`, this value should indicate + if the pairing is confirmed. If the `pairingKind` is `providePin` the value + should be `true` when a value is provided. + * `pin` string | null (optional) - When the `pairingKind` is `providePin` + this value should be the required pin for the Bluetooth device. + +Sets a handler to respond to Bluetooth pairing requests. This handler +allows developers to handle devices that require additional validation +before pairing. When a handler is not defined, any pairing on Linux or Windows +that requires additional validation will be automatically cancelled. +macOS does not require a handler because macOS handles the pairing +automatically. To clear the handler, call `setBluetoothPairingHandler(null)`. + +```javascript + +const { app, BrowserWindow, ipcMain, session } = require('electron') + +let bluetoothPinCallback = null + +function createWindow () { + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) +} + +// Listen for an IPC message from the renderer to get the response for the Bluetooth pairing. +ipcMain.on('bluetooth-pairing-response', (event, response) => { + bluetoothPinCallback(response) +}) + +mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => { + bluetoothPinCallback = callback + // Send a IPC message to the renderer to prompt the user to confirm the pairing. + // Note that this will require logic in the renderer to handle this message and + // display a prompt to the user. + mainWindow.webContents.send('bluetooth-pairing-request', details) +}) + +app.whenReady().then(() => { + createWindow() +}) +``` + #### `ses.clearHostResolverCache()` Returns `Promise<void>` - Resolves when the operation is complete. @@ -908,7 +997,7 @@ Returns `string[]` - An array of language codes the spellchecker is enabled for. will fallback to using `en-US`. By default on launch if this setting is an empty list Electron will try to populate this setting with the current OS locale. This setting is persisted across restarts. -**Note:** On macOS the OS spellchecker is used and has its own list of languages. This API is a no-op on macOS. +**Note:** On macOS the OS spellchecker is used and has its own list of languages. On macOS, this API will return whichever languages have been configured by the OS. #### `ses.setSpellCheckerDictionaryDownloadURL(url)` @@ -1025,7 +1114,7 @@ is emitted. #### `ses.getStoragePath()` -A `string | null` indicating the absolute file system path where data for this +Returns `string | null` - The absolute file system path where data for this session is persisted on disk. For in memory sessions this returns `null`. ### Instance Properties diff --git a/docs/api/structures/protocol-response.md b/docs/api/structures/protocol-response.md index a20873ebb3b46..21a863240fabb 100644 --- a/docs/api/structures/protocol-response.md +++ b/docs/api/structures/protocol-response.md @@ -31,4 +31,4 @@ * `uploadData` [ProtocolResponseUploadData](protocol-response-upload-data.md) (optional) - The data used as upload data. This is only used for URL responses when `method` is `"POST"`. -[net-error]: https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h +[net-error]: https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h diff --git a/docs/api/structures/trace-config.md b/docs/api/structures/trace-config.md index d5b3795f228fd..4160b7121ca57 100644 --- a/docs/api/structures/trace-config.md +++ b/docs/api/structures/trace-config.md @@ -8,7 +8,7 @@ * `enable_argument_filter` boolean (optional) - if true, filter event data according to a specific list of events that have been manually vetted to not include any PII. See [the implementation in - Chromium][trace_event_args_whitelist.cc] for specifics. + Chromium][trace_event_args_allowlist.cc] for specifics. * `included_categories` string[] (optional) - a list of tracing categories to include. Can include glob-like patterns using `*` at the end of the category name. See [tracing categories][] for the list of categories. @@ -45,7 +45,7 @@ An example TraceConfig that roughly matches what Chrome DevTools records: } ``` -[tracing categories]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/builtin_categories.h -[memory-infra docs]: https://chromium.googlesource.com/chromium/src/+/master/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way -[trace_event_args_whitelist.cc]: https://chromium.googlesource.com/chromium/src/+/master/services/tracing/public/cpp/trace_event_args_whitelist.cc +[tracing categories]: https://chromium.googlesource.com/chromium/src/+/main/base/trace_event/builtin_categories.h +[memory-infra docs]: https://chromium.googlesource.com/chromium/src/+/main/docs/memory-infra/memory_infra_startup_tracing.md#the-advanced-way +[trace_event_args_allowlist.cc]: https://chromium.googlesource.com/chromium/src/+/main/services/tracing/public/cpp/trace_event_args_allowlist.cc [histogram]: https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md diff --git a/docs/api/system-preferences.md b/docs/api/system-preferences.md index 69124edda9f87..6c0a6a388fb46 100644 --- a/docs/api/system-preferences.md +++ b/docs/api/system-preferences.md @@ -183,11 +183,11 @@ Some popular `key` and `type`s are: * `NSPreferredWebServices`: `dictionary` * `NSUserDictionaryReplacementItems`: `array` -### `systemPreferences.setUserDefault(key, type, value)` _macOS_ +### `systemPreferences.setUserDefault<Type extends keyof UserDefaultTypes>(key, type, value)` _macOS_ * `key` string -* `type` string - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array` or `dictionary`. -* `value` string +* `type` Type - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array` or `dictionary`. +* `value` UserDefaultTypes[Type] Set the value of `key` in `NSUserDefaults`. diff --git a/docs/api/tray.md b/docs/api/tray.md index d8dac322f769d..0cb995ce2fb3d 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -25,15 +25,20 @@ app.whenReady().then(() => { }) ``` -__Platform limitations:__ +__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__ -* 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. -* 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, +* The `click` event is ignored when using the app indicator. +* In order for changes made to individual `MenuItem`s to take effect, you have to call `setContextMenu` again. For example: ```javascript @@ -55,10 +60,16 @@ app.whenReady().then(() => { }) ``` -* On Windows it is recommended to use `ICO` icons to get best visual effects. +__MacOS__ -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. +* 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. ### `new Tray(image, [guid])` diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index d4a1233c5976a..37e5137340a23 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -35,7 +35,7 @@ for all windows, webviews, opened devtools, and devtools extension background pa ### `webContents.getFocusedWebContents()` -Returns `WebContents` - The web contents that is focused in this application, otherwise +Returns `WebContents` | null - The web contents that is focused in this application, otherwise returns `null`. ### `webContents.fromId(id)` @@ -45,6 +45,13 @@ returns `null`. Returns `WebContents` | undefined - A WebContents instance with the given ID, or `undefined` if there is no WebContents associated with the given ID. +### `webContents.fromFrame(frame)` + +* `frame` WebFrameMain + +Returns `WebContents` | undefined - A WebContents instance with the given WebFrameMain, or +`undefined` if there is no WebContents associated with the given WebFrameMain. + ### `webContents.fromDevToolsTargetId(targetId)` * `targetId` string - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance. @@ -92,7 +99,7 @@ Returns: * `frameRoutingId` Integer This event is like `did-finish-load` but emitted when the load failed. -The full list of error codes and their meaning is available [here](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h). +The full list of error codes and their meaning is available [here](https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h). #### Event: 'did-fail-provisional-load' @@ -820,9 +827,6 @@ This event can be used to configure `webPreferences` for the `webContents` of a `<webview>` before it's loaded, and provides the ability to set settings that can't be set via `<webview>` attributes. -**Note:** The specified `preload` script option will appear as `preloadURL` -(not `preload`) in the `webPreferences` object emitted with this event. - #### Event: 'did-attach-webview' Returns: @@ -865,6 +869,8 @@ 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: @@ -875,6 +881,8 @@ 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: @@ -1431,7 +1439,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`. + `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`. * `callback` Function (optional) * `success` boolean - Indicates success of the print call. * `failureReason` string - Error description called back if the print fails. @@ -1462,43 +1470,28 @@ win.webContents.print(options, (success, errorType) => { #### `contents.printToPDF(options)` * `options` Object - * `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. + * `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. Returns `Promise<Buffer>` - Resolves with the generated PDF data. -Prints window's web page as PDF with Chromium's preview printing custom -settings. +Prints the window's web page as PDF. 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 @@ -1507,7 +1500,7 @@ const fs = require('fs') const path = require('path') const os = require('os') -const win = new BrowserWindow({ width: 800, height: 600 }) +const win = new BrowserWindow() win.loadURL('http://github.com') win.webContents.on('did-finish-load', () => { @@ -1524,6 +1517,8 @@ 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 @@ -1638,6 +1633,8 @@ Opens the devtools. When `contents` is a `<webview>` tag, the `mode` would be `detach` by default, explicitly passing an empty `mode` can force using last used dock state. +On Windows, if Windows Control Overlay is enabled, Devtools will be opened with `mode: 'detach'`. + #### `contents.closeDevTools()` Closes the devtools. @@ -2001,6 +1998,35 @@ 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. @@ -2060,6 +2086,11 @@ when the page becomes backgrounded. This also affects the Page Visibility API. A [`WebFrameMain`](web-frame-main.md) property that represents the top frame of the page's frame hierarchy. +#### `contents.opener` _Readonly_ + +A [`WebFrameMain`](web-frame-main.md) property that represents the frame that opened this WebContents, either +with open(), or by navigating a link with a target attribute. + [keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter [SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm diff --git a/docs/api/web-frame-main.md b/docs/api/web-frame-main.md index a3fd055d80134..3d3b87b354028 100644 --- a/docs/api/web-frame-main.md +++ b/docs/api/web-frame-main.md @@ -16,7 +16,7 @@ win.loadURL('https://twitter.com') win.webContents.on( 'did-frame-navigate', - (event, url, isMainFrame, frameProcessId, frameRoutingId) => { + (event, url, httpResponseCode, httpStatusText, isMainFrame, frameProcessId, frameRoutingId) => { const frame = webFrameMain.fromId(frameProcessId, frameRoutingId) if (frame) { const code = 'document.body.innerHTML = document.body.innerHTML.replaceAll("heck", "h*ck")' @@ -140,10 +140,45 @@ 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. +#### `frame.origin` _Readonly_ + +A `string` representing the current origin of the frame, serialized according +to [RFC 6454](https://www.rfc-editor.org/rfc/rfc6454). This may be different +from the URL. For instance, if the frame is a child window opened to +`about:blank`, then `frame.origin` will return the parent frame's origin, while +`frame.url` will return the empty string. Pages without a scheme/host/port +triple origin will have the serialized origin of `"null"` (that is, the string +containing the letters n, u, l, l). + #### `frame.top` _Readonly_ A `WebFrameMain | null` representing top frame in the frame hierarchy to which `frame` @@ -195,3 +230,6 @@ have the same `routingId`. A `string` representing the [visibility state](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState) of the frame. See also how the [Page Visibility API](browser-window.md#page-visibility) is affected by other Electron APIs. + +[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm +[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index b59d98c54cb60..06bf313547d01 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -110,7 +110,7 @@ webFrame.setSpellCheckProvider('en-US', { }) ``` -#### `webFrame.insertCSS(css[, options])` +### `webFrame.insertCSS(css[, options])` * `css` string * `options` Object (optional) diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index fd90e8b5d5660..cc86a05d5be4d 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -158,9 +158,6 @@ When the guest page doesn't have node integration this script will still have access to all Node APIs, but global objects injected by Node will be deleted after this script has finished executing. -**Note:** This option will appear as `preloadURL` (not `preload`) in -the `webPreferences` specified to the `will-attach-webview` event. - ### `httpreferrer` ```html @@ -559,7 +556,7 @@ Stops any `findInPage` request for the `webview` with the provided `action`. * `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`. + `A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` in microns. Returns `Promise<void>` @@ -568,21 +565,21 @@ Prints `webview`'s web page. Same as `webContents.print([options])`. ### `<webview>.printToPDF(options)` * `options` Object - * `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. + * `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. Returns `Promise<Uint8Array>` - Resolves with the generated PDF data. diff --git a/docs/api/window-open.md b/docs/api/window-open.md index a2cb76a2a569e..1925a5d1e7e5d 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -73,6 +73,11 @@ creating the window. Note that this is more powerful than passing options through the feature string, as the renderer has more limited privileges in deciding security preferences than the main process. +In addition to passing in `action` and `overrideBrowserWindowOptions`, +`outlivesOpener` can be passed like: `{ action: 'allow', outlivesOpener: true, +overrideBrowserWindowOptions: { ... } }`. If set to `true`, the newly created +window will not close when the opener window closes. The default value is `false`. + ### Native `Window` example ```javascript diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index c448a5303836e..c6c511b32bb18 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -14,6 +14,68 @@ 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 @@ -34,9 +96,19 @@ 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) -*None (yet)* +### 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). ## Planned Breaking API Changes (18.0) @@ -372,7 +444,7 @@ value. In Electron 12, `contextIsolation` will be enabled by default. To restore the previous behavior, `contextIsolation: false` must be specified in WebPreferences. -We [recommend having contextIsolation enabled](tutorial/security.md#3-enable-context-isolation-for-remote-content) for the security of your application. +We [recommend having contextIsolation enabled](tutorial/security.md#3-enable-context-isolation) for the security of your application. Another implication is that `require()` cannot be used in the renderer process unless `nodeIntegration` is `true` and `contextIsolation` is `false`. @@ -1203,6 +1275,10 @@ 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. diff --git a/docs/development/Electronite/ElectroniteBuildNotes.md b/docs/development/Electronite/ElectroniteBuildNotes.md index f1ba71ad9c76f..dca7aab1fb4fb 100644 --- a/docs/development/Electronite/ElectroniteBuildNotes.md +++ b/docs/development/Electronite/ElectroniteBuildNotes.md @@ -26,7 +26,7 @@ The simplest way to update Electronite is to pull down the branch from upstream Updating Electronite is pretty straight forward. 1. Get the version of Electron that you want to update to, e.g. `git checkout upstream v12.0.5`. -2. Branch from Electron `git checkout -b electronite-12.0.5` +2. Create new electronite branch from Electron `git checkout -b electronite-v12.0.5` 3. Apply the [Graphite Patch](https://github.com/unfoldingWord/electronite/wiki/Graphite-Patch) `git am add-graphite-to-electron.patch` (you might need to manually apply it if there are conflicting changes from upstream). 4. Build and test the Electronite branch (see below). 5. If everything is working properly, push the branch and tag the release using the proper naming convention, and create a new release based on your new tag with the compiled binaries attached to it. @@ -34,7 +34,7 @@ Updating Electronite is pretty straight forward. # Building -[Build Notes](https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/Electronite/ElectroniteCurrentVersionBuildNotes.md) +[Build Notes](ElectroniteCurrentVersionBuildNotes.md) # Other Electronite Steps diff --git a/docs/development/Electronite/ElectroniteCurrentVersionBuildNotes.md b/docs/development/Electronite/ElectroniteCurrentVersionBuildNotes.md index f117f24968d7c..e65ddab30cbe8 100644 --- a/docs/development/Electronite/ElectroniteCurrentVersionBuildNotes.md +++ b/docs/development/Electronite/ElectroniteCurrentVersionBuildNotes.md @@ -6,9 +6,9 @@ Based on wiki notes for `electronite-v12.0.5` from: https://github.com/unfolding # Building -- Windows build notes: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/Electronite/WindowsBuildNotes.md -- MacOS build notes: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/Electronite/MacBuildNotes.md -- Linux build notes: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/Electronite/LinuxBuildNotes.md +- [Windows build notes](WindowsBuildNotes.md) +- [MacOS build notes](MacBuildNotes.md) +- [Linux build notes](LinuxBuildNotes.md) Running the scripts without arguments will display the following commands which you will generally want to execute in order: 1. `get <ref>` fetches all of the code. Where `<ref>` is a branch or tag. diff --git a/docs/development/Electronite/LinuxBuildNotes.md b/docs/development/Electronite/LinuxBuildNotes.md index e2d5a2dcf7dc2..6ba6ebe0286c2 100644 --- a/docs/development/Electronite/LinuxBuildNotes.md +++ b/docs/development/Electronite/LinuxBuildNotes.md @@ -1,8 +1,8 @@ ## Building Electronite on Linux ### Setup on Clean Linux VM -- Configured my VM using these notes as a reference: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/build-instructions-linux.md +- Configured my VM using these notes as a reference: [build-instructions-linux](../build-instructions-linux.md) - Make sure the VM has a lot of disk space - I ran out of disk space with 60GB of storage configured. Rather than starting over with a new VM. I added a second Virtual Hard Drive with 100GB and then used that drive for the builds. -- if you have trouble building with these notes, you could try the older Chromium Build tools: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/Electronite/LinuxBuildNotesChromeTools.md +- if you have trouble building with these notes, you could try the older Chromium Build tools: [LinuxBuildNotesChromeTools](LinuxBuildNotesChromeTools.md) - if you get warning that you need to upgrade to newer g++, here's an example of how to upgrade to g++ 10: ``` sudo apt install build-essential @@ -13,154 +13,80 @@ g++ --version - to create `arm64` and `arm` builds, you must have installed the arm dependencies mentioned in the Linux build instructions above. Then run: - install and configure python: ``` -sudo apt install python python3.9 +sudo apt install python python3 python3-pip pip3 install --user --upgrade pip pip3 install --user pyobjc +pip3 install importlib-metadata ``` +- use node v16 (had build problems with latest v18) - installed electron build-tools (https://github.com/electron/build-tools): ``` +npm i -g yarn npm i -g @electron/build-tools ``` + - if e commands don’t work, try this and then initialization seemed to work: ``` git clone https://github.com/electron/build-tools ~/.electron_build_tools && (cd ~/.electron_build_tools && npm install) ``` -#### Monitoring Goma status -- if you browse to http://localhost:8088 on your local machine you can monitor compile jobs as they flow through the goma system. +- note 32-bit builds for Linux no longer supported. ### Build Electronite -#### Build x64 -- open terminal and initialize build configuration (note that if you have a slow or unreliable internet connection, it is better to change the goma setting from `cache-only` to `none`): -``` -e init --root=~/Develop/Electronite-Build -o x64 x64 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f -``` - -- edit `~/.electron_build_tools/configs/evm.x64.json` - and add option to args: `"target_cpu = \"x64\""` -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): -``` -e sync -``` - -- checkout the correct Electronite tag -``` -cd ~/Develop/Electronite-Build/src/electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ../.. -``` +- first make sure you have downloaded the current version of electronite-tools-2.sh. There may have been changes from other electronite versions. -- now get the Electronite sources +#### Build x64 +- get the Electronite source code for branch (this can take many hours the first time as the git cache is loaded): ``` -e sync +export PATH=$PATH:~/.electron_build_tools/third_party/depot_tools:~/.electron_build_tools/src +e init --root=~/Develop/Electronite-Build -o x64 x64 -i release --goma none --fork unfoldingWord/electronite --use-https -f +./electronite-tools-2.sh get electronite-v21.2.0-beta ``` - Do build (takes a long time) ``` -e use x64 -export NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron +./electronite-tools-2.sh build x64 +./electronite-tools-2.sh release x64 ``` -- Make the release to ~/Develop/Electronite-Build/src/out/x64/dist.zip -``` -./src/electron/script/strip-binaries.py -d src/out/x64 -e build electron:dist -``` - -#### Build x86 -- open terminal and initialize build configuration (note that if you have a slow or unreliable internet connection, it is better to change the goma setting from `cache-only` to `none`): -``` -sudo apt-get install ia32-libs-gtk ia32-libs -e init --root=~/Develop/Electronite-Build -o x86 x86 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f -``` +- Test the build. + - Do `cd src/out/Release-x64 && ./electron`. + - Open the developer console by typing`Control-Shift-I`. + - in console execute `window.location="https://scripts.sil.org/cms/scripts/page.php?site_id=projects&item_id=graphite_fontdemo"` + - Ensure all the tests pass by visually inspecting the rendered fonts and comparing against the image samples on the site. + - The example for Padauk from server will not be correct with the triangles. So need to: + Open elements tab, select body of html, do Control-F to search, and search for `padauk_ttf`, and apply attribute `font-feature-settings: "wtri" 1;`. The triangles should now be rendered correctly. -- edit `~/.electron_build_tools/configs/evm.x86.json` - and add option to args: `"target_cpu = \"x86\""` -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): -``` -e sync -``` - -- to create `x86` builds, you must have installed the x86 dependencies mentioned in the Linux build instructions above. Then run: -``` -cd ./src -build/linux/sysroot_scripts/install-sysroot.py --arch=x86 -cd .. -``` - -- checkout the correct Electronite tag -``` -cd ~/Develop/Electronite-Build/src/electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ../.. -``` - -- now get the Electronite sources -``` -e sync -``` - -- Do build (takes a long time) -``` -e use x86 -export NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron -``` - -- Make the release to ~/Develop/Electronite-Build/src/out/x86/dist.zip -``` -./src/electron/script/strip-binaries.py --target-cpu=x86 -d src/out/x86 -e build electron:dist -``` +- The release is at ~/Develop/Electronite-Build/src/out/Release-x64/dist.zip #### Build Arm64 - open terminal and initialize build configuration (note that if you have a slow or unreliable internet connection, it is better to change the goma setting from `cache-only` to `none`): ``` sudo apt-get install binutils-aarch64-linux-gnu -e init --root=~/Develop/Electronite-Build -o arm64 arm64 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f ``` -- edit `~/.electron_build_tools/configs/evm.arm64.json` - and add option to args: `"target_cpu = \"arm64\""` -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): +- if Electronite source already checked out, then skip to `Build Init` step. + +- get the Electronite source code for branch (this can take many hours the first time as the git cache is loaded): ``` -e sync +export PATH=$PATH:~/.electron_build_tools/third_party/depot_tools:~/.electron_build_tools/src +e init --root=~/Develop/Electronite-Build -o x64 x64 -i release --goma none --fork unfoldingWord/electronite --use-https -f +./electronite-tools-2.sh get electronite-v21.2.0-beta ``` -- to create `arm64` builds, you must have installed the arm64 dependencies mentioned in the Linux build instructions above. Then run: +- Build Init: to create `arm64` builds, you must have installed the arm64 dependencies mentioned in the Linux build instructions above. Then run: ``` cd ./src build/linux/sysroot_scripts/install-sysroot.py --arch=arm64 cd .. ``` -- checkout the correct Electronite tag -``` -cd ~/Develop/Electronite-Build/src/electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ../.. -``` - -- now get the Electronite sources -``` -e sync -``` - - Do build (takes a long time) ``` -e use arm64 -export NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron +./electronite-tools-2.sh build arm64 +./electronite-tools-2.sh release arm64 ``` -- Make the release to ~/Develop/Electronite-Build/src/out/arm64/dist.zip -``` -./src/electron/script/strip-binaries.py --target-cpu=arm64 -d src/out/arm64 -e build electron:dist -``` +- The release is at ~/Develop/Electronite-Build/src/out/Release-arm64/dist.zip diff --git a/docs/development/Electronite/LinuxBuildNotesChromeTools.md b/docs/development/Electronite/LinuxBuildNotesChromeTools.md index d781478a95c6e..910c0b476d497 100644 --- a/docs/development/Electronite/LinuxBuildNotesChromeTools.md +++ b/docs/development/Electronite/LinuxBuildNotesChromeTools.md @@ -1,12 +1,12 @@ ## Building Electronite on Linux ### Setup on Linux VM -- Configured my VM using these notes as a reference: https://github.com/unfoldingWord/electronite/blob/v17.3.1-graphite/docs/development/build-instructions-linux.md +- Configured my VM using these notes as a reference: [build-instructions-linux](../build-instructions-linux.md){ - Make sure the VM has a lot of disk space - I ran out of disk space with 60GB of storage configured. Rather than starting over with a new VM. I added a second Virtual Hard Drive with 100GB and then used that drive for the builds. ### Build Electronite - open terminal and cd to the folder you will use for build - install the depot_tools here: `git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git` -- download build script to this folder from: https://github.com/unfoldingWord/electronite/blob/v17.3.1-graphite/docs/development/Electronite/electronite-tools.sh +- download build script to this folder from: [electronite-tools](electronite-tools.sh) - set execute permission on script: `chmod +x ./electronite-tools.sh` - before build do: `export PATH=/path/to/depot_tools:$PATH` - get source files (this can take several hours the first time as the git cache is loaded): `./electronite-tools.sh get <<build-tag>>` @@ -25,7 +25,12 @@ cd ../.. - builds can take over 20 hours on a VM. - build Electronite for Intel 64-bit: - build for 64-bit: `./electronite-tools.sh build x64` - - create release for 32-bit: `./electronite-tools.sh release x64` + - create release for 64-bit: `./electronite-tools.sh release x64` + +- build Electronite for Intel 32-bit: + - initialize build configuration: `sudo apt-get install ia32-libs-gtk ia32-libs` + - build for 32-bit: `./electronite-tools.sh build x86` + - create release for 32-bit: `./electronite-tools.sh release x86` - build Electronite for Arm 64-bit: - build for arm 64-bit: `./electronite-tools.sh build arm64` diff --git a/docs/development/Electronite/MacBuildNotes.md b/docs/development/Electronite/MacBuildNotes.md index c5d22c6c5cb90..975ea40b4ad6a 100644 --- a/docs/development/Electronite/MacBuildNotes.md +++ b/docs/development/Electronite/MacBuildNotes.md @@ -1,17 +1,18 @@ ## Building Electronite on MacOS -### Setup on MacOS Monterey -- Configured using these notes as a reference: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/build-instructions-macos.md +### Setup on MacOS Big Sur +- Configured using these notes as a reference: [build-instructions-macos](../build-instructions-macos.md) +- Can build on Monterey - Building for x64 does not work on M1 Silicon Macs, only for Arm64. On Intel based Macs can build for both Arm64 and Intel x64 - Make sure you have a lot of free disk space - need over 150GB free. -- if you have trouble building with these notes, you could try the older Chromium Build tools: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/Electronite/MacBuildNotesChromeTools.md +- if you have trouble building with these notes, you could try the older Chromium Build tools: [MacBuildNotesChromeTools](MacBuildNotesChromeTools.md) - installed node using nvm - install nvm: `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash` - restart terminal - - install latest stable node: + - install v16 (had build problems with latest v18): ``` -nvm install --lts -nvm use --lts +nvm install v16 +nvm use v16 node --version ``` - installed homebrew: `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"` @@ -20,9 +21,12 @@ node --version ``` pip3 install --user --upgrade pip pip3 install --user pyobjc +pip3 install importlib-metadata ``` - installed electron build-tools (https://github.com/electron/build-tools): ``` +xcode-select --install +npm i -g yarn sudo npm i -g @electron/build-tools ``` @@ -36,79 +40,46 @@ git clone https://github.com/electron/build-tools ~/.electron_build_tools && (cd ### Build Electronite -#### Build Arm64 -- open terminal and initialize build (on M1 Mac, had to use `--goma none`, and it may be faster if you have a slow or unreliable internet connection): -``` -e init --root=~/Develop/Electronite-Build -o arm64 arm64 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f -``` - -- edit `~/.electron_build_tools/configs/evm.arm64.json` -and add option to args: `"target_cpu = \"arm64\""` -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): -``` -e sync -``` +- first make sure you have downloaded the current version of electronite-tools-2.sh. There may have been changes from other electronite versions. -- checkout the correct Electronite tag -``` -cd ~/Develop/Electronite-Build/src/electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ../.. -``` - -- now get the Electronite sources +#### Build Intel x64 +- get the Electronite source code for branch (this can take many hours the first time as the git cache is loaded): ``` -e sync +export PATH=$PATH:~/.electron_build_tools/third_party/depot_tools:~/.electron_build_tools/src +e init --root=~/Develop/Electronite-Build -o x64 x64 -i release --goma none --fork unfoldingWord/electronite --use-https -f +./electronite-tools-2.sh get electronite-v21.2.0-beta ``` - Do build (takes a long time) ``` -e use arm64 -export NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron -``` - -- Make the release to ~/Develop/Electronite-Build/src/out/arm64/dist.zip -``` -e build electron:dist +./electronite-tools-2.sh build x64 +./electronite-tools-2.sh release x64 ``` -#### Build Intel x64 -- open terminal and initialize build (on M1 Mac, had to use `--goma none`): -``` -e init --root=~/Develop/Electronite-Build -o x64 x64 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f -``` +- Test the build. + - Do `e start`. (or `open ./src/out/Release-x64/Electron.app`) + - Open the developer console by typing`Command-Alt-I`. + - in console execute `window.location="https://scripts.sil.org/cms/scripts/page.php?site_id=projects&item_id=graphite_fontdemo"` + - Ensure all the tests pass by visually inspecting the rendered fonts and comparing against the image samples on the site. + - The example for Padauk from server will not be correct with the triangles. So need to: +Open elements tab, select body of html, do command-F to search, and search for `padauk_ttf`, and apply attribute `font-feature-settings: "wtri" 1;`. The triangles should now be rendered correctly. -- edit `~/.electron_build_tools/configs/evm.x64.json` - and add option to args: `"target_cpu = \"x64\""` -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): -``` -e sync -``` +- The release is at ~/Develop/Electronite-Build/src/out/Release-x64/dist.zip -- checkout the correct Electronite tag -``` -cd ~/Develop/Electronite-Build/src/electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ../.. -``` +#### Build Arm64 +- if Electronite source already checked out, then skip to `Do build` step: -- now get the Electronite sources +- get the Electronite source code for branch (this can take many hours the first time as the git cache is loaded): ``` -e sync +export PATH=$PATH:~/.electron_build_tools/third_party/depot_tools:~/.electron_build_tools/src +e init --root=~/Develop/Electronite-Build -o x64 x64 -i release --goma none --fork unfoldingWord/electronite --use-https -f +./electronite-tools-2.sh get electronite-v21.2.0-beta ``` - Do build (takes a long time) ``` -e use x64 -export NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron -``` - -- Make the release to ~/Develop/Electronite-Build/src/out/x64/dist.zip -``` -e build electron:dist +./electronite-tools-2.sh build arm64 +./electronite-tools-2.sh release arm64 ``` +- The release is at ~/Develop/Electronite-Build/src/out/Release-arm64/dist.zip diff --git a/docs/development/Electronite/MacBuildNotesChromeTools.md b/docs/development/Electronite/MacBuildNotesChromeTools.md index c637113969ad8..9558db03dc1a6 100644 --- a/docs/development/Electronite/MacBuildNotesChromeTools.md +++ b/docs/development/Electronite/MacBuildNotesChromeTools.md @@ -1,6 +1,6 @@ ## Building Electronite on MacOS ### Setup on MacOS Catalina VM -- Configured my VM using these notes as a reference: https:https://github.com/unfoldingWord/electronite/blob/v17.3.1-graphite/docs/development/build-instructions-macos.md +- Configured my VM using these notes as a reference: [build-instructions-macos](../build-instructions-macos.md) - Make sure the VM has a lot of disk space - I was able to build with 120GB of storage configured. But only had 13GB of space at end of build, so that may not be enough in the future. - Installed xcode 12.4. - installed node using nvm @@ -23,7 +23,7 @@ pip3 install --user pyobjc ### Build Electronite - open terminal and cd to the folder you will use for build - install the depot_tools here: `git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git` -- download build script to this folder from: https://github.com/unfoldingWord/electronite/blob/v17.3.1-graphite/docs/development/Electronite/electronite-tools.sh +- download build script to this folder from: [electronite-tools](electronite-tools.sh) - set execute permission on script: `chmod +x ./electronite-tools.sh` - before build do: `export PATH=/path/to/depot_tools:$PATH` - get source files (this can take several hours the first time as the git cache is loaded): `./electronite-tools.sh get <<build-tag>>` diff --git a/docs/development/Electronite/WindowsBuildNotes.md b/docs/development/Electronite/WindowsBuildNotes.md index 0f2c5f99f577c..b2221d5dda703 100644 --- a/docs/development/Electronite/WindowsBuildNotes.md +++ b/docs/development/Electronite/WindowsBuildNotes.md @@ -2,9 +2,9 @@ ### Setup on Clean Windows 10 VM - Configured my VM using these notes as a reference: - https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md#visual-studio - - https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/build-instructions-windows.md + - [build-instructions-windows](../build-instructions-windows.md) - Make sure the VM has a lot of disk space - I configured with 220GB of storage. -- if you have trouble building with these notes, you could try the older Chromium Build tools: https://github.com/unfoldingWord/electronite/blob/v18.2.1-graphite/docs/development/Electronite/WindowsBuildNotesChromeTools.md +- if you have trouble building with these notes, you could try the older Chromium Build tools: [WindowsBuildNotesChromeTools](WindowsBuildNotesChromeTools.md) - Make sure to add exception to the build folder for Windows defender, or it will delete a couple of the build files. - Go to Start button > Settings > Update & Security > Windows Security > Virus & threat protection. - Under Virus & threat protection settings, select Manage settings, and then under Exclusions, select Add or remove exclusions. @@ -26,7 +26,7 @@ WINDOWSSDKDIR=C:\Program Files (x86)\Windows Kits\10 - installed: https://chocolatey.org/install -- Setup Build tools (using command prompt, not powershell). Install using didn't work for me: +- Setup Build tools (using command prompt, not powershell). Install using powershell didn't work for me: ``` npm i -g @electron/build-tools C: @@ -40,120 +40,64 @@ npm i - if you browse to http://localhost:8088 on your local machine you can monitor compile jobs as they flow through the goma system. ### Build Electronite -#### Build Intel x64 -- open command prompt and initialize build configuration (note that if you have a slow or unreliable internet connection, it is better to change the goma setting from `cache-only` to `none`): -``` -e init --root=.\Build-Electron -o x64 x64 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f -``` +- first make sure you have downloaded the current version of electronite-tools-2.bat. There may have been changes from other electronite versions. -- edit `~\.electron_build_tools\configs\evm.x64.json` -and add option to args: `"target_cpu = \"x64\""` - -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): -``` -e sync -``` - -- checkout the correct Electronite tag +#### Build Intel x64 +- open command prompt, cd to the build directory, and initialize build configuration: ``` -cd .\Build-Electron\src\electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ..\.. +e init --root=. -o x64 x64 -i release --goma none --fork unfoldingWord/electronite --use-https -f ``` -- now get the Electronite sources +- get the Electronite source code (this can take many hours the first time as the git cache is loaded), checkout the correct Electronite tag and get build sources ``` -e sync +.\electronite-tools-2.bat get electronite-v21.2.0-beta ``` - Do build (takes a long time) ``` -e use x64 -set NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron +.\electronite-tools-2.bat build x64 +.\electronite-tools-2.bat release x64 ``` -- Make the release to .\Build-Electron\src\out\x64\dist.zip -``` -e build electron:dist -``` - -#### Build Intel x86 (32 bit) -- open command prompt and initialize build configuration (note that if you have a slow or unreliable internet connection, it is better to change the goma setting from `cache-only` to `none`): -``` -e init --root=.\Build-Electron -o x86 x86 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f -``` - -- edit `~\.electron_build_tools\configs\evm.x86.json` - and add option to args: `"target_cpu = \"x86\""` +- Test the build. + - Do `e start`. Or open electron.exe in finder. + - Open the developer console by typing`Control-Shift-I`. + - in console execute `window.location="https://scripts.sil.org/cms/scripts/page.php?site_id=projects&item_id=graphite_fontdemo"` + - Ensure all the tests pass by visually inspecting the rendered fonts and comparing against the image samples on the site. + - The example for Padauk from server will not be correct with the triangles. So need to: + Open elements tab, select body of html, do Control-F to search, and search for `padauk_ttf`, and apply attribute `font-feature-settings: "wtri" 1;`. The triangles should now be rendered correctly. -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): -``` -e sync -``` +- The release is at .\Build-Electron\src\out\Release-x64\dist.zip -- checkout the correct Electronite tag -``` -cd .\Build-Electron\src\electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ..\.. -``` +#### Build Intel x86 (32 bit) +- if Electronite source already checked out, then skip to `Do build` step. -- now get the Electronite sources +- get the Electronite source code (this can take many hours the first time as the git cache is loaded), checkout the correct Electronite tag and get build sources ``` -e sync +.\electronite-tools-2.bat get electronite-v21.2.0-beta ``` - Do build (takes a long time) ``` -e use x86 -set NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron +.\electronite-tools-2.bat build x86 +.\electronite-tools-2.bat release x86 ``` -- Make the release to .\Build-Electron\src\out\x86\dist.zip -``` -e build electron:dist -``` +- The release is at .\Build-Electron\src\out\Release-x86\dist.zip #### Build Intel arm64 -- open command prompt and initialize build configuration (note that if you have a slow or unreliable internet connection, it is better to change the goma setting from `cache-only` to `none`): -``` -e init --root=.\Build-Electron -o arm64 arm64 -i release --goma cache-only --fork unfoldingWord/electronite --use-https -f -``` - -- edit `~\.electron_build_tools\configs\evm.arm64.json` - and add option to args: `"target_cpu = \"arm64\""` +- if Electronite source already checked out, then skip to `Do build` step. -- get the base Electron source code (this can take many hours the first time as the git cache is loaded): +-- get the Electronite source code (this can take many hours the first time as the git cache is loaded), checkout the correct Electronite tag and get build sources ``` -e sync -``` - -- checkout the correct Electronite tag -``` -cd .\Build-Electron\src\electron -git fetch --all -git checkout tags/v18.2.1-graphite -b v18.2.1-graphite -cd ..\.. -``` - -- now get the Electronite sources -``` -e sync +.\electronite-tools-2.bat get electronite-v21.2.0-beta ``` - Do build (takes a long time) ``` -e use arm64 -set NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " -e build electron +.\electronite-tools-2.bat build arm64 +.\electronite-tools-2.bat release arm64 ``` -- Make the release to .\Build-Electron\src\out\arm64\dist.zip -``` -e build electron:dist -``` +- The release is at .\Build-Electron\src\out\Release-arm64\dist.zip diff --git a/docs/development/Electronite/WindowsBuildNotesChromeTools.md b/docs/development/Electronite/WindowsBuildNotesChromeTools.md index 823b2426a4425..94affab40bb12 100644 --- a/docs/development/Electronite/WindowsBuildNotesChromeTools.md +++ b/docs/development/Electronite/WindowsBuildNotesChromeTools.md @@ -2,7 +2,7 @@ ### Setup on Clean Windows 10 VM - Configured my VM using these notes as a reference: - https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md#visual-studio - - https://github.com/unfoldingWord/electronite/blob/v17.3.1-graphite/docs/development/build-instructions-windows.md + - [build-instructions-windows](../build-instructions-windows.md) - Make sure the VM has a lot of disk space - I ran out of disk space with 120GB of storage configured. Rather than starting over with a new VM. I added a second Virtual Hard Drive with 100GB and then used that drive for the builds. - Make sure to add exception to the build folder for Windows defender, or it will delete a couple of the build files. - Add to git support for long file names: `git config --system core.longpaths true` @@ -24,7 +24,7 @@ WINDOWSSDKDIR=C:\Program Files (x86)\Windows Kits\10 - _**Note:** Use command prompt, not powershell as it will cause problems._ - cd to the folder you will use for build - unzip the depot_tools here -- download build script to this folder from: https://github.com/unfoldingWord/electronite/blob/v17.3.1-graphite/docs/development/Electronite/electronite-tools.bat +- download build script to this folder from: [electronite-tools](electronite-tools.bat) - before build do: `set PATH=%cd%\depot_tools;%PATH%` - get source files (this can take several hours the first time as the git cache is loaded): `.\electronite-tools.bat get <<build-tag>>` - builds can take over 20 hours on a VM. diff --git a/docs/development/Electronite/add_graphite_cpp_std_iterator.patch b/docs/development/Electronite/add_graphite_cpp_std_iterator.patch new file mode 100755 index 0000000000000..19bb14da416d8 --- /dev/null +++ b/docs/development/Electronite/add_graphite_cpp_std_iterator.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Thu Nov 3 15:48:39 2022 +From: Bruce <bruce.mclean@unfoldingword.org> +Date: Thu Nov 3 2022 15:48:39 -0700 +Subject: [PATCH] fix C++ std::iterator in graphite to be compatible with latest standard -- patched for v21.2.0 + +diff --git a/third_party/graphite/graphite2/src/GlyphCache.cpp b/third_party/graphite/graphite2/src/GlyphCache.cpp +index 282bdc18..336de3f1 100644 +--- a/third_party/graphite/graphite2/src/GlyphCache.cpp ++++ b/third_party/graphite/graphite2/src/GlyphCache.cpp +@@ -44,12 +44,18 @@ namespace + // variable length structures. + + template<typename W> +- class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> > ++ class _glat_iterator + { + unsigned short key() const { return uint16(be::peek<W>(_e) + _n); } + unsigned int run() const { return be::peek<W>(_e+sizeof(W)); } + void advance_entry() { _n = 0; _e = _v; be::skip<W>(_v,2); } + public: ++ using iterator_category = std::input_iterator_tag; ++ using value_type = std::pair<sparse::key_type, sparse::mapped_type>; ++ using difference_type = std::pair<sparse::key_type, sparse::mapped_type>; ++ using pointer = std::pair<sparse::key_type, sparse::mapped_type>*; ++ using reference = std::pair<sparse::key_type, sparse::mapped_type>&; ++ + _glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {} + + _glat_iterator<W> & operator ++ () { + diff --git a/docs/development/Electronite/electron.d.ts b/docs/development/Electronite/electron.d.ts index bc46d191bc13b..b6af4acc2218b 100644 --- a/docs/development/Electronite/electron.d.ts +++ b/docs/development/Electronite/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 18.2.1 +// Type definitions for Electron 21.2.0 // Project: http://electronjs.org/ // Definitions by: The Electron Team <https://github.com/electron/electron> // Definitions: https://github.com/electron/electron-typescript-definitions @@ -8,17786 +8,18115 @@ type GlobalEvent = Event & { returnValue: any }; declare namespace Electron { - const NodeEventEmitter: typeof import('events').EventEmitter; + const NodeEventEmitter: typeof import('events').EventEmitter; - class Accelerator extends String { + class Accelerator extends String { - } - interface App extends NodeJS.EventEmitter { + } + interface App extends NodeJS.EventEmitter { - // Docs: https://electronjs.org/docs/api/app + // Docs: https://electronjs.org/docs/api/app - /** - * Emitted when Chrome's accessibility support changes. This event fires when - * assistive technologies, such as screen readers, are enabled or disabled. See - * https://www.chromium.org/developers/design-documents/accessibility for more - * details. - * - * @platform darwin,win32 - */ - on(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - once(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - addListener(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - removeListener(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - /** - * Emitted when the application is activated. Various actions can trigger this - * event, such as launching the application for the first time, attempting to - * re-launch the application when it's already running, or clicking on the - * application's dock or taskbar icon. - * - * @platform darwin - */ - on(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - once(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - addListener(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - removeListener(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - /** - * Emitted during Handoff after an activity from this device was successfully - * resumed on another one. - * - * @platform darwin - */ - on(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - once(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - addListener(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - removeListener(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - /** - * Emitted before the application starts closing its windows. Calling - * `event.preventDefault()` will prevent the default behavior, which is terminating - * the application. - * - * **Note:** If application quit was initiated by `autoUpdater.quitAndInstall()`, - * then `before-quit` is emitted *after* emitting `close` event on all windows and - * closing them. - * - * **Note:** On Windows, this event will not be emitted if the app is closed due to - * a shutdown/restart of the system or a user logout. - */ - on(event: 'before-quit', listener: (event: Event) => void): this; - once(event: 'before-quit', listener: (event: Event) => void): this; - addListener(event: 'before-quit', listener: (event: Event) => void): this; - removeListener(event: 'before-quit', listener: (event: Event) => void): this; - /** - * Emitted when a browserWindow gets blurred. - */ - on(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - once(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - addListener(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - removeListener(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - /** - * Emitted when a new browserWindow is created. - */ - on(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - once(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - addListener(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - removeListener(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - /** - * Emitted when a browserWindow gets focused. - */ - on(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - once(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - addListener(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - removeListener(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - /** - * Emitted when failed to verify the `certificate` for `url`, to trust the - * certificate you should prevent the default behavior with - * `event.preventDefault()` and call `callback(true)`. - */ - on(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - once(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - addListener(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - removeListener(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - /** - * Emitted when the child process unexpectedly disappears. This is normally because - * it was crashed or killed. It does not include renderer processes. - */ - on(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - once(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - addListener(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - removeListener(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - /** - * Emitted during Handoff when an activity from a different device wants to be - * resumed. You should call `event.preventDefault()` if you want to handle this - * event. - * - * A user activity can be continued only in an app that has the same developer Team - * ID as the activity's source app and that supports the activity's type. Supported - * activity types are specified in the app's `Info.plist` under the - * `NSUserActivityTypes` key. - * - * @platform darwin - */ - on(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown, - details: ContinueActivityDetails) => void): this; - once(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown, - details: ContinueActivityDetails) => void): this; - addListener(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown, - details: ContinueActivityDetails) => void): this; - removeListener(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown, - details: ContinueActivityDetails) => void): this; - /** - * Emitted during Handoff when an activity from a different device fails to be - * resumed. - * - * @platform darwin - */ - on(event: 'continue-activity-error', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * A string with the error's localized description. - */ - error: string) => void): this; - once(event: 'continue-activity-error', listener: (event: Event, + /** + * Emitted when Chrome's accessibility support changes. This event fires when + * assistive technologies, such as screen readers, are enabled or disabled. See + * https://www.chromium.org/developers/design-documents/accessibility for more + * details. + * + * @platform darwin,win32 + */ + on(event: 'accessibility-support-changed', listener: (event: Event, /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. + * `true` when Chrome's accessibility support is enabled, `false` otherwise. */ - type: string, + accessibilitySupportEnabled: boolean) => void): this; + once(event: 'accessibility-support-changed', listener: (event: Event, /** - * A string with the error's localized description. + * `true` when Chrome's accessibility support is enabled, `false` otherwise. */ - error: string) => void): this; - addListener(event: 'continue-activity-error', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * A string with the error's localized description. - */ - error: string) => void): this; - removeListener(event: 'continue-activity-error', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * A string with the error's localized description. - */ - error: string) => void): this; - /** - * Emitted when mac application become active. Difference from `activate` event is - * that `did-become-active` is emitted every time the app becomes active, not only - * when Dock icon is clicked or application is re-launched. - * - * @platform darwin - */ - on(event: 'did-become-active', listener: (event: Event) => void): this; - once(event: 'did-become-active', listener: (event: Event) => void): this; - addListener(event: 'did-become-active', listener: (event: Event) => void): this; - removeListener(event: 'did-become-active', listener: (event: Event) => void): this; - /** - * This event will be emitted within the second instance during the call to - * `app.requestSingleInstanceLock()`, when the first instance calls the - * `ackCallback` provided by the `second-instance` event handler. - */ - on(event: 'first-instance-ack', listener: (event: Event, + accessibilitySupportEnabled: boolean) => void): this; + addListener(event: 'accessibility-support-changed', listener: (event: Event, + /** + * `true` when Chrome's accessibility support is enabled, `false` otherwise. + */ + accessibilitySupportEnabled: boolean) => void): this; + removeListener(event: 'accessibility-support-changed', listener: (event: Event, + /** + * `true` when Chrome's accessibility support is enabled, `false` otherwise. + */ + accessibilitySupportEnabled: boolean) => void): this; + /** + * Emitted when the application is activated. Various actions can trigger this + * event, such as launching the application for the first time, attempting to + * re-launch the application when it's already running, or clicking on the + * application's dock or taskbar icon. + * + * @platform darwin + */ + on(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; + once(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; + addListener(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; + removeListener(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; + /** + * Emitted during Handoff after an activity from this device was successfully + * resumed on another one. + * + * @platform darwin + */ + on(event: 'activity-was-continued', listener: (event: Event, /** - * A JSON object of additional data passed from the first instance, in response to - * the first instance's `second-instance` event. + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - additionalData: unknown) => void): this; - once(event: 'first-instance-ack', listener: (event: Event, - /** - * A JSON object of additional data passed from the first instance, in response to - * the first instance's `second-instance` event. - */ - additionalData: unknown) => void): this; - addListener(event: 'first-instance-ack', listener: (event: Event, - /** - * A JSON object of additional data passed from the first instance, in response to - * the first instance's `second-instance` event. - */ - additionalData: unknown) => void): this; - removeListener(event: 'first-instance-ack', listener: (event: Event, - /** - * A JSON object of additional data passed from the first instance, in response to - * the first instance's `second-instance` event. - */ - additionalData: unknown) => void): this; - /** - * Emitted whenever there is a GPU info update. - */ - on(event: 'gpu-info-update', listener: Function): this; - once(event: 'gpu-info-update', listener: Function): this; - addListener(event: 'gpu-info-update', listener: Function): this; - removeListener(event: 'gpu-info-update', listener: Function): this; - /** - * Emitted when the GPU process crashes or is killed. - * - * **Deprecated:** This event is superceded by the `child-process-gone` event which - * contains more information about why the child process disappeared. It isn't - * always because it crashed. The `killed` boolean can be replaced by checking - * `reason === 'killed'` when you switch to that event. - * - * @deprecated - */ - on(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - once(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - addListener(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - removeListener(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - /** - * Emitted when `webContents` wants to do basic auth. - * - * The default behavior is to cancel all authentications. To override this you - * should prevent the default behavior with `event.preventDefault()` and call - * `callback(username, password)` with the credentials. - * - * If `callback` is called without a username or password, the authentication - * request will be cancelled and the authentication error will be returned to the - * page. - */ - on(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - once(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - addListener(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - removeListener(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - /** - * Emitted when the user clicks the native macOS new tab button. The new tab button - * is only visible if the current `BrowserWindow` has a `tabbingIdentifier` - * - * @platform darwin - */ - on(event: 'new-window-for-tab', listener: (event: Event) => void): this; - once(event: 'new-window-for-tab', listener: (event: Event) => void): this; - addListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; - removeListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; - /** - * Emitted when the user wants to open a file with the application. The `open-file` - * event is usually emitted when the application is already open and the OS wants - * to reuse the application to open the file. `open-file` is also emitted when a - * file is dropped onto the dock and the application is not yet running. Make sure - * to listen for the `open-file` event very early in your application startup to - * handle this case (even before the `ready` event is emitted). - * - * You should call `event.preventDefault()` if you want to handle this event. - * - * On Windows, you have to parse `process.argv` (in the main process) to get the - * filepath. - * - * @platform darwin - */ - on(event: 'open-file', listener: (event: Event, - path: string) => void): this; - once(event: 'open-file', listener: (event: Event, - path: string) => void): this; - addListener(event: 'open-file', listener: (event: Event, - path: string) => void): this; - removeListener(event: 'open-file', listener: (event: Event, - path: string) => void): this; - /** - * Emitted when the user wants to open a URL with the application. Your - * application's `Info.plist` file must define the URL scheme within the - * `CFBundleURLTypes` key, and set `NSPrincipalClass` to `AtomApplication`. - * - * You should call `event.preventDefault()` if you want to handle this event. - * - * @platform darwin - */ - on(event: 'open-url', listener: (event: Event, - url: string) => void): this; - once(event: 'open-url', listener: (event: Event, - url: string) => void): this; - addListener(event: 'open-url', listener: (event: Event, - url: string) => void): this; - removeListener(event: 'open-url', listener: (event: Event, - url: string) => void): this; - /** - * Emitted when the application is quitting. - * - * **Note:** On Windows, this event will not be emitted if the app is closed due to - * a shutdown/restart of the system or a user logout. - */ - on(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - once(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - addListener(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - removeListener(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - /** - * Emitted once, when Electron has finished initializing. On macOS, `launchInfo` - * holds the `userInfo` of the `NSUserNotification` or information from - * `UNNotificationResponse` that was used to open the application, if it was - * launched from Notification Center. You can also call `app.isReady()` to check if - * this event has already fired and `app.whenReady()` to get a Promise that is - * fulfilled when Electron is initialized. - */ - on(event: 'ready', listener: (event: Event, - launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; - once(event: 'ready', listener: (event: Event, - launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; - addListener(event: 'ready', listener: (event: Event, - launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; - removeListener(event: 'ready', listener: (event: Event, - launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; - /** - * Emitted when the renderer process unexpectedly disappears. This is normally - * because it was crashed or killed. - */ - on(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - once(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - addListener(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - removeListener(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - /** - * Emitted when the renderer process of `webContents` crashes or is killed. - * - * **Deprecated:** This event is superceded by the `render-process-gone` event - * which contains more information about why the render process disappeared. It - * isn't always because it crashed. The `killed` boolean can be replaced by - * checking `reason === 'killed'` when you switch to that event. - * - * @deprecated - */ - on(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - once(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - addListener(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - removeListener(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - /** - * This event will be emitted inside the primary instance of your application when - * a second instance has been executed and calls `app.requestSingleInstanceLock()`. - * - * `argv` is an Array of the second instance's command line arguments, and - * `workingDirectory` is its current working directory. Usually applications - * respond to this by making their primary window focused and non-minimized. - * - * **Note:** If the second instance is started by a different user than the first, - * the `argv` array will not include the arguments. - * - * **Note:** `ackCallback` allows the user to send data back to the second instance - * during the `app.requestSingleInstanceLock()` flow. This callback can be used for - * cases where the second instance needs to obtain additional information from the - * first instance before quitting. - * - * Currently, the limit on the message size is kMaxMessageLength, or around 32kB. - * To be safe, keep the amount of data passed to 31kB at most. - * - * In order to call the callback, `event.preventDefault()` must be called, first. - * If the callback is not called in either case, `null` will be sent back. If - * `event.preventDefault()` is not called, but `ackCallback` is called by the user - * in the event, then the behaviour is undefined. - * - * This event is guaranteed to be emitted after the `ready` event of `app` gets - * emitted. - * - * **Note:** Extra command line arguments might be added by Chromium, such as - * `--original-process-start-time`. - */ - on(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string, - /** - * A JSON object of additional data passed from the second instance - */ - additionalData: unknown, - /** - * A function that can be used to send data back to the second instance - */ - ackCallback: unknown) => void): this; - once(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string, - /** - * A JSON object of additional data passed from the second instance - */ - additionalData: unknown, - /** - * A function that can be used to send data back to the second instance - */ - ackCallback: unknown) => void): this; - addListener(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string, - /** - * A JSON object of additional data passed from the second instance - */ - additionalData: unknown, - /** - * A function that can be used to send data back to the second instance - */ - ackCallback: unknown) => void): this; - removeListener(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string, - /** - * A JSON object of additional data passed from the second instance - */ - additionalData: unknown, - /** - * A function that can be used to send data back to the second instance - */ - ackCallback: unknown) => void): this; - /** - * Emitted when a client certificate is requested. - * - * The `url` corresponds to the navigation entry requesting the client certificate - * and `callback` can be called with an entry filtered from the list. Using - * `event.preventDefault()` prevents the application from using the first - * certificate from the store. - */ - on(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - once(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - addListener(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - removeListener(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - /** - * Emitted when Electron has created a new `session`. - */ - on(event: 'session-created', listener: (session: Session) => void): this; - once(event: 'session-created', listener: (session: Session) => void): this; - addListener(event: 'session-created', listener: (session: Session) => void): this; - removeListener(event: 'session-created', listener: (session: Session) => void): this; - /** - * Emitted when Handoff is about to be resumed on another device. If you need to - * update the state to be transferred, you should call `event.preventDefault()` - * immediately, construct a new `userInfo` dictionary and call - * `app.updateCurrentActivity()` in a timely manner. Otherwise, the operation will - * fail and `continue-activity-error` will be called. - * - * @platform darwin - */ - on(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - once(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - addListener(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - removeListener(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - /** - * Emitted when a new webContents is created. - */ - on(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - /** - * Emitted during Handoff before an activity from a different device wants to be - * resumed. You should call `event.preventDefault()` if you want to handle this - * event. - * - * @platform darwin - */ - on(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - once(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - addListener(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - removeListener(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - /** - * Emitted when the application has finished basic startup. On Windows and Linux, - * the `will-finish-launching` event is the same as the `ready` event; on macOS, - * this event represents the `applicationWillFinishLaunching` notification of - * `NSApplication`. You would usually set up listeners for the `open-file` and - * `open-url` events here, and start the crash reporter and auto updater. - * - * In most cases, you should do everything in the `ready` event handler. - */ - on(event: 'will-finish-launching', listener: Function): this; - once(event: 'will-finish-launching', listener: Function): this; - addListener(event: 'will-finish-launching', listener: Function): this; - removeListener(event: 'will-finish-launching', listener: Function): this; - /** - * Emitted when all windows have been closed and the application will quit. Calling - * `event.preventDefault()` will prevent the default behavior, which is terminating - * the application. - * - * See the description of the `window-all-closed` event for the differences between - * the `will-quit` and `window-all-closed` events. - * - * **Note:** On Windows, this event will not be emitted if the app is closed due to - * a shutdown/restart of the system or a user logout. - */ - on(event: 'will-quit', listener: (event: Event) => void): this; - once(event: 'will-quit', listener: (event: Event) => void): this; - addListener(event: 'will-quit', listener: (event: Event) => void): this; - removeListener(event: 'will-quit', listener: (event: Event) => void): this; - /** - * Emitted when all windows have been closed. - * - * If you do not subscribe to this event and all windows are closed, the default - * behavior is to quit the app; however, if you subscribe, you control whether the - * app quits or not. If the user pressed `Cmd + Q`, or the developer called - * `app.quit()`, Electron will first try to close all the windows and then emit the - * `will-quit` event, and in this case the `window-all-closed` event would not be - * emitted. - */ - on(event: 'window-all-closed', listener: Function): this; - once(event: 'window-all-closed', listener: Function): this; - addListener(event: 'window-all-closed', listener: Function): this; - removeListener(event: 'window-all-closed', listener: Function): this; - /** - * Adds `path` to the recent documents list. - * - * This list is managed by the OS. On Windows, you can visit the list from the task - * bar, and on macOS, you can visit it from dock menu. - * - * @platform darwin,win32 - */ - addRecentDocument(path: string): void; - /** - * Clears the recent documents list. - * - * @platform darwin,win32 - */ - clearRecentDocuments(): void; - /** - * Configures host resolution (DNS and DNS-over-HTTPS). By default, the following - * resolvers will be used, in order: - * - * * DNS-over-HTTPS, if the DNS provider supports it, then - * * the built-in resolver (enabled on macOS only by default), then - * * the system's resolver (e.g. `getaddrinfo`). - * - * This can be configured to either restrict usage of non-encrypted DNS - * (`secureDnsMode: "secure"`), or disable DNS-over-HTTPS (`secureDnsMode: "off"`). - * It is also possible to enable or disable the built-in resolver. - * - * To disable insecure DNS, you can specify a `secureDnsMode` of `"secure"`. If you - * do so, you should make sure to provide a list of DNS-over-HTTPS servers to use, - * in case the user's DNS configuration does not include a provider that supports - * DoH. - * - * This API must be called after the `ready` event is emitted. - */ - configureHostResolver(options: ConfigureHostResolverOptions): void; - /** - * By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per domain - * basis if the GPU processes crashes too frequently. This function disables that - * behavior. - * - * This method can only be called before app is ready. - */ - disableDomainBlockingFor3DAPIs(): void; - /** - * Disables hardware acceleration for current app. - * - * This method can only be called before app is ready. - */ - disableHardwareAcceleration(): void; - /** - * Enables full sandbox mode on the app. This means that all renderers will be - * launched sandboxed, regardless of the value of the `sandbox` flag in - * WebPreferences. - * - * This method can only be called before app is ready. - */ - enableSandbox(): void; - /** - * Exits immediately with `exitCode`. `exitCode` defaults to 0. - * - * All windows will be closed immediately without asking the user, and the - * `before-quit` and `will-quit` events will not be emitted. - */ - exit(exitCode?: number): void; - /** - * On Linux, focuses on the first visible window. On macOS, makes the application - * the active app. On Windows, focuses on the application's first window. - * - * You should seek to use the `steal` option as sparingly as possible. - */ - focus(options?: FocusOptions): void; - /** - * Resolve with an object containing the following: - * - * * `icon` NativeImage - the display icon of the app handling the protocol. - * * `path` string - installation path of the app handling the protocol. - * * `name` string - display name of the app handling the protocol. - * - * This method returns a promise that contains the application name, icon and path - * of the default handler for the protocol (aka URI scheme) of a URL. - * - * @platform darwin,win32 - */ - getApplicationInfoForProtocol(url: string): Promise<Electron.ApplicationInfoForProtocolReturnValue>; - /** - * Name of the application handling the protocol, or an empty string if there is no - * handler. For instance, if Electron is the default handler of the URL, this could - * be `Electron` on Windows and Mac. However, don't rely on the precise format - * which is not guaranteed to remain unchanged. Expect a different format on Linux, - * possibly with a `.desktop` suffix. - * - * This method returns the application name of the default handler for the protocol - * (aka URI scheme) of a URL. - */ - getApplicationNameForProtocol(url: string): string; - /** - * Array of `ProcessMetric` objects that correspond to memory and CPU usage - * statistics of all the processes associated with the app. - */ - getAppMetrics(): ProcessMetric[]; - /** - * The current application directory. - */ - getAppPath(): string; - /** - * The current value displayed in the counter badge. - * - * @platform linux,darwin - */ - getBadgeCount(): number; - /** - * The type of the currently running activity. - * - * @platform darwin - */ - getCurrentActivityType(): string; - /** - * fulfilled with the app's icon, which is a NativeImage. - * - * Fetches a path's associated icon. - * - * On _Windows_, there a 2 kinds of icons: - * - * * Icons associated with certain file extensions, like `.mp3`, `.png`, etc. - * * Icons inside the file itself, like `.exe`, `.dll`, `.ico`. - * - * On _Linux_ and _macOS_, icons depend on the application associated with file - * mime type. - */ - getFileIcon(path: string, options?: FileIconOptions): Promise<Electron.NativeImage>; - /** - * The Graphics Feature Status from `chrome://gpu/`. - * - * **Note:** This information is only usable after the `gpu-info-update` event is - * emitted. - */ - getGPUFeatureStatus(): GPUFeatureStatus; - /** - * For `infoType` equal to `complete`: Promise is fulfilled with `Object` - * containing all the GPU Information as in chromium's GPUInfo object. This - * includes the version and driver information that's shown on `chrome://gpu` page. - * - * For `infoType` equal to `basic`: Promise is fulfilled with `Object` containing - * fewer attributes than when requested with `complete`. Here's an example of basic - * response: - * - * Using `basic` should be preferred if only basic information like `vendorId` or - * `driverId` is needed. - */ - getGPUInfo(infoType: 'basic' | 'complete'): Promise<unknown>; - /** - * * `minItems` Integer - The minimum number of items that will be shown in the - * Jump List (for a more detailed description of this value see the MSDN docs). - * * `removedItems` JumpListItem[] - Array of `JumpListItem` objects that - * correspond to items that the user has explicitly removed from custom categories - * in the Jump List. These items must not be re-added to the Jump List in the - * **next** call to `app.setJumpList()`, Windows will not display any custom - * category that contains any of the removed items. - * - * @platform win32 - */ - getJumpListSettings(): JumpListSettings; - /** - * The current application locale, fetched using Chromium's `l10n_util` library. - * Possible return values are documented here. - * - * To set the locale, you'll want to use a command line switch at app startup, - * which may be found here. - * - * **Note:** When distributing your packaged app, you have to also ship the - * `locales` folder. - * - * **Note:** On Windows, you have to call it after the `ready` events gets emitted. - */ - getLocale(): string; - /** - * User operating system's locale two-letter ISO 3166 country code. The value is - * taken from native OS APIs. - * - * **Note:** When unable to detect locale country code, it returns empty string. - */ - getLocaleCountryCode(): string; - /** - * If you provided `path` and `args` options to `app.setLoginItemSettings`, then - * you need to pass the same arguments here for `openAtLogin` to be set correctly. - * - * - * * `openAtLogin` boolean - `true` if the app is set to open at login. - * * `openAsHidden` boolean _macOS_ - `true` if the app is set to open as hidden at - * login. This setting is not available on MAS builds. - * * `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login - * automatically. This setting is not available on MAS builds. - * * `wasOpenedAsHidden` boolean _macOS_ - `true` if the app was opened as a hidden - * login item. This indicates that the app should not open any windows at startup. - * This setting is not available on MAS builds. - * * `restoreState` boolean _macOS_ - `true` if the app was opened as a login item - * that should restore the state from the previous session. This indicates that the - * app should restore the windows that were open the last time the app was closed. - * This setting is not available on MAS builds. - * * `executableWillLaunchAtLogin` boolean _Windows_ - `true` if app is set to open - * at login and its run key is not deactivated. This differs from `openAtLogin` as - * it ignores the `args` option, this property will be true if the given executable - * would be launched at login with **any** arguments. - * * `launchItems` Object[] _Windows_ - * * `name` string _Windows_ - name value of a registry entry. - * * `path` string _Windows_ - The executable to an app that corresponds to a - * registry entry. - * * `args` string[] _Windows_ - the command-line arguments to pass to the - * executable. - * * `scope` string _Windows_ - one of `user` or `machine`. Indicates whether the - * registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. - * * `enabled` boolean _Windows_ - `true` if the app registry key is startup - * approved and therefore shows as `enabled` in Task Manager and Windows settings. - * - * @platform darwin,win32 - */ - getLoginItemSettings(options?: LoginItemSettingsOptions): LoginItemSettings; - /** - * The current application's name, which is the name in the application's - * `package.json` file. - * - * Usually the `name` field of `package.json` is a short lowercase name, according - * to the npm modules spec. You should usually also specify a `productName` field, - * which is your application's full capitalized name, and which will be preferred - * over `name` by Electron. - */ - getName(): string; - /** - * A path to a special directory or file associated with `name`. On failure, an - * `Error` is thrown. - * - * If `app.getPath('logs')` is called without called `app.setAppLogsPath()` being - * called first, a default log directory will be created equivalent to calling - * `app.setAppLogsPath()` without a `path` parameter. - */ - getPath(name: 'home' | 'appData' | 'userData' | 'cache' | 'temp' | 'exe' | 'module' | 'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos' | 'recent' | 'logs' | 'crashDumps'): string; - /** - * The version of the loaded application. If no version is found in the - * application's `package.json` file, the version of the current bundle or - * executable is returned. - */ - getVersion(): string; - /** - * This method returns whether or not this instance of your app is currently - * holding the single instance lock. You can request the lock with - * `app.requestSingleInstanceLock()` and release with - * `app.releaseSingleInstanceLock()` - */ - hasSingleInstanceLock(): boolean; - /** - * Hides all application windows without minimizing them. - * - * @platform darwin - */ - hide(): void; - /** - * Imports the certificate in pkcs12 format into the platform certificate store. - * `callback` is called with the `result` of import operation, a value of `0` - * indicates success while any other value indicates failure according to Chromium - * net_error_list. - * - * @platform linux - */ - importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; - /** - * Invalidates the current Handoff user activity. - * - * @platform darwin - */ - invalidateCurrentActivity(): void; - /** - * `true` if Chrome's accessibility support is enabled, `false` otherwise. This API - * will return `true` if the use of assistive technologies, such as screen readers, - * has been detected. See - * https://www.chromium.org/developers/design-documents/accessibility for more - * details. - * - * @platform darwin,win32 - */ - isAccessibilitySupportEnabled(): boolean; - /** - * Whether the current executable is the default handler for a protocol (aka URI - * scheme). - * - * **Note:** On macOS, you can use this method to check if the app has been - * registered as the default protocol handler for a protocol. You can also verify - * this by checking `~/Library/Preferences/com.apple.LaunchServices.plist` on the - * macOS machine. Please refer to Apple's documentation for details. - * - * The API uses the Windows Registry and `LSCopyDefaultHandlerForURLScheme` - * internally. - */ - isDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * whether or not the current OS version allows for native emoji pickers. - */ - isEmojiPanelSupported(): boolean; - /** - * Whether the application is currently running from the systems Application - * folder. Use in combination with `app.moveToApplicationsFolder()` - * - * @platform darwin - */ - isInApplicationsFolder(): boolean; - /** - * `true` if Electron has finished initializing, `false` otherwise. See also - * `app.whenReady()`. - */ - isReady(): boolean; - /** - * whether `Secure Keyboard Entry` is enabled. - * - * By default this API will return `false`. - * - * @platform darwin - */ - isSecureKeyboardEntryEnabled(): boolean; - /** - * Whether the current desktop environment is Unity launcher. - * - * @platform linux - */ - isUnityRunning(): boolean; - /** - * Whether the move was successful. Please note that if the move is successful, - * your application will quit and relaunch. - * - * No confirmation dialog will be presented by default. If you wish to allow the - * user to confirm the operation, you may do so using the `dialog` API. - * - * **NOTE:** This method throws errors if anything other than the user causes the - * move to fail. For instance if the user cancels the authorization dialog, this - * 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 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: - * - * Would mean that if an app already exists in the user directory, if the user - * chooses to 'Continue Move' then the function would continue with its default - * behavior and the existing app will be trashed and the active app moved into its - * place. - * - * @platform darwin - */ - moveToApplicationsFolder(options?: MoveToApplicationsFolderOptions): boolean; - /** - * Try to close all windows. The `before-quit` event will be emitted first. If all - * windows are successfully closed, the `will-quit` event will be emitted and by - * default the application will terminate. - * - * This method guarantees that all `beforeunload` and `unload` event handlers are - * correctly executed. It is possible that a window cancels the quitting by - * returning `false` in the `beforeunload` event handler. - */ - quit(): void; - /** - * Relaunches the app when current instance exits. - * - * By default, the new instance will use the same working directory and command - * line arguments with current instance. When `args` is specified, the `args` will - * be passed as command line arguments instead. When `execPath` is specified, the - * `execPath` will be executed for relaunch instead of current app. - * - * Note that this method does not quit the app when executed, you have to call - * `app.quit` or `app.exit` after calling `app.relaunch` to make the app restart. - * - * When `app.relaunch` is called for multiple times, multiple instances will be - * started after current instance exited. - * - * An example of restarting current instance immediately and adding a new command - * line argument to the new instance: - */ - relaunch(options?: RelaunchOptions): void; - /** - * Releases all locks that were created by `requestSingleInstanceLock`. This will - * allow multiple instances of the application to once again run side by side. - */ - releaseSingleInstanceLock(): void; - /** - * Whether the call succeeded. - * - * This method checks if the current executable as the default handler for a - * protocol (aka URI scheme). If so, it will remove the app as the default handler. - * - * @platform darwin,win32 - */ - removeAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * The return value of this method indicates whether or not this instance of your - * application successfully obtained the lock. If it failed to obtain the lock, - * you can assume that another instance of your application is already running with - * the lock and exit immediately. - * - * I.e. This method returns `true` if your process is the primary instance of your - * application and your app should continue loading. It returns `false` if your - * process should immediately quit as it has sent its parameters to another - * instance that has already acquired the lock. - * - * On macOS, the system enforces single instance automatically when users try to - * open a second instance of your app in Finder, and the `open-file` and `open-url` - * events will be emitted for that. However when users start your app in command - * line, the system's single instance mechanism will be bypassed, and you have to - * use this method to ensure single instance. - * - * An example of activating the window of primary instance when a second instance - * starts: - */ - requestSingleInstanceLock(additionalData?: Record<any, any>): boolean; - /** - * Marks the current Handoff user activity as inactive without invalidating it. - * - * @platform darwin - */ - resignCurrentActivity(): void; - /** - * Set the about panel options. This will override the values defined in the app's - * `.plist` file on macOS. See the Apple docs for more details. On Linux, values - * must be set in order to be shown; there are no defaults. - * - * If you do not set `credits` but still wish to surface them in your app, AppKit - * will look for a file named "Credits.html", "Credits.rtf", and "Credits.rtfd", in - * that order, in the bundle returned by the NSBundle class method main. The first - * file found is used, and if none is found, the info area is left blank. See Apple - * documentation for more information. - */ - setAboutPanelOptions(options: AboutPanelOptionsOptions): void; - /** - * Manually enables Chrome's accessibility support, allowing to expose - * accessibility switch to users in application settings. See Chromium's - * accessibility docs for more details. Disabled by default. - * - * This API must be called after the `ready` event is emitted. - * - * **Note:** Rendering accessibility tree can significantly affect the performance - * of your app. It should not be enabled by default. - * - * @platform darwin,win32 - */ - setAccessibilitySupportEnabled(enabled: boolean): void; - /** - * Sets the activation policy for a given app. - * - * Activation policy types: - * - * * 'regular' - The application is an ordinary app that appears in the Dock and - * may have a user interface. - * * 'accessory' - The application doesn’t appear in the Dock and doesn’t have a - * menu bar, but it may be activated programmatically or by clicking on one of its - * windows. - * * 'prohibited' - The application doesn’t appear in the Dock and may not create - * windows or be activated. - * - * @platform darwin - */ - setActivationPolicy(policy: 'regular' | 'accessory' | 'prohibited'): void; - /** - * Sets or creates a directory your app's logs which can then be manipulated with - * `app.getPath()` or `app.setPath(pathName, newPath)`. - * - * Calling `app.setAppLogsPath()` without a `path` parameter will result in this - * directory being set to `~/Library/Logs/YourAppName` on _macOS_, and inside the - * `userData` directory on _Linux_ and _Windows_. - */ - setAppLogsPath(path?: string): void; - /** - * Changes the Application User Model ID to `id`. - * - * @platform win32 - */ - setAppUserModelId(id: string): void; - /** - * Whether the call succeeded. - * - * Sets the current executable as the default handler for a protocol (aka URI - * scheme). It allows you to integrate your app deeper into the operating system. - * Once registered, all links with `your-protocol://` will be opened with the - * current executable. The whole link, including protocol, will be passed to your - * application as a parameter. - * - * **Note:** On macOS, you can only register protocols that have been added to your - * app's `info.plist`, which cannot be modified at runtime. However, you can change - * the file during build time via Electron Forge, Electron Packager, or by editing - * `info.plist` with a text editor. Please refer to Apple's documentation for - * details. - * - * **Note:** In a Windows Store environment (when packaged as an `appx`) this API - * will return `true` for all calls but the registry key it sets won't be - * accessible by other applications. In order to register your Windows Store - * application as a default protocol handler you must declare the protocol in your - * manifest. - * - * The API uses the Windows Registry and `LSSetDefaultHandlerForURLScheme` - * internally. - */ - setAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * Whether the call succeeded. - * - * Sets the counter badge for current app. Setting the count to `0` will hide the - * badge. - * - * On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher. - * - * **Note:** Unity launcher requires a `.desktop` file to work. For more - * information, please read the Unity integration documentation. - * - * @platform linux,darwin - */ - setBadgeCount(count?: number): boolean; - /** - * Sets or removes a custom Jump List for the application, and returns one of the - * following strings: - * - * * `ok` - Nothing went wrong. - * * `error` - One or more errors occurred, enable runtime logging to figure out - * the likely cause. - * * `invalidSeparatorError` - An attempt was made to add a separator to a custom - * category in the Jump List. Separators are only allowed in the standard `Tasks` - * category. - * * `fileTypeRegistrationError` - An attempt was made to add a file link to the - * Jump List for a file type the app isn't registered to handle. - * * `customCategoryAccessDeniedError` - Custom categories can't be added to the - * Jump List due to user privacy or group policy settings. - * - * If `categories` is `null` the previously set custom Jump List (if any) will be - * replaced by the standard Jump List for the app (managed by Windows). - * - * **Note:** If a `JumpListCategory` object has neither the `type` nor the `name` - * property set then its `type` is assumed to be `tasks`. If the `name` property is - * set but the `type` property is omitted then the `type` is assumed to be - * `custom`. - * - * **Note:** Users can remove items from custom categories, and Windows will not - * allow a removed item to be added back into a custom category until **after** the - * next successful call to `app.setJumpList(categories)`. Any attempt to re-add a - * removed item to a custom category earlier than that will result in the entire - * custom category being omitted from the Jump List. The list of removed items can - * be obtained using `app.getJumpListSettings()`. - * - * **Note:** The maximum length of a Jump List item's `description` property is 260 - * characters. Beyond this limit, the item will not be added to the Jump List, nor - * will it be displayed. - * - * Here's a very simple example of creating a custom Jump List: - * - * @platform win32 - */ - setJumpList(categories: (JumpListCategory[]) | (null)): ('ok' | 'error' | 'invalidSeparatorError' | 'fileTypeRegistrationError' | 'customCategoryAccessDeniedError'); - /** - * To work with Electron's `autoUpdater` on Windows, which uses Squirrel, you'll - * want to set the launch path to Update.exe, and pass arguments that specify your - * application name. For example: - * - * @platform darwin,win32 - */ - setLoginItemSettings(settings: Settings): void; - /** - * Overrides the current application's name. - * - * **Note:** This function overrides the name used internally by Electron; it does - * not affect the name that the OS uses. - */ - setName(name: string): void; - /** - * Overrides the `path` to a special directory or file associated with `name`. If - * the path specifies a directory that does not exist, an `Error` is thrown. In - * that case, the directory should be created with `fs.mkdirSync` or similar. - * - * You can only override paths of a `name` defined in `app.getPath`. - * - * By default, web pages' cookies and caches will be stored under the `userData` - * directory. If you want to change this location, you have to override the - * `userData` path before the `ready` event of the `app` module is emitted. - */ - setPath(name: string, path: string): void; - /** - * Set the `Secure Keyboard Entry` is enabled in your application. - * - * By using this API, important information such as password and other sensitive - * information can be prevented from being intercepted by other processes. - * - * See Apple's documentation for more details. - * - * **Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it - * when it is no longer needed. - * - * @platform darwin - */ - setSecureKeyboardEntryEnabled(enabled: boolean): void; - /** - * Creates an `NSUserActivity` and sets it as the current activity. The activity is - * eligible for Handoff to another device afterward. - * - * @platform darwin - */ - setUserActivity(type: string, userInfo: any, webpageURL?: string): void; - /** - * Adds `tasks` to the Tasks category of the Jump List on Windows. - * - * `tasks` is an array of `Task` objects. - * - * Whether the call succeeded. - * - * **Note:** If you'd like to customize the Jump List even more use - * `app.setJumpList(categories)` instead. - * - * @platform win32 - */ - setUserTasks(tasks: Task[]): boolean; - /** - * Shows application windows after they were hidden. Does not automatically focus - * them. - * - * @platform darwin - */ - show(): void; - /** - * Show the app's about panel options. These options can be overridden with - * `app.setAboutPanelOptions(options)`. - */ - showAboutPanel(): void; - /** - * Show the platform's native emoji picker. - * - * @platform darwin,win32 - */ - showEmojiPanel(): void; - /** - * This function **must** be called once you have finished accessing the security - * scoped file. If you do not remember to stop accessing the bookmark, kernel - * resources will be leaked and your app will lose its ability to reach outside the - * sandbox completely, until your app is restarted. - * - * Start accessing a security scoped resource. With this method Electron - * applications that are packaged for the Mac App Store may reach outside their - * sandbox to access files chosen by the user. See Apple's documentation for a - * description of how this system works. - * - * @platform mas - */ - startAccessingSecurityScopedResource(bookmarkData: string): Function; - /** - * Updates the current activity if its type matches `type`, merging the entries - * from `userInfo` into its current `userInfo` dictionary. - * - * @platform darwin - */ - updateCurrentActivity(type: string, userInfo: any): void; - /** - * fulfilled when Electron is initialized. May be used as a convenient alternative - * to checking `app.isReady()` and subscribing to the `ready` event if the app is - * not ready yet. - */ - whenReady(): Promise<void>; - /** - * A `boolean` property that's `true` if Chrome's accessibility support is enabled, - * `false` otherwise. This property will be `true` if the use of assistive - * technologies, such as screen readers, has been detected. Setting this property - * to `true` manually enables Chrome's accessibility support, allowing developers - * to expose accessibility switch to users in application settings. - * - * See Chromium's accessibility docs for more details. Disabled by default. - * - * This API must be called after the `ready` event is emitted. - * - * **Note:** Rendering accessibility tree can significantly affect the performance - * of your app. It should not be enabled by default. - * - * @platform darwin,win32 - */ - accessibilitySupportEnabled: boolean; - /** - * A `Menu | null` property that returns `Menu` if one has been set and `null` - * otherwise. Users can pass a Menu to set this property. - */ - applicationMenu: (Menu) | (null); - /** - * An `Integer` property that returns the badge count for current app. Setting the - * count to `0` will hide the badge. - * - * On macOS, setting this with any nonzero integer shows on the dock icon. On - * Linux, this property only works for Unity launcher. - * - * **Note:** Unity launcher requires a `.desktop` file to work. For more - * information, please read the Unity integration documentation. - * - * **Note:** On macOS, you need to ensure that your application has the permission - * to display notifications for this property to take effect. - * - * @platform linux,darwin - */ - badgeCount: number; - /** - * A `CommandLine` object that allows you to read and manipulate the command line - * arguments that Chromium uses. - * - */ - readonly commandLine: CommandLine; - /** - * A `Dock` `| undefined` object that allows you to perform actions on your app - * icon in the user's dock on macOS. - * - * @platform darwin - */ - readonly dock: Dock; - /** - * A `boolean` property that returns `true` if the app is packaged, `false` - * otherwise. For many apps, this property can be used to distinguish development - * and production environments. - * - */ - readonly isPackaged: boolean; - /** - * A `string` property that indicates the current application's name, which is the - * name in the application's `package.json` file. - * - * Usually the `name` field of `package.json` is a short lowercase name, according - * to the npm modules spec. You should usually also specify a `productName` field, - * which is your application's full capitalized name, and which will be preferred - * over `name` by Electron. - */ - name: string; - /** - * A `boolean` which when `true` indicates that the app is currently running under - * an ARM64 translator (like the macOS Rosetta Translator Environment or Windows - * WOW). - * - * You can use this property to prompt users to download the arm64 version of your - * application when they are running the x64 version under Rosetta incorrectly. - * - * @platform darwin,win32 - */ - readonly runningUnderARM64Translation: boolean; - /** - * A `boolean` which when `true` indicates that the app is currently running under - * the Rosetta Translator Environment. - * - * You can use this property to prompt users to download the arm64 version of your - * application when they are running the x64 version under Rosetta incorrectly. - * - * **Deprecated:** This property is superceded by the - * `runningUnderARM64Translation` property which detects when the app is being - * translated to ARM64 in both macOS and Windows. - * - * @deprecated - * @platform darwin - */ - readonly runningUnderRosettaTranslation: boolean; - /** - * A `string` which is the user agent string Electron will use as a global - * fallback. - * - * This is the user agent that will be used when no user agent is set at the - * `webContents` or `session` level. It is useful for ensuring that your entire - * app has the same user agent. Set to a custom value as early as possible in your - * app's initialization to ensure that your overridden value is used. - */ - userAgentFallback: string; - } - - interface AutoUpdater extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/auto-updater - - /** - * This event is emitted after a user calls `quitAndInstall()`. - * - * When this API is called, the `before-quit` event is not emitted before all - * windows are closed. As a result you should listen to this event if you wish to - * perform actions before the windows are closed while a process is quitting, as - * well as listening to `before-quit`. - */ - on(event: 'before-quit-for-update', listener: Function): this; - once(event: 'before-quit-for-update', listener: Function): this; - addListener(event: 'before-quit-for-update', listener: Function): this; - removeListener(event: 'before-quit-for-update', listener: Function): this; - /** - * Emitted when checking if an update has started. - */ - on(event: 'checking-for-update', listener: Function): this; - once(event: 'checking-for-update', listener: Function): this; - addListener(event: 'checking-for-update', listener: Function): this; - removeListener(event: 'checking-for-update', listener: Function): this; - /** - * Emitted when there is an error while updating. - */ - on(event: 'error', listener: (error: Error) => void): this; - once(event: 'error', listener: (error: Error) => void): this; - addListener(event: 'error', listener: (error: Error) => void): this; - removeListener(event: 'error', listener: (error: Error) => void): this; - /** - * Emitted when there is an available update. The update is downloaded - * automatically. - */ - on(event: 'update-available', listener: Function): this; - once(event: 'update-available', listener: Function): this; - addListener(event: 'update-available', listener: Function): this; - removeListener(event: 'update-available', listener: Function): this; - /** - * Emitted when an update has been downloaded. - * - * On Windows only `releaseName` is available. - * - * **Note:** It is not strictly necessary to handle this event. A successfully - * downloaded update will still be applied the next time the application starts. - */ - on(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - once(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - addListener(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - removeListener(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - /** - * Emitted when there is no available update. - */ - on(event: 'update-not-available', listener: Function): this; - once(event: 'update-not-available', listener: Function): this; - addListener(event: 'update-not-available', listener: Function): this; - removeListener(event: 'update-not-available', listener: Function): this; - /** - * Asks the server whether there is an update. You must call `setFeedURL` before - * using this API. - * - * **Note:** If an update is available it will be downloaded automatically. Calling - * `autoUpdater.checkForUpdates()` twice will download the update two times. - */ - checkForUpdates(): void; - /** - * The current update feed URL. - */ - getFeedURL(): string; - /** - * Restarts the app and installs the update after it has been downloaded. It should - * only be called after `update-downloaded` has been emitted. - * - * Under the hood calling `autoUpdater.quitAndInstall()` will close all application - * windows first, and automatically call `app.quit()` after all windows have been - * closed. - * - * **Note:** It is not strictly necessary to call this function to apply an update, - * as a successfully downloaded update will always be applied the next time the - * application starts. - */ - quitAndInstall(): void; - /** - * Sets the `url` and initialize the auto updater. - */ - setFeedURL(options: FeedURLOptions): void; - } - - interface BluetoothDevice { - - // Docs: https://electronjs.org/docs/api/structures/bluetooth-device - - deviceId: string; - deviceName: string; - } - - class BrowserView { - - // Docs: https://electronjs.org/docs/api/browser-view - - /** - * BrowserView - */ - constructor(options?: BrowserViewConstructorOptions); - /** - * The `bounds` of this BrowserView instance as `Object`. - * - * @experimental - */ - getBounds(): Rectangle; - setAutoResize(options: AutoResizeOptions): void; - /** - * Examples of valid `color` values: - * - * * Hex - * * #fff (RGB) - * * #ffff (ARGB) - * * #ffffff (RRGGBB) - * * #ffffffff (AARRGGBB) - * * RGB - * * rgb(([\d]+),\s*([\d]+),\s*([\d]+)) - * * e.g. rgb(255, 255, 255) - * * RGBA - * * rgba(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)) - * * e.g. rgba(255, 255, 255, 1.0) - * * HSL - * * hsl((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%) - * * e.g. hsl(200, 20%, 50%) - * * HSLA - * * hsla((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)) - * * e.g. hsla(200, 20%, 50%, 0.5) - * * Color name - * * Options are listed in SkParseColor.cpp - * * Similar to CSS Color Module Level 3 keywords, but case-sensitive. - * * e.g. `blueviolet` or `red` - * - * **Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBA` or - * `RGA`. - * - * @experimental - */ - setBackgroundColor(color: string): void; - /** - * Resizes and moves the view to the supplied bounds relative to the window. - * - * @experimental - */ - setBounds(bounds: Rectangle): void; - /** - * A `WebContents` object owned by this view. - * - * @experimental - */ - webContents: WebContents; - } - - class BrowserWindow extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/browser-window - - /** - * Emitted when the window is set or unset to show always on top of other windows. - */ - on(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - once(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - addListener(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - removeListener(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - /** - * Emitted when an App Command is invoked. These are typically related to keyboard - * media keys or browser commands, as well as the "Back" button built into some - * mice on Windows. - * - * Commands are lowercased, underscores are replaced with hyphens, and the - * `APPCOMMAND_` prefix is stripped off. e.g. `APPCOMMAND_BROWSER_BACKWARD` is - * emitted as `browser-backward`. - * - * The following app commands are explicitly supported on Linux: - * - * * `browser-backward` - * * `browser-forward` - * - * @platform win32,linux - */ - on(event: 'app-command', listener: (event: Event, - command: string) => void): this; - once(event: 'app-command', listener: (event: Event, - command: string) => void): this; - addListener(event: 'app-command', listener: (event: Event, - command: string) => void): this; - removeListener(event: 'app-command', listener: (event: Event, - command: string) => void): this; - /** - * Emitted when the window loses focus. - */ - on(event: 'blur', listener: Function): this; - once(event: 'blur', listener: Function): this; - addListener(event: 'blur', listener: Function): this; - removeListener(event: 'blur', listener: Function): this; - /** - * Emitted when the window is going to be closed. It's emitted before the - * `beforeunload` and `unload` event of the DOM. Calling `event.preventDefault()` - * will cancel the close. - * - * Usually you would want to use the `beforeunload` handler to decide whether the - * window should be closed, which will also be called when the window is reloaded. - * In Electron, returning any value other than `undefined` would cancel the close. - * For example: - * - * _**Note**: There is a subtle difference between the behaviors of - * `window.onbeforeunload = handler` and `window.addEventListener('beforeunload', - * handler)`. It is recommended to always set the `event.returnValue` explicitly, - * instead of only returning a value, as the former works more consistently within - * Electron._ - */ - on(event: 'close', listener: (event: Event) => void): this; - once(event: 'close', listener: (event: Event) => void): this; - addListener(event: 'close', listener: (event: Event) => void): this; - removeListener(event: 'close', listener: (event: Event) => void): this; - /** - * Emitted when the window is closed. After you have received this event you should - * remove the reference to the window and avoid using it any more. - */ - on(event: 'closed', listener: Function): this; - once(event: 'closed', listener: Function): this; - addListener(event: 'closed', listener: Function): this; - removeListener(event: 'closed', listener: Function): this; - /** - * Emitted when the window enters a full-screen state. - */ - on(event: 'enter-full-screen', listener: Function): this; - once(event: 'enter-full-screen', listener: Function): this; - addListener(event: 'enter-full-screen', listener: Function): this; - removeListener(event: 'enter-full-screen', listener: Function): this; - /** - * Emitted when the window enters a full-screen state triggered by HTML API. - */ - on(event: 'enter-html-full-screen', listener: Function): this; - once(event: 'enter-html-full-screen', listener: Function): this; - addListener(event: 'enter-html-full-screen', listener: Function): this; - removeListener(event: 'enter-html-full-screen', listener: Function): this; - /** - * Emitted when the window gains focus. - */ - on(event: 'focus', listener: Function): this; - once(event: 'focus', listener: Function): this; - addListener(event: 'focus', listener: Function): this; - removeListener(event: 'focus', listener: Function): this; - /** - * Emitted when the window is hidden. - */ - on(event: 'hide', listener: Function): this; - once(event: 'hide', listener: Function): this; - addListener(event: 'hide', listener: Function): this; - removeListener(event: 'hide', listener: Function): this; - /** - * Emitted when the window leaves a full-screen state. - */ - on(event: 'leave-full-screen', listener: Function): this; - once(event: 'leave-full-screen', listener: Function): this; - addListener(event: 'leave-full-screen', listener: Function): this; - removeListener(event: 'leave-full-screen', listener: Function): this; - /** - * Emitted when the window leaves a full-screen state triggered by HTML API. - */ - on(event: 'leave-html-full-screen', listener: Function): this; - once(event: 'leave-html-full-screen', listener: Function): this; - addListener(event: 'leave-html-full-screen', listener: Function): this; - removeListener(event: 'leave-html-full-screen', listener: Function): this; - /** - * Emitted when window is maximized. - */ - on(event: 'maximize', listener: Function): this; - once(event: 'maximize', listener: Function): this; - addListener(event: 'maximize', listener: Function): this; - removeListener(event: 'maximize', listener: Function): this; - /** - * Emitted when the window is minimized. - */ - on(event: 'minimize', listener: Function): this; - once(event: 'minimize', listener: Function): this; - addListener(event: 'minimize', listener: Function): this; - removeListener(event: 'minimize', listener: Function): this; - /** - * Emitted when the window is being moved to a new position. - */ - on(event: 'move', listener: Function): this; - once(event: 'move', listener: Function): this; - addListener(event: 'move', listener: Function): this; - removeListener(event: 'move', listener: Function): this; - /** - * Emitted once when the window is moved to a new position. - * - * __Note__: On macOS this event is an alias of `move`. - * - * @platform darwin,win32 - */ - on(event: 'moved', listener: Function): this; - once(event: 'moved', listener: Function): this; - addListener(event: 'moved', listener: Function): this; - removeListener(event: 'moved', listener: Function): this; - /** - * Emitted when the native new tab button is clicked. - * - * @platform darwin - */ - on(event: 'new-window-for-tab', listener: Function): this; - once(event: 'new-window-for-tab', listener: Function): this; - addListener(event: 'new-window-for-tab', listener: Function): this; - removeListener(event: 'new-window-for-tab', listener: Function): this; - /** - * Emitted when the document changed its title, calling `event.preventDefault()` - * will prevent the native window's title from changing. `explicitSet` is false - * when title is synthesized from file URL. - */ - on(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - once(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - addListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - removeListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - /** - * Emitted when the web page has been rendered (while not being shown) and window - * can be displayed without a visual flash. - * - * Please note that using this event implies that the renderer will be considered - * "visible" and paint even though `show` is false. This event will never fire if - * you use `paintWhenInitiallyHidden: false` - */ - on(event: 'ready-to-show', listener: Function): this; - once(event: 'ready-to-show', listener: Function): this; - addListener(event: 'ready-to-show', listener: Function): this; - removeListener(event: 'ready-to-show', listener: Function): this; - /** - * Emitted after the window has been resized. - */ - on(event: 'resize', listener: Function): this; - once(event: 'resize', listener: Function): this; - addListener(event: 'resize', listener: Function): this; - removeListener(event: 'resize', listener: Function): this; - /** - * Emitted once when the window has finished being resized. - * - * This is usually emitted when the window has been resized manually. On macOS, - * resizing the window with `setBounds`/`setSize` and setting the `animate` - * parameter to `true` will also emit this event once resizing has finished. - * - * @platform darwin,win32 - */ - on(event: 'resized', listener: Function): this; - once(event: 'resized', listener: Function): this; - addListener(event: 'resized', listener: Function): this; - removeListener(event: 'resized', listener: Function): this; - /** - * Emitted when the unresponsive web page becomes responsive again. - */ - on(event: 'responsive', listener: Function): this; - once(event: 'responsive', listener: Function): this; - addListener(event: 'responsive', listener: Function): this; - removeListener(event: 'responsive', listener: Function): this; - /** - * Emitted when the window is restored from a minimized state. - */ - on(event: 'restore', listener: Function): this; - once(event: 'restore', listener: Function): this; - addListener(event: 'restore', listener: Function): this; - removeListener(event: 'restore', listener: Function): this; - /** - * Emitted on trackpad rotation gesture. Continually emitted until rotation gesture - * is ended. The `rotation` value on each emission is the angle in degrees rotated - * since the last emission. The last emitted event upon a rotation gesture will - * always be of value `0`. Counter-clockwise rotation values are positive, while - * clockwise ones are negative. - * - * @platform darwin - */ - on(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - once(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - addListener(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - removeListener(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - /** - * Emitted when scroll wheel event phase has begun. - * - * @platform darwin - */ - on(event: 'scroll-touch-begin', listener: Function): this; - once(event: 'scroll-touch-begin', listener: Function): this; - addListener(event: 'scroll-touch-begin', listener: Function): this; - removeListener(event: 'scroll-touch-begin', listener: Function): this; - /** - * Emitted when scroll wheel event phase filed upon reaching the edge of element. - * - * @platform darwin - */ - on(event: 'scroll-touch-edge', listener: Function): this; - once(event: 'scroll-touch-edge', listener: Function): this; - addListener(event: 'scroll-touch-edge', listener: Function): this; - removeListener(event: 'scroll-touch-edge', listener: Function): this; - /** - * Emitted when scroll wheel event phase has ended. - * - * @platform darwin - */ - on(event: 'scroll-touch-end', listener: Function): this; - once(event: 'scroll-touch-end', listener: Function): this; - addListener(event: 'scroll-touch-end', listener: Function): this; - removeListener(event: 'scroll-touch-end', listener: Function): this; - /** - * Emitted when window session is going to end due to force shutdown or machine - * restart or session log off. - * - * @platform win32 - */ - on(event: 'session-end', listener: Function): this; - once(event: 'session-end', listener: Function): this; - addListener(event: 'session-end', listener: Function): this; - removeListener(event: 'session-end', listener: Function): this; - /** - * Emitted when the window opens a sheet. - * - * @platform darwin - */ - on(event: 'sheet-begin', listener: Function): this; - once(event: 'sheet-begin', listener: Function): this; - addListener(event: 'sheet-begin', listener: Function): this; - removeListener(event: 'sheet-begin', listener: Function): this; - /** - * Emitted when the window has closed a sheet. - * - * @platform darwin - */ - on(event: 'sheet-end', listener: Function): this; - once(event: 'sheet-end', listener: Function): this; - addListener(event: 'sheet-end', listener: Function): this; - removeListener(event: 'sheet-end', listener: Function): this; - /** - * Emitted when the window is shown. - */ - on(event: 'show', listener: Function): this; - once(event: 'show', listener: Function): this; - addListener(event: 'show', listener: Function): this; - removeListener(event: 'show', listener: Function): this; - /** - * Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, - * `left`. - * - * The method underlying this event is built to handle older macOS-style trackpad - * swiping, where the content on the screen doesn't move with the swipe. Most macOS - * trackpads are not configured to allow this kind of swiping anymore, so in order - * for it to emit properly the 'Swipe between pages' preference in `System - * Preferences > Trackpad > More Gestures` must be set to 'Swipe with two or three - * fingers'. - * - * @platform darwin - */ - on(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - once(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - addListener(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - removeListener(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - /** - * Emitted when the system context menu is triggered on the window, this is - * normally only triggered when the user right clicks on the non-client area of - * your window. This is the window titlebar or any area you have declared as - * `-webkit-app-region: drag` in a frameless window. - * - * Calling `event.preventDefault()` will prevent the menu from being displayed. - * - * @platform win32 - */ - on(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - once(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - addListener(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - removeListener(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - /** - * Emitted when the window exits from a maximized state. - */ - on(event: 'unmaximize', listener: Function): this; - once(event: 'unmaximize', listener: Function): this; - addListener(event: 'unmaximize', listener: Function): this; - removeListener(event: 'unmaximize', listener: Function): this; - /** - * Emitted when the web page becomes unresponsive. - */ - on(event: 'unresponsive', listener: Function): this; - once(event: 'unresponsive', listener: Function): this; - addListener(event: 'unresponsive', listener: Function): this; - removeListener(event: 'unresponsive', listener: Function): this; - /** - * Emitted before the window is moved. On Windows, calling `event.preventDefault()` - * will prevent the window from being moved. - * - * Note that this is only emitted when the window is being moved manually. Moving - * the window with `setPosition`/`setBounds`/`center` will not emit this event. - * - * @platform darwin,win32 - */ - on(event: 'will-move', listener: (event: Event, - /** - * Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - once(event: 'will-move', listener: (event: Event, - /** - * Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - addListener(event: 'will-move', listener: (event: Event, + type: string, /** - * Location the window is being moved to. + * Contains app-specific state stored by the activity. */ - newBounds: Rectangle) => void): this; - removeListener(event: 'will-move', listener: (event: Event, - /** - * Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - /** - * Emitted before the window is resized. Calling `event.preventDefault()` will - * prevent the window from being resized. - * - * Note that this is only emitted when the window is being resized manually. - * Resizing the window with `setBounds`/`setSize` will not emit this event. - * - * The possible values and behaviors of the `edge` option are platform dependent. - * Possible values are: - * - * * On Windows, possible values are `bottom`, `top`, `left`, `right`, `top-left`, - * `top-right`, `bottom-left`, `bottom-right`. - * * On macOS, possible values are `bottom` and `right`. - * * The value `bottom` is used to denote vertical resizing. - * * The value `right` is used to denote horizontal resizing. - * - * @platform darwin,win32 - */ - on(event: 'will-resize', listener: (event: Event, - /** - * Size the window is being resized to. - */ - newBounds: Rectangle, - details: WillResizeDetails) => void): this; - once(event: 'will-resize', listener: (event: Event, + userInfo: unknown) => void): this; + once(event: 'activity-was-continued', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity. + */ + userInfo: unknown) => void): this; + addListener(event: 'activity-was-continued', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity. + */ + userInfo: unknown) => void): this; + removeListener(event: 'activity-was-continued', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity. + */ + userInfo: unknown) => void): this; + /** + * Emitted before the application starts closing its windows. Calling + * `event.preventDefault()` will prevent the default behavior, which is terminating + * the application. + * + * **Note:** If application quit was initiated by `autoUpdater.quitAndInstall()`, + * then `before-quit` is emitted *after* emitting `close` event on all windows and + * closing them. + * + * **Note:** On Windows, this event will not be emitted if the app is closed due to + * a shutdown/restart of the system or a user logout. + */ + on(event: 'before-quit', listener: (event: Event) => void): this; + once(event: 'before-quit', listener: (event: Event) => void): this; + addListener(event: 'before-quit', listener: (event: Event) => void): this; + removeListener(event: 'before-quit', listener: (event: Event) => void): this; + /** + * Emitted when a browserWindow gets blurred. + */ + on(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; + once(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; + addListener(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; + removeListener(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; + /** + * Emitted when a new browserWindow is created. + */ + on(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; + once(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; + addListener(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; + removeListener(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; + /** + * Emitted when a browserWindow gets focused. + */ + on(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; + once(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; + addListener(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; + removeListener(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; + /** + * Emitted when failed to verify the `certificate` for `url`, to trust the + * certificate you should prevent the default behavior with + * `event.preventDefault()` and call `callback(true)`. + */ + on(event: 'certificate-error', listener: (event: Event, + webContents: WebContents, + url: string, /** - * Size the window is being resized to. + * The error code */ - newBounds: Rectangle, - details: WillResizeDetails) => void): this; - addListener(event: 'will-resize', listener: (event: Event, - /** - * Size the window is being resized to. - */ - newBounds: Rectangle, - details: WillResizeDetails) => void): this; - removeListener(event: 'will-resize', listener: (event: Event, - /** - * Size the window is being resized to. - */ - newBounds: Rectangle, - details: WillResizeDetails) => void): this; - /** - * BrowserWindow - */ - constructor(options?: BrowserWindowConstructorOptions); - /** - * The window that owns the given `browserView`. If the given view is not attached - * to any window, returns `null`. - */ - static fromBrowserView(browserView: BrowserView): (BrowserWindow) | (null); - /** - * The window with the given `id`. - */ - static fromId(id: number): (BrowserWindow) | (null); - /** - * The window that owns the given `webContents` or `null` if the contents are not - * owned by a window. - */ - static fromWebContents(webContents: WebContents): (BrowserWindow) | (null); - /** - * An array of all opened browser windows. - */ - static getAllWindows(): BrowserWindow[]; - /** - * The window that is focused in this application, otherwise returns `null`. - */ - static getFocusedWindow(): (BrowserWindow) | (null); - /** - * Replacement API for setBrowserView supporting work with multi browser views. - * - * @experimental - */ - addBrowserView(browserView: BrowserView): void; - /** - * Adds a window as a tab on this window, after the tab for the window instance. - * - * @platform darwin - */ - addTabbedWindow(browserWindow: BrowserWindow): void; - /** - * Removes focus from the window. - */ - blur(): void; - blurWebView(): void; - /** - * Resolves with a NativeImage - * - * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the - * whole visible page. If the page is not visible, `rect` may be empty. - */ - capturePage(rect?: Rectangle): Promise<Electron.NativeImage>; - /** - * Moves window to the center of the screen. - */ - center(): void; - /** - * Try to close the window. This has the same effect as a user manually clicking - * the close button of the window. The web page may cancel the close though. See - * the close event. - */ - close(): void; - /** - * Closes the currently open Quick Look panel. - * - * @platform darwin - */ - closeFilePreview(): void; - /** - * Force closing the window, the `unload` and `beforeunload` event won't be emitted - * for the web page, and `close` event will also not be emitted for this window, - * but it guarantees the `closed` event will be emitted. - */ - destroy(): void; - /** - * Starts or stops flashing the window to attract user's attention. - */ - flashFrame(flag: boolean): void; - /** - * Focuses on the window. - */ - focus(): void; - focusOnWebView(): void; - /** - * Gets the background color of the window in Hex (`#RRGGBB`) format. - * - * See Setting `backgroundColor`. - * - * **Note:** The alpha value is _not_ returned alongside the red, green, and blue - * values. - */ - getBackgroundColor(): string; - /** - * The `bounds` of the window as `Object`. - */ - getBounds(): Rectangle; - /** - * The `BrowserView` attached to `win`. Returns `null` if one is not attached. - * Throws an error if multiple `BrowserView`s are attached. - * - * @experimental - */ - getBrowserView(): (BrowserView) | (null); - /** - * an array of all BrowserViews that have been attached with `addBrowserView` or - * `setBrowserView`. - * - * **Note:** The BrowserView API is currently experimental and may change or be - * removed in future Electron releases. - * - * @experimental - */ - getBrowserViews(): BrowserView[]; - /** - * All child windows. - */ - getChildWindows(): BrowserWindow[]; - /** - * The `bounds` of the window's client area as `Object`. - */ - getContentBounds(): Rectangle; - /** - * Contains the window's client area's width and height. - */ - getContentSize(): number[]; - /** - * Contains the window's maximum width and height. - */ - getMaximumSize(): number[]; - /** - * Window id in the format of DesktopCapturerSource's id. For example - * "window:1324:0". - * - * More precisely the format is `window:id:other_id` where `id` is `HWND` on - * Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on - * Linux. `other_id` is used to identify web contents (tabs) so within the same top - * level window. - */ - getMediaSourceId(): string; - /** - * Contains the window's minimum width and height. - */ - getMinimumSize(): number[]; - /** - * The platform-specific handle of the window. - * - * The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and - * `Window` (`unsigned long`) on Linux. - */ - getNativeWindowHandle(): Buffer; - /** - * Contains the window bounds of the normal state - * - * **Note:** whatever the current state of the window : maximized, minimized or in - * fullscreen, this function always returns the position and size of the window in - * normal state. In normal state, getBounds and getNormalBounds returns the same - * `Rectangle`. - */ - getNormalBounds(): Rectangle; - /** - * between 0.0 (fully transparent) and 1.0 (fully opaque). On Linux, always returns - * 1. - */ - getOpacity(): number; - /** - * The parent window or `null` if there is no parent. - */ - getParentWindow(): (BrowserWindow) | (null); - /** - * Contains the window's current position. - */ - getPosition(): number[]; - /** - * The pathname of the file the window represents. - * - * @platform darwin - */ - getRepresentedFilename(): string; - /** - * Contains the window's width and height. - */ - getSize(): number[]; - /** - * The title of the native window. - * - * **Note:** The title of the web page can be different from the title of the - * native window. - */ - getTitle(): string; - /** - * The custom position for the traffic light buttons in frameless window. - * - * @platform darwin - */ - getTrafficLightPosition(): Point; - /** - * Whether the window has a shadow. - */ - hasShadow(): boolean; - /** - * Hides the window. - */ - hide(): void; - /** - * Hooks a windows message. The `callback` is called when the message is received - * in the WndProc. - * - * @platform win32 - */ - hookWindowMessage(message: number, callback: (wParam: any, lParam: any) => void): void; - /** - * Whether the window is always on top of other windows. - */ - isAlwaysOnTop(): boolean; - /** - * Whether the window can be manually closed by user. - * - * On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isClosable(): boolean; - /** - * Whether the window is destroyed. - */ - isDestroyed(): boolean; - /** - * Whether the window's document has been edited. - * - * @platform darwin - */ - isDocumentEdited(): boolean; - /** - * whether the window is enabled. - */ - isEnabled(): boolean; - /** - * Returns whether the window can be focused. - * - * @platform darwin,win32 - */ - isFocusable(): void; - /** - * Whether the window is focused. - */ - isFocused(): boolean; - /** - * Whether the window is in fullscreen mode. - */ - isFullScreen(): boolean; - /** - * Whether the maximize/zoom window button toggles fullscreen mode or maximizes the - * window. - */ - isFullScreenable(): boolean; - /** - * Whether the window is in kiosk mode. - */ - isKiosk(): boolean; - /** - * Whether the window can be manually maximized by user. - * - * On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isMaximizable(): boolean; - /** - * Whether the window is maximized. - */ - isMaximized(): boolean; - /** - * Whether menu bar automatically hides itself. - */ - isMenuBarAutoHide(): boolean; - /** - * Whether the menu bar is visible. - */ - isMenuBarVisible(): boolean; - /** - * Whether the window can be manually minimized by the user. - * - * On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isMinimizable(): boolean; - /** - * Whether the window is minimized. - */ - isMinimized(): boolean; - /** - * Whether current window is a modal window. - */ - isModal(): boolean; - /** - * Whether the window can be moved by user. - * - * On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isMovable(): boolean; - /** - * Whether the window is in normal state (not maximized, not minimized, not in - * fullscreen mode). - */ - isNormal(): boolean; - /** - * Whether the window can be manually resized by the user. - */ - isResizable(): boolean; - /** - * Whether the window is in simple (pre-Lion) fullscreen mode. - * - * @platform darwin - */ - isSimpleFullScreen(): boolean; - /** - * Whether the window is in Windows 10 tablet mode. - * - * Since Windows 10 users can use their PC as tablet, under this mode apps can - * choose to optimize their UI for tablets, such as enlarging the titlebar and - * hiding titlebar buttons. - * - * This API returns whether the window is in tablet mode, and the `resize` event - * can be be used to listen to changes to tablet mode. - * - * @platform win32 - */ - isTabletMode(): boolean; - /** - * Whether the window is visible to the user. - */ - isVisible(): boolean; - /** - * Whether the window is visible on all workspaces. - * - * **Note:** This API always returns false on Windows. - */ - isVisibleOnAllWorkspaces(): boolean; - /** - * `true` or `false` depending on whether the message is hooked. - * - * @platform win32 - */ - isWindowMessageHooked(message: number): boolean; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Same as `webContents.loadFile`, `filePath` should be a path to an HTML file - * relative to the root of your application. See the `webContents` docs for more - * information. - */ - loadFile(filePath: string, options?: LoadFileOptions): Promise<void>; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Same as `webContents.loadURL(url[, options])`. - * - * The `url` can be a remote address (e.g. `http://`) or a path to a local HTML - * file using the `file://` protocol. - * - * To ensure that file URLs are properly formatted, it is recommended to use Node's - * `url.format` method: - * - * You can load a URL using a `POST` request with URL-encoded data by doing the - * following: - */ - loadURL(url: string, options?: LoadURLOptions): Promise<void>; - /** - * Maximizes the window. This will also show (but not focus) the window if it isn't - * being displayed already. - */ - maximize(): void; - /** - * Merges all windows into one window with multiple tabs when native tabs are - * enabled and there is more than one open window. - * - * @platform darwin - */ - mergeAllWindows(): void; - /** - * Minimizes the window. On some platforms the minimized window will be shown in - * the Dock. - */ - minimize(): void; - /** - * Moves window above the source window in the sense of z-order. If the - * `mediaSourceId` is not of type window or if the window does not exist then this - * method throws an error. - */ - moveAbove(mediaSourceId: string): void; - /** - * Moves the current tab into a new window if native tabs are enabled and there is - * more than one tab in the current window. - * - * @platform darwin - */ - moveTabToNewWindow(): void; - /** - * Moves window to top(z-order) regardless of focus - */ - moveTop(): void; - /** - * Uses Quick Look to preview a file at a given path. - * - * @platform darwin - */ - previewFile(path: string, displayName?: string): void; - /** - * Same as `webContents.reload`. - */ - reload(): void; - removeBrowserView(browserView: BrowserView): void; - /** - * Remove the window's menu bar. - * - * @platform linux,win32 - */ - removeMenu(): void; - /** - * Restores the window from minimized state to its previous state. - */ - restore(): void; - /** - * Selects the next tab when native tabs are enabled and there are other tabs in - * the window. - * - * @platform darwin - */ - selectNextTab(): void; - /** - * Selects the previous tab when native tabs are enabled and there are other tabs - * in the window. - * - * @platform darwin - */ - selectPreviousTab(): void; - /** - * Sets whether the window should show always on top of other windows. After - * setting this, the window is still a normal window, not a toolbox window which - * can not be focused on. - */ - setAlwaysOnTop(flag: boolean, level?: 'normal' | 'floating' | 'torn-off-menu' | 'modal-panel' | 'main-menu' | 'status' | 'pop-up-menu' | 'screen-saver', relativeLevel?: number): void; - /** - * Sets the properties for the window's taskbar button. - * - * **Note:** `relaunchCommand` and `relaunchDisplayName` must always be set - * together. If one of those properties is not set, then neither will be used. - * - * @platform win32 - */ - setAppDetails(options: AppDetailsOptions): void; - /** - * This will make a window maintain an aspect ratio. The extra size allows a - * developer to have space, specified in pixels, not included within the aspect - * ratio calculations. This API already takes into account the difference between a - * window's size and its content size. - * - * Consider a normal window with an HD video player and associated controls. - * Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls - * on the right edge and 50 pixels of controls below the player. In order to - * maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within - * the player itself we would call this function with arguments of 16/9 and { - * width: 40, height: 50 }. The second argument doesn't care where the extra width - * and height are within the content view--only that they exist. Sum any extra - * width and height areas you have within the overall content view. - * - * The aspect ratio is not respected when window is resized programmatically with - * APIs like `win.setSize`. - */ - setAspectRatio(aspectRatio: number, extraSize?: Size): void; - /** - * Controls whether to hide cursor when typing. - * - * @platform darwin - */ - setAutoHideCursor(autoHide: boolean): void; - /** - * Sets whether the window menu bar should hide itself automatically. Once set the - * menu bar will only show when users press the single `Alt` key. - * - * If the menu bar is already visible, calling `setAutoHideMenuBar(true)` won't - * hide it immediately. - */ - setAutoHideMenuBar(hide: boolean): void; - /** - * Examples of valid `backgroundColor` values: - * - * * Hex - * * #fff (shorthand RGB) - * * #ffff (shorthand ARGB) - * * #ffffff (RGB) - * * #ffffffff (ARGB) - * * RGB - * * rgb(([\d]+),\s*([\d]+),\s*([\d]+)) - * * e.g. rgb(255, 255, 255) - * * RGBA - * * rgba(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)) - * * e.g. rgba(255, 255, 255, 1.0) - * * HSL - * * hsl((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%) - * * e.g. hsl(200, 20%, 50%) - * * HSLA - * * hsla((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)) - * * e.g. hsla(200, 20%, 50%, 0.5) - * * Color name - * * Options are listed in SkParseColor.cpp - * * Similar to CSS Color Module Level 3 keywords, but case-sensitive. - * * e.g. `blueviolet` or `red` - * - * Sets the background color of the window. See Setting `backgroundColor`. - */ - setBackgroundColor(backgroundColor: string): void; - /** - * Resizes and moves the window to the supplied bounds. Any properties that are not - * supplied will default to their current values. - */ - setBounds(bounds: Partial<Rectangle>, animate?: boolean): void; - setBrowserView(browserView: (BrowserView) | (null)): void; - /** - * Sets whether the window can be manually closed by user. On Linux does nothing. - * - * @platform darwin,win32 - */ - setClosable(closable: boolean): void; - /** - * Resizes and moves the window's client area (e.g. the web page) to the supplied - * bounds. - */ - setContentBounds(bounds: Rectangle, animate?: boolean): void; - /** - * Prevents the window contents from being captured by other apps. - * - * On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. On Windows - * it calls SetWindowDisplayAffinity with `WDA_EXCLUDEFROMCAPTURE`. For Windows 10 - * version 2004 and up the window will be removed from capture entirely, older - * Windows versions behave as if `WDA_MONITOR` is applied capturing a black window. - * - * @platform darwin,win32 - */ - setContentProtection(enable: boolean): void; - /** - * Resizes the window's client area (e.g. the web page) to `width` and `height`. - */ - setContentSize(width: number, height: number, animate?: boolean): void; - /** - * Specifies whether the window’s document has been edited, and the icon in title - * bar will become gray when set to `true`. - * - * @platform darwin - */ - setDocumentEdited(edited: boolean): void; - /** - * Disable or enable the window. - */ - setEnabled(enable: boolean): void; - /** - * Changes whether the window can be focused. - * - * On macOS it does not remove the focus from the window. - * - * @platform darwin,win32 - */ - setFocusable(focusable: boolean): void; - /** - * Sets whether the window should be in fullscreen mode. - */ - setFullScreen(flag: boolean): void; - /** - * Sets whether the maximize/zoom window button toggles fullscreen mode or - * maximizes the window. - */ - setFullScreenable(fullscreenable: boolean): void; - /** - * Sets whether the window should have a shadow. - */ - setHasShadow(hasShadow: boolean): void; - /** - * Changes window icon. - * - * @platform win32,linux - */ - setIcon(icon: (NativeImage) | (string)): void; - /** - * Makes the window ignore all mouse events. - * - * All mouse events happened in this window will be passed to the window below this - * window, but if this window has focus, it will still receive keyboard events. - */ - setIgnoreMouseEvents(ignore: boolean, options?: IgnoreMouseEventsOptions): void; - /** - * Enters or leaves kiosk mode. - */ - setKiosk(flag: boolean): void; - /** - * Sets whether the window can be manually maximized by user. On Linux does - * nothing. - * - * @platform darwin,win32 - */ - setMaximizable(maximizable: boolean): void; - /** - * Sets the maximum size of window to `width` and `height`. - */ - setMaximumSize(width: number, height: number): void; - /** - * Sets the `menu` as the window's menu bar. - * - * @platform linux,win32 - */ - setMenu(menu: (Menu) | (null)): void; - /** - * Sets whether the menu bar should be visible. If the menu bar is auto-hide, users - * can still bring up the menu bar by pressing the single `Alt` key. - * - * @platform win32,linux - */ - setMenuBarVisibility(visible: boolean): void; - /** - * Sets whether the window can be manually minimized by user. On Linux does - * nothing. - * - * @platform darwin,win32 - */ - setMinimizable(minimizable: boolean): void; - /** - * Sets the minimum size of window to `width` and `height`. - */ - setMinimumSize(width: number, height: number): void; - /** - * Sets whether the window can be moved by user. On Linux does nothing. - * - * @platform darwin,win32 - */ - setMovable(movable: boolean): void; - /** - * Sets the opacity of the window. On Linux, does nothing. Out of bound number - * values are clamped to the [0, 1] range. - * - * @platform win32,darwin - */ - setOpacity(opacity: number): void; - /** - * Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to - * convey some sort of application status or to passively notify the user. - * - * @platform win32 - */ - setOverlayIcon(overlay: (NativeImage) | (null), description: string): void; - /** - * Sets `parent` as current window's parent window, passing `null` will turn - * current window into a top-level window. - */ - setParentWindow(parent: (BrowserWindow) | (null)): void; - /** - * Moves window to `x` and `y`. - */ - setPosition(x: number, y: number, animate?: boolean): void; - /** - * Sets progress value in progress bar. Valid range is [0, 1.0]. - * - * Remove progress bar when progress < 0; Change to indeterminate mode when - * progress > 1. - * - * On Linux platform, only supports Unity desktop environment, you need to specify - * the `*.desktop` file name to `desktopName` field in `package.json`. By default, - * it will assume `{app.name}.desktop`. - * - * On Windows, a mode can be passed. Accepted values are `none`, `normal`, - * `indeterminate`, `error`, and `paused`. If you call `setProgressBar` without a - * mode set (but with a value within the valid range), `normal` will be assumed. - */ - setProgressBar(progress: number, options?: ProgressBarOptions): void; - /** - * Sets the pathname of the file the window represents, and the icon of the file - * will show in window's title bar. - * - * @platform darwin - */ - setRepresentedFilename(filename: string): void; - /** - * Sets whether the window can be manually resized by the user. - */ - setResizable(resizable: boolean): void; - /** - * Setting a window shape determines the area within the window where the system - * permits drawing and user interaction. Outside of the given region, no pixels - * will be drawn and no mouse events will be registered. Mouse events outside of - * the region will not be received by that window, but will fall through to - * whatever is behind the window. - * - * @experimental - * @platform win32,linux - */ - setShape(rects: Rectangle[]): void; - /** - * Changes the attachment point for sheets on macOS. By default, sheets are - * attached just below the window frame, but you may want to display them beneath a - * HTML-rendered toolbar. For example: - * - * @platform darwin - */ - setSheetOffset(offsetY: number, offsetX?: number): void; - /** - * Enters or leaves simple fullscreen mode. - * - * Simple fullscreen mode emulates the native fullscreen behavior found in versions - * of macOS prior to Lion (10.7). - * - * @platform darwin - */ - setSimpleFullScreen(flag: boolean): void; - /** - * Resizes the window to `width` and `height`. If `width` or `height` are below any - * set minimum size constraints the window will snap to its minimum size. - */ - setSize(width: number, height: number, animate?: boolean): void; - /** - * Makes the window not show in the taskbar. - */ - setSkipTaskbar(skip: boolean): void; - /** - * Whether the buttons were added successfully - * - * Add a thumbnail toolbar with a specified set of buttons to the thumbnail image - * of a window in a taskbar button layout. Returns a `boolean` object indicates - * whether the thumbnail has been added successfully. - * - * The number of buttons in thumbnail toolbar should be no greater than 7 due to - * the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be - * removed due to the platform's limitation. But you can call the API with an empty - * array to clean the buttons. - * - * The `buttons` is an array of `Button` objects: - * - * * `Button` Object - * * `icon` NativeImage - The icon showing in thumbnail toolbar. - * * `click` Function - * * `tooltip` string (optional) - The text of the button's tooltip. - * * `flags` string[] (optional) - Control specific states and behaviors of the - * button. By default, it is `['enabled']`. - * - * The `flags` is an array that can include following `string`s: - * - * * `enabled` - The button is active and available to the user. - * * `disabled` - The button is disabled. It is present, but has a visual state - * indicating it will not respond to user action. - * * `dismissonclick` - When the button is clicked, the thumbnail window closes - * immediately. - * * `nobackground` - Do not draw a button border, use only the image. - * * `hidden` - The button is not shown to the user. - * * `noninteractive` - The button is enabled but not interactive; no pressed - * button state is drawn. This value is intended for instances where the button is - * used in a notification. - * - * @platform win32 - */ - setThumbarButtons(buttons: ThumbarButton[]): boolean; - /** - * Sets the region of the window to show as the thumbnail image displayed when - * hovering over the window in the taskbar. You can reset the thumbnail to be the - * entire window by specifying an empty region: `{ x: 0, y: 0, width: 0, height: 0 - * }`. - * - * @platform win32 - */ - setThumbnailClip(region: Rectangle): void; - /** - * Sets the toolTip that is displayed when hovering over the window thumbnail in - * the taskbar. - * - * @platform win32 - */ - setThumbnailToolTip(toolTip: string): void; - /** - * Changes the title of native window to `title`. - */ - setTitle(title: string): void; - /** - * On a Window with Window Controls Overlay already enabled, this method updates - * the style of the title bar overlay. - * - * @platform win32 - */ - setTitleBarOverlay(options: TitleBarOverlayOptions): void; - /** - * Raises `browserView` above other `BrowserView`s attached to `win`. Throws an - * error if `browserView` is not attached to `win`. - * - * @experimental - */ - setTopBrowserView(browserView: BrowserView): void; - /** - * Sets the touchBar layout for the current window. Specifying `null` or - * `undefined` clears the touch bar. This method only has an effect if the machine - * has a touch bar and is running on macOS 10.12.1+. - * - * **Note:** The TouchBar API is currently experimental and may change or be - * removed in future Electron releases. - * - * @platform darwin - */ - setTouchBar(touchBar: (TouchBar) | (null)): void; - /** - * Set a custom position for the traffic light buttons in frameless window. - * - * @platform darwin - */ - setTrafficLightPosition(position: Point): void; - /** - * Adds a vibrancy effect to the browser window. Passing `null` or an empty string - * will remove the vibrancy effect on the window. - * - * Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` - * have been deprecated and will be removed in an upcoming version of macOS. - * - * @platform darwin - */ - setVibrancy(type: (('appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark' | 'header' | 'sheet' | 'window' | 'hud' | 'fullscreen-ui' | 'tooltip' | 'content' | 'under-window' | 'under-page')) | (null)): void; - /** - * Sets whether the window should be visible on all workspaces. - * - * **Note:** This API does nothing on Windows. - */ - setVisibleOnAllWorkspaces(visible: boolean, options?: VisibleOnAllWorkspacesOptions): void; - /** - * Sets whether the window traffic light buttons should be visible. - * - * @platform darwin - */ - setWindowButtonVisibility(visible: boolean): void; - /** - * Shows and gives focus to the window. - */ - show(): void; - /** - * Same as `webContents.showDefinitionForSelection()`. - * - * @platform darwin - */ - showDefinitionForSelection(): void; - /** - * Shows the window but doesn't focus on it. - */ - showInactive(): void; - /** - * Toggles the visibility of the tab bar if native tabs are enabled and there is - * only one tab in the current window. - * - * @platform darwin - */ - toggleTabBar(): void; - /** - * Unhooks all of the window messages. - * - * @platform win32 - */ - unhookAllWindowMessages(): void; - /** - * Unhook the window message. - * - * @platform win32 - */ - unhookWindowMessage(message: number): void; - /** - * Unmaximizes the window. - */ - unmaximize(): void; - /** - * A `string` property that defines an alternative title provided only to - * accessibility tools such as screen readers. This string is not directly visible - * to users. - */ - accessibleTitle: string; - /** - * A `boolean` property that determines whether the window menu bar should hide - * itself automatically. Once set, the menu bar will only show when users press the - * single `Alt` key. - * - * If the menu bar is already visible, setting this property to `true` won't hide - * it immediately. - */ - autoHideMenuBar: boolean; - /** - * A `boolean` property that determines whether the window can be manually closed - * by user. - * - * On Linux the setter is a no-op, although the getter returns `true`. - */ - closable: boolean; - /** - * A `boolean` property that specifies whether the window’s document has been - * edited. - * - * The icon in title bar will become gray when set to `true`. - * - * @platform darwin - */ - documentEdited: boolean; - /** - * A `boolean` property that determines whether the window is excluded from the - * application’s Windows menu. `false` by default. - * - * @platform darwin - */ - excludedFromShownWindowsMenu: boolean; - /** - * A `boolean` property that determines whether the window is focusable. - * - * @platform win32,darwin - */ - focusable: boolean; - /** - * A `boolean` property that determines whether the window is in fullscreen mode. - */ - fullScreen: boolean; - /** - * A `boolean` property that determines whether the maximize/zoom window button - * toggles fullscreen mode or maximizes the window. - */ - fullScreenable: boolean; - /** - * A `Integer` property representing the unique ID of the window. Each ID is unique - * among all `BrowserWindow` instances of the entire Electron application. - * - */ - readonly id: number; - /** - * A `boolean` property that determines whether the window is in kiosk mode. - */ - kiosk: boolean; - /** - * A `boolean` property that determines whether the window can be manually - * maximized by user. - * - * On Linux the setter is a no-op, although the getter returns `true`. - */ - maximizable: boolean; - /** - * A `boolean` property that determines whether the menu bar should be visible. - * - * **Note:** If the menu bar is auto-hide, users can still bring up the menu bar by - * pressing the single `Alt` key. - * - * @platform win32,linux - */ - menuBarVisible: boolean; - /** - * A `boolean` property that determines whether the window can be manually - * minimized by user. - * - * On Linux the setter is a no-op, although the getter returns `true`. - */ - minimizable: boolean; - /** - * A `boolean` property that determines Whether the window can be moved by user. - * - * On Linux the setter is a no-op, although the getter returns `true`. - */ - movable: boolean; - /** - * A `string` property that determines the pathname of the file the window - * represents, and the icon of the file will show in window's title bar. - * - * @platform darwin - */ - representedFilename: string; - /** - * A `boolean` property that determines whether the window can be manually resized - * by user. - */ - resizable: boolean; - /** - * A `boolean` property that determines whether the window has a shadow. - */ - shadow: boolean; - /** - * A `boolean` property that determines whether the window is in simple (pre-Lion) - * fullscreen mode. - */ - simpleFullScreen: boolean; - /** - * A `string` property that determines the title of the native window. - * - * **Note:** The title of the web page can be different from the title of the - * native window. - */ - title: string; - /** - * A `boolean` property that determines whether the window is visible on all - * workspaces. - * - * **Note:** Always returns false on Windows. - */ - visibleOnAllWorkspaces: boolean; - /** - * A `WebContents` object this window owns. All web page related events and - * operations will be done via it. - * - * See the `webContents` documentation for its methods and events. - * - */ - readonly webContents: WebContents; - } - - interface Certificate { - - // Docs: https://electronjs.org/docs/api/structures/certificate - - /** - * PEM encoded data - */ - data: string; - /** - * Fingerprint of the certificate - */ - fingerprint: string; - /** - * Issuer principal - */ - issuer: CertificatePrincipal; - /** - * Issuer certificate (if not self-signed) - */ - issuerCert: Certificate; - /** - * Issuer's Common Name - */ - issuerName: string; - /** - * Hex value represented string - */ - serialNumber: string; - /** - * Subject principal - */ - subject: CertificatePrincipal; - /** - * Subject's Common Name - */ - subjectName: string; - /** - * End date of the certificate being valid in seconds - */ - validExpiry: number; - /** - * Start date of the certificate being valid in seconds - */ - validStart: number; - } - - interface CertificatePrincipal { - - // Docs: https://electronjs.org/docs/api/structures/certificate-principal - - /** - * Common Name. - */ - commonName: string; - /** - * Country or region. - */ - country: string; - /** - * Locality. - */ - locality: string; - /** - * Organization names. - */ - organizations: string[]; - /** - * Organization Unit names. - */ - organizationUnits: string[]; - /** - * State or province. - */ - state: string; - } - - class ClientRequest extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/client-request - - /** - * Emitted when the `request` is aborted. The `abort` event will not be fired if - * the `request` is already closed. - */ - on(event: 'abort', listener: Function): this; - once(event: 'abort', listener: Function): this; - addListener(event: 'abort', listener: Function): this; - removeListener(event: 'abort', listener: Function): this; - /** - * Emitted as the last event in the HTTP request-response transaction. The `close` - * event indicates that no more events will be emitted on either the `request` or - * `response` objects. - */ - on(event: 'close', listener: Function): this; - once(event: 'close', listener: Function): this; - addListener(event: 'close', listener: Function): this; - removeListener(event: 'close', listener: Function): this; - /** - * Emitted when the `net` module fails to issue a network request. Typically when - * the `request` object emits an `error` event, a `close` event will subsequently - * follow and no response object will be provided. - */ - on(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - once(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - addListener(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - removeListener(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - /** - * Emitted just after the last chunk of the `request`'s data has been written into - * the `request` object. - */ - on(event: 'finish', listener: Function): this; - once(event: 'finish', listener: Function): this; - addListener(event: 'finish', listener: Function): this; - removeListener(event: 'finish', listener: Function): this; - /** - * Emitted when an authenticating proxy is asking for user credentials. - * - * The `callback` function is expected to be called back with user credentials: - * - * * `username` string - * * `password` string - * - * Providing empty credentials will cancel the request and report an authentication - * error on the response object: - */ - on(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - once(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - addListener(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - removeListener(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - /** - * Emitted when the server returns a redirect response (e.g. 301 Moved - * Permanently). Calling `request.followRedirect` will continue with the - * redirection. If this event is handled, `request.followRedirect` must be called - * **synchronously**, otherwise the request will be cancelled. - */ - on(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record<string, string[]>) => void): this; - once(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record<string, string[]>) => void): this; - addListener(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record<string, string[]>) => void): this; - removeListener(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record<string, string[]>) => void): this; - on(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - once(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - addListener(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - removeListener(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - /** - * ClientRequest - */ - constructor(options: (ClientRequestConstructorOptions) | (string)); - /** - * Cancels an ongoing HTTP transaction. If the request has already emitted the - * `close` event, the abort operation will have no effect. Otherwise an ongoing - * event will emit `abort` and `close` events. Additionally, if there is an ongoing - * response object,it will emit the `aborted` event. - */ - abort(): void; - /** - * Sends the last chunk of the request data. Subsequent write or end operations - * will not be allowed. The `finish` event is emitted just after the end operation. - */ - end(chunk?: (string) | (Buffer), encoding?: string, callback?: () => void): void; - /** - * Continues any pending redirection. Can only be called during a `'redirect'` - * event. - */ - followRedirect(): void; - /** - * The value of a previously set extra header name. - */ - getHeader(name: string): string; - /** - * * `active` boolean - Whether the request is currently active. If this is false - * no other properties will be set - * * `started` boolean - Whether the upload has started. If this is false both - * `current` and `total` will be set to 0. - * * `current` Integer - The number of bytes that have been uploaded so far - * * `total` Integer - The number of bytes that will be uploaded this request - * - * You can use this method in conjunction with `POST` requests to get the progress - * of a file upload or other data transfer. - */ - getUploadProgress(): UploadProgress; - /** - * Removes a previously set extra header name. This method can be called only - * before first write. Trying to call it after the first write will throw an error. - */ - removeHeader(name: string): void; - /** - * Adds an extra HTTP header. The header name will be issued as-is without - * lowercasing. It can be called only before first write. Calling this method after - * the first write will throw an error. If the passed value is not a `string`, its - * `toString()` method will be called to obtain the final value. - * - * Certain headers are restricted from being set by apps. These headers are listed - * below. More information on restricted headers can be found in Chromium's header - * utils. - * - * * `Content-Length` - * * `Host` - * * `Trailer` or `Te` - * * `Upgrade` - * * `Cookie2` - * * `Keep-Alive` - * * `Transfer-Encoding` - * - * Additionally, setting the `Connection` header to the value `upgrade` is also - * disallowed. - */ - setHeader(name: string, value: string): void; - /** - * `callback` is essentially a dummy function introduced in the purpose of keeping - * similarity with the Node.js API. It is called asynchronously in the next tick - * after `chunk` content have been delivered to the Chromium networking layer. - * Contrary to the Node.js implementation, it is not guaranteed that `chunk` - * content have been flushed on the wire before `callback` is called. - * - * Adds a chunk of data to the request body. The first write operation may cause - * the request headers to be issued on the wire. After the first write operation, - * it is not allowed to add or remove a custom header. - */ - write(chunk: (string) | (Buffer), encoding?: string, callback?: () => void): void; - /** - * A `boolean` specifying whether the request will use HTTP chunked transfer - * encoding or not. Defaults to false. The property is readable and writable, - * however it can be set only before the first write operation as the HTTP headers - * are not yet put on the wire. Trying to set the `chunkedEncoding` property after - * the first write will throw an error. - * - * Using chunked encoding is strongly recommended if you need to send a large - * request body as data will be streamed in small chunks instead of being - * internally buffered inside Electron process memory. - */ - chunkedEncoding: boolean; - } - - interface Clipboard { - - // Docs: https://electronjs.org/docs/api/clipboard - - /** - * An array of supported formats for the clipboard `type`. - */ - availableFormats(type?: 'selection' | 'clipboard'): string[]; - /** - * Clears the clipboard content. - */ - clear(type?: 'selection' | 'clipboard'): void; - /** - * Whether the clipboard supports the specified `format`. - * - * @experimental - */ - has(format: string, type?: 'selection' | 'clipboard'): boolean; - /** - * Reads `format` type from the clipboard. - * - * `format` should contain valid ASCII characters and have `/` separator. `a/c`, - * `a/bc` are valid formats while `/abc`, `abc/`, `a/`, `/a`, `a` are not valid. - * - * @experimental - */ - read(format: string): string; - /** - * * `title` string - * * `url` string - * - * Returns an Object containing `title` and `url` keys representing the bookmark in - * the clipboard. The `title` and `url` values will be empty strings when the - * bookmark is unavailable. The `title` value will always be empty on Windows. - * - * @platform darwin,win32 - */ - readBookmark(): ReadBookmark; - /** - * Reads `format` type from the clipboard. - * - * @experimental - */ - readBuffer(format: string): Buffer; - /** - * The text on the find pasteboard, which is the pasteboard that holds information - * about the current state of the active application’s find panel. - * - * This method uses synchronous IPC when called from the renderer process. The - * cached value is reread from the find pasteboard whenever the application is - * activated. - * - * @platform darwin - */ - readFindText(): string; - /** - * The content in the clipboard as markup. - */ - readHTML(type?: 'selection' | 'clipboard'): string; - /** - * The image content in the clipboard. - */ - readImage(type?: 'selection' | 'clipboard'): NativeImage; - /** - * The content in the clipboard as RTF. - */ - readRTF(type?: 'selection' | 'clipboard'): string; - /** - * The content in the clipboard as plain text. - */ - readText(type?: 'selection' | 'clipboard'): string; - /** - * Writes `data` to the clipboard. - */ - write(data: Data, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `title` (macOS only) and `url` into the clipboard as a bookmark. - * - * **Note:** Most apps on Windows don't support pasting bookmarks into them so you - * can use `clipboard.write` to write both a bookmark and fallback text to the - * clipboard. - * - * @platform darwin,win32 - */ - writeBookmark(title: string, url: string, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `buffer` into the clipboard as `format`. - * - * @experimental - */ - writeBuffer(format: string, buffer: Buffer, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `text` into the find pasteboard (the pasteboard that holds - * information about the current state of the active application’s find panel) as - * plain text. This method uses synchronous IPC when called from the renderer - * process. - * - * @platform darwin - */ - writeFindText(text: string): void; - /** - * Writes `markup` to the clipboard. - */ - writeHTML(markup: string, type?: 'selection' | 'clipboard'): void; - /** - * Writes `image` to the clipboard. - */ - writeImage(image: NativeImage, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `text` into the clipboard in RTF. - */ - writeRTF(text: string, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `text` into the clipboard as plain text. - */ - writeText(text: string, type?: 'selection' | 'clipboard'): void; - } - - class CommandLine { - - // Docs: https://electronjs.org/docs/api/command-line - - /** - * Append an argument to Chromium's command line. The argument will be quoted - * correctly. Switches will precede arguments regardless of appending order. - * - * If you're appending an argument like `--switch=value`, consider using - * `appendSwitch('switch', 'value')` instead. - * - * **Note:** This will not affect `process.argv`. The intended usage of this - * function is to control Chromium's behavior. - */ - appendArgument(value: string): void; - /** - * Append a switch (with optional `value`) to Chromium's command line. - * - * **Note:** This will not affect `process.argv`. The intended usage of this - * function is to control Chromium's behavior. - */ - appendSwitch(the_switch: string, value?: string): void; - /** - * The command-line switch value. - * - * **Note:** When the switch is not present or has no value, it returns empty - * string. - */ - getSwitchValue(the_switch: string): string; - /** - * Whether the command-line switch is present. - */ - hasSwitch(the_switch: string): boolean; - /** - * Removes the specified switch from Chromium's command line. - * - * **Note:** This will not affect `process.argv`. The intended usage of this - * function is to control Chromium's behavior. - */ - removeSwitch(the_switch: string): void; - } - - interface ContentTracing { - - // Docs: https://electronjs.org/docs/api/content-tracing - - /** - * resolves with an array of category groups once all child processes have - * acknowledged the `getCategories` request - * - * Get a set of category groups. The category groups can change as new code paths - * are reached. See also the list of built-in tracing categories. - * - * > **NOTE:** Electron adds a non-default tracing category called `"electron"`. - * This category can be used to capture Electron-specific tracing events. - */ - getCategories(): Promise<string[]>; - /** - * Resolves with an object containing the `value` and `percentage` of trace buffer - * maximum usage - * - * * `value` number - * * `percentage` number - * - * Get the maximum usage across processes of trace buffer as a percentage of the - * full state. - */ - getTraceBufferUsage(): Promise<Electron.TraceBufferUsageReturnValue>; - /** - * resolved once all child processes have acknowledged the `startRecording` - * request. - * - * Start recording on all processes. - * - * Recording begins immediately locally and asynchronously on child processes as - * soon as they receive the EnableRecording request. - * - * If a recording is already running, the promise will be immediately resolved, as - * only one trace operation can be in progress at a time. - */ - startRecording(options: (TraceConfig) | (TraceCategoriesAndOptions)): Promise<void>; - /** - * resolves with a path to a file that contains the traced data once all child - * processes have acknowledged the `stopRecording` request - * - * Stop recording on all processes. - * - * Child processes typically cache trace data and only rarely flush and send trace - * data back to the main process. This helps to minimize the runtime overhead of - * tracing since sending trace data over IPC can be an expensive operation. So, to - * end tracing, Chromium asynchronously asks all child processes to flush any - * pending trace data. - * - * Trace data will be written into `resultFilePath`. If `resultFilePath` is empty - * or not provided, trace data will be written to a temporary file, and the path - * will be returned in the promise. - */ - stopRecording(resultFilePath?: string): Promise<string>; - } - - interface ContextBridge { - - // Docs: https://electronjs.org/docs/api/context-bridge - - exposeInMainWorld(apiKey: string, api: any): void; - } - - interface Cookie { - - // Docs: https://electronjs.org/docs/api/structures/cookie - - /** - * The domain of the cookie; this will be normalized with a preceding dot so that - * it's also valid for subdomains. - */ - domain?: string; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * Not provided for session cookies. - */ - expirationDate?: number; - /** - * Whether the cookie is a host-only cookie; this will only be `true` if no domain - * was passed. - */ - hostOnly?: boolean; - /** - * Whether the cookie is marked as HTTP only. - */ - httpOnly?: boolean; - /** - * The name of the cookie. - */ - name: string; - /** - * The path of the cookie. - */ - path?: string; - /** - * The Same Site policy applied to this cookie. Can be `unspecified`, - * `no_restriction`, `lax` or `strict`. - */ - sameSite: ('unspecified' | 'no_restriction' | 'lax' | 'strict'); - /** - * Whether the cookie is marked as secure. - */ - secure?: boolean; - /** - * Whether the cookie is a session cookie or a persistent cookie with an expiration - * date. - */ - session?: boolean; - /** - * The value of the cookie. - */ - value: string; - } - - class Cookies extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/cookies - - /** - * Emitted when a cookie is changed because it was added, edited, removed, or - * expired. - */ - on(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, - /** - * The cause of the change with one of the following values: - */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), - /** - * `true` if the cookie was removed, `false` otherwise. - */ - removed: boolean) => void): this; - once(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, - /** - * The cause of the change with one of the following values: - */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), - /** - * `true` if the cookie was removed, `false` otherwise. - */ - removed: boolean) => void): this; - addListener(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, - /** - * The cause of the change with one of the following values: - */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), - /** - * `true` if the cookie was removed, `false` otherwise. - */ - removed: boolean) => void): this; - removeListener(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + once(event: 'certificate-error', listener: (event: Event, + webContents: WebContents, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + addListener(event: 'certificate-error', listener: (event: Event, + webContents: WebContents, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + removeListener(event: 'certificate-error', listener: (event: Event, + webContents: WebContents, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + /** + * Emitted when the child process unexpectedly disappears. This is normally because + * it was crashed or killed. It does not include renderer processes. + */ + on(event: 'child-process-gone', listener: (event: Event, + details: Details) => void): this; + once(event: 'child-process-gone', listener: (event: Event, + details: Details) => void): this; + addListener(event: 'child-process-gone', listener: (event: Event, + details: Details) => void): this; + removeListener(event: 'child-process-gone', listener: (event: Event, + details: Details) => void): this; + /** + * Emitted during Handoff when an activity from a different device wants to be + * resumed. You should call `event.preventDefault()` if you want to handle this + * event. + * + * A user activity can be continued only in an app that has the same developer Team + * ID as the activity's source app and that supports the activity's type. Supported + * activity types are specified in the app's `Info.plist` under the + * `NSUserActivityTypes` key. + * + * @platform darwin + */ + on(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: unknown, + details: ContinueActivityDetails) => void): this; + once(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: unknown, + details: ContinueActivityDetails) => void): this; + addListener(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: unknown, + details: ContinueActivityDetails) => void): this; + removeListener(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: unknown, + details: ContinueActivityDetails) => void): this; + /** + * Emitted during Handoff when an activity from a different device fails to be + * resumed. + * + * @platform darwin + */ + on(event: 'continue-activity-error', listener: (event: Event, /** - * The cause of the change with one of the following values: + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + type: string, /** - * `true` if the cookie was removed, `false` otherwise. + * A string with the error's localized description. */ - removed: boolean) => void): this; - /** - * A promise which resolves when the cookie store has been flushed - * - * Writes any unwritten cookies data to disk. - */ - flushStore(): Promise<void>; - /** - * A promise which resolves an array of cookie objects. - * - * Sends a request to get all cookies matching `filter`, and resolves a promise - * with the response. - */ - get(filter: CookiesGetFilter): Promise<Electron.Cookie[]>; - /** - * A promise which resolves when the cookie has been removed - * - * Removes the cookies matching `url` and `name` - */ - remove(url: string, name: string): Promise<void>; - /** - * A promise which resolves when the cookie has been set - * - * Sets a cookie with `details`. - */ - set(details: CookiesSetDetails): Promise<void>; - } - - interface CPUUsage { - - // Docs: https://electronjs.org/docs/api/structures/cpu-usage - - /** - * The number of average idle CPU wakeups per second since the last call to - * getCPUUsage. First call returns 0. Will always return 0 on Windows. - */ - idleWakeupsPerSecond: number; - /** - * Percentage of CPU used since the last call to getCPUUsage. First call returns 0. - */ - percentCPUUsage: number; - } - - interface CrashReport { - - // Docs: https://electronjs.org/docs/api/structures/crash-report - - date: Date; - id: string; - } - - interface CrashReporter { - - // Docs: https://electronjs.org/docs/api/crash-reporter - - /** - * Set an extra parameter to be sent with the crash report. The values specified - * here will be sent in addition to any values set via the `extra` option when - * `start` was called. - * - * Parameters added in this fashion (or via the `extra` parameter to - * `crashReporter.start`) are specific to the calling process. Adding extra - * parameters in the main process will not cause those parameters to be sent along - * with crashes from renderer or other child processes. Similarly, adding extra - * parameters in a renderer process will not result in those parameters being sent - * with crashes that occur in other renderer processes or in the main process. - * - * **Note:** Parameters have limits on the length of the keys and values. Key names - * must be no longer than 39 bytes, and values must be no longer than 20320 bytes. - * Keys with names longer than the maximum will be silently ignored. Key values - * longer than the maximum length will be truncated. - */ - addExtraParameter(key: string, value: string): void; - /** - * The date and ID of the last crash report. Only crash reports that have been - * uploaded will be returned; even if a crash report is present on disk it will not - * be returned until it is uploaded. In the case that there are no uploaded - * reports, `null` is returned. - * - * **Note:** This method is only available in the main process. - */ - getLastCrashReport(): CrashReport; - /** - * The current 'extra' parameters of the crash reporter. - */ - getParameters(): Record<string, string>; - /** - * Returns all uploaded crash reports. Each report contains the date and uploaded - * ID. - * - * **Note:** This method is only available in the main process. - */ - getUploadedReports(): CrashReport[]; - /** - * Whether reports should be submitted to the server. Set through the `start` - * method or `setUploadToServer`. - * - * **Note:** This method is only available in the main process. - */ - getUploadToServer(): boolean; - /** - * Remove an extra parameter from the current set of parameters. Future crashes - * will not include this parameter. - */ - removeExtraParameter(key: string): void; - /** - * This would normally be controlled by user preferences. This has no effect if - * called before `start` is called. - * - * **Note:** This method is only available in the main process. - */ - setUploadToServer(uploadToServer: boolean): void; - /** - * This method must be called before using any other `crashReporter` APIs. Once - * initialized this way, the crashpad handler collects crashes from all - * subsequently created processes. The crash reporter cannot be disabled once - * started. - * - * This method should be called as early as possible in app startup, preferably - * before `app.on('ready')`. If the crash reporter is not initialized at the time a - * renderer process is created, then that renderer process will not be monitored by - * the crash reporter. - * - * **Note:** You can test out the crash reporter by generating a crash using - * `process.crash()`. - * - * **Note:** If you need to send additional/updated `extra` parameters after your - * first call `start` you can call `addExtraParameter`. - * - * **Note:** Parameters passed in `extra`, `globalExtra` or set with - * `addExtraParameter` have limits on the length of the keys and values. Key names - * must be at most 39 bytes long, and values must be no longer than 127 bytes. Keys - * with names longer than the maximum will be silently ignored. Key values longer - * than the maximum length will be truncated. - * - * **Note:** This method is only available in the main process. - */ - start(options: CrashReporterStartOptions): void; - } - - interface CustomScheme { - - // Docs: https://electronjs.org/docs/api/structures/custom-scheme - - privileges?: Privileges; - /** - * Custom schemes to be registered with options. - */ - scheme: string; - } - - class Debugger extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/debugger - - /** - * Emitted when the debugging session is terminated. This happens either when - * `webContents` is closed or devtools is invoked for the attached `webContents`. - */ - on(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - once(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - addListener(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - removeListener(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - /** - * Emitted whenever the debugging target issues an instrumentation event. - */ - on(event: 'message', listener: (event: Event, - /** - * Method name. - */ - method: string, - /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. - */ - params: any, - /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. - */ - sessionId: string) => void): this; - once(event: 'message', listener: (event: Event, - /** - * Method name. - */ - method: string, - /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. - */ - params: any, - /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. - */ - sessionId: string) => void): this; - addListener(event: 'message', listener: (event: Event, - /** - * Method name. - */ - method: string, - /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. - */ - params: any, - /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. - */ - sessionId: string) => void): this; - removeListener(event: 'message', listener: (event: Event, + error: string) => void): this; + once(event: 'continue-activity-error', listener: (event: Event, /** - * Method name. + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - method: string, + type: string, /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. + * A string with the error's localized description. */ - params: any, + error: string) => void): this; + addListener(event: 'continue-activity-error', listener: (event: Event, /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - sessionId: string) => void): this; - /** - * Attaches the debugger to the `webContents`. - */ - attach(protocolVersion?: string): void; - /** - * Detaches the debugger from the `webContents`. - */ - detach(): void; - /** - * Whether a debugger is attached to the `webContents`. - */ - isAttached(): boolean; - /** - * A promise that resolves with the response defined by the 'returns' attribute of - * the command description in the remote debugging protocol or is rejected - * indicating the failure of the command. - * - * Send given command to the debugging target. - */ - sendCommand(method: string, commandParams?: any, sessionId?: string): Promise<any>; - } - - interface DesktopCapturer { - - // Docs: https://electronjs.org/docs/api/desktop-capturer - - /** - * Resolves with an array of `DesktopCapturerSource` objects, each - * `DesktopCapturerSource` represents a screen or an individual window that can be - * captured. - * - * **Note** Capturing the screen contents requires user consent on macOS 10.15 - * Catalina or higher, which can detected by - * `systemPreferences.getMediaAccessStatus`. - */ - getSources(options: SourcesOptions): Promise<Electron.DesktopCapturerSource[]>; - } - - interface DesktopCapturerSource { - - // Docs: https://electronjs.org/docs/api/structures/desktop-capturer-source - - /** - * An icon image of the application that owns the window or null if the source has - * a type screen. The size of the icon is not known in advance and depends on what - * the application provides. - */ - appIcon: NativeImage; - /** - * A unique identifier that will correspond to the `id` of the matching Display - * returned by the Screen API. On some platforms, this is equivalent to the `XX` - * portion of the `id` field above and on others it will differ. It will be an - * empty string if not available. - */ - display_id: string; - /** - * The identifier of a window or screen that can be used as a `chromeMediaSourceId` - * constraint when calling [`navigator.webkitGetUserMedia`]. The format of the - * identifier will be `window:XX:YY` or `screen:ZZ:0`. XX is the windowID/handle. - * YY is 1 for the current process, and 0 for all others. ZZ is a sequential number - * that represents the screen, and it does not equal to the index in the source's - * name. - */ - id: string; - /** - * A screen source will be named either `Entire Screen` or `Screen <index>`, while - * the name of a window source will match the window title. - */ - name: string; - /** - * A thumbnail image. **Note:** There is no guarantee that the size of the - * thumbnail is the same as the `thumbnailSize` specified in the `options` passed - * to `desktopCapturer.getSources`. The actual size depends on the scale of the - * screen or window. - */ - thumbnail: NativeImage; - } - - interface Dialog { - - // Docs: https://electronjs.org/docs/api/dialog - - /** - * resolves when the certificate trust dialog is shown. - * - * On macOS, this displays a modal dialog that shows a message and certificate - * information, and gives the user the option of trusting/importing the - * certificate. If you provide a `browserWindow` argument the dialog will be - * attached to the parent window, making it modal. - * - * On Windows the options are more limited, due to the Win32 APIs used: - * - * * The `message` argument is not used, as the OS provides its own confirmation - * dialog. - * * The `browserWindow` argument is ignored since it is not possible to make this - * confirmation dialog modal. - * - * @platform darwin,win32 - */ - showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions): Promise<void>; - /** - * resolves when the certificate trust dialog is shown. - * - * On macOS, this displays a modal dialog that shows a message and certificate - * information, and gives the user the option of trusting/importing the - * certificate. If you provide a `browserWindow` argument the dialog will be - * attached to the parent window, making it modal. - * - * On Windows the options are more limited, due to the Win32 APIs used: - * - * * The `message` argument is not used, as the OS provides its own confirmation - * dialog. - * * The `browserWindow` argument is ignored since it is not possible to make this - * confirmation dialog modal. - * - * @platform darwin,win32 - */ - showCertificateTrustDialog(options: CertificateTrustDialogOptions): Promise<void>; - /** - * Displays a modal dialog that shows an error message. - * - * This API can be called safely before the `ready` event the `app` module emits, - * it is usually used to report errors in early stage of startup. If called before - * the app `ready`event on Linux, the message will be emitted to stderr, and no GUI - * dialog will appear. - */ - showErrorBox(title: string, content: string): void; - /** - * resolves with a promise containing the following properties: - * - * * `response` number - The index of the clicked button. - * * `checkboxChecked` boolean - The checked state of the checkbox if - * `checkboxLabel` was set. Otherwise `false`. - * - * Shows a message box. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - */ - showMessageBox(browserWindow: BrowserWindow, options: MessageBoxOptions): Promise<Electron.MessageBoxReturnValue>; - /** - * resolves with a promise containing the following properties: - * - * * `response` number - The index of the clicked button. - * * `checkboxChecked` boolean - The checked state of the checkbox if - * `checkboxLabel` was set. Otherwise `false`. - * - * Shows a message box. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - */ - showMessageBox(options: MessageBoxOptions): Promise<Electron.MessageBoxReturnValue>; - /** - * the index of the clicked button. - * - * Shows a message box, it will block the process until the message box is closed. - * It returns the index of the clicked button. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. If `browserWindow` is not shown dialog will not be - * attached to it. In such case it will be displayed as an independent window. - */ - showMessageBoxSync(browserWindow: BrowserWindow, options: MessageBoxSyncOptions): number; - /** - * the index of the clicked button. - * - * Shows a message box, it will block the process until the message box is closed. - * It returns the index of the clicked button. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. If `browserWindow` is not shown dialog will not be - * attached to it. In such case it will be displayed as an independent window. - */ - showMessageBoxSync(options: MessageBoxSyncOptions): number; - /** - * Resolve with an object containing the following: - * - * * `canceled` boolean - whether or not the dialog was canceled. - * * `filePaths` string[] - An array of file paths chosen by the user. If the - * dialog is cancelled this will be an empty array. - * * `bookmarks` string[] (optional) _macOS_ _mas_ - An array matching the - * `filePaths` array of base64 encoded strings which contains security scoped - * bookmark data. `securityScopedBookmarks` must be enabled for this to be - * populated. (For return values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions): Promise<Electron.OpenDialogReturnValue>; - /** - * Resolve with an object containing the following: - * - * * `canceled` boolean - whether or not the dialog was canceled. - * * `filePaths` string[] - An array of file paths chosen by the user. If the - * dialog is cancelled this will be an empty array. - * * `bookmarks` string[] (optional) _macOS_ _mas_ - An array matching the - * `filePaths` array of base64 encoded strings which contains security scoped - * bookmark data. `securityScopedBookmarks` must be enabled for this to be - * populated. (For return values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialog(options: OpenDialogOptions): Promise<Electron.OpenDialogReturnValue>; - /** - * the file paths chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialogSync(browserWindow: BrowserWindow, options: OpenDialogSyncOptions): (string[]) | (undefined); - /** - * the file paths chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialogSync(options: OpenDialogSyncOptions): (string[]) | (undefined); - /** - * Resolve with an object containing the following: - * - * * `canceled` boolean - whether or not the dialog was canceled. - * * `filePath` string (optional) - If the dialog is canceled, this will be - * `undefined`. - * * `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which - * contains the security scoped bookmark data for the saved file. - * `securityScopedBookmarks` must be enabled for this to be present. (For return - * values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - * - * **Note:** On macOS, using the asynchronous version is recommended to avoid - * issues when expanding and collapsing the dialog. - */ - showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions): Promise<Electron.SaveDialogReturnValue>; - /** - * Resolve with an object containing the following: - * - * * `canceled` boolean - whether or not the dialog was canceled. - * * `filePath` string (optional) - If the dialog is canceled, this will be - * `undefined`. - * * `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which - * contains the security scoped bookmark data for the saved file. - * `securityScopedBookmarks` must be enabled for this to be present. (For return - * values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - * - * **Note:** On macOS, using the asynchronous version is recommended to avoid - * issues when expanding and collapsing the dialog. - */ - showSaveDialog(options: SaveDialogOptions): Promise<Electron.SaveDialogReturnValue>; - /** - * the path of the file chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - */ - showSaveDialogSync(browserWindow: BrowserWindow, options: SaveDialogSyncOptions): (string) | (undefined); - /** - * the path of the file chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - */ - showSaveDialogSync(options: SaveDialogSyncOptions): (string) | (undefined); - } - - interface Display { - - // Docs: https://electronjs.org/docs/api/structures/display - - /** - * Can be `available`, `unavailable`, `unknown`. - */ - accelerometerSupport: ('available' | 'unavailable' | 'unknown'); - /** - * the bounds of the display in DIP points. - */ - bounds: Rectangle; - /** - * The number of bits per pixel. - */ - colorDepth: number; - /** - * represent a color space (three-dimensional object which contains all realizable - * color combinations) for the purpose of color conversions - */ - colorSpace: string; - /** - * The number of bits per color component. - */ - depthPerComponent: number; - /** - * The display refresh rate. - */ - displayFrequency: number; - /** - * Unique identifier associated with the display. - */ - id: number; - /** - * `true` for an internal display and `false` for an external display - */ - internal: boolean; - /** - * Whether or not the display is a monochrome display. - */ - monochrome: boolean; - /** - * Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. - */ - rotation: number; - /** - * Output device's pixel scale factor. - */ - scaleFactor: number; - size: Size; - /** - * Can be `available`, `unavailable`, `unknown`. - */ - touchSupport: ('available' | 'unavailable' | 'unknown'); - /** - * the work area of the display in DIP points. - */ - workArea: Rectangle; - workAreaSize: Size; - } - - class Dock { - - // Docs: https://electronjs.org/docs/api/dock - - /** - * an ID representing the request. - * - * When `critical` is passed, the dock icon will bounce until either the - * application becomes active or the request is canceled. - * - * When `informational` is passed, the dock icon will bounce for one second. - * However, the request remains active until either the application becomes active - * or the request is canceled. - * - * **Note:** This method can only be used while the app is not focused; when the - * app is focused it will return -1. - * - * @platform darwin - */ - bounce(type?: 'critical' | 'informational'): number; - /** - * Cancel the bounce of `id`. - * - * @platform darwin - */ - cancelBounce(id: number): void; - /** - * Bounces the Downloads stack if the filePath is inside the Downloads folder. - * - * @platform darwin - */ - downloadFinished(filePath: string): void; - /** - * The badge string of the dock. - * - * @platform darwin - */ - getBadge(): string; - /** - * The application's [dock menu][dock-menu]. - * - * @platform darwin - */ - getMenu(): (Menu) | (null); - /** - * Hides the dock icon. - * - * @platform darwin - */ - hide(): void; - /** - * Whether the dock icon is visible. - * - * @platform darwin - */ - isVisible(): boolean; - /** - * Sets the string to be displayed in the dock’s badging area. - * - * @platform darwin - */ - setBadge(text: string): void; - /** - * Sets the `image` associated with this dock icon. - * - * @platform darwin - */ - setIcon(image: (NativeImage) | (string)): void; - /** - * Sets the application's [dock menu][dock-menu]. - * - * @platform darwin - */ - setMenu(menu: Menu): void; - /** - * Resolves when the dock icon is shown. - * - * @platform darwin - */ - show(): Promise<void>; - } - - class DownloadItem extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/download-item - - /** - * Emitted when the download is in a terminal state. This includes a completed - * download, a cancelled download (via `downloadItem.cancel()`), and interrupted - * download that can't be resumed. - * - * The `state` can be one of following: - * - * * `completed` - The download completed successfully. - * * `cancelled` - The download has been cancelled. - * * `interrupted` - The download has interrupted and can not resume. - */ - on(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - once(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - addListener(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - removeListener(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - /** - * Emitted when the download has been updated and is not done. - * - * The `state` can be one of following: - * - * * `progressing` - The download is in-progress. - * * `interrupted` - The download has interrupted and can be resumed. - */ - on(event: 'updated', listener: (event: Event, - /** - * Can be `progressing` or `interrupted`. - */ - state: ('progressing' | 'interrupted')) => void): this; - once(event: 'updated', listener: (event: Event, - /** - * Can be `progressing` or `interrupted`. - */ - state: ('progressing' | 'interrupted')) => void): this; - addListener(event: 'updated', listener: (event: Event, - /** - * Can be `progressing` or `interrupted`. - */ - state: ('progressing' | 'interrupted')) => void): this; - removeListener(event: 'updated', listener: (event: Event, + type: string, /** - * Can be `progressing` or `interrupted`. + * A string with the error's localized description. */ - state: ('progressing' | 'interrupted')) => void): this; - /** - * Cancels the download operation. - */ - cancel(): void; - /** - * Whether the download can resume. - */ - canResume(): boolean; - /** - * The Content-Disposition field from the response header. - */ - getContentDisposition(): string; - /** - * ETag header value. - */ - getETag(): string; - /** - * The file name of the download item. - * - * **Note:** The file name is not always the same as the actual one saved in local - * disk. If user changes the file name in a prompted download saving dialog, the - * actual name of saved file will be different. - */ - getFilename(): string; - /** - * Last-Modified header value. - */ - getLastModifiedTime(): string; - /** - * The files mime type. - */ - getMimeType(): string; - /** - * The received bytes of the download item. - */ - getReceivedBytes(): number; - /** - * Returns the object previously set by - * `downloadItem.setSaveDialogOptions(options)`. - */ - getSaveDialogOptions(): SaveDialogOptions; - /** - * The save path of the download item. This will be either the path set via - * `downloadItem.setSavePath(path)` or the path selected from the shown save - * dialog. - */ - getSavePath(): string; - /** - * Number of seconds since the UNIX epoch when the download was started. - */ - getStartTime(): number; - /** - * The current state. Can be `progressing`, `completed`, `cancelled` or - * `interrupted`. - * - * **Note:** The following methods are useful specifically to resume a `cancelled` - * item when session is restarted. - */ - getState(): ('progressing' | 'completed' | 'cancelled' | 'interrupted'); - /** - * The total size in bytes of the download item. - * - * If the size is unknown, it returns 0. - */ - getTotalBytes(): number; - /** - * The origin URL where the item is downloaded from. - */ - getURL(): string; - /** - * The complete URL chain of the item including any redirects. - */ - getURLChain(): string[]; - /** - * Whether the download has user gesture. - */ - hasUserGesture(): boolean; - /** - * Whether the download is paused. - */ - isPaused(): boolean; - /** - * Pauses the download. - */ - pause(): void; - /** - * Resumes the download that has been paused. - * - * **Note:** To enable resumable downloads the server you are downloading from must - * support range requests and provide both `Last-Modified` and `ETag` header - * values. Otherwise `resume()` will dismiss previously received bytes and restart - * the download from the beginning. - */ - resume(): void; - /** - * This API allows the user to set custom options for the save dialog that opens - * for the download item by default. The API is only available in session's - * `will-download` callback function. - */ - setSaveDialogOptions(options: SaveDialogOptions): void; - /** - * The API is only available in session's `will-download` callback function. If - * `path` doesn't exist, Electron will try to make the directory recursively. If - * user doesn't set the save path via the API, Electron will use the original - * routine to determine the save path; this usually prompts a save dialog. - */ - setSavePath(path: string): void; - /** - * A `string` property that determines the save file path of the download item. - * - * The property is only available in session's `will-download` callback function. - * If user doesn't set the save path via the property, Electron will use the - * original routine to determine the save path; this usually prompts a save dialog. - */ - savePath: string; - } - - interface Event extends GlobalEvent { - - // Docs: https://electronjs.org/docs/api/structures/event - - preventDefault: (() => void); - } - - interface Extension { - - // Docs: https://electronjs.org/docs/api/structures/extension - - id: string; - /** - * Copy of the extension's manifest data. - */ - manifest: any; - name: string; - /** - * The extension's file path. - */ - path: string; - /** - * The extension's `chrome-extension://` URL. - */ - url: string; - version: string; - } - - interface ExtensionInfo { - - // Docs: https://electronjs.org/docs/api/structures/extension-info - - name: string; - version: string; - } - - interface FileFilter { - - // Docs: https://electronjs.org/docs/api/structures/file-filter - - extensions: string[]; - name: string; - } - - interface FilePathWithHeaders { - - // Docs: https://electronjs.org/docs/api/structures/file-path-with-headers - - /** - * Additional headers to be sent. - */ - headers?: Record<string, string>; - /** - * The path to the file to send. - */ - path: string; - } - - interface GlobalShortcut { - - // Docs: https://electronjs.org/docs/api/global-shortcut - - /** - * Whether this application has registered `accelerator`. - * - * When the accelerator is already taken by other applications, this call will - * still return `false`. This behavior is intended by operating systems, since they - * don't want applications to fight for global shortcuts. - */ - isRegistered(accelerator: Accelerator): boolean; - /** - * Whether or not the shortcut was registered successfully. - * - * Registers a global shortcut of `accelerator`. The `callback` is called when the - * registered shortcut is pressed by the user. - * - * When the accelerator is already taken by other applications, this call will - * silently fail. This behavior is intended by operating systems, since they don't - * want applications to fight for global shortcuts. - * - * The following accelerators will not be registered successfully on macOS 10.14 - * Mojave unless the app has been authorized as a trusted accessibility client: - * - * * "Media Play/Pause" - * * "Media Next Track" - * * "Media Previous Track" - * * "Media Stop" - */ - register(accelerator: Accelerator, callback: () => void): boolean; - /** - * Registers a global shortcut of all `accelerator` items in `accelerators`. The - * `callback` is called when any of the registered shortcuts are pressed by the - * user. - * - * When a given accelerator is already taken by other applications, this call will - * silently fail. This behavior is intended by operating systems, since they don't - * want applications to fight for global shortcuts. - * - * The following accelerators will not be registered successfully on macOS 10.14 - * Mojave unless the app has been authorized as a trusted accessibility client: - * - * * "Media Play/Pause" - * * "Media Next Track" - * * "Media Previous Track" - * * "Media Stop" - */ - registerAll(accelerators: string[], callback: () => void): void; - /** - * Unregisters the global shortcut of `accelerator`. - */ - unregister(accelerator: Accelerator): void; - /** - * Unregisters all of the global shortcuts. - */ - unregisterAll(): void; - } - - interface GPUFeatureStatus { - - // Docs: https://electronjs.org/docs/api/structures/gpu-feature-status - - /** - * Canvas. - */ - '2d_canvas': string; - /** - * Flash. - */ - flash_3d: string; - /** - * Flash Stage3D. - */ - flash_stage3d: string; - /** - * Flash Stage3D Baseline profile. - */ - flash_stage3d_baseline: string; - /** - * Compositing. - */ - gpu_compositing: string; - /** - * Multiple Raster Threads. - */ - multiple_raster_threads: string; - /** - * Native GpuMemoryBuffers. - */ - native_gpu_memory_buffers: string; - /** - * Rasterization. - */ - rasterization: string; - /** - * Video Decode. - */ - video_decode: string; - /** - * Video Encode. - */ - video_encode: string; - /** - * VPx Video Decode. - */ - vpx_decode: string; - /** - * WebGL. - */ - webgl: string; - /** - * WebGL2. - */ - webgl2: string; - } - - interface HIDDevice { - - // Docs: https://electronjs.org/docs/api/structures/hid-device - - /** - * Unique identifier for the device. - */ - deviceId: string; - /** - * Unique identifier for the HID interface. A device may have multiple HID - * interfaces. - */ - guid?: string; - /** - * Name of the device. - */ - name: string; - /** - * The USB product ID. - */ - productId: number; - /** - * The USB device serial number. - */ - serialNumber?: string; - /** - * The USB vendor ID. - */ - vendorId: number; - } - - interface InAppPurchase extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/in-app-purchase - - on(event: 'transactions-updated', listener: Function): this; - once(event: 'transactions-updated', listener: Function): this; - addListener(event: 'transactions-updated', listener: Function): this; - removeListener(event: 'transactions-updated', listener: Function): this; - /** - * whether a user can make a payment. - */ - canMakePayments(): boolean; - /** - * Completes all pending transactions. - */ - finishAllTransactions(): void; - /** - * Completes the pending transactions corresponding to the date. - */ - finishTransactionByDate(date: string): void; - /** - * Resolves with an array of `Product` objects. - * - * Retrieves the product descriptions. - */ - getProducts(productIDs: string[]): Promise<Electron.Product[]>; - /** - * the path to the receipt. - */ - getReceiptURL(): string; - /** - * Returns `true` if the product is valid and added to the payment queue. - * - * You should listen for the `transactions-updated` event as soon as possible and - * certainly before you call `purchaseProduct`. - */ - purchaseProduct(productID: string, quantity?: number): Promise<boolean>; - /** - * Restores finished transactions. This method can be called either to install - * purchases on additional devices, or to restore purchases for an application that - * the user deleted and reinstalled. - * - * The payment queue delivers a new transaction for each previously completed - * transaction that can be restored. Each transaction includes a copy of the - * original transaction. - */ - restoreCompletedTransactions(): void; - } - - class IncomingMessage extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/incoming-message - - /** - * Emitted when a request has been canceled during an ongoing HTTP transaction. - */ - on(event: 'aborted', listener: Function): this; - once(event: 'aborted', listener: Function): this; - addListener(event: 'aborted', listener: Function): this; - removeListener(event: 'aborted', listener: Function): this; - /** - * The `data` event is the usual method of transferring response data into - * applicative code. - */ - on(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - once(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - addListener(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - removeListener(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - /** - * Indicates that response body has ended. Must be placed before 'data' event. - */ - on(event: 'end', listener: Function): this; - once(event: 'end', listener: Function): this; - addListener(event: 'end', listener: Function): this; - removeListener(event: 'end', listener: Function): this; - /** - * Returns: - * - * `error` Error - Typically holds an error string identifying failure root cause. - * - * Emitted when an error was encountered while streaming response data events. For - * instance, if the server closes the underlying while the response is still - * streaming, an `error` event will be emitted on the response object and a `close` - * event will subsequently follow on the request object. - */ - on(event: 'error', listener: Function): this; - once(event: 'error', listener: Function): this; - addListener(event: 'error', listener: Function): this; - removeListener(event: 'error', listener: Function): this; - /** - * A `Record<string, string | string[]>` representing the HTTP response headers. - * The `headers` object is formatted as follows: - * - * * All header names are lowercased. - * * Duplicates of `age`, `authorization`, `content-length`, `content-type`, - * `etag`, `expires`, `from`, `host`, `if-modified-since`, `if-unmodified-since`, - * `last-modified`, `location`, `max-forwards`, `proxy-authorization`, `referer`, - * `retry-after`, `server`, or `user-agent` are discarded. - * * `set-cookie` is always an array. Duplicates are added to the array. - * * For duplicate `cookie` headers, the values are joined together with '; '. - * * For all other headers, the values are joined together with ', '. - */ - headers: Record<string, (string) | (string[])>; - /** - * A `string` indicating the HTTP protocol version number. Typical values are '1.0' - * or '1.1'. Additionally `httpVersionMajor` and `httpVersionMinor` are two - * Integer-valued readable properties that return respectively the HTTP major and - * minor version numbers. - */ - httpVersion: string; - /** - * An `Integer` indicating the HTTP protocol major version number. - */ - httpVersionMajor: number; - /** - * An `Integer` indicating the HTTP protocol minor version number. - */ - httpVersionMinor: number; - /** - * A `string[]` containing the raw HTTP response headers exactly as they were - * received. The keys and values are in the same list. It is not a list of tuples. - * So, the even-numbered offsets are key values, and the odd-numbered offsets are - * the associated values. Header names are not lowercased, and duplicates are not - * merged. - */ - rawHeaders: string[]; - /** - * An `Integer` indicating the HTTP response status code. - */ - statusCode: number; - /** - * A `string` representing the HTTP status message. - */ - statusMessage: string; - } - - interface InputEvent { - - // Docs: https://electronjs.org/docs/api/structures/input-event - - /** - * An array of modifiers of the event, can be `shift`, `control`, `ctrl`, `alt`, - * `meta`, `command`, `cmd`, `isKeypad`, `isAutoRepeat`, `leftButtonDown`, - * `middleButtonDown`, `rightButtonDown`, `capsLock`, `numLock`, `left`, `right`. - */ - modifiers?: Array<'shift' | 'control' | 'ctrl' | 'alt' | 'meta' | 'command' | 'cmd' | 'isKeypad' | 'isAutoRepeat' | 'leftButtonDown' | 'middleButtonDown' | 'rightButtonDown' | 'capsLock' | 'numLock' | 'left' | 'right'>; - } - - interface IOCounters { - - // Docs: https://electronjs.org/docs/api/structures/io-counters - - /** - * Then number of I/O other operations. - */ - otherOperationCount: number; - /** - * Then number of I/O other transfers. - */ - otherTransferCount: number; - /** - * The number of I/O read operations. - */ - readOperationCount: number; - /** - * The number of I/O read transfers. - */ - readTransferCount: number; - /** - * The number of I/O write operations. - */ - writeOperationCount: number; - /** - * The number of I/O write transfers. - */ - writeTransferCount: number; - } - - interface IpcMain extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/ipc-main - - /** - * Adds a handler for an `invoke`able IPC. This handler will be called whenever a - * renderer calls `ipcRenderer.invoke(channel, ...args)`. - * - * If `listener` returns a Promise, the eventual result of the promise will be - * returned as a reply to the remote caller. Otherwise, the return value of the - * listener will be used as the value of the reply. - * - * The `event` that is passed as the first argument to the handler is the same as - * that passed to a regular event listener. It includes information about which - * WebContents is the source of the invoke request. - * - * Errors thrown through `handle` in the main process are not transparent as they - * are serialized and only the `message` property from the original error is - * provided to the renderer process. Please refer to #24427 for details. - */ - handle(channel: string, listener: (event: IpcMainInvokeEvent, ...args: any[]) => (Promise<void>) | (any)): void; - /** - * Handles a single `invoke`able IPC message, then removes the listener. See - * `ipcMain.handle(channel, listener)`. - */ - handleOnce(channel: string, listener: (event: IpcMainInvokeEvent, ...args: any[]) => (Promise<void>) | (any)): void; - /** - * Listens to `channel`, when a new message arrives `listener` would be called with - * `listener(event, args...)`. - */ - on(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; - /** - * Adds a one time `listener` function for the event. This `listener` is invoked - * only the next time a message is sent to `channel`, after which it is removed. - */ - once(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; - /** - * Removes listeners of the specified `channel`. - */ - removeAllListeners(channel?: string): this; - /** - * Removes any handler for `channel`, if present. - */ - removeHandler(channel: string): void; - /** - * Removes the specified `listener` from the listener array for the specified - * `channel`. - */ - removeListener(channel: string, listener: (...args: any[]) => void): this; - } - - interface IpcMainEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/ipc-main-event - - /** - * The ID of the renderer frame that sent this message - */ - frameId: number; - /** - * A list of MessagePorts that were transferred with this message - */ - ports: MessagePortMain[]; - /** - * The internal ID of the renderer process that sent this message - */ - processId: number; - /** - * A function that will send an IPC message to the renderer frame that sent the - * original message that you are currently handling. You should use this method to - * "reply" to the sent message in order to guarantee the reply will go to the - * correct process and frame. - */ - reply: Function; - /** - * Set this to the value to be returned in a synchronous message - */ - returnValue: any; - /** - * Returns the `webContents` that sent the message - */ - sender: WebContents; - /** - * The frame that sent this message - * - */ - readonly senderFrame: WebFrameMain; - } - - interface IpcMainInvokeEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/ipc-main-invoke-event - - /** - * The ID of the renderer frame that sent this message - */ - frameId: number; - /** - * The internal ID of the renderer process that sent this message - */ - processId: number; - /** - * Returns the `webContents` that sent the message - */ - sender: WebContents; - /** - * The frame that sent this message - * - */ - readonly senderFrame: WebFrameMain; - } - - interface IpcRenderer extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/ipc-renderer - - /** - * Resolves with the response from the main process. - * - * Send a message to the main process via `channel` and expect a result - * asynchronously. Arguments will be serialized with the Structured Clone - * Algorithm, just like `window.postMessage`, so prototype chains will not be - * included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw - * an exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * Since the main process does not have support for DOM objects such as - * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over - * Electron's IPC to the main process, as the main process would have no way to - * decode them. Attempting to send such objects over IPC will result in an error. - * - * The main process should listen for `channel` with `ipcMain.handle()`. - * - * For example: - * - * If you need to transfer a `MessagePort` to the main process, use - * `ipcRenderer.postMessage`. - * - * If you do not need a response to the message, consider using `ipcRenderer.send`. - */ - invoke(channel: string, ...args: any[]): Promise<any>; - /** - * Listens to `channel`, when a new message arrives `listener` would be called with - * `listener(event, args...)`. - */ - on(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; - /** - * Adds a one time `listener` function for the event. This `listener` is invoked - * only the next time a message is sent to `channel`, after which it is removed. - */ - once(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; - /** - * Send a message to the main process, optionally transferring ownership of zero or - * more `MessagePort` objects. - * - * The transferred `MessagePort` objects will be available in the main process as - * `MessagePortMain` objects by accessing the `ports` property of the emitted - * event. - * - * For example: - * - * For more information on using `MessagePort` and `MessageChannel`, see the MDN - * documentation. - */ - postMessage(channel: string, message: any, transfer?: MessagePort[]): void; - /** - * Removes all listeners, or those of the specified `channel`. - */ - removeAllListeners(channel: string): this; - /** - * Removes the specified `listener` from the listener array for the specified - * `channel`. - */ - removeListener(channel: string, listener: (...args: any[]) => void): this; - /** - * Send an asynchronous message to the main process via `channel`, along with - * arguments. Arguments will be serialized with the Structured Clone Algorithm, - * just like `window.postMessage`, so prototype chains will not be included. - * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an - * exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * Since the main process does not have support for DOM objects such as - * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over - * Electron's IPC to the main process, as the main process would have no way to - * decode them. Attempting to send such objects over IPC will result in an error. - * - * The main process handles it by listening for `channel` with the `ipcMain` - * module. - * - * If you need to transfer a `MessagePort` to the main process, use - * `ipcRenderer.postMessage`. - * - * If you want to receive a single response from the main process, like the result - * of a method call, consider using `ipcRenderer.invoke`. - */ - send(channel: string, ...args: any[]): void; - /** - * The value sent back by the `ipcMain` handler. - * - * Send a message to the main process via `channel` and expect a result - * synchronously. Arguments will be serialized with the Structured Clone Algorithm, - * just like `window.postMessage`, so prototype chains will not be included. - * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an - * exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * Since the main process does not have support for DOM objects such as - * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over - * Electron's IPC to the main process, as the main process would have no way to - * decode them. Attempting to send such objects over IPC will result in an error. - * - * The main process handles it by listening for `channel` with `ipcMain` module, - * and replies by setting `event.returnValue`. - * - * > :warning: **WARNING**: Sending a synchronous message will block the whole - * renderer process until the reply is received, so use this method only as a last - * resort. It's much better to use the asynchronous version, `invoke()`. - */ - sendSync(channel: string, ...args: any[]): any; - /** - * Sends a message to a window with `webContentsId` via `channel`. - */ - sendTo(webContentsId: number, channel: string, ...args: any[]): void; - /** - * Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in - * the host page instead of the main process. - */ - sendToHost(channel: string, ...args: any[]): void; - } - - interface IpcRendererEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/ipc-renderer-event - - /** - * A list of MessagePorts that were transferred with this message - */ - ports: MessagePort[]; - /** - * The `IpcRenderer` instance that emitted the event originally - */ - sender: IpcRenderer; - /** - * The `webContents.id` that sent the message, you can call - * `event.sender.sendTo(event.senderId, ...)` to reply to the message, see - * ipcRenderer.sendTo for more information. This only applies to messages sent from - * a different renderer. Messages sent directly from the main process set - * `event.senderId` to `0`. - */ - senderId: number; - } - - interface JumpListCategory { - - // Docs: https://electronjs.org/docs/api/structures/jump-list-category - - /** - * Array of `JumpListItem` objects if `type` is `tasks` or `custom`, otherwise it - * should be omitted. - */ - items?: JumpListItem[]; - /** - * Must be set if `type` is `custom`, otherwise it should be omitted. - */ - name?: string; - /** - * One of the following: - */ - type?: ('tasks' | 'frequent' | 'recent' | 'custom'); - } - - interface JumpListItem { - - // Docs: https://electronjs.org/docs/api/structures/jump-list-item - - /** - * The command line arguments when `program` is executed. Should only be set if - * `type` is `task`. - */ - args?: string; - /** - * Description of the task (displayed in a tooltip). Should only be set if `type` - * is `task`. Maximum length 260 characters. - */ - description?: string; - /** - * The index of the icon in the resource file. If a resource file contains multiple - * icons this value can be used to specify the zero-based index of the icon that - * should be displayed for this task. If a resource file contains only one icon, - * this property should be set to zero. - */ - iconIndex?: number; - /** - * The absolute path to an icon to be displayed in a Jump List, which can be an - * arbitrary resource file that contains an icon (e.g. `.ico`, `.exe`, `.dll`). You - * can usually specify `process.execPath` to show the program icon. - */ - iconPath?: string; - /** - * Path of the file to open, should only be set if `type` is `file`. - */ - path?: string; - /** - * Path of the program to execute, usually you should specify `process.execPath` - * which opens the current program. Should only be set if `type` is `task`. - */ - program?: string; - /** - * The text to be displayed for the item in the Jump List. Should only be set if - * `type` is `task`. - */ - title?: string; - /** - * One of the following: - */ - type?: ('task' | 'separator' | 'file'); - /** - * The working directory. Default is empty. - */ - workingDirectory?: string; - } - - interface KeyboardEvent { - - // Docs: https://electronjs.org/docs/api/structures/keyboard-event - - /** - * whether an Alt key was used in an accelerator to trigger the Event - */ - altKey?: boolean; - /** - * whether the Control key was used in an accelerator to trigger the Event - */ - ctrlKey?: boolean; - /** - * whether a meta key was used in an accelerator to trigger the Event - */ - metaKey?: boolean; - /** - * whether a Shift key was used in an accelerator to trigger the Event - */ - shiftKey?: boolean; - /** - * whether an accelerator was used to trigger the event as opposed to another user - * gesture like mouse click - */ - triggeredByAccelerator?: boolean; - } - - interface KeyboardInputEvent extends InputEvent { - - // Docs: https://electronjs.org/docs/api/structures/keyboard-input-event - - /** - * The character that will be sent as the keyboard event. Should only use the valid - * key codes in Accelerator. - */ - keyCode: string; - /** - * The type of the event, can be `keyDown`, `keyUp` or `char`. - */ - type: ('keyDown' | 'keyUp' | 'char'); - } - - interface MemoryInfo { - - // Docs: https://electronjs.org/docs/api/structures/memory-info - - /** - * The maximum amount of memory that has ever been pinned to actual physical RAM. - */ - peakWorkingSetSize: number; - /** - * The amount of memory not shared by other processes, such as JS heap or HTML - * content. - * - * @platform win32 - */ - privateBytes?: number; - /** - * The amount of memory currently pinned to actual physical RAM. - */ - workingSetSize: number; - } - - interface MemoryUsageDetails { - - // Docs: https://electronjs.org/docs/api/structures/memory-usage-details - - count: number; - liveSize: number; - size: number; - } - - class Menu { - - // Docs: https://electronjs.org/docs/api/menu - - /** - * Emitted when a popup is closed either manually or with `menu.closePopup()`. - */ - on(event: 'menu-will-close', listener: (event: Event) => void): this; - once(event: 'menu-will-close', listener: (event: Event) => void): this; - addListener(event: 'menu-will-close', listener: (event: Event) => void): this; - removeListener(event: 'menu-will-close', listener: (event: Event) => void): this; - /** - * Emitted when `menu.popup()` is called. - */ - on(event: 'menu-will-show', listener: (event: Event) => void): this; - once(event: 'menu-will-show', listener: (event: Event) => void): this; - addListener(event: 'menu-will-show', listener: (event: Event) => void): this; - removeListener(event: 'menu-will-show', listener: (event: Event) => void): this; - /** - * Menu - */ - constructor(); - /** - * Generally, the `template` is an array of `options` for constructing a MenuItem. - * The usage can be referenced above. - * - * You can also attach other fields to the element of the `template` and they will - * become properties of the constructed menu items. - */ - static buildFromTemplate(template: Array<(MenuItemConstructorOptions) | (MenuItem)>): Menu; - /** - * The application menu, if set, or `null`, if not set. - * - * **Note:** The returned `Menu` instance doesn't support dynamic addition or - * removal of menu items. Instance properties can still be dynamically modified. - */ - static getApplicationMenu(): (Menu) | (null); - /** - * Sends the `action` to the first responder of application. This is used for - * emulating default macOS menu behaviors. Usually you would use the `role` - * property of a `MenuItem`. - * - * See the macOS Cocoa Event Handling Guide for more information on macOS' native - * actions. - * - * @platform darwin - */ - static sendActionToFirstResponder(action: string): void; - /** - * Sets `menu` as the application menu on macOS. On Windows and Linux, the `menu` - * will be set as each window's top menu. - * - * Also on Windows and Linux, you can use a `&` in the top-level item name to - * indicate which letter should get a generated accelerator. For example, using - * `&File` for the file menu would result in a generated `Alt-F` accelerator that - * opens the associated menu. The indicated character in the button label then gets - * an underline, and the `&` character is not displayed on the button label. - * - * In order to escape the `&` character in an item name, add a proceeding `&`. For - * example, `&&File` would result in `&File` displayed on the button label. - * - * Passing `null` will suppress the default menu. On Windows and Linux, this has - * the additional effect of removing the menu bar from the window. - * - * **Note:** The default menu will be created automatically if the app does not set - * one. It contains standard items such as `File`, `Edit`, `View`, `Window` and - * `Help`. - */ - static setApplicationMenu(menu: (Menu) | (null)): void; - /** - * Appends the `menuItem` to the menu. - */ - append(menuItem: MenuItem): void; - /** - * Closes the context menu in the `browserWindow`. - */ - closePopup(browserWindow?: BrowserWindow): void; - /** - * the item with the specified `id` - */ - getMenuItemById(id: string): (MenuItem) | (null); - /** - * Inserts the `menuItem` to the `pos` position of the menu. - */ - insert(pos: number, menuItem: MenuItem): void; - /** - * Pops up this menu as a context menu in the `BrowserWindow`. - */ - popup(options?: PopupOptions): void; - /** - * A `MenuItem[]` array containing the menu's items. - * - * Each `Menu` consists of multiple `MenuItem`s and each `MenuItem` can have a - * submenu. - */ - items: MenuItem[]; - } - - class MenuItem { - - // Docs: https://electronjs.org/docs/api/menu-item - - /** - * MenuItem - */ - constructor(options: MenuItemConstructorOptions); - /** - * An `Accelerator` (optional) indicating the item's accelerator, if set. - */ - accelerator?: Accelerator; - /** - * A `boolean` indicating whether the item is checked, this property can be - * dynamically changed. - * - * A `checkbox` menu item will toggle the `checked` property on and off when - * selected. - * - * A `radio` menu item will turn on its `checked` property when clicked, and will - * turn off that property for all adjacent items in the same menu. - * - * You can add a `click` function for additional behavior. - */ - checked: boolean; - /** - * A `Function` that is fired when the MenuItem receives a click event. It can be - * called with `menuItem.click(event, focusedWindow, focusedWebContents)`. - * - * * `event` KeyboardEvent - * * `focusedWindow` BrowserWindow - * * `focusedWebContents` WebContents - */ - click: Function; - /** - * A `number` indicating an item's sequential unique id. - */ - commandId: number; - /** - * A `boolean` indicating whether the item is enabled, this property can be - * dynamically changed. - */ - enabled: boolean; - /** - * A `NativeImage | string` (optional) indicating the item's icon, if set. - */ - icon?: (NativeImage) | (string); - /** - * A `string` indicating the item's unique id, this property can be dynamically - * changed. - */ - id: string; - /** - * A `string` indicating the item's visible label. - */ - label: string; - /** - * A `Menu` that the item is a part of. - */ - menu: Menu; - /** - * A `boolean` indicating if the accelerator should be registered with the system - * or just displayed. - * - * This property can be dynamically changed. - */ - registerAccelerator: boolean; - /** - * A `string` (optional) indicating the item's role, if set. Can be `undo`, `redo`, - * `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, - * `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, - * `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, - * `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, - * `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, - * `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, - * `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, - * `moveTabToNewWindow` or `windowMenu` - */ - role?: ('undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'toggleSpellChecker' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'startSpeaking' | 'stopSpeaking' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'shareMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'); - /** - * A `SharingItem` indicating the item to share when the `role` is `shareMenu`. - * - * This property can be dynamically changed. - * - * @platform darwin - */ - sharingItem: SharingItem; - /** - * A `string` indicating the item's sublabel. - */ - sublabel: string; - /** - * A `Menu` (optional) containing the menu item's submenu, if present. - */ - submenu?: Menu; - /** - * A `string` indicating the item's hover text. - * - * @platform darwin - */ - toolTip: string; - /** - * A `string` indicating the type of the item. Can be `normal`, `separator`, - * `submenu`, `checkbox` or `radio`. - */ - type: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'); - /** - * An `Accelerator | null` indicating the item's user-assigned accelerator for the - * menu item. - * - * **Note:** This property is only initialized after the `MenuItem` has been added - * to a `Menu`. Either via `Menu.buildFromTemplate` or via - * `Menu.append()/insert()`. Accessing before initialization will just return - * `null`. - * - * @platform darwin - */ - readonly userAccelerator: (Accelerator) | (null); - /** - * A `boolean` indicating whether the item is visible, this property can be - * dynamically changed. - */ - visible: boolean; - } - - class MessageChannelMain extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/message-channel-main - - /** - * A `MessagePortMain` property. - */ - port1: MessagePortMain; - /** - * A `MessagePortMain` property. - */ - port2: MessagePortMain; - } - - class MessagePortMain extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/message-port-main - - /** - * Emitted when the remote end of a MessagePortMain object becomes disconnected. - */ - on(event: 'close', listener: Function): this; - once(event: 'close', listener: Function): this; - addListener(event: 'close', listener: Function): this; - removeListener(event: 'close', listener: Function): this; - /** - * Emitted when a MessagePortMain object receives a message. - */ - on(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - once(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - addListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - removeListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - /** - * Disconnects the port, so it is no longer active. - */ - close(): void; - /** - * Sends a message from the port, and optionally, transfers ownership of objects to - * other browsing contexts. - */ - postMessage(message: any, transfer?: MessagePortMain[]): void; - /** - * Starts the sending of messages queued on the port. Messages will be queued until - * this method is called. - */ - start(): void; - } - - interface MimeTypedBuffer { - - // Docs: https://electronjs.org/docs/api/structures/mime-typed-buffer - - /** - * Charset of the buffer. - */ - charset?: string; - /** - * The actual Buffer content. - */ - data: Buffer; - /** - * MIME type of the buffer. - */ - mimeType?: string; - } - - interface MouseInputEvent extends InputEvent { - - // Docs: https://electronjs.org/docs/api/structures/mouse-input-event - - /** - * The button pressed, can be `left`, `middle`, `right`. - */ - button?: ('left' | 'middle' | 'right'); - clickCount?: number; - globalX?: number; - globalY?: number; - movementX?: number; - movementY?: number; - /** - * The type of the event, can be `mouseDown`, `mouseUp`, `mouseEnter`, - * `mouseLeave`, `contextMenu`, `mouseWheel` or `mouseMove`. - */ - type: ('mouseDown' | 'mouseUp' | 'mouseEnter' | 'mouseLeave' | 'contextMenu' | 'mouseWheel' | 'mouseMove'); - x: number; - y: number; - } - - interface MouseWheelInputEvent extends MouseInputEvent { - - // Docs: https://electronjs.org/docs/api/structures/mouse-wheel-input-event - - accelerationRatioX?: number; - accelerationRatioY?: number; - canScroll?: boolean; - deltaX?: number; - deltaY?: number; - hasPreciseScrollingDeltas?: boolean; - /** - * The type of the event, can be `mouseWheel`. - */ - type: ('mouseWheel'); - wheelTicksX?: number; - wheelTicksY?: number; - } - - class NativeImage { - - // Docs: https://electronjs.org/docs/api/native-image - - /** - * Creates an empty `NativeImage` instance. - */ - static createEmpty(): NativeImage; - /** - * Creates a new `NativeImage` instance from `buffer` that contains the raw bitmap - * pixel data returned by `toBitmap()`. The specific format is platform-dependent. - */ - static createFromBitmap(buffer: Buffer, options: CreateFromBitmapOptions): NativeImage; - /** - * Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or - * JPEG first. - */ - static createFromBuffer(buffer: Buffer, options?: CreateFromBufferOptions): NativeImage; - /** - * Creates a new `NativeImage` instance from `dataURL`. - */ - static createFromDataURL(dataURL: string): NativeImage; - /** - * Creates a new `NativeImage` instance from the NSImage that maps to the given - * image name. See `System Icons` for a list of possible values. - * - * The `hslShift` is applied to the image with the following rules: - * - * * `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map to 0 - * and 360 on the hue color wheel (red). - * * `hsl_shift[1]` (saturation): A saturation shift for the image, with the - * following key values: 0 = remove all color. 0.5 = leave unchanged. 1 = fully - * saturate the image. - * * `hsl_shift[2]` (lightness): A lightness shift for the image, with the - * following key values: 0 = remove all lightness (make all pixels black). 0.5 = - * leave unchanged. 1 = full lightness (make all pixels white). - * - * This means that `[-1, 0, 1]` will make the image completely white and `[-1, 1, - * 0]` will make the image completely black. - * - * In some cases, the `NSImageName` doesn't match its string representation; one - * example of this is `NSFolderImageName`, whose string representation would - * actually be `NSFolder`. Therefore, you'll need to determine the correct string - * representation for your image before passing it in. This can be done with the - * following: - * - * `echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); - * }' | clang -otest -x objective-c -framework Cocoa - && ./test` - * - * where `SYSTEM_IMAGE_NAME` should be replaced with any value from this list. - * - * @platform darwin - */ - static createFromNamedImage(imageName: string, hslShift?: number[]): NativeImage; - /** - * Creates a new `NativeImage` instance from a file located at `path`. This method - * returns an empty image if the `path` does not exist, cannot be read, or is not a - * valid image. - */ - static createFromPath(path: string): NativeImage; - /** - * fulfilled with the file's thumbnail preview image, which is a NativeImage. - * - * @platform darwin,win32 - */ - static createThumbnailFromPath(path: string, maxSize: Size): Promise<Electron.NativeImage>; - /** - * Add an image representation for a specific scale factor. This can be used to - * explicitly add different scale factor representations to an image. This can be - * called on empty images. - */ - addRepresentation(options: AddRepresentationOptions): void; - /** - * The cropped image. - */ - crop(rect: Rectangle): NativeImage; - /** - * 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. - */ - getAspectRatio(scaleFactor?: number): number; - /** - * A Buffer that contains the image's raw bitmap pixel data. - * - * The difference between `getBitmap()` and `toBitmap()` is that `getBitmap()` does - * not copy the bitmap data, so you have to use the returned Buffer immediately in - * current event loop tick; otherwise the data might be changed or destroyed. - */ - getBitmap(options?: BitmapOptions): Buffer; - /** - * A Buffer that stores C pointer to underlying native handle of the image. On - * macOS, a pointer to `NSImage` instance would be returned. - * - * Notice that the returned pointer is a weak pointer to the underlying native - * image instead of a copy, so you _must_ ensure that the associated `nativeImage` - * instance is kept around. - * - * @platform darwin - */ - getNativeHandle(): Buffer; - /** - * An array of all scale factors corresponding to representations for a given - * nativeImage. - */ - getScaleFactors(): number[]; - /** - * If `scaleFactor` is passed, this will return the size corresponding to the image - * representation most closely matching the passed value. - */ - getSize(scaleFactor?: number): Size; - /** - * Whether the image is empty. - */ - isEmpty(): boolean; - /** - * Whether the image is a template image. - */ - isTemplateImage(): boolean; - /** - * The resized image. - * - * If only the `height` or the `width` are specified then the current aspect ratio - * will be preserved in the resized image. - */ - resize(options: ResizeOptions): NativeImage; - /** - * Marks the image as a template image. - */ - setTemplateImage(option: boolean): void; - /** - * A Buffer that contains a copy of the image's raw bitmap pixel data. - */ - toBitmap(options?: ToBitmapOptions): Buffer; - /** - * The data URL of the image. - */ - toDataURL(options?: ToDataURLOptions): string; - /** - * A Buffer that contains the image's `JPEG` encoded data. - */ - toJPEG(quality: number): Buffer; - /** - * A Buffer that contains the image's `PNG` encoded data. - */ - toPNG(options?: ToPNGOptions): Buffer; - /** - * A `boolean` property that determines whether the image is considered a template - * image. - * - * Please note that this property only has an effect on macOS. - * - * @platform darwin - */ - isMacTemplateImage: boolean; - } - - interface NativeTheme extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/native-theme - - /** - * Emitted when something in the underlying NativeTheme has changed. This normally - * means that either the value of `shouldUseDarkColors`, - * `shouldUseHighContrastColors` or `shouldUseInvertedColorScheme` has changed. You - * will have to check them to determine which one has changed. - */ - on(event: 'updated', listener: Function): this; - once(event: 'updated', listener: Function): this; - addListener(event: 'updated', listener: Function): this; - removeListener(event: 'updated', listener: Function): this; - /** - * A `boolean` indicating whether Chromium is in forced colors mode, controlled by - * system accessibility settings. Currently, Windows high contrast is the only - * system setting that triggers forced colors mode. - * - * @platform win32 - */ - readonly inForcedColorsMode: boolean; - /** - * A `boolean` for if the OS / Chromium currently has a dark mode enabled or is - * being instructed to show a dark-style UI. If you want to modify this value you - * should use `themeSource` below. - * - */ - readonly shouldUseDarkColors: boolean; - /** - * A `boolean` for if the OS / Chromium currently has high-contrast mode enabled or - * is being instructed to show a high-contrast UI. - * - * @platform darwin,win32 - */ - readonly shouldUseHighContrastColors: boolean; - /** - * A `boolean` for if the OS / Chromium currently has an inverted color scheme or - * is being instructed to use an inverted color scheme. - * - * @platform darwin,win32 - */ - readonly shouldUseInvertedColorScheme: boolean; - /** - * A `string` property that can be `system`, `light` or `dark`. It is used to - * override and supersede the value that Chromium has chosen to use internally. - * - * Setting this property to `system` will remove the override and everything will - * be reset to the OS default. By default `themeSource` is `system`. - * - * Settings this property to `dark` will have the following effects: - * - * * `nativeTheme.shouldUseDarkColors` will be `true` when accessed - * * Any UI Electron renders on Linux and Windows including context menus, - * devtools, etc. will use the dark UI. - * * Any UI the OS renders on macOS including menus, window frames, etc. will use - * the dark UI. - * * The `prefers-color-scheme` CSS query will match `dark` mode. - * * The `updated` event will be emitted - * - * Settings this property to `light` will have the following effects: - * - * * `nativeTheme.shouldUseDarkColors` will be `false` when accessed - * * Any UI Electron renders on Linux and Windows including context menus, - * devtools, etc. will use the light UI. - * * Any UI the OS renders on macOS including menus, window frames, etc. will use - * the light UI. - * * The `prefers-color-scheme` CSS query will match `light` mode. - * * The `updated` event will be emitted - * - * The usage of this property should align with a classic "dark mode" state machine - * in your application where the user has three options. - * - * * `Follow OS` --> `themeSource = 'system'` - * * `Dark Mode` --> `themeSource = 'dark'` - * * `Light Mode` --> `themeSource = 'light'` - * - * Your application should then always use `shouldUseDarkColors` to determine what - * CSS to apply. - */ - themeSource: ('system' | 'light' | 'dark'); - } - - interface Net { - - // Docs: https://electronjs.org/docs/api/net - - /** - * Whether there is currently internet connection. - * - * A return value of `false` is a pretty strong indicator that the user won't be - * able to connect to remote sites. However, a return value of `true` is - * inconclusive; even if some link is up, it is uncertain whether a particular - * connection attempt to a particular remote site will be successful. - */ - isOnline(): boolean; - /** - * Creates a `ClientRequest` instance using the provided `options` which are - * directly forwarded to the `ClientRequest` constructor. The `net.request` method - * would be used to issue both secure and insecure HTTP requests according to the - * specified protocol scheme in the `options` object. - */ - request(options: (ClientRequestConstructorOptions) | (string)): ClientRequest; - /** - * A `boolean` property. Whether there is currently internet connection. - * - * A return value of `false` is a pretty strong indicator that the user won't be - * able to connect to remote sites. However, a return value of `true` is - * inconclusive; even if some link is up, it is uncertain whether a particular - * connection attempt to a particular remote site will be successful. - * - */ - readonly online: boolean; - } - - interface NetLog { - - // Docs: https://electronjs.org/docs/api/net-log - - /** - * resolves when the net log has begun recording. - * - * Starts recording network events to `path`. - */ - startLogging(path: string, options?: StartLoggingOptions): Promise<void>; - /** - * resolves when the net log has been flushed to disk. - * - * Stops recording network events. If not called, net logging will automatically - * end when app quits. - */ - stopLogging(): Promise<void>; - /** - * A `boolean` property that indicates whether network logs are currently being - * recorded. - * - */ - readonly currentlyLogging: boolean; - } - - interface NewWindowWebContentsEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/new-window-web-contents-event - - newGuest?: BrowserWindow; - } - - class Notification extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/notification - - on(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - once(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - addListener(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - removeListener(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - /** - * Emitted when the notification is clicked by the user. - */ - on(event: 'click', listener: (event: Event) => void): this; - once(event: 'click', listener: (event: Event) => void): this; - addListener(event: 'click', listener: (event: Event) => void): this; - removeListener(event: 'click', listener: (event: Event) => void): this; - /** - * Emitted when the notification is closed by manual intervention from the user. - * - * This event is not guaranteed to be emitted in all cases where the notification - * is closed. - */ - on(event: 'close', listener: (event: Event) => void): this; - once(event: 'close', listener: (event: Event) => void): this; - addListener(event: 'close', listener: (event: Event) => void): this; - removeListener(event: 'close', listener: (event: Event) => void): this; - /** - * Emitted when an error is encountered while creating and showing the native - * notification. - * - * @platform win32 - */ - on(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - once(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - addListener(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - removeListener(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - /** - * Emitted when the user clicks the "Reply" button on a notification with - * `hasReply: true`. - * - * @platform darwin - */ - on(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - once(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - addListener(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - removeListener(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - /** - * Emitted when the notification is shown to the user, note this could be fired - * multiple times as a notification can be shown multiple times through the - * `show()` method. - */ - on(event: 'show', listener: (event: Event) => void): this; - once(event: 'show', listener: (event: Event) => void): this; - addListener(event: 'show', listener: (event: Event) => void): this; - removeListener(event: 'show', listener: (event: Event) => void): this; - /** - * Notification - */ - constructor(options?: NotificationConstructorOptions); - /** - * Whether or not desktop notifications are supported on the current system - */ - static isSupported(): boolean; - /** - * Dismisses the notification. - */ - close(): void; - /** - * Immediately shows the notification to the user, please note this means unlike - * the HTML5 Notification implementation, instantiating a `new Notification` does - * not immediately show it to the user, you need to call this method before the OS - * will display it. - * - * If the notification has been shown before, this method will dismiss the - * previously shown notification and create a new one with identical properties. - */ - show(): void; - /** - * A `NotificationAction[]` property representing the actions of the notification. - */ - actions: NotificationAction[]; - /** - * A `string` property representing the body of the notification. - */ - body: string; - /** - * A `string` property representing the close button text of the notification. - */ - closeButtonText: string; - /** - * A `boolean` property representing whether the notification has a reply action. - */ - hasReply: boolean; - /** - * A `string` property representing the reply placeholder of the notification. - */ - replyPlaceholder: string; - /** - * A `boolean` property representing whether the notification is silent. - */ - silent: boolean; - /** - * A `string` property representing the sound of the notification. - */ - sound: string; - /** - * A `string` property representing the subtitle of the notification. - */ - subtitle: string; - /** - * A `string` property representing the type of timeout duration for the - * notification. Can be 'default' or 'never'. - * - * If `timeoutType` is set to 'never', the notification never expires. It stays - * open until closed by the calling API or the user. - * - * @platform linux,win32 - */ - timeoutType: ('default' | 'never'); - /** - * A `string` property representing the title of the notification. - */ - title: string; - /** - * A `string` property representing the custom Toast XML of the notification. - * - * @platform win32 - */ - toastXml: string; - /** - * A `string` property representing the urgency level of the notification. Can be - * 'normal', 'critical', or 'low'. - * - * Default is 'low' - see NotifyUrgency for more information. - * - * @platform linux - */ - urgency: ('normal' | 'critical' | 'low'); - } - - interface NotificationAction { - - // Docs: https://electronjs.org/docs/api/structures/notification-action - - /** - * The label for the given action. - */ - text?: string; - /** - * The type of action, can be `button`. - */ - type: ('button'); - } - - interface NotificationResponse { - - // Docs: https://electronjs.org/docs/api/structures/notification-response - - /** - * The identifier string of the action that the user selected. - */ - actionIdentifier: string; - /** - * The delivery date of the notification. - */ - date: number; - /** - * The unique identifier for this notification request. - */ - identifier: string; - /** - * A dictionary of custom information associated with the notification. - */ - userInfo: Record<string, any>; - /** - * The text entered or chosen by the user. - */ - userText?: string; - } - - interface PaymentDiscount { - - // Docs: https://electronjs.org/docs/api/structures/payment-discount - - /** - * A string used to uniquely identify a discount offer for a product. - */ - identifier: string; - /** - * A string that identifies the key used to generate the signature. - */ - keyIdentifier: string; - /** - * A universally unique ID (UUID) value that you define. - */ - nonce: string; - /** - * A UTF-8 string representing the properties of a specific discount offer, - * cryptographically signed. - */ - signature: string; - /** - * The date and time of the signature's creation in milliseconds, formatted in Unix - * epoch time. - */ - timestamp: number; - } - - interface Point { - - // Docs: https://electronjs.org/docs/api/structures/point - - x: number; - y: number; - } - - interface PostBody { - - // Docs: https://electronjs.org/docs/api/structures/post-body - - /** - * The boundary used to separate multiple parts of the message. Only valid when - * `contentType` is `multipart/form-data`. - */ - boundary?: string; - /** - * The `content-type` header used for the data. One of - * `application/x-www-form-urlencoded` or `multipart/form-data`. Corresponds to the - * `enctype` attribute of the submitted HTML form. - */ - contentType: string; - /** - * The post data to be sent to the new window. - */ - data: Array<(UploadRawData) | (UploadFile)>; - } - - interface PowerMonitor extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/power-monitor - - /** - * Emitted when the system is about to lock the screen. - * - * @platform darwin,win32 - */ - on(event: 'lock-screen', listener: Function): this; - once(event: 'lock-screen', listener: Function): this; - addListener(event: 'lock-screen', listener: Function): this; - removeListener(event: 'lock-screen', listener: Function): this; - /** - * Emitted when the system changes to AC power. - * - * @platform darwin,win32 - */ - on(event: 'on-ac', listener: Function): this; - once(event: 'on-ac', listener: Function): this; - addListener(event: 'on-ac', listener: Function): this; - removeListener(event: 'on-ac', listener: Function): this; - /** - * Emitted when system changes to battery power. - * - * @platform darwin - */ - on(event: 'on-battery', listener: Function): this; - once(event: 'on-battery', listener: Function): this; - addListener(event: 'on-battery', listener: Function): this; - removeListener(event: 'on-battery', listener: Function): this; - /** - * Emitted when system is resuming. - */ - on(event: 'resume', listener: Function): this; - once(event: 'resume', listener: Function): this; - addListener(event: 'resume', listener: Function): this; - removeListener(event: 'resume', listener: Function): this; - /** - * Emitted when the system is about to reboot or shut down. If the event handler - * invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in - * order for the app to exit cleanly. If `e.preventDefault()` is called, the app - * should exit as soon as possible by calling something like `app.quit()`. - * - * @platform linux,darwin - */ - on(event: 'shutdown', listener: Function): this; - once(event: 'shutdown', listener: Function): this; - addListener(event: 'shutdown', listener: Function): this; - removeListener(event: 'shutdown', listener: Function): this; - /** - * Emitted when the system is suspending. - */ - on(event: 'suspend', listener: Function): this; - once(event: 'suspend', listener: Function): this; - addListener(event: 'suspend', listener: Function): this; - removeListener(event: 'suspend', listener: Function): this; - /** - * Emitted as soon as the systems screen is unlocked. - * - * @platform darwin,win32 - */ - on(event: 'unlock-screen', listener: Function): this; - once(event: 'unlock-screen', listener: Function): this; - addListener(event: 'unlock-screen', listener: Function): this; - removeListener(event: 'unlock-screen', listener: Function): this; - /** - * Emitted when a login session is activated. See documentation for more - * information. - * - * @platform darwin - */ - on(event: 'user-did-become-active', listener: Function): this; - once(event: 'user-did-become-active', listener: Function): this; - addListener(event: 'user-did-become-active', listener: Function): this; - removeListener(event: 'user-did-become-active', listener: Function): this; - /** - * Emitted when a login session is deactivated. See documentation for more - * information. - * - * @platform darwin - */ - on(event: 'user-did-resign-active', listener: Function): this; - once(event: 'user-did-resign-active', listener: Function): this; - addListener(event: 'user-did-resign-active', listener: Function): this; - removeListener(event: 'user-did-resign-active', listener: Function): this; - /** - * The system's current state. Can be `active`, `idle`, `locked` or `unknown`. - * - * Calculate the system idle state. `idleThreshold` is the amount of time (in - * seconds) before considered idle. `locked` is available on supported systems - * only. - */ - getSystemIdleState(idleThreshold: number): ('active' | 'idle' | 'locked' | 'unknown'); - /** - * Idle time in seconds - * - * Calculate system idle time in seconds. - */ - getSystemIdleTime(): number; - /** - * Whether the system is on battery power. - * - * To monitor for changes in this property, use the `on-battery` and `on-ac` - * events. - */ - isOnBatteryPower(): boolean; - /** - * A `boolean` property. True if the system is on battery power. - * - * See `powerMonitor.isOnBatteryPower()`. - */ - onBatteryPower: boolean; - } - - interface PowerSaveBlocker { - - // Docs: https://electronjs.org/docs/api/power-save-blocker - - /** - * Whether the corresponding `powerSaveBlocker` has started. - */ - isStarted(id: number): boolean; - /** - * The blocker ID that is assigned to this power blocker. - * - * Starts preventing the system from entering lower-power mode. Returns an integer - * identifying the power save blocker. - * - * **Note:** `prevent-display-sleep` has higher precedence over - * `prevent-app-suspension`. Only the highest precedence type takes effect. In - * other words, `prevent-display-sleep` always takes precedence over - * `prevent-app-suspension`. - * - * For example, an API calling A requests for `prevent-app-suspension`, and another - * calling B requests for `prevent-display-sleep`. `prevent-display-sleep` will be - * used until B stops its request. After that, `prevent-app-suspension` is used. - */ - start(type: 'prevent-app-suspension' | 'prevent-display-sleep'): number; - /** - * Stops the specified power save blocker. - */ - stop(id: number): void; - } - - interface PrinterInfo { - - // Docs: https://electronjs.org/docs/api/structures/printer-info - - /** - * a longer description of the printer's type. - */ - description: string; - /** - * the name of the printer as shown in Print Preview. - */ - displayName: string; - /** - * whether or not a given printer is set as the default printer on the OS. - */ - isDefault: boolean; - /** - * the name of the printer as understood by the OS. - */ - name: string; - /** - * an object containing a variable number of platform-specific printer information. - */ - options: Options; - /** - * the current status of the printer. - */ - status: number; - } - - interface ProcessMemoryInfo { - - // Docs: https://electronjs.org/docs/api/structures/process-memory-info - - /** - * The amount of memory not shared by other processes, such as JS heap or HTML - * content in Kilobytes. - */ - private: number; - /** - * The amount of memory currently pinned to actual physical RAM in Kilobytes. - * - * @platform linux,win32 - */ - residentSet: number; - /** - * The amount of memory shared between processes, typically memory consumed by the - * Electron code itself in Kilobytes. - */ - shared: number; - } - - interface ProcessMetric { - - // Docs: https://electronjs.org/docs/api/structures/process-metric - - /** - * CPU usage of the process. - */ - cpu: CPUUsage; - /** - * Creation time for this process. The time is represented as number of - * milliseconds since epoch. Since the `pid` can be reused after a process dies, it - * is useful to use both the `pid` and the `creationTime` to uniquely identify a - * process. - */ - creationTime: number; - /** - * One of the following values: - * - * @platform win32 - */ - integrityLevel?: ('untrusted' | 'low' | 'medium' | 'high' | 'unknown'); - /** - * Memory information for the process. - */ - memory: MemoryInfo; - /** - * The name of the process. Examples for utility: `Audio Service`, `Content - * Decryption Module Service`, `Network Service`, `Video Capture`, etc. - */ - name?: string; - /** - * Process id of the process. - */ - pid: number; - /** - * Whether the process is sandboxed on OS level. - * - * @platform darwin,win32 - */ - sandboxed?: boolean; - /** - * The non-localized name of the process. - */ - serviceName?: string; - /** - * Process type. One of the following values: - */ - type: ('Browser' | 'Tab' | 'Utility' | 'Zygote' | 'Sandbox helper' | 'GPU' | 'Pepper Plugin' | 'Pepper Plugin Broker' | 'Unknown'); - } - - interface Product { - - // Docs: https://electronjs.org/docs/api/structures/product - - /** - * The total size of the content, in bytes. - */ - contentLengths: number[]; - /** - * A string that identifies the version of the content. - */ - contentVersion: string; - /** - * 3 character code presenting a product's currency based on the ISO 4217 standard. - */ - currencyCode: string; - /** - * An array of discount offers - */ - discounts: ProductDiscount[]; - /** - * The total size of the content, in bytes. - */ - downloadContentLengths: number[]; - /** - * A string that identifies the version of the content. - */ - downloadContentVersion: string; - /** - * The locale formatted price of the product. - */ - formattedPrice: string; - /** - * The object containing introductory price information for the product. available - * for the product. - */ - introductoryPrice?: ProductDiscount; - /** - * A boolean value that indicates whether the App Store has downloadable content - * for this product. `true` if at least one file has been associated with the - * product. - */ - isDownloadable: boolean; - /** - * A description of the product. - */ - localizedDescription: string; - /** - * The name of the product. - */ - localizedTitle: string; - /** - * The cost of the product in the local currency. - */ - price: number; - /** - * The string that identifies the product to the Apple App Store. - */ - productIdentifier: string; - /** - * The identifier of the subscription group to which the subscription belongs. - */ - subscriptionGroupIdentifier: string; - /** - * The period details for products that are subscriptions. - */ - subscriptionPeriod?: ProductSubscriptionPeriod; - } - - interface ProductDiscount { - - // Docs: https://electronjs.org/docs/api/structures/product-discount - - /** - * A string used to uniquely identify a discount offer for a product. - */ - identifier: string; - /** - * An integer that indicates the number of periods the product discount is - * available. - */ - numberOfPeriods: number; - /** - * The payment mode for this product discount. Can be `payAsYouGo`, `payUpFront`, - * or `freeTrial`. - */ - paymentMode: ('payAsYouGo' | 'payUpFront' | 'freeTrial'); - /** - * The discount price of the product in the local currency. - */ - price: number; - /** - * The locale used to format the discount price of the product. - */ - priceLocale: string; - /** - * An object that defines the period for the product discount. - */ - subscriptionPeriod?: ProductSubscriptionPeriod; - /** - * The type of discount offer. - */ - type: number; - } - - interface ProductSubscriptionPeriod { - - // Docs: https://electronjs.org/docs/api/structures/product-subscription-period - - /** - * The number of units per subscription period. - */ - numberOfUnits: number; - /** - * The increment of time that a subscription period is specified in. Can be `day`, - * `week`, `month`, `year`. - */ - unit: ('day' | 'week' | 'month' | 'year'); - } - - interface Protocol { - - // Docs: https://electronjs.org/docs/api/protocol - - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a `Buffer` as a response. - */ - interceptBufferProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (Buffer) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a file as a response. - */ - interceptFileProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a new HTTP request as a response. - */ - interceptHttpProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: ProtocolResponse) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Same as `protocol.registerStreamProtocol`, except that it replaces an existing - * protocol handler. - */ - interceptStreamProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (NodeJS.ReadableStream) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a `string` as a response. - */ - interceptStringProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether `scheme` is already intercepted. - */ - isProtocolIntercepted(scheme: string): boolean; - /** - * Whether `scheme` is already registered. - */ - isProtocolRegistered(scheme: string): boolean; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send a `Buffer` as a response. - * - * The usage is the same with `registerFileProtocol`, except that the `callback` - * should be called with either a `Buffer` object or an object that has the `data` - * property. - * - * Example: - */ - registerBufferProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (Buffer) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send a file as the response. The - * `handler` will be called with `request` and `callback` where `request` is an - * incoming request for the `scheme`. - * - * To handle the `request`, the `callback` should be called with either the file's - * path or an object that has a `path` property, e.g. `callback(filePath)` or - * `callback({ path: filePath })`. The `filePath` must be an absolute path. - * - * By default the `scheme` is treated like `http:`, which is parsed differently - * from protocols that follow the "generic URI syntax" like `file:`. - */ - registerFileProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send an HTTP request as a response. - * - * The usage is the same with `registerFileProtocol`, except that the `callback` - * should be called with an object that has the `url` property. - */ - registerHttpProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: ProtocolResponse) => void) => void): boolean; - /** - * **Note:** This method can only be used before the `ready` event of the `app` - * module gets emitted and can be called only once. - * - * Registers the `scheme` as standard, secure, bypasses content security policy for - * resources, allows registering ServiceWorker, supports fetch API, and streaming - * video/audio. Specify a privilege with the value of `true` to enable the - * capability. - * - * An example of registering a privileged scheme, that bypasses Content Security - * Policy: - * - * A standard scheme adheres to what RFC 3986 calls generic URI syntax. For example - * `http` and `https` are standard schemes, while `file` is not. - * - * Registering a scheme as standard allows relative and absolute resources to be - * resolved correctly when served. Otherwise the scheme will behave like the `file` - * protocol, but without the ability to resolve relative URLs. - * - * For example when you load following page with custom protocol without - * registering it as standard scheme, the image will not be loaded because - * non-standard schemes can not recognize relative URLs: - * - * Registering a scheme as standard will allow access to files through the - * FileSystem API. Otherwise the renderer will throw a security error for the - * scheme. - * - * By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, - * cookies) are disabled for non standard schemes. So in general if you want to - * register a custom protocol to replace the `http` protocol, you have to register - * it as a standard scheme. - * - * Protocols that use streams (http and stream protocols) should set `stream: - * true`. The `<video>` and `<audio>` HTML elements expect protocols to buffer - * their responses by default. The `stream` flag configures those elements to - * correctly expect streaming responses. - */ - registerSchemesAsPrivileged(customSchemes: CustomScheme[]): void; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send a stream as a response. - * - * The usage is the same with `registerFileProtocol`, except that the `callback` - * should be called with either a `ReadableStream` object or an object that has the - * `data` property. - * - * Example: - * - * It is possible to pass any object that implements the readable stream API (emits - * `data`/`end`/`error` events). For example, here's how a file could be returned: - */ - registerStreamProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (NodeJS.ReadableStream) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send a `string` as a response. - * - * The usage is the same with `registerFileProtocol`, except that the `callback` - * should be called with either a `string` or an object that has the `data` - * property. - */ - registerStringProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully unintercepted - * - * Remove the interceptor installed for `scheme` and restore its original handler. - */ - uninterceptProtocol(scheme: string): boolean; - /** - * Whether the protocol was successfully unregistered - * - * Unregisters the custom protocol of `scheme`. - */ - unregisterProtocol(scheme: string): boolean; - } - - interface ProtocolRequest { - - // Docs: https://electronjs.org/docs/api/structures/protocol-request - - headers: Record<string, string>; - method: string; - referrer: string; - uploadData?: UploadData[]; - url: string; - } - - interface ProtocolResponse { - - // Docs: https://electronjs.org/docs/api/structures/protocol-response - - /** - * The charset of response body, default is `"utf-8"`. - */ - charset?: string; - /** - * The response body. When returning stream as response, this is a Node.js readable - * stream representing the response body. When returning `Buffer` as response, this - * is a `Buffer`. When returning `string` as response, this is a `string`. This is - * ignored for other types of responses. - */ - data?: (Buffer) | (string) | (NodeJS.ReadableStream); - /** - * When assigned, the `request` will fail with the `error` number . For the - * available error numbers you can use, please see the net error list. - */ - error?: number; - /** - * An object containing the response headers. The keys must be string, and values - * must be either string or Array of string. - */ - headers?: Record<string, (string) | (string[])>; - /** - * The HTTP `method`. This is only used for file and URL responses. - */ - method?: string; - /** - * The MIME type of response body, default is `"text/html"`. Setting `mimeType` - * would implicitly set the `content-type` header in response, but if - * `content-type` is already set in `headers`, the `mimeType` would be ignored. - */ - mimeType?: string; - /** - * Path to the file which would be sent as response body. This is only used for - * file responses. - */ - path?: string; - /** - * The `referrer` URL. This is only used for file and URL responses. - */ - referrer?: string; - /** - * The session used for requesting URL, by default the HTTP request will reuse the - * current session. Setting `session` to `null` would use a random independent - * session. This is only used for URL responses. - */ - session?: Session; - /** - * The HTTP response code, default is 200. - */ - statusCode?: number; - /** - * The data used as upload data. This is only used for URL responses when `method` - * is `"POST"`. - */ - uploadData?: ProtocolResponseUploadData; - /** - * Download the `url` and pipe the result as response body. This is only used for - * URL responses. - */ - url?: string; - } - - interface ProtocolResponseUploadData { - - // Docs: https://electronjs.org/docs/api/structures/protocol-response-upload-data - - /** - * MIME type of the content. - */ - contentType: string; - /** - * Content to be sent. - */ - data: (string) | (Buffer); - } - - interface Rectangle { - - // Docs: https://electronjs.org/docs/api/structures/rectangle - - /** - * The height of the rectangle (must be an integer). - */ - height: number; - /** - * The width of the rectangle (must be an integer). - */ - width: number; - /** - * The x coordinate of the origin of the rectangle (must be an integer). - */ - x: number; - /** - * The y coordinate of the origin of the rectangle (must be an integer). - */ - y: number; - } - - interface Referrer { - - // Docs: https://electronjs.org/docs/api/structures/referrer - - /** - * Can be `default`, `unsafe-url`, `no-referrer-when-downgrade`, `no-referrer`, - * `origin`, `strict-origin-when-cross-origin`, `same-origin` or `strict-origin`. - * See the Referrer-Policy spec for more details on the meaning of these values. - */ - policy: ('default' | 'unsafe-url' | 'no-referrer-when-downgrade' | 'no-referrer' | 'origin' | 'strict-origin-when-cross-origin' | 'same-origin' | 'strict-origin'); - /** - * HTTP Referrer URL. - */ - url: string; - } - - interface SafeStorage extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/safe-storage - - /** - * the decrypted string. Decrypts the encrypted buffer obtained with - * `safeStorage.encryptString` back into a string. - * - * This function will throw an error if decryption fails. - */ - decryptString(encrypted: Buffer): string; - /** - * An array of bytes representing the encrypted string. - * - * This function will throw an error if encryption fails. - */ - encryptString(plainText: string): Buffer; - /** - * Whether encryption is available. - * - * On Linux, returns true if the secret key is available. On MacOS, returns true if - * Keychain is available. On Windows, returns true once the app has emitted the - * `ready` event. - */ - isEncryptionAvailable(): boolean; - } - - interface Screen extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/screen - - /** - * Emitted when `newDisplay` has been added. - */ - on(event: 'display-added', listener: (event: Event, - newDisplay: Display) => void): this; - once(event: 'display-added', listener: (event: Event, - newDisplay: Display) => void): this; - addListener(event: 'display-added', listener: (event: Event, - newDisplay: Display) => void): this; - removeListener(event: 'display-added', listener: (event: Event, - newDisplay: Display) => void): this; - /** - * Emitted when one or more metrics change in a `display`. The `changedMetrics` is - * an array of strings that describe the changes. Possible changes are `bounds`, - * `workArea`, `scaleFactor` and `rotation`. - */ - on(event: 'display-metrics-changed', listener: (event: Event, - display: Display, - changedMetrics: string[]) => void): this; - once(event: 'display-metrics-changed', listener: (event: Event, - display: Display, - changedMetrics: string[]) => void): this; - addListener(event: 'display-metrics-changed', listener: (event: Event, - display: Display, - changedMetrics: string[]) => void): this; - removeListener(event: 'display-metrics-changed', listener: (event: Event, - display: Display, - changedMetrics: string[]) => void): this; - /** - * Emitted when `oldDisplay` has been removed. - */ - on(event: 'display-removed', listener: (event: Event, - oldDisplay: Display) => void): this; - once(event: 'display-removed', listener: (event: Event, - oldDisplay: Display) => void): this; - addListener(event: 'display-removed', listener: (event: Event, - oldDisplay: Display) => void): this; - removeListener(event: 'display-removed', listener: (event: Event, - oldDisplay: Display) => void): this; - /** - * Converts a screen DIP point to a screen physical point. The DPI scale is - * performed relative to the display containing the DIP point. - * - * @platform win32 - */ - dipToScreenPoint(point: Point): Point; - /** - * Converts a screen DIP rect to a screen physical rect. The DPI scale is performed - * relative to the display nearest to `window`. If `window` is null, scaling will - * be performed to the display nearest to `rect`. - * - * @platform win32 - */ - dipToScreenRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; - /** - * An array of displays that are currently available. - */ - getAllDisplays(): Display[]; - /** - * The current absolute position of the mouse pointer. - * - * **Note:** The return value is a DIP point, not a screen physical point. - */ - getCursorScreenPoint(): Point; - /** - * The display that most closely intersects the provided bounds. - */ - getDisplayMatching(rect: Rectangle): Display; - /** - * The display nearest the specified point. - */ - getDisplayNearestPoint(point: Point): Display; - /** - * The primary display. - */ - getPrimaryDisplay(): Display; - /** - * Converts a screen physical point to a screen DIP point. The DPI scale is - * performed relative to the display containing the physical point. - * - * @platform win32 - */ - screenToDipPoint(point: Point): Point; - /** - * Converts a screen physical rect to a screen DIP rect. The DPI scale is performed - * relative to the display nearest to `window`. If `window` is null, scaling will - * be performed to the display nearest to `rect`. - * - * @platform win32 - */ - screenToDipRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; - } - - interface ScrubberItem { - - // Docs: https://electronjs.org/docs/api/structures/scrubber-item - - /** - * The image to appear in this item. - */ - icon?: NativeImage; - /** - * The text to appear in this item. - */ - label?: string; - } - - interface SegmentedControlSegment { - - // Docs: https://electronjs.org/docs/api/structures/segmented-control-segment - - /** - * Whether this segment is selectable. Default: true. - */ - enabled?: boolean; - /** - * The image to appear in this segment. - */ - icon?: NativeImage; - /** - * The text to appear in this segment. - */ - label?: string; - } - - interface SerialPort { - - // Docs: https://electronjs.org/docs/api/structures/serial-port - - /** - * A stable identifier on Windows that can be used for device permissions. - */ - deviceInstanceId?: string; - /** - * A string suitable for display to the user for describing this device. - */ - displayName: string; - /** - * Unique identifier for the port. - */ - portId: string; - /** - * Name of the port. - */ - portName: string; - /** - * Optional USB product ID. - */ - productId: string; - /** - * The USB device serial number. - */ - serialNumber: string; - /** - * Represents a single serial port on macOS can be enumerated by multiple drivers. - */ - usbDriverName?: string; - /** - * Optional USB vendor ID. - */ - vendorId: string; - } - - interface ServiceWorkerInfo { - - // Docs: https://electronjs.org/docs/api/structures/service-worker-info - - /** - * The virtual ID of the process that this service worker is running in. This is - * not an OS level PID. This aligns with the ID set used for - * `webContents.getProcessId()`. - */ - renderProcessId: number; - /** - * The base URL that this service worker is active for. - */ - scope: string; - /** - * The full URL to the script that this service worker runs - */ - scriptUrl: string; - } - - class ServiceWorkers extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/service-workers - - /** - * Emitted when a service worker logs something to the console. - */ - on(event: 'console-message', listener: (event: Event, - /** - * Information about the console message - */ - messageDetails: MessageDetails) => void): this; - once(event: 'console-message', listener: (event: Event, - /** - * Information about the console message - */ - messageDetails: MessageDetails) => void): this; - addListener(event: 'console-message', listener: (event: Event, - /** - * Information about the console message - */ - messageDetails: MessageDetails) => void): this; - removeListener(event: 'console-message', listener: (event: Event, - /** - * Information about the console message - */ - messageDetails: MessageDetails) => void): this; - /** - * Emitted when a service worker has been registered. Can occur after a call to - * `navigator.serviceWorker.register('/sw.js')` successfully resolves or when a - * Chrome extension is loaded. - */ - on(event: 'registration-completed', listener: (event: Event, - /** - * Information about the registered service worker - */ - details: RegistrationCompletedDetails) => void): this; - once(event: 'registration-completed', listener: (event: Event, - /** - * Information about the registered service worker - */ - details: RegistrationCompletedDetails) => void): this; - addListener(event: 'registration-completed', listener: (event: Event, - /** - * Information about the registered service worker - */ - details: RegistrationCompletedDetails) => void): this; - removeListener(event: 'registration-completed', listener: (event: Event, - /** - * Information about the registered service worker - */ - details: RegistrationCompletedDetails) => void): this; - /** - * A ServiceWorkerInfo object where the keys are the service worker version ID and - * the values are the information about that service worker. - */ - getAllRunning(): Record<number, ServiceWorkerInfo>; - /** - * Information about this service worker - * - * If the service worker does not exist or is not running this method will throw an - * exception. - */ - getFromVersionID(versionId: number): ServiceWorkerInfo; - } - - class Session extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/session - - /** - * A session instance from `partition` string. When there is an existing `Session` - * with the same `partition`, it will be returned; otherwise a new `Session` - * instance will be created with `options`. - * - * If `partition` starts with `persist:`, the page will use a persistent session - * available to all pages in the app with the same `partition`. if there is no - * `persist:` prefix, the page will use an in-memory session. If the `partition` is - * empty then default session of the app will be returned. - * - * To create a `Session` with `options`, you have to ensure the `Session` with the - * `partition` has never been used before. There is no way to change the `options` - * of an existing `Session` object. - */ - static fromPartition(partition: string, options?: FromPartitionOptions): Session; - /** - * A `Session` object, the default session object of the app. - */ - static defaultSession: Session; - /** - * Emitted after an extension is loaded. This occurs whenever an extension is added - * to the "enabled" set of extensions. This includes: - * - * * Extensions being loaded from `Session.loadExtension`. - * * Extensions being reloaded: - * * from a crash. - * * if the extension requested it (`chrome.runtime.reload()`). - */ - on(event: 'extension-loaded', listener: (event: Event, - extension: Extension) => void): this; - once(event: 'extension-loaded', listener: (event: Event, - extension: Extension) => void): this; - addListener(event: 'extension-loaded', listener: (event: Event, - extension: Extension) => void): this; - removeListener(event: 'extension-loaded', listener: (event: Event, - extension: Extension) => void): this; - /** - * Emitted after an extension is loaded and all necessary browser state is - * initialized to support the start of the extension's background page. - */ - on(event: 'extension-ready', listener: (event: Event, - extension: Extension) => void): this; - once(event: 'extension-ready', listener: (event: Event, - extension: Extension) => void): this; - addListener(event: 'extension-ready', listener: (event: Event, - extension: Extension) => void): this; - removeListener(event: 'extension-ready', listener: (event: Event, - extension: Extension) => void): this; - /** - * Emitted after an extension is unloaded. This occurs when - * `Session.removeExtension` is called. - */ - on(event: 'extension-unloaded', listener: (event: Event, - extension: Extension) => void): this; - once(event: 'extension-unloaded', listener: (event: Event, - extension: Extension) => void): this; - addListener(event: 'extension-unloaded', listener: (event: Event, - extension: Extension) => void): this; - removeListener(event: 'extension-unloaded', listener: (event: Event, - extension: Extension) => void): this; - /** - * Emitted when a new HID device becomes available. For example, when a new USB - * device is plugged in. - * - * This event will only be emitted after `navigator.hid.requestDevice` has been - * called and `select-hid-device` has fired. - */ - on(event: 'hid-device-added', listener: (event: Event, - details: HidDeviceAddedDetails) => void): this; - once(event: 'hid-device-added', listener: (event: Event, - details: HidDeviceAddedDetails) => void): this; - addListener(event: 'hid-device-added', listener: (event: Event, - details: HidDeviceAddedDetails) => void): this; - removeListener(event: 'hid-device-added', listener: (event: Event, - details: HidDeviceAddedDetails) => void): this; - /** - * Emitted when a HID device has been removed. For example, this event will fire - * when a USB device is unplugged. - * - * This event will only be emitted after `navigator.hid.requestDevice` has been - * called and `select-hid-device` has fired. - */ - on(event: 'hid-device-removed', listener: (event: Event, - details: HidDeviceRemovedDetails) => void): this; - once(event: 'hid-device-removed', listener: (event: Event, - details: HidDeviceRemovedDetails) => void): this; - addListener(event: 'hid-device-removed', listener: (event: Event, - details: HidDeviceRemovedDetails) => void): this; - removeListener(event: 'hid-device-removed', listener: (event: Event, - details: HidDeviceRemovedDetails) => void): this; - /** - * Emitted when a render process requests preconnection to a URL, generally due to - * a resource hint. - */ - on(event: 'preconnect', listener: (event: Event, - /** - * The URL being requested for preconnection by the renderer. - */ - preconnectUrl: string, - /** - * True if the renderer is requesting that the connection include credentials (see - * the spec for more details.) - */ - allowCredentials: boolean) => void): this; - once(event: 'preconnect', listener: (event: Event, - /** - * The URL being requested for preconnection by the renderer. - */ - preconnectUrl: string, - /** - * True if the renderer is requesting that the connection include credentials (see - * the spec for more details.) - */ - allowCredentials: boolean) => void): this; - addListener(event: 'preconnect', listener: (event: Event, + error: string) => void): this; + removeListener(event: 'continue-activity-error', listener: (event: Event, /** - * The URL being requested for preconnection by the renderer. + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - preconnectUrl: string, + type: string, /** - * True if the renderer is requesting that the connection include credentials (see - * the spec for more details.) + * A string with the error's localized description. */ - allowCredentials: boolean) => void): this; - removeListener(event: 'preconnect', listener: (event: Event, - /** - * The URL being requested for preconnection by the renderer. - */ - preconnectUrl: string, - /** - * True if the renderer is requesting that the connection include credentials (see - * the spec for more details.) - */ - allowCredentials: boolean) => void): this; - /** - * Emitted when a HID device needs to be selected when a call to - * `navigator.hid.requestDevice` is made. `callback` should be called with - * `deviceId` to be selected; passing no arguments to `callback` will cancel the - * request. Additionally, permissioning on `navigator.hid` can be further managed - * by using ses.setPermissionCheckHandler(handler) and - * ses.setDevicePermissionHandler(handler)`. - */ - on(event: 'select-hid-device', listener: (event: Event, - details: SelectHidDeviceDetails, - callback: (deviceId?: (string) | (null)) => void) => void): this; - once(event: 'select-hid-device', listener: (event: Event, - details: SelectHidDeviceDetails, - callback: (deviceId?: (string) | (null)) => void) => void): this; - addListener(event: 'select-hid-device', listener: (event: Event, - details: SelectHidDeviceDetails, - callback: (deviceId?: (string) | (null)) => void) => void): this; - removeListener(event: 'select-hid-device', listener: (event: Event, - details: SelectHidDeviceDetails, - callback: (deviceId?: (string) | (null)) => void) => void): this; - /** - * Emitted when a serial port needs to be selected when a call to - * `navigator.serial.requestPort` is made. `callback` should be called with - * `portId` to be selected, passing an empty string to `callback` will cancel the - * request. Additionally, permissioning on `navigator.serial` can be managed by - * using ses.setPermissionCheckHandler(handler) with the `serial` permission. - */ - on(event: 'select-serial-port', listener: (event: Event, - portList: SerialPort[], - webContents: WebContents, - callback: (portId: string) => void) => void): this; - once(event: 'select-serial-port', listener: (event: Event, - portList: SerialPort[], + error: string) => void): this; + /** + * Emitted when mac application become active. Difference from `activate` event is + * that `did-become-active` is emitted every time the app becomes active, not only + * when Dock icon is clicked or application is re-launched. + * + * @platform darwin + */ + on(event: 'did-become-active', listener: (event: Event) => void): this; + once(event: 'did-become-active', listener: (event: Event) => void): this; + addListener(event: 'did-become-active', listener: (event: Event) => void): this; + removeListener(event: 'did-become-active', listener: (event: Event) => void): this; + /** + * Emitted whenever there is a GPU info update. + */ + on(event: 'gpu-info-update', listener: Function): this; + once(event: 'gpu-info-update', listener: Function): this; + addListener(event: 'gpu-info-update', listener: Function): this; + removeListener(event: 'gpu-info-update', listener: Function): this; + /** + * Emitted when the GPU process crashes or is killed. + * + * **Deprecated:** This event is superceded by the `child-process-gone` event which + * contains more information about why the child process disappeared. It isn't + * always because it crashed. The `killed` boolean can be replaced by checking + * `reason === 'killed'` when you switch to that event. + * + * @deprecated + */ + on(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + once(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + addListener(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + removeListener(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + /** + * Emitted when `webContents` wants to do basic auth. + * + * The default behavior is to cancel all authentications. To override this you + * should prevent the default behavior with `event.preventDefault()` and call + * `callback(username, password)` with the credentials. + * + * If `callback` is called without a username or password, the authentication + * request will be cancelled and the authentication error will be returned to the + * page. + */ + on(event: 'login', listener: (event: Event, + webContents: WebContents, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + once(event: 'login', listener: (event: Event, + webContents: WebContents, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + addListener(event: 'login', listener: (event: Event, + webContents: WebContents, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + removeListener(event: 'login', listener: (event: Event, + webContents: WebContents, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + /** + * Emitted when the user clicks the native macOS new tab button. The new tab button + * is only visible if the current `BrowserWindow` has a `tabbingIdentifier` + * + * @platform darwin + */ + on(event: 'new-window-for-tab', listener: (event: Event) => void): this; + once(event: 'new-window-for-tab', listener: (event: Event) => void): this; + addListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; + removeListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; + /** + * Emitted when the user wants to open a file with the application. The `open-file` + * event is usually emitted when the application is already open and the OS wants + * to reuse the application to open the file. `open-file` is also emitted when a + * file is dropped onto the dock and the application is not yet running. Make sure + * to listen for the `open-file` event very early in your application startup to + * handle this case (even before the `ready` event is emitted). + * + * You should call `event.preventDefault()` if you want to handle this event. + * + * On Windows, you have to parse `process.argv` (in the main process) to get the + * filepath. + * + * @platform darwin + */ + on(event: 'open-file', listener: (event: Event, + path: string) => void): this; + once(event: 'open-file', listener: (event: Event, + path: string) => void): this; + addListener(event: 'open-file', listener: (event: Event, + path: string) => void): this; + removeListener(event: 'open-file', listener: (event: Event, + path: string) => void): this; + /** + * Emitted when the user wants to open a URL with the application. Your + * application's `Info.plist` file must define the URL scheme within the + * `CFBundleURLTypes` key, and 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. + * + * @platform darwin + */ + on(event: 'open-url', listener: (event: Event, + url: string) => void): this; + once(event: 'open-url', listener: (event: Event, + url: string) => void): this; + addListener(event: 'open-url', listener: (event: Event, + url: string) => void): this; + removeListener(event: 'open-url', listener: (event: Event, + url: string) => void): this; + /** + * Emitted when the application is quitting. + * + * **Note:** On Windows, this event will not be emitted if the app is closed due to + * a shutdown/restart of the system or a user logout. + */ + on(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + once(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + addListener(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + removeListener(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + /** + * Emitted once, when Electron has finished initializing. On macOS, `launchInfo` + * holds the `userInfo` of the `NSUserNotification` or information from + * `UNNotificationResponse` that was used to open the application, if it was + * launched from Notification Center. You can also call `app.isReady()` to check if + * this event has already fired and `app.whenReady()` to get a Promise that is + * fulfilled when Electron is initialized. + */ + on(event: 'ready', listener: (event: Event, + launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; + once(event: 'ready', listener: (event: Event, + launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; + addListener(event: 'ready', listener: (event: Event, + launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; + removeListener(event: 'ready', listener: (event: Event, + launchInfo: (Record<string, any>) | (NotificationResponse)) => void): this; + /** + * Emitted when the renderer process unexpectedly disappears. This is normally + * because it was crashed or killed. + */ + on(event: 'render-process-gone', listener: (event: Event, + webContents: WebContents, + details: RenderProcessGoneDetails) => void): this; + once(event: 'render-process-gone', listener: (event: Event, + webContents: WebContents, + details: RenderProcessGoneDetails) => void): this; + addListener(event: 'render-process-gone', listener: (event: Event, + webContents: WebContents, + details: RenderProcessGoneDetails) => void): this; + removeListener(event: 'render-process-gone', listener: (event: Event, + webContents: WebContents, + details: RenderProcessGoneDetails) => void): this; + /** + * Emitted when the renderer process of `webContents` crashes or is killed. + * + * **Deprecated:** This event is superceded by the `render-process-gone` event + * which contains more information about why the render process disappeared. It + * isn't always because it crashed. The `killed` boolean can be replaced by + * checking `reason === 'killed'` when you switch to that event. + * + * @deprecated + */ + on(event: 'renderer-process-crashed', listener: (event: Event, webContents: WebContents, - callback: (portId: string) => void) => void): this; - addListener(event: 'select-serial-port', listener: (event: Event, - portList: SerialPort[], - webContents: WebContents, - callback: (portId: string) => void) => void): this; - removeListener(event: 'select-serial-port', listener: (event: Event, - portList: SerialPort[], - webContents: WebContents, - callback: (portId: string) => void) => void): this; - /** - * Emitted after `navigator.serial.requestPort` has been called and - * `select-serial-port` has fired if a new serial port becomes available. For - * example, this event will fire when a new USB device is plugged in. - */ - on(event: 'serial-port-added', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - once(event: 'serial-port-added', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - addListener(event: 'serial-port-added', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - removeListener(event: 'serial-port-added', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - /** - * Emitted after `navigator.serial.requestPort` has been called and - * `select-serial-port` has fired if a serial port has been removed. For example, - * this event will fire when a USB device is unplugged. - */ - on(event: 'serial-port-removed', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - once(event: 'serial-port-removed', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - addListener(event: 'serial-port-removed', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - removeListener(event: 'serial-port-removed', listener: (event: Event, - port: SerialPort, - webContents: WebContents) => void): this; - /** - * Emitted when a hunspell dictionary file starts downloading - */ - on(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - once(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - addListener(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - removeListener(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - /** - * Emitted when a hunspell dictionary file download fails. For details on the - * failure you should collect a netlog and inspect the download request. - */ - on(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - once(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - addListener(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - removeListener(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - /** - * Emitted when a hunspell dictionary file has been successfully downloaded - */ - on(event: 'spellcheck-dictionary-download-success', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - once(event: 'spellcheck-dictionary-download-success', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - addListener(event: 'spellcheck-dictionary-download-success', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - removeListener(event: 'spellcheck-dictionary-download-success', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - /** - * Emitted when a hunspell dictionary file has been successfully initialized. This - * occurs after the file has been downloaded. - */ - on(event: 'spellcheck-dictionary-initialized', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - once(event: 'spellcheck-dictionary-initialized', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - addListener(event: 'spellcheck-dictionary-initialized', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - removeListener(event: 'spellcheck-dictionary-initialized', listener: (event: Event, - /** - * The language code of the dictionary file - */ - languageCode: string) => void): this; - /** - * Emitted when Electron is about to download `item` in `webContents`. - * - * Calling `event.preventDefault()` will cancel the download and `item` will not be - * available from next tick of the process. - */ - on(event: 'will-download', listener: (event: Event, - item: DownloadItem, - webContents: WebContents) => void): this; - once(event: 'will-download', listener: (event: Event, - item: DownloadItem, - webContents: WebContents) => void): this; - addListener(event: 'will-download', listener: (event: Event, - item: DownloadItem, - webContents: WebContents) => void): this; - removeListener(event: 'will-download', listener: (event: Event, - item: DownloadItem, - webContents: WebContents) => void): this; - /** - * Whether the word was successfully written to the custom dictionary. This API - * will not work on non-persistent (in-memory) sessions. - * - * **Note:** On macOS and Windows 10 this word will be written to the OS custom - * dictionary as well - */ - addWordToSpellCheckerDictionary(word: string): boolean; - /** - * Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate - * authentication. - */ - allowNTLMCredentialsForDomains(domains: string): void; - /** - * resolves when the session’s HTTP authentication cache has been cleared. - */ - clearAuthCache(): Promise<void>; - /** - * resolves when the cache clear operation is complete. - * - * Clears the session’s HTTP cache. - */ - clearCache(): Promise<void>; - /** - * resolves when the code cache clear operation is complete. - */ - clearCodeCaches(options: ClearCodeCachesOptions): Promise<void>; - /** - * Resolves when the operation is complete. - * - * Clears the host resolver cache. - */ - clearHostResolverCache(): Promise<void>; - /** - * resolves when the storage data has been cleared. - */ - clearStorageData(options?: ClearStorageDataOptions): Promise<void>; - /** - * Resolves when all connections are closed. - * - * **Note:** It will terminate / fail all requests currently in flight. - */ - closeAllConnections(): Promise<void>; - /** - * Allows resuming `cancelled` or `interrupted` downloads from previous `Session`. - * The API will generate a DownloadItem that can be accessed with the will-download - * event. The DownloadItem will not have any `WebContents` associated with it and - * the initial state will be `interrupted`. The download will start only when the - * `resume` API is called on the DownloadItem. - */ - createInterruptedDownload(options: CreateInterruptedDownloadOptions): void; - /** - * Disables any network emulation already active for the `session`. Resets to the - * original network configuration. - */ - disableNetworkEmulation(): void; - /** - * Initiates a download of the resource at `url`. The API will generate a - * DownloadItem that can be accessed with the will-download event. - * - * **Note:** This does not perform any security checks that relate to a page's - * origin, unlike `webContents.downloadURL`. - */ - downloadURL(url: string): void; - /** - * Emulates network with the given configuration for the `session`. - */ - enableNetworkEmulation(options: EnableNetworkEmulationOptions): void; - /** - * Writes any unwritten DOMStorage data to disk. - */ - flushStorageData(): void; - /** - * Resolves when the all internal states of proxy service is reset and the latest - * proxy configuration is reapplied if it's already available. The pac script will - * be fetched from `pacScript` again if the proxy mode is `pac_script`. - */ - forceReloadProxyConfig(): Promise<void>; - /** - * A list of all loaded extensions. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - */ - getAllExtensions(): Extension[]; - /** - * resolves with blob data. - */ - getBlobData(identifier: string): Promise<Buffer>; - /** - * the session's current cache size, in bytes. - */ - getCacheSize(): Promise<number>; - /** - * | `null` - The loaded extension with the given ID. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - */ - getExtension(extensionId: string): Extension; - /** - * an array of paths to preload scripts that have been registered. - */ - getPreloads(): string[]; - /** - * An array of language codes the spellchecker is enabled for. If this list is - * empty the spellchecker will fallback to using `en-US`. By default on launch if - * this setting is an empty list Electron will try to populate this setting with - * the current OS locale. This setting is persisted across restarts. - * - * **Note:** On macOS the OS spellchecker is used and has its own list of - * languages. This API is a no-op on macOS. - */ - getSpellCheckerLanguages(): string[]; - /** - * 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`. - */ - getStoragePath(): void; - /** - * The user agent for this session. - */ - getUserAgent(): string; - /** - * Whether or not this session is a persistent one. The default `webContents` - * session of a `BrowserWindow` is persistent. When creating a session from a - * partition, session prefixed with `persist:` will be persistent, while others - * will be temporary. - */ - isPersistent(): boolean; - /** - * Whether the builtin spell checker is enabled. - */ - isSpellCheckerEnabled(): boolean; - /** - * An array of all words in app's custom dictionary. Resolves when the full - * dictionary is loaded from disk. - */ - listWordsInSpellCheckerDictionary(): Promise<string[]>; - /** - * resolves when the extension is loaded. - * - * This method will raise an exception if the extension could not be loaded. If - * there are warnings when installing the extension (e.g. if the extension requests - * an API that Electron does not support) then they will be logged to the console. - * - * Note that Electron does not support the full range of Chrome extensions APIs. - * See Supported Extensions APIs for more details on what is supported. - * - * Note that in previous versions of Electron, extensions that were loaded would be - * remembered for future runs of the application. This is no longer the case: - * `loadExtension` must be called on every boot of your app if you want the - * extension to be loaded. - * - * This API does not support loading packed (.crx) extensions. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - * - * **Note:** Loading extensions into in-memory (non-persistent) sessions is not - * supported and will throw an error. - */ - loadExtension(path: string, options?: LoadExtensionOptions): Promise<Electron.Extension>; - /** - * Preconnects the given number of sockets to an origin. - */ - preconnect(options: PreconnectOptions): void; - /** - * Unloads an extension. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - */ - removeExtension(extensionId: string): void; - /** - * Whether the word was successfully removed from the custom dictionary. This API - * will not work on non-persistent (in-memory) sessions. - * - * **Note:** On macOS and Windows 10 this word will be removed from the OS custom - * dictionary as well - */ - removeWordFromSpellCheckerDictionary(word: string): boolean; - /** - * Resolves with the proxy information for `url`. - */ - resolveProxy(url: string): Promise<string>; - /** - * Sets the certificate verify proc for `session`, the `proc` will be called with - * `proc(request, callback)` whenever a server certificate verification is - * requested. Calling `callback(0)` accepts the certificate, calling `callback(-2)` - * rejects it. - * - * Calling `setCertificateVerifyProc(null)` will revert back to default certificate - * verify proc. - * - * > **NOTE:** The result of this procedure is cached by the network service. - */ - setCertificateVerifyProc(proc: ((request: Request, callback: (verificationResult: number) => void) => void) | (null)): void; - /** - * Sets the directory to store the generated JS code cache for this session. The - * directory is not required to be created by the user before this call, the - * runtime will create if it does not exist otherwise will use the existing - * directory. If directory cannot be created, then code cache will not be used and - * all operations related to code cache will fail silently inside the runtime. By - * default, the directory will be `Code Cache` under the respective user data - * folder. - */ - setCodeCachePath(path: string): void; - /** - * 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. 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 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`. - */ - setDevicePermissionHandler(handler: ((details: DevicePermissionHandlerHandlerDetails) => boolean) | (null)): void; - /** - * Sets download saving directory. By default, the download directory will be the - * `Downloads` under the respective app folder. - */ - setDownloadPath(path: string): void; - /** - * Sets the handler which can be used to respond to permission checks for the - * `session`. Returning `true` will allow the permission and `false` will reject - * it. Please note that you must also implement `setPermissionRequestHandler` to - * get complete permission handling. Most web APIs do a permission check and then - * make a permission request if the check is denied. To clear the handler, call - * `setPermissionCheckHandler(null)`. - */ - setPermissionCheckHandler(handler: ((webContents: (WebContents) | (null), permission: string, requestingOrigin: string, details: PermissionCheckHandlerHandlerDetails) => boolean) | (null)): void; - /** - * Sets the handler which can be used to respond to permission requests for the - * `session`. Calling `callback(true)` will allow the permission and - * `callback(false)` will reject it. To clear the handler, call - * `setPermissionRequestHandler(null)`. Please note that you must also implement - * `setPermissionCheckHandler` to get complete permission handling. Most web APIs - * do a permission check and then make a permission request if the check is denied. - */ - setPermissionRequestHandler(handler: ((webContents: WebContents, permission: 'clipboard-read' | 'media' | 'display-capture' | 'mediaKeySystem' | 'geolocation' | 'notifications' | 'midi' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' | 'unknown', callback: (permissionGranted: boolean) => void, details: PermissionRequestHandlerHandlerDetails) => void) | (null)): void; - /** - * Adds scripts that will be executed on ALL web contents that are associated with - * this session just before normal `preload` scripts run. - */ - setPreloads(preloads: string[]): void; - /** - * Resolves when the proxy setting process is complete. - * - * Sets the proxy settings. - * - * When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, - * the `proxyRules` option is ignored and `pacScript` configuration is applied. - * - * You may need `ses.closeAllConnections` to close currently in flight connections - * to prevent pooled sockets using previous proxy from being reused by future - * requests. - * - * The `proxyRules` has to follow the rules below: - * - * For example: - * - * * `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and - * HTTP proxy `foopy2:80` for `ftp://` URLs. - * * `foopy:80` - Use HTTP proxy `foopy:80` for all URLs. - * * `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing - * over to `bar` if `foopy:80` is unavailable, and after that using no proxy. - * * `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs. - * * `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail - * over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable. - * * `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no - * proxy if `foopy` is unavailable. - * * `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use - * `socks4://foopy2` for all other URLs. - * - * The `proxyBypassRules` is a comma separated list of rules described below: - * - * * `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]` - * - * Match all hostnames that match the pattern HOSTNAME_PATTERN. - * - * Examples: "foobar.com", "*foobar.com", "*.foobar.com", "*foobar.com:99", - * "https://x.*.y.com:99" - * * `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]` - * - * Match a particular domain suffix. - * - * Examples: ".google.com", ".com", "http://.google.com" - * * `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]` - * - * Match URLs which are IP address literals. - * - * Examples: "127.0.1", "[0:0::1]", "[::1]", "http://[::1]:99" - * * `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS` - * - * Match any URL that is to an IP literal that falls between the given range. IP - * range is specified using CIDR notation. - * - * Examples: "192.168.1.1/16", "fefe:13::abc/33". - * * `<local>` - * - * Match local addresses. The meaning of `<local>` is whether the host matches one - * of: "127.0.0.1", "::1", "localhost". - */ - setProxy(config: Config): Promise<void>; - /** - * By default Electron will download hunspell dictionaries from the Chromium CDN. - * If you want to override this behavior you can use this API to point the - * dictionary downloader at your own hosted version of the hunspell dictionaries. - * We publish a `hunspell_dictionaries.zip` file with each release which contains - * the files you need to host here. - * - * The file server must be **case insensitive**. If you cannot do this, you must - * upload each file twice: once with the case it has in the ZIP file and once with - * the filename as all lowercase. - * - * If the files present in `hunspell_dictionaries.zip` are available at - * `https://example.com/dictionaries/language-code.bdic` then you should call this - * api with - * `ses.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/')`. - * Please note the trailing slash. The URL to the dictionaries is formed as - * `${url}${filename}`. - * - * **Note:** On macOS the OS spellchecker is used and therefore we do not download - * any dictionary files. This API is a no-op on macOS. - */ - setSpellCheckerDictionaryDownloadURL(url: string): void; - /** - * Sets whether to enable the builtin spell checker. - */ - setSpellCheckerEnabled(enable: boolean): void; - /** - * The built in spellchecker does not automatically detect what language a user is - * typing in. In order for the spell checker to correctly check their words you - * must call this API with an array of language codes. You can get the list of - * supported language codes with the `ses.availableSpellCheckerLanguages` property. - * - * **Note:** On macOS the OS spellchecker is used and will detect your language - * automatically. This API is a no-op on macOS. - */ - setSpellCheckerLanguages(languages: string[]): void; - /** - * Sets the SSL configuration for the session. All subsequent network requests will - * use the new configuration. Existing network connections (such as WebSocket - * connections) will not be terminated, but old sockets in the pool will not be - * reused for new connections. - */ - setSSLConfig(config: SSLConfigConfig): void; - /** - * Overrides the `userAgent` and `acceptLanguages` for this session. - * - * The `acceptLanguages` must a comma separated ordered list of language codes, for - * example `"en-US,fr,de,ko,zh-CN,ja"`. - * - * This doesn't affect existing `WebContents`, and each `WebContents` can use - * `webContents.setUserAgent` to override the session-wide user agent. - */ - setUserAgent(userAgent: string, acceptLanguages?: string): void; - /** - * A `string[]` array which consists of all the known available spell checker - * languages. Providing a language code to the `setSpellCheckerLanguages` API that - * isn't in this array will result in an error. - * - */ - readonly availableSpellCheckerLanguages: string[]; - /** - * A `Cookies` object for this session. - * - */ - readonly cookies: Cookies; - /** - * A `NetLog` object for this session. - * - */ - readonly netLog: NetLog; - /** - * A `Protocol` object for this session. - * - */ - readonly protocol: Protocol; - /** - * A `ServiceWorkers` object for this session. - * - */ - readonly serviceWorkers: ServiceWorkers; - /** - * A `boolean` indicating whether builtin spell checker is enabled. - */ - spellCheckerEnabled: boolean; - /** - * 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`. - * - */ - readonly storagePath: (string) | (null); - /** - * A `WebRequest` object for this session. - * - */ - readonly webRequest: WebRequest; - } - - interface SharedWorkerInfo { - - // Docs: https://electronjs.org/docs/api/structures/shared-worker-info - - /** - * The unique id of the shared worker. - */ - id: string; - /** - * The url of the shared worker. - */ - url: string; - } - - class ShareMenu extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/share-menu - - /** - * ShareMenu - */ - constructor(sharingItem: SharingItem); - /** - * Closes the context menu in the `browserWindow`. - */ - closePopup(browserWindow?: BrowserWindow): void; - /** - * Pops up this menu as a context menu in the `BrowserWindow`. - */ - popup(options?: PopupOptions): void; - } - - interface SharingItem { - - // Docs: https://electronjs.org/docs/api/structures/sharing-item - - /** - * An array of files to share. - */ - filePaths?: string[]; - /** - * An array of text to share. - */ - texts?: string[]; - /** - * An array of URLs to share. - */ - urls?: string[]; - } - - interface Shell { - - // Docs: https://electronjs.org/docs/api/shell - - /** - * Play the beep sound. - */ - beep(): void; - /** - * Open the given external protocol URL in the desktop's default manner. (For - * example, mailto: URLs in the user's default mail agent). - */ - openExternal(url: string, options?: OpenExternalOptions): Promise<void>; - /** - * Resolves with a string containing the error message corresponding to the failure - * if a failure occurred, otherwise "". - * - * Open the given file in the desktop's default manner. - */ - openPath(path: string): Promise<string>; - /** - * Resolves the shortcut link at `shortcutPath`. - * - * An exception will be thrown when any error happens. - * - * @platform win32 - */ - readShortcutLink(shortcutPath: string): ShortcutDetails; - /** - * Show the given file in a file manager. If possible, select the file. - */ - showItemInFolder(fullPath: string): void; - /** - * Resolves when the operation has been completed. Rejects if there was an error - * while deleting the requested item. - * - * This moves a path to the OS-specific trash location (Trash on macOS, Recycle Bin - * on Windows, and a desktop-environment-specific location on Linux). - */ - trashItem(path: string): Promise<void>; - /** - * Whether the shortcut was created successfully. - * - * Creates or updates a shortcut link at `shortcutPath`. - * - * @platform win32 - */ - writeShortcutLink(shortcutPath: string, operation: 'create' | 'update' | 'replace', options: ShortcutDetails): boolean; - /** - * Whether the shortcut was created successfully. - * - * Creates or updates a shortcut link at `shortcutPath`. - * - * @platform win32 - */ - writeShortcutLink(shortcutPath: string, options: ShortcutDetails): boolean; - } - - interface ShortcutDetails { - - // Docs: https://electronjs.org/docs/api/structures/shortcut-details - - /** - * The Application User Model ID. Default is empty. - */ - appUserModelId?: string; - /** - * The arguments to be applied to `target` when launching from this shortcut. - * Default is empty. - */ - args?: string; - /** - * The working directory. Default is empty. - */ - cwd?: string; - /** - * The description of the shortcut. Default is empty. - */ - description?: string; - /** - * The path to the icon, can be a DLL or EXE. `icon` and `iconIndex` have to be set - * together. Default is empty, which uses the target's icon. - */ - icon?: string; - /** - * The resource ID of icon when `icon` is a DLL or EXE. Default is 0. - */ - iconIndex?: number; - /** - * The target to launch from this shortcut. - */ - target: string; - /** - * The Application Toast Activator CLSID. Needed for participating in Action - * Center. - */ - toastActivatorClsid?: string; - } - - interface Size { - - // Docs: https://electronjs.org/docs/api/structures/size - - height: number; - width: number; - } - - interface SystemPreferences extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/system-preferences - - on(event: 'accent-color-changed', listener: (event: Event, - /** - * The new RGBA color the user assigned to be their system accent color. - */ - newColor: string) => void): this; - once(event: 'accent-color-changed', listener: (event: Event, - /** - * The new RGBA color the user assigned to be their system accent color. - */ - newColor: string) => void): this; - addListener(event: 'accent-color-changed', listener: (event: Event, - /** - * The new RGBA color the user assigned to be their system accent color. - */ - newColor: string) => void): this; - removeListener(event: 'accent-color-changed', listener: (event: Event, - /** - * The new RGBA color the user assigned to be their system accent color. - */ - newColor: string) => void): this; - on(event: 'color-changed', listener: (event: Event) => void): this; - once(event: 'color-changed', listener: (event: Event) => void): this; - addListener(event: 'color-changed', listener: (event: Event) => void): this; - removeListener(event: 'color-changed', listener: (event: Event) => void): this; - /** - * **Deprecated:** Should use the new `updated` event on the `nativeTheme` module. - * - * @deprecated - * @platform win32 - */ - on(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; - once(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; - addListener(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; - removeListener(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; - /** - * **Deprecated:** Should use the new `updated` event on the `nativeTheme` module. - * - * @deprecated - * @platform win32 - */ - on(event: 'inverted-color-scheme-changed', listener: (event: Event, - /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. - */ - invertedColorScheme: boolean) => void): this; - once(event: 'inverted-color-scheme-changed', listener: (event: Event, - /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. - */ - invertedColorScheme: boolean) => void): this; - addListener(event: 'inverted-color-scheme-changed', listener: (event: Event, - /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. - */ - invertedColorScheme: boolean) => void): this; - removeListener(event: 'inverted-color-scheme-changed', listener: (event: Event, - /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. - */ - invertedColorScheme: boolean) => void): this; - /** - * A promise that resolves with `true` if consent was granted and `false` if it was - * denied. If an invalid `mediaType` is passed, the promise will be rejected. If an - * access request was denied and later is changed through the System Preferences - * pane, a restart of the app will be required for the new permissions to take - * effect. If access has already been requested and denied, it _must_ be changed - * through the preference pane; an alert will not pop up and the promise will - * resolve with the existing access status. - * - * **Important:** In order to properly leverage this API, you must set the - * `NSMicrophoneUsageDescription` and `NSCameraUsageDescription` strings in your - * app's `Info.plist` file. The values for these keys will be used to populate the - * permission dialogs so that the user will be properly informed as to the purpose - * of the permission request. See Electron Application Distribution for more - * information about how to set these in the context of Electron. - * - * This user consent was not required until macOS 10.14 Mojave, so this method will - * always return `true` if your system is running 10.13 High Sierra or lower. - * - * @platform darwin - */ - askForMediaAccess(mediaType: 'microphone' | 'camera'): Promise<boolean>; - /** - * whether or not this device has the ability to use Touch ID. - * - * **NOTE:** This API will return `false` on macOS systems older than Sierra - * 10.12.2. - * - * @platform darwin - */ - canPromptTouchID(): boolean; - /** - * The users current system wide accent color preference in RGBA hexadecimal form. - * - * This API is only available on macOS 10.14 Mojave or newer. - * - * @platform win32,darwin - */ - getAccentColor(): string; - /** - * * `shouldRenderRichAnimation` boolean - Returns true if rich animations should - * be rendered. Looks at session type (e.g. remote desktop) and accessibility - * settings to give guidance for heavy animations. - * * `scrollAnimationsEnabledBySystem` boolean - Determines on a per-platform basis - * whether scroll animations (e.g. produced by home/end key) should be enabled. - * * `prefersReducedMotion` boolean - Determines whether the user desires reduced - * motion based on platform APIs. - * - * Returns an object with system animation settings. - */ - getAnimationSettings(): AnimationSettings; - /** - * | `null` - Can be `dark`, `light` or `unknown`. - * - * Gets the macOS appearance setting that you have declared you want for your - * application, maps to NSApplication.appearance. You can use the - * `setAppLevelAppearance` API to set this value. - * - * @deprecated - * @platform darwin - */ - getAppLevelAppearance(): ('dark' | 'light' | 'unknown'); - /** - * The system color setting in RGB hexadecimal form (`#ABCDEF`). See the Windows - * docs and the macOS docs for more details. - * - * The following colors are only available on macOS 10.14: `find-highlight`, - * `selected-content-background`, `separator`, - * `unemphasized-selected-content-background`, - * `unemphasized-selected-text-background`, and `unemphasized-selected-text`. - * - * @platform win32,darwin - */ - getColor(color: '3d-dark-shadow' | '3d-face' | '3d-highlight' | '3d-light' | '3d-shadow' | 'active-border' | 'active-caption' | 'active-caption-gradient' | 'app-workspace' | 'button-text' | 'caption-text' | 'desktop' | 'disabled-text' | 'highlight' | 'highlight-text' | 'hotlight' | 'inactive-border' | 'inactive-caption' | 'inactive-caption-gradient' | 'inactive-caption-text' | 'info-background' | 'info-text' | 'menu' | 'menu-highlight' | 'menubar' | 'menu-text' | 'scrollbar' | 'window' | 'window-frame' | 'window-text' | 'alternate-selected-control-text' | 'control-background' | 'control' | 'control-text' | 'disabled-control-text' | 'find-highlight' | 'grid' | 'header-text' | 'highlight' | 'keyboard-focus-indicator' | 'label' | 'link' | 'placeholder-text' | 'quaternary-label' | 'scrubber-textured-background' | 'secondary-label' | 'selected-content-background' | 'selected-control' | 'selected-control-text' | 'selected-menu-item-text' | 'selected-text-background' | 'selected-text' | 'separator' | 'shadow' | 'tertiary-label' | 'text-background' | 'text' | 'under-page-background' | 'unemphasized-selected-content-background' | 'unemphasized-selected-text-background' | 'unemphasized-selected-text' | 'window-background' | 'window-frame-text'): string; - /** - * Can be `dark`, `light` or `unknown`. - * - * Gets the macOS appearance setting that is currently applied to your application, - * maps to NSApplication.effectiveAppearance - * - * @platform darwin - */ - getEffectiveAppearance(): ('dark' | 'light' | 'unknown'); - /** - * Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`. - * - * This user consent was not required on macOS 10.13 High Sierra or lower so this - * method will always return `granted`. macOS 10.14 Mojave or higher requires - * consent for `microphone` and `camera` access. macOS 10.15 Catalina or higher - * requires consent for `screen` access. - * - * Windows 10 has a global setting controlling `microphone` and `camera` access for - * all win32 applications. It will always return `granted` for `screen` and for all - * media types on older versions of Windows. - * - * @platform win32,darwin - */ - getMediaAccessStatus(mediaType: 'microphone' | 'camera' | 'screen'): ('not-determined' | 'granted' | 'denied' | 'restricted' | 'unknown'); - /** - * The standard system color formatted as `#RRGGBBAA`. - * - * Returns one of several standard system colors that automatically adapt to - * vibrancy and changes in accessibility settings like 'Increase contrast' and - * 'Reduce transparency'. See Apple Documentation for more details. - * - * @platform darwin - */ - getSystemColor(color: 'blue' | 'brown' | 'gray' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'yellow'): string; - /** - * The value of `key` in `NSUserDefaults`. - * - * Some popular `key` and `type`s are: - * - * * `AppleInterfaceStyle`: `string` - * * `AppleAquaColorVariant`: `integer` - * * `AppleHighlightColor`: `string` - * * `AppleShowScrollBars`: `string` - * * `NSNavRecentPlaces`: `array` - * * `NSPreferredWebServices`: `dictionary` - * * `NSUserDictionaryReplacementItems`: `array` - * - * @platform darwin - */ - getUserDefault<Type extends keyof UserDefaultTypes>(key: string, type: Type): UserDefaultTypes[Type]; - /** - * `true` if DWM composition (Aero Glass) is enabled, and `false` otherwise. - * - * An example of using it to determine if you should create a transparent window or - * not (transparent windows won't work correctly when DWM composition is disabled): - * - * @platform win32 - */ - isAeroGlassEnabled(): boolean; - /** - * Whether the system is in Dark Mode. - * - * **Deprecated:** Should use the new `nativeTheme.shouldUseDarkColors` API. - * - * @deprecated - * @platform darwin,win32 - */ - isDarkMode(): boolean; - /** - * `true` if a high contrast theme is active, `false` otherwise. - * - * **Deprecated:** Should use the new `nativeTheme.shouldUseHighContrastColors` - * API. - * - * @deprecated - * @platform darwin,win32 - */ - isHighContrastColorScheme(): boolean; - /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is active, `false` otherwise. - * - * **Deprecated:** Should use the new `nativeTheme.shouldUseInvertedColorScheme` - * API. - * - * @deprecated - * @platform win32 - */ - isInvertedColorScheme(): boolean; - /** - * Whether the Swipe between pages setting is on. - * - * @platform darwin - */ - isSwipeTrackingFromScrollEventsEnabled(): boolean; - /** - * `true` if the current process is a trusted accessibility client and `false` if - * it is not. - * - * @platform darwin - */ - isTrustedAccessibilityClient(prompt: boolean): boolean; - /** - * Posts `event` as native notifications of macOS. The `userInfo` is an Object that - * contains the user information dictionary sent along with the notification. - * - * @platform darwin - */ - postLocalNotification(event: string, userInfo: Record<string, any>): void; - /** - * Posts `event` as native notifications of macOS. The `userInfo` is an Object that - * contains the user information dictionary sent along with the notification. - * - * @platform darwin - */ - postNotification(event: string, userInfo: Record<string, any>, deliverImmediately?: boolean): void; - /** - * Posts `event` as native notifications of macOS. The `userInfo` is an Object that - * contains the user information dictionary sent along with the notification. - * - * @platform darwin - */ - postWorkspaceNotification(event: string, userInfo: Record<string, any>): void; - /** - * resolves if the user has successfully authenticated with Touch ID. - * - * This API itself will not protect your user data; rather, it is a mechanism to - * allow you to do so. Native apps will need to set Access Control Constants like - * `kSecAccessControlUserPresence` on their keychain entry so that reading it would - * auto-prompt for Touch ID biometric consent. This could be done with - * `node-keytar`, such that one would store an encryption key with `node-keytar` - * and only fetch it if `promptTouchID()` resolves. - * - * **NOTE:** This API will return a rejected Promise on macOS systems older than - * Sierra 10.12.2. - * - * @platform darwin - */ - promptTouchID(reason: string): Promise<void>; - /** - * Add the specified defaults to your application's `NSUserDefaults`. - * - * @platform darwin - */ - registerDefaults(defaults: Record<string, (string) | (boolean) | (number)>): void; - /** - * Removes the `key` in `NSUserDefaults`. This can be used to restore the default - * or global value of a `key` previously set with `setUserDefault`. - * - * @platform darwin - */ - removeUserDefault(key: string): void; - /** - * Sets the appearance setting for your application, this should override the - * system default and override the value of `getEffectiveAppearance`. - * - * @deprecated - * @platform darwin - */ - setAppLevelAppearance(appearance: (('dark' | 'light')) | (null)): void; - /** - * Set the value of `key` in `NSUserDefaults`. - * - * Note that `type` should match actual type of `value`. An exception is thrown if - * they don't. - * - * Some popular `key` and `type`s are: - * - * * `ApplePressAndHoldEnabled`: `boolean` - * - * @platform darwin - */ - setUserDefault(key: string, type: 'string' | 'boolean' | 'integer' | 'float' | 'double' | 'url' | 'array' | 'dictionary', value: string): void; - /** - * The ID of this subscription - * - * Same as `subscribeNotification`, but uses `NSNotificationCenter` for local - * defaults. This is necessary for events such as - * `NSUserDefaultsDidChangeNotification`. - * - * If `event` is null, the `NSNotificationCenter` doesn’t use it as criteria for - * delivery to the observer. See docs for more information. - * - * @platform darwin - */ - subscribeLocalNotification(event: (string) | (null), callback: (event: string, userInfo: Record<string, unknown>, object: string) => void): number; - /** - * The ID of this subscription - * - * Subscribes to native notifications of macOS, `callback` will be called with - * `callback(event, userInfo)` when the corresponding `event` happens. The - * `userInfo` is an Object that contains the user information dictionary sent along - * with the notification. The `object` is the sender of the notification, and only - * supports `NSString` values for now. - * - * The `id` of the subscriber is returned, which can be used to unsubscribe the - * `event`. - * - * Under the hood this API subscribes to `NSDistributedNotificationCenter`, example - * values of `event` are: - * - * * `AppleInterfaceThemeChangedNotification` - * * `AppleAquaColorVariantChanged` - * * `AppleColorPreferencesChangedNotification` - * * `AppleShowScrollBarsSettingChanged` - * - * If `event` is null, the `NSDistributedNotificationCenter` doesn’t use it as - * criteria for delivery to the observer. See docs for more information. - * - * @platform darwin - */ - subscribeNotification(event: (string) | (null), callback: (event: string, userInfo: Record<string, unknown>, object: string) => void): number; - /** - * The ID of this subscription - * - * Same as `subscribeNotification`, but uses - * `NSWorkspace.sharedWorkspace.notificationCenter`. This is necessary for events - * such as `NSWorkspaceDidActivateApplicationNotification`. - * - * If `event` is null, the `NSWorkspaceNotificationCenter` doesn’t use it as - * criteria for delivery to the observer. See docs for more information. - * - * @platform darwin - */ - subscribeWorkspaceNotification(event: (string) | (null), callback: (event: string, userInfo: Record<string, unknown>, object: string) => void): number; - /** - * Same as `unsubscribeNotification`, but removes the subscriber from - * `NSNotificationCenter`. - * - * @platform darwin - */ - unsubscribeLocalNotification(id: number): void; - /** - * Removes the subscriber with `id`. - * - * @platform darwin - */ - unsubscribeNotification(id: number): void; - /** - * Same as `unsubscribeNotification`, but removes the subscriber from - * `NSWorkspace.sharedWorkspace.notificationCenter`. - * - * @platform darwin - */ - unsubscribeWorkspaceNotification(id: number): void; - /** - * A `string` property that can be `dark`, `light` or `unknown`. It determines the - * macOS appearance setting for your application. This maps to values in: - * NSApplication.appearance. Setting this will override the system default as well - * as the value of `getEffectiveAppearance`. - * - * Possible values that can be set are `dark` and `light`, and possible return - * values are `dark`, `light`, and `unknown`. - * - * This property is only available on macOS 10.14 Mojave or newer. - * - * @platform darwin - */ - appLevelAppearance: ('dark' | 'light' | 'unknown'); - /** - * A `string` property that can be `dark`, `light` or `unknown`. - * - * Returns the macOS appearance setting that is currently applied to your - * application, maps to NSApplication.effectiveAppearance - * - * @platform darwin - */ - readonly effectiveAppearance: ('dark' | 'light' | 'unknown'); - } - - interface Task { - - // Docs: https://electronjs.org/docs/api/structures/task - - /** - * The command line arguments when `program` is executed. - */ - arguments: string; - /** - * Description of this task. - */ - description: string; - /** - * The icon index in the icon file. If an icon file consists of two or more icons, - * set this value to identify the icon. If an icon file consists of one icon, this - * value is 0. - */ - iconIndex: number; - /** - * The absolute path to an icon to be displayed in a JumpList, which can be an - * arbitrary resource file that contains an icon. You can usually specify - * `process.execPath` to show the icon of the program. - */ - iconPath: string; - /** - * Path of the program to execute, usually you should specify `process.execPath` - * which opens the current program. - */ - program: string; - /** - * The string to be displayed in a JumpList. - */ - title: string; - /** - * The working directory. Default is empty. - */ - workingDirectory?: string; - } - - interface ThumbarButton { - - // Docs: https://electronjs.org/docs/api/structures/thumbar-button - - click: Function; - /** - * Control specific states and behaviors of the button. By default, it is - * `['enabled']`. - */ - flags?: string[]; - /** - * The icon showing in thumbnail toolbar. - */ - icon: NativeImage; - /** - * The text of the button's tooltip. - */ - tooltip?: string; - } - - class TouchBar { - - // Docs: https://electronjs.org/docs/api/touch-bar - - /** - * TouchBar - */ - constructor(options: TouchBarConstructorOptions); - /** - * A `TouchBarItem` that will replace the "esc" button on the touch bar when set. - * Setting to `null` restores the default "esc" button. Changing this value - * immediately updates the escape item in the touch bar. - */ - escapeItem: (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer | null); - /** - * A `typeof TouchBarButton` reference to the `TouchBarButton` class. - */ - static TouchBarButton: typeof TouchBarButton; - /** - * A `typeof TouchBarColorPicker` reference to the `TouchBarColorPicker` class. - */ - static TouchBarColorPicker: typeof TouchBarColorPicker; - /** - * A `typeof TouchBarGroup` reference to the `TouchBarGroup` class. - */ - static TouchBarGroup: typeof TouchBarGroup; - /** - * A `typeof TouchBarLabel` reference to the `TouchBarLabel` class. - */ - static TouchBarLabel: typeof TouchBarLabel; - /** - * A `typeof TouchBarOtherItemsProxy` reference to the `TouchBarOtherItemsProxy` - * class. - */ - static TouchBarOtherItemsProxy: typeof TouchBarOtherItemsProxy; - /** - * A `typeof TouchBarPopover` reference to the `TouchBarPopover` class. - */ - static TouchBarPopover: typeof TouchBarPopover; - /** - * A `typeof TouchBarScrubber` reference to the `TouchBarScrubber` class. - */ - static TouchBarScrubber: typeof TouchBarScrubber; - /** - * A `typeof TouchBarSegmentedControl` reference to the `TouchBarSegmentedControl` - * class. - */ - static TouchBarSegmentedControl: typeof TouchBarSegmentedControl; - /** - * A `typeof TouchBarSlider` reference to the `TouchBarSlider` class. - */ - static TouchBarSlider: typeof TouchBarSlider; - /** - * A `typeof TouchBarSpacer` reference to the `TouchBarSpacer` class. - */ - static TouchBarSpacer: typeof TouchBarSpacer; - } - - class TouchBarButton { - - // Docs: https://electronjs.org/docs/api/touch-bar-button - - /** - * TouchBarButton - */ - constructor(options: TouchBarButtonConstructorOptions); - /** - * A `string` representing the description of the button to be read by a screen - * reader. Will only be read by screen readers if no label is set. - */ - accessibilityLabel: string; - /** - * A `string` hex code representing the button's current background color. Changing - * this value immediately updates the button in the touch bar. - */ - backgroundColor: string; - /** - * A `boolean` representing whether the button is in an enabled state. - */ - enabled: boolean; - /** - * A `NativeImage` representing the button's current icon. Changing this value - * immediately updates the button in the touch bar. - */ - icon: NativeImage; - /** - * A `string` - Can be `left`, `right` or `overlay`. Defaults to `overlay`. - */ - iconPosition: ('left' | 'right' | 'overlay'); - /** - * A `string` representing the button's current text. Changing this value - * immediately updates the button in the touch bar. - */ - label: string; - } - - class TouchBarColorPicker extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-color-picker - - /** - * TouchBarColorPicker - */ - constructor(options: TouchBarColorPickerConstructorOptions); - /** - * A `string[]` array representing the color picker's available colors to select. - * Changing this value immediately updates the color picker in the touch bar. - */ - availableColors: string[]; - /** - * A `string` hex code representing the color picker's currently selected color. - * Changing this value immediately updates the color picker in the touch bar. - */ - selectedColor: string; - } - - class TouchBarGroup extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-group - - /** - * TouchBarGroup - */ - constructor(options: TouchBarGroupConstructorOptions); - } - - class TouchBarLabel extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-label - - /** - * TouchBarLabel - */ - constructor(options: TouchBarLabelConstructorOptions); - /** - * A `string` representing the description of the label to be read by a screen - * reader. - */ - accessibilityLabel: string; - /** - * A `string` representing the label's current text. Changing this value - * immediately updates the label in the touch bar. - */ - label: string; - /** - * A `string` hex code representing the label's current text color. Changing this - * value immediately updates the label in the touch bar. - */ - textColor: string; - } - - class TouchBarOtherItemsProxy extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-other-items-proxy - - /** - * TouchBarOtherItemsProxy - */ - constructor(); - } - - class TouchBarPopover extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-popover - - /** - * TouchBarPopover - */ - constructor(options: TouchBarPopoverConstructorOptions); - /** - * A `NativeImage` representing the popover's current button icon. Changing this - * value immediately updates the popover in the touch bar. - */ - icon: NativeImage; - /** - * A `string` representing the popover's current button text. Changing this value - * immediately updates the popover in the touch bar. - */ - label: string; - } - - class TouchBarScrubber extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-scrubber - - /** - * TouchBarScrubber - */ - constructor(options: TouchBarScrubberConstructorOptions); - /** - * A `boolean` representing whether this scrubber is continuous or not. Updating - * this value immediately updates the control in the touch bar. - */ - continuous: boolean; - /** - * A `ScrubberItem[]` array representing the items in this scrubber. Updating this - * value immediately updates the control in the touch bar. Updating deep properties - * inside this array **does not update the touch bar**. - */ - items: ScrubberItem[]; - /** - * A `string` representing the mode of this scrubber. Updating this value - * immediately updates the control in the touch bar. Possible values: - * - * * `fixed` - Maps to `NSScrubberModeFixed`. - * * `free` - Maps to `NSScrubberModeFree`. - */ - mode: ('fixed' | 'free'); - /** - * A `string` representing the style that selected items in the scrubber should - * have. This style is overlayed on top of the scrubber item instead of being - * placed behind it. Updating this value immediately updates the control in the - * touch bar. Possible values: - * - * * `background` - Maps to `[NSScrubberSelectionStyle roundedBackgroundStyle]`. - * * `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`. - * * `none` - Removes all styles. - */ - overlayStyle: ('background' | 'outline' | 'none'); - /** - * A `string` representing the style that selected items in the scrubber should - * have. Updating this value immediately updates the control in the touch bar. - * Possible values: - * - * * `background` - Maps to `[NSScrubberSelectionStyle roundedBackgroundStyle]`. - * * `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`. - * * `none` - Removes all styles. - */ - selectedStyle: ('background' | 'outline' | 'none'); - /** - * A `boolean` representing whether to show the left / right selection arrows in - * this scrubber. Updating this value immediately updates the control in the touch - * bar. - */ - showArrowButtons: boolean; - } - - class TouchBarSegmentedControl extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-segmented-control - - /** - * TouchBarSegmentedControl - */ - constructor(options: TouchBarSegmentedControlConstructorOptions); - /** - * A `string` representing the current selection mode of the control. Can be - * `single`, `multiple` or `buttons`. - */ - mode: ('single' | 'multiple' | 'buttons'); - /** - * A `SegmentedControlSegment[]` array representing the segments in this control. - * Updating this value immediately updates the control in the touch bar. Updating - * deep properties inside this array **does not update the touch bar**. - */ - segments: SegmentedControlSegment[]; - /** - * A `string` representing the controls current segment style. Updating this value - * immediately updates the control in the touch bar. - */ - segmentStyle: string; - /** - * An `Integer` representing the currently selected segment. Changing this value - * immediately updates the control in the touch bar. User interaction with the - * touch bar will update this value automatically. - */ - selectedIndex: number; - } - - class TouchBarSlider extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-slider - - /** - * TouchBarSlider - */ - constructor(options: TouchBarSliderConstructorOptions); - /** - * A `string` representing the slider's current text. Changing this value - * immediately updates the slider in the touch bar. - */ - label: string; - /** - * A `number` representing the slider's current maximum value. Changing this value - * immediately updates the slider in the touch bar. - */ - maxValue: number; - /** - * A `number` representing the slider's current minimum value. Changing this value - * immediately updates the slider in the touch bar. - */ - minValue: number; - /** - * A `number` representing the slider's current value. Changing this value - * immediately updates the slider in the touch bar. - */ - value: number; - } - - class TouchBarSpacer extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/touch-bar-spacer - - /** - * TouchBarSpacer - */ - constructor(options: TouchBarSpacerConstructorOptions); - /** - * A `string` representing the size of the spacer. Can be `small`, `large` or - * `flexible`. - */ - size: ('small' | 'large' | 'flexible'); - } - - interface TraceCategoriesAndOptions { - - // Docs: https://electronjs.org/docs/api/structures/trace-categories-and-options - - /** - * A filter to control what category groups should be traced. A filter can have an - * optional '-' prefix to exclude category groups that contain a matching category. - * Having both included and excluded category patterns in the same list is not - * supported. Examples: `test_MyTest*`, `test_MyTest*,test_OtherStuff`, - * `-excluded_category1,-excluded_category2`. - */ - categoryFilter: string; - /** - * Controls what kind of tracing is enabled, it is a comma-delimited sequence of - * the following strings: `record-until-full`, `record-continuously`, - * `trace-to-console`, `enable-sampling`, `enable-systrace`, e.g. - * `'record-until-full,enable-sampling'`. The first 3 options are trace recording - * modes and hence mutually exclusive. If more than one trace recording modes - * appear in the `traceOptions` string, the last one takes precedence. If none of - * the trace recording modes are specified, recording mode is `record-until-full`. - * The trace option will first be reset to the default option (`record_mode` set to - * `record-until-full`, `enable_sampling` and `enable_systrace` set to `false`) - * before options parsed from `traceOptions` are applied on it. - */ - traceOptions: string; - } - - interface TraceConfig { - - // Docs: https://electronjs.org/docs/api/structures/trace-config - - /** - * if true, filter event data according to a specific list of events that have been - * manually vetted to not include any PII. See the implementation in Chromium for - * specifics. - */ - enable_argument_filter?: boolean; - /** - * a list of tracing categories to exclude. Can include glob-like patterns using - * `*` at the end of the category name. See tracing categories for the list of - * categories. - */ - excluded_categories?: string[]; - /** - * a list of histogram names to report with the trace. - */ - histogram_names?: string[]; - /** - * a list of tracing categories to include. Can include glob-like patterns using - * `*` at the end of the category name. See tracing categories for the list of - * categories. - */ - included_categories?: string[]; - /** - * a list of process IDs to include in the trace. If not specified, trace all - * processes. - */ - included_process_ids?: number[]; - /** - * if the `disabled-by-default-memory-infra` category is enabled, this contains - * optional additional configuration for data collection. See the Chromium - * memory-infra docs for more information. - */ - memory_dump_config?: Record<string, any>; - /** - * Can be `record-until-full`, `record-continuously`, `record-as-much-as-possible` - * or `trace-to-console`. Defaults to `record-until-full`. - */ - recording_mode?: ('record-until-full' | 'record-continuously' | 'record-as-much-as-possible' | 'trace-to-console'); - /** - * maximum size of the trace recording buffer in events. - */ - trace_buffer_size_in_events?: number; - /** - * maximum size of the trace recording buffer in kilobytes. Defaults to 100MB. - */ - trace_buffer_size_in_kb?: number; - } - - interface Transaction { - - // Docs: https://electronjs.org/docs/api/structures/transaction - - /** - * The error code if an error occurred while processing the transaction. - */ - errorCode: number; - /** - * The error message if an error occurred while processing the transaction. - */ - errorMessage: string; - /** - * The identifier of the restored transaction by the App Store. - */ - originalTransactionIdentifier: string; - payment: Payment; - /** - * The date the transaction was added to the App Store’s payment queue. - */ - transactionDate: string; - /** - * A string that uniquely identifies a successful payment transaction. - */ - transactionIdentifier: string; - /** - * The transaction state, can be `purchasing`, `purchased`, `failed`, `restored` or - * `deferred`. - */ - transactionState: ('purchasing' | 'purchased' | 'failed' | 'restored' | 'deferred'); - } - - class Tray extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/tray - - /** - * Emitted when the tray balloon is clicked. - * - * @platform win32 - */ - on(event: 'balloon-click', listener: Function): this; - once(event: 'balloon-click', listener: Function): this; - addListener(event: 'balloon-click', listener: Function): this; - removeListener(event: 'balloon-click', listener: Function): this; - /** - * Emitted when the tray balloon is closed because of timeout or user manually - * closes it. - * - * @platform win32 - */ - on(event: 'balloon-closed', listener: Function): this; - once(event: 'balloon-closed', listener: Function): this; - addListener(event: 'balloon-closed', listener: Function): this; - removeListener(event: 'balloon-closed', listener: Function): this; - /** - * Emitted when the tray balloon shows. - * - * @platform win32 - */ - on(event: 'balloon-show', listener: Function): this; - once(event: 'balloon-show', listener: Function): this; - addListener(event: 'balloon-show', listener: Function): this; - removeListener(event: 'balloon-show', listener: Function): this; - /** - * Emitted when the tray icon is clicked. - */ - on(event: 'click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle, - /** - * The position of the event. - */ - position: Point) => void): this; - once(event: 'click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle, - /** - * The position of the event. - */ - position: Point) => void): this; - addListener(event: 'click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle, - /** - * The position of the event. - */ - position: Point) => void): this; - removeListener(event: 'click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle, - /** - * The position of the event. - */ - position: Point) => void): this; - /** - * Emitted when the tray icon is double clicked. - * - * @platform darwin,win32 - */ - on(event: 'double-click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle) => void): this; - once(event: 'double-click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle) => void): this; - addListener(event: 'double-click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle) => void): this; - removeListener(event: 'double-click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle) => void): this; - /** - * Emitted when a drag operation ends on the tray or ends at another location. - * - * @platform darwin - */ - on(event: 'drag-end', listener: Function): this; - once(event: 'drag-end', listener: Function): this; - addListener(event: 'drag-end', listener: Function): this; - removeListener(event: 'drag-end', listener: Function): this; - /** - * Emitted when a drag operation enters the tray icon. - * - * @platform darwin - */ - on(event: 'drag-enter', listener: Function): this; - once(event: 'drag-enter', listener: Function): this; - addListener(event: 'drag-enter', listener: Function): this; - removeListener(event: 'drag-enter', listener: Function): this; - /** - * Emitted when a drag operation exits the tray icon. - * - * @platform darwin - */ - on(event: 'drag-leave', listener: Function): this; - once(event: 'drag-leave', listener: Function): this; - addListener(event: 'drag-leave', listener: Function): this; - removeListener(event: 'drag-leave', listener: Function): this; - /** - * Emitted when any dragged items are dropped on the tray icon. - * - * @platform darwin - */ - on(event: 'drop', listener: Function): this; - once(event: 'drop', listener: Function): this; - addListener(event: 'drop', listener: Function): this; - removeListener(event: 'drop', listener: Function): this; - /** - * Emitted when dragged files are dropped in the tray icon. - * - * @platform darwin - */ - on(event: 'drop-files', listener: (event: Event, - /** - * The paths of the dropped files. - */ - files: string[]) => void): this; - once(event: 'drop-files', listener: (event: Event, - /** - * The paths of the dropped files. - */ - files: string[]) => void): this; - addListener(event: 'drop-files', listener: (event: Event, - /** - * The paths of the dropped files. - */ - files: string[]) => void): this; - removeListener(event: 'drop-files', listener: (event: Event, - /** - * The paths of the dropped files. - */ - files: string[]) => void): this; - /** - * Emitted when dragged text is dropped in the tray icon. - * - * @platform darwin - */ - on(event: 'drop-text', listener: (event: Event, - /** - * the dropped text string. - */ - text: string) => void): this; - once(event: 'drop-text', listener: (event: Event, + killed: boolean) => void): this; + once(event: 'renderer-process-crashed', listener: (event: Event, + webContents: WebContents, + killed: boolean) => void): this; + addListener(event: 'renderer-process-crashed', listener: (event: Event, + webContents: WebContents, + killed: boolean) => void): this; + removeListener(event: 'renderer-process-crashed', listener: (event: Event, + webContents: WebContents, + killed: boolean) => void): this; + /** + * This event will be emitted inside the primary instance of your application when + * a second instance has been executed and calls `app.requestSingleInstanceLock()`. + * + * `argv` is an Array of the second instance's command line arguments, and + * `workingDirectory` is its current working directory. Usually applications + * respond to this by making their primary window focused and non-minimized. + * + * **Note:** If the second instance is started by a different user than the first, + * the `argv` array will not include the arguments. + * + * This event is guaranteed to be emitted after the `ready` event of `app` gets + * emitted. + * + * **Note:** Extra command line arguments might be added by Chromium, such as + * `--original-process-start-time`. + */ + on(event: 'second-instance', listener: (event: Event, /** - * the dropped text string. + * An array of the second instance's command line arguments */ - text: string) => void): this; - addListener(event: 'drop-text', listener: (event: Event, - /** - * the dropped text string. - */ - text: string) => void): this; - removeListener(event: 'drop-text', listener: (event: Event, - /** - * the dropped text string. - */ - text: string) => void): this; - /** - * Emitted when the mouse clicks the tray icon. - * - * @platform darwin - */ - on(event: 'mouse-down', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - once(event: 'mouse-down', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - addListener(event: 'mouse-down', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - removeListener(event: 'mouse-down', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - /** - * Emitted when the mouse enters the tray icon. - * - * @platform darwin - */ - on(event: 'mouse-enter', listener: (event: KeyboardEvent, + argv: string[], /** - * The position of the event. + * The second instance's working directory */ - position: Point) => void): this; - once(event: 'mouse-enter', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - addListener(event: 'mouse-enter', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - removeListener(event: 'mouse-enter', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - /** - * Emitted when the mouse exits the tray icon. - * - * @platform darwin - */ - on(event: 'mouse-leave', listener: (event: KeyboardEvent, + workingDirectory: string, /** - * The position of the event. + * A JSON object of additional data passed from the second instance */ - position: Point) => void): this; - once(event: 'mouse-leave', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - addListener(event: 'mouse-leave', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - removeListener(event: 'mouse-leave', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - /** - * Emitted when the mouse moves in the tray icon. - * - * @platform darwin,win32 - */ - on(event: 'mouse-move', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - once(event: 'mouse-move', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - addListener(event: 'mouse-move', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - removeListener(event: 'mouse-move', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - /** - * Emitted when the mouse is released from clicking the tray icon. - * - * Note: This will not be emitted if you have set a context menu for your Tray - * using `tray.setContextMenu`, as a result of macOS-level constraints. - * - * @platform darwin - */ - on(event: 'mouse-up', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - once(event: 'mouse-up', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - addListener(event: 'mouse-up', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - removeListener(event: 'mouse-up', listener: (event: KeyboardEvent, - /** - * The position of the event. - */ - position: Point) => void): this; - /** - * Emitted when the tray icon is right clicked. - * - * @platform darwin,win32 - */ - on(event: 'right-click', listener: (event: KeyboardEvent, + additionalData: unknown) => void): this; + once(event: 'second-instance', listener: (event: Event, /** - * The bounds of tray icon. + * An array of the second instance's command line arguments */ - bounds: Rectangle) => void): this; - once(event: 'right-click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle) => void): this; - addListener(event: 'right-click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle) => void): this; - removeListener(event: 'right-click', listener: (event: KeyboardEvent, - /** - * The bounds of tray icon. - */ - bounds: Rectangle) => void): this; - /** - * Tray - */ - constructor(image: (NativeImage) | (string), guid?: string); - /** - * Closes an open context menu, as set by `tray.setContextMenu()`. - * - * @platform darwin,win32 - */ - closeContextMenu(): void; - /** - * Destroys the tray icon immediately. - */ - destroy(): void; - /** - * Displays a tray balloon. - * - * @platform win32 - */ - displayBalloon(options: DisplayBalloonOptions): void; - /** - * Returns focus to the taskbar notification area. Notification area icons should - * use this message when they have completed their UI operation. For example, if - * the icon displays a shortcut menu, but the user presses ESC to cancel it, use - * `tray.focus()` to return focus to the notification area. - * - * @platform win32 - */ - focus(): void; - /** - * The `bounds` of this tray icon as `Object`. - * - * @platform darwin,win32 - */ - getBounds(): Rectangle; - /** - * Whether double click events will be ignored. - * - * @platform darwin - */ - getIgnoreDoubleClickEvents(): boolean; - /** - * the title displayed next to the tray icon in the status bar - * - * @platform darwin - */ - getTitle(): string; - /** - * Whether the tray icon is destroyed. - */ - isDestroyed(): boolean; - /** - * Pops up the context menu of the tray icon. When `menu` is passed, the `menu` - * will be shown instead of the tray icon's context menu. - * - * The `position` is only available on Windows, and it is (0, 0) by default. - * - * @platform darwin,win32 - */ - popUpContextMenu(menu?: Menu, position?: Point): void; - /** - * Removes a tray balloon. - * - * @platform win32 - */ - removeBalloon(): void; - /** - * Sets the context menu for this icon. - */ - setContextMenu(menu: (Menu) | (null)): void; - /** - * Sets the option to ignore double click events. Ignoring these events allows you - * to detect every individual click of the tray icon. - * - * This value is set to false by default. - * - * @platform darwin - */ - setIgnoreDoubleClickEvents(ignore: boolean): void; - /** - * Sets the `image` associated with this tray icon. - */ - setImage(image: (NativeImage) | (string)): void; - /** - * Sets the `image` associated with this tray icon when pressed on macOS. - * - * @platform darwin - */ - setPressedImage(image: (NativeImage) | (string)): void; - /** - * Sets the title displayed next to the tray icon in the status bar (Support ANSI - * colors). - * - * @platform darwin - */ - setTitle(title: string, options?: TitleOptions): void; - /** - * Sets the hover text for this tray icon. - */ - setToolTip(toolTip: string): void; - } - - interface UploadData { - - // Docs: https://electronjs.org/docs/api/structures/upload-data - - /** - * UUID of blob data. Use ses.getBlobData method to retrieve the data. - */ - blobUUID?: string; - /** - * Content being sent. - */ - bytes: Buffer; - /** - * Path of file being uploaded. - */ - file?: string; - } - - interface UploadFile { - - // Docs: https://electronjs.org/docs/api/structures/upload-file - - /** - * Path of file to be uploaded. - */ - filePath: string; - /** - * Number of bytes to read from `offset`. Defaults to `0`. - */ - length: number; - /** - * Last Modification time in number of seconds since the UNIX epoch. - */ - modificationTime: number; - /** - * Defaults to `0`. - */ - offset: number; - /** - * `file`. - */ - type: 'file'; - } - - interface UploadRawData { - - // Docs: https://electronjs.org/docs/api/structures/upload-raw-data - - /** - * Data to be uploaded. - */ - bytes: Buffer; - /** - * `rawData`. - */ - type: 'rawData'; - } - - interface UserDefaultTypes { - - // Docs: https://electronjs.org/docs/api/structures/user-default-types - - array: Array<unknown>; - boolean: boolean; - dictionary: Record<string, unknown>; - double: number; - float: number; - integer: number; - string: string; - url: string; - } - - class WebContents extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/web-contents - - /** - * | undefined - A WebContents instance with the given TargetID, or `undefined` if - * there is no WebContents associated with the given TargetID. - * - * When communicating with the Chrome DevTools Protocol, it can be useful to lookup - * a WebContents instance based on its assigned TargetID. - */ - static fromDevToolsTargetId(targetId: string): WebContents; - /** - * | undefined - A WebContents instance with the given ID, or `undefined` if there - * is no WebContents associated with the given ID. - */ - static fromId(id: number): WebContents; - /** - * An array of all `WebContents` instances. This will contain web contents for all - * windows, webviews, opened devtools, and devtools extension background pages. - */ - static getAllWebContents(): WebContents[]; - /** - * The web contents that is focused in this application, otherwise returns `null`. - */ - static getFocusedWebContents(): WebContents; - /** - * Emitted before dispatching the `keydown` and `keyup` events in the page. Calling - * `event.preventDefault` will prevent the page `keydown`/`keyup` events and the - * menu shortcuts. - * - * To only prevent the menu shortcuts, use `setIgnoreMenuShortcuts`: - */ - on(event: 'before-input-event', listener: (event: Event, - /** - * Input properties. - */ - input: Input) => void): this; - once(event: 'before-input-event', listener: (event: Event, - /** - * Input properties. - */ - input: Input) => void): this; - addListener(event: 'before-input-event', listener: (event: Event, - /** - * Input properties. - */ - input: Input) => void): this; - removeListener(event: 'before-input-event', listener: (event: Event, - /** - * Input properties. - */ - input: Input) => void): this; - /** - * Emitted when the `WebContents` loses focus. - */ - on(event: 'blur', listener: Function): this; - once(event: 'blur', listener: Function): this; - addListener(event: 'blur', listener: Function): this; - removeListener(event: 'blur', listener: Function): this; - /** - * Emitted when failed to verify the `certificate` for `url`. - * - * The usage is the same with the `certificate-error` event of `app`. - */ - on(event: 'certificate-error', listener: (event: Event, - url: string, + argv: string[], + /** + * The second instance's working directory + */ + workingDirectory: string, + /** + * A JSON object of additional data passed from the second instance + */ + additionalData: unknown) => void): this; + addListener(event: 'second-instance', listener: (event: Event, + /** + * An array of the second instance's command line arguments + */ + argv: string[], + /** + * The second instance's working directory + */ + workingDirectory: string, + /** + * A JSON object of additional data passed from the second instance + */ + additionalData: unknown) => void): this; + removeListener(event: 'second-instance', listener: (event: Event, + /** + * An array of the second instance's command line arguments + */ + argv: string[], + /** + * The second instance's working directory + */ + workingDirectory: string, + /** + * A JSON object of additional data passed from the second instance + */ + additionalData: unknown) => void): this; + /** + * Emitted when a client certificate is requested. + * + * The `url` corresponds to the navigation entry requesting the client certificate + * and `callback` can be called with an entry filtered from the list. Using + * `event.preventDefault()` prevents the application from using the first + * certificate from the store. + */ + on(event: 'select-client-certificate', listener: (event: Event, + webContents: WebContents, + url: string, + certificateList: Certificate[], + callback: (certificate?: Certificate) => void) => void): this; + once(event: 'select-client-certificate', listener: (event: Event, + webContents: WebContents, + url: string, + certificateList: Certificate[], + callback: (certificate?: Certificate) => void) => void): this; + addListener(event: 'select-client-certificate', listener: (event: Event, + webContents: WebContents, + url: string, + certificateList: Certificate[], + callback: (certificate?: Certificate) => void) => void): this; + removeListener(event: 'select-client-certificate', listener: (event: Event, + webContents: WebContents, + url: string, + certificateList: Certificate[], + callback: (certificate?: Certificate) => void) => void): this; + /** + * Emitted when Electron has created a new `session`. + */ + on(event: 'session-created', listener: (session: Session) => void): this; + once(event: 'session-created', listener: (session: Session) => void): this; + addListener(event: 'session-created', listener: (session: Session) => void): this; + removeListener(event: 'session-created', listener: (session: Session) => void): this; + /** + * Emitted when Handoff is about to be resumed on another device. If you need to + * update the state to be transferred, you should call `event.preventDefault()` + * immediately, construct a new `userInfo` dictionary and call + * `app.updateCurrentActivity()` in a timely manner. Otherwise, the operation will + * fail and `continue-activity-error` will be called. + * + * @platform darwin + */ + on(event: 'update-activity-state', listener: (event: Event, /** - * The error code. + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - once(event: 'certificate-error', listener: (event: Event, - url: string, - /** - * The error code. - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - addListener(event: 'certificate-error', listener: (event: Event, - url: string, - /** - * The error code. - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - removeListener(event: 'certificate-error', listener: (event: Event, - url: string, - /** - * The error code. - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void, - isMainFrame: boolean) => void): this; - /** - * Emitted when the associated window logs a console message. - */ - on(event: 'console-message', listener: (event: Event, - /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. - */ - level: number, - /** - * The actual console message - */ - message: string, - /** - * The line number of the source that triggered this console message - */ - line: number, - sourceId: string) => void): this; - once(event: 'console-message', listener: (event: Event, + type: string, /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. + * Contains app-specific state stored by the activity. */ - level: number, + userInfo: unknown) => void): this; + once(event: 'update-activity-state', listener: (event: Event, /** - * The actual console message + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - message: string, + type: string, /** - * The line number of the source that triggered this console message + * Contains app-specific state stored by the activity. */ - line: number, - sourceId: string) => void): this; - addListener(event: 'console-message', listener: (event: Event, - /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. - */ - level: number, - /** - * The actual console message - */ - message: string, - /** - * The line number of the source that triggered this console message - */ - line: number, - sourceId: string) => void): this; - removeListener(event: 'console-message', listener: (event: Event, - /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. - */ - level: number, - /** - * The actual console message - */ - message: string, - /** - * The line number of the source that triggered this console message - */ - line: number, - sourceId: string) => void): this; - /** - * Emitted when there is a new context menu that needs to be handled. - */ - on(event: 'context-menu', listener: (event: Event, - params: ContextMenuParams) => void): this; - once(event: 'context-menu', listener: (event: Event, - params: ContextMenuParams) => void): this; - addListener(event: 'context-menu', listener: (event: Event, - params: ContextMenuParams) => void): this; - removeListener(event: 'context-menu', listener: (event: Event, - params: ContextMenuParams) => void): this; - /** - * Emitted when the renderer process crashes or is killed. - * - * **Deprecated:** This event is superceded by the `render-process-gone` event - * which contains more information about why the render process disappeared. It - * isn't always because it crashed. The `killed` boolean can be replaced by - * checking `reason === 'killed'` when you switch to that event. - * - * @deprecated - */ - on(event: 'crashed', listener: (event: Event, - killed: boolean) => void): this; - once(event: 'crashed', listener: (event: Event, - killed: boolean) => void): this; - addListener(event: 'crashed', listener: (event: Event, - killed: boolean) => void): this; - removeListener(event: 'crashed', listener: (event: Event, - killed: boolean) => void): this; - /** - * Emitted when the cursor's type changes. The `type` parameter can be `default`, - * `crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, - * `ne-resize`, `nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`, - * `ns-resize`, `ew-resize`, `nesw-resize`, `nwse-resize`, `col-resize`, - * `row-resize`, `m-panning`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, - * `s-panning`, `se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, - * `cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`, - * `not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing` or `custom`. - * - * If the `type` parameter is `custom`, the `image` parameter will hold the custom - * cursor image in a `NativeImage`, and `scale`, `size` and `hotspot` will hold - * additional information about the custom cursor. - */ - on(event: 'cursor-changed', listener: (event: Event, - type: string, - image: NativeImage, - /** - * scaling factor for the custom cursor. - */ - scale: number, - /** - * the size of the `image`. - */ - size: Size, - /** - * coordinates of the custom cursor's hotspot. - */ - hotspot: Point) => void): this; - once(event: 'cursor-changed', listener: (event: Event, - type: string, - image: NativeImage, - /** - * scaling factor for the custom cursor. - */ - scale: number, - /** - * the size of the `image`. - */ - size: Size, - /** - * coordinates of the custom cursor's hotspot. - */ - hotspot: Point) => void): this; - addListener(event: 'cursor-changed', listener: (event: Event, - type: string, - image: NativeImage, - /** - * scaling factor for the custom cursor. - */ - scale: number, - /** - * the size of the `image`. - */ - size: Size, - /** - * coordinates of the custom cursor's hotspot. - */ - hotspot: Point) => void): this; - removeListener(event: 'cursor-changed', listener: (event: Event, - type: string, - image: NativeImage, - /** - * scaling factor for the custom cursor. - */ - scale: number, - /** - * the size of the `image`. - */ - size: Size, - /** - * coordinates of the custom cursor's hotspot. - */ - hotspot: Point) => void): this; - /** - * Emitted when `webContents` is destroyed. - */ - on(event: 'destroyed', listener: Function): this; - once(event: 'destroyed', listener: Function): this; - addListener(event: 'destroyed', listener: Function): this; - removeListener(event: 'destroyed', listener: Function): this; - /** - * Emitted when DevTools is closed. - */ - on(event: 'devtools-closed', listener: Function): this; - once(event: 'devtools-closed', listener: Function): this; - addListener(event: 'devtools-closed', listener: Function): this; - removeListener(event: 'devtools-closed', listener: Function): this; - /** - * Emitted when DevTools is focused / opened. - */ - on(event: 'devtools-focused', listener: Function): this; - once(event: 'devtools-focused', listener: Function): this; - addListener(event: 'devtools-focused', listener: Function): this; - removeListener(event: 'devtools-focused', listener: Function): this; - /** - * Emitted when DevTools is opened. - */ - on(event: 'devtools-opened', listener: Function): this; - once(event: 'devtools-opened', listener: Function): this; - addListener(event: 'devtools-opened', listener: Function): this; - removeListener(event: 'devtools-opened', listener: Function): this; - /** - * Emitted when the devtools window instructs the webContents to reload - */ - on(event: 'devtools-reload-page', listener: Function): this; - once(event: 'devtools-reload-page', listener: Function): this; - addListener(event: 'devtools-reload-page', listener: Function): this; - removeListener(event: 'devtools-reload-page', listener: Function): this; - /** - * Emitted when a `<webview>` has been attached to this web contents. - */ - on(event: 'did-attach-webview', listener: (event: Event, + userInfo: unknown) => void): this; + addListener(event: 'update-activity-state', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity. + */ + userInfo: unknown) => void): this; + removeListener(event: 'update-activity-state', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string, + /** + * Contains app-specific state stored by the activity. + */ + userInfo: unknown) => void): this; + /** + * Emitted when a new webContents is created. + */ + on(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; + once(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; + addListener(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; + removeListener(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; + /** + * Emitted during Handoff before an activity from a different device wants to be + * resumed. You should call `event.preventDefault()` if you want to handle this + * event. + * + * @platform darwin + */ + on(event: 'will-continue-activity', listener: (event: Event, /** - * The guest web contents that is used by the `<webview>`. + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - webContents: WebContents) => void): this; - once(event: 'did-attach-webview', listener: (event: Event, - /** - * The guest web contents that is used by the `<webview>`. - */ - webContents: WebContents) => void): this; - addListener(event: 'did-attach-webview', listener: (event: Event, - /** - * The guest web contents that is used by the `<webview>`. - */ - webContents: WebContents) => void): this; - removeListener(event: 'did-attach-webview', listener: (event: Event, - /** - * The guest web contents that is used by the `<webview>`. - */ - webContents: WebContents) => void): this; - /** - * Emitted when a page's theme color changes. This is usually due to encountering a - * meta tag: - */ - on(event: 'did-change-theme-color', listener: (event: Event, - /** - * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. - */ - color: (string) | (null)) => void): this; - once(event: 'did-change-theme-color', listener: (event: Event, - /** - * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. - */ - color: (string) | (null)) => void): this; - addListener(event: 'did-change-theme-color', listener: (event: Event, - /** - * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. - */ - color: (string) | (null)) => void): this; - removeListener(event: 'did-change-theme-color', listener: (event: Event, - /** - * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. - */ - color: (string) | (null)) => void): this; - /** - * Emitted _after_ successful creation of a window via `window.open` in the - * renderer. Not emitted if the creation of the window is canceled from - * `webContents.setWindowOpenHandler`. - * - * See `window.open()` for more details and how to use this in conjunction with - * `webContents.setWindowOpenHandler`. - */ - on(event: 'did-create-window', listener: (window: BrowserWindow, - details: DidCreateWindowDetails) => void): this; - once(event: 'did-create-window', listener: (window: BrowserWindow, - details: DidCreateWindowDetails) => void): this; - addListener(event: 'did-create-window', listener: (window: BrowserWindow, - details: DidCreateWindowDetails) => void): this; - removeListener(event: 'did-create-window', listener: (window: BrowserWindow, - details: DidCreateWindowDetails) => void): this; - /** - * This event is like `did-finish-load` but emitted when the load failed. The full - * list of error codes and their meaning is available here. - */ - on(event: 'did-fail-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-fail-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-fail-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-fail-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * This event is like `did-fail-load` but emitted when the load was cancelled (e.g. - * `window.stop()` was invoked). - */ - on(event: 'did-fail-provisional-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-fail-provisional-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-fail-provisional-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-fail-provisional-load', listener: (event: Event, - errorCode: number, - errorDescription: string, - validatedURL: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Emitted when the navigation is done, i.e. the spinner of the tab has stopped - * spinning, and the `onload` event was dispatched. - */ - on(event: 'did-finish-load', listener: Function): this; - once(event: 'did-finish-load', listener: Function): this; - addListener(event: 'did-finish-load', listener: Function): this; - removeListener(event: 'did-finish-load', listener: Function): this; - /** - * Emitted when a frame has done navigation. - */ - on(event: 'did-frame-finish-load', listener: (event: Event, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-frame-finish-load', listener: (event: Event, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-frame-finish-load', listener: (event: Event, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-frame-finish-load', listener: (event: Event, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Emitted when any frame navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the `window.location.hash`. Use `did-navigate-in-page` event for - * this purpose. - */ - on(event: 'did-frame-navigate', listener: (event: Event, - url: string, + type: string) => void): this; + once(event: 'will-continue-activity', listener: (event: Event, /** - * -1 for non HTTP navigations + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - httpResponseCode: number, + type: string) => void): this; + addListener(event: 'will-continue-activity', listener: (event: Event, /** - * empty for non HTTP navigations, + * A string identifying the activity. Maps to `NSUserActivity.activityType`. */ - httpStatusText: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-frame-navigate', listener: (event: Event, - url: string, - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number, - /** - * empty for non HTTP navigations, - */ - httpStatusText: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-frame-navigate', listener: (event: Event, - url: string, - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number, - /** - * empty for non HTTP navigations, - */ - httpStatusText: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-frame-navigate', listener: (event: Event, - url: string, - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number, - /** - * empty for non HTTP navigations, - */ - httpStatusText: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Emitted when a main frame navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the `window.location.hash`. Use `did-navigate-in-page` event for - * this purpose. - */ - on(event: 'did-navigate', listener: (event: Event, - url: string, - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number, - /** - * empty for non HTTP navigations - */ - httpStatusText: string) => void): this; - once(event: 'did-navigate', listener: (event: Event, - url: string, - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number, - /** - * empty for non HTTP navigations - */ - httpStatusText: string) => void): this; - addListener(event: 'did-navigate', listener: (event: Event, - url: string, - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number, - /** - * empty for non HTTP navigations - */ - httpStatusText: string) => void): this; - removeListener(event: 'did-navigate', listener: (event: Event, - url: string, - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number, - /** - * empty for non HTTP navigations - */ - httpStatusText: string) => void): this; - /** - * Emitted when an in-page navigation happened in any frame. - * - * When in-page navigation happens, the page URL changes but does not cause - * navigation outside of the page. Examples of this occurring are when anchor links - * are clicked or when the DOM `hashchange` event is triggered. - */ - on(event: 'did-navigate-in-page', listener: (event: Event, - url: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-navigate-in-page', listener: (event: Event, - url: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-navigate-in-page', listener: (event: Event, - url: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-navigate-in-page', listener: (event: Event, - url: string, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Emitted after a server side redirect occurs during navigation. For example a - * 302 redirect. - * - * This event cannot be prevented, if you want to prevent redirects you should - * checkout out the `will-redirect` event above. - */ - on(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab started spinning. - */ - on(event: 'did-start-loading', listener: Function): this; - once(event: 'did-start-loading', listener: Function): this; - addListener(event: 'did-start-loading', listener: Function): this; - removeListener(event: 'did-start-loading', listener: Function): this; - /** - * Emitted when any frame (including main) starts navigating. `isInPlace` will be - * `true` for in-page navigations. - */ - on(event: 'did-start-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-start-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-start-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-start-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab stopped spinning. - */ - on(event: 'did-stop-loading', listener: Function): this; - once(event: 'did-stop-loading', listener: Function): this; - addListener(event: 'did-stop-loading', listener: Function): this; - removeListener(event: 'did-stop-loading', listener: Function): this; - /** - * Emitted when the document in the top-level frame is loaded. - */ - on(event: 'dom-ready', listener: (event: Event) => void): this; - once(event: 'dom-ready', listener: (event: Event) => void): this; - addListener(event: 'dom-ready', listener: (event: Event) => void): this; - removeListener(event: 'dom-ready', listener: (event: Event) => void): this; - /** - * Emitted when the window enters a full-screen state triggered by HTML API. - */ - on(event: 'enter-html-full-screen', listener: Function): this; - once(event: 'enter-html-full-screen', listener: Function): this; - addListener(event: 'enter-html-full-screen', listener: Function): this; - removeListener(event: 'enter-html-full-screen', listener: Function): this; - /** - * Emitted when the `WebContents` gains focus. - * - * Note that on macOS, having focus means the `WebContents` is the first responder - * of window, so switching focus between windows would not trigger the `focus` and - * `blur` events of `WebContents`, as the first responder of each window is not - * changed. - * - * The `focus` and `blur` events of `WebContents` should only be used to detect - * focus change between different `WebContents` and `BrowserView` in the same - * window. - */ - on(event: 'focus', listener: Function): this; - once(event: 'focus', listener: Function): this; - addListener(event: 'focus', listener: Function): this; - removeListener(event: 'focus', listener: Function): this; - /** - * Emitted when a result is available for [`webContents.findInPage`] request. - */ - on(event: 'found-in-page', listener: (event: Event, - result: Result) => void): this; - once(event: 'found-in-page', listener: (event: Event, - result: Result) => void): this; - addListener(event: 'found-in-page', listener: (event: Event, - result: Result) => void): this; - removeListener(event: 'found-in-page', listener: (event: Event, - result: Result) => void): this; - /** - * Emitted when the mainFrame, an `<iframe>`, or a nested `<iframe>` is loaded - * within the page. - */ - on(event: 'frame-created', listener: (event: Event, - details: FrameCreatedDetails) => void): this; - once(event: 'frame-created', listener: (event: Event, - details: FrameCreatedDetails) => void): this; - addListener(event: 'frame-created', listener: (event: Event, - details: FrameCreatedDetails) => void): this; - removeListener(event: 'frame-created', listener: (event: Event, - details: FrameCreatedDetails) => void): this; - /** - * Emitted when the renderer process sends an asynchronous message via - * `ipcRenderer.send()`. - */ - on(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - once(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - addListener(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - removeListener(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - /** - * Emitted when the renderer process sends a synchronous message via - * `ipcRenderer.sendSync()`. - */ - on(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - once(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - addListener(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - removeListener(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - /** - * Emitted when the window leaves a full-screen state triggered by HTML API. - */ - on(event: 'leave-html-full-screen', listener: Function): this; - once(event: 'leave-html-full-screen', listener: Function): this; - addListener(event: 'leave-html-full-screen', listener: Function): this; - removeListener(event: 'leave-html-full-screen', listener: Function): this; - /** - * Emitted when `webContents` wants to do basic auth. - * - * The usage is the same with the `login` event of `app`. - */ - on(event: 'login', listener: (event: Event, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - once(event: 'login', listener: (event: Event, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - addListener(event: 'login', listener: (event: Event, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - removeListener(event: 'login', listener: (event: Event, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - /** - * Emitted when media is paused or done playing. - */ - on(event: 'media-paused', listener: Function): this; - once(event: 'media-paused', listener: Function): this; - addListener(event: 'media-paused', listener: Function): this; - removeListener(event: 'media-paused', listener: Function): this; - /** - * Emitted when media starts playing. - */ - on(event: 'media-started-playing', listener: Function): this; - once(event: 'media-started-playing', listener: Function): this; - addListener(event: 'media-started-playing', listener: Function): this; - removeListener(event: 'media-started-playing', listener: Function): this; - /** - * Deprecated in favor of `webContents.setWindowOpenHandler`. - * - * Emitted when the page requests to open a new window for a `url`. It could be - * requested by `window.open` or an external link like `<a target='_blank'>`. - * - * By default a new `BrowserWindow` will be created for the `url`. - * - * Calling `event.preventDefault()` will prevent Electron from automatically - * creating a new `BrowserWindow`. If you call `event.preventDefault()` and - * manually create a new `BrowserWindow` then you must set `event.newGuest` to - * reference the new `BrowserWindow` instance, failing to do so may result in - * unexpected behavior. For example: - * - * @deprecated - */ - on(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. Deprecated, and will now always be the empty array `[]`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - once(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. Deprecated, and will now always be the empty array `[]`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - addListener(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. Deprecated, and will now always be the empty array `[]`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - removeListener(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. Deprecated, and will now always be the empty array `[]`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - /** - * Emitted when page receives favicon urls. - */ - on(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - once(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - addListener(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - removeListener(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - /** - * Fired when page title is set during navigation. `explicitSet` is false when - * title is synthesized from file url. - */ - on(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - once(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - addListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - removeListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - /** - * Emitted when a new frame is generated. Only the dirty area is passed in the - * buffer. - */ - on(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - once(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - addListener(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - removeListener(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - /** - * Emitted when a plugin process has crashed. - */ - on(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - once(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - addListener(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - removeListener(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - /** - * Emitted when the `WebContents` preferred size has changed. - * - * This event will only be emitted when `enablePreferredSizeMode` is set to `true` - * in `webPreferences`. - */ - on(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the documentβ€”without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - once(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the documentβ€”without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - addListener(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the documentβ€”without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - removeListener(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the documentβ€”without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - /** - * Emitted when the preload script `preloadPath` throws an unhandled exception - * `error`. - */ - on(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - once(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - addListener(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - removeListener(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - /** - * Emitted when the renderer process unexpectedly disappears. This is normally - * because it was crashed or killed. - */ - on(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - once(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - addListener(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - removeListener(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - /** - * Emitted when the unresponsive web page becomes responsive again. - */ - on(event: 'responsive', listener: Function): this; - once(event: 'responsive', listener: Function): this; - addListener(event: 'responsive', listener: Function): this; - removeListener(event: 'responsive', listener: Function): this; - /** - * Emitted when bluetooth device needs to be selected on call to - * `navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api - * `webBluetooth` should be enabled. If `event.preventDefault` is not called, first - * available device will be selected. `callback` should be called with `deviceId` - * to be selected, passing empty string to `callback` will cancel the request. - * - * If no event listener is added for this event, all bluetooth requests will be - * cancelled. - */ - on(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - once(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - addListener(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - removeListener(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - /** - * Emitted when a client certificate is requested. - * - * The usage is the same with the `select-client-certificate` event of `app`. - */ - on(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - once(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - addListener(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - removeListener(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - /** - * Emitted when the web page becomes unresponsive. - */ - on(event: 'unresponsive', listener: Function): this; - once(event: 'unresponsive', listener: Function): this; - addListener(event: 'unresponsive', listener: Function): this; - removeListener(event: 'unresponsive', listener: Function): this; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - on(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - once(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - addListener(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - removeListener(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - /** - * Emitted when a `<webview>`'s web contents is being attached to this web - * contents. Calling `event.preventDefault()` will destroy the guest page. - * - * This event can be used to configure `webPreferences` for the `webContents` of a - * `<webview>` before it's loaded, and provides the ability to set settings that - * can't be set via `<webview>` attributes. - * - * **Note:** The specified `preload` script option will appear as `preloadURL` (not - * `preload`) in the `webPreferences` object emitted with this event. - */ - on(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `<webview>` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record<string, string>) => void): this; - once(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `<webview>` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record<string, string>) => void): this; - addListener(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `<webview>` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record<string, string>) => void): this; - removeListener(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `<webview>` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record<string, string>) => void): this; - /** - * Emitted when a user or the page wants to start navigation. It can happen when - * the `window.location` object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with - * APIs like `webContents.loadURL` and `webContents.back`. - * - * It is also not emitted for in-page navigations, such as clicking anchor links or - * updating the `window.location.hash`. Use `did-navigate-in-page` event for this - * purpose. - * - * Calling `event.preventDefault()` will prevent the navigation. - */ - on(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - once(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - addListener(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - removeListener(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - /** - * Emitted when a `beforeunload` event handler is attempting to cancel a page - * unload. - * - * Calling `event.preventDefault()` will ignore the `beforeunload` event handler - * and allow the page to be unloaded. - * - * **Note:** This will be emitted for `BrowserViews` but will _not_ be respected - - * this is because we have chosen not to tie the `BrowserView` lifecycle to its - * owning BrowserWindow should one exist per the specification. - */ - on(event: 'will-prevent-unload', listener: (event: Event) => void): this; - once(event: 'will-prevent-unload', listener: (event: Event) => void): this; - addListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; - removeListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; - /** - * Emitted when a server side redirect occurs during navigation. For example a 302 - * redirect. - * - * This event will be emitted after `did-start-navigation` and always before the - * `did-redirect-navigation` event for the same navigation. - * - * Calling `event.preventDefault()` will prevent the navigation (not just the - * redirect). - */ - on(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Emitted when the user is requesting to change the zoom level using the mouse - * wheel. - */ - on(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - once(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - addListener(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - removeListener(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - /** - * Adds the specified path to DevTools workspace. Must be used after DevTools - * creation: - */ - addWorkSpace(path: string): void; - /** - * Begin subscribing for presentation events and captured frames, the `callback` - * will be called with `callback(image, dirtyRect)` when there is a presentation - * event. - * - * The `image` is an instance of NativeImage that stores the captured frame. - * - * The `dirtyRect` is an object with `x, y, width, height` properties that - * describes which part of the page was repainted. If `onlyDirty` is set to `true`, - * `image` will only contain the repainted area. `onlyDirty` defaults to `false`. - */ - beginFrameSubscription(onlyDirty: boolean, callback: (image: NativeImage, dirtyRect: Rectangle) => void): void; - /** - * Begin subscribing for presentation events and captured frames, the `callback` - * will be called with `callback(image, dirtyRect)` when there is a presentation - * event. - * - * The `image` is an instance of NativeImage that stores the captured frame. - * - * The `dirtyRect` is an object with `x, y, width, height` properties that - * describes which part of the page was repainted. If `onlyDirty` is set to `true`, - * `image` will only contain the repainted area. `onlyDirty` defaults to `false`. - */ - beginFrameSubscription(callback: (image: NativeImage, dirtyRect: Rectangle) => void): void; - /** - * Whether the browser can go back to previous web page. - */ - canGoBack(): boolean; - /** - * Whether the browser can go forward to next web page. - */ - canGoForward(): boolean; - /** - * Whether the web page can go to `offset`. - */ - canGoToOffset(offset: number): boolean; - /** - * Resolves with a NativeImage - * - * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the - * whole visible page. - */ - capturePage(rect?: Rectangle): Promise<Electron.NativeImage>; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Closes the devtools. - */ - closeDevTools(): void; - /** - * Executes the editing command `copy` in web page. - */ - copy(): void; - /** - * Copy the image at the given position to the clipboard. - */ - copyImageAt(x: number, y: number): void; - /** - * Executes the editing command `cut` in web page. - */ - cut(): void; - /** - * Decrease the capturer count by one. The page will be set to hidden or occluded - * state when its browser window is hidden or occluded and the capturer count - * reaches zero. If you want to decrease the hidden capturer count instead you - * should set `stayHidden` to true. - */ - decrementCapturerCount(stayHidden?: boolean, stayAwake?: boolean): void; - /** - * Executes the editing command `delete` in web page. - */ - delete(): void; - /** - * Disable device emulation enabled by `webContents.enableDeviceEmulation`. - */ - disableDeviceEmulation(): void; - /** - * Initiates a download of the resource at `url` without navigating. The - * `will-download` event of `session` will be triggered. - */ - downloadURL(url: string): void; - /** - * Enable device emulation with the given parameters. - */ - enableDeviceEmulation(parameters: Parameters): void; - /** - * End subscribing for frame presentation events. - */ - endFrameSubscription(): void; - /** - * A promise that resolves with the result of the executed code or is rejected if - * the result of the code is a rejected promise. - * - * Evaluates `code` in page. - * - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - * - * Code execution will be suspended until web page stop loading. - */ - executeJavaScript(code: string, userGesture?: boolean): Promise<any>; - /** - * A promise that resolves with the result of the executed code or is rejected if - * the result of the code is a rejected promise. - * - * Works like `executeJavaScript` but evaluates `scripts` in an isolated context. - */ - executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean): Promise<any>; - /** - * The request id used for the request. - * - * Starts a request to find all matches for the `text` in the web page. The result - * of the request can be obtained by subscribing to `found-in-page` event. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * Focuses the web page. - */ - focus(): void; - /** - * Forcefully terminates the renderer process that is currently hosting this - * `webContents`. This will cause the `render-process-gone` event to be emitted - * with the `reason=killed || reason=crashed`. Please note that some webContents - * share renderer processes and therefore calling this method may also crash the - * host process for other webContents as well. - * - * Calling `reload()` immediately after calling this method will force the reload - * to occur in a new process. This should be used when this process is unstable or - * unusable, for instance in order to recover from the `unresponsive` event. - */ - forcefullyCrashRenderer(): void; - /** - * Information about all Shared Workers. - */ - getAllSharedWorkers(): SharedWorkerInfo[]; - /** - * whether or not this WebContents will throttle animations and timers when the - * page becomes backgrounded. This also affects the Page Visibility API. - */ - getBackgroundThrottling(): boolean; - /** - * If *offscreen rendering* is enabled returns the current frame rate. - */ - getFrameRate(): number; - /** - * The identifier of a WebContents stream. This identifier can be used with - * `navigator.mediaDevices.getUserMedia` using a `chromeMediaSource` of `tab`. The - * identifier is restricted to the web contents that it is registered to and is - * only valid for 10 seconds. - */ - getMediaSourceId(requestWebContents: WebContents): string; - /** - * The operating system `pid` of the associated renderer process. - */ - getOSProcessId(): number; - /** - * Get the system printer list. - * - * - * **Deprecated:** Should use the new `contents.getPrintersAsync` API. - * - * @deprecated - */ - getPrinters(): PrinterInfo[]; - /** - * Get the system printer list. - * - * Resolves with a `PrinterInfo[]` - */ - getPrintersAsync(): Promise<Electron.PrinterInfo[]>; - /** - * The Chromium internal `pid` of the associated renderer. Can be compared to the - * `frameProcessId` passed by frame specific navigation events (e.g. - * `did-frame-navigate`) - */ - getProcessId(): number; - /** - * The title of the current web page. - */ - getTitle(): string; - /** - * the type of the webContent. Can be `backgroundPage`, `window`, `browserView`, - * `remote`, `webview` or `offscreen`. - */ - getType(): ('backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'); - /** - * The URL of the current web page. - */ - getURL(): string; - /** - * The user agent for this web page. - */ - getUserAgent(): string; - /** - * Returns the WebRTC IP Handling Policy. - */ - getWebRTCIPHandlingPolicy(): string; - /** - * the current zoom factor. - */ - getZoomFactor(): number; - /** - * the current zoom level. - */ - getZoomLevel(): number; - /** - * Makes the browser go back a web page. - */ - goBack(): void; - /** - * Makes the browser go forward a web page. - */ - goForward(): void; - /** - * Navigates browser to the specified absolute web page index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * Increase the capturer count by one. The page is considered visible when its - * browser window is hidden and the capturer count is non-zero. If you would like - * the page to stay hidden, you should ensure that `stayHidden` is set to true. - * - * This also affects the Page Visibility API. - */ - incrementCapturerCount(size?: Size, stayHidden?: boolean, stayAwake?: boolean): void; - /** - * A promise that resolves with a key for the inserted CSS that can later be used - * to remove the CSS via `contents.removeInsertedCSS(key)`. - * - * Injects CSS into the current web page and returns a unique key for the inserted - * stylesheet. - */ - insertCSS(css: string, options?: InsertCSSOptions): Promise<string>; - /** - * Inserts `text` to the focused element. - */ - insertText(text: string): Promise<void>; - /** - * Starts inspecting element at position (`x`, `y`). - */ - inspectElement(x: number, y: number): void; - /** - * Opens the developer tools for the service worker context. - */ - inspectServiceWorker(): void; - /** - * Opens the developer tools for the shared worker context. - */ - inspectSharedWorker(): void; - /** - * Inspects the shared worker based on its ID. - */ - inspectSharedWorkerById(workerId: string): void; - /** - * Schedules a full repaint of the window this web contents is in. - * - * If *offscreen rendering* is enabled invalidates the frame and generates a new - * one through the `'paint'` event. - */ - invalidate(): void; - /** - * Whether this page has been muted. - */ - isAudioMuted(): boolean; - /** - * Whether this page is being captured. It returns true when the capturer count is - * large then 0. - */ - isBeingCaptured(): boolean; - /** - * Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Whether audio is currently playing. - */ - isCurrentlyAudible(): boolean; - /** - * Whether the web page is destroyed. - */ - isDestroyed(): boolean; - /** - * Whether the devtools view is focused . - */ - isDevToolsFocused(): boolean; - /** - * Whether the devtools is opened. - */ - isDevToolsOpened(): boolean; - /** - * Whether the web page is focused. - */ - isFocused(): boolean; - /** - * Whether web page is still loading resources. - */ - isLoading(): boolean; - /** - * Whether the main frame (and not just iframes or frames within it) is still - * loading. - */ - isLoadingMainFrame(): boolean; - /** - * Indicates whether *offscreen rendering* is enabled. - */ - isOffscreen(): boolean; - /** - * If *offscreen rendering* is enabled returns whether it is currently painting. - */ - isPainting(): boolean; - /** - * Whether the web page is waiting for a first-response from the main resource of - * the page. - */ - isWaitingForResponse(): boolean; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Loads the given file in the window, `filePath` should be a path to an HTML file - * relative to the root of your application. For instance an app structure like - * this: - * - * Would require code like this - */ - loadFile(filePath: string, options?: LoadFileOptions): Promise<void>; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * A noop rejection handler is already attached, which avoids unhandled rejection - * errors. - * - * Loads the `url` in the window. The `url` must contain the protocol prefix, e.g. - * the `http://` or `file://`. If the load should bypass http cache then use the - * `pragma` header to achieve it. - */ - loadURL(url: string, options?: LoadURLOptions): Promise<void>; - /** - * Opens the devtools. - * - * When `contents` is a `<webview>` tag, the `mode` would be `detach` by default, - * explicitly passing an empty `mode` can force using last used dock state. - */ - openDevTools(options?: OpenDevToolsOptions): void; - /** - * Executes the editing command `paste` in web page. - */ - paste(): void; - /** - * Executes the editing command `pasteAndMatchStyle` in web page. - */ - pasteAndMatchStyle(): void; - /** - * Send a message to the renderer process, optionally transferring ownership of - * zero or more [`MessagePortMain`][] objects. - * - * The transferred `MessagePortMain` objects will be available in the renderer - * process by accessing the `ports` property of the emitted event. When they arrive - * in the renderer, they will be native DOM `MessagePort` objects. - * - * For example: - */ - postMessage(channel: string, message: any, transfer?: MessagePortMain[]): void; - /** - * When a custom `pageSize` is passed, Chromium attempts to validate platform - * specific minimum values for `width_microns` and `height_microns`. Width and - * height must both be minimum 353 microns but may be higher on some operating - * systems. - * - * Prints window's web page. When `silent` is set to `true`, Electron will pick the - * system's default printer if `deviceName` is empty and the default settings for - * printing. - * - * Use `page-break-before: always;` CSS style to force to print to a new page. - * - * Example usage: - */ - print(options?: WebContentsPrintOptions, callback?: (success: boolean, failureReason: string) => void): void; - /** - * Resolves with the generated PDF data. - * - * 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: - * - * Use `page-break-before: always;` CSS style to force to print to a new page. - * - * An example of `webContents.printToPDF`: - */ - printToPDF(options: PrintToPDFOptions): Promise<Buffer>; - /** - * Executes the editing command `redo` in web page. - */ - redo(): void; - /** - * Reloads the current web page. - */ - reload(): void; - /** - * Reloads current page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * Resolves if the removal was successful. - * - * Removes the inserted CSS from the current web page. The stylesheet is identified - * by its key, which is returned from `contents.insertCSS(css)`. - */ - removeInsertedCSS(key: string): Promise<void>; - /** - * Removes the specified path from DevTools workspace. - */ - removeWorkSpace(path: string): void; - /** - * Executes the editing command `replace` in web page. - */ - replace(text: string): void; - /** - * Executes the editing command `replaceMisspelling` in web page. - */ - replaceMisspelling(text: string): void; - /** - * resolves if the page is saved. - */ - savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML'): Promise<void>; - /** - * Executes the editing command `selectAll` in web page. - */ - selectAll(): void; - /** - * Send an asynchronous message to the renderer process via `channel`, along with - * arguments. Arguments will be serialized with the Structured Clone Algorithm, - * just like `postMessage`, so prototype chains will not be included. Sending - * Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. - * - * > **NOTE**: Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * The renderer process can handle the message by listening to `channel` with the - * `ipcRenderer` module. - * - * An example of sending messages from the main process to the renderer process: - */ - send(channel: string, ...args: any[]): void; - /** - * Sends an input `event` to the page. **Note:** The `BrowserWindow` containing the - * contents needs to be focused for `sendInputEvent()` to work. - */ - sendInputEvent(inputEvent: (MouseInputEvent) | (MouseWheelInputEvent) | (KeyboardInputEvent)): void; - /** - * Send an asynchronous message to a specific frame in a renderer process via - * `channel`, along with arguments. Arguments will be serialized with the - * Structured Clone Algorithm, just like `postMessage`, so prototype chains will - * not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets - * will throw an exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * The renderer process can handle the message by listening to `channel` with the - * `ipcRenderer` module. - * - * If you want to get the `frameId` of a given renderer context you should use the - * `webFrame.routingId` value. E.g. - * - * You can also read `frameId` from all incoming IPC messages in the main process. - */ - sendToFrame(frameId: (number) | ([number, number]), channel: string, ...args: any[]): void; - /** - * Mute the audio on the current web page. - */ - setAudioMuted(muted: boolean): void; - /** - * Controls whether or not this WebContents will throttle animations and timers - * when the page becomes backgrounded. This also affects the Page Visibility API. - */ - setBackgroundThrottling(allowed: boolean): void; - /** - * Uses the `devToolsWebContents` as the target `WebContents` to show devtools. - * - * The `devToolsWebContents` must not have done any navigation, and it should not - * be used for other purposes after the call. - * - * By default Electron manages the devtools by creating an internal `WebContents` - * with native view, which developers have very limited control of. With the - * `setDevToolsWebContents` method, developers can use any `WebContents` to show - * the devtools in it, including `BrowserWindow`, `BrowserView` and `<webview>` - * tag. - * - * Note that closing the devtools does not destroy the `devToolsWebContents`, it is - * caller's responsibility to destroy `devToolsWebContents`. - * - * An example of showing devtools in a `<webview>` tag: - * - * An example of showing devtools in a `BrowserWindow`: - */ - setDevToolsWebContents(devToolsWebContents: WebContents): void; - /** - * If *offscreen rendering* is enabled sets the frame rate to the specified number. - * Only values between 1 and 240 are accepted. - */ - setFrameRate(fps: number): void; - /** - * Ignore application menu shortcuts while this web contents is focused. - */ - setIgnoreMenuShortcuts(ignore: boolean): void; - /** - * Sets the image animation policy for this webContents. The policy only affects - * _new_ images, existing images that are currently being animated are unaffected. - * This is a known limitation in Chromium, you can force image animation to be - * recalculated with `img.src = img.src` which will result in no network traffic - * but will update the animation policy. - * - * This corresponds to the animationPolicy accessibility feature in Chromium. - */ - setImageAnimationPolicy(policy: 'animate' | 'animateOnce' | 'noAnimation'): void; - /** - * Overrides the user agent for this web page. - */ - setUserAgent(userAgent: string): void; - /** - * Sets the maximum and minimum pinch-to-zoom level. - * - * > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, - * call: - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): Promise<void>; - /** - * Setting the WebRTC IP handling policy allows you to control which IPs are - * exposed via WebRTC. See BrowserLeaks for more details. - */ - setWebRTCIPHandlingPolicy(policy: 'default' | 'default_public_interface_only' | 'default_public_and_private_interfaces' | 'disable_non_proxied_udp'): void; - /** - * Called before creating a window a new window is requested by the renderer, e.g. - * by `window.open()`, a link with `target="_blank"`, shift+clicking on a link, or - * submitting a form with `<form target="_blank">`. See `window.open()` for more - * details and how to use this in conjunction with `did-create-window`. - */ - setWindowOpenHandler(handler: (details: HandlerDetails) => ({action: 'deny'}) | ({action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions})): void; - /** - * Changes the zoom factor to the specified factor. Zoom factor is zoom percent - * divided by 100, so 300% = 3.0. - * - * The factor must be greater than 0.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. The original size is 0 and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. The formula for this is - * `scale := 1.2 ^ level`. - * - * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that - * the zoom level for a specific domain propagates across all instances of windows - * with the same domain. Differentiating the window URLs will make zoom work - * per-window. - */ - setZoomLevel(level: number): void; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * - * @platform darwin - */ - showDefinitionForSelection(): void; - /** - * Sets the `item` as dragging item for current drag-drop operation, `file` is the - * absolute path of the file to be dragged, and `icon` is the image showing under - * the cursor when dragging. - */ - startDrag(item: Item): void; - /** - * If *offscreen rendering* is enabled and not painting, start painting. - */ - startPainting(): void; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Stops any `findInPage` request for the `webContents` with the provided `action`. - */ - stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; - /** - * If *offscreen rendering* is enabled and painting, stop painting. - */ - stopPainting(): void; - /** - * Indicates whether the snapshot has been created successfully. - * - * Takes a V8 heap snapshot and saves it to `filePath`. - */ - takeHeapSnapshot(filePath: string): Promise<void>; - /** - * Toggles the developer tools. - */ - toggleDevTools(): void; - /** - * Executes the editing command `undo` in web page. - */ - undo(): void; - /** - * Executes the editing command `unselect` in web page. - */ - unselect(): void; - /** - * A `boolean` property that determines whether this page is muted. - */ - audioMuted: boolean; - /** - * A `boolean` property that determines whether or not this WebContents will - * throttle animations and timers when the page becomes backgrounded. This also - * affects the Page Visibility API. - */ - backgroundThrottling: boolean; - /** - * A `Debugger` instance for this webContents. - * - */ - readonly debugger: Debugger; - /** - * A `WebContents | null` property that represents the of DevTools `WebContents` - * associated with a given `WebContents`. - * - * **Note:** Users should never store this object because it may become `null` when - * the DevTools has been closed. - * - */ - readonly devToolsWebContents: (WebContents) | (null); - /** - * An `Integer` property that sets the frame rate of the web contents to the - * specified number. Only values between 1 and 240 are accepted. - * - * Only applicable if *offscreen rendering* is enabled. - */ - frameRate: number; - /** - * A `WebContents` instance that might own this `WebContents`. - * - */ - readonly hostWebContents: WebContents; - /** - * A `Integer` representing the unique ID of this WebContents. Each ID is unique - * among all `WebContents` instances of the entire Electron application. - * - */ - readonly id: number; - /** - * A `WebFrameMain` property that represents the top frame of the page's frame - * hierarchy. - * - */ - readonly mainFrame: WebFrameMain; - /** - * A `Session` used by this webContents. - * - */ - readonly session: Session; - /** - * A `string` property that determines the user agent for this web page. - */ - userAgent: string; - /** - * A `number` property that determines the zoom factor for this web contents. - * - * The zoom factor is the zoom percent divided by 100, so 300% = 3.0. - */ - zoomFactor: number; - /** - * A `number` property that determines the zoom level for this web contents. - * - * The original size is 0 and each increment above or below represents zooming 20% - * larger or smaller to default limits of 300% and 50% of original size, - * respectively. The formula for this is `scale := 1.2 ^ level`. - */ - zoomLevel: number; - } - - interface WebFrame extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/web-frame - - /** - * Attempts to free memory that is no longer being used (like images from a - * previous navigation). - * - * Note that blindly calling this method probably makes Electron slower since it - * will have to refill these emptied caches, you should only call it if an event in - * your app has occurred that makes you think your page is actually using less - * memory (i.e. you have navigated from a super heavy page to a mostly empty one, - * and intend to stay there). - */ - clearCache(): void; - /** - * A promise that resolves with the result of the executed code or is rejected if - * execution throws or results in a rejected promise. - * - * Evaluates `code` in page. - * - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise<any>; - /** - * A promise that resolves with the result of the executed code or is rejected if - * execution could not start. - * - * Works like `executeJavaScript` but evaluates `scripts` in an isolated context. - * - * Note that when the execution of script fails, the returned promise will not - * reject and the `result` would be `undefined`. This is because Chromium does not - * dispatch errors of isolated worlds to foreign worlds. - */ - executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise<any>; - /** - * A child of `webFrame` with the supplied `name`, `null` would be returned if - * there's no such frame or if the frame is not in the current renderer process. - */ - findFrameByName(name: string): WebFrame; - /** - * that has the supplied `routingId`, `null` if not found. - */ - findFrameByRoutingId(routingId: number): WebFrame; - /** - * The frame element in `webFrame's` document selected by `selector`, `null` would - * be returned if `selector` does not select a frame or if the frame is not in the - * current renderer process. - */ - getFrameForSelector(selector: string): WebFrame; - /** - * * `images` MemoryUsageDetails - * * `scripts` MemoryUsageDetails - * * `cssStyleSheets` MemoryUsageDetails - * * `xslStyleSheets` MemoryUsageDetails - * * `fonts` MemoryUsageDetails - * * `other` MemoryUsageDetails - * - * Returns an object describing usage information of Blink's internal memory - * caches. - * - * This will generate: - */ - getResourceUsage(): ResourceUsage; - /** - * A list of suggested words for a given word. If the word is spelled correctly, - * the result will be empty. - */ - getWordSuggestions(word: string): string[]; - /** - * The current zoom factor. - */ - getZoomFactor(): number; - /** - * The current zoom level. - */ - getZoomLevel(): number; - /** - * A key for the inserted CSS that can later be used to remove the CSS via - * `webFrame.removeInsertedCSS(key)`. - * - * Injects CSS into the current web page and returns a unique key for the inserted - * stylesheet. - */ - insertCSS(css: string, options?: InsertCSSOptions): string; - /** - * Inserts `text` to the focused element. - */ - insertText(text: string): void; - /** - * True if the word is misspelled according to the built in spellchecker, false - * otherwise. If no dictionary is loaded, always return false. - */ - isWordMisspelled(word: string): boolean; - /** - * Removes the inserted CSS from the current web page. The stylesheet is identified - * by its key, which is returned from `webFrame.insertCSS(css)`. - */ - removeInsertedCSS(key: string): void; - /** - * Set the security origin, content security policy and name of the isolated world. - * Note: If the `csp` is specified, then the `securityOrigin` also has to be - * specified. - */ - setIsolatedWorldInfo(worldId: number, info: Info): void; - setSpellCheckProvider(language: string, provider: Provider): void; - /** - * Sets the maximum and minimum pinch-to-zoom level. - * - * > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, - * call: - * - * > **NOTE**: Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom - * shortcuts are controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem - * roles in the application Menu. To disable shortcuts, manually define the Menu - * and omit zoom roles from the definition. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Changes the zoom factor to the specified factor. Zoom factor is zoom percent - * divided by 100, so 300% = 3.0. - * - * The factor must be greater than 0.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. The original size is 0 and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. - * - * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that - * the zoom level for a specific domain propagates across all instances of windows - * with the same domain. Differentiating the window URLs will make zoom work - * per-window. - */ - setZoomLevel(level: number): void; - /** - * A `WebFrame | null` representing the first child frame of `webFrame`, the - * property would be `null` if `webFrame` has no children or if first child is not - * in the current renderer process. - * - */ - readonly firstChild: (WebFrame) | (null); - /** - * A `WebFrame | null` representing next sibling frame, the property would be - * `null` if `webFrame` is the last frame in its parent or if the next sibling is - * not in the current renderer process. - * - */ - readonly nextSibling: (WebFrame) | (null); - /** - * A `WebFrame | null` representing the frame which opened `webFrame`, the property - * would be `null` if there's no opener or opener is not in the current renderer - * process. - * - */ - readonly opener: (WebFrame) | (null); - /** - * A `WebFrame | null` representing parent frame of `webFrame`, the property would - * be `null` if `webFrame` is top or parent is not in the current renderer process. - * - */ - readonly parent: (WebFrame) | (null); - /** - * An `Integer` representing the unique frame id in the current renderer process. - * Distinct WebFrame instances that refer to the same underlying frame will have - * the same `routingId`. - * - */ - readonly routingId: number; - /** - * A `WebFrame | null` representing top frame in frame hierarchy to which - * `webFrame` belongs, the property would be `null` if top frame is not in the - * current renderer process. - * - */ - readonly top: (WebFrame) | (null); - } - - class WebFrameMain extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/web-frame-main - - /** - * A frame with the given process and routing IDs, or `undefined` if there is no - * WebFrameMain associated with the given IDs. - */ - static fromId(processId: number, routingId: number): (WebFrameMain) | (undefined); - /** - * Emitted when the document is loaded. - */ - on(event: 'dom-ready', listener: Function): this; - once(event: 'dom-ready', listener: Function): this; - addListener(event: 'dom-ready', listener: Function): this; - removeListener(event: 'dom-ready', listener: Function): this; - /** - * A promise that resolves with the result of the executed code or is rejected if - * execution throws or results in a rejected promise. - * - * Evaluates `code` in page. - * - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - */ - executeJavaScript(code: string, userGesture?: boolean): Promise<unknown>; - /** - * Send a message to the renderer process, optionally transferring ownership of - * zero or more [`MessagePortMain`][] objects. - * - * The transferred `MessagePortMain` objects will be available in the renderer - * process by accessing the `ports` property of the emitted event. When they arrive - * in the renderer, they will be native DOM `MessagePort` objects. - * - * For example: - */ - postMessage(channel: string, message: any, transfer?: MessagePortMain[]): void; - /** - * Whether the reload was initiated successfully. Only results in `false` when the - * frame has no history. - */ - reload(): boolean; - /** - * Send an asynchronous message to the renderer process via `channel`, along with - * arguments. Arguments will be serialized with the [Structured Clone - * Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be - * included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw - * an exception. - * - * The renderer process can handle the message by listening to `channel` with the - * `ipcRenderer` module. - */ - send(channel: string, ...args: any[]): void; - /** - * A `WebFrameMain[]` collection containing the direct descendents of `frame`. - * - */ - readonly frames: WebFrameMain[]; - /** - * A `WebFrameMain[]` collection containing every frame in the subtree of `frame`, - * including itself. This can be useful when traversing through all frames. - * - */ - readonly framesInSubtree: WebFrameMain[]; - /** - * An `Integer` representing the id of the frame's internal FrameTreeNode instance. - * This id is browser-global and uniquely identifies a frame that hosts content. - * The identifier is fixed at the creation of the frame and stays constant for the - * lifetime of the frame. When the frame is removed, the id is not used again. - * - */ - readonly frameTreeNodeId: number; - /** - * A `string` representing the frame name. - * - */ - readonly name: string; - /** - * An `Integer` representing the operating system `pid` of the process which owns - * this frame. - * - */ - readonly osProcessId: number; - /** - * A `WebFrameMain | null` representing parent frame of `frame`, the property would - * be `null` if `frame` is the top frame in the frame hierarchy. - * - */ - readonly parent: (WebFrameMain) | (null); - /** - * An `Integer` representing the Chromium internal `pid` of the process which owns - * this frame. This is not the same as the OS process ID; to read that use - * `frame.osProcessId`. - * - */ - readonly processId: number; - /** - * An `Integer` representing the unique frame id in the current renderer process. - * Distinct `WebFrameMain` instances that refer to the same underlying frame will - * have the same `routingId`. - * - */ - readonly routingId: number; - /** - * A `WebFrameMain | null` representing top frame in the frame hierarchy to which - * `frame` belongs. - * - */ - readonly top: (WebFrameMain) | (null); - /** - * A `string` representing the current URL of the frame. - * - */ - readonly url: string; - /** - * A `string` representing the visibility state of the frame. - * - * See also how the Page Visibility API is affected by other Electron APIs. - * - */ - readonly visibilityState: string; - } - - class WebRequest { - - // Docs: https://electronjs.org/docs/api/web-request - - /** - * The `listener` will be called with `listener(details)` when a server initiated - * redirect is about to occur. - */ - onBeforeRedirect(filter: WebRequestFilter, listener: ((details: OnBeforeRedirectListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when a server initiated - * redirect is about to occur. - */ - onBeforeRedirect(listener: ((details: OnBeforeRedirectListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when a request - * is about to occur. - * - * The `uploadData` is an array of `UploadData` objects. - * - * The `callback` has to be called with an `response` object. - * - * Some examples of valid `urls`: - */ - onBeforeRequest(filter: WebRequestFilter, listener: ((details: OnBeforeRequestListenerDetails, callback: (response: Response) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when a request - * is about to occur. - * - * The `uploadData` is an array of `UploadData` objects. - * - * The `callback` has to be called with an `response` object. - * - * Some examples of valid `urls`: - */ - onBeforeRequest(listener: ((details: OnBeforeRequestListenerDetails, callback: (response: Response) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` before sending - * an HTTP request, once the request headers are available. This may occur after a - * TCP connection is made to the server, but before any http data is sent. - * - * The `callback` has to be called with a `response` object. - */ - onBeforeSendHeaders(filter: WebRequestFilter, listener: ((details: OnBeforeSendHeadersListenerDetails, callback: (beforeSendResponse: BeforeSendResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` before sending - * an HTTP request, once the request headers are available. This may occur after a - * TCP connection is made to the server, but before any http data is sent. - * - * The `callback` has to be called with a `response` object. - */ - onBeforeSendHeaders(listener: ((details: OnBeforeSendHeadersListenerDetails, callback: (beforeSendResponse: BeforeSendResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when a request is - * completed. - */ - onCompleted(filter: WebRequestFilter, listener: ((details: OnCompletedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when a request is - * completed. - */ - onCompleted(listener: ((details: OnCompletedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when an error occurs. - */ - onErrorOccurred(filter: WebRequestFilter, listener: ((details: OnErrorOccurredListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when an error occurs. - */ - onErrorOccurred(listener: ((details: OnErrorOccurredListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when HTTP - * response headers of a request have been received. - * - * The `callback` has to be called with a `response` object. - */ - onHeadersReceived(filter: WebRequestFilter, listener: ((details: OnHeadersReceivedListenerDetails, callback: (headersReceivedResponse: HeadersReceivedResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when HTTP - * response headers of a request have been received. - * - * The `callback` has to be called with a `response` object. - */ - onHeadersReceived(listener: ((details: OnHeadersReceivedListenerDetails, callback: (headersReceivedResponse: HeadersReceivedResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when first byte of the - * response body is received. For HTTP requests, this means that the status line - * and response headers are available. - */ - onResponseStarted(filter: WebRequestFilter, listener: ((details: OnResponseStartedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when first byte of the - * response body is received. For HTTP requests, this means that the status line - * and response headers are available. - */ - onResponseStarted(listener: ((details: OnResponseStartedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` just before a request is - * going to be sent to the server, modifications of previous `onBeforeSendHeaders` - * response are visible by the time this listener is fired. - */ - onSendHeaders(filter: WebRequestFilter, listener: ((details: OnSendHeadersListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` just before a request is - * going to be sent to the server, modifications of previous `onBeforeSendHeaders` - * response are visible by the time this listener is fired. - */ - onSendHeaders(listener: ((details: OnSendHeadersListenerDetails) => void) | (null)): void; - } - - interface WebRequestFilter { - - // Docs: https://electronjs.org/docs/api/structures/web-request-filter - - /** - * Array of URL patterns that will be used to filter out the requests that do not - * match the URL patterns. - */ - urls: string[]; - } - - interface WebSource { - - // Docs: https://electronjs.org/docs/api/structures/web-source - - code: string; - url?: string; - } - - interface WebviewTag extends HTMLElement { - - // Docs: https://electronjs.org/docs/api/webview-tag - - /** - * Fired when a load has committed. This includes navigation within the current - * document as well as subframe document-level loads, but does not include - * asynchronous resource loads. - */ - addEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void): this; - /** - * Fired when the navigation is done, i.e. the spinner of the tab will stop - * spinning, and the `onload` event is dispatched. - */ - addEventListener(event: 'did-finish-load', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-finish-load', listener: (event: Event) => void): this; - /** - * This event is like `did-finish-load`, but fired when the load failed or was - * cancelled, e.g. `window.stop()` is invoked. - */ - addEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void): this; - /** - * Fired when a frame has done navigation. - */ - addEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab starts spinning. - */ - addEventListener(event: 'did-start-loading', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-start-loading', listener: (event: Event) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab stops spinning. - */ - addEventListener(event: 'did-stop-loading', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-stop-loading', listener: (event: Event) => void): this; - /** - * Fired when attached to the embedder web contents. - */ - addEventListener(event: 'did-attach', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-attach', listener: (event: Event) => void): this; - /** - * Fired when document in the given frame is loaded. - */ - addEventListener(event: 'dom-ready', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'dom-ready', listener: (event: Event) => void): this; - /** - * Fired when page title is set during navigation. `explicitSet` is false when - * title is synthesized from file url. - */ - addEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void): this; - /** - * Fired when page receives favicon urls. - */ - addEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void): this; - /** - * Fired when page enters fullscreen triggered by HTML API. - */ - addEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void): this; - /** - * Fired when page leaves fullscreen triggered by HTML API. - */ - addEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void): this; - /** - * Fired when the guest window logs a console message. - * - * The following example code forwards all log messages to the embedder's console - * without regard for log level or other properties. - */ - addEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void): this; - /** - * Fired when a result is available for `webview.findInPage` request. - */ - addEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void): this; - /** - * Fired when the guest page attempts to open a new browser window. - * - * The following example code opens the new url in system's default browser. - */ - addEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void): this; - /** - * Emitted when a user or the page wants to start navigation. It can happen when - * the `window.location` object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with - * APIs like `<webview>.loadURL` and `<webview>.back`. - * - * It is also not emitted during in-page navigation, such as clicking anchor links - * or updating the `window.location.hash`. Use `did-navigate-in-page` event for - * this purpose. - * - * Calling `event.preventDefault()` does __NOT__ have any effect. - */ - addEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void): this; - /** - * Emitted when any frame (including main) starts navigating. `isInPlace` will be - * `true` for in-page navigations. - */ - addEventListener(event: 'did-start-navigation', listener: (event: DidStartNavigationEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-start-navigation', listener: (event: DidStartNavigationEvent) => void): this; - /** - * Emitted after a server side redirect occurs during navigation. For example a 302 - * redirect. - */ - addEventListener(event: 'did-redirect-navigation', listener: (event: DidRedirectNavigationEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-redirect-navigation', listener: (event: DidRedirectNavigationEvent) => void): this; - /** - * Emitted when a navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the `window.location.hash`. Use `did-navigate-in-page` event for - * this purpose. - */ - addEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void): this; - /** - * Emitted when any frame navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the `window.location.hash`. Use `did-navigate-in-page` event for - * this purpose. - */ - addEventListener(event: 'did-frame-navigate', listener: (event: DidFrameNavigateEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-frame-navigate', listener: (event: DidFrameNavigateEvent) => void): this; - /** - * Emitted when an in-page navigation happened. - * - * When in-page navigation happens, the page URL changes but does not cause - * navigation outside of the page. Examples of this occurring are when anchor links - * are clicked or when the DOM `hashchange` event is triggered. - */ - addEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void): this; - /** - * Fired when the guest page attempts to close itself. - * - * The following example code navigates the `webview` to `about:blank` when the - * guest attempts to close itself. - */ - addEventListener(event: 'close', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'close', listener: (event: Event) => void): this; - /** - * Fired when the guest page has sent an asynchronous message to embedder page. - * - * With `sendToHost` method and `ipc-message` event you can communicate between - * guest page and embedder page: - */ - addEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void): this; - /** - * Fired when the renderer process is crashed. - */ - addEventListener(event: 'crashed', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'crashed', listener: (event: Event) => void): this; - /** - * Fired when a plugin process is crashed. - */ - addEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void): this; - /** - * Fired when the WebContents is destroyed. - */ - addEventListener(event: 'destroyed', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'destroyed', listener: (event: Event) => void): this; - /** - * Emitted when media starts playing. - */ - addEventListener(event: 'media-started-playing', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'media-started-playing', listener: (event: Event) => void): this; - /** - * Emitted when media is paused or done playing. - */ - addEventListener(event: 'media-paused', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'media-paused', listener: (event: Event) => void): this; - /** - * Emitted when a page's theme color changes. This is usually due to encountering a - * meta tag: - */ - addEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void): this; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - addEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void): this; - /** - * Emitted when DevTools is opened. - */ - addEventListener(event: 'devtools-opened', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'devtools-opened', listener: (event: Event) => void): this; - /** - * Emitted when DevTools is closed. - */ - addEventListener(event: 'devtools-closed', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'devtools-closed', listener: (event: Event) => void): this; - /** - * Emitted when DevTools is focused / opened. - */ - addEventListener(event: 'devtools-focused', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'devtools-focused', listener: (event: Event) => void): this; - /** - * Emitted when there is a new context menu that needs to be handled. - */ - addEventListener(event: 'context-menu', listener: (event: ContextMenuEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'context-menu', listener: (event: ContextMenuEvent) => void): this; - addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - /** - * Whether the guest page can go back. - */ - canGoBack(): boolean; - /** - * Whether the guest page can go forward. - */ - canGoForward(): boolean; - /** - * Whether the guest page can go to `offset`. - */ - canGoToOffset(offset: number): boolean; - /** - * Resolves with a NativeImage - * - * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the - * whole visible page. - */ - capturePage(rect?: Rectangle): Promise<Electron.NativeImage>; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Closes the DevTools window of guest page. - */ - closeDevTools(): void; - /** - * Executes editing command `copy` in page. - */ - copy(): void; - /** - * Executes editing command `cut` in page. - */ - cut(): void; - /** - * Executes editing command `delete` in page. - */ - delete(): void; - /** - * Initiates a download of the resource at `url` without navigating. - */ - downloadURL(url: string): void; - /** - * A promise that resolves with the result of the executed code or is rejected if - * the result of the code is a rejected promise. - * - * Evaluates `code` in page. If `userGesture` is set, it will create the user - * gesture context in the page. HTML APIs like `requestFullScreen`, which require - * user action, can take advantage of this option for automation. - */ - executeJavaScript(code: string, userGesture?: boolean): Promise<any>; - /** - * The request id used for the request. - * - * Starts a request to find all matches for the `text` in the web page. The result - * of the request can be obtained by subscribing to `found-in-page` event. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * The title of guest page. - */ - getTitle(): string; - /** - * The URL of guest page. - */ - getURL(): string; - /** - * The user agent for guest page. - */ - getUserAgent(): string; - /** - * The WebContents ID of this `webview`. - */ - getWebContentsId(): number; - /** - * the current zoom factor. - */ - getZoomFactor(): number; - /** - * the current zoom level. - */ - getZoomLevel(): number; - /** - * Makes the guest page go back. - */ - goBack(): void; - /** - * Makes the guest page go forward. - */ - goForward(): void; - /** - * Navigates to the specified absolute index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * A promise that resolves with a key for the inserted CSS that can later be used - * to remove the CSS via `<webview>.removeInsertedCSS(key)`. - * - * Injects CSS into the current web page and returns a unique key for the inserted - * stylesheet. - */ - insertCSS(css: string): Promise<string>; - /** - * Inserts `text` to the focused element. - */ - insertText(text: string): Promise<void>; - /** - * Starts inspecting element at position (`x`, `y`) of guest page. - */ - inspectElement(x: number, y: number): void; - /** - * Opens the DevTools for the service worker context present in the guest page. - */ - inspectServiceWorker(): void; - /** - * Opens the DevTools for the shared worker context present in the guest page. - */ - inspectSharedWorker(): void; - /** - * Whether guest page has been muted. - */ - isAudioMuted(): boolean; - /** - * Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Whether audio is currently playing. - */ - isCurrentlyAudible(): boolean; - /** - * Whether DevTools window of guest page is focused. - */ - isDevToolsFocused(): boolean; - /** - * Whether guest page has a DevTools window attached. - */ - isDevToolsOpened(): boolean; - /** - * Whether guest page is still loading resources. - */ - isLoading(): boolean; - /** - * Whether the main frame (and not just iframes or frames within it) is still - * loading. - */ - isLoadingMainFrame(): boolean; - /** - * Whether the guest page is waiting for a first-response for the main resource of - * the page. - */ - isWaitingForResponse(): boolean; - /** - * The promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Loads the `url` in the webview, the `url` must contain the protocol prefix, e.g. - * the `http://` or `file://`. - */ - loadURL(url: string, options?: LoadURLOptions): Promise<void>; - /** - * Opens a DevTools window for guest page. - */ - openDevTools(): void; - /** - * Executes editing command `paste` in page. - */ - paste(): void; - /** - * Executes editing command `pasteAndMatchStyle` in page. - */ - pasteAndMatchStyle(): void; - /** - * Prints `webview`'s web page. Same as `webContents.print([options])`. - */ - print(options?: WebviewTagPrintOptions): Promise<void>; - /** - * Resolves with the generated PDF data. - * - * Prints `webview`'s web page as PDF, Same as `webContents.printToPDF(options)`. - */ - printToPDF(options: PrintToPDFOptions): Promise<Uint8Array>; - /** - * Executes editing command `redo` in page. - */ - redo(): void; - /** - * Reloads the guest page. - */ - reload(): void; - /** - * Reloads the guest page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * Resolves if the removal was successful. - * - * Removes the inserted CSS from the current web page. The stylesheet is identified - * by its key, which is returned from `<webview>.insertCSS(css)`. - */ - removeInsertedCSS(key: string): Promise<void>; - /** - * Executes editing command `replace` in page. - */ - replace(text: string): void; - /** - * Executes editing command `replaceMisspelling` in page. - */ - replaceMisspelling(text: string): void; - /** - * Executes editing command `selectAll` in page. - */ - selectAll(): void; - /** - * Send an asynchronous message to renderer process via `channel`, you can also - * send arbitrary arguments. The renderer process can handle the message by - * listening to the `channel` event with the `ipcRenderer` module. - * - * See webContents.send for examples. - */ - send(channel: string, ...args: any[]): Promise<void>; - /** - * Sends an input `event` to the page. - * - * See webContents.sendInputEvent for detailed description of `event` object. - */ - sendInputEvent(event: (MouseInputEvent) | (MouseWheelInputEvent) | (KeyboardInputEvent)): Promise<void>; - /** - * Send an asynchronous message to renderer process via `channel`, you can also - * send arbitrary arguments. The renderer process can handle the message by - * listening to the `channel` event with the `ipcRenderer` module. - * - * See webContents.sendToFrame for examples. - */ - sendToFrame(frameId: [number, number], channel: string, ...args: any[]): Promise<void>; - /** - * Set guest page muted. - */ - setAudioMuted(muted: boolean): void; - /** - * Overrides the user agent for the guest page. - */ - setUserAgent(userAgent: string): void; - /** - * Sets the maximum and minimum pinch-to-zoom level. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): Promise<void>; - /** - * Changes the zoom factor to the specified factor. Zoom factor is zoom percent - * divided by 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. The original size is 0 and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. The formula for this is - * `scale := 1.2 ^ level`. - * - * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that - * the zoom level for a specific domain propagates across all instances of windows - * with the same domain. Differentiating the window URLs will make zoom work - * per-window. - */ - setZoomLevel(level: number): void; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * - * @platform darwin - */ - showDefinitionForSelection(): void; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Stops any `findInPage` request for the `webview` with the provided `action`. - */ - stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; - /** - * Executes editing command `undo` in page. - */ - undo(): void; - /** - * Executes editing command `unselect` in page. - */ - unselect(): void; - /** - * A `boolean`. When this attribute is present the guest page will be allowed to - * open new windows. Popups are disabled by default. - */ - allowpopups: boolean; - /** - * A `string` which is a list of strings which specifies the blink features to be - * disabled separated by `,`. The full list of supported feature strings can be - * found in the RuntimeEnabledFeatures.json5 file. - */ - disableblinkfeatures: string; - /** - * A `boolean`. When this attribute is present the guest page will have web - * security disabled. Web security is enabled by default. - */ - disablewebsecurity: boolean; - /** - * A `string` which is a list of strings which specifies the blink features to be - * enabled separated by `,`. The full list of supported feature strings can be - * found in the RuntimeEnabledFeatures.json5 file. - */ - enableblinkfeatures: string; - /** - * A `string` that sets the referrer URL for the guest page. - */ - httpreferrer: string; - /** - * A `boolean`. When this attribute is present the guest page in `webview` will - * have node integration and can use node APIs like `require` and `process` to - * access low level system resources. Node integration is disabled by default in - * the guest page. - */ - nodeintegration: boolean; - /** - * A `boolean` for the experimental option for enabling NodeJS support in - * sub-frames such as iframes inside the `webview`. All your preloads will load for - * every iframe, you can use `process.isMainFrame` to determine if you are in the - * main frame or not. This option is disabled by default in the guest page. - */ - nodeintegrationinsubframes: boolean; - /** - * A `string` that sets the session used by the page. If `partition` starts with - * `persist:`, the page will use a persistent session available to all pages in the - * app with the same `partition`. if there is no `persist:` prefix, the page will - * use an in-memory session. By assigning the same `partition`, multiple pages can - * share the same session. If the `partition` is unset then default session of the - * app will be used. - * - * This value can only be modified before the first navigation, since the session - * of an active renderer process cannot change. Subsequent attempts to modify the - * value will fail with a DOM exception. - */ - partition: string; - /** - * A `boolean`. When this attribute is present the guest page in `webview` will be - * able to use browser plugins. Plugins are disabled by default. - */ - plugins: boolean; - /** - * A `string` that specifies a script that will be loaded before other scripts run - * in the guest page. The protocol of script's URL must be `file:` (even when using - * `asar:` archives) because it will be loaded by Node's `require` under the hood, - * which treats `asar:` archives as virtual directories. - * - * When the guest page doesn't have node integration this script will still have - * access to all Node APIs, but global objects injected by Node will be deleted - * after this script has finished executing. - * - * **Note:** This option will appear as `preloadURL` (not `preload`) in the - * `webPreferences` specified to the `will-attach-webview` event. - */ - preload: string; - /** - * A `string` representing the visible URL. Writing to this attribute initiates - * top-level navigation. - * - * Assigning `src` its own value will reload the current page. - * - * The `src` attribute can also accept data URLs, such as `data:text/plain,Hello, - * world!`. - */ - src: string; - /** - * A `string` that sets the user agent for the guest page before the page is - * navigated to. Once the page is loaded, use the `setUserAgent` method to change - * the user agent. - */ - useragent: string; - /** - * A `string` which is a comma separated list of strings which specifies the web - * preferences to be set on the webview. The full list of supported preference - * strings can be found in BrowserWindow. - * - * The string follows the same format as the features string in `window.open`. A - * name by itself is given a `true` boolean value. A preference can be set to - * another value by including an `=`, followed by the value. Special values `yes` - * and `1` are interpreted as `true`, while `no` and `0` are interpreted as - * `false`. - */ - webpreferences: string; - } - - interface AboutPanelOptionsOptions { - /** - * The app's name. - */ - applicationName?: string; - /** - * The app's version. - */ - applicationVersion?: string; - /** - * Copyright information. - */ - copyright?: string; - /** - * The app's build version number. - * - * @platform darwin - */ - version?: string; - /** - * Credit information. - * - * @platform darwin,win32 - */ - credits?: string; - /** - * List of app authors. - * - * @platform linux - */ - authors?: string[]; - /** - * The app's website. - * - * @platform linux - */ - website?: string; - /** - * Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as - * 64x64 pixels while retaining aspect ratio. - * - * @platform linux,win32 - */ - iconPath?: string; - } - - interface AddRepresentationOptions { - /** - * The scale factor to add the image representation for. - */ - scaleFactor: number; - /** - * Defaults to 0. Required if a bitmap buffer is specified as `buffer`. - */ - width?: number; - /** - * Defaults to 0. Required if a bitmap buffer is specified as `buffer`. - */ - height?: number; - /** - * The buffer containing the raw image data. - */ - buffer?: Buffer; - /** - * The data URL containing either a base 64 encoded PNG or JPEG image. - */ - dataURL?: string; - } - - interface AnimationSettings { - /** - * Returns true if rich animations should be rendered. Looks at session type (e.g. - * remote desktop) and accessibility settings to give guidance for heavy - * animations. - */ - shouldRenderRichAnimation: boolean; - /** - * Determines on a per-platform basis whether scroll animations (e.g. produced by - * home/end key) should be enabled. - */ - scrollAnimationsEnabledBySystem: boolean; - /** - * Determines whether the user desires reduced motion based on platform APIs. - */ - prefersReducedMotion: boolean; - } - - interface AppDetailsOptions { - /** - * Window's App User Model ID. It has to be set, otherwise the other options will - * have no effect. - */ - appId?: string; - /** - * Window's Relaunch Icon. - */ - appIconPath?: string; - /** - * Index of the icon in `appIconPath`. Ignored when `appIconPath` is not set. - * Default is `0`. - */ - appIconIndex?: number; - /** - * Window's Relaunch Command. - */ - relaunchCommand?: string; - /** - * Window's Relaunch Display Name. - */ - relaunchDisplayName?: string; - } - - interface ApplicationInfoForProtocolReturnValue { - /** - * the display icon of the app handling the protocol. - */ - icon: NativeImage; - /** - * installation path of the app handling the protocol. - */ - path: string; - /** - * display name of the app handling the protocol. - */ - name: string; - } - - interface AuthenticationResponseDetails { - url: string; - } - - interface AuthInfo { - isProxy: boolean; - scheme: string; - host: string; - port: number; - realm: string; - } - - interface AutoResizeOptions { - /** - * If `true`, the view's width will grow and shrink together with the window. - * `false` by default. - */ - width?: boolean; - /** - * If `true`, the view's height will grow and shrink together with the window. - * `false` by default. - */ - height?: boolean; - /** - * If `true`, the view's x position and width will grow and shrink proportionally - * with the window. `false` by default. - */ - horizontal?: boolean; - /** - * If `true`, the view's y position and height will grow and shrink proportionally - * with the window. `false` by default. - */ - vertical?: boolean; - } - - interface BeforeSendResponse { - cancel?: boolean; - /** - * When provided, request will be made with these headers. - */ - requestHeaders?: Record<string, (string) | (string[])>; - } - - interface BitmapOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface BlinkMemoryInfo { - /** - * Size of all allocated objects in Kilobytes. - */ - allocated: number; - /** - * Total allocated space in Kilobytes. - */ - total: number; - } - - interface BrowserViewConstructorOptions { - /** - * See BrowserWindow. - */ - webPreferences?: WebPreferences; - } - - interface BrowserWindowConstructorOptions { - /** - * Window's width in pixels. Default is `800`. - */ - width?: number; - /** - * Window's height in pixels. Default is `600`. - */ - height?: number; - /** - * (**required** if y is used) Window's left offset from screen. Default is to - * center the window. - */ - x?: number; - /** - * (**required** if x is used) Window's top offset from screen. Default is to - * center the window. - */ - y?: number; - /** - * The `width` and `height` would be used as web page's size, which means the - * actual window's size will include window frame's size and be slightly larger. - * Default is `false`. - */ - useContentSize?: boolean; - /** - * Show window in the center of the screen. - */ - center?: boolean; - /** - * Window's minimum width. Default is `0`. - */ - minWidth?: number; - /** - * Window's minimum height. Default is `0`. - */ - minHeight?: number; - /** - * Window's maximum width. Default is no limit. - */ - maxWidth?: number; - /** - * Window's maximum height. Default is no limit. - */ - maxHeight?: number; - /** - * Whether window is resizable. Default is `true`. - */ - resizable?: boolean; - /** - * Whether window is movable. This is not implemented on Linux. Default is `true`. - */ - movable?: boolean; - /** - * Whether window is minimizable. This is not implemented on Linux. Default is - * `true`. - */ - minimizable?: boolean; - /** - * Whether window is maximizable. This is not implemented on Linux. Default is - * `true`. - */ - maximizable?: boolean; - /** - * Whether window is closable. This is not implemented on Linux. Default is `true`. - */ - closable?: boolean; - /** - * Whether the window can be focused. Default is `true`. On Windows setting - * `focusable: false` also implies setting `skipTaskbar: true`. On Linux setting - * `focusable: false` makes the window stop interacting with wm, so the window will - * always stay on top in all workspaces. - */ - focusable?: boolean; - /** - * Whether the window should always stay on top of other windows. Default is - * `false`. - */ - alwaysOnTop?: boolean; - /** - * Whether the window should show in fullscreen. When explicitly set to `false` the - * fullscreen button will be hidden or disabled on macOS. Default is `false`. - */ - fullscreen?: boolean; - /** - * Whether the window can be put into fullscreen mode. On macOS, also whether the - * maximize/zoom button should toggle full screen mode or maximize window. Default - * is `true`. - */ - fullscreenable?: boolean; - /** - * Use pre-Lion fullscreen on macOS. Default is `false`. - */ - simpleFullscreen?: boolean; - /** - * Whether to show the window in taskbar. Default is `false`. - */ - skipTaskbar?: boolean; - /** - * Whether the window is in kiosk mode. Default is `false`. - */ - kiosk?: boolean; - /** - * Default window title. Default is `"Electron"`. If the HTML tag `<title>` is - * defined in the HTML file loaded by `loadURL()`, this property will be ignored. - */ - title?: string; - /** - * The window icon. On Windows it is recommended to use `ICO` icons to get best - * visual effects, you can also leave it undefined so the executable's icon will be - * used. - */ - icon?: (NativeImage) | (string); - /** - * Whether window should be shown when created. Default is `true`. - */ - show?: boolean; - /** - * Whether the renderer should be active when `show` is `false` and it has just - * been created. In order for `document.visibilityState` to work correctly on - * first load with `show: false` you should set this to `false`. Setting this to - * `false` will cause the `ready-to-show` event to not fire. Default is `true`. - */ - paintWhenInitiallyHidden?: boolean; - /** - * Specify `false` to create a frameless window. Default is `true`. - */ - frame?: boolean; - /** - * Specify parent window. Default is `null`. - */ - parent?: BrowserWindow; - /** - * Whether this is a modal window. This only works when the window is a child - * window. Default is `false`. - */ - modal?: boolean; - /** - * Whether clicking an inactive window will also click through to the web contents. - * Default is `false` on macOS. This option is not configurable on other platforms. - */ - acceptFirstMouse?: boolean; - /** - * Whether to hide cursor when typing. Default is `false`. - */ - disableAutoHideCursor?: boolean; - /** - * Auto hide the menu bar unless the `Alt` key is pressed. Default is `false`. - */ - autoHideMenuBar?: boolean; - /** - * Enable the window to be resized larger than screen. Only relevant for macOS, as - * other OSes allow larger-than-screen windows by default. Default is `false`. - */ - enableLargerThanScreen?: boolean; - /** - * The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color - * format. Alpha in #AARRGGBB format is supported if `transparent` is set to - * `true`. Default is `#FFF` (white). See win.setBackgroundColor for more - * information. - */ - backgroundColor?: string; - /** - * Whether window should have a shadow. Default is `true`. - */ - hasShadow?: boolean; - /** - * Set the initial opacity of the window, between 0.0 (fully transparent) and 1.0 - * (fully opaque). This is only implemented on Windows and macOS. - */ - opacity?: number; - /** - * Forces using dark theme for the window, only works on some GTK+3 desktop - * environments. Default is `false`. - */ - darkTheme?: boolean; - /** - * Makes the window transparent. Default is `false`. On Windows, does not work - * unless the window is frameless. - */ - transparent?: boolean; - /** - * The type of window, default is normal window. See more about this below. - */ - type?: string; - /** - * Specify how the material appearance should reflect window activity state on - * macOS. Must be used with the `vibrancy` property. Possible values are: - */ - visualEffectState?: ('followWindow' | 'active' | 'inactive'); - /** - * The style of window title bar. Default is `default`. Possible values are: - * - * @platform darwin,win32 - */ - titleBarStyle?: ('default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover'); - /** - * Set a custom position for the traffic light buttons in frameless windows. - */ - trafficLightPosition?: Point; - /** - * Whether frameless window should have rounded corners on macOS. Default is - * `true`. - */ - roundedCorners?: boolean; - /** - * Shows the title in the title bar in full screen mode on macOS for `hiddenInset` - * titleBarStyle. Default is `false`. - * - * @deprecated - */ - fullscreenWindowTitle?: boolean; - /** - * Use `WS_THICKFRAME` style for frameless windows on Windows, which adds standard - * window frame. Setting it to `false` will remove window shadow and window - * animations. Default is `true`. - */ - thickFrame?: boolean; - /** - * Add a type of vibrancy effect to the window, only on macOS. Can be - * `appearance-based`, `light`, `dark`, `titlebar`, `selection`, `menu`, `popover`, - * `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, - * `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. Please - * note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` - * are deprecated and have been removed in macOS Catalina (10.15). - */ - vibrancy?: ('appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark' | 'header' | 'sheet' | 'window' | 'hud' | 'fullscreen-ui' | 'tooltip' | 'content' | 'under-window' | 'under-page'); - /** - * Controls the behavior on macOS when option-clicking the green stoplight button - * on the toolbar or by clicking the Window > Zoom menu item. If `true`, the window - * will grow to the preferred width of the web page when zoomed, `false` will cause - * it to zoom to the width of the screen. This will also affect the behavior when - * calling `maximize()` directly. Default is `false`. - */ - zoomToPageWidth?: boolean; - /** - * Tab group name, allows opening the window as a native tab on macOS 10.12+. - * Windows with the same tabbing identifier will be grouped together. This also - * adds a native new tab button to your window's tab bar and allows your `app` and - * window to receive the `new-window-for-tab` event. - */ - tabbingIdentifier?: string; - /** - * Settings of web page's features. - */ - webPreferences?: WebPreferences; - /** - * When using a frameless window in conjunction with - * `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so - * that the standard window controls ("traffic lights" on macOS) are visible, this - * property enables the Window Controls Overlay JavaScript APIs and CSS Environment - * Variables. Specifying `true` will result in an overlay with default system - * colors. Default is `false`. - */ - titleBarOverlay?: (TitleBarOverlay) | (boolean); - } - - interface CertificateTrustDialogOptions { - /** - * The certificate to trust/import. - */ - certificate: Certificate; - /** - * The message to display to the user. - */ - message: string; - } - - interface ClearCodeCachesOptions { - /** - * An array of url corresponding to the resource whose generated code cache needs - * to be removed. If the list is empty then all entries in the cache directory will - * be removed. - */ - urls?: string[]; - } - - interface ClearStorageDataOptions { - /** - * Should follow `window.location.origin`’s representation `scheme://host:port`. - */ - origin?: string; - /** - * The types of storages to clear, can contain: `appcache`, `cookies`, - * `filesystem`, `indexdb`, `localstorage`, `shadercache`, `websql`, - * `serviceworkers`, `cachestorage`. If not specified, clear all storage types. - */ - storages?: string[]; - /** - * The types of quotas to clear, can contain: `temporary`, `persistent`, - * `syncable`. If not specified, clear all quotas. - */ - quotas?: string[]; - } - - interface ClientRequestConstructorOptions { - /** - * The HTTP request method. Defaults to the GET method. - */ - method?: string; - /** - * The request URL. Must be provided in the absolute form with the protocol scheme - * specified as http or https. - */ - url?: string; - /** - * The `Session` instance with which the request is associated. - */ - session?: Session; - /** - * The name of the `partition` with which the request is associated. Defaults to - * the empty string. The `session` option supersedes `partition`. Thus if a - * `session` is explicitly specified, `partition` is ignored. - */ - partition?: string; - /** - * Can be `include` or `omit`. Whether to send credentials with this request. If - * set to `include`, credentials from the session associated with the request will - * be used. If set to `omit`, credentials will not be sent with the request (and - * the `'login'` event will not be triggered in the event of a 401). This matches - * the behavior of the fetch option of the same name. If this option is not - * specified, authentication data from the session will be sent, and cookies will - * not be sent (unless `useSessionCookies` is set). - */ - credentials?: ('include' | 'omit'); - /** - * Whether to send cookies with this request from the provided session. If - * `credentials` is specified, this option has no effect. Default is `false`. - */ - useSessionCookies?: boolean; - /** - * Can be `http:` or `https:`. The protocol scheme in the form 'scheme:'. Defaults - * to 'http:'. - */ - protocol?: string; - /** - * The server host provided as a concatenation of the hostname and the port number - * 'hostname:port'. - */ - host?: string; - /** - * The server host name. - */ - hostname?: string; - /** - * The server's listening port number. - */ - port?: number; - /** - * The path part of the request URL. - */ - path?: string; - /** - * Can be `follow`, `error` or `manual`. The redirect mode for this request. When - * mode is `error`, any redirection will be aborted. When mode is `manual` the - * redirection will be cancelled unless `request.followRedirect` is invoked - * synchronously during the `redirect` event. Defaults to `follow`. - */ - redirect?: ('follow' | 'error' | 'manual'); - /** - * The origin URL of the request. - */ - origin?: string; - } - - interface Config { - /** - * The proxy mode. Should be one of `direct`, `auto_detect`, `pac_script`, - * `fixed_servers` or `system`. If it's unspecified, it will be automatically - * determined based on other specified options. - */ - mode?: ('direct' | 'auto_detect' | 'pac_script' | 'fixed_servers' | 'system'); - /** - * The URL associated with the PAC file. - */ - pacScript?: string; - /** - * Rules indicating which proxies to use. - */ - proxyRules?: string; - /** - * Rules indicating which URLs should bypass the proxy settings. - */ - proxyBypassRules?: string; - } - - interface ConfigureHostResolverOptions { - /** - * Whether the built-in host resolver is used in preference to getaddrinfo. When - * enabled, the built-in resolver will attempt to use the system's DNS settings to - * do DNS lookups itself. Enabled by default on macOS, disabled by default on - * Windows and Linux. - */ - enableBuiltInResolver?: boolean; - /** - * Can be "off", "automatic" or "secure". Configures the DNS-over-HTTP mode. When - * "off", no DoH lookups will be performed. When "automatic", DoH lookups will be - * performed first if DoH is available, and insecure DNS lookups will be performed - * as a fallback. When "secure", only DoH lookups will be performed. Defaults to - * "automatic". - */ - secureDnsMode?: string; - /** - * A list of DNS-over-HTTP server templates. See RFC8484 Β§ 3 for details on the - * template format. Most servers support the POST method; the template for such - * servers is simply a URI. Note that for some DNS providers, the resolver will - * automatically upgrade to DoH unless DoH is explicitly disabled, even if there - * are no DoH servers provided in this list. - */ - secureDnsServers?: string[]; - /** - * Controls whether additional DNS query types, e.g. HTTPS (DNS type 65) will be - * allowed besides the traditional A and AAAA queries when a request is being made - * via insecure DNS. Has no effect on Secure DNS which always allows additional - * types. Defaults to true. - */ - enableAdditionalDnsQueryTypes?: boolean; - } - - interface ConsoleMessageEvent extends Event { - /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. - */ - level: number; - /** - * The actual console message - */ - message: string; - /** - * The line number of the source that triggered this console message - */ - line: number; - sourceId: string; - } - - interface ContextMenuEvent extends Event { - params: Params; - } - - interface ContextMenuParams { - /** - * x coordinate. - */ - x: number; - /** - * y coordinate. - */ - y: number; - /** - * Frame from which the context menu was invoked. - */ - frame: WebFrameMain; - /** - * URL of the link that encloses the node the context menu was invoked on. - */ - linkURL: string; - /** - * Text associated with the link. May be an empty string if the contents of the - * link are an image. - */ - linkText: string; - /** - * URL of the top level page that the context menu was invoked on. - */ - pageURL: string; - /** - * URL of the subframe that the context menu was invoked on. - */ - frameURL: string; - /** - * Source URL for the element that the context menu was invoked on. Elements with - * source URLs are images, audio and video. - */ - srcURL: string; - /** - * Type of the node the context menu was invoked on. Can be `none`, `image`, - * `audio`, `video`, `canvas`, `file` or `plugin`. - */ - mediaType: ('none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'); - /** - * Whether the context menu was invoked on an image which has non-empty contents. - */ - hasImageContents: boolean; - /** - * Whether the context is editable. - */ - isEditable: boolean; - /** - * Text of the selection that the context menu was invoked on. - */ - selectionText: string; - /** - * Title text of the selection that the context menu was invoked on. - */ - titleText: string; - /** - * Alt text of the selection that the context menu was invoked on. - */ - altText: string; - /** - * Suggested filename to be used when saving file through 'Save Link As' option of - * context menu. - */ - suggestedFilename: string; - /** - * Rect representing the coordinates in the document space of the selection. - */ - selectionRect: Rectangle; - /** - * Start position of the selection text. - */ - selectionStartOffset: number; - /** - * The referrer policy of the frame on which the menu is invoked. - */ - referrerPolicy: Referrer; - /** - * The misspelled word under the cursor, if any. - */ - misspelledWord: string; - /** - * An array of suggested words to show the user to replace the `misspelledWord`. - * Only available if there is a misspelled word and spellchecker is enabled. - */ - dictionarySuggestions: string[]; - /** - * The character encoding of the frame on which the menu was invoked. - */ - frameCharset: string; - /** - * If the context menu was invoked on an input field, the type of that field. - * Possible values are `none`, `plainText`, `password`, `other`. - */ - inputFieldType: string; - /** - * If the context is editable, whether or not spellchecking is enabled. - */ - spellcheckEnabled: boolean; - /** - * Input source that invoked the context menu. Can be `none`, `mouse`, `keyboard`, - * `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, - * `adjustSelection`, or `adjustSelectionReset`. - */ - menuSourceType: ('none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu' | 'longPress' | 'longTap' | 'touchHandle' | 'stylus' | 'adjustSelection' | 'adjustSelectionReset'); - /** - * The flags for the media element the context menu was invoked on. - */ - mediaFlags: MediaFlags; - /** - * These flags indicate whether the renderer believes it is able to perform the - * corresponding action. - */ - editFlags: EditFlags; - } - - interface ContinueActivityDetails { - /** - * A string identifying the URL of the webpage accessed by the activity on another - * device, if available. - */ - webpageURL?: string; - } - - interface CookiesGetFilter { - /** - * Retrieves cookies which are associated with `url`. Empty implies retrieving - * cookies of all URLs. - */ - url?: string; - /** - * Filters cookies by name. - */ - name?: string; - /** - * Retrieves cookies whose domains match or are subdomains of `domains`. - */ - domain?: string; - /** - * Retrieves cookies whose path matches `path`. - */ - path?: string; - /** - * Filters cookies by their Secure property. - */ - secure?: boolean; - /** - * Filters out session or persistent cookies. - */ - session?: boolean; - } - - interface CookiesSetDetails { - /** - * The URL to associate the cookie with. The promise will be rejected if the URL is - * invalid. - */ - url: string; - /** - * The name of the cookie. Empty by default if omitted. - */ - name?: string; - /** - * The value of the cookie. Empty by default if omitted. - */ - value?: string; - /** - * The domain of the cookie; this will be normalized with a preceding dot so that - * it's also valid for subdomains. Empty by default if omitted. - */ - domain?: string; - /** - * The path of the cookie. Empty by default if omitted. - */ - path?: string; - /** - * Whether the cookie should be marked as Secure. Defaults to false unless Same - * Site=None attribute is used. - */ - secure?: boolean; - /** - * Whether the cookie should be marked as HTTP only. Defaults to false. - */ - httpOnly?: boolean; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * If omitted then the cookie becomes a session cookie and will not be retained - * between sessions. - */ - expirationDate?: number; - /** - * The Same Site policy to apply to this cookie. Can be `unspecified`, - * `no_restriction`, `lax` or `strict`. Default is `lax`. - */ - sameSite?: ('unspecified' | 'no_restriction' | 'lax' | 'strict'); - } - - interface CrashReporterStartOptions { - /** - * URL that crash reports will be sent to as POST. Required unless `uploadToServer` - * is `false`. - */ - submitURL?: string; - /** - * Defaults to `app.name`. - */ - productName?: string; - /** - * Deprecated alias for `{ globalExtra: { _companyName: ... } }`. - * - * @deprecated - */ - companyName?: string; - /** - * Whether crash reports should be sent to the server. If false, crash reports will - * be collected and stored in the crashes directory, but not uploaded. Default is - * `true`. - */ - uploadToServer?: boolean; - /** - * If true, crashes generated in the main process will not be forwarded to the - * system crash handler. Default is `false`. - */ - ignoreSystemCrashHandler?: boolean; - /** - * If true, limit the number of crashes uploaded to 1/hour. Default is `false`. - * - * @platform darwin,win32 - */ - rateLimit?: boolean; - /** - * If true, crash reports will be compressed and uploaded with `Content-Encoding: - * gzip`. Default is `true`. - */ - compress?: boolean; - /** - * Extra string key/value annotations that will be sent along with crash reports - * that are generated in the main process. Only string values are supported. - * Crashes generated in child processes will not contain these extra parameters to - * crash reports generated from child processes, call `addExtraParameter` from the - * child process. - */ - extra?: Record<string, string>; - /** - * Extra string key/value annotations that will be sent along with any crash - * reports generated in any process. These annotations cannot be changed once the - * crash reporter has been started. If a key is present in both the global extra - * parameters and the process-specific extra parameters, then the global one will - * take precedence. By default, `productName` and the app version are included, as - * well as the Electron version. - */ - globalExtra?: Record<string, string>; - } - - interface CreateFromBitmapOptions { - width: number; - height: number; - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface CreateFromBufferOptions { - /** - * Required for bitmap buffers. - */ - width?: number; - /** - * Required for bitmap buffers. - */ - height?: number; - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface CreateInterruptedDownloadOptions { - /** - * Absolute path of the download. - */ - path: string; - /** - * Complete URL chain for the download. - */ - urlChain: string[]; - mimeType?: string; - /** - * Start range for the download. - */ - offset: number; - /** - * Total length of the download. - */ - length: number; - /** - * Last-Modified header value. - */ - lastModified?: string; - /** - * ETag header value. - */ - eTag?: string; - /** - * Time when download was started in number of seconds since UNIX epoch. - */ - startTime?: number; - } - - interface Data { - text?: string; - html?: string; - image?: NativeImage; - rtf?: string; - /** - * The title of the URL at `text`. - */ - bookmark?: string; - } - - interface Details { - /** - * Process type. One of the following values: - */ - type: ('Utility' | 'Zygote' | 'Sandbox helper' | 'GPU' | 'Pepper Plugin' | 'Pepper Plugin Broker' | 'Unknown'); - /** - * The reason the child process is gone. Possible values: - */ - reason: ('clean-exit' | 'abnormal-exit' | 'killed' | 'crashed' | 'oom' | 'launch-failed' | 'integrity-failure'); - /** - * The exit code for the process (e.g. status from waitpid if on posix, from - * GetExitCodeProcess on Windows). - */ - exitCode: number; - /** - * The non-localized name of the process. - */ - serviceName?: string; - /** - * The name of the process. Examples for utility: `Audio Service`, `Content - * Decryption Module Service`, `Network Service`, `Video Capture`, etc. - */ - name?: string; - } - - interface DevicePermissionHandlerHandlerDetails { - /** - * The type of device that permission is being requested on, can be `hid` or - * `serial`. - */ - deviceType: ('hid' | 'serial'); - /** - * The origin URL of the device permission check. - */ - origin: string; - /** - * the device that permission is being requested for. - */ - device: (HIDDevice) | (SerialPort); - /** - * WebFrameMain checking the device permission. - */ - frame: WebFrameMain; - } - - interface DidChangeThemeColorEvent extends Event { - themeColor: string; - } - - interface DidCreateWindowDetails { - /** - * URL for the created window. - */ - url: string; - /** - * Name given to the created window in the `window.open()` call. - */ - frameName: string; - /** - * The options used to create the BrowserWindow. They are merged in increasing - * precedence: parsed options from the `features` string from `window.open()`, - * security-related webPreferences inherited from the parent, and options given by - * `webContents.setWindowOpenHandler`. Unrecognized options are not filtered out. - */ - options: BrowserWindowConstructorOptions; - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer; - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody?: PostBody; - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); - } - - interface DidFailLoadEvent extends Event { - errorCode: number; - errorDescription: string; - validatedURL: string; - isMainFrame: boolean; - } - - interface DidFrameFinishLoadEvent extends Event { - isMainFrame: boolean; - } - - interface DidFrameNavigateEvent extends Event { - url: string; - /** - * -1 for non HTTP navigations - */ - httpResponseCode: number; - /** - * empty for non HTTP navigations, - */ - httpStatusText: string; - isMainFrame: boolean; - frameProcessId: number; - frameRoutingId: number; - } - - interface DidNavigateEvent extends Event { - url: string; - } - - interface DidNavigateInPageEvent extends Event { - isMainFrame: boolean; - url: string; - } - - interface DidRedirectNavigationEvent extends Event { - url: string; - isInPlace: boolean; - isMainFrame: boolean; - frameProcessId: number; - frameRoutingId: number; - } - - interface DidStartNavigationEvent extends Event { - url: string; - isInPlace: boolean; - isMainFrame: boolean; - frameProcessId: number; - frameRoutingId: number; - } - - interface DisplayBalloonOptions { - /** - * Icon to use when `iconType` is `custom`. - */ - icon?: (NativeImage) | (string); - /** - * Can be `none`, `info`, `warning`, `error` or `custom`. Default is `custom`. - */ - iconType?: ('none' | 'info' | 'warning' | 'error' | 'custom'); - title: string; - content: string; - /** - * The large version of the icon should be used. Default is `true`. Maps to - * `NIIF_LARGE_ICON`. - */ - largeIcon?: boolean; - /** - * Do not play the associated sound. Default is `false`. Maps to `NIIF_NOSOUND`. - */ - noSound?: boolean; - /** - * Do not display the balloon notification if the current user is in "quiet time". - * Default is `false`. Maps to `NIIF_RESPECT_QUIET_TIME`. - */ - respectQuietTime?: boolean; - } - - interface EnableNetworkEmulationOptions { - /** - * Whether to emulate network outage. Defaults to false. - */ - offline?: boolean; - /** - * RTT in ms. Defaults to 0 which will disable latency throttling. - */ - latency?: number; - /** - * Download rate in Bps. Defaults to 0 which will disable download throttling. - */ - downloadThroughput?: number; - /** - * Upload rate in Bps. Defaults to 0 which will disable upload throttling. - */ - uploadThroughput?: number; - } - - interface FeedURLOptions { - url: string; - /** - * HTTP request headers. - * - * @platform darwin - */ - headers?: Record<string, string>; - /** - * Can be `json` or `default`, see the Squirrel.Mac README for more information. - * - * @platform darwin - */ - serverType?: ('json' | 'default'); - } - - interface FileIconOptions { - size: ('small' | 'normal' | 'large'); - } - - interface FindInPageOptions { - /** - * Whether to search forward or backward, defaults to `true`. - */ - forward?: boolean; - /** - * Whether to begin a new text finding session with this request. Should be `true` - * for initial requests, and `false` for follow-up requests. Defaults to `false`. - */ - findNext?: boolean; - /** - * Whether search should be case-sensitive, defaults to `false`. - */ - matchCase?: boolean; - } - - interface FocusOptions { - /** - * Make the receiver the active app even if another app is currently active. - * - * @platform darwin - */ - steal: boolean; - } - - interface FoundInPageEvent extends Event { - result: FoundInPageResult; - } - - interface FrameCreatedDetails { - frame: WebFrameMain; - } - - interface FromPartitionOptions { - /** - * Whether to enable cache. - */ - cache: boolean; - } - - interface HandlerDetails { - /** - * The _resolved_ version of the URL passed to `window.open()`. e.g. opening a - * window with `window.open('foo')` will yield something like - * `https://the-origin/the/current/path/foo`. - */ - url: string; - /** - * Name of the window provided in `window.open()` - */ - frameName: string; - /** - * Comma separated list of window features provided to `window.open()`. - */ - features: string; - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` or `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer; - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody?: PostBody; - } - - interface HeadersReceivedResponse { - cancel?: boolean; - /** - * When provided, the server is assumed to have responded with these headers. - */ - responseHeaders?: Record<string, (string) | (string[])>; - /** - * Should be provided when overriding `responseHeaders` to change header status - * otherwise original response header's status will be used. - */ - statusLine?: string; - } - - interface HeapStatistics { - totalHeapSize: number; - totalHeapSizeExecutable: number; - totalPhysicalSize: number; - totalAvailableSize: number; - usedHeapSize: number; - heapSizeLimit: number; - mallocedMemory: number; - peakMallocedMemory: number; - doesZapGarbage: boolean; - } - - interface HidDeviceAddedDetails { - device: HIDDevice[]; - frame: WebFrameMain; - } - - interface HidDeviceRemovedDetails { - device: HIDDevice[]; - frame: WebFrameMain; - } - - interface IgnoreMouseEventsOptions { - /** - * If true, forwards mouse move messages to Chromium, enabling mouse related events - * such as `mouseleave`. Only used when `ignore` is true. If `ignore` is false, - * forwarding is always disabled regardless of this value. - * - * @platform darwin,win32 - */ - forward?: boolean; - } - - interface ImportCertificateOptions { - /** - * Path for the pkcs12 file. - */ - certificate: string; - /** - * Passphrase for the certificate. - */ - password: string; - } - - interface Info { - /** - * Security origin for the isolated world. - */ - securityOrigin?: string; - /** - * Content Security Policy for the isolated world. - */ - csp?: string; - /** - * Name for isolated world. Useful in devtools. - */ - name?: string; - } - - interface Input { - /** - * Either `keyUp` or `keyDown`. - */ - type: string; - /** - * Equivalent to KeyboardEvent.key. - */ - key: string; - /** - * Equivalent to KeyboardEvent.code. - */ - code: string; - /** - * Equivalent to KeyboardEvent.repeat. - */ - isAutoRepeat: boolean; - /** - * Equivalent to KeyboardEvent.isComposing. - */ - isComposing: boolean; - /** - * Equivalent to KeyboardEvent.shiftKey. - */ - shift: boolean; - /** - * Equivalent to KeyboardEvent.controlKey. - */ - control: boolean; - /** - * Equivalent to KeyboardEvent.altKey. - */ - alt: boolean; - /** - * Equivalent to KeyboardEvent.metaKey. - */ - meta: boolean; - /** - * Equivalent to KeyboardEvent.location. - */ - location: number; - /** - * See InputEvent.modifiers. - */ - modifiers: string[]; - } - - interface InsertCSSOptions { - /** - * Can be either 'user' or 'author'. Sets the cascade origin of the inserted - * stylesheet. Default is 'author'. - */ - cssOrigin?: string; - } - - interface IpcMessageEvent extends Event { - /** - * pair of `[processId, frameId]`. - */ - frameId: [number, number]; - channel: string; - args: any[]; - } - - interface Item { - /** - * The path to the file being dragged. - */ - file: string; - /** - * The paths to the files being dragged. (`files` will override `file` field) - */ - files?: string[]; - /** - * The image must be non-empty on macOS. - */ - icon: (NativeImage) | (string); - } - - interface JumpListSettings { - /** - * The minimum number of items that will be shown in the Jump List (for a more - * detailed description of this value see the MSDN docs). - */ - minItems: number; - /** - * Array of `JumpListItem` objects that correspond to items that the user has - * explicitly removed from custom categories in the Jump List. These items must not - * be re-added to the Jump List in the **next** call to `app.setJumpList()`, - * Windows will not display any custom category that contains any of the removed - * items. - */ - removedItems: JumpListItem[]; - } - - interface LoadCommitEvent extends Event { - url: string; - isMainFrame: boolean; - } - - interface LoadExtensionOptions { - /** - * Whether to allow the extension to read local files over `file://` protocol and - * inject content scripts into `file://` pages. This is required e.g. for loading - * devtools extensions on `file://` URLs. Defaults to false. - */ - allowFileAccess: boolean; - } - - interface LoadFileOptions { - /** - * Passed to `url.format()`. - */ - query?: Record<string, string>; - /** - * Passed to `url.format()`. - */ - search?: string; - /** - * Passed to `url.format()`. - */ - hash?: string; - } - - interface LoadURLOptions { - /** - * An HTTP Referrer url. - */ - httpReferrer?: (string) | (Referrer); - /** - * A user agent originating the request. - */ - userAgent?: string; - /** - * Extra headers separated by "\n" - */ - extraHeaders?: string; - postData?: Array<(UploadRawData) | (UploadFile)>; - /** - * Base url (with trailing path separator) for files to be loaded by the data url. - * This is needed only if the specified `url` is a data url and needs to load other - * files. - */ - baseURLForDataURL?: string; - } - - interface LoginItemSettings { - /** - * `true` if the app is set to open at login. - */ - openAtLogin: boolean; - /** - * `true` if the app is set to open as hidden at login. This setting is not - * available on MAS builds. - * - * @platform darwin - */ - openAsHidden: boolean; - /** - * `true` if the app was opened at login automatically. This setting is not - * available on MAS builds. - * - * @platform darwin - */ - wasOpenedAtLogin: boolean; - /** - * `true` if the app was opened as a hidden login item. This indicates that the app - * should not open any windows at startup. This setting is not available on MAS - * builds. - * - * @platform darwin - */ - wasOpenedAsHidden: boolean; - /** - * `true` if the app was opened as a login item that should restore the state from - * the previous session. This indicates that the app should restore the windows - * that were open the last time the app was closed. This setting is not available - * on MAS builds. - * - * @platform darwin - */ - restoreState: boolean; - /** - * `true` if app is set to open at login and its run key is not deactivated. This - * differs from `openAtLogin` as it ignores the `args` option, this property will - * be true if the given executable would be launched at login with **any** - * arguments. - * - * @platform win32 - */ - executableWillLaunchAtLogin: boolean; - launchItems: LaunchItems[]; - } - - interface LoginItemSettingsOptions { - /** - * The executable path to compare against. Defaults to `process.execPath`. - * - * @platform win32 - */ - path?: string; - /** - * The command-line arguments to compare against. Defaults to an empty array. - * - * @platform win32 - */ - args?: string[]; - } - - interface MenuItemConstructorOptions { - /** - * Will be called with `click(menuItem, browserWindow, event)` when the menu item - * is clicked. - */ - click?: (menuItem: MenuItem, browserWindow: (BrowserWindow) | (undefined), event: KeyboardEvent) => void; - /** - * Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, - * `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, - * `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, - * `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, - * 'showSubstitutions', 'toggleSmartQuotes', 'toggleSmartDashes', - * 'toggleTextReplacement', `startSpeaking`, `stopSpeaking`, `zoom`, `front`, - * `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, - * `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, - * `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action - * of the menu item, when specified the `click` property will be ignored. See - * roles. - */ - role?: ('undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'toggleSpellChecker' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'showSubstitutions' | 'toggleSmartQuotes' | 'toggleSmartDashes' | 'toggleTextReplacement' | 'startSpeaking' | 'stopSpeaking' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'shareMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'); - /** - * Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. - */ - type?: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'); - label?: string; - sublabel?: string; - /** - * Hover text for this menu item. - * - * @platform darwin - */ - toolTip?: string; - accelerator?: Accelerator; - icon?: (NativeImage) | (string); - /** - * If false, the menu item will be greyed out and unclickable. - */ - enabled?: boolean; - /** - * default is `true`, and when `false` will prevent the accelerator from triggering - * the item if the item is not visible`. - * - * @platform darwin - */ - acceleratorWorksWhenHidden?: boolean; - /** - * If false, the menu item will be entirely hidden. - */ - visible?: boolean; - /** - * Should only be specified for `checkbox` or `radio` type menu items. - */ - checked?: boolean; - /** - * If false, the accelerator won't be registered with the system, but it will still - * be displayed. Defaults to true. - * - * @platform linux,win32 - */ - registerAccelerator?: boolean; - /** - * The item to share when the `role` is `shareMenu`. - * - * @platform darwin - */ - sharingItem?: SharingItem; - /** - * Should be specified for `submenu` type menu items. If `submenu` is specified, - * the `type: 'submenu'` can be omitted. If the value is not a `Menu` then it will - * be automatically converted to one using `Menu.buildFromTemplate`. - */ - submenu?: (MenuItemConstructorOptions[]) | (Menu); - /** - * Unique within a single menu. If defined then it can be used as a reference to - * this item by the position attribute. - */ - id?: string; - /** - * Inserts this item before the item with the specified label. If the referenced - * item doesn't exist the item will be inserted at the end of the menu. Also - * implies that the menu item in question should be placed in the same β€œgroup” as - * the item. - */ - before?: string[]; - /** - * Inserts this item after the item with the specified label. If the referenced - * item doesn't exist the item will be inserted at the end of the menu. - */ - after?: string[]; - /** - * Provides a means for a single context menu to declare the placement of their - * containing group before the containing group of the item with the specified - * label. - */ - beforeGroupContaining?: string[]; - /** - * Provides a means for a single context menu to declare the placement of their - * containing group after the containing group of the item with the specified - * label. - */ - afterGroupContaining?: string[]; - } - - interface MessageBoxOptions { - /** - * Content of the message box. - */ - message: string; - /** - * Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, - * `"question"` displays the same icon as `"info"`, unless you set an icon using - * the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same - * warning icon. - */ - type?: string; - /** - * Array of texts for buttons. On Windows, an empty array will result in one button - * labeled "OK". - */ - buttons?: string[]; - /** - * Index of the button in the buttons array which will be selected by default when - * the message box opens. - */ - defaultId?: number; - /** - * Pass an instance of AbortSignal to optionally close the message box, the message - * box will behave as if it was cancelled by the user. On macOS, `signal` does not - * work with message boxes that do not have a parent window, since those message - * boxes run synchronously due to platform limitations. - */ - signal?: AbortSignal; - /** - * Title of the message box, some platforms will not show it. - */ - title?: string; - /** - * Extra information of the message. - */ - detail?: string; - /** - * If provided, the message box will include a checkbox with the given label. - */ - checkboxLabel?: string; - /** - * Initial checked state of the checkbox. `false` by default. - */ - checkboxChecked?: boolean; - icon?: (NativeImage) | (string); - /** - * Custom width of the text in the message box. - * - * @platform darwin - */ - textWidth?: number; - /** - * The index of the button to be used to cancel the dialog, via the `Esc` key. By - * default this is assigned to the first button with "cancel" or "no" as the label. - * If no such labeled buttons exist and this option is not set, `0` will be used as - * the return value. - */ - cancelId?: number; - /** - * On Windows Electron will try to figure out which one of the `buttons` are common - * buttons (like "Cancel" or "Yes"), and show the others as command links in the - * dialog. This can make the dialog appear in the style of modern Windows apps. If - * you don't like this behavior, you can set `noLink` to `true`. - */ - noLink?: boolean; - /** - * Normalize the keyboard access keys across platforms. Default is `false`. - * Enabling this assumes `&` is used in the button labels for the placement of the - * keyboard shortcut access key and labels will be converted so they work correctly - * on each platform, `&` characters are removed on macOS, converted to `_` on - * Linux, and left untouched on Windows. For example, a button label of `Vie&w` - * will be converted to `Vie_w` on Linux and `View` on macOS and can be selected - * via `Alt-W` on Windows and Linux. - */ - normalizeAccessKeys?: boolean; - } - - interface MessageBoxReturnValue { - /** - * The index of the clicked button. - */ - response: number; - /** - * The checked state of the checkbox if `checkboxLabel` was set. Otherwise `false`. - */ - checkboxChecked: boolean; - } - - interface MessageBoxSyncOptions { - /** - * Content of the message box. - */ - message: string; - /** - * Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, - * `"question"` displays the same icon as `"info"`, unless you set an icon using - * the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same - * warning icon. - */ - type?: string; - /** - * Array of texts for buttons. On Windows, an empty array will result in one button - * labeled "OK". - */ - buttons?: string[]; - /** - * Index of the button in the buttons array which will be selected by default when - * the message box opens. - */ - defaultId?: number; - /** - * Title of the message box, some platforms will not show it. - */ - title?: string; - /** - * Extra information of the message. - */ - detail?: string; - icon?: (NativeImage) | (string); - /** - * Custom width of the text in the message box. - * - * @platform darwin - */ - textWidth?: number; - /** - * The index of the button to be used to cancel the dialog, via the `Esc` key. By - * default this is assigned to the first button with "cancel" or "no" as the label. - * If no such labeled buttons exist and this option is not set, `0` will be used as - * the return value. - */ - cancelId?: number; - /** - * On Windows Electron will try to figure out which one of the `buttons` are common - * buttons (like "Cancel" or "Yes"), and show the others as command links in the - * dialog. This can make the dialog appear in the style of modern Windows apps. If - * you don't like this behavior, you can set `noLink` to `true`. - */ - noLink?: boolean; - /** - * Normalize the keyboard access keys across platforms. Default is `false`. - * Enabling this assumes `&` is used in the button labels for the placement of the - * keyboard shortcut access key and labels will be converted so they work correctly - * on each platform, `&` characters are removed on macOS, converted to `_` on - * Linux, and left untouched on Windows. For example, a button label of `Vie&w` - * will be converted to `Vie_w` on Linux and `View` on macOS and can be selected - * via `Alt-W` on Windows and Linux. - */ - normalizeAccessKeys?: boolean; - } - - interface MessageDetails { - /** - * The actual console message - */ - message: string; - /** - * The version ID of the service worker that sent the log message - */ - versionId: number; - /** - * The type of source for this message. Can be `javascript`, `xml`, `network`, - * `console-api`, `storage`, `rendering`, `security`, `deprecation`, `worker`, - * `violation`, `intervention`, `recommendation` or `other`. - */ - source: ('javascript' | 'xml' | 'network' | 'console-api' | 'storage' | 'rendering' | 'security' | 'deprecation' | 'worker' | 'violation' | 'intervention' | 'recommendation' | 'other'); - /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. - */ - level: number; - /** - * The URL the message came from - */ - sourceUrl: string; - /** - * The line number of the source that triggered this console message - */ - lineNumber: number; - } - - interface MessageEvent { - data: any; - ports: MessagePortMain[]; - } - - interface MoveToApplicationsFolderOptions { - /** - * A handler for potential conflict in move failure. - */ - conflictHandler?: (conflictType: 'exists' | 'existsAndRunning') => boolean; - } - - interface NewWindowEvent extends Event { - url: string; - frameName: string; - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); - /** - * The options which should be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions; - } - - interface NotificationConstructorOptions { - /** - * A title for the notification, which will be shown at the top of the notification - * window when it is shown. - */ - title?: string; - /** - * A subtitle for the notification, which will be displayed below the title. - * - * @platform darwin - */ - subtitle?: string; - /** - * The body text of the notification, which will be displayed below the title or - * subtitle. - */ - body?: string; - /** - * Whether or not to emit an OS notification noise when showing the notification. - */ - silent?: boolean; - /** - * An icon to use in the notification. - */ - icon?: (string) | (NativeImage); - /** - * Whether or not to add an inline reply option to the notification. - * - * @platform darwin - */ - hasReply?: boolean; - /** - * The timeout duration of the notification. Can be 'default' or 'never'. - * - * @platform linux,win32 - */ - timeoutType?: ('default' | 'never'); - /** - * The placeholder to write in the inline reply input field. - * - * @platform darwin - */ - replyPlaceholder?: string; - /** - * The name of the sound file to play when the notification is shown. - * - * @platform darwin - */ - sound?: string; - /** - * The urgency level of the notification. Can be 'normal', 'critical', or 'low'. - * - * @platform linux - */ - urgency?: ('normal' | 'critical' | 'low'); - /** - * Actions to add to the notification. Please read the available actions and - * limitations in the `NotificationAction` documentation. - * - * @platform darwin - */ - actions?: NotificationAction[]; - /** - * A custom title for the close button of an alert. An empty string will cause the - * default localized text to be used. - * - * @platform darwin - */ - closeButtonText?: string; - /** - * A custom description of the Notification on Windows superseding all properties - * above. Provides full customization of design and behavior of the notification. - * - * @platform win32 - */ - toastXml?: string; - } - - interface OnBeforeRedirectListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - redirectURL: string; - statusCode: number; - statusLine: string; - /** - * The server IP address that the request was actually sent to. - */ - ip?: string; - fromCache: boolean; - responseHeaders?: Record<string, string[]>; - } - - interface OnBeforeRequestListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - uploadData: UploadData[]; - } - - interface OnBeforeSendHeadersListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - uploadData?: UploadData[]; - requestHeaders: Record<string, string>; - } - - interface OnCompletedListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - responseHeaders?: Record<string, string[]>; - fromCache: boolean; - statusCode: number; - statusLine: string; - error: string; - } - - interface OnErrorOccurredListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - fromCache: boolean; - /** - * The error description. - */ - error: string; - } - - interface OnHeadersReceivedListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - statusLine: string; - statusCode: number; - responseHeaders?: Record<string, string[]>; - } - - interface OnResponseStartedListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - responseHeaders?: Record<string, string[]>; - /** - * Indicates whether the response was fetched from disk cache. - */ - fromCache: boolean; - statusCode: number; - statusLine: string; - } - - interface OnSendHeadersListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - /** - * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, - * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. - */ - resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); - referrer: string; - timestamp: number; - requestHeaders: Record<string, string>; - } - - interface OpenDevToolsOptions { - /** - * Opens the devtools with specified dock state, can be `left`, `right`, `bottom`, - * `undocked`, `detach`. Defaults to last used dock state. In `undocked` mode it's - * possible to dock back. In `detach` mode it's not. - */ - mode: ('left' | 'right' | 'bottom' | 'undocked' | 'detach'); - /** - * Whether to bring the opened devtools window to the foreground. The default is - * `true`. - */ - activate?: boolean; - } - - interface OpenDialogOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Contains which features the dialog should use. The following values are - * supported: - */ - properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory' | 'dontAddToRecent'>; - /** - * Message to display above input boxes. - * - * @platform darwin - */ - message?: string; - /** - * Create security scoped bookmarks when packaged for the Mac App Store. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface OpenDialogReturnValue { - /** - * whether or not the dialog was canceled. - */ - canceled: boolean; - /** - * An array of file paths chosen by the user. If the dialog is cancelled this will - * be an empty array. - */ - filePaths: string[]; - /** - * An array matching the `filePaths` array of base64 encoded strings which contains - * security scoped bookmark data. `securityScopedBookmarks` must be enabled for - * this to be populated. (For return values, see table here.) - * - * @platform darwin,mas - */ - bookmarks?: string[]; - } - - interface OpenDialogSyncOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Contains which features the dialog should use. The following values are - * supported: - */ - properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory' | 'dontAddToRecent'>; - /** - * Message to display above input boxes. - * - * @platform darwin - */ - message?: string; - /** - * Create security scoped bookmarks when packaged for the Mac App Store. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface OpenExternalOptions { - /** - * `true` to bring the opened application to the foreground. The default is `true`. - * - * @platform darwin - */ - activate?: boolean; - /** - * The working directory. - * - * @platform win32 - */ - workingDirectory?: string; - } - - interface Options { - } - - interface PageFaviconUpdatedEvent extends Event { - /** - * Array of URLs. - */ - favicons: string[]; - } - - interface PageTitleUpdatedEvent extends Event { - title: string; - explicitSet: boolean; - } - - interface Parameters { - /** - * Specify the screen type to emulate (default: `desktop`): - */ - screenPosition: ('desktop' | 'mobile'); - /** - * Set the emulated screen size (screenPosition == mobile). - */ - screenSize: Size; - /** - * Position the view on the screen (screenPosition == mobile) (default: `{ x: 0, y: - * 0 }`). - */ - viewPosition: Point; - /** - * Set the device scale factor (if zero defaults to original device scale factor) - * (default: `0`). - */ - deviceScaleFactor: number; - /** - * Set the emulated view size (empty means no override) - */ - viewSize: Size; - /** - * Scale of emulated view inside available space (not in fit to view mode) - * (default: `1`). - */ - scale: number; - } - - interface Payment { - /** - * The identifier of the purchased product. - */ - productIdentifier: string; - /** - * The quantity purchased. - */ - quantity: number; - /** - * An opaque identifier for the user’s account on your system. - */ - applicationUsername: string; - /** - * The details of the discount offer to apply to the payment. - */ - paymentDiscount?: PaymentDiscount; - } - - interface PermissionCheckHandlerHandlerDetails { - /** - * The origin of the frame embedding the frame that made the permission check. - * Only set for cross-origin sub frames making permission checks. - */ - embeddingOrigin?: string; - /** - * The security origin of the `media` check. - */ - securityOrigin?: string; - /** - * The type of media access being requested, can be `video`, `audio` or `unknown` - */ - mediaType?: ('video' | 'audio' | 'unknown'); - /** - * The last URL the requesting frame loaded. This is not provided for cross-origin - * sub frames making permission checks. - */ - requestingUrl?: string; - /** - * Whether the frame making the request is the main frame - */ - isMainFrame: boolean; - } - - interface PermissionRequestHandlerHandlerDetails { - /** - * The url of the `openExternal` request. - */ - externalURL?: string; - /** - * The security origin of the `media` request. - */ - securityOrigin?: string; - /** - * The types of media access being requested, elements can be `video` or `audio` - */ - mediaTypes?: Array<'video' | 'audio'>; - /** - * The last URL the requesting frame loaded - */ - requestingUrl: string; - /** - * Whether the frame making the request is the main frame - */ - isMainFrame: boolean; - } - - interface PluginCrashedEvent extends Event { - name: string; - version: string; - } - - interface PopupOptions { - /** - * Default is the focused window. - */ - window?: BrowserWindow; - /** - * Default is the current mouse cursor position. Must be declared if `y` is - * declared. - */ - x?: number; - /** - * Default is the current mouse cursor position. Must be declared if `x` is - * declared. - */ - y?: number; - /** - * The index of the menu item to be positioned under the mouse cursor at the - * specified coordinates. Default is -1. - * - * @platform darwin - */ - positioningItem?: number; - /** - * Called when menu is closed. - */ - callback?: () => void; - } - - interface PreconnectOptions { - /** - * URL for preconnect. Only the origin is relevant for opening the socket. - */ - url: string; - /** - * number of sockets to preconnect. Must be between 1 and 6. Defaults to 1. - */ - numSockets?: number; - } - - interface PrintToPDFOptions { - /** - * the header and footer for the PDF. - */ - headerFooter?: Record<string, string>; - /** - * `true` for landscape, `false` for portrait. - */ - landscape?: boolean; - /** - * 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. - */ - marginsType?: number; - /** - * The scale factor of the web page. Can range from 0 to 100. - */ - scaleFactor?: number; - /** - * The page range to print. On macOS, only the first range is honored. - */ - pageRanges?: Record<string, number>; - /** - * Specify page size of the generated PDF. Can be `A3`, `A4`, `A5`, `Legal`, - * `Letter`, `Tabloid` or an Object containing `height` - */ - pageSize?: (string) | (Size); - /** - * Whether to print CSS backgrounds. - */ - printBackground?: boolean; - /** - * Whether to print selection only. - */ - printSelectionOnly?: boolean; - } - - interface Privileges { - /** - * Default false. - */ - standard?: boolean; - /** - * Default false. - */ - secure?: boolean; - /** - * Default false. - */ - bypassCSP?: boolean; - /** - * Default false. - */ - allowServiceWorkers?: boolean; - /** - * Default false. - */ - supportFetchAPI?: boolean; - /** - * Default false. - */ - corsEnabled?: boolean; - /** - * Default false. - */ - stream?: boolean; - } - - interface ProgressBarOptions { - /** - * Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or - * `paused`. - * - * @platform win32 - */ - mode: ('none' | 'normal' | 'indeterminate' | 'error' | 'paused'); - } - - interface Provider { - spellCheck: (words: string[], callback: (misspeltWords: string[]) => void) => void; - } - - interface ReadBookmark { - title: string; - url: string; - } - - interface RegistrationCompletedDetails { - /** - * The base URL that a service worker is registered for - */ - scope: string; - } - - interface RelaunchOptions { - args?: string[]; - execPath?: string; - } - - interface RenderProcessGoneDetails { - /** - * The reason the render process is gone. Possible values: - */ - reason: ('clean-exit' | 'abnormal-exit' | 'killed' | 'crashed' | 'oom' | 'launch-failed' | 'integrity-failure'); - /** - * The exit code of the process, unless `reason` is `launch-failed`, in which case - * `exitCode` will be a platform-specific launch failure error code. - */ - exitCode: number; - } - - interface Request { - hostname: string; - certificate: Certificate; - validatedCertificate: Certificate; - /** - * `true` if Chromium recognises the root CA as a standard root. If it isn't then - * it's probably the case that this certificate was generated by a MITM proxy whose - * root has been installed locally (for example, by a corporate proxy). This should - * not be trusted if the `verificationResult` is not `OK`. - */ - isIssuedByKnownRoot: boolean; - /** - * `OK` if the certificate is trusted, otherwise an error like `CERT_REVOKED`. - */ - verificationResult: string; - /** - * Error code. - */ - errorCode: number; - } - - interface ResizeOptions { - /** - * Defaults to the image's width. - */ - width?: number; - /** - * Defaults to the image's height. - */ - height?: number; - /** - * The desired quality of the resize image. Possible values are `good`, `better`, - * or `best`. The default is `best`. These values express a desired quality/speed - * tradeoff. They are translated into an algorithm-specific method that depends on - * the capabilities (CPU, GPU) of the underlying platform. It is possible for all - * three methods to be mapped to the same algorithm on a given platform. - */ - quality?: string; - } - - interface ResourceUsage { - images: MemoryUsageDetails; - scripts: MemoryUsageDetails; - cssStyleSheets: MemoryUsageDetails; - xslStyleSheets: MemoryUsageDetails; - fonts: MemoryUsageDetails; - other: MemoryUsageDetails; - } - - interface Response { - cancel?: boolean; - /** - * The original request is prevented from being sent or completed and is instead - * redirected to the given URL. - */ - redirectURL?: string; - } - - interface Result { - requestId: number; - /** - * Position of the active match. - */ - activeMatchOrdinal: number; - /** - * Number of Matches. - */ - matches: number; - /** - * Coordinates of first match region. - */ - selectionArea: Rectangle; - finalUpdate: boolean; - } - - interface SaveDialogOptions { - /** - * The dialog title. Cannot be displayed on some _Linux_ desktop environments. - */ - title?: string; - /** - * Absolute directory path, absolute file path, or file name to use by default. - */ - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Message to display above text fields. - * - * @platform darwin - */ - message?: string; - /** - * Custom label for the text displayed in front of the filename text field. - * - * @platform darwin - */ - nameFieldLabel?: string; - /** - * Show the tags input box, defaults to `true`. - * - * @platform darwin - */ - showsTagField?: boolean; - properties?: Array<'showHiddenFiles' | 'createDirectory' | 'treatPackageAsDirectory' | 'showOverwriteConfirmation' | 'dontAddToRecent'>; - /** - * Create a security scoped bookmark when packaged for the Mac App Store. If this - * option is enabled and the file doesn't already exist a blank file will be - * created at the chosen path. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface SaveDialogReturnValue { - /** - * whether or not the dialog was canceled. - */ - canceled: boolean; - /** - * If the dialog is canceled, this will be `undefined`. - */ - filePath?: string; - /** - * Base64 encoded string which contains the security scoped bookmark data for the - * saved file. `securityScopedBookmarks` must be enabled for this to be present. - * (For return values, see table here.) - * - * @platform darwin,mas - */ - bookmark?: string; - } - - interface SaveDialogSyncOptions { - /** - * The dialog title. Cannot be displayed on some _Linux_ desktop environments. - */ - title?: string; - /** - * Absolute directory path, absolute file path, or file name to use by default. - */ - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Message to display above text fields. - * - * @platform darwin - */ - message?: string; - /** - * Custom label for the text displayed in front of the filename text field. - * - * @platform darwin - */ - nameFieldLabel?: string; - /** - * Show the tags input box, defaults to `true`. - * - * @platform darwin - */ - showsTagField?: boolean; - properties?: Array<'showHiddenFiles' | 'createDirectory' | 'treatPackageAsDirectory' | 'showOverwriteConfirmation' | 'dontAddToRecent'>; - /** - * Create a security scoped bookmark when packaged for the Mac App Store. If this - * option is enabled and the file doesn't already exist a blank file will be - * created at the chosen path. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface SelectHidDeviceDetails { - deviceList: HIDDevice[]; - frame: WebFrameMain; - } - - interface Settings { - /** - * `true` to open the app at login, `false` to remove the app as a login item. - * Defaults to `false`. - */ - openAtLogin?: boolean; - /** - * `true` to open the app as hidden. Defaults to `false`. The user can edit this - * setting from the System Preferences so - * `app.getLoginItemSettings().wasOpenedAsHidden` should be checked when the app is - * opened to know the current value. This setting is not available on MAS builds. - * - * @platform darwin - */ - openAsHidden?: boolean; - /** - * The executable to launch at login. Defaults to `process.execPath`. - * - * @platform win32 - */ - path?: string; - /** - * The command-line arguments to pass to the executable. Defaults to an empty - * array. Take care to wrap paths in quotes. - * - * @platform win32 - */ - args?: string[]; - /** - * `true` will change the startup approved registry key and `enable / disable` the - * App in Task Manager and Windows Settings. Defaults to `true`. - * - * @platform win32 - */ - enabled?: boolean; - /** - * value name to write into registry. Defaults to the app's AppUserModelId(). Set - * the app's login item settings. - * - * @platform win32 - */ - name?: string; - } - - interface SourcesOptions { - /** - * An array of strings that lists the types of desktop sources to be captured, - * available types are `screen` and `window`. - */ - types: string[]; - /** - * The size that the media source thumbnail should be scaled to. Default is `150` x - * `150`. Set width or height to 0 when you do not need the thumbnails. This will - * save the processing time required for capturing the content of each window and - * screen. - */ - thumbnailSize?: Size; - /** - * Set to true to enable fetching window icons. The default value is false. When - * false the appIcon property of the sources return null. Same if a source has the - * type screen. - */ - fetchWindowIcons?: boolean; - } - - interface SSLConfigConfig { - /** - * Can be `tls1`, `tls1.1`, `tls1.2` or `tls1.3`. The minimum SSL version to allow - * when connecting to remote servers. Defaults to `tls1`. - */ - minVersion?: string; - /** - * Can be `tls1.2` or `tls1.3`. The maximum SSL version to allow when connecting to - * remote servers. Defaults to `tls1.3`. - */ - maxVersion?: string; - /** - * List of cipher suites which should be explicitly prevented from being used in - * addition to those disabled by the net built-in policy. Supported literal forms: - * 0xAABB, where AA is `cipher_suite[0]` and BB is `cipher_suite[1]`, as defined in - * RFC 2246, Section 7.4.1.2. Unrecognized but parsable cipher suites in this form - * will not return an error. Ex: To disable TLS_RSA_WITH_RC4_128_MD5, specify - * 0x0004, while to disable TLS_ECDH_ECDSA_WITH_RC4_128_SHA, specify 0xC002. Note - * that TLSv1.3 ciphers cannot be disabled using this mechanism. - */ - disabledCipherSuites?: number[]; - } - - interface StartLoggingOptions { - /** - * What kinds of data should be captured. By default, only metadata about requests - * will be captured. Setting this to `includeSensitive` will include cookies and - * authentication data. Setting it to `everything` will include all bytes - * transferred on sockets. Can be `default`, `includeSensitive` or `everything`. - */ - captureMode?: ('default' | 'includeSensitive' | 'everything'); - /** - * When the log grows beyond this size, logging will automatically stop. Defaults - * to unlimited. - */ - maxFileSize?: number; - } - - interface SystemMemoryInfo { - /** - * The total amount of physical memory in Kilobytes available to the system. - */ - total: number; - /** - * The total amount of memory not being used by applications or disk cache. - */ - free: number; - /** - * The total amount of swap memory in Kilobytes available to the system. - * - * @platform win32,linux - */ - swapTotal: number; - /** - * The free amount of swap memory in Kilobytes available to the system. - * - * @platform win32,linux - */ - swapFree: number; - } - - interface TitleBarOverlayOptions { - /** - * The CSS color of the Window Controls Overlay when enabled. - * - * @platform win32 - */ - color?: string; - /** - * The CSS color of the symbols on the Window Controls Overlay when enabled. - * - * @platform win32 - */ - symbolColor?: string; - /** - * The height of the title bar and Window Controls Overlay in pixels. - * - * @platform win32 - */ - height?: number; - } - - interface TitleOptions { - /** - * The font family variant to display, can be `monospaced` or `monospacedDigit`. - * `monospaced` is available in macOS 10.15+ and `monospacedDigit` is available in - * macOS 10.11+. When left blank, the title uses the default system font. - */ - fontType?: ('monospaced' | 'monospacedDigit'); - } - - interface ToBitmapOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface ToDataURLOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface ToPNGOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface TouchBarButtonConstructorOptions { - /** - * Button text. - */ - label?: string; - /** - * A short description of the button for use by screenreaders like VoiceOver. - */ - accessibilityLabel?: string; - /** - * Button background color in hex format, i.e `#ABCDEF`. - */ - backgroundColor?: string; - /** - * Button icon. - */ - icon?: (NativeImage) | (string); - /** - * Can be `left`, `right` or `overlay`. Defaults to `overlay`. - */ - iconPosition?: ('left' | 'right' | 'overlay'); - /** - * Function to call when the button is clicked. - */ - click?: () => void; - /** - * Whether the button is in an enabled state. Default is `true`. - */ - enabled?: boolean; - } - - interface TouchBarColorPickerConstructorOptions { - /** - * Array of hex color strings to appear as possible colors to select. - */ - availableColors?: string[]; - /** - * The selected hex color in the picker, i.e `#ABCDEF`. - */ - selectedColor?: string; - /** - * Function to call when a color is selected. - */ - change?: (color: string) => void; - } - - interface TouchBarConstructorOptions { - items?: Array<(TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer)>; - escapeItem?: (TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer) | (null); - } - - interface TouchBarGroupConstructorOptions { - /** - * Items to display as a group. - */ - items: TouchBar; - } - - interface TouchBarLabelConstructorOptions { - /** - * Text to display. - */ - label?: string; - /** - * A short description of the button for use by screenreaders like VoiceOver. - */ - accessibilityLabel?: string; - /** - * Hex color of text, i.e `#ABCDEF`. - */ - textColor?: string; - } - - interface TouchBarPopoverConstructorOptions { - /** - * Popover button text. - */ - label?: string; - /** - * Popover button icon. - */ - icon?: NativeImage; - /** - * Items to display in the popover. - */ - items: TouchBar; - /** - * `true` to display a close button on the left of the popover, `false` to not show - * it. Default is `true`. - */ - showCloseButton?: boolean; - } - - interface TouchBarScrubberConstructorOptions { - /** - * An array of items to place in this scrubber. - */ - items: ScrubberItem[]; - /** - * Called when the user taps an item that was not the last tapped item. - */ - select?: (selectedIndex: number) => void; - /** - * Called when the user taps any item. - */ - highlight?: (highlightedIndex: number) => void; - /** - * Selected item style. Can be `background`, `outline` or `none`. Defaults to - * `none`. - */ - selectedStyle?: ('background' | 'outline' | 'none'); - /** - * Selected overlay item style. Can be `background`, `outline` or `none`. Defaults - * to `none`. - */ - overlayStyle?: ('background' | 'outline' | 'none'); - /** - * Whether to show arrow buttons. Defaults to `false` and is only shown if `items` - * is non-empty. - */ - showArrowButtons?: boolean; - /** - * Can be `fixed` or `free`. The default is `free`. - */ - mode?: ('fixed' | 'free'); - /** - * Defaults to `true`. - */ - continuous?: boolean; - } - - interface TouchBarSegmentedControlConstructorOptions { - /** - * Style of the segments: - */ - segmentStyle?: ('automatic' | 'rounded' | 'textured-rounded' | 'round-rect' | 'textured-square' | 'capsule' | 'small-square' | 'separated'); - /** - * The selection mode of the control: - */ - mode?: ('single' | 'multiple' | 'buttons'); - /** - * An array of segments to place in this control. - */ - segments: SegmentedControlSegment[]; - /** - * The index of the currently selected segment, will update automatically with user - * interaction. When the mode is `multiple` it will be the last selected item. - */ - selectedIndex?: number; - /** - * Called when the user selects a new segment. - */ - change?: (selectedIndex: number, isSelected: boolean) => void; - } - - interface TouchBarSliderConstructorOptions { - /** - * Label text. - */ - label?: string; - /** - * Selected value. - */ - value?: number; - /** - * Minimum value. - */ - minValue?: number; - /** - * Maximum value. - */ - maxValue?: number; - /** - * Function to call when the slider is changed. - */ - change?: (newValue: number) => void; - } - - interface TouchBarSpacerConstructorOptions { - /** - * Size of spacer, possible values are: - */ - size?: ('small' | 'large' | 'flexible'); - } - - interface TraceBufferUsageReturnValue { - value: number; - percentage: number; - } - - interface UpdateTargetUrlEvent extends Event { - url: string; - } - - interface UploadProgress { - /** - * Whether the request is currently active. If this is false no other properties - * will be set - */ - active: boolean; - /** - * Whether the upload has started. If this is false both `current` and `total` will - * be set to 0. - */ - started: boolean; - /** - * The number of bytes that have been uploaded so far - */ - current: number; - /** - * The number of bytes that will be uploaded this request - */ - total: number; - } - - interface VisibleOnAllWorkspacesOptions { - /** - * Sets whether the window should be visible above fullscreen windows. - * - * @platform darwin - */ - visibleOnFullScreen?: boolean; - /** - * Calling setVisibleOnAllWorkspaces will by default transform the process type - * between UIElementApplication and ForegroundApplication to ensure the correct - * behavior. However, this will hide the window and dock for a short time every - * time it is called. If your window is already of type UIElementApplication, you - * can bypass this transformation by passing true to skipTransformProcessType. - * - * @platform darwin - */ - skipTransformProcessType?: boolean; - } - - interface WebContentsPrintOptions { - /** - * Don't ask user for print settings. Default is `false`. - */ - silent?: boolean; - /** - * Prints the background color and image of the web page. Default is `false`. - */ - printBackground?: boolean; - /** - * Set the printer device name to use. Must be the system-defined name and not the - * 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. - */ - deviceName?: string; - /** - * Set whether the printed web page will be in color or grayscale. Default is - * `true`. - */ - color?: boolean; - margins?: Margins; - /** - * Whether the web page should be printed in landscape mode. Default is `false`. - */ - landscape?: boolean; - /** - * The scale factor of the web page. - */ - scaleFactor?: number; - /** - * The number of pages to print per page sheet. - */ - pagesPerSheet?: number; - /** - * Whether the web page should be collated. - */ - collate?: boolean; - /** - * The number of copies of the web page to print. - */ - copies?: number; - /** - * The page range to print. On macOS, only one range is honored. - */ - pageRanges?: PageRanges[]; - /** - * Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or - * `longEdge`. - */ - duplexMode?: ('simplex' | 'shortEdge' | 'longEdge'); - dpi?: Record<string, number>; - /** - * string to be printed as page header. - */ - header?: string; - /** - * string to be printed as page footer. - */ - footer?: string; - /** - * Specify page size of the printed document. Can be `A3`, `A4`, `A5`, `Legal`, - * `Letter`, `Tabloid` or an Object containing `height`. - */ - pageSize?: (string) | (Size); - } - - interface WebviewTagPrintOptions { - /** - * Don't ask user for print settings. Default is `false`. - */ - silent?: boolean; - /** - * Prints the background color and image of the web page. Default is `false`. - */ - printBackground?: boolean; - /** - * Set the printer device name to use. Must be the system-defined name and not the - * 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. - */ - deviceName?: string; - /** - * Set whether the printed web page will be in color or grayscale. Default is - * `true`. - */ - color?: boolean; - margins?: Margins; - /** - * Whether the web page should be printed in landscape mode. Default is `false`. - */ - landscape?: boolean; - /** - * The scale factor of the web page. - */ - scaleFactor?: number; - /** - * The number of pages to print per page sheet. - */ - pagesPerSheet?: number; - /** - * Whether the web page should be collated. - */ - collate?: boolean; - /** - * The number of copies of the web page to print. - */ - copies?: number; - /** - * The page range to print. - */ - pageRanges?: PageRanges[]; - /** - * Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or - * `longEdge`. - */ - duplexMode?: ('simplex' | 'shortEdge' | 'longEdge'); - dpi?: Record<string, number>; - /** - * string to be printed as page header. - */ - header?: string; - /** - * string to be printed as page footer. - */ - footer?: string; - /** - * Specify page size of the printed document. Can be `A3`, `A4`, `A5`, `Legal`, - * `Letter`, `Tabloid` or an Object containing `height`. - */ - pageSize?: (string) | (Size); - } - - interface WillNavigateEvent extends Event { - url: string; - } - - interface WillResizeDetails { - /** - * The edge of the window being dragged for resizing. Can be `bottom`, `left`, - * `right`, `top-left`, `top-right`, `bottom-left` or `bottom-right`. - */ - edge: ('bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'); - } - - interface EditFlags { - /** - * Whether the renderer believes it can undo. - */ - canUndo: boolean; - /** - * Whether the renderer believes it can redo. - */ - canRedo: boolean; - /** - * Whether the renderer believes it can cut. - */ - canCut: boolean; - /** - * Whether the renderer believes it can copy. - */ - canCopy: boolean; - /** - * Whether the renderer believes it can paste. - */ - canPaste: boolean; - /** - * Whether the renderer believes it can delete. - */ - canDelete: boolean; - /** - * Whether the renderer believes it can select all. - */ - canSelectAll: boolean; - /** - * Whether the renderer believes it can edit text richly. - */ - canEditRichly: boolean; - } - - interface FoundInPageResult { - requestId: number; - /** - * Position of the active match. - */ - activeMatchOrdinal: number; - /** - * Number of Matches. - */ - matches: number; - /** - * Coordinates of first match region. - */ - selectionArea: Rectangle; - finalUpdate: boolean; - } - - interface LaunchItems { - /** - * name value of a registry entry. - * - * @platform win32 - */ - name: string; - /** - * The executable to an app that corresponds to a registry entry. - * - * @platform win32 - */ - path: string; - /** - * the command-line arguments to pass to the executable. - * - * @platform win32 - */ - args: string[]; - /** - * one of `user` or `machine`. Indicates whether the registry entry is under - * `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. - * - * @platform win32 - */ - scope: string; - /** - * `true` if the app registry key is startup approved and therefore shows as - * `enabled` in Task Manager and Windows settings. - * - * @platform win32 - */ - enabled: boolean; - } - - interface Margins { - /** - * Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, - * you will also need to specify `top`, `bottom`, `left`, and `right`. - */ - marginType?: ('default' | 'none' | 'printableArea' | 'custom'); - /** - * The top margin of the printed web page, in pixels. - */ - top?: number; - /** - * The bottom margin of the printed web page, in pixels. - */ - bottom?: number; - /** - * The left margin of the printed web page, in pixels. - */ - left?: number; - /** - * The right margin of the printed web page, in pixels. - */ - right?: number; - } - - interface MediaFlags { - /** - * Whether the media element has crashed. - */ - inError: boolean; - /** - * Whether the media element is paused. - */ - isPaused: boolean; - /** - * Whether the media element is muted. - */ - isMuted: boolean; - /** - * Whether the media element has audio. - */ - hasAudio: boolean; - /** - * Whether the media element is looping. - */ - isLooping: boolean; - /** - * Whether the media element's controls are visible. - */ - isControlsVisible: boolean; - /** - * Whether the media element's controls are toggleable. - */ - canToggleControls: boolean; - /** - * Whether the media element can be printed. - */ - canPrint: boolean; - /** - * Whether or not the media element can be downloaded. - */ - canSave: boolean; - /** - * Whether the media element can show picture-in-picture. - */ - canShowPictureInPicture: boolean; - /** - * Whether the media element is currently showing picture-in-picture. - */ - isShowingPictureInPicture: boolean; - /** - * Whether the media element can be rotated. - */ - canRotate: boolean; - /** - * Whether the media element can be looped. - */ - canLoop: boolean; - } - - interface PageRanges { - /** - * Index of the first page to print (0-based). - */ - from: number; - /** - * Index of the last page to print (inclusive) (0-based). - */ - to: number; - } - - interface Params { - /** - * x coordinate. - */ - x: number; - /** - * y coordinate. - */ - y: number; - /** - * URL of the link that encloses the node the context menu was invoked on. - */ - linkURL: string; - /** - * Text associated with the link. May be an empty string if the contents of the - * link are an image. - */ - linkText: string; - /** - * URL of the top level page that the context menu was invoked on. - */ - pageURL: string; - /** - * URL of the subframe that the context menu was invoked on. - */ - frameURL: string; - /** - * Source URL for the element that the context menu was invoked on. Elements with - * source URLs are images, audio and video. - */ - srcURL: string; - /** - * Type of the node the context menu was invoked on. Can be `none`, `image`, - * `audio`, `video`, `canvas`, `file` or `plugin`. - */ - mediaType: ('none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'); - /** - * Whether the context menu was invoked on an image which has non-empty contents. - */ - hasImageContents: boolean; - /** - * Whether the context is editable. - */ - isEditable: boolean; - /** - * Text of the selection that the context menu was invoked on. - */ - selectionText: string; - /** - * Title text of the selection that the context menu was invoked on. - */ - titleText: string; - /** - * Alt text of the selection that the context menu was invoked on. - */ - altText: string; - /** - * Suggested filename to be used when saving file through 'Save Link As' option of - * context menu. - */ - suggestedFilename: string; - /** - * Rect representing the coordinates in the document space of the selection. - */ - selectionRect: Rectangle; - /** - * Start position of the selection text. - */ - selectionStartOffset: number; - /** - * The referrer policy of the frame on which the menu is invoked. - */ - referrerPolicy: Referrer; - /** - * The misspelled word under the cursor, if any. - */ - misspelledWord: string; - /** - * An array of suggested words to show the user to replace the `misspelledWord`. - * Only available if there is a misspelled word and spellchecker is enabled. - */ - dictionarySuggestions: string[]; - /** - * The character encoding of the frame on which the menu was invoked. - */ - frameCharset: string; - /** - * If the context menu was invoked on an input field, the type of that field. - * Possible values are `none`, `plainText`, `password`, `other`. - */ - inputFieldType: string; - /** - * If the context is editable, whether or not spellchecking is enabled. - */ - spellcheckEnabled: boolean; - /** - * Input source that invoked the context menu. Can be `none`, `mouse`, `keyboard`, - * `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, - * `adjustSelection`, or `adjustSelectionReset`. - */ - menuSourceType: ('none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu' | 'longPress' | 'longTap' | 'touchHandle' | 'stylus' | 'adjustSelection' | 'adjustSelectionReset'); - /** - * The flags for the media element the context menu was invoked on. - */ - mediaFlags: MediaFlags; - /** - * These flags indicate whether the renderer believes it is able to perform the - * corresponding action. - */ - editFlags: EditFlags; - } - - interface TitleBarOverlay { - /** - * The CSS color of the Window Controls Overlay when enabled. Default is the system - * color. - * - * @platform win32 - */ - color?: string; - /** - * The CSS color of the symbols on the Window Controls Overlay when enabled. - * Default is the system color. - * - * @platform win32 - */ - symbolColor?: string; - /** - * The height of the title bar and Window Controls Overlay in pixels. Default is - * system height. - * - * @platform darwin,win32 - */ - height?: number; - } - - interface WebPreferences { - /** - * Whether to enable DevTools. If it is set to `false`, can not use - * `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. - */ - devTools?: boolean; - /** - * Whether node integration is enabled. Default is `false`. - */ - nodeIntegration?: boolean; - /** - * Whether node integration is enabled in web workers. Default is `false`. More - * about this can be found in Multithreading. - */ - nodeIntegrationInWorker?: boolean; - /** - * Experimental option for enabling Node.js support in sub-frames such as iframes - * and child windows. All your preloads will load for every iframe, you can use - * `process.isMainFrame` to determine if you are in the main frame or not. - */ - nodeIntegrationInSubFrames?: boolean; - /** - * Specifies a script that will be loaded before other scripts run in the page. - * This script will always have access to node APIs no matter whether node - * integration is turned on or off. The value should be the absolute file path to - * the script. When node integration is turned off, the preload script can - * reintroduce Node global symbols back to the global scope. See example here. - */ - preload?: string; - /** - * If set, this will sandbox the renderer associated with the window, making it - * compatible with the Chromium OS-level sandbox and disabling the Node.js engine. - * This is not the same as the `nodeIntegration` option and the APIs available to - * the preload script are more limited. Read more about the option here. - */ - sandbox?: boolean; - /** - * Sets the session used by the page. Instead of passing the Session object - * directly, you can also choose to use the `partition` option instead, which - * accepts a partition string. When both `session` and `partition` are provided, - * `session` will be preferred. Default is the default session. - */ - session?: Session; - /** - * Sets the session used by the page according to the session's partition string. - * If `partition` starts with `persist:`, the page will use a persistent session - * available to all pages in the app with the same `partition`. If there is no - * `persist:` prefix, the page will use an in-memory session. By assigning the same - * `partition`, multiple pages can share the same session. Default is the default - * session. - */ - partition?: string; - /** - * The default zoom factor of the page, `3.0` represents `300%`. Default is `1.0`. - */ - zoomFactor?: number; - /** - * Enables JavaScript support. Default is `true`. - */ - javascript?: boolean; - /** - * When `false`, it will disable the same-origin policy (usually using testing - * websites by people), and set `allowRunningInsecureContent` to `true` if this - * options has not been set by user. Default is `true`. - */ - webSecurity?: boolean; - /** - * Allow an https page to run JavaScript, CSS or plugins from http URLs. Default is - * `false`. - */ - allowRunningInsecureContent?: boolean; - /** - * Enables image support. Default is `true`. - */ - images?: boolean; - /** - * Specifies how to run image animations (E.g. GIFs). Can be `animate`, - * `animateOnce` or `noAnimation`. Default is `animate`. - */ - imageAnimationPolicy?: ('animate' | 'animateOnce' | 'noAnimation'); - /** - * Make TextArea elements resizable. Default is `true`. - */ - textAreasAreResizable?: boolean; - /** - * Enables WebGL support. Default is `true`. - */ - webgl?: boolean; - /** - * Whether plugins should be enabled. Default is `false`. - */ - plugins?: boolean; - /** - * Enables Chromium's experimental features. Default is `false`. - */ - experimentalFeatures?: boolean; - /** - * Enables scroll bounce (rubber banding) effect on macOS. Default is `false`. - */ - scrollBounce?: boolean; - /** - * A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` - * to enable. The full list of supported feature strings can be found in the - * RuntimeEnabledFeatures.json5 file. - */ - enableBlinkFeatures?: string; - /** - * A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` - * to disable. The full list of supported feature strings can be found in the - * RuntimeEnabledFeatures.json5 file. - */ - disableBlinkFeatures?: string; - /** - * Sets the default font for the font-family. - */ - defaultFontFamily?: DefaultFontFamily; - /** - * Defaults to `16`. - */ - defaultFontSize?: number; - /** - * Defaults to `13`. - */ - defaultMonospaceFontSize?: number; - /** - * Defaults to `0`. - */ - minimumFontSize?: number; - /** - * Defaults to `ISO-8859-1`. - */ - defaultEncoding?: string; - /** - * Whether to throttle animations and timers when the page becomes background. This - * also affects the Page Visibility API. Defaults to `true`. - */ - backgroundThrottling?: boolean; - /** - * Whether to enable offscreen rendering for the browser window. Defaults to - * `false`. See the offscreen rendering tutorial for more details. - */ - offscreen?: boolean; - /** - * Whether to run Electron APIs and the specified `preload` script in a separate - * JavaScript context. Defaults to `true`. The context that the `preload` script - * runs in will only have access to its own dedicated `document` and `window` - * globals, as well as its own set of JavaScript builtins (`Array`, `Object`, - * `JSON`, etc.), which are all invisible to the loaded content. The Electron API - * will only be available in the `preload` script and not the loaded page. This - * option should be used when loading potentially untrusted remote content to - * ensure the loaded content cannot tamper with the `preload` script and any - * Electron APIs being used. This option uses the same technique used by Chrome - * Content Scripts. You can access this context in the dev tools by selecting the - * 'Electron Isolated Context' entry in the combo box at the top of the Console - * tab. - */ - contextIsolation?: boolean; - /** - * Whether to enable the `<webview>` tag. Defaults to `false`. **Note:** The - * `preload` script configured for the `<webview>` will have node integration - * enabled when it is executed so you should ensure remote/untrusted content is not - * able to create a `<webview>` tag with a possibly malicious `preload` script. You - * can use the `will-attach-webview` event on webContents to strip away the - * `preload` script and to validate or alter the `<webview>`'s initial settings. - */ - webviewTag?: boolean; - /** - * A list of strings that will be appended to `process.argv` in the renderer - * process of this app. Useful for passing small bits of data down to renderer - * process preload scripts. - */ - additionalArguments?: string[]; - /** - * Whether to enable browser style consecutive dialog protection. Default is - * `false`. - */ - safeDialogs?: boolean; - /** - * The message to display when consecutive dialog protection is triggered. If not - * defined the default message would be used, note that currently the default - * message is in English and not localized. - */ - safeDialogsMessage?: string; - /** - * Whether to disable dialogs completely. Overrides `safeDialogs`. Default is - * `false`. - */ - disableDialogs?: boolean; - /** - * Whether dragging and dropping a file or link onto the page causes a navigation. - * Default is `false`. - */ - navigateOnDragDrop?: boolean; - /** - * Autoplay policy to apply to content in the window, can be - * `no-user-gesture-required`, `user-gesture-required`, - * `document-user-activation-required`. Defaults to `no-user-gesture-required`. - */ - autoplayPolicy?: ('no-user-gesture-required' | 'user-gesture-required' | 'document-user-activation-required'); - /** - * Whether to prevent the window from resizing when entering HTML Fullscreen. - * Default is `false`. - */ - disableHtmlFullscreenWindowResize?: boolean; - /** - * An alternative title string provided only to accessibility tools such as screen - * readers. This string is not directly visible to users. - */ - accessibleTitle?: string; - /** - * Whether to enable the builtin spellchecker. Default is `true`. - */ - spellcheck?: boolean; - /** - * Whether to enable the WebSQL api. Default is `true`. - */ - enableWebSQL?: boolean; - /** - * Enforces the v8 code caching policy used by blink. Accepted values are - */ - v8CacheOptions?: ('none' | 'code' | 'bypassHeatCheck' | 'bypassHeatCheckAndEagerCompile'); - /** - * Whether to enable preferred size mode. The preferred size is the minimum size - * needed to contain the layout of the documentβ€”without requiring scrolling. - * Enabling this will cause the `preferred-size-changed` event to be emitted on the - * `WebContents` when the preferred size changes. Default is `false`. - */ - enablePreferredSizeMode?: boolean; - } - - interface DefaultFontFamily { - /** - * Defaults to `Times New Roman`. - */ - standard?: string; - /** - * Defaults to `Times New Roman`. - */ - serif?: string; - /** - * Defaults to `Arial`. - */ - sansSerif?: string; - /** - * Defaults to `Courier New`. - */ - monospace?: string; - /** - * Defaults to `Script`. - */ - cursive?: string; - /** - * Defaults to `Impact`. - */ - fantasy?: string; - } - - interface RemoteMainInterface { - app: App; - autoUpdater: AutoUpdater; - BrowserView: typeof BrowserView; - BrowserWindow: typeof BrowserWindow; - clipboard: Clipboard; - contentTracing: ContentTracing; - crashReporter: CrashReporter; - desktopCapturer: DesktopCapturer; - dialog: Dialog; - globalShortcut: GlobalShortcut; - inAppPurchase: InAppPurchase; - ipcMain: IpcMain; - Menu: typeof Menu; - MenuItem: typeof MenuItem; - MessageChannelMain: typeof MessageChannelMain; - nativeImage: typeof NativeImage; - nativeTheme: NativeTheme; - net: Net; - netLog: NetLog; - Notification: typeof Notification; - powerMonitor: PowerMonitor; - powerSaveBlocker: PowerSaveBlocker; - protocol: Protocol; - safeStorage: SafeStorage; - screen: Screen; - session: typeof Session; - ShareMenu: typeof ShareMenu; - shell: Shell; - systemPreferences: SystemPreferences; - TouchBar: typeof TouchBar; - Tray: typeof Tray; - webContents: typeof WebContents; - webFrameMain: typeof WebFrameMain; - } - - - - namespace Common { - const clipboard: Clipboard; - type Clipboard = Electron.Clipboard; - const crashReporter: CrashReporter; - type CrashReporter = Electron.CrashReporter; - const nativeImage: typeof NativeImage; - type NativeImage = Electron.NativeImage; - const shell: Shell; - type Shell = Electron.Shell; - type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; - type AddRepresentationOptions = Electron.AddRepresentationOptions; - type AnimationSettings = Electron.AnimationSettings; - type AppDetailsOptions = Electron.AppDetailsOptions; - type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; - type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; - type AuthInfo = Electron.AuthInfo; - type AutoResizeOptions = Electron.AutoResizeOptions; - type BeforeSendResponse = Electron.BeforeSendResponse; - type BitmapOptions = Electron.BitmapOptions; - type BlinkMemoryInfo = Electron.BlinkMemoryInfo; - type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; - type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; - type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; - type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; - type ClearStorageDataOptions = Electron.ClearStorageDataOptions; - type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; - type Config = Electron.Config; - type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; - type ConsoleMessageEvent = Electron.ConsoleMessageEvent; - type ContextMenuEvent = Electron.ContextMenuEvent; - type ContextMenuParams = Electron.ContextMenuParams; - type ContinueActivityDetails = Electron.ContinueActivityDetails; - type CookiesGetFilter = Electron.CookiesGetFilter; - type CookiesSetDetails = Electron.CookiesSetDetails; - type CrashReporterStartOptions = Electron.CrashReporterStartOptions; - type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; - type CreateFromBufferOptions = Electron.CreateFromBufferOptions; - type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; - type Data = Electron.Data; - type Details = Electron.Details; - type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; - type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; - type DidCreateWindowDetails = Electron.DidCreateWindowDetails; - type DidFailLoadEvent = Electron.DidFailLoadEvent; - type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; - type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; - type DidNavigateEvent = Electron.DidNavigateEvent; - type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; - type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; - type DidStartNavigationEvent = Electron.DidStartNavigationEvent; - type DisplayBalloonOptions = Electron.DisplayBalloonOptions; - type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; - type FeedURLOptions = Electron.FeedURLOptions; - type FileIconOptions = Electron.FileIconOptions; - type FindInPageOptions = Electron.FindInPageOptions; - type FocusOptions = Electron.FocusOptions; - type FoundInPageEvent = Electron.FoundInPageEvent; - type FrameCreatedDetails = Electron.FrameCreatedDetails; - type FromPartitionOptions = Electron.FromPartitionOptions; - type HandlerDetails = Electron.HandlerDetails; - type HeadersReceivedResponse = Electron.HeadersReceivedResponse; - type HeapStatistics = Electron.HeapStatistics; - type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; - type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; - type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; - type ImportCertificateOptions = Electron.ImportCertificateOptions; - type Info = Electron.Info; - type Input = Electron.Input; - type InsertCSSOptions = Electron.InsertCSSOptions; - type IpcMessageEvent = Electron.IpcMessageEvent; - type Item = Electron.Item; - type JumpListSettings = Electron.JumpListSettings; - type LoadCommitEvent = Electron.LoadCommitEvent; - type LoadExtensionOptions = Electron.LoadExtensionOptions; - type LoadFileOptions = Electron.LoadFileOptions; - type LoadURLOptions = Electron.LoadURLOptions; - type LoginItemSettings = Electron.LoginItemSettings; - type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; - type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; - type MessageBoxOptions = Electron.MessageBoxOptions; - type MessageBoxReturnValue = Electron.MessageBoxReturnValue; - type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; - type MessageDetails = Electron.MessageDetails; - type MessageEvent = Electron.MessageEvent; - type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; - type NewWindowEvent = Electron.NewWindowEvent; - type NotificationConstructorOptions = Electron.NotificationConstructorOptions; - type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; - type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; - type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; - type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; - type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; - type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; - type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; - type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; - type OpenDevToolsOptions = Electron.OpenDevToolsOptions; - type OpenDialogOptions = Electron.OpenDialogOptions; - type OpenDialogReturnValue = Electron.OpenDialogReturnValue; - type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; - type OpenExternalOptions = Electron.OpenExternalOptions; - type Options = Electron.Options; - type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; - type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; - type Parameters = Electron.Parameters; - type Payment = Electron.Payment; - type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; - type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; - type PluginCrashedEvent = Electron.PluginCrashedEvent; - type PopupOptions = Electron.PopupOptions; - type PreconnectOptions = Electron.PreconnectOptions; - type PrintToPDFOptions = Electron.PrintToPDFOptions; - type Privileges = Electron.Privileges; - type ProgressBarOptions = Electron.ProgressBarOptions; - type Provider = Electron.Provider; - type ReadBookmark = Electron.ReadBookmark; - type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; - type RelaunchOptions = Electron.RelaunchOptions; - type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; - type Request = Electron.Request; - type ResizeOptions = Electron.ResizeOptions; - type ResourceUsage = Electron.ResourceUsage; - type Response = Electron.Response; - type Result = Electron.Result; - type SaveDialogOptions = Electron.SaveDialogOptions; - type SaveDialogReturnValue = Electron.SaveDialogReturnValue; - type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; - type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; - type Settings = Electron.Settings; - type SourcesOptions = Electron.SourcesOptions; - type SSLConfigConfig = Electron.SSLConfigConfig; - type StartLoggingOptions = Electron.StartLoggingOptions; - type SystemMemoryInfo = Electron.SystemMemoryInfo; - type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; - type TitleOptions = Electron.TitleOptions; - type ToBitmapOptions = Electron.ToBitmapOptions; - type ToDataURLOptions = Electron.ToDataURLOptions; - type ToPNGOptions = Electron.ToPNGOptions; - type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; - type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; - type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; - type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; - type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; - type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; - type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; - type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; - type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; - type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; - type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; - type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; - type UploadProgress = Electron.UploadProgress; - type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; - type WebContentsPrintOptions = Electron.WebContentsPrintOptions; - type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; - type WillNavigateEvent = Electron.WillNavigateEvent; - type WillResizeDetails = Electron.WillResizeDetails; - type EditFlags = Electron.EditFlags; - type FoundInPageResult = Electron.FoundInPageResult; - type LaunchItems = Electron.LaunchItems; - type Margins = Electron.Margins; - type MediaFlags = Electron.MediaFlags; - type PageRanges = Electron.PageRanges; - type Params = Electron.Params; - type TitleBarOverlay = Electron.TitleBarOverlay; - type WebPreferences = Electron.WebPreferences; - type DefaultFontFamily = Electron.DefaultFontFamily; - type BluetoothDevice = Electron.BluetoothDevice; - type Certificate = Electron.Certificate; - type CertificatePrincipal = Electron.CertificatePrincipal; - type Cookie = Electron.Cookie; - type CPUUsage = Electron.CPUUsage; - type CrashReport = Electron.CrashReport; - type CustomScheme = Electron.CustomScheme; - type DesktopCapturerSource = Electron.DesktopCapturerSource; - type Display = Electron.Display; - type Event = Electron.Event; - type Extension = Electron.Extension; - type ExtensionInfo = Electron.ExtensionInfo; - type FileFilter = Electron.FileFilter; - type FilePathWithHeaders = Electron.FilePathWithHeaders; - type GPUFeatureStatus = Electron.GPUFeatureStatus; - type HIDDevice = Electron.HIDDevice; - type InputEvent = Electron.InputEvent; - type IOCounters = Electron.IOCounters; - type IpcMainEvent = Electron.IpcMainEvent; - type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; - type IpcRendererEvent = Electron.IpcRendererEvent; - type JumpListCategory = Electron.JumpListCategory; - type JumpListItem = Electron.JumpListItem; - type KeyboardEvent = Electron.KeyboardEvent; - type KeyboardInputEvent = Electron.KeyboardInputEvent; - type MemoryInfo = Electron.MemoryInfo; - type MemoryUsageDetails = Electron.MemoryUsageDetails; - type MimeTypedBuffer = Electron.MimeTypedBuffer; - type MouseInputEvent = Electron.MouseInputEvent; - type MouseWheelInputEvent = Electron.MouseWheelInputEvent; - type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; - type NotificationAction = Electron.NotificationAction; - type NotificationResponse = Electron.NotificationResponse; - type PaymentDiscount = Electron.PaymentDiscount; - type Point = Electron.Point; - type PostBody = Electron.PostBody; - type PrinterInfo = Electron.PrinterInfo; - type ProcessMemoryInfo = Electron.ProcessMemoryInfo; - type ProcessMetric = Electron.ProcessMetric; - type Product = Electron.Product; - type ProductDiscount = Electron.ProductDiscount; - type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; - type ProtocolRequest = Electron.ProtocolRequest; - type ProtocolResponse = Electron.ProtocolResponse; - type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; - type Rectangle = Electron.Rectangle; - type Referrer = Electron.Referrer; - type ScrubberItem = Electron.ScrubberItem; - type SegmentedControlSegment = Electron.SegmentedControlSegment; - type SerialPort = Electron.SerialPort; - type ServiceWorkerInfo = Electron.ServiceWorkerInfo; - type SharedWorkerInfo = Electron.SharedWorkerInfo; - type SharingItem = Electron.SharingItem; - type ShortcutDetails = Electron.ShortcutDetails; - type Size = Electron.Size; - type Task = Electron.Task; - type ThumbarButton = Electron.ThumbarButton; - type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; - type TraceConfig = Electron.TraceConfig; - type Transaction = Electron.Transaction; - type UploadData = Electron.UploadData; - type UploadFile = Electron.UploadFile; - type UploadRawData = Electron.UploadRawData; - type UserDefaultTypes = Electron.UserDefaultTypes; - type WebRequestFilter = Electron.WebRequestFilter; - type WebSource = Electron.WebSource; - } - - namespace Main { - const app: App; - type App = Electron.App; - const autoUpdater: AutoUpdater; - type AutoUpdater = Electron.AutoUpdater; - class BrowserView extends Electron.BrowserView {} - class BrowserWindow extends Electron.BrowserWindow {} - type ClientRequest = Electron.ClientRequest; - type CommandLine = Electron.CommandLine; - const contentTracing: ContentTracing; - type ContentTracing = Electron.ContentTracing; - type Cookies = Electron.Cookies; - type Debugger = Electron.Debugger; - const desktopCapturer: DesktopCapturer; - type DesktopCapturer = Electron.DesktopCapturer; - const dialog: Dialog; - type Dialog = Electron.Dialog; - type Dock = Electron.Dock; - type DownloadItem = Electron.DownloadItem; - const globalShortcut: GlobalShortcut; - type GlobalShortcut = Electron.GlobalShortcut; - const inAppPurchase: InAppPurchase; - type InAppPurchase = Electron.InAppPurchase; - type IncomingMessage = Electron.IncomingMessage; - const ipcMain: IpcMain; - type IpcMain = Electron.IpcMain; - class Menu extends Electron.Menu {} - class MenuItem extends Electron.MenuItem {} - class MessageChannelMain extends Electron.MessageChannelMain {} - type MessagePortMain = Electron.MessagePortMain; - const nativeTheme: NativeTheme; - type NativeTheme = Electron.NativeTheme; - const net: Net; - type Net = Electron.Net; - const netLog: NetLog; - type NetLog = Electron.NetLog; - class Notification extends Electron.Notification {} - const powerMonitor: PowerMonitor; - type PowerMonitor = Electron.PowerMonitor; - const powerSaveBlocker: PowerSaveBlocker; - type PowerSaveBlocker = Electron.PowerSaveBlocker; - const protocol: Protocol; - type Protocol = Electron.Protocol; - const safeStorage: SafeStorage; - type SafeStorage = Electron.SafeStorage; - const screen: Screen; - type Screen = Electron.Screen; - type ServiceWorkers = Electron.ServiceWorkers; - const session: typeof Session; - type Session = Electron.Session; - class ShareMenu extends Electron.ShareMenu {} - const systemPreferences: SystemPreferences; - type SystemPreferences = Electron.SystemPreferences; - class TouchBar extends Electron.TouchBar {} - type TouchBarButton = Electron.TouchBarButton; - type TouchBarColorPicker = Electron.TouchBarColorPicker; - type TouchBarGroup = Electron.TouchBarGroup; - type TouchBarLabel = Electron.TouchBarLabel; - type TouchBarOtherItemsProxy = Electron.TouchBarOtherItemsProxy; - type TouchBarPopover = Electron.TouchBarPopover; - type TouchBarScrubber = Electron.TouchBarScrubber; - type TouchBarSegmentedControl = Electron.TouchBarSegmentedControl; - type TouchBarSlider = Electron.TouchBarSlider; - type TouchBarSpacer = Electron.TouchBarSpacer; - class Tray extends Electron.Tray {} - const webContents: typeof WebContents; - type WebContents = Electron.WebContents; - const webFrameMain: typeof WebFrameMain; - type WebFrameMain = Electron.WebFrameMain; - type WebRequest = Electron.WebRequest; - type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; - type AddRepresentationOptions = Electron.AddRepresentationOptions; - type AnimationSettings = Electron.AnimationSettings; - type AppDetailsOptions = Electron.AppDetailsOptions; - type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; - type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; - type AuthInfo = Electron.AuthInfo; - type AutoResizeOptions = Electron.AutoResizeOptions; - type BeforeSendResponse = Electron.BeforeSendResponse; - type BitmapOptions = Electron.BitmapOptions; - type BlinkMemoryInfo = Electron.BlinkMemoryInfo; - type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; - type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; - type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; - type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; - type ClearStorageDataOptions = Electron.ClearStorageDataOptions; - type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; - type Config = Electron.Config; - type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; - type ConsoleMessageEvent = Electron.ConsoleMessageEvent; - type ContextMenuEvent = Electron.ContextMenuEvent; - type ContextMenuParams = Electron.ContextMenuParams; - type ContinueActivityDetails = Electron.ContinueActivityDetails; - type CookiesGetFilter = Electron.CookiesGetFilter; - type CookiesSetDetails = Electron.CookiesSetDetails; - type CrashReporterStartOptions = Electron.CrashReporterStartOptions; - type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; - type CreateFromBufferOptions = Electron.CreateFromBufferOptions; - type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; - type Data = Electron.Data; - type Details = Electron.Details; - type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; - type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; - type DidCreateWindowDetails = Electron.DidCreateWindowDetails; - type DidFailLoadEvent = Electron.DidFailLoadEvent; - type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; - type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; - type DidNavigateEvent = Electron.DidNavigateEvent; - type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; - type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; - type DidStartNavigationEvent = Electron.DidStartNavigationEvent; - type DisplayBalloonOptions = Electron.DisplayBalloonOptions; - type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; - type FeedURLOptions = Electron.FeedURLOptions; - type FileIconOptions = Electron.FileIconOptions; - type FindInPageOptions = Electron.FindInPageOptions; - type FocusOptions = Electron.FocusOptions; - type FoundInPageEvent = Electron.FoundInPageEvent; - type FrameCreatedDetails = Electron.FrameCreatedDetails; - type FromPartitionOptions = Electron.FromPartitionOptions; - type HandlerDetails = Electron.HandlerDetails; - type HeadersReceivedResponse = Electron.HeadersReceivedResponse; - type HeapStatistics = Electron.HeapStatistics; - type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; - type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; - type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; - type ImportCertificateOptions = Electron.ImportCertificateOptions; - type Info = Electron.Info; - type Input = Electron.Input; - type InsertCSSOptions = Electron.InsertCSSOptions; - type IpcMessageEvent = Electron.IpcMessageEvent; - type Item = Electron.Item; - type JumpListSettings = Electron.JumpListSettings; - type LoadCommitEvent = Electron.LoadCommitEvent; - type LoadExtensionOptions = Electron.LoadExtensionOptions; - type LoadFileOptions = Electron.LoadFileOptions; - type LoadURLOptions = Electron.LoadURLOptions; - type LoginItemSettings = Electron.LoginItemSettings; - type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; - type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; - type MessageBoxOptions = Electron.MessageBoxOptions; - type MessageBoxReturnValue = Electron.MessageBoxReturnValue; - type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; - type MessageDetails = Electron.MessageDetails; - type MessageEvent = Electron.MessageEvent; - type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; - type NewWindowEvent = Electron.NewWindowEvent; - type NotificationConstructorOptions = Electron.NotificationConstructorOptions; - type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; - type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; - type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; - type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; - type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; - type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; - type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; - type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; - type OpenDevToolsOptions = Electron.OpenDevToolsOptions; - type OpenDialogOptions = Electron.OpenDialogOptions; - type OpenDialogReturnValue = Electron.OpenDialogReturnValue; - type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; - type OpenExternalOptions = Electron.OpenExternalOptions; - type Options = Electron.Options; - type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; - type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; - type Parameters = Electron.Parameters; - type Payment = Electron.Payment; - type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; - type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; - type PluginCrashedEvent = Electron.PluginCrashedEvent; - type PopupOptions = Electron.PopupOptions; - type PreconnectOptions = Electron.PreconnectOptions; - type PrintToPDFOptions = Electron.PrintToPDFOptions; - type Privileges = Electron.Privileges; - type ProgressBarOptions = Electron.ProgressBarOptions; - type Provider = Electron.Provider; - type ReadBookmark = Electron.ReadBookmark; - type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; - type RelaunchOptions = Electron.RelaunchOptions; - type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; - type Request = Electron.Request; - type ResizeOptions = Electron.ResizeOptions; - type ResourceUsage = Electron.ResourceUsage; - type Response = Electron.Response; - type Result = Electron.Result; - type SaveDialogOptions = Electron.SaveDialogOptions; - type SaveDialogReturnValue = Electron.SaveDialogReturnValue; - type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; - type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; - type Settings = Electron.Settings; - type SourcesOptions = Electron.SourcesOptions; - type SSLConfigConfig = Electron.SSLConfigConfig; - type StartLoggingOptions = Electron.StartLoggingOptions; - type SystemMemoryInfo = Electron.SystemMemoryInfo; - type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; - type TitleOptions = Electron.TitleOptions; - type ToBitmapOptions = Electron.ToBitmapOptions; - type ToDataURLOptions = Electron.ToDataURLOptions; - type ToPNGOptions = Electron.ToPNGOptions; - type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; - type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; - type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; - type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; - type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; - type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; - type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; - type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; - type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; - type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; - type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; - type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; - type UploadProgress = Electron.UploadProgress; - type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; - type WebContentsPrintOptions = Electron.WebContentsPrintOptions; - type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; - type WillNavigateEvent = Electron.WillNavigateEvent; - type WillResizeDetails = Electron.WillResizeDetails; - type EditFlags = Electron.EditFlags; - type FoundInPageResult = Electron.FoundInPageResult; - type LaunchItems = Electron.LaunchItems; - type Margins = Electron.Margins; - type MediaFlags = Electron.MediaFlags; - type PageRanges = Electron.PageRanges; - type Params = Electron.Params; - type TitleBarOverlay = Electron.TitleBarOverlay; - type WebPreferences = Electron.WebPreferences; - type DefaultFontFamily = Electron.DefaultFontFamily; - type BluetoothDevice = Electron.BluetoothDevice; - type Certificate = Electron.Certificate; - type CertificatePrincipal = Electron.CertificatePrincipal; - type Cookie = Electron.Cookie; - type CPUUsage = Electron.CPUUsage; - type CrashReport = Electron.CrashReport; - type CustomScheme = Electron.CustomScheme; - type DesktopCapturerSource = Electron.DesktopCapturerSource; - type Display = Electron.Display; - type Event = Electron.Event; - type Extension = Electron.Extension; - type ExtensionInfo = Electron.ExtensionInfo; - type FileFilter = Electron.FileFilter; - type FilePathWithHeaders = Electron.FilePathWithHeaders; - type GPUFeatureStatus = Electron.GPUFeatureStatus; - type HIDDevice = Electron.HIDDevice; - type InputEvent = Electron.InputEvent; - type IOCounters = Electron.IOCounters; - type IpcMainEvent = Electron.IpcMainEvent; - type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; - type IpcRendererEvent = Electron.IpcRendererEvent; - type JumpListCategory = Electron.JumpListCategory; - type JumpListItem = Electron.JumpListItem; - type KeyboardEvent = Electron.KeyboardEvent; - type KeyboardInputEvent = Electron.KeyboardInputEvent; - type MemoryInfo = Electron.MemoryInfo; - type MemoryUsageDetails = Electron.MemoryUsageDetails; - type MimeTypedBuffer = Electron.MimeTypedBuffer; - type MouseInputEvent = Electron.MouseInputEvent; - type MouseWheelInputEvent = Electron.MouseWheelInputEvent; - type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; - type NotificationAction = Electron.NotificationAction; - type NotificationResponse = Electron.NotificationResponse; - type PaymentDiscount = Electron.PaymentDiscount; - type Point = Electron.Point; - type PostBody = Electron.PostBody; - type PrinterInfo = Electron.PrinterInfo; - type ProcessMemoryInfo = Electron.ProcessMemoryInfo; - type ProcessMetric = Electron.ProcessMetric; - type Product = Electron.Product; - type ProductDiscount = Electron.ProductDiscount; - type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; - type ProtocolRequest = Electron.ProtocolRequest; - type ProtocolResponse = Electron.ProtocolResponse; - type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; - type Rectangle = Electron.Rectangle; - type Referrer = Electron.Referrer; - type ScrubberItem = Electron.ScrubberItem; - type SegmentedControlSegment = Electron.SegmentedControlSegment; - type SerialPort = Electron.SerialPort; - type ServiceWorkerInfo = Electron.ServiceWorkerInfo; - type SharedWorkerInfo = Electron.SharedWorkerInfo; - type SharingItem = Electron.SharingItem; - type ShortcutDetails = Electron.ShortcutDetails; - type Size = Electron.Size; - type Task = Electron.Task; - type ThumbarButton = Electron.ThumbarButton; - type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; - type TraceConfig = Electron.TraceConfig; - type Transaction = Electron.Transaction; - type UploadData = Electron.UploadData; - type UploadFile = Electron.UploadFile; - type UploadRawData = Electron.UploadRawData; - type UserDefaultTypes = Electron.UserDefaultTypes; - type WebRequestFilter = Electron.WebRequestFilter; - type WebSource = Electron.WebSource; - } - - namespace Renderer { - const contextBridge: ContextBridge; - type ContextBridge = Electron.ContextBridge; - const ipcRenderer: IpcRenderer; - type IpcRenderer = Electron.IpcRenderer; - const webFrame: WebFrame; - type WebFrame = Electron.WebFrame; - type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; - type AddRepresentationOptions = Electron.AddRepresentationOptions; - type AnimationSettings = Electron.AnimationSettings; - type AppDetailsOptions = Electron.AppDetailsOptions; - type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; - type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; - type AuthInfo = Electron.AuthInfo; - type AutoResizeOptions = Electron.AutoResizeOptions; - type BeforeSendResponse = Electron.BeforeSendResponse; - type BitmapOptions = Electron.BitmapOptions; - type BlinkMemoryInfo = Electron.BlinkMemoryInfo; - type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; - type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; - type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; - type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; - type ClearStorageDataOptions = Electron.ClearStorageDataOptions; - type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; - type Config = Electron.Config; - type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; - type ConsoleMessageEvent = Electron.ConsoleMessageEvent; - type ContextMenuEvent = Electron.ContextMenuEvent; - type ContextMenuParams = Electron.ContextMenuParams; - type ContinueActivityDetails = Electron.ContinueActivityDetails; - type CookiesGetFilter = Electron.CookiesGetFilter; - type CookiesSetDetails = Electron.CookiesSetDetails; - type CrashReporterStartOptions = Electron.CrashReporterStartOptions; - type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; - type CreateFromBufferOptions = Electron.CreateFromBufferOptions; - type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; - type Data = Electron.Data; - type Details = Electron.Details; - type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; - type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; - type DidCreateWindowDetails = Electron.DidCreateWindowDetails; - type DidFailLoadEvent = Electron.DidFailLoadEvent; - type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; - type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; - type DidNavigateEvent = Electron.DidNavigateEvent; - type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; - type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; - type DidStartNavigationEvent = Electron.DidStartNavigationEvent; - type DisplayBalloonOptions = Electron.DisplayBalloonOptions; - type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; - type FeedURLOptions = Electron.FeedURLOptions; - type FileIconOptions = Electron.FileIconOptions; - type FindInPageOptions = Electron.FindInPageOptions; - type FocusOptions = Electron.FocusOptions; - type FoundInPageEvent = Electron.FoundInPageEvent; - type FrameCreatedDetails = Electron.FrameCreatedDetails; - type FromPartitionOptions = Electron.FromPartitionOptions; - type HandlerDetails = Electron.HandlerDetails; - type HeadersReceivedResponse = Electron.HeadersReceivedResponse; - type HeapStatistics = Electron.HeapStatistics; - type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; - type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; - type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; - type ImportCertificateOptions = Electron.ImportCertificateOptions; - type Info = Electron.Info; - type Input = Electron.Input; - type InsertCSSOptions = Electron.InsertCSSOptions; - type IpcMessageEvent = Electron.IpcMessageEvent; - type Item = Electron.Item; - type JumpListSettings = Electron.JumpListSettings; - type LoadCommitEvent = Electron.LoadCommitEvent; - type LoadExtensionOptions = Electron.LoadExtensionOptions; - type LoadFileOptions = Electron.LoadFileOptions; - type LoadURLOptions = Electron.LoadURLOptions; - type LoginItemSettings = Electron.LoginItemSettings; - type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; - type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; - type MessageBoxOptions = Electron.MessageBoxOptions; - type MessageBoxReturnValue = Electron.MessageBoxReturnValue; - type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; - type MessageDetails = Electron.MessageDetails; - type MessageEvent = Electron.MessageEvent; - type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; - type NewWindowEvent = Electron.NewWindowEvent; - type NotificationConstructorOptions = Electron.NotificationConstructorOptions; - type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; - type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; - type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; - type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; - type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; - type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; - type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; - type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; - type OpenDevToolsOptions = Electron.OpenDevToolsOptions; - type OpenDialogOptions = Electron.OpenDialogOptions; - type OpenDialogReturnValue = Electron.OpenDialogReturnValue; - type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; - type OpenExternalOptions = Electron.OpenExternalOptions; - type Options = Electron.Options; - type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; - type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; - type Parameters = Electron.Parameters; - type Payment = Electron.Payment; - type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; - type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; - type PluginCrashedEvent = Electron.PluginCrashedEvent; - type PopupOptions = Electron.PopupOptions; - type PreconnectOptions = Electron.PreconnectOptions; - type PrintToPDFOptions = Electron.PrintToPDFOptions; - type Privileges = Electron.Privileges; - type ProgressBarOptions = Electron.ProgressBarOptions; - type Provider = Electron.Provider; - type ReadBookmark = Electron.ReadBookmark; - type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; - type RelaunchOptions = Electron.RelaunchOptions; - type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; - type Request = Electron.Request; - type ResizeOptions = Electron.ResizeOptions; - type ResourceUsage = Electron.ResourceUsage; - type Response = Electron.Response; - type Result = Electron.Result; - type SaveDialogOptions = Electron.SaveDialogOptions; - type SaveDialogReturnValue = Electron.SaveDialogReturnValue; - type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; - type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; - type Settings = Electron.Settings; - type SourcesOptions = Electron.SourcesOptions; - type SSLConfigConfig = Electron.SSLConfigConfig; - type StartLoggingOptions = Electron.StartLoggingOptions; - type SystemMemoryInfo = Electron.SystemMemoryInfo; - type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; - type TitleOptions = Electron.TitleOptions; - type ToBitmapOptions = Electron.ToBitmapOptions; - type ToDataURLOptions = Electron.ToDataURLOptions; - type ToPNGOptions = Electron.ToPNGOptions; - type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; - type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; - type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; - type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; - type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; - type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; - type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; - type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; - type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; - type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; - type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; - type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; - type UploadProgress = Electron.UploadProgress; - type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; - type WebContentsPrintOptions = Electron.WebContentsPrintOptions; - type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; - type WillNavigateEvent = Electron.WillNavigateEvent; - type WillResizeDetails = Electron.WillResizeDetails; - type EditFlags = Electron.EditFlags; - type FoundInPageResult = Electron.FoundInPageResult; - type LaunchItems = Electron.LaunchItems; - type Margins = Electron.Margins; - type MediaFlags = Electron.MediaFlags; - type PageRanges = Electron.PageRanges; - type Params = Electron.Params; - type TitleBarOverlay = Electron.TitleBarOverlay; - type WebPreferences = Electron.WebPreferences; - type DefaultFontFamily = Electron.DefaultFontFamily; - type BluetoothDevice = Electron.BluetoothDevice; - type Certificate = Electron.Certificate; - type CertificatePrincipal = Electron.CertificatePrincipal; - type Cookie = Electron.Cookie; - type CPUUsage = Electron.CPUUsage; - type CrashReport = Electron.CrashReport; - type CustomScheme = Electron.CustomScheme; - type DesktopCapturerSource = Electron.DesktopCapturerSource; - type Display = Electron.Display; - type Event = Electron.Event; - type Extension = Electron.Extension; - type ExtensionInfo = Electron.ExtensionInfo; - type FileFilter = Electron.FileFilter; - type FilePathWithHeaders = Electron.FilePathWithHeaders; - type GPUFeatureStatus = Electron.GPUFeatureStatus; - type HIDDevice = Electron.HIDDevice; - type InputEvent = Electron.InputEvent; - type IOCounters = Electron.IOCounters; - type IpcMainEvent = Electron.IpcMainEvent; - type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; - type IpcRendererEvent = Electron.IpcRendererEvent; - type JumpListCategory = Electron.JumpListCategory; - type JumpListItem = Electron.JumpListItem; - type KeyboardEvent = Electron.KeyboardEvent; - type KeyboardInputEvent = Electron.KeyboardInputEvent; - type MemoryInfo = Electron.MemoryInfo; - type MemoryUsageDetails = Electron.MemoryUsageDetails; - type MimeTypedBuffer = Electron.MimeTypedBuffer; - type MouseInputEvent = Electron.MouseInputEvent; - type MouseWheelInputEvent = Electron.MouseWheelInputEvent; - type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; - type NotificationAction = Electron.NotificationAction; - type NotificationResponse = Electron.NotificationResponse; - type PaymentDiscount = Electron.PaymentDiscount; - type Point = Electron.Point; - type PostBody = Electron.PostBody; - type PrinterInfo = Electron.PrinterInfo; - type ProcessMemoryInfo = Electron.ProcessMemoryInfo; - type ProcessMetric = Electron.ProcessMetric; - type Product = Electron.Product; - type ProductDiscount = Electron.ProductDiscount; - type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; - type ProtocolRequest = Electron.ProtocolRequest; - type ProtocolResponse = Electron.ProtocolResponse; - type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; - type Rectangle = Electron.Rectangle; - type Referrer = Electron.Referrer; - type ScrubberItem = Electron.ScrubberItem; - type SegmentedControlSegment = Electron.SegmentedControlSegment; - type SerialPort = Electron.SerialPort; - type ServiceWorkerInfo = Electron.ServiceWorkerInfo; - type SharedWorkerInfo = Electron.SharedWorkerInfo; - type SharingItem = Electron.SharingItem; - type ShortcutDetails = Electron.ShortcutDetails; - type Size = Electron.Size; - type Task = Electron.Task; - type ThumbarButton = Electron.ThumbarButton; - type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; - type TraceConfig = Electron.TraceConfig; - type Transaction = Electron.Transaction; - type UploadData = Electron.UploadData; - type UploadFile = Electron.UploadFile; - type UploadRawData = Electron.UploadRawData; - type UserDefaultTypes = Electron.UserDefaultTypes; - type WebRequestFilter = Electron.WebRequestFilter; - type WebSource = Electron.WebSource; - } - - namespace CrossProcessExports { - const app: App; - type App = Electron.App; - const autoUpdater: AutoUpdater; - type AutoUpdater = Electron.AutoUpdater; - class BrowserView extends Electron.BrowserView {} - class BrowserWindow extends Electron.BrowserWindow {} - type ClientRequest = Electron.ClientRequest; - const clipboard: Clipboard; - type Clipboard = Electron.Clipboard; - type CommandLine = Electron.CommandLine; - const contentTracing: ContentTracing; - type ContentTracing = Electron.ContentTracing; - const contextBridge: ContextBridge; - type ContextBridge = Electron.ContextBridge; - type Cookies = Electron.Cookies; - const crashReporter: CrashReporter; - type CrashReporter = Electron.CrashReporter; - type Debugger = Electron.Debugger; - const desktopCapturer: DesktopCapturer; - type DesktopCapturer = Electron.DesktopCapturer; - const dialog: Dialog; - type Dialog = Electron.Dialog; - type Dock = Electron.Dock; - type DownloadItem = Electron.DownloadItem; - const globalShortcut: GlobalShortcut; - type GlobalShortcut = Electron.GlobalShortcut; - const inAppPurchase: InAppPurchase; - type InAppPurchase = Electron.InAppPurchase; - type IncomingMessage = Electron.IncomingMessage; - const ipcMain: IpcMain; - type IpcMain = Electron.IpcMain; - const ipcRenderer: IpcRenderer; - type IpcRenderer = Electron.IpcRenderer; - class Menu extends Electron.Menu {} - class MenuItem extends Electron.MenuItem {} - class MessageChannelMain extends Electron.MessageChannelMain {} - type MessagePortMain = Electron.MessagePortMain; - const nativeImage: typeof NativeImage; - type NativeImage = Electron.NativeImage; - const nativeTheme: NativeTheme; - type NativeTheme = Electron.NativeTheme; - const net: Net; - type Net = Electron.Net; - const netLog: NetLog; - type NetLog = Electron.NetLog; - class Notification extends Electron.Notification {} - const powerMonitor: PowerMonitor; - type PowerMonitor = Electron.PowerMonitor; - const powerSaveBlocker: PowerSaveBlocker; - type PowerSaveBlocker = Electron.PowerSaveBlocker; - const protocol: Protocol; - type Protocol = Electron.Protocol; - const safeStorage: SafeStorage; - type SafeStorage = Electron.SafeStorage; - const screen: Screen; - type Screen = Electron.Screen; - type ServiceWorkers = Electron.ServiceWorkers; - const session: typeof Session; - type Session = Electron.Session; - class ShareMenu extends Electron.ShareMenu {} - const shell: Shell; - type Shell = Electron.Shell; - const systemPreferences: SystemPreferences; - type SystemPreferences = Electron.SystemPreferences; - class TouchBar extends Electron.TouchBar {} - type TouchBarButton = Electron.TouchBarButton; - type TouchBarColorPicker = Electron.TouchBarColorPicker; - type TouchBarGroup = Electron.TouchBarGroup; - type TouchBarLabel = Electron.TouchBarLabel; - type TouchBarOtherItemsProxy = Electron.TouchBarOtherItemsProxy; - type TouchBarPopover = Electron.TouchBarPopover; - type TouchBarScrubber = Electron.TouchBarScrubber; - type TouchBarSegmentedControl = Electron.TouchBarSegmentedControl; - type TouchBarSlider = Electron.TouchBarSlider; - type TouchBarSpacer = Electron.TouchBarSpacer; - class Tray extends Electron.Tray {} - const webContents: typeof WebContents; - type WebContents = Electron.WebContents; - const webFrame: WebFrame; - type WebFrame = Electron.WebFrame; - const webFrameMain: typeof WebFrameMain; - type WebFrameMain = Electron.WebFrameMain; - type WebRequest = Electron.WebRequest; - type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; - type AddRepresentationOptions = Electron.AddRepresentationOptions; - type AnimationSettings = Electron.AnimationSettings; - type AppDetailsOptions = Electron.AppDetailsOptions; - type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; - type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; - type AuthInfo = Electron.AuthInfo; - type AutoResizeOptions = Electron.AutoResizeOptions; - type BeforeSendResponse = Electron.BeforeSendResponse; - type BitmapOptions = Electron.BitmapOptions; - type BlinkMemoryInfo = Electron.BlinkMemoryInfo; - type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; - type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; - type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; - type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; - type ClearStorageDataOptions = Electron.ClearStorageDataOptions; - type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; - type Config = Electron.Config; - type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; - type ConsoleMessageEvent = Electron.ConsoleMessageEvent; - type ContextMenuEvent = Electron.ContextMenuEvent; - type ContextMenuParams = Electron.ContextMenuParams; - type ContinueActivityDetails = Electron.ContinueActivityDetails; - type CookiesGetFilter = Electron.CookiesGetFilter; - type CookiesSetDetails = Electron.CookiesSetDetails; - type CrashReporterStartOptions = Electron.CrashReporterStartOptions; - type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; - type CreateFromBufferOptions = Electron.CreateFromBufferOptions; - type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; - type Data = Electron.Data; - type Details = Electron.Details; - type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; - type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; - type DidCreateWindowDetails = Electron.DidCreateWindowDetails; - type DidFailLoadEvent = Electron.DidFailLoadEvent; - type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; - type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; - type DidNavigateEvent = Electron.DidNavigateEvent; - type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; - type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; - type DidStartNavigationEvent = Electron.DidStartNavigationEvent; - type DisplayBalloonOptions = Electron.DisplayBalloonOptions; - type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; - type FeedURLOptions = Electron.FeedURLOptions; - type FileIconOptions = Electron.FileIconOptions; - type FindInPageOptions = Electron.FindInPageOptions; - type FocusOptions = Electron.FocusOptions; - type FoundInPageEvent = Electron.FoundInPageEvent; - type FrameCreatedDetails = Electron.FrameCreatedDetails; - type FromPartitionOptions = Electron.FromPartitionOptions; - type HandlerDetails = Electron.HandlerDetails; - type HeadersReceivedResponse = Electron.HeadersReceivedResponse; - type HeapStatistics = Electron.HeapStatistics; - type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; - type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; - type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; - type ImportCertificateOptions = Electron.ImportCertificateOptions; - type Info = Electron.Info; - type Input = Electron.Input; - type InsertCSSOptions = Electron.InsertCSSOptions; - type IpcMessageEvent = Electron.IpcMessageEvent; - type Item = Electron.Item; - type JumpListSettings = Electron.JumpListSettings; - type LoadCommitEvent = Electron.LoadCommitEvent; - type LoadExtensionOptions = Electron.LoadExtensionOptions; - type LoadFileOptions = Electron.LoadFileOptions; - type LoadURLOptions = Electron.LoadURLOptions; - type LoginItemSettings = Electron.LoginItemSettings; - type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; - type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; - type MessageBoxOptions = Electron.MessageBoxOptions; - type MessageBoxReturnValue = Electron.MessageBoxReturnValue; - type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; - type MessageDetails = Electron.MessageDetails; - type MessageEvent = Electron.MessageEvent; - type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; - type NewWindowEvent = Electron.NewWindowEvent; - type NotificationConstructorOptions = Electron.NotificationConstructorOptions; - type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; - type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; - type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; - type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; - type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; - type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; - type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; - type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; - type OpenDevToolsOptions = Electron.OpenDevToolsOptions; - type OpenDialogOptions = Electron.OpenDialogOptions; - type OpenDialogReturnValue = Electron.OpenDialogReturnValue; - type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; - type OpenExternalOptions = Electron.OpenExternalOptions; - type Options = Electron.Options; - type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; - type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; - type Parameters = Electron.Parameters; - type Payment = Electron.Payment; - type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; - type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; - type PluginCrashedEvent = Electron.PluginCrashedEvent; - type PopupOptions = Electron.PopupOptions; - type PreconnectOptions = Electron.PreconnectOptions; - type PrintToPDFOptions = Electron.PrintToPDFOptions; - type Privileges = Electron.Privileges; - type ProgressBarOptions = Electron.ProgressBarOptions; - type Provider = Electron.Provider; - type ReadBookmark = Electron.ReadBookmark; - type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; - type RelaunchOptions = Electron.RelaunchOptions; - type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; - type Request = Electron.Request; - type ResizeOptions = Electron.ResizeOptions; - type ResourceUsage = Electron.ResourceUsage; - type Response = Electron.Response; - type Result = Electron.Result; - type SaveDialogOptions = Electron.SaveDialogOptions; - type SaveDialogReturnValue = Electron.SaveDialogReturnValue; - type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; - type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; - type Settings = Electron.Settings; - type SourcesOptions = Electron.SourcesOptions; - type SSLConfigConfig = Electron.SSLConfigConfig; - type StartLoggingOptions = Electron.StartLoggingOptions; - type SystemMemoryInfo = Electron.SystemMemoryInfo; - type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; - type TitleOptions = Electron.TitleOptions; - type ToBitmapOptions = Electron.ToBitmapOptions; - type ToDataURLOptions = Electron.ToDataURLOptions; - type ToPNGOptions = Electron.ToPNGOptions; - type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; - type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; - type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; - type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; - type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; - type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; - type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; - type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; - type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; - type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; - type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; - type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; - type UploadProgress = Electron.UploadProgress; - type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; - type WebContentsPrintOptions = Electron.WebContentsPrintOptions; - type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; - type WillNavigateEvent = Electron.WillNavigateEvent; - type WillResizeDetails = Electron.WillResizeDetails; - type EditFlags = Electron.EditFlags; - type FoundInPageResult = Electron.FoundInPageResult; - type LaunchItems = Electron.LaunchItems; - type Margins = Electron.Margins; - type MediaFlags = Electron.MediaFlags; - type PageRanges = Electron.PageRanges; - type Params = Electron.Params; - type TitleBarOverlay = Electron.TitleBarOverlay; - type WebPreferences = Electron.WebPreferences; - type DefaultFontFamily = Electron.DefaultFontFamily; - type BluetoothDevice = Electron.BluetoothDevice; - type Certificate = Electron.Certificate; - type CertificatePrincipal = Electron.CertificatePrincipal; - type Cookie = Electron.Cookie; - type CPUUsage = Electron.CPUUsage; - type CrashReport = Electron.CrashReport; - type CustomScheme = Electron.CustomScheme; - type DesktopCapturerSource = Electron.DesktopCapturerSource; - type Display = Electron.Display; - type Event = Electron.Event; - type Extension = Electron.Extension; - type ExtensionInfo = Electron.ExtensionInfo; - type FileFilter = Electron.FileFilter; - type FilePathWithHeaders = Electron.FilePathWithHeaders; - type GPUFeatureStatus = Electron.GPUFeatureStatus; - type HIDDevice = Electron.HIDDevice; - type InputEvent = Electron.InputEvent; - type IOCounters = Electron.IOCounters; - type IpcMainEvent = Electron.IpcMainEvent; - type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; - type IpcRendererEvent = Electron.IpcRendererEvent; - type JumpListCategory = Electron.JumpListCategory; - type JumpListItem = Electron.JumpListItem; - type KeyboardEvent = Electron.KeyboardEvent; - type KeyboardInputEvent = Electron.KeyboardInputEvent; - type MemoryInfo = Electron.MemoryInfo; - type MemoryUsageDetails = Electron.MemoryUsageDetails; - type MimeTypedBuffer = Electron.MimeTypedBuffer; - type MouseInputEvent = Electron.MouseInputEvent; - type MouseWheelInputEvent = Electron.MouseWheelInputEvent; - type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; - type NotificationAction = Electron.NotificationAction; - type NotificationResponse = Electron.NotificationResponse; - type PaymentDiscount = Electron.PaymentDiscount; - type Point = Electron.Point; - type PostBody = Electron.PostBody; - type PrinterInfo = Electron.PrinterInfo; - type ProcessMemoryInfo = Electron.ProcessMemoryInfo; - type ProcessMetric = Electron.ProcessMetric; - type Product = Electron.Product; - type ProductDiscount = Electron.ProductDiscount; - type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; - type ProtocolRequest = Electron.ProtocolRequest; - type ProtocolResponse = Electron.ProtocolResponse; - type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; - type Rectangle = Electron.Rectangle; - type Referrer = Electron.Referrer; - type ScrubberItem = Electron.ScrubberItem; - type SegmentedControlSegment = Electron.SegmentedControlSegment; - type SerialPort = Electron.SerialPort; - type ServiceWorkerInfo = Electron.ServiceWorkerInfo; - type SharedWorkerInfo = Electron.SharedWorkerInfo; - type SharingItem = Electron.SharingItem; - type ShortcutDetails = Electron.ShortcutDetails; - type Size = Electron.Size; - type Task = Electron.Task; - type ThumbarButton = Electron.ThumbarButton; - type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; - type TraceConfig = Electron.TraceConfig; - type Transaction = Electron.Transaction; - type UploadData = Electron.UploadData; - type UploadFile = Electron.UploadFile; - type UploadRawData = Electron.UploadRawData; - type UserDefaultTypes = Electron.UserDefaultTypes; - type WebRequestFilter = Electron.WebRequestFilter; - type WebSource = Electron.WebSource; - } + type: string) => void): this; + removeListener(event: 'will-continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to `NSUserActivity.activityType`. + */ + type: string) => void): this; + /** + * Emitted when the application has finished basic startup. On Windows and Linux, + * the `will-finish-launching` event is the same as the `ready` event; on macOS, + * this event represents the `applicationWillFinishLaunching` notification of + * `NSApplication`. You would usually set up listeners for the `open-file` and + * `open-url` events here, and start the crash reporter and auto updater. + * + * In most cases, you should do everything in the `ready` event handler. + */ + on(event: 'will-finish-launching', listener: Function): this; + once(event: 'will-finish-launching', listener: Function): this; + addListener(event: 'will-finish-launching', listener: Function): this; + removeListener(event: 'will-finish-launching', listener: Function): this; + /** + * Emitted when all windows have been closed and the application will quit. Calling + * `event.preventDefault()` will prevent the default behavior, which is terminating + * the application. + * + * See the description of the `window-all-closed` event for the differences between + * the `will-quit` and `window-all-closed` events. + * + * **Note:** On Windows, this event will not be emitted if the app is closed due to + * a shutdown/restart of the system or a user logout. + */ + on(event: 'will-quit', listener: (event: Event) => void): this; + once(event: 'will-quit', listener: (event: Event) => void): this; + addListener(event: 'will-quit', listener: (event: Event) => void): this; + removeListener(event: 'will-quit', listener: (event: Event) => void): this; + /** + * Emitted when all windows have been closed. + * + * If you do not subscribe to this event and all windows are closed, the default + * behavior is to quit the app; however, if you subscribe, you control whether the + * app quits or not. If the user pressed `Cmd + Q`, or the developer called + * `app.quit()`, Electron will first try to close all the windows and then emit the + * `will-quit` event, and in this case the `window-all-closed` event would not be + * emitted. + */ + on(event: 'window-all-closed', listener: Function): this; + once(event: 'window-all-closed', listener: Function): this; + addListener(event: 'window-all-closed', listener: Function): this; + removeListener(event: 'window-all-closed', listener: Function): this; + /** + * Adds `path` to the recent documents list. + * + * This list is managed by the OS. On Windows, you can visit the list from the task + * bar, and on macOS, you can visit it from dock menu. + * + * @platform darwin,win32 + */ + addRecentDocument(path: string): void; + /** + * Clears the recent documents list. + * + * @platform darwin,win32 + */ + clearRecentDocuments(): void; + /** + * Configures host resolution (DNS and DNS-over-HTTPS). By default, the following + * resolvers will be used, in order: + * + * * DNS-over-HTTPS, if the DNS provider supports it, then + * * the built-in resolver (enabled on macOS only by default), then + * * the system's resolver (e.g. `getaddrinfo`). + * + * This can be configured to either restrict usage of non-encrypted DNS + * (`secureDnsMode: "secure"`), or disable DNS-over-HTTPS (`secureDnsMode: "off"`). + * It is also possible to enable or disable the built-in resolver. + * + * To disable insecure DNS, you can specify a `secureDnsMode` of `"secure"`. If you + * do so, you should make sure to provide a list of DNS-over-HTTPS servers to use, + * in case the user's DNS configuration does not include a provider that supports + * DoH. + * + * This API must be called after the `ready` event is emitted. + */ + configureHostResolver(options: ConfigureHostResolverOptions): void; + /** + * By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per domain + * basis if the GPU processes crashes too frequently. This function disables that + * behavior. + * + * This method can only be called before app is ready. + */ + disableDomainBlockingFor3DAPIs(): void; + /** + * Disables hardware acceleration for current app. + * + * This method can only be called before app is ready. + */ + disableHardwareAcceleration(): void; + /** + * Enables full sandbox mode on the app. This means that all renderers will be + * launched sandboxed, regardless of the value of the `sandbox` flag in + * WebPreferences. + * + * This method can only be called before app is ready. + */ + enableSandbox(): void; + /** + * Exits immediately with `exitCode`. `exitCode` defaults to 0. + * + * All windows will be closed immediately without asking the user, and the + * `before-quit` and `will-quit` events will not be emitted. + */ + exit(exitCode?: number): void; + /** + * On Linux, focuses on the first visible window. On macOS, makes the application + * the active app. On Windows, focuses on the application's first window. + * + * You should seek to use the `steal` option as sparingly as possible. + */ + focus(options?: FocusOptions): void; + /** + * Resolve with an object containing the following: + * + * * `icon` NativeImage - the display icon of the app handling the protocol. + * * `path` string - installation path of the app handling the protocol. + * * `name` string - display name of the app handling the protocol. + * + * This method returns a promise that contains the application name, icon and path + * of the default handler for the protocol (aka URI scheme) of a URL. + * + * @platform darwin,win32 + */ + getApplicationInfoForProtocol(url: string): Promise<Electron.ApplicationInfoForProtocolReturnValue>; + /** + * Name of the application handling the protocol, or an empty string if there is no + * handler. For instance, if Electron is the default handler of the URL, this could + * be `Electron` on Windows and Mac. However, don't rely on the precise format + * which is not guaranteed to remain unchanged. Expect a different format on Linux, + * possibly with a `.desktop` suffix. + * + * This method returns the application name of the default handler for the protocol + * (aka URI scheme) of a URL. + */ + getApplicationNameForProtocol(url: string): string; + /** + * Array of `ProcessMetric` objects that correspond to memory and CPU usage + * statistics of all the processes associated with the app. + */ + getAppMetrics(): ProcessMetric[]; + /** + * The current application directory. + */ + getAppPath(): string; + /** + * The current value displayed in the counter badge. + * + * @platform linux,darwin + */ + getBadgeCount(): number; + /** + * The type of the currently running activity. + * + * @platform darwin + */ + getCurrentActivityType(): string; + /** + * fulfilled with the app's icon, which is a NativeImage. + * + * Fetches a path's associated icon. + * + * On _Windows_, there a 2 kinds of icons: + * + * * Icons associated with certain file extensions, like `.mp3`, `.png`, etc. + * * Icons inside the file itself, like `.exe`, `.dll`, `.ico`. + * + * On _Linux_ and _macOS_, icons depend on the application associated with file + * mime type. + */ + getFileIcon(path: string, options?: FileIconOptions): Promise<Electron.NativeImage>; + /** + * The Graphics Feature Status from `chrome://gpu/`. + * + * **Note:** This information is only usable after the `gpu-info-update` event is + * emitted. + */ + getGPUFeatureStatus(): GPUFeatureStatus; + /** + * For `infoType` equal to `complete`: Promise is fulfilled with `Object` + * containing all the GPU Information as in chromium's GPUInfo object. This + * includes the version and driver information that's shown on `chrome://gpu` page. + * + * For `infoType` equal to `basic`: Promise is fulfilled with `Object` containing + * fewer attributes than when requested with `complete`. Here's an example of basic + * response: + * + * Using `basic` should be preferred if only basic information like `vendorId` or + * `driverId` is needed. + */ + getGPUInfo(infoType: 'basic' | 'complete'): Promise<unknown>; + /** + * * `minItems` Integer - The minimum number of items that will be shown in the + * Jump List (for a more detailed description of this value see the MSDN docs). + * * `removedItems` JumpListItem[] - Array of `JumpListItem` objects that + * correspond to items that the user has explicitly removed from custom categories + * in the Jump List. These items must not be re-added to the Jump List in the + * **next** call to `app.setJumpList()`, Windows will not display any custom + * category that contains any of the removed items. + * + * @platform win32 + */ + getJumpListSettings(): JumpListSettings; + /** + * The current application locale, fetched using Chromium's `l10n_util` library. + * Possible return values are documented here. + * + * To set the locale, you'll want to use a command line switch at app startup, + * which may be found here. + * + * **Note:** When distributing your packaged app, you have to also ship the + * `locales` folder. + * + * **Note:** This API must be called after the `ready` event is emitted. + */ + getLocale(): string; + /** + * User operating system's locale two-letter ISO 3166 country code. The value is + * taken from native OS APIs. + * + * **Note:** When unable to detect locale country code, it returns empty string. + */ + getLocaleCountryCode(): string; + /** + * If you provided `path` and `args` options to `app.setLoginItemSettings`, then + * you need to pass the same arguments here for `openAtLogin` to be set correctly. + * + * + * * `openAtLogin` boolean - `true` if the app is set to open at login. + * * `openAsHidden` boolean _macOS_ - `true` if the app is set to open as hidden at + * login. This setting is not available on MAS builds. + * * `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login + * automatically. This setting is not available on MAS builds. + * * `wasOpenedAsHidden` boolean _macOS_ - `true` if the app was opened as a hidden + * login item. This indicates that the app should not open any windows at startup. + * This setting is not available on MAS builds. + * * `restoreState` boolean _macOS_ - `true` if the app was opened as a login item + * that should restore the state from the previous session. This indicates that the + * app should restore the windows that were open the last time the app was closed. + * This setting is not available on MAS builds. + * * `executableWillLaunchAtLogin` boolean _Windows_ - `true` if app is set to open + * at login and its run key is not deactivated. This differs from `openAtLogin` as + * it ignores the `args` option, this property will be true if the given executable + * would be launched at login with **any** arguments. + * * `launchItems` Object[] _Windows_ + * * `name` string _Windows_ - name value of a registry entry. + * * `path` string _Windows_ - The executable to an app that corresponds to a + * registry entry. + * * `args` string[] _Windows_ - the command-line arguments to pass to the + * executable. + * * `scope` string _Windows_ - one of `user` or `machine`. Indicates whether the + * registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. + * * `enabled` boolean _Windows_ - `true` if the app registry key is startup + * approved and therefore shows as `enabled` in Task Manager and Windows settings. + * + * @platform darwin,win32 + */ + getLoginItemSettings(options?: LoginItemSettingsOptions): LoginItemSettings; + /** + * The current application's name, which is the name in the application's + * `package.json` file. + * + * Usually the `name` field of `package.json` is a short lowercase name, according + * to the npm modules spec. You should usually also specify a `productName` field, + * which is your application's full capitalized name, and which will be preferred + * over `name` by Electron. + */ + getName(): string; + /** + * A path to a special directory or file associated with `name`. On failure, an + * `Error` is thrown. + * + * If `app.getPath('logs')` is called without called `app.setAppLogsPath()` being + * called first, a default log directory will be created equivalent to calling + * `app.setAppLogsPath()` without a `path` parameter. + */ + getPath(name: 'home' | 'appData' | 'userData' | 'sessionData' | 'temp' | 'exe' | 'module' | 'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos' | 'recent' | 'logs' | 'crashDumps'): string; + /** + * The current system locale. On Windows and Linux, it is fetched using Chromium's + * `i18n` library. On macOS, the `NSLocale` object is used instead. + * + * **Note:** This API must be called after the `ready` event is emitted. + */ + getSystemLocale(): string; + /** + * The version of the loaded application. If no version is found in the + * application's `package.json` file, the version of the current bundle or + * executable is returned. + */ + getVersion(): string; + /** + * This method returns whether or not this instance of your app is currently + * holding the single instance lock. You can request the lock with + * `app.requestSingleInstanceLock()` and release with + * `app.releaseSingleInstanceLock()` + */ + hasSingleInstanceLock(): boolean; + /** + * Hides all application windows without minimizing them. + * + * @platform darwin + */ + hide(): void; + /** + * Imports the certificate in pkcs12 format into the platform certificate store. + * `callback` is called with the `result` of import operation, a value of `0` + * indicates success while any other value indicates failure according to Chromium + * net_error_list. + * + * @platform linux + */ + importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; + /** + * Invalidates the current Handoff user activity. + * + * @platform darwin + */ + invalidateCurrentActivity(): void; + /** + * `true` if Chrome's accessibility support is enabled, `false` otherwise. This API + * will return `true` if the use of assistive technologies, such as screen readers, + * has been detected. See + * https://www.chromium.org/developers/design-documents/accessibility for more + * details. + * + * @platform darwin,win32 + */ + isAccessibilitySupportEnabled(): boolean; + /** + * Whether the current executable is the default handler for a protocol (aka URI + * scheme). + * + * **Note:** On macOS, you can use this method to check if the app has been + * registered as the default protocol handler for a protocol. You can also verify + * this by checking `~/Library/Preferences/com.apple.LaunchServices.plist` on the + * macOS machine. Please refer to Apple's documentation for details. + * + * The API uses the Windows Registry and `LSCopyDefaultHandlerForURLScheme` + * internally. + */ + isDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; + /** + * whether or not the current OS version allows for native emoji pickers. + */ + isEmojiPanelSupported(): boolean; + /** + * `true` if the applicationβ€”including all of its windowsβ€”is hidden (e.g. with + * `Command-H`), `false` otherwise. + * + * @platform darwin + */ + isHidden(): boolean; + /** + * Whether the application is currently running from the systems Application + * folder. Use in combination with `app.moveToApplicationsFolder()` + * + * @platform darwin + */ + isInApplicationsFolder(): boolean; + /** + * `true` if Electron has finished initializing, `false` otherwise. See also + * `app.whenReady()`. + */ + isReady(): boolean; + /** + * whether `Secure Keyboard Entry` is enabled. + * + * By default this API will return `false`. + * + * @platform darwin + */ + isSecureKeyboardEntryEnabled(): boolean; + /** + * Whether the current desktop environment is Unity launcher. + * + * @platform linux + */ + isUnityRunning(): boolean; + /** + * Whether the move was successful. Please note that if the move is successful, + * your application will quit and relaunch. + * + * No confirmation dialog will be presented by default. If you wish to allow the + * user to confirm the operation, you may do so using the `dialog` API. + * + * **NOTE:** This method throws errors if anything other than the user causes the + * move to fail. For instance if the user cancels the authorization dialog, this + * 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. + * + * For example: + * + * Would mean that if an app already exists in the user directory, if the user + * chooses to 'Continue Move' then the function would continue with its default + * behavior and the existing app will be trashed and the active app moved into its + * place. + * + * @platform darwin + */ + moveToApplicationsFolder(options?: MoveToApplicationsFolderOptions): boolean; + /** + * Try to close all windows. The `before-quit` event will be emitted first. If all + * windows are successfully closed, the `will-quit` event will be emitted and by + * default the application will terminate. + * + * This method guarantees that all `beforeunload` and `unload` event handlers are + * correctly executed. It is possible that a window cancels the quitting by + * returning `false` in the `beforeunload` event handler. + */ + quit(): void; + /** + * Relaunches the app when current instance exits. + * + * By default, the new instance will use the same working directory and command + * line arguments with current instance. When `args` is specified, the `args` will + * be passed as command line arguments instead. When `execPath` is specified, the + * `execPath` will be executed for relaunch instead of current app. + * + * Note that this method does not quit the app when executed, you have to call + * `app.quit` or `app.exit` after calling `app.relaunch` to make the app restart. + * + * When `app.relaunch` is called for multiple times, multiple instances will be + * started after current instance exited. + * + * An example of restarting current instance immediately and adding a new command + * line argument to the new instance: + */ + relaunch(options?: RelaunchOptions): void; + /** + * Releases all locks that were created by `requestSingleInstanceLock`. This will + * allow multiple instances of the application to once again run side by side. + */ + releaseSingleInstanceLock(): void; + /** + * Whether the call succeeded. + * + * This method checks if the current executable as the default handler for a + * protocol (aka URI scheme). If so, it will remove the app as the default handler. + * + * @platform darwin,win32 + */ + removeAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; + /** + * The return value of this method indicates whether or not this instance of your + * application successfully obtained the lock. If it failed to obtain the lock, + * you can assume that another instance of your application is already running with + * the lock and exit immediately. + * + * I.e. This method returns `true` if your process is the primary instance of your + * application and your app should continue loading. It returns `false` if your + * process should immediately quit as it has sent its parameters to another + * instance that has already acquired the lock. + * + * On macOS, the system enforces single instance automatically when users try to + * open a second instance of your app in Finder, and the `open-file` and `open-url` + * events will be emitted for that. However when users start your app in command + * line, the system's single instance mechanism will be bypassed, and you have to + * use this method to ensure single instance. + * + * An example of activating the window of primary instance when a second instance + * starts: + */ + requestSingleInstanceLock(additionalData?: Record<any, any>): boolean; + /** + * Marks the current Handoff user activity as inactive without invalidating it. + * + * @platform darwin + */ + resignCurrentActivity(): void; + /** + * Set the about panel options. This will override the values defined in the app's + * `.plist` file on macOS. See the Apple docs for more details. On Linux, values + * must be set in order to be shown; there are no defaults. + * + * If you do not set `credits` but still wish to surface them in your app, AppKit + * will look for a file named "Credits.html", "Credits.rtf", and "Credits.rtfd", in + * that order, in the bundle returned by the NSBundle class method main. The first + * file found is used, and if none is found, the info area is left blank. See Apple + * documentation for more information. + */ + setAboutPanelOptions(options: AboutPanelOptionsOptions): void; + /** + * Manually enables Chrome's accessibility support, allowing to expose + * accessibility switch to users in application settings. See Chromium's + * accessibility docs for more details. Disabled by default. + * + * This API must be called after the `ready` event is emitted. + * + * **Note:** Rendering accessibility tree can significantly affect the performance + * of your app. It should not be enabled by default. + * + * @platform darwin,win32 + */ + setAccessibilitySupportEnabled(enabled: boolean): void; + /** + * Sets the activation policy for a given app. + * + * Activation policy types: + * + * * 'regular' - The application is an ordinary app that appears in the Dock and + * may have a user interface. + * * 'accessory' - The application doesn’t appear in the Dock and doesn’t have a + * menu bar, but it may be activated programmatically or by clicking on one of its + * windows. + * * 'prohibited' - The application doesn’t appear in the Dock and may not create + * windows or be activated. + * + * @platform darwin + */ + setActivationPolicy(policy: 'regular' | 'accessory' | 'prohibited'): void; + /** + * Sets or creates a directory your app's logs which can then be manipulated with + * `app.getPath()` or `app.setPath(pathName, newPath)`. + * + * Calling `app.setAppLogsPath()` without a `path` parameter will result in this + * directory being set to `~/Library/Logs/YourAppName` on _macOS_, and inside the + * `userData` directory on _Linux_ and _Windows_. + */ + setAppLogsPath(path?: string): void; + /** + * Changes the Application User Model ID to `id`. + * + * @platform win32 + */ + setAppUserModelId(id: string): void; + /** + * Whether the call succeeded. + * + * Sets the current executable as the default handler for a protocol (aka URI + * scheme). It allows you to integrate your app deeper into the operating system. + * Once registered, all links with `your-protocol://` will be opened with the + * current executable. The whole link, including protocol, will be passed to your + * application as a parameter. + * + * **Note:** On macOS, you can only register protocols that have been added to your + * app's `info.plist`, which cannot be modified at runtime. However, you can change + * the file during build time via Electron Forge, Electron Packager, or by editing + * `info.plist` with a text editor. Please refer to Apple's documentation for + * details. + * + * **Note:** In a Windows Store environment (when packaged as an `appx`) this API + * will return `true` for all calls but the registry key it sets won't be + * accessible by other applications. In order to register your Windows Store + * application as a default protocol handler you must declare the protocol in your + * manifest. + * + * The API uses the Windows Registry and `LSSetDefaultHandlerForURLScheme` + * internally. + */ + setAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; + /** + * Whether the call succeeded. + * + * Sets the counter badge for current app. Setting the count to `0` will hide the + * badge. + * + * On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher. + * + * **Note:** Unity launcher requires a `.desktop` file to work. For more + * information, please read the Unity integration documentation. + * + * @platform linux,darwin + */ + setBadgeCount(count?: number): boolean; + /** + * Sets or removes a custom Jump List for the application, and returns one of the + * following strings: + * + * * `ok` - Nothing went wrong. + * * `error` - One or more errors occurred, enable runtime logging to figure out + * the likely cause. + * * `invalidSeparatorError` - An attempt was made to add a separator to a custom + * category in the Jump List. Separators are only allowed in the standard `Tasks` + * category. + * * `fileTypeRegistrationError` - An attempt was made to add a file link to the + * Jump List for a file type the app isn't registered to handle. + * * `customCategoryAccessDeniedError` - Custom categories can't be added to the + * Jump List due to user privacy or group policy settings. + * + * If `categories` is `null` the previously set custom Jump List (if any) will be + * replaced by the standard Jump List for the app (managed by Windows). + * + * **Note:** If a `JumpListCategory` object has neither the `type` nor the `name` + * property set then its `type` is assumed to be `tasks`. If the `name` property is + * set but the `type` property is omitted then the `type` is assumed to be + * `custom`. + * + * **Note:** Users can remove items from custom categories, and Windows will not + * allow a removed item to be added back into a custom category until **after** the + * next successful call to `app.setJumpList(categories)`. Any attempt to re-add a + * removed item to a custom category earlier than that will result in the entire + * custom category being omitted from the Jump List. The list of removed items can + * be obtained using `app.getJumpListSettings()`. + * + * **Note:** The maximum length of a Jump List item's `description` property is 260 + * characters. Beyond this limit, the item will not be added to the Jump List, nor + * will it be displayed. + * + * Here's a very simple example of creating a custom Jump List: + * + * @platform win32 + */ + setJumpList(categories: (JumpListCategory[]) | (null)): ('ok' | 'error' | 'invalidSeparatorError' | 'fileTypeRegistrationError' | 'customCategoryAccessDeniedError'); + /** + * To work with Electron's `autoUpdater` on Windows, which uses Squirrel, you'll + * want to set the launch path to Update.exe, and pass arguments that specify your + * application name. For example: + * + * @platform darwin,win32 + */ + setLoginItemSettings(settings: Settings): void; + /** + * Overrides the current application's name. + * + * **Note:** This function overrides the name used internally by Electron; it does + * not affect the name that the OS uses. + */ + setName(name: string): void; + /** + * Overrides the `path` to a special directory or file associated with `name`. If + * the path specifies a directory that does not exist, an `Error` is thrown. In + * that case, the directory should be created with `fs.mkdirSync` or similar. + * + * You can only override paths of a `name` defined in `app.getPath`. + * + * By default, web pages' cookies and caches will be stored under the `sessionData` + * directory. If you want to change this location, you have to override the + * `sessionData` path before the `ready` event of the `app` module is emitted. + */ + setPath(name: string, path: string): void; + /** + * Set the `Secure Keyboard Entry` is enabled in your application. + * + * By using this API, important information such as password and other sensitive + * information can be prevented from being intercepted by other processes. + * + * See Apple's documentation for more details. + * + * **Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it + * when it is no longer needed. + * + * @platform darwin + */ + setSecureKeyboardEntryEnabled(enabled: boolean): void; + /** + * Creates an `NSUserActivity` and sets it as the current activity. The activity is + * eligible for Handoff to another device afterward. + * + * @platform darwin + */ + setUserActivity(type: string, userInfo: any, webpageURL?: string): void; + /** + * Adds `tasks` to the Tasks category of the Jump List on Windows. + * + * `tasks` is an array of `Task` objects. + * + * Whether the call succeeded. + * + * **Note:** If you'd like to customize the Jump List even more use + * `app.setJumpList(categories)` instead. + * + * @platform win32 + */ + setUserTasks(tasks: Task[]): boolean; + /** + * Shows application windows after they were hidden. Does not automatically focus + * them. + * + * @platform darwin + */ + show(): void; + /** + * Show the app's about panel options. These options can be overridden with + * `app.setAboutPanelOptions(options)`. + */ + showAboutPanel(): void; + /** + * Show the platform's native emoji picker. + * + * @platform darwin,win32 + */ + showEmojiPanel(): void; + /** + * This function **must** be called once you have finished accessing the security + * scoped file. If you do not remember to stop accessing the bookmark, kernel + * resources will be leaked and your app will lose its ability to reach outside the + * sandbox completely, until your app is restarted. + * + * Start accessing a security scoped resource. With this method Electron + * applications that are packaged for the Mac App Store may reach outside their + * sandbox to access files chosen by the user. See Apple's documentation for a + * description of how this system works. + * + * @platform mas + */ + startAccessingSecurityScopedResource(bookmarkData: string): Function; + /** + * Updates the current activity if its type matches `type`, merging the entries + * from `userInfo` into its current `userInfo` dictionary. + * + * @platform darwin + */ + updateCurrentActivity(type: string, userInfo: any): void; + /** + * fulfilled when Electron is initialized. May be used as a convenient alternative + * to checking `app.isReady()` and subscribing to the `ready` event if the app is + * not ready yet. + */ + whenReady(): Promise<void>; + /** + * A `boolean` property that's `true` if Chrome's accessibility support is enabled, + * `false` otherwise. This property will be `true` if the use of assistive + * technologies, such as screen readers, has been detected. Setting this property + * to `true` manually enables Chrome's accessibility support, allowing developers + * to expose accessibility switch to users in application settings. + * + * See Chromium's accessibility docs for more details. Disabled by default. + * + * This API must be called after the `ready` event is emitted. + * + * **Note:** Rendering accessibility tree can significantly affect the performance + * of your app. It should not be enabled by default. + * + * @platform darwin,win32 + */ + accessibilitySupportEnabled: boolean; + /** + * A `Menu | null` property that returns `Menu` if one has been set and `null` + * otherwise. Users can pass a Menu to set this property. + */ + applicationMenu: (Menu) | (null); + /** + * An `Integer` property that returns the badge count for current app. Setting the + * count to `0` will hide the badge. + * + * On macOS, setting this with any nonzero integer shows on the dock icon. On + * Linux, this property only works for Unity launcher. + * + * **Note:** Unity launcher requires a `.desktop` file to work. For more + * information, please read the Unity integration documentation. + * + * **Note:** On macOS, you need to ensure that your application has the permission + * to display notifications for this property to take effect. + * + * @platform linux,darwin + */ + badgeCount: number; + /** + * A `CommandLine` object that allows you to read and manipulate the command line + * arguments that Chromium uses. + * + */ + readonly commandLine: CommandLine; + /** + * A `Dock` `| undefined` object that allows you to perform actions on your app + * icon in the user's dock on macOS. + * + * @platform darwin + */ + readonly dock: Dock; + /** + * A `boolean` property that returns `true` if the app is packaged, `false` + * otherwise. For many apps, this property can be used to distinguish development + * and production environments. + * + */ + readonly isPackaged: boolean; + /** + * A `string` property that indicates the current application's name, which is the + * name in the application's `package.json` file. + * + * Usually the `name` field of `package.json` is a short lowercase name, according + * to the npm modules spec. You should usually also specify a `productName` field, + * which is your application's full capitalized name, and which will be preferred + * over `name` by Electron. + */ + name: string; + /** + * A `boolean` which when `true` indicates that the app is currently running under + * an ARM64 translator (like the macOS Rosetta Translator Environment or Windows + * WOW). + * + * You can use this property to prompt users to download the arm64 version of your + * application when they are running the x64 version under Rosetta incorrectly. + * + * @platform darwin,win32 + */ + readonly runningUnderARM64Translation: boolean; + /** + * A `boolean` which when `true` indicates that the app is currently running under + * the Rosetta Translator Environment. + * + * You can use this property to prompt users to download the arm64 version of your + * application when they are running the x64 version under Rosetta incorrectly. + * + * **Deprecated:** This property is superceded by the + * `runningUnderARM64Translation` property which detects when the app is being + * translated to ARM64 in both macOS and Windows. + * + * @deprecated + * @platform darwin + */ + readonly runningUnderRosettaTranslation: boolean; + /** + * A `string` which is the user agent string Electron will use as a global + * fallback. + * + * This is the user agent that will be used when no user agent is set at the + * `webContents` or `session` level. It is useful for ensuring that your entire + * app has the same user agent. Set to a custom value as early as possible in your + * app's initialization to ensure that your overridden value is used. + */ + userAgentFallback: string; + } + + interface AutoUpdater extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/auto-updater + + /** + * This event is emitted after a user calls `quitAndInstall()`. + * + * When this API is called, the `before-quit` event is not emitted before all + * windows are closed. As a result you should listen to this event if you wish to + * perform actions before the windows are closed while a process is quitting, as + * well as listening to `before-quit`. + */ + on(event: 'before-quit-for-update', listener: Function): this; + once(event: 'before-quit-for-update', listener: Function): this; + addListener(event: 'before-quit-for-update', listener: Function): this; + removeListener(event: 'before-quit-for-update', listener: Function): this; + /** + * Emitted when checking if an update has started. + */ + on(event: 'checking-for-update', listener: Function): this; + once(event: 'checking-for-update', listener: Function): this; + addListener(event: 'checking-for-update', listener: Function): this; + removeListener(event: 'checking-for-update', listener: Function): this; + /** + * Emitted when there is an error while updating. + */ + on(event: 'error', listener: (error: Error) => void): this; + once(event: 'error', listener: (error: Error) => void): this; + addListener(event: 'error', listener: (error: Error) => void): this; + removeListener(event: 'error', listener: (error: Error) => void): this; + /** + * Emitted when there is an available update. The update is downloaded + * automatically. + */ + on(event: 'update-available', listener: Function): this; + once(event: 'update-available', listener: Function): this; + addListener(event: 'update-available', listener: Function): this; + removeListener(event: 'update-available', listener: Function): this; + /** + * Emitted when an update has been downloaded. + * + * On Windows only `releaseName` is available. + * + * **Note:** It is not strictly necessary to handle this event. A successfully + * downloaded update will still be applied the next time the application starts. + */ + on(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + once(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + addListener(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + removeListener(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + /** + * Emitted when there is no available update. + */ + on(event: 'update-not-available', listener: Function): this; + once(event: 'update-not-available', listener: Function): this; + addListener(event: 'update-not-available', listener: Function): this; + removeListener(event: 'update-not-available', listener: Function): this; + /** + * Asks the server whether there is an update. You must call `setFeedURL` before + * using this API. + * + * **Note:** If an update is available it will be downloaded automatically. Calling + * `autoUpdater.checkForUpdates()` twice will download the update two times. + */ + checkForUpdates(): void; + /** + * The current update feed URL. + */ + getFeedURL(): string; + /** + * Restarts the app and installs the update after it has been downloaded. It should + * only be called after `update-downloaded` has been emitted. + * + * Under the hood calling `autoUpdater.quitAndInstall()` will close all application + * windows first, and automatically call `app.quit()` after all windows have been + * closed. + * + * **Note:** It is not strictly necessary to call this function to apply an update, + * as a successfully downloaded update will always be applied the next time the + * application starts. + */ + quitAndInstall(): void; + /** + * Sets the `url` and initialize the auto updater. + */ + setFeedURL(options: FeedURLOptions): void; + } + + interface BluetoothDevice { + + // Docs: https://electronjs.org/docs/api/structures/bluetooth-device + + deviceId: string; + deviceName: string; + } + + class BrowserView { + + // Docs: https://electronjs.org/docs/api/browser-view + + /** + * BrowserView + */ + constructor(options?: BrowserViewConstructorOptions); + /** + * The `bounds` of this BrowserView instance as `Object`. + * + * @experimental + */ + getBounds(): Rectangle; + setAutoResize(options: AutoResizeOptions): void; + /** + * Examples of valid `color` values: + * + * * Hex + * * #fff (RGB) + * * #ffff (ARGB) + * * #ffffff (RRGGBB) + * * #ffffffff (AARRGGBB) + * * RGB + * * rgb(([\d]+),\s*([\d]+),\s*([\d]+)) + * * e.g. rgb(255, 255, 255) + * * RGBA + * * rgba(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)) + * * e.g. rgba(255, 255, 255, 1.0) + * * HSL + * * hsl((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%) + * * e.g. hsl(200, 20%, 50%) + * * HSLA + * * hsla((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)) + * * e.g. hsla(200, 20%, 50%, 0.5) + * * Color name + * * Options are listed in SkParseColor.cpp + * * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * * e.g. `blueviolet` or `red` + * + * **Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBA` or + * `RGA`. + * + * @experimental + */ + setBackgroundColor(color: string): void; + /** + * Resizes and moves the view to the supplied bounds relative to the window. + * + * @experimental + */ + setBounds(bounds: Rectangle): void; + /** + * A `WebContents` object owned by this view. + * + * @experimental + */ + webContents: WebContents; + } + + class BrowserWindow extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/browser-window + + /** + * Emitted when the window is set or unset to show always on top of other windows. + */ + on(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; + once(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; + addListener(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; + removeListener(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; + /** + * Emitted when an App Command is invoked. These are typically related to keyboard + * media keys or browser commands, as well as the "Back" button built into some + * mice on Windows. + * + * Commands are lowercased, underscores are replaced with hyphens, and the + * `APPCOMMAND_` prefix is stripped off. e.g. `APPCOMMAND_BROWSER_BACKWARD` is + * emitted as `browser-backward`. + * + * The following app commands are explicitly supported on Linux: + * + * * `browser-backward` + * * `browser-forward` + * + * @platform win32,linux + */ + on(event: 'app-command', listener: (event: Event, + command: string) => void): this; + once(event: 'app-command', listener: (event: Event, + command: string) => void): this; + addListener(event: 'app-command', listener: (event: Event, + command: string) => void): this; + removeListener(event: 'app-command', listener: (event: Event, + command: string) => void): this; + /** + * Emitted when the window loses focus. + */ + on(event: 'blur', listener: Function): this; + once(event: 'blur', listener: Function): this; + addListener(event: 'blur', listener: Function): this; + removeListener(event: 'blur', listener: Function): this; + /** + * Emitted when the window is going to be closed. It's emitted before the + * `beforeunload` and `unload` event of the DOM. Calling `event.preventDefault()` + * will cancel the close. + * + * Usually you would want to use the `beforeunload` handler to decide whether the + * window should be closed, which will also be called when the window is reloaded. + * In Electron, returning any value other than `undefined` would cancel the close. + * For example: + * + * _**Note**: There is a subtle difference between the behaviors of + * `window.onbeforeunload = handler` and `window.addEventListener('beforeunload', + * handler)`. It is recommended to always set the `event.returnValue` explicitly, + * instead of only returning a value, as the former works more consistently within + * Electron._ + */ + on(event: 'close', listener: (event: Event) => void): this; + once(event: 'close', listener: (event: Event) => void): this; + addListener(event: 'close', listener: (event: Event) => void): this; + removeListener(event: 'close', listener: (event: Event) => void): this; + /** + * Emitted when the window is closed. After you have received this event you should + * remove the reference to the window and avoid using it any more. + */ + on(event: 'closed', listener: Function): this; + once(event: 'closed', listener: Function): this; + addListener(event: 'closed', listener: Function): this; + removeListener(event: 'closed', listener: Function): this; + /** + * Emitted when the window enters a full-screen state. + */ + on(event: 'enter-full-screen', listener: Function): this; + once(event: 'enter-full-screen', listener: Function): this; + addListener(event: 'enter-full-screen', listener: Function): this; + removeListener(event: 'enter-full-screen', listener: Function): this; + /** + * Emitted when the window enters a full-screen state triggered by HTML API. + */ + on(event: 'enter-html-full-screen', listener: Function): this; + once(event: 'enter-html-full-screen', listener: Function): this; + addListener(event: 'enter-html-full-screen', listener: Function): this; + removeListener(event: 'enter-html-full-screen', listener: Function): this; + /** + * Emitted when the window gains focus. + */ + on(event: 'focus', listener: Function): this; + once(event: 'focus', listener: Function): this; + addListener(event: 'focus', listener: Function): this; + removeListener(event: 'focus', listener: Function): this; + /** + * Emitted when the window is hidden. + */ + on(event: 'hide', listener: Function): this; + once(event: 'hide', listener: Function): this; + addListener(event: 'hide', listener: Function): this; + removeListener(event: 'hide', listener: Function): this; + /** + * Emitted when the window leaves a full-screen state. + */ + on(event: 'leave-full-screen', listener: Function): this; + once(event: 'leave-full-screen', listener: Function): this; + addListener(event: 'leave-full-screen', listener: Function): this; + removeListener(event: 'leave-full-screen', listener: Function): this; + /** + * Emitted when the window leaves a full-screen state triggered by HTML API. + */ + on(event: 'leave-html-full-screen', listener: Function): this; + once(event: 'leave-html-full-screen', listener: Function): this; + addListener(event: 'leave-html-full-screen', listener: Function): this; + removeListener(event: 'leave-html-full-screen', listener: Function): this; + /** + * Emitted when window is maximized. + */ + on(event: 'maximize', listener: Function): this; + once(event: 'maximize', listener: Function): this; + addListener(event: 'maximize', listener: Function): this; + removeListener(event: 'maximize', listener: Function): this; + /** + * Emitted when the window is minimized. + */ + on(event: 'minimize', listener: Function): this; + once(event: 'minimize', listener: Function): this; + addListener(event: 'minimize', listener: Function): this; + removeListener(event: 'minimize', listener: Function): this; + /** + * Emitted when the window is being moved to a new position. + */ + on(event: 'move', listener: Function): this; + once(event: 'move', listener: Function): this; + addListener(event: 'move', listener: Function): this; + removeListener(event: 'move', listener: Function): this; + /** + * Emitted once when the window is moved to a new position. + * + * __Note__: On macOS this event is an alias of `move`. + * + * @platform darwin,win32 + */ + on(event: 'moved', listener: Function): this; + once(event: 'moved', listener: Function): this; + addListener(event: 'moved', listener: Function): this; + removeListener(event: 'moved', listener: Function): this; + /** + * Emitted when the native new tab button is clicked. + * + * @platform darwin + */ + on(event: 'new-window-for-tab', listener: Function): this; + once(event: 'new-window-for-tab', listener: Function): this; + addListener(event: 'new-window-for-tab', listener: Function): this; + removeListener(event: 'new-window-for-tab', listener: Function): this; + /** + * Emitted when the document changed its title, calling `event.preventDefault()` + * will prevent the native window's title from changing. `explicitSet` is false + * when title is synthesized from file URL. + */ + on(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + once(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + addListener(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + removeListener(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + /** + * Emitted when the web page has been rendered (while not being shown) and window + * can be displayed without a visual flash. + * + * Please note that using this event implies that the renderer will be considered + * "visible" and paint even though `show` is false. This event will never fire if + * you use `paintWhenInitiallyHidden: false` + */ + on(event: 'ready-to-show', listener: Function): this; + once(event: 'ready-to-show', listener: Function): this; + addListener(event: 'ready-to-show', listener: Function): this; + removeListener(event: 'ready-to-show', listener: Function): this; + /** + * Emitted after the window has been resized. + */ + on(event: 'resize', listener: Function): this; + once(event: 'resize', listener: Function): this; + addListener(event: 'resize', listener: Function): this; + removeListener(event: 'resize', listener: Function): this; + /** + * Emitted once when the window has finished being resized. + * + * This is usually emitted when the window has been resized manually. On macOS, + * resizing the window with `setBounds`/`setSize` and setting the `animate` + * parameter to `true` will also emit this event once resizing has finished. + * + * @platform darwin,win32 + */ + on(event: 'resized', listener: Function): this; + once(event: 'resized', listener: Function): this; + addListener(event: 'resized', listener: Function): this; + removeListener(event: 'resized', listener: Function): this; + /** + * Emitted when the unresponsive web page becomes responsive again. + */ + on(event: 'responsive', listener: Function): this; + once(event: 'responsive', listener: Function): this; + addListener(event: 'responsive', listener: Function): this; + removeListener(event: 'responsive', listener: Function): this; + /** + * Emitted when the window is restored from a minimized state. + */ + on(event: 'restore', listener: Function): this; + once(event: 'restore', listener: Function): this; + addListener(event: 'restore', listener: Function): this; + removeListener(event: 'restore', listener: Function): this; + /** + * Emitted on trackpad rotation gesture. Continually emitted until rotation gesture + * is ended. The `rotation` value on each emission is the angle in degrees rotated + * since the last emission. The last emitted event upon a rotation gesture will + * always be of value `0`. Counter-clockwise rotation values are positive, while + * clockwise ones are negative. + * + * @platform darwin + */ + on(event: 'rotate-gesture', listener: (event: Event, + rotation: number) => void): this; + once(event: 'rotate-gesture', listener: (event: Event, + rotation: number) => void): this; + addListener(event: 'rotate-gesture', listener: (event: Event, + rotation: number) => void): this; + removeListener(event: 'rotate-gesture', listener: (event: Event, + rotation: number) => void): this; + /** + * Emitted when scroll wheel event phase has begun. + * + * @platform darwin + */ + on(event: 'scroll-touch-begin', listener: Function): this; + once(event: 'scroll-touch-begin', listener: Function): this; + addListener(event: 'scroll-touch-begin', listener: Function): this; + removeListener(event: 'scroll-touch-begin', listener: Function): this; + /** + * Emitted when scroll wheel event phase filed upon reaching the edge of element. + * + * @platform darwin + */ + on(event: 'scroll-touch-edge', listener: Function): this; + once(event: 'scroll-touch-edge', listener: Function): this; + addListener(event: 'scroll-touch-edge', listener: Function): this; + removeListener(event: 'scroll-touch-edge', listener: Function): this; + /** + * Emitted when scroll wheel event phase has ended. + * + * @platform darwin + */ + on(event: 'scroll-touch-end', listener: Function): this; + once(event: 'scroll-touch-end', listener: Function): this; + addListener(event: 'scroll-touch-end', listener: Function): this; + removeListener(event: 'scroll-touch-end', listener: Function): this; + /** + * Emitted when window session is going to end due to force shutdown or machine + * restart or session log off. + * + * @platform win32 + */ + on(event: 'session-end', listener: Function): this; + once(event: 'session-end', listener: Function): this; + addListener(event: 'session-end', listener: Function): this; + removeListener(event: 'session-end', listener: Function): this; + /** + * Emitted when the window opens a sheet. + * + * @platform darwin + */ + on(event: 'sheet-begin', listener: Function): this; + once(event: 'sheet-begin', listener: Function): this; + addListener(event: 'sheet-begin', listener: Function): this; + removeListener(event: 'sheet-begin', listener: Function): this; + /** + * Emitted when the window has closed a sheet. + * + * @platform darwin + */ + on(event: 'sheet-end', listener: Function): this; + once(event: 'sheet-end', listener: Function): this; + addListener(event: 'sheet-end', listener: Function): this; + removeListener(event: 'sheet-end', listener: Function): this; + /** + * Emitted when the window is shown. + */ + on(event: 'show', listener: Function): this; + once(event: 'show', listener: Function): this; + addListener(event: 'show', listener: Function): this; + removeListener(event: 'show', listener: Function): this; + /** + * Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, + * `left`. + * + * The method underlying this event is built to handle older macOS-style trackpad + * swiping, where the content on the screen doesn't move with the swipe. Most macOS + * trackpads are not configured to allow this kind of swiping anymore, so in order + * for it to emit properly the 'Swipe between pages' preference in `System + * Preferences > Trackpad > More Gestures` must be set to 'Swipe with two or three + * fingers'. + * + * @platform darwin + */ + on(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + once(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + addListener(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + removeListener(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + /** + * Emitted when the system context menu is triggered on the window, this is + * normally only triggered when the user right clicks on the non-client area of + * your window. This is the window titlebar or any area you have declared as + * `-webkit-app-region: drag` in a frameless window. + * + * Calling `event.preventDefault()` will prevent the menu from being displayed. + * + * @platform win32 + */ + on(event: 'system-context-menu', listener: (event: Event, + /** + * The screen coordinates the context menu was triggered at + */ + point: Point) => void): this; + once(event: 'system-context-menu', listener: (event: Event, + /** + * The screen coordinates the context menu was triggered at + */ + point: Point) => void): this; + addListener(event: 'system-context-menu', listener: (event: Event, + /** + * The screen coordinates the context menu was triggered at + */ + point: Point) => void): this; + removeListener(event: 'system-context-menu', listener: (event: Event, + /** + * The screen coordinates the context menu was triggered at + */ + point: Point) => void): this; + /** + * Emitted when the window exits from a maximized state. + */ + on(event: 'unmaximize', listener: Function): this; + once(event: 'unmaximize', listener: Function): this; + addListener(event: 'unmaximize', listener: Function): this; + removeListener(event: 'unmaximize', listener: Function): this; + /** + * Emitted when the web page becomes unresponsive. + */ + on(event: 'unresponsive', listener: Function): this; + once(event: 'unresponsive', listener: Function): this; + addListener(event: 'unresponsive', listener: Function): this; + removeListener(event: 'unresponsive', listener: Function): this; + /** + * Emitted before the window is moved. On Windows, calling `event.preventDefault()` + * will prevent the window from being moved. + * + * Note that this is only emitted when the window is being moved manually. Moving + * the window with `setPosition`/`setBounds`/`center` will not emit this event. + * + * @platform darwin,win32 + */ + on(event: 'will-move', listener: (event: Event, + /** + * Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + once(event: 'will-move', listener: (event: Event, + /** + * Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + addListener(event: 'will-move', listener: (event: Event, + /** + * Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + removeListener(event: 'will-move', listener: (event: Event, + /** + * Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + /** + * Emitted before the window is resized. Calling `event.preventDefault()` will + * prevent the window from being resized. + * + * Note that this is only emitted when the window is being resized manually. + * Resizing the window with `setBounds`/`setSize` will not emit this event. + * + * The possible values and behaviors of the `edge` option are platform dependent. + * Possible values are: + * + * * On Windows, possible values are `bottom`, `top`, `left`, `right`, `top-left`, + * `top-right`, `bottom-left`, `bottom-right`. + * * On macOS, possible values are `bottom` and `right`. + * * The value `bottom` is used to denote vertical resizing. + * * The value `right` is used to denote horizontal resizing. + * + * @platform darwin,win32 + */ + on(event: 'will-resize', listener: (event: Event, + /** + * Size the window is being resized to. + */ + newBounds: Rectangle, + details: WillResizeDetails) => void): this; + once(event: 'will-resize', listener: (event: Event, + /** + * Size the window is being resized to. + */ + newBounds: Rectangle, + details: WillResizeDetails) => void): this; + addListener(event: 'will-resize', listener: (event: Event, + /** + * Size the window is being resized to. + */ + newBounds: Rectangle, + details: WillResizeDetails) => void): this; + removeListener(event: 'will-resize', listener: (event: Event, + /** + * Size the window is being resized to. + */ + newBounds: Rectangle, + details: WillResizeDetails) => void): this; + /** + * BrowserWindow + */ + constructor(options?: BrowserWindowConstructorOptions); + /** + * The window that owns the given `browserView`. If the given view is not attached + * to any window, returns `null`. + */ + static fromBrowserView(browserView: BrowserView): (BrowserWindow) | (null); + /** + * The window with the given `id`. + */ + static fromId(id: number): (BrowserWindow) | (null); + /** + * The window that owns the given `webContents` or `null` if the contents are not + * owned by a window. + */ + static fromWebContents(webContents: WebContents): (BrowserWindow) | (null); + /** + * An array of all opened browser windows. + */ + static getAllWindows(): BrowserWindow[]; + /** + * The window that is focused in this application, otherwise returns `null`. + */ + static getFocusedWindow(): (BrowserWindow) | (null); + /** + * Replacement API for setBrowserView supporting work with multi browser views. + * + * @experimental + */ + addBrowserView(browserView: BrowserView): void; + /** + * Adds a window as a tab on this window, after the tab for the window instance. + * + * @platform darwin + */ + addTabbedWindow(browserWindow: BrowserWindow): void; + /** + * Removes focus from the window. + */ + blur(): void; + blurWebView(): void; + /** + * Resolves with a NativeImage + * + * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the + * whole visible page. If the page is not visible, `rect` may be empty. + */ + capturePage(rect?: Rectangle): Promise<Electron.NativeImage>; + /** + * Moves window to the center of the screen. + */ + center(): void; + /** + * Try to close the window. This has the same effect as a user manually clicking + * the close button of the window. The web page may cancel the close though. See + * the close event. + */ + close(): void; + /** + * Closes the currently open Quick Look panel. + * + * @platform darwin + */ + closeFilePreview(): void; + /** + * Force closing the window, the `unload` and `beforeunload` event won't be emitted + * for the web page, and `close` event will also not be emitted for this window, + * but it guarantees the `closed` event will be emitted. + */ + destroy(): void; + /** + * Starts or stops flashing the window to attract user's attention. + */ + flashFrame(flag: boolean): void; + /** + * Focuses on the window. + */ + focus(): void; + focusOnWebView(): void; + /** + * Gets the background color of the window in Hex (`#RRGGBB`) format. + * + * See Setting `backgroundColor`. + * + * **Note:** The alpha value is _not_ returned alongside the red, green, and blue + * values. + */ + getBackgroundColor(): string; + /** + * The `bounds` of the window as `Object`. + */ + getBounds(): Rectangle; + /** + * The `BrowserView` attached to `win`. Returns `null` if one is not attached. + * Throws an error if multiple `BrowserView`s are attached. + * + * @experimental + */ + getBrowserView(): (BrowserView) | (null); + /** + * an array of all BrowserViews that have been attached with `addBrowserView` or + * `setBrowserView`. + * + * **Note:** The BrowserView API is currently experimental and may change or be + * removed in future Electron releases. + * + * @experimental + */ + getBrowserViews(): BrowserView[]; + /** + * All child windows. + */ + getChildWindows(): BrowserWindow[]; + /** + * The `bounds` of the window's client area as `Object`. + */ + getContentBounds(): Rectangle; + /** + * Contains the window's client area's width and height. + */ + getContentSize(): number[]; + /** + * Contains the window's maximum width and height. + */ + getMaximumSize(): number[]; + /** + * Window id in the format of DesktopCapturerSource's id. For example + * "window:1324:0". + * + * More precisely the format is `window:id:other_id` where `id` is `HWND` on + * Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on + * Linux. `other_id` is used to identify web contents (tabs) so within the same top + * level window. + */ + getMediaSourceId(): string; + /** + * Contains the window's minimum width and height. + */ + getMinimumSize(): number[]; + /** + * The platform-specific handle of the window. + * + * The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and + * `Window` (`unsigned long`) on Linux. + */ + getNativeWindowHandle(): Buffer; + /** + * Contains the window bounds of the normal state + * + * **Note:** whatever the current state of the window : maximized, minimized or in + * fullscreen, this function always returns the position and size of the window in + * normal state. In normal state, getBounds and getNormalBounds returns the same + * `Rectangle`. + */ + getNormalBounds(): Rectangle; + /** + * between 0.0 (fully transparent) and 1.0 (fully opaque). On Linux, always returns + * 1. + */ + getOpacity(): number; + /** + * The parent window or `null` if there is no parent. + */ + getParentWindow(): (BrowserWindow) | (null); + /** + * Contains the window's current position. + */ + getPosition(): number[]; + /** + * The pathname of the file the window represents. + * + * @platform darwin + */ + getRepresentedFilename(): string; + /** + * Contains the window's width and height. + */ + getSize(): number[]; + /** + * The title of the native window. + * + * **Note:** The title of the web page can be different from the title of the + * native window. + */ + getTitle(): string; + /** + * The custom position for the traffic light buttons in frameless window. + * + * @platform darwin + */ + getTrafficLightPosition(): Point; + /** + * Whether the window has a shadow. + */ + hasShadow(): boolean; + /** + * Hides the window. + */ + hide(): void; + /** + * Hooks a windows message. The `callback` is called when the message is received + * in the WndProc. + * + * @platform win32 + */ + hookWindowMessage(message: number, callback: (wParam: any, lParam: any) => void): void; + /** + * Whether the window is always on top of other windows. + */ + isAlwaysOnTop(): boolean; + /** + * Whether the window can be manually closed by user. + * + * On Linux always returns `true`. + * + * @platform darwin,win32 + */ + isClosable(): boolean; + /** + * Whether the window is destroyed. + */ + isDestroyed(): boolean; + /** + * Whether the window's document has been edited. + * + * @platform darwin + */ + isDocumentEdited(): boolean; + /** + * whether the window is enabled. + */ + isEnabled(): boolean; + /** + * Returns whether the window can be focused. + * + * @platform darwin,win32 + */ + isFocusable(): void; + /** + * Whether the window is focused. + */ + isFocused(): boolean; + /** + * Whether the window is in fullscreen mode. + */ + isFullScreen(): boolean; + /** + * Whether the maximize/zoom window button toggles fullscreen mode or maximizes the + * window. + */ + isFullScreenable(): boolean; + /** + * Whether the window is in kiosk mode. + */ + isKiosk(): boolean; + /** + * Whether the window can be manually maximized by user. + * + * On Linux always returns `true`. + * + * @platform darwin,win32 + */ + isMaximizable(): boolean; + /** + * Whether the window is maximized. + */ + isMaximized(): boolean; + /** + * Whether menu bar automatically hides itself. + * + * @platform win32,linux + */ + isMenuBarAutoHide(): boolean; + /** + * Whether the menu bar is visible. + * + * @platform win32,linux + */ + isMenuBarVisible(): boolean; + /** + * Whether the window can be manually minimized by the user. + * + * On Linux always returns `true`. + * + * @platform darwin,win32 + */ + isMinimizable(): boolean; + /** + * Whether the window is minimized. + */ + isMinimized(): boolean; + /** + * Whether current window is a modal window. + */ + isModal(): boolean; + /** + * Whether the window can be moved by user. + * + * On Linux always returns `true`. + * + * @platform darwin,win32 + */ + isMovable(): boolean; + /** + * Whether the window is in normal state (not maximized, not minimized, not in + * fullscreen mode). + */ + isNormal(): boolean; + /** + * Whether the window can be manually resized by the user. + */ + isResizable(): boolean; + /** + * Whether the window is in simple (pre-Lion) fullscreen mode. + * + * @platform darwin + */ + isSimpleFullScreen(): boolean; + /** + * Whether the window is in Windows 10 tablet mode. + * + * Since Windows 10 users can use their PC as tablet, under this mode apps can + * choose to optimize their UI for tablets, such as enlarging the titlebar and + * hiding titlebar buttons. + * + * This API returns whether the window is in tablet mode, and the `resize` event + * can be be used to listen to changes to tablet mode. + * + * @platform win32 + */ + isTabletMode(): boolean; + /** + * Whether the window is visible to the user. + */ + isVisible(): boolean; + /** + * Whether the window is visible on all workspaces. + * + * **Note:** This API always returns false on Windows. + * + * @platform darwin,linux + */ + isVisibleOnAllWorkspaces(): boolean; + /** + * `true` or `false` depending on whether the message is hooked. + * + * @platform win32 + */ + isWindowMessageHooked(message: number): boolean; + /** + * the promise will resolve when the page has finished loading (see + * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). + * + * Same as `webContents.loadFile`, `filePath` should be a path to an HTML file + * relative to the root of your application. See the `webContents` docs for more + * information. + */ + loadFile(filePath: string, options?: LoadFileOptions): Promise<void>; + /** + * the promise will resolve when the page has finished loading (see + * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). + * + * Same as `webContents.loadURL(url[, options])`. + * + * The `url` can be a remote address (e.g. `http://`) or a path to a local HTML + * file using the `file://` protocol. + * + * To ensure that file URLs are properly formatted, it is recommended to use Node's + * `url.format` method: + * + * You can load a URL using a `POST` request with URL-encoded data by doing the + * following: + */ + loadURL(url: string, options?: LoadURLOptions): Promise<void>; + /** + * Maximizes the window. This will also show (but not focus) the window if it isn't + * being displayed already. + */ + maximize(): void; + /** + * Merges all windows into one window with multiple tabs when native tabs are + * enabled and there is more than one open window. + * + * @platform darwin + */ + mergeAllWindows(): void; + /** + * Minimizes the window. On some platforms the minimized window will be shown in + * the Dock. + */ + minimize(): void; + /** + * Moves window above the source window in the sense of z-order. If the + * `mediaSourceId` is not of type window or if the window does not exist then this + * method throws an error. + */ + moveAbove(mediaSourceId: string): void; + /** + * Moves the current tab into a new window if native tabs are enabled and there is + * more than one tab in the current window. + * + * @platform darwin + */ + moveTabToNewWindow(): void; + /** + * Moves window to top(z-order) regardless of focus + */ + moveTop(): void; + /** + * Uses Quick Look to preview a file at a given path. + * + * @platform darwin + */ + previewFile(path: string, displayName?: string): void; + /** + * Same as `webContents.reload`. + */ + reload(): void; + removeBrowserView(browserView: BrowserView): void; + /** + * Remove the window's menu bar. + * + * @platform linux,win32 + */ + removeMenu(): void; + /** + * Restores the window from minimized state to its previous state. + */ + restore(): void; + /** + * Selects the next tab when native tabs are enabled and there are other tabs in + * the window. + * + * @platform darwin + */ + selectNextTab(): void; + /** + * Selects the previous tab when native tabs are enabled and there are other tabs + * in the window. + * + * @platform darwin + */ + selectPreviousTab(): void; + /** + * Sets whether the window should show always on top of other windows. After + * setting this, the window is still a normal window, not a toolbox window which + * can not be focused on. + */ + setAlwaysOnTop(flag: boolean, level?: 'normal' | 'floating' | 'torn-off-menu' | 'modal-panel' | 'main-menu' | 'status' | 'pop-up-menu' | 'screen-saver', relativeLevel?: number): void; + /** + * Sets the properties for the window's taskbar button. + * + * **Note:** `relaunchCommand` and `relaunchDisplayName` must always be set + * together. If one of those properties is not set, then neither will be used. + * + * @platform win32 + */ + setAppDetails(options: AppDetailsOptions): void; + /** + * This will make a window maintain an aspect ratio. The extra size allows a + * developer to have space, specified in pixels, not included within the aspect + * ratio calculations. This API already takes into account the difference between a + * window's size and its content size. + * + * Consider a normal window with an HD video player and associated controls. + * Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls + * on the right edge and 50 pixels of controls below the player. In order to + * maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within + * the player itself we would call this function with arguments of 16/9 and { + * width: 40, height: 50 }. The second argument doesn't care where the extra width + * and height are within the content view--only that they exist. Sum any extra + * width and height areas you have within the overall content view. + * + * The aspect ratio is not respected when window is resized programmatically with + * APIs like `win.setSize`. + */ + setAspectRatio(aspectRatio: number, extraSize?: Size): void; + /** + * Controls whether to hide cursor when typing. + * + * @platform darwin + */ + setAutoHideCursor(autoHide: boolean): void; + /** + * Sets whether the window menu bar should hide itself automatically. Once set the + * menu bar will only show when users press the single `Alt` key. + * + * If the menu bar is already visible, calling `setAutoHideMenuBar(true)` won't + * hide it immediately. + * + * @platform win32,linux + */ + setAutoHideMenuBar(hide: boolean): void; + /** + * Examples of valid `backgroundColor` values: + * + * * Hex + * * #fff (shorthand RGB) + * * #ffff (shorthand ARGB) + * * #ffffff (RGB) + * * #ffffffff (ARGB) + * * RGB + * * rgb(([\d]+),\s*([\d]+),\s*([\d]+)) + * * e.g. rgb(255, 255, 255) + * * RGBA + * * rgba(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)) + * * e.g. rgba(255, 255, 255, 1.0) + * * HSL + * * hsl((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%) + * * e.g. hsl(200, 20%, 50%) + * * HSLA + * * hsla((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)) + * * e.g. hsla(200, 20%, 50%, 0.5) + * * Color name + * * Options are listed in SkParseColor.cpp + * * Similar to CSS Color Module Level 3 keywords, but case-sensitive. + * * e.g. `blueviolet` or `red` + * + * Sets the background color of the window. See Setting `backgroundColor`. + */ + setBackgroundColor(backgroundColor: string): void; + /** + * Resizes and moves the window to the supplied bounds. Any properties that are not + * supplied will default to their current values. + */ + setBounds(bounds: Partial<Rectangle>, animate?: boolean): void; + setBrowserView(browserView: (BrowserView) | (null)): void; + /** + * Sets whether the window can be manually closed by user. On Linux does nothing. + * + * @platform darwin,win32 + */ + setClosable(closable: boolean): void; + /** + * Resizes and moves the window's client area (e.g. the web page) to the supplied + * bounds. + */ + setContentBounds(bounds: Rectangle, animate?: boolean): void; + /** + * Prevents the window contents from being captured by other apps. + * + * On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. On Windows + * it calls SetWindowDisplayAffinity with `WDA_EXCLUDEFROMCAPTURE`. For Windows 10 + * version 2004 and up the window will be removed from capture entirely, older + * Windows versions behave as if `WDA_MONITOR` is applied capturing a black window. + * + * @platform darwin,win32 + */ + setContentProtection(enable: boolean): void; + /** + * Resizes the window's client area (e.g. the web page) to `width` and `height`. + */ + setContentSize(width: number, height: number, animate?: boolean): void; + /** + * Specifies whether the window’s document has been edited, and the icon in title + * bar will become gray when set to `true`. + * + * @platform darwin + */ + setDocumentEdited(edited: boolean): void; + /** + * Disable or enable the window. + */ + setEnabled(enable: boolean): void; + /** + * Changes whether the window can be focused. + * + * On macOS it does not remove the focus from the window. + * + * @platform darwin,win32 + */ + setFocusable(focusable: boolean): void; + /** + * Sets whether the window should be in fullscreen mode. + */ + setFullScreen(flag: boolean): void; + /** + * Sets whether the maximize/zoom window button toggles fullscreen mode or + * maximizes the window. + */ + setFullScreenable(fullscreenable: boolean): void; + /** + * Sets whether the window should have a shadow. + */ + setHasShadow(hasShadow: boolean): void; + /** + * Changes window icon. + * + * @platform win32,linux + */ + setIcon(icon: (NativeImage) | (string)): void; + /** + * Makes the window ignore all mouse events. + * + * All mouse events happened in this window will be passed to the window below this + * window, but if this window has focus, it will still receive keyboard events. + */ + setIgnoreMouseEvents(ignore: boolean, options?: IgnoreMouseEventsOptions): void; + /** + * Enters or leaves kiosk mode. + */ + setKiosk(flag: boolean): void; + /** + * Sets whether the window can be manually maximized by user. On Linux does + * nothing. + * + * @platform darwin,win32 + */ + setMaximizable(maximizable: boolean): void; + /** + * Sets the maximum size of window to `width` and `height`. + */ + setMaximumSize(width: number, height: number): void; + /** + * Sets the `menu` as the window's menu bar. + * + * @platform linux,win32 + */ + setMenu(menu: (Menu) | (null)): void; + /** + * Sets whether the menu bar should be visible. If the menu bar is auto-hide, users + * can still bring up the menu bar by pressing the single `Alt` key. + * + * @platform win32,linux + */ + setMenuBarVisibility(visible: boolean): void; + /** + * Sets whether the window can be manually minimized by user. On Linux does + * nothing. + * + * @platform darwin,win32 + */ + setMinimizable(minimizable: boolean): void; + /** + * Sets the minimum size of window to `width` and `height`. + */ + setMinimumSize(width: number, height: number): void; + /** + * Sets whether the window can be moved by user. On Linux does nothing. + * + * @platform darwin,win32 + */ + setMovable(movable: boolean): void; + /** + * Sets the opacity of the window. On Linux, does nothing. Out of bound number + * values are clamped to the [0, 1] range. + * + * @platform win32,darwin + */ + setOpacity(opacity: number): void; + /** + * Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to + * convey some sort of application status or to passively notify the user. + * + * @platform win32 + */ + setOverlayIcon(overlay: (NativeImage) | (null), description: string): void; + /** + * Sets `parent` as current window's parent window, passing `null` will turn + * current window into a top-level window. + */ + setParentWindow(parent: (BrowserWindow) | (null)): void; + /** + * Moves window to `x` and `y`. + */ + setPosition(x: number, y: number, animate?: boolean): void; + /** + * Sets progress value in progress bar. Valid range is [0, 1.0]. + * + * Remove progress bar when progress < 0; Change to indeterminate mode when + * progress > 1. + * + * On Linux platform, only supports Unity desktop environment, you need to specify + * the `*.desktop` file name to `desktopName` field in `package.json`. By default, + * it will assume `{app.name}.desktop`. + * + * On Windows, a mode can be passed. Accepted values are `none`, `normal`, + * `indeterminate`, `error`, and `paused`. If you call `setProgressBar` without a + * mode set (but with a value within the valid range), `normal` will be assumed. + */ + setProgressBar(progress: number, options?: ProgressBarOptions): void; + /** + * Sets the pathname of the file the window represents, and the icon of the file + * will show in window's title bar. + * + * @platform darwin + */ + setRepresentedFilename(filename: string): void; + /** + * Sets whether the window can be manually resized by the user. + */ + setResizable(resizable: boolean): void; + /** + * Setting a window shape determines the area within the window where the system + * permits drawing and user interaction. Outside of the given region, no pixels + * will be drawn and no mouse events will be registered. Mouse events outside of + * the region will not be received by that window, but will fall through to + * whatever is behind the window. + * + * @experimental + * @platform win32,linux + */ + setShape(rects: Rectangle[]): void; + /** + * Changes the attachment point for sheets on macOS. By default, sheets are + * attached just below the window frame, but you may want to display them beneath a + * HTML-rendered toolbar. For example: + * + * @platform darwin + */ + setSheetOffset(offsetY: number, offsetX?: number): void; + /** + * Enters or leaves simple fullscreen mode. + * + * Simple fullscreen mode emulates the native fullscreen behavior found in versions + * of macOS prior to Lion (10.7). + * + * @platform darwin + */ + setSimpleFullScreen(flag: boolean): void; + /** + * Resizes the window to `width` and `height`. If `width` or `height` are below any + * set minimum size constraints the window will snap to its minimum size. + */ + setSize(width: number, height: number, animate?: boolean): void; + /** + * Makes the window not show in the taskbar. + * + * @platform darwin,win32 + */ + setSkipTaskbar(skip: boolean): void; + /** + * Whether the buttons were added successfully + * + * Add a thumbnail toolbar with a specified set of buttons to the thumbnail image + * of a window in a taskbar button layout. Returns a `boolean` object indicates + * whether the thumbnail has been added successfully. + * + * The number of buttons in thumbnail toolbar should be no greater than 7 due to + * the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be + * removed due to the platform's limitation. But you can call the API with an empty + * array to clean the buttons. + * + * The `buttons` is an array of `Button` objects: + * + * * `Button` Object + * * `icon` NativeImage - The icon showing in thumbnail toolbar. + * * `click` Function + * * `tooltip` string (optional) - The text of the button's tooltip. + * * `flags` string[] (optional) - Control specific states and behaviors of the + * button. By default, it is `['enabled']`. + * + * The `flags` is an array that can include following `string`s: + * + * * `enabled` - The button is active and available to the user. + * * `disabled` - The button is disabled. It is present, but has a visual state + * indicating it will not respond to user action. + * * `dismissonclick` - When the button is clicked, the thumbnail window closes + * immediately. + * * `nobackground` - Do not draw a button border, use only the image. + * * `hidden` - The button is not shown to the user. + * * `noninteractive` - The button is enabled but not interactive; no pressed + * button state is drawn. This value is intended for instances where the button is + * used in a notification. + * + * @platform win32 + */ + setThumbarButtons(buttons: ThumbarButton[]): boolean; + /** + * Sets the region of the window to show as the thumbnail image displayed when + * hovering over the window in the taskbar. You can reset the thumbnail to be the + * entire window by specifying an empty region: `{ x: 0, y: 0, width: 0, height: 0 + * }`. + * + * @platform win32 + */ + setThumbnailClip(region: Rectangle): void; + /** + * Sets the toolTip that is displayed when hovering over the window thumbnail in + * the taskbar. + * + * @platform win32 + */ + setThumbnailToolTip(toolTip: string): void; + /** + * Changes the title of native window to `title`. + */ + setTitle(title: string): void; + /** + * On a Window with Window Controls Overlay already enabled, this method updates + * the style of the title bar overlay. + * + * @platform win32 + */ + setTitleBarOverlay(options: TitleBarOverlayOptions): void; + /** + * Raises `browserView` above other `BrowserView`s attached to `win`. Throws an + * error if `browserView` is not attached to `win`. + * + * @experimental + */ + setTopBrowserView(browserView: BrowserView): void; + /** + * Sets the touchBar layout for the current window. Specifying `null` or + * `undefined` clears the touch bar. This method only has an effect if the machine + * has a touch bar and is running on macOS 10.12.1+. + * + * **Note:** The TouchBar API is currently experimental and may change or be + * removed in future Electron releases. + * + * @platform darwin + */ + setTouchBar(touchBar: (TouchBar) | (null)): void; + /** + * Set a custom position for the traffic light buttons in frameless window. + * + * @platform darwin + */ + setTrafficLightPosition(position: Point): void; + /** + * Adds a vibrancy effect to the browser window. Passing `null` or an empty string + * will remove the vibrancy effect on the window. + * + * Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` + * have been deprecated and will be removed in an upcoming version of macOS. + * + * @platform darwin + */ + setVibrancy(type: (('appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark' | 'header' | 'sheet' | 'window' | 'hud' | 'fullscreen-ui' | 'tooltip' | 'content' | 'under-window' | 'under-page')) | (null)): void; + /** + * Sets whether the window should be visible on all workspaces. + * + * **Note:** This API does nothing on Windows. + * + * @platform darwin,linux + */ + setVisibleOnAllWorkspaces(visible: boolean, options?: VisibleOnAllWorkspacesOptions): void; + /** + * Sets whether the window traffic light buttons should be visible. + * + * @platform darwin + */ + setWindowButtonVisibility(visible: boolean): void; + /** + * Shows and gives focus to the window. + */ + show(): void; + /** + * Same as `webContents.showDefinitionForSelection()`. + * + * @platform darwin + */ + showDefinitionForSelection(): void; + /** + * Shows the window but doesn't focus on it. + */ + showInactive(): void; + /** + * Toggles the visibility of the tab bar if native tabs are enabled and there is + * only one tab in the current window. + * + * @platform darwin + */ + toggleTabBar(): void; + /** + * Unhooks all of the window messages. + * + * @platform win32 + */ + unhookAllWindowMessages(): void; + /** + * Unhook the window message. + * + * @platform win32 + */ + unhookWindowMessage(message: number): void; + /** + * Unmaximizes the window. + */ + unmaximize(): void; + /** + * A `string` property that defines an alternative title provided only to + * accessibility tools such as screen readers. This string is not directly visible + * to users. + */ + accessibleTitle: string; + /** + * A `boolean` property that determines whether the window menu bar should hide + * itself automatically. Once set, the menu bar will only show when users press the + * single `Alt` key. + * + * If the menu bar is already visible, setting this property to `true` won't hide + * it immediately. + */ + autoHideMenuBar: boolean; + /** + * A `boolean` property that determines whether the window can be manually closed + * by user. + * + * On Linux the setter is a no-op, although the getter returns `true`. + * + * @platform darwin,win32 + */ + closable: boolean; + /** + * A `boolean` property that specifies whether the window’s document has been + * edited. + * + * The icon in title bar will become gray when set to `true`. + * + * @platform darwin + */ + documentEdited: boolean; + /** + * A `boolean` property that determines whether the window is excluded from the + * application’s Windows menu. `false` by default. + * + * @platform darwin + */ + excludedFromShownWindowsMenu: boolean; + /** + * A `boolean` property that determines whether the window is focusable. + * + * @platform win32,darwin + */ + focusable: boolean; + /** + * A `boolean` property that determines whether the window is in fullscreen mode. + */ + fullScreen: boolean; + /** + * A `boolean` property that determines whether the maximize/zoom window button + * toggles fullscreen mode or maximizes the window. + */ + fullScreenable: boolean; + /** + * A `Integer` property representing the unique ID of the window. Each ID is unique + * among all `BrowserWindow` instances of the entire Electron application. + * + */ + readonly id: number; + /** + * A `boolean` property that determines whether the window is in kiosk mode. + */ + kiosk: boolean; + /** + * A `boolean` property that determines whether the window can be manually + * maximized by user. + * + * On Linux the setter is a no-op, although the getter returns `true`. + * + * @platform darwin,win32 + */ + maximizable: boolean; + /** + * A `boolean` property that determines whether the menu bar should be visible. + * + * **Note:** If the menu bar is auto-hide, users can still bring up the menu bar by + * pressing the single `Alt` key. + * + * @platform win32,linux + */ + menuBarVisible: boolean; + /** + * A `boolean` property that determines whether the window can be manually + * minimized by user. + * + * On Linux the setter is a no-op, although the getter returns `true`. + * + * @platform darwin,win32 + */ + minimizable: boolean; + /** + * A `boolean` property that determines Whether the window can be moved by user. + * + * On Linux the setter is a no-op, although the getter returns `true`. + * + * @platform darwin,win32 + */ + movable: boolean; + /** + * A `string` property that determines the pathname of the file the window + * represents, and the icon of the file will show in window's title bar. + * + * @platform darwin + */ + representedFilename: string; + /** + * A `boolean` property that determines whether the window can be manually resized + * by user. + */ + resizable: boolean; + /** + * A `boolean` property that determines whether the window has a shadow. + */ + shadow: boolean; + /** + * A `boolean` property that determines whether the window is in simple (pre-Lion) + * fullscreen mode. + */ + simpleFullScreen: boolean; + /** + * A `string` property that determines the title of the native window. + * + * **Note:** The title of the web page can be different from the title of the + * native window. + */ + title: string; + /** + * A `boolean` property that determines whether the window is visible on all + * workspaces. + * + * **Note:** Always returns false on Windows. + * + * @platform darwin,linux + */ + visibleOnAllWorkspaces: boolean; + /** + * A `WebContents` object this window owns. All web page related events and + * operations will be done via it. + * + * See the `webContents` documentation for its methods and events. + * + */ + readonly webContents: WebContents; + } + + interface Certificate { + + // Docs: https://electronjs.org/docs/api/structures/certificate + + /** + * PEM encoded data + */ + data: string; + /** + * Fingerprint of the certificate + */ + fingerprint: string; + /** + * Issuer principal + */ + issuer: CertificatePrincipal; + /** + * Issuer certificate (if not self-signed) + */ + issuerCert: Certificate; + /** + * Issuer's Common Name + */ + issuerName: string; + /** + * Hex value represented string + */ + serialNumber: string; + /** + * Subject principal + */ + subject: CertificatePrincipal; + /** + * Subject's Common Name + */ + subjectName: string; + /** + * End date of the certificate being valid in seconds + */ + validExpiry: number; + /** + * Start date of the certificate being valid in seconds + */ + validStart: number; + } + + interface CertificatePrincipal { + + // Docs: https://electronjs.org/docs/api/structures/certificate-principal + + /** + * Common Name. + */ + commonName: string; + /** + * Country or region. + */ + country: string; + /** + * Locality. + */ + locality: string; + /** + * Organization names. + */ + organizations: string[]; + /** + * Organization Unit names. + */ + organizationUnits: string[]; + /** + * State or province. + */ + state: string; + } + + class ClientRequest extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/client-request + + /** + * Emitted when the `request` is aborted. The `abort` event will not be fired if + * the `request` is already closed. + */ + on(event: 'abort', listener: Function): this; + once(event: 'abort', listener: Function): this; + addListener(event: 'abort', listener: Function): this; + removeListener(event: 'abort', listener: Function): this; + /** + * Emitted as the last event in the HTTP request-response transaction. The `close` + * event indicates that no more events will be emitted on either the `request` or + * `response` objects. + */ + on(event: 'close', listener: Function): this; + once(event: 'close', listener: Function): this; + addListener(event: 'close', listener: Function): this; + removeListener(event: 'close', listener: Function): this; + /** + * Emitted when the `net` module fails to issue a network request. Typically when + * the `request` object emits an `error` event, a `close` event will subsequently + * follow and no response object will be provided. + */ + on(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + once(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + addListener(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + removeListener(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + /** + * Emitted just after the last chunk of the `request`'s data has been written into + * the `request` object. + */ + on(event: 'finish', listener: Function): this; + once(event: 'finish', listener: Function): this; + addListener(event: 'finish', listener: Function): this; + removeListener(event: 'finish', listener: Function): this; + /** + * Emitted when an authenticating proxy is asking for user credentials. + * + * The `callback` function is expected to be called back with user credentials: + * + * * `username` string + * * `password` string + * + * Providing empty credentials will cancel the request and report an authentication + * error on the response object: + */ + on(event: 'login', listener: (authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + once(event: 'login', listener: (authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + addListener(event: 'login', listener: (authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + removeListener(event: 'login', listener: (authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + /** + * Emitted when the server returns a redirect response (e.g. 301 Moved + * Permanently). Calling `request.followRedirect` will continue with the + * redirection. If this event is handled, `request.followRedirect` must be called + * **synchronously**, otherwise the request will be cancelled. + */ + on(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: Record<string, string[]>) => void): this; + once(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: Record<string, string[]>) => void): this; + addListener(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: Record<string, string[]>) => void): this; + removeListener(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: Record<string, string[]>) => void): this; + on(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + once(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + addListener(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + removeListener(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + /** + * ClientRequest + */ + constructor(options: (ClientRequestConstructorOptions) | (string)); + /** + * Cancels an ongoing HTTP transaction. If the request has already emitted the + * `close` event, the abort operation will have no effect. Otherwise an ongoing + * event will emit `abort` and `close` events. Additionally, if there is an ongoing + * response object,it will emit the `aborted` event. + */ + abort(): void; + /** + * Sends the last chunk of the request data. Subsequent write or end operations + * will not be allowed. The `finish` event is emitted just after the end operation. + */ + end(chunk?: (string) | (Buffer), encoding?: string, callback?: () => void): void; + /** + * Continues any pending redirection. Can only be called during a `'redirect'` + * event. + */ + followRedirect(): void; + /** + * The value of a previously set extra header name. + */ + getHeader(name: string): string; + /** + * * `active` boolean - Whether the request is currently active. If this is false + * no other properties will be set + * * `started` boolean - Whether the upload has started. If this is false both + * `current` and `total` will be set to 0. + * * `current` Integer - The number of bytes that have been uploaded so far + * * `total` Integer - The number of bytes that will be uploaded this request + * + * You can use this method in conjunction with `POST` requests to get the progress + * of a file upload or other data transfer. + */ + getUploadProgress(): UploadProgress; + /** + * Removes a previously set extra header name. This method can be called only + * before first write. Trying to call it after the first write will throw an error. + */ + removeHeader(name: string): void; + /** + * Adds an extra HTTP header. The header name will be issued as-is without + * lowercasing. It can be called only before first write. Calling this method after + * the first write will throw an error. If the passed value is not a `string`, its + * `toString()` method will be called to obtain the final value. + * + * Certain headers are restricted from being set by apps. These headers are listed + * below. More information on restricted headers can be found in Chromium's header + * utils. + * + * * `Content-Length` + * * `Host` + * * `Trailer` or `Te` + * * `Upgrade` + * * `Cookie2` + * * `Keep-Alive` + * * `Transfer-Encoding` + * + * Additionally, setting the `Connection` header to the value `upgrade` is also + * disallowed. + */ + setHeader(name: string, value: string): void; + /** + * `callback` is essentially a dummy function introduced in the purpose of keeping + * similarity with the Node.js API. It is called asynchronously in the next tick + * after `chunk` content have been delivered to the Chromium networking layer. + * Contrary to the Node.js implementation, it is not guaranteed that `chunk` + * content have been flushed on the wire before `callback` is called. + * + * Adds a chunk of data to the request body. The first write operation may cause + * the request headers to be issued on the wire. After the first write operation, + * it is not allowed to add or remove a custom header. + */ + write(chunk: (string) | (Buffer), encoding?: string, callback?: () => void): void; + /** + * A `boolean` specifying whether the request will use HTTP chunked transfer + * encoding or not. Defaults to false. The property is readable and writable, + * however it can be set only before the first write operation as the HTTP headers + * are not yet put on the wire. Trying to set the `chunkedEncoding` property after + * the first write will throw an error. + * + * Using chunked encoding is strongly recommended if you need to send a large + * request body as data will be streamed in small chunks instead of being + * internally buffered inside Electron process memory. + */ + chunkedEncoding: boolean; + } + + interface Clipboard { + + // Docs: https://electronjs.org/docs/api/clipboard + + /** + * An array of supported formats for the clipboard `type`. + */ + availableFormats(type?: 'selection' | 'clipboard'): string[]; + /** + * Clears the clipboard content. + */ + clear(type?: 'selection' | 'clipboard'): void; + /** + * Whether the clipboard supports the specified `format`. + * + * @experimental + */ + has(format: string, type?: 'selection' | 'clipboard'): boolean; + /** + * Reads `format` type from the clipboard. + * + * `format` should contain valid ASCII characters and have `/` separator. `a/c`, + * `a/bc` are valid formats while `/abc`, `abc/`, `a/`, `/a`, `a` are not valid. + * + * @experimental + */ + read(format: string): string; + /** + * * `title` string + * * `url` string + * + * Returns an Object containing `title` and `url` keys representing the bookmark in + * the clipboard. The `title` and `url` values will be empty strings when the + * bookmark is unavailable. The `title` value will always be empty on Windows. + * + * @platform darwin,win32 + */ + readBookmark(): ReadBookmark; + /** + * Reads `format` type from the clipboard. + * + * @experimental + */ + readBuffer(format: string): Buffer; + /** + * The text on the find pasteboard, which is the pasteboard that holds information + * about the current state of the active application’s find panel. + * + * This method uses synchronous IPC when called from the renderer process. The + * cached value is reread from the find pasteboard whenever the application is + * activated. + * + * @platform darwin + */ + readFindText(): string; + /** + * The content in the clipboard as markup. + */ + readHTML(type?: 'selection' | 'clipboard'): string; + /** + * The image content in the clipboard. + */ + readImage(type?: 'selection' | 'clipboard'): NativeImage; + /** + * The content in the clipboard as RTF. + */ + readRTF(type?: 'selection' | 'clipboard'): string; + /** + * The content in the clipboard as plain text. + */ + readText(type?: 'selection' | 'clipboard'): string; + /** + * Writes `data` to the clipboard. + */ + write(data: Data, type?: 'selection' | 'clipboard'): void; + /** + * Writes the `title` (macOS only) and `url` into the clipboard as a bookmark. + * + * **Note:** Most apps on Windows don't support pasting bookmarks into them so you + * can use `clipboard.write` to write both a bookmark and fallback text to the + * clipboard. + * + * @platform darwin,win32 + */ + writeBookmark(title: string, url: string, type?: 'selection' | 'clipboard'): void; + /** + * Writes the `buffer` into the clipboard as `format`. + * + * @experimental + */ + writeBuffer(format: string, buffer: Buffer, type?: 'selection' | 'clipboard'): void; + /** + * Writes the `text` into the find pasteboard (the pasteboard that holds + * information about the current state of the active application’s find panel) as + * plain text. This method uses synchronous IPC when called from the renderer + * process. + * + * @platform darwin + */ + writeFindText(text: string): void; + /** + * Writes `markup` to the clipboard. + */ + writeHTML(markup: string, type?: 'selection' | 'clipboard'): void; + /** + * Writes `image` to the clipboard. + */ + writeImage(image: NativeImage, type?: 'selection' | 'clipboard'): void; + /** + * Writes the `text` into the clipboard in RTF. + */ + writeRTF(text: string, type?: 'selection' | 'clipboard'): void; + /** + * Writes the `text` into the clipboard as plain text. + */ + writeText(text: string, type?: 'selection' | 'clipboard'): void; + } + + class CommandLine { + + // Docs: https://electronjs.org/docs/api/command-line + + /** + * Append an argument to Chromium's command line. The argument will be quoted + * correctly. Switches will precede arguments regardless of appending order. + * + * If you're appending an argument like `--switch=value`, consider using + * `appendSwitch('switch', 'value')` instead. + * + * **Note:** This will not affect `process.argv`. The intended usage of this + * function is to control Chromium's behavior. + */ + appendArgument(value: string): void; + /** + * Append a switch (with optional `value`) to Chromium's command line. + * + * **Note:** This will not affect `process.argv`. The intended usage of this + * function is to control Chromium's behavior. + */ + appendSwitch(the_switch: string, value?: string): void; + /** + * The command-line switch value. + * + * **Note:** When the switch is not present or has no value, it returns empty + * string. + */ + getSwitchValue(the_switch: string): string; + /** + * Whether the command-line switch is present. + */ + hasSwitch(the_switch: string): boolean; + /** + * Removes the specified switch from Chromium's command line. + * + * **Note:** This will not affect `process.argv`. The intended usage of this + * function is to control Chromium's behavior. + */ + removeSwitch(the_switch: string): void; + } + + interface ContentTracing { + + // Docs: https://electronjs.org/docs/api/content-tracing + + /** + * resolves with an array of category groups once all child processes have + * acknowledged the `getCategories` request + * + * Get a set of category groups. The category groups can change as new code paths + * are reached. See also the list of built-in tracing categories. + * + * > **NOTE:** Electron adds a non-default tracing category called `"electron"`. + * This category can be used to capture Electron-specific tracing events. + */ + getCategories(): Promise<string[]>; + /** + * Resolves with an object containing the `value` and `percentage` of trace buffer + * maximum usage + * + * * `value` number + * * `percentage` number + * + * Get the maximum usage across processes of trace buffer as a percentage of the + * full state. + */ + getTraceBufferUsage(): Promise<Electron.TraceBufferUsageReturnValue>; + /** + * resolved once all child processes have acknowledged the `startRecording` + * request. + * + * Start recording on all processes. + * + * Recording begins immediately locally and asynchronously on child processes as + * soon as they receive the EnableRecording request. + * + * If a recording is already running, the promise will be immediately resolved, as + * only one trace operation can be in progress at a time. + */ + startRecording(options: (TraceConfig) | (TraceCategoriesAndOptions)): Promise<void>; + /** + * resolves with a path to a file that contains the traced data once all child + * processes have acknowledged the `stopRecording` request + * + * Stop recording on all processes. + * + * Child processes typically cache trace data and only rarely flush and send trace + * data back to the main process. This helps to minimize the runtime overhead of + * tracing since sending trace data over IPC can be an expensive operation. So, to + * end tracing, Chromium asynchronously asks all child processes to flush any + * pending trace data. + * + * Trace data will be written into `resultFilePath`. If `resultFilePath` is empty + * or not provided, trace data will be written to a temporary file, and the path + * will be returned in the promise. + */ + stopRecording(resultFilePath?: string): Promise<string>; + } + + interface ContextBridge { + + // Docs: https://electronjs.org/docs/api/context-bridge + + exposeInMainWorld(apiKey: string, api: any): void; + } + + interface Cookie { + + // Docs: https://electronjs.org/docs/api/structures/cookie + + /** + * The domain of the cookie; this will be normalized with a preceding dot so that + * it's also valid for subdomains. + */ + domain?: string; + /** + * The expiration date of the cookie as the number of seconds since the UNIX epoch. + * Not provided for session cookies. + */ + expirationDate?: number; + /** + * Whether the cookie is a host-only cookie; this will only be `true` if no domain + * was passed. + */ + hostOnly?: boolean; + /** + * Whether the cookie is marked as HTTP only. + */ + httpOnly?: boolean; + /** + * The name of the cookie. + */ + name: string; + /** + * The path of the cookie. + */ + path?: string; + /** + * The Same Site policy applied to this cookie. Can be `unspecified`, + * `no_restriction`, `lax` or `strict`. + */ + sameSite: ('unspecified' | 'no_restriction' | 'lax' | 'strict'); + /** + * Whether the cookie is marked as secure. + */ + secure?: boolean; + /** + * Whether the cookie is a session cookie or a persistent cookie with an expiration + * date. + */ + session?: boolean; + /** + * The value of the cookie. + */ + value: string; + } + + class Cookies extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/cookies + + /** + * Emitted when a cookie is changed because it was added, edited, removed, or + * expired. + */ + on(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed. + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + once(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed. + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + addListener(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed. + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + removeListener(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed. + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + /** + * A promise which resolves when the cookie store has been flushed + * + * Writes any unwritten cookies data to disk. + */ + flushStore(): Promise<void>; + /** + * A promise which resolves an array of cookie objects. + * + * Sends a request to get all cookies matching `filter`, and resolves a promise + * with the response. + */ + get(filter: CookiesGetFilter): Promise<Electron.Cookie[]>; + /** + * A promise which resolves when the cookie has been removed + * + * Removes the cookies matching `url` and `name` + */ + remove(url: string, name: string): Promise<void>; + /** + * A promise which resolves when the cookie has been set + * + * Sets a cookie with `details`. + */ + set(details: CookiesSetDetails): Promise<void>; + } + + interface CPUUsage { + + // Docs: https://electronjs.org/docs/api/structures/cpu-usage + + /** + * The number of average idle CPU wakeups per second since the last call to + * getCPUUsage. First call returns 0. Will always return 0 on Windows. + */ + idleWakeupsPerSecond: number; + /** + * Percentage of CPU used since the last call to getCPUUsage. First call returns 0. + */ + percentCPUUsage: number; + } + + interface CrashReport { + + // Docs: https://electronjs.org/docs/api/structures/crash-report + + date: Date; + id: string; + } + + interface CrashReporter { + + // Docs: https://electronjs.org/docs/api/crash-reporter + + /** + * Set an extra parameter to be sent with the crash report. The values specified + * here will be sent in addition to any values set via the `extra` option when + * `start` was called. + * + * Parameters added in this fashion (or via the `extra` parameter to + * `crashReporter.start`) are specific to the calling process. Adding extra + * parameters in the main process will not cause those parameters to be sent along + * with crashes from renderer or other child processes. Similarly, adding extra + * parameters in a renderer process will not result in those parameters being sent + * with crashes that occur in other renderer processes or in the main process. + * + * **Note:** Parameters have limits on the length of the keys and values. Key names + * must be no longer than 39 bytes, and values must be no longer than 20320 bytes. + * Keys with names longer than the maximum will be silently ignored. Key values + * longer than the maximum length will be truncated. + */ + addExtraParameter(key: string, value: string): void; + /** + * The date and ID of the last crash report. Only crash reports that have been + * uploaded will be returned; even if a crash report is present on disk it will not + * be returned until it is uploaded. In the case that there are no uploaded + * reports, `null` is returned. + * + * **Note:** This method is only available in the main process. + */ + getLastCrashReport(): CrashReport; + /** + * The current 'extra' parameters of the crash reporter. + */ + getParameters(): Record<string, string>; + /** + * Returns all uploaded crash reports. Each report contains the date and uploaded + * ID. + * + * **Note:** This method is only available in the main process. + */ + getUploadedReports(): CrashReport[]; + /** + * Whether reports should be submitted to the server. Set through the `start` + * method or `setUploadToServer`. + * + * **Note:** This method is only available in the main process. + */ + getUploadToServer(): boolean; + /** + * Remove an extra parameter from the current set of parameters. Future crashes + * will not include this parameter. + */ + removeExtraParameter(key: string): void; + /** + * This would normally be controlled by user preferences. This has no effect if + * called before `start` is called. + * + * **Note:** This method is only available in the main process. + */ + setUploadToServer(uploadToServer: boolean): void; + /** + * This method must be called before using any other `crashReporter` APIs. Once + * initialized this way, the crashpad handler collects crashes from all + * subsequently created processes. The crash reporter cannot be disabled once + * started. + * + * This method should be called as early as possible in app startup, preferably + * before `app.on('ready')`. If the crash reporter is not initialized at the time a + * renderer process is created, then that renderer process will not be monitored by + * the crash reporter. + * + * **Note:** You can test out the crash reporter by generating a crash using + * `process.crash()`. + * + * **Note:** If you need to send additional/updated `extra` parameters after your + * first call `start` you can call `addExtraParameter`. + * + * **Note:** Parameters passed in `extra`, `globalExtra` or set with + * `addExtraParameter` have limits on the length of the keys and values. Key names + * must be at most 39 bytes long, and values must be no longer than 127 bytes. Keys + * with names longer than the maximum will be silently ignored. Key values longer + * than the maximum length will be truncated. + * + * **Note:** This method is only available in the main process. + */ + start(options: CrashReporterStartOptions): void; + } + + interface CustomScheme { + + // Docs: https://electronjs.org/docs/api/structures/custom-scheme + + privileges?: Privileges; + /** + * Custom schemes to be registered with options. + */ + scheme: string; + } + + class Debugger extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/debugger + + /** + * Emitted when the debugging session is terminated. This happens either when + * `webContents` is closed or devtools is invoked for the attached `webContents`. + */ + on(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + once(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + addListener(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + removeListener(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + /** + * Emitted whenever the debugging target issues an instrumentation event. + */ + on(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any, + /** + * Unique identifier of attached debugging session, will match the value sent from + * `debugger.sendCommand`. + */ + sessionId: string) => void): this; + once(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any, + /** + * Unique identifier of attached debugging session, will match the value sent from + * `debugger.sendCommand`. + */ + sessionId: string) => void): this; + addListener(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any, + /** + * Unique identifier of attached debugging session, will match the value sent from + * `debugger.sendCommand`. + */ + sessionId: string) => void): this; + removeListener(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any, + /** + * Unique identifier of attached debugging session, will match the value sent from + * `debugger.sendCommand`. + */ + sessionId: string) => void): this; + /** + * Attaches the debugger to the `webContents`. + */ + attach(protocolVersion?: string): void; + /** + * Detaches the debugger from the `webContents`. + */ + detach(): void; + /** + * Whether a debugger is attached to the `webContents`. + */ + isAttached(): boolean; + /** + * A promise that resolves with the response defined by the 'returns' attribute of + * the command description in the remote debugging protocol or is rejected + * indicating the failure of the command. + * + * Send given command to the debugging target. + */ + sendCommand(method: string, commandParams?: any, sessionId?: string): Promise<any>; + } + + interface DesktopCapturer { + + // Docs: https://electronjs.org/docs/api/desktop-capturer + + /** + * Resolves with an array of `DesktopCapturerSource` objects, each + * `DesktopCapturerSource` represents a screen or an individual window that can be + * captured. + * + * **Note** Capturing the screen contents requires user consent on macOS 10.15 + * Catalina or higher, which can detected by + * `systemPreferences.getMediaAccessStatus`. + */ + getSources(options: SourcesOptions): Promise<Electron.DesktopCapturerSource[]>; + } + + interface DesktopCapturerSource { + + // Docs: https://electronjs.org/docs/api/structures/desktop-capturer-source + + /** + * An icon image of the application that owns the window or null if the source has + * a type screen. The size of the icon is not known in advance and depends on what + * the application provides. + */ + appIcon: NativeImage; + /** + * A unique identifier that will correspond to the `id` of the matching Display + * returned by the Screen API. On some platforms, this is equivalent to the `XX` + * portion of the `id` field above and on others it will differ. It will be an + * empty string if not available. + */ + display_id: string; + /** + * The identifier of a window or screen that can be used as a `chromeMediaSourceId` + * constraint when calling [`navigator.webkitGetUserMedia`]. The format of the + * identifier will be `window:XX:YY` or `screen:ZZ:0`. XX is the windowID/handle. + * YY is 1 for the current process, and 0 for all others. ZZ is a sequential number + * that represents the screen, and it does not equal to the index in the source's + * name. + */ + id: string; + /** + * A screen source will be named either `Entire Screen` or `Screen <index>`, while + * the name of a window source will match the window title. + */ + name: string; + /** + * A thumbnail image. **Note:** There is no guarantee that the size of the + * thumbnail is the same as the `thumbnailSize` specified in the `options` passed + * to `desktopCapturer.getSources`. The actual size depends on the scale of the + * screen or window. + */ + thumbnail: NativeImage; + } + + interface Dialog { + + // Docs: https://electronjs.org/docs/api/dialog + + /** + * resolves when the certificate trust dialog is shown. + * + * On macOS, this displays a modal dialog that shows a message and certificate + * information, and gives the user the option of trusting/importing the + * certificate. If you provide a `browserWindow` argument the dialog will be + * attached to the parent window, making it modal. + * + * On Windows the options are more limited, due to the Win32 APIs used: + * + * * The `message` argument is not used, as the OS provides its own confirmation + * dialog. + * * The `browserWindow` argument is ignored since it is not possible to make this + * confirmation dialog modal. + * + * @platform darwin,win32 + */ + showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions): Promise<void>; + /** + * resolves when the certificate trust dialog is shown. + * + * On macOS, this displays a modal dialog that shows a message and certificate + * information, and gives the user the option of trusting/importing the + * certificate. If you provide a `browserWindow` argument the dialog will be + * attached to the parent window, making it modal. + * + * On Windows the options are more limited, due to the Win32 APIs used: + * + * * The `message` argument is not used, as the OS provides its own confirmation + * dialog. + * * The `browserWindow` argument is ignored since it is not possible to make this + * confirmation dialog modal. + * + * @platform darwin,win32 + */ + showCertificateTrustDialog(options: CertificateTrustDialogOptions): Promise<void>; + /** + * Displays a modal dialog that shows an error message. + * + * This API can be called safely before the `ready` event the `app` module emits, + * it is usually used to report errors in early stage of startup. If called before + * the app `ready`event on Linux, the message will be emitted to stderr, and no GUI + * dialog will appear. + */ + showErrorBox(title: string, content: string): void; + /** + * resolves with a promise containing the following properties: + * + * * `response` number - The index of the clicked button. + * * `checkboxChecked` boolean - The checked state of the checkbox if + * `checkboxLabel` was set. Otherwise `false`. + * + * Shows a message box. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + */ + showMessageBox(browserWindow: BrowserWindow, options: MessageBoxOptions): Promise<Electron.MessageBoxReturnValue>; + /** + * resolves with a promise containing the following properties: + * + * * `response` number - The index of the clicked button. + * * `checkboxChecked` boolean - The checked state of the checkbox if + * `checkboxLabel` was set. Otherwise `false`. + * + * Shows a message box. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + */ + showMessageBox(options: MessageBoxOptions): Promise<Electron.MessageBoxReturnValue>; + /** + * the index of the clicked button. + * + * Shows a message box, it will block the process until the message box is closed. + * It returns the index of the clicked button. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. If `browserWindow` is not shown dialog will not be + * attached to it. In such case it will be displayed as an independent window. + */ + showMessageBoxSync(browserWindow: BrowserWindow, options: MessageBoxSyncOptions): number; + /** + * the index of the clicked button. + * + * Shows a message box, it will block the process until the message box is closed. + * It returns the index of the clicked button. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. If `browserWindow` is not shown dialog will not be + * attached to it. In such case it will be displayed as an independent window. + */ + showMessageBoxSync(options: MessageBoxSyncOptions): number; + /** + * Resolve with an object containing the following: + * + * * `canceled` boolean - whether or not the dialog was canceled. + * * `filePaths` string[] - An array of file paths chosen by the user. If the + * dialog is cancelled this will be an empty array. + * * `bookmarks` string[] (optional) _macOS_ _mas_ - An array matching the + * `filePaths` array of base64 encoded strings which contains security scoped + * bookmark data. `securityScopedBookmarks` must be enabled for this to be + * populated. (For return values, see table here.) + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed or selected + * when you want to limit the user to a specific type. For example: + * + * The `extensions` array should contain extensions without wildcards or dots (e.g. + * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the + * `'*'` wildcard (no other wildcard is supported). + * + * **Note:** On Windows and Linux an open dialog can not be both a file selector + * and a directory selector, so if you set `properties` to `['openFile', + * 'openDirectory']` on these platforms, a directory selector will be shown. + */ + showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions): Promise<Electron.OpenDialogReturnValue>; + /** + * Resolve with an object containing the following: + * + * * `canceled` boolean - whether or not the dialog was canceled. + * * `filePaths` string[] - An array of file paths chosen by the user. If the + * dialog is cancelled this will be an empty array. + * * `bookmarks` string[] (optional) _macOS_ _mas_ - An array matching the + * `filePaths` array of base64 encoded strings which contains security scoped + * bookmark data. `securityScopedBookmarks` must be enabled for this to be + * populated. (For return values, see table here.) + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed or selected + * when you want to limit the user to a specific type. For example: + * + * The `extensions` array should contain extensions without wildcards or dots (e.g. + * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the + * `'*'` wildcard (no other wildcard is supported). + * + * **Note:** On Windows and Linux an open dialog can not be both a file selector + * and a directory selector, so if you set `properties` to `['openFile', + * 'openDirectory']` on these platforms, a directory selector will be shown. + */ + showOpenDialog(options: OpenDialogOptions): Promise<Electron.OpenDialogReturnValue>; + /** + * the file paths chosen by the user; if the dialog is cancelled it returns + * `undefined`. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed or selected + * when you want to limit the user to a specific type. For example: + * + * The `extensions` array should contain extensions without wildcards or dots (e.g. + * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the + * `'*'` wildcard (no other wildcard is supported). + * + * **Note:** On Windows and Linux an open dialog can not be both a file selector + * and a directory selector, so if you set `properties` to `['openFile', + * 'openDirectory']` on these platforms, a directory selector will be shown. + */ + showOpenDialogSync(browserWindow: BrowserWindow, options: OpenDialogSyncOptions): (string[]) | (undefined); + /** + * the file paths chosen by the user; if the dialog is cancelled it returns + * `undefined`. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed or selected + * when you want to limit the user to a specific type. For example: + * + * The `extensions` array should contain extensions without wildcards or dots (e.g. + * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the + * `'*'` wildcard (no other wildcard is supported). + * + * **Note:** On Windows and Linux an open dialog can not be both a file selector + * and a directory selector, so if you set `properties` to `['openFile', + * 'openDirectory']` on these platforms, a directory selector will be shown. + */ + showOpenDialogSync(options: OpenDialogSyncOptions): (string[]) | (undefined); + /** + * Resolve with an object containing the following: + * + * * `canceled` boolean - whether or not the dialog was canceled. + * * `filePath` string (optional) - If the dialog is canceled, this will be + * `undefined`. + * * `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which + * contains the security scoped bookmark data for the saved file. + * `securityScopedBookmarks` must be enabled for this to be present. (For return + * values, see table here.) + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed, see + * `dialog.showOpenDialog` for an example. + * + * **Note:** On macOS, using the asynchronous version is recommended to avoid + * issues when expanding and collapsing the dialog. + */ + showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions): Promise<Electron.SaveDialogReturnValue>; + /** + * Resolve with an object containing the following: + * + * * `canceled` boolean - whether or not the dialog was canceled. + * * `filePath` string (optional) - If the dialog is canceled, this will be + * `undefined`. + * * `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which + * contains the security scoped bookmark data for the saved file. + * `securityScopedBookmarks` must be enabled for this to be present. (For return + * values, see table here.) + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed, see + * `dialog.showOpenDialog` for an example. + * + * **Note:** On macOS, using the asynchronous version is recommended to avoid + * issues when expanding and collapsing the dialog. + */ + showSaveDialog(options: SaveDialogOptions): Promise<Electron.SaveDialogReturnValue>; + /** + * the path of the file chosen by the user; if the dialog is cancelled it returns + * `undefined`. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed, see + * `dialog.showOpenDialog` for an example. + */ + showSaveDialogSync(browserWindow: BrowserWindow, options: SaveDialogSyncOptions): (string) | (undefined); + /** + * the path of the file chosen by the user; if the dialog is cancelled it returns + * `undefined`. + * + * The `browserWindow` argument allows the dialog to attach itself to a parent + * window, making it modal. + * + * The `filters` specifies an array of file types that can be displayed, see + * `dialog.showOpenDialog` for an example. + */ + showSaveDialogSync(options: SaveDialogSyncOptions): (string) | (undefined); + } + + interface Display { + + // Docs: https://electronjs.org/docs/api/structures/display + + /** + * Can be `available`, `unavailable`, `unknown`. + */ + accelerometerSupport: ('available' | 'unavailable' | 'unknown'); + /** + * the bounds of the display in DIP points. + */ + bounds: Rectangle; + /** + * The number of bits per pixel. + */ + colorDepth: number; + /** + * represent a color space (three-dimensional object which contains all realizable + * color combinations) for the purpose of color conversions + */ + colorSpace: string; + /** + * The number of bits per color component. + */ + depthPerComponent: number; + /** + * The display refresh rate. + */ + displayFrequency: number; + /** + * Unique identifier associated with the display. + */ + id: number; + /** + * `true` for an internal display and `false` for an external display + */ + internal: boolean; + /** + * Whether or not the display is a monochrome display. + */ + monochrome: boolean; + /** + * Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. + */ + rotation: number; + /** + * Output device's pixel scale factor. + */ + scaleFactor: number; + size: Size; + /** + * Can be `available`, `unavailable`, `unknown`. + */ + touchSupport: ('available' | 'unavailable' | 'unknown'); + /** + * the work area of the display in DIP points. + */ + workArea: Rectangle; + workAreaSize: Size; + } + + class Dock { + + // Docs: https://electronjs.org/docs/api/dock + + /** + * an ID representing the request. + * + * When `critical` is passed, the dock icon will bounce until either the + * application becomes active or the request is canceled. + * + * When `informational` is passed, the dock icon will bounce for one second. + * However, the request remains active until either the application becomes active + * or the request is canceled. + * + * **Note:** This method can only be used while the app is not focused; when the + * app is focused it will return -1. + * + * @platform darwin + */ + bounce(type?: 'critical' | 'informational'): number; + /** + * Cancel the bounce of `id`. + * + * @platform darwin + */ + cancelBounce(id: number): void; + /** + * Bounces the Downloads stack if the filePath is inside the Downloads folder. + * + * @platform darwin + */ + downloadFinished(filePath: string): void; + /** + * The badge string of the dock. + * + * @platform darwin + */ + getBadge(): string; + /** + * The application's [dock menu][dock-menu]. + * + * @platform darwin + */ + getMenu(): (Menu) | (null); + /** + * Hides the dock icon. + * + * @platform darwin + */ + hide(): void; + /** + * Whether the dock icon is visible. + * + * @platform darwin + */ + isVisible(): boolean; + /** + * Sets the string to be displayed in the dock’s badging area. + * + * @platform darwin + */ + setBadge(text: string): void; + /** + * Sets the `image` associated with this dock icon. + * + * @platform darwin + */ + setIcon(image: (NativeImage) | (string)): void; + /** + * Sets the application's [dock menu][dock-menu]. + * + * @platform darwin + */ + setMenu(menu: Menu): void; + /** + * Resolves when the dock icon is shown. + * + * @platform darwin + */ + show(): Promise<void>; + } + + class DownloadItem extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/download-item + + /** + * Emitted when the download is in a terminal state. This includes a completed + * download, a cancelled download (via `downloadItem.cancel()`), and interrupted + * download that can't be resumed. + * + * The `state` can be one of following: + * + * * `completed` - The download completed successfully. + * * `cancelled` - The download has been cancelled. + * * `interrupted` - The download has interrupted and can not resume. + */ + on(event: 'done', listener: (event: Event, + /** + * Can be `completed`, `cancelled` or `interrupted`. + */ + state: ('completed' | 'cancelled' | 'interrupted')) => void): this; + once(event: 'done', listener: (event: Event, + /** + * Can be `completed`, `cancelled` or `interrupted`. + */ + state: ('completed' | 'cancelled' | 'interrupted')) => void): this; + addListener(event: 'done', listener: (event: Event, + /** + * Can be `completed`, `cancelled` or `interrupted`. + */ + state: ('completed' | 'cancelled' | 'interrupted')) => void): this; + removeListener(event: 'done', listener: (event: Event, + /** + * Can be `completed`, `cancelled` or `interrupted`. + */ + state: ('completed' | 'cancelled' | 'interrupted')) => void): this; + /** + * Emitted when the download has been updated and is not done. + * + * The `state` can be one of following: + * + * * `progressing` - The download is in-progress. + * * `interrupted` - The download has interrupted and can be resumed. + */ + on(event: 'updated', listener: (event: Event, + /** + * Can be `progressing` or `interrupted`. + */ + state: ('progressing' | 'interrupted')) => void): this; + once(event: 'updated', listener: (event: Event, + /** + * Can be `progressing` or `interrupted`. + */ + state: ('progressing' | 'interrupted')) => void): this; + addListener(event: 'updated', listener: (event: Event, + /** + * Can be `progressing` or `interrupted`. + */ + state: ('progressing' | 'interrupted')) => void): this; + removeListener(event: 'updated', listener: (event: Event, + /** + * Can be `progressing` or `interrupted`. + */ + state: ('progressing' | 'interrupted')) => void): this; + /** + * Cancels the download operation. + */ + cancel(): void; + /** + * Whether the download can resume. + */ + canResume(): boolean; + /** + * The Content-Disposition field from the response header. + */ + getContentDisposition(): string; + /** + * ETag header value. + */ + getETag(): string; + /** + * The file name of the download item. + * + * **Note:** The file name is not always the same as the actual one saved in local + * disk. If user changes the file name in a prompted download saving dialog, the + * actual name of saved file will be different. + */ + getFilename(): string; + /** + * Last-Modified header value. + */ + getLastModifiedTime(): string; + /** + * The files mime type. + */ + getMimeType(): string; + /** + * The received bytes of the download item. + */ + getReceivedBytes(): number; + /** + * Returns the object previously set by + * `downloadItem.setSaveDialogOptions(options)`. + */ + getSaveDialogOptions(): SaveDialogOptions; + /** + * The save path of the download item. This will be either the path set via + * `downloadItem.setSavePath(path)` or the path selected from the shown save + * dialog. + */ + getSavePath(): string; + /** + * Number of seconds since the UNIX epoch when the download was started. + */ + getStartTime(): number; + /** + * The current state. Can be `progressing`, `completed`, `cancelled` or + * `interrupted`. + * + * **Note:** The following methods are useful specifically to resume a `cancelled` + * item when session is restarted. + */ + getState(): ('progressing' | 'completed' | 'cancelled' | 'interrupted'); + /** + * The total size in bytes of the download item. + * + * If the size is unknown, it returns 0. + */ + getTotalBytes(): number; + /** + * The origin URL where the item is downloaded from. + */ + getURL(): string; + /** + * The complete URL chain of the item including any redirects. + */ + getURLChain(): string[]; + /** + * Whether the download has user gesture. + */ + hasUserGesture(): boolean; + /** + * Whether the download is paused. + */ + isPaused(): boolean; + /** + * Pauses the download. + */ + pause(): void; + /** + * Resumes the download that has been paused. + * + * **Note:** To enable resumable downloads the server you are downloading from must + * support range requests and provide both `Last-Modified` and `ETag` header + * values. Otherwise `resume()` will dismiss previously received bytes and restart + * the download from the beginning. + */ + resume(): void; + /** + * This API allows the user to set custom options for the save dialog that opens + * for the download item by default. The API is only available in session's + * `will-download` callback function. + */ + setSaveDialogOptions(options: SaveDialogOptions): void; + /** + * The API is only available in session's `will-download` callback function. If + * `path` doesn't exist, Electron will try to make the directory recursively. If + * user doesn't set the save path via the API, Electron will use the original + * routine to determine the save path; this usually prompts a save dialog. + */ + setSavePath(path: string): void; + /** + * A `string` property that determines the save file path of the download item. + * + * The property is only available in session's `will-download` callback function. + * If user doesn't set the save path via the property, Electron will use the + * original routine to determine the save path; this usually prompts a save dialog. + */ + savePath: string; + } + + interface Event extends GlobalEvent { + + // Docs: https://electronjs.org/docs/api/structures/event + + preventDefault: (() => void); + } + + interface Extension { + + // Docs: https://electronjs.org/docs/api/structures/extension + + id: string; + /** + * Copy of the extension's manifest data. + */ + manifest: any; + name: string; + /** + * The extension's file path. + */ + path: string; + /** + * The extension's `chrome-extension://` URL. + */ + url: string; + version: string; + } + + interface ExtensionInfo { + + // Docs: https://electronjs.org/docs/api/structures/extension-info + + name: string; + version: string; + } + + interface FileFilter { + + // Docs: https://electronjs.org/docs/api/structures/file-filter + + extensions: string[]; + name: string; + } + + interface FilePathWithHeaders { + + // Docs: https://electronjs.org/docs/api/structures/file-path-with-headers + + /** + * Additional headers to be sent. + */ + headers?: Record<string, string>; + /** + * The path to the file to send. + */ + path: string; + } + + interface GlobalShortcut { + + // Docs: https://electronjs.org/docs/api/global-shortcut + + /** + * Whether this application has registered `accelerator`. + * + * When the accelerator is already taken by other applications, this call will + * still return `false`. This behavior is intended by operating systems, since they + * don't want applications to fight for global shortcuts. + */ + isRegistered(accelerator: Accelerator): boolean; + /** + * Whether or not the shortcut was registered successfully. + * + * Registers a global shortcut of `accelerator`. The `callback` is called when the + * registered shortcut is pressed by the user. + * + * When the accelerator is already taken by other applications, this call will + * silently fail. This behavior is intended by operating systems, since they don't + * want applications to fight for global shortcuts. + * + * The following accelerators will not be registered successfully on macOS 10.14 + * Mojave unless the app has been authorized as a trusted accessibility client: + * + * * "Media Play/Pause" + * * "Media Next Track" + * * "Media Previous Track" + * * "Media Stop" + */ + register(accelerator: Accelerator, callback: () => void): boolean; + /** + * Registers a global shortcut of all `accelerator` items in `accelerators`. The + * `callback` is called when any of the registered shortcuts are pressed by the + * user. + * + * When a given accelerator is already taken by other applications, this call will + * silently fail. This behavior is intended by operating systems, since they don't + * want applications to fight for global shortcuts. + * + * The following accelerators will not be registered successfully on macOS 10.14 + * Mojave unless the app has been authorized as a trusted accessibility client: + * + * * "Media Play/Pause" + * * "Media Next Track" + * * "Media Previous Track" + * * "Media Stop" + */ + registerAll(accelerators: string[], callback: () => void): void; + /** + * Unregisters the global shortcut of `accelerator`. + */ + unregister(accelerator: Accelerator): void; + /** + * Unregisters all of the global shortcuts. + */ + unregisterAll(): void; + } + + interface GPUFeatureStatus { + + // Docs: https://electronjs.org/docs/api/structures/gpu-feature-status + + /** + * Canvas. + */ + '2d_canvas': string; + /** + * Flash. + */ + flash_3d: string; + /** + * Flash Stage3D. + */ + flash_stage3d: string; + /** + * Flash Stage3D Baseline profile. + */ + flash_stage3d_baseline: string; + /** + * Compositing. + */ + gpu_compositing: string; + /** + * Multiple Raster Threads. + */ + multiple_raster_threads: string; + /** + * Native GpuMemoryBuffers. + */ + native_gpu_memory_buffers: string; + /** + * Rasterization. + */ + rasterization: string; + /** + * Video Decode. + */ + video_decode: string; + /** + * Video Encode. + */ + video_encode: string; + /** + * VPx Video Decode. + */ + vpx_decode: string; + /** + * WebGL. + */ + webgl: string; + /** + * WebGL2. + */ + webgl2: string; + } + + interface HIDDevice { + + // Docs: https://electronjs.org/docs/api/structures/hid-device + + /** + * Unique identifier for the device. + */ + deviceId: string; + /** + * Unique identifier for the HID interface. A device may have multiple HID + * interfaces. + */ + guid?: string; + /** + * Name of the device. + */ + name: string; + /** + * The USB product ID. + */ + productId: number; + /** + * The USB device serial number. + */ + serialNumber?: string; + /** + * The USB vendor ID. + */ + vendorId: number; + } + + interface InAppPurchase extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/in-app-purchase + + on(event: 'transactions-updated', listener: Function): this; + once(event: 'transactions-updated', listener: Function): this; + addListener(event: 'transactions-updated', listener: Function): this; + removeListener(event: 'transactions-updated', listener: Function): this; + /** + * whether a user can make a payment. + */ + canMakePayments(): boolean; + /** + * Completes all pending transactions. + */ + finishAllTransactions(): void; + /** + * Completes the pending transactions corresponding to the date. + */ + finishTransactionByDate(date: string): void; + /** + * Resolves with an array of `Product` objects. + * + * Retrieves the product descriptions. + */ + getProducts(productIDs: string[]): Promise<Electron.Product[]>; + /** + * the path to the receipt. + */ + getReceiptURL(): string; + /** + * Returns `true` if the product is valid and added to the payment queue. + * + * You should listen for the `transactions-updated` event as soon as possible and + * certainly before you call `purchaseProduct`. + */ + purchaseProduct(productID: string, quantity?: number): Promise<boolean>; + /** + * Restores finished transactions. This method can be called either to install + * purchases on additional devices, or to restore purchases for an application that + * the user deleted and reinstalled. + * + * The payment queue delivers a new transaction for each previously completed + * transaction that can be restored. Each transaction includes a copy of the + * original transaction. + */ + restoreCompletedTransactions(): void; + } + + class IncomingMessage extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/incoming-message + + /** + * Emitted when a request has been canceled during an ongoing HTTP transaction. + */ + on(event: 'aborted', listener: Function): this; + once(event: 'aborted', listener: Function): this; + addListener(event: 'aborted', listener: Function): this; + removeListener(event: 'aborted', listener: Function): this; + /** + * The `data` event is the usual method of transferring response data into + * applicative code. + */ + on(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + once(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + addListener(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + removeListener(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + /** + * Indicates that response body has ended. Must be placed before 'data' event. + */ + on(event: 'end', listener: Function): this; + once(event: 'end', listener: Function): this; + addListener(event: 'end', listener: Function): this; + removeListener(event: 'end', listener: Function): this; + /** + * Returns: + * + * `error` Error - Typically holds an error string identifying failure root cause. + * + * Emitted when an error was encountered while streaming response data events. For + * instance, if the server closes the underlying while the response is still + * streaming, an `error` event will be emitted on the response object and a `close` + * event will subsequently follow on the request object. + */ + on(event: 'error', listener: Function): this; + once(event: 'error', listener: Function): this; + addListener(event: 'error', listener: Function): this; + removeListener(event: 'error', listener: Function): this; + /** + * A `Record<string, string | string[]>` representing the HTTP response headers. + * The `headers` object is formatted as follows: + * + * * All header names are lowercased. + * * Duplicates of `age`, `authorization`, `content-length`, `content-type`, + * `etag`, `expires`, `from`, `host`, `if-modified-since`, `if-unmodified-since`, + * `last-modified`, `location`, `max-forwards`, `proxy-authorization`, `referer`, + * `retry-after`, `server`, or `user-agent` are discarded. + * * `set-cookie` is always an array. Duplicates are added to the array. + * * For duplicate `cookie` headers, the values are joined together with '; '. + * * For all other headers, the values are joined together with ', '. + */ + headers: Record<string, (string) | (string[])>; + /** + * A `string` indicating the HTTP protocol version number. Typical values are '1.0' + * or '1.1'. Additionally `httpVersionMajor` and `httpVersionMinor` are two + * Integer-valued readable properties that return respectively the HTTP major and + * minor version numbers. + */ + httpVersion: string; + /** + * An `Integer` indicating the HTTP protocol major version number. + */ + httpVersionMajor: number; + /** + * An `Integer` indicating the HTTP protocol minor version number. + */ + httpVersionMinor: number; + /** + * A `string[]` containing the raw HTTP response headers exactly as they were + * received. The keys and values are in the same list. It is not a list of tuples. + * So, the even-numbered offsets are key values, and the odd-numbered offsets are + * the associated values. Header names are not lowercased, and duplicates are not + * merged. + */ + rawHeaders: string[]; + /** + * An `Integer` indicating the HTTP response status code. + */ + statusCode: number; + /** + * A `string` representing the HTTP status message. + */ + statusMessage: string; + } + + interface InputEvent { + + // Docs: https://electronjs.org/docs/api/structures/input-event + + /** + * An array of modifiers of the event, can be `shift`, `control`, `ctrl`, `alt`, + * `meta`, `command`, `cmd`, `isKeypad`, `isAutoRepeat`, `leftButtonDown`, + * `middleButtonDown`, `rightButtonDown`, `capsLock`, `numLock`, `left`, `right`. + */ + modifiers?: Array<'shift' | 'control' | 'ctrl' | 'alt' | 'meta' | 'command' | 'cmd' | 'isKeypad' | 'isAutoRepeat' | 'leftButtonDown' | 'middleButtonDown' | 'rightButtonDown' | 'capsLock' | 'numLock' | 'left' | 'right'>; + } + + interface IOCounters { + + // Docs: https://electronjs.org/docs/api/structures/io-counters + + /** + * Then number of I/O other operations. + */ + otherOperationCount: number; + /** + * Then number of I/O other transfers. + */ + otherTransferCount: number; + /** + * The number of I/O read operations. + */ + readOperationCount: number; + /** + * The number of I/O read transfers. + */ + readTransferCount: number; + /** + * The number of I/O write operations. + */ + writeOperationCount: number; + /** + * The number of I/O write transfers. + */ + writeTransferCount: number; + } + + interface IpcMain extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/ipc-main + + /** + * Adds a handler for an `invoke`able IPC. This handler will be called whenever a + * renderer calls `ipcRenderer.invoke(channel, ...args)`. + * + * If `listener` returns a Promise, the eventual result of the promise will be + * returned as a reply to the remote caller. Otherwise, the return value of the + * listener will be used as the value of the reply. + * + * The `event` that is passed as the first argument to the handler is the same as + * that passed to a regular event listener. It includes information about which + * WebContents is the source of the invoke request. + * + * Errors thrown through `handle` in the main process are not transparent as they + * are serialized and only the `message` property from the original error is + * provided to the renderer process. Please refer to #24427 for details. + */ + handle(channel: string, listener: (event: IpcMainInvokeEvent, ...args: any[]) => (Promise<void>) | (any)): void; + /** + * Handles a single `invoke`able IPC message, then removes the listener. See + * `ipcMain.handle(channel, listener)`. + */ + handleOnce(channel: string, listener: (event: IpcMainInvokeEvent, ...args: any[]) => (Promise<void>) | (any)): void; + /** + * Listens to `channel`, when a new message arrives `listener` would be called with + * `listener(event, args...)`. + */ + on(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; + /** + * Adds a one time `listener` function for the event. This `listener` is invoked + * only the next time a message is sent to `channel`, after which it is removed. + */ + once(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; + /** + * Removes listeners of the specified `channel`. + */ + removeAllListeners(channel?: string): this; + /** + * Removes any handler for `channel`, if present. + */ + removeHandler(channel: string): void; + /** + * Removes the specified `listener` from the listener array for the specified + * `channel`. + */ + removeListener(channel: string, listener: (...args: any[]) => void): this; + } + + interface IpcMainEvent extends Event { + + // Docs: https://electronjs.org/docs/api/structures/ipc-main-event + + /** + * The ID of the renderer frame that sent this message + */ + frameId: number; + /** + * A list of MessagePorts that were transferred with this message + */ + ports: MessagePortMain[]; + /** + * The internal ID of the renderer process that sent this message + */ + processId: number; + /** + * A function that will send an IPC message to the renderer frame that sent the + * original message that you are currently handling. You should use this method to + * "reply" to the sent message in order to guarantee the reply will go to the + * correct process and frame. + */ + reply: Function; + /** + * Set this to the value to be returned in a synchronous message + */ + returnValue: any; + /** + * Returns the `webContents` that sent the message + */ + sender: WebContents; + /** + * The frame that sent this message + * + */ + readonly senderFrame: WebFrameMain; + } + + interface IpcMainInvokeEvent extends Event { + + // Docs: https://electronjs.org/docs/api/structures/ipc-main-invoke-event + + /** + * The ID of the renderer frame that sent this message + */ + frameId: number; + /** + * The internal ID of the renderer process that sent this message + */ + processId: number; + /** + * Returns the `webContents` that sent the message + */ + sender: WebContents; + /** + * The frame that sent this message + * + */ + readonly senderFrame: WebFrameMain; + } + + interface IpcRenderer extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/ipc-renderer + + /** + * Resolves with the response from the main process. + * + * Send a message to the main process via `channel` and expect a result + * asynchronously. Arguments will be serialized with the Structured Clone + * Algorithm, just like `window.postMessage`, so prototype chains will not be + * included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw + * an exception. + * + * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + * Electron objects will throw an exception. + * + * Since the main process does not have support for DOM objects such as + * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over + * Electron's IPC to the main process, as the main process would have no way to + * decode them. Attempting to send such objects over IPC will result in an error. + * + * The main process should listen for `channel` with `ipcMain.handle()`. + * + * For example: + * + * If you need to transfer a `MessagePort` to the main process, use + * `ipcRenderer.postMessage`. + * + * If you do not need a response to the message, consider using `ipcRenderer.send`. + */ + invoke(channel: string, ...args: any[]): Promise<any>; + /** + * Listens to `channel`, when a new message arrives `listener` would be called with + * `listener(event, args...)`. + */ + on(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; + /** + * Adds a one time `listener` function for the event. This `listener` is invoked + * only the next time a message is sent to `channel`, after which it is removed. + */ + once(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; + /** + * Send a message to the main process, optionally transferring ownership of zero or + * more `MessagePort` objects. + * + * The transferred `MessagePort` objects will be available in the main process as + * `MessagePortMain` objects by accessing the `ports` property of the emitted + * event. + * + * For example: + * + * For more information on using `MessagePort` and `MessageChannel`, see the MDN + * documentation. + */ + postMessage(channel: string, message: any, transfer?: MessagePort[]): void; + /** + * Removes all listeners, or those of the specified `channel`. + */ + removeAllListeners(channel: string): this; + /** + * Removes the specified `listener` from the listener array for the specified + * `channel`. + */ + removeListener(channel: string, listener: (...args: any[]) => void): this; + /** + * Send an asynchronous message to the main process via `channel`, along with + * arguments. Arguments will be serialized with the Structured Clone Algorithm, + * just like `window.postMessage`, so prototype chains will not be included. + * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an + * exception. + * + * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + * Electron objects will throw an exception. + * + * Since the main process does not have support for DOM objects such as + * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over + * Electron's IPC to the main process, as the main process would have no way to + * decode them. Attempting to send such objects over IPC will result in an error. + * + * The main process handles it by listening for `channel` with the `ipcMain` + * module. + * + * If you need to transfer a `MessagePort` to the main process, use + * `ipcRenderer.postMessage`. + * + * If you want to receive a single response from the main process, like the result + * of a method call, consider using `ipcRenderer.invoke`. + */ + send(channel: string, ...args: any[]): void; + /** + * The value sent back by the `ipcMain` handler. + * + * Send a message to the main process via `channel` and expect a result + * synchronously. Arguments will be serialized with the Structured Clone Algorithm, + * just like `window.postMessage`, so prototype chains will not be included. + * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an + * exception. + * + * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + * Electron objects will throw an exception. + * + * Since the main process does not have support for DOM objects such as + * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over + * Electron's IPC to the main process, as the main process would have no way to + * decode them. Attempting to send such objects over IPC will result in an error. + * + * The main process handles it by listening for `channel` with `ipcMain` module, + * and replies by setting `event.returnValue`. + * + * > :warning: **WARNING**: Sending a synchronous message will block the whole + * renderer process until the reply is received, so use this method only as a last + * resort. It's much better to use the asynchronous version, `invoke()`. + */ + sendSync(channel: string, ...args: any[]): any; + /** + * Sends a message to a window with `webContentsId` via `channel`. + */ + sendTo(webContentsId: number, channel: string, ...args: any[]): void; + /** + * Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in + * the host page instead of the main process. + */ + sendToHost(channel: string, ...args: any[]): void; + } + + interface IpcRendererEvent extends Event { + + // Docs: https://electronjs.org/docs/api/structures/ipc-renderer-event + + /** + * A list of MessagePorts that were transferred with this message + */ + ports: MessagePort[]; + /** + * The `IpcRenderer` instance that emitted the event originally + */ + sender: IpcRenderer; + /** + * The `webContents.id` that sent the message, you can call + * `event.sender.sendTo(event.senderId, ...)` to reply to the message, see + * ipcRenderer.sendTo for more information. This only applies to messages sent from + * a different renderer. Messages sent directly from the main process set + * `event.senderId` to `0`. + */ + senderId: number; + } + + interface JumpListCategory { + + // Docs: https://electronjs.org/docs/api/structures/jump-list-category + + /** + * Array of `JumpListItem` objects if `type` is `tasks` or `custom`, otherwise it + * should be omitted. + */ + items?: JumpListItem[]; + /** + * Must be set if `type` is `custom`, otherwise it should be omitted. + */ + name?: string; + /** + * One of the following: + */ + type?: ('tasks' | 'frequent' | 'recent' | 'custom'); + } + + interface JumpListItem { + + // Docs: https://electronjs.org/docs/api/structures/jump-list-item + + /** + * The command line arguments when `program` is executed. Should only be set if + * `type` is `task`. + */ + args?: string; + /** + * Description of the task (displayed in a tooltip). Should only be set if `type` + * is `task`. Maximum length 260 characters. + */ + description?: string; + /** + * The index of the icon in the resource file. If a resource file contains multiple + * icons this value can be used to specify the zero-based index of the icon that + * should be displayed for this task. If a resource file contains only one icon, + * this property should be set to zero. + */ + iconIndex?: number; + /** + * The absolute path to an icon to be displayed in a Jump List, which can be an + * arbitrary resource file that contains an icon (e.g. `.ico`, `.exe`, `.dll`). You + * can usually specify `process.execPath` to show the program icon. + */ + iconPath?: string; + /** + * Path of the file to open, should only be set if `type` is `file`. + */ + path?: string; + /** + * Path of the program to execute, usually you should specify `process.execPath` + * which opens the current program. Should only be set if `type` is `task`. + */ + program?: string; + /** + * The text to be displayed for the item in the Jump List. Should only be set if + * `type` is `task`. + */ + title?: string; + /** + * One of the following: + */ + type?: ('task' | 'separator' | 'file'); + /** + * The working directory. Default is empty. + */ + workingDirectory?: string; + } + + interface KeyboardEvent { + + // Docs: https://electronjs.org/docs/api/structures/keyboard-event + + /** + * whether an Alt key was used in an accelerator to trigger the Event + */ + altKey?: boolean; + /** + * whether the Control key was used in an accelerator to trigger the Event + */ + ctrlKey?: boolean; + /** + * whether a meta key was used in an accelerator to trigger the Event + */ + metaKey?: boolean; + /** + * whether a Shift key was used in an accelerator to trigger the Event + */ + shiftKey?: boolean; + /** + * whether an accelerator was used to trigger the event as opposed to another user + * gesture like mouse click + */ + triggeredByAccelerator?: boolean; + } + + interface KeyboardInputEvent extends InputEvent { + + // Docs: https://electronjs.org/docs/api/structures/keyboard-input-event + + /** + * The character that will be sent as the keyboard event. Should only use the valid + * key codes in Accelerator. + */ + keyCode: string; + /** + * The type of the event, can be `keyDown`, `keyUp` or `char`. + */ + type: ('keyDown' | 'keyUp' | 'char'); + } + + interface MemoryInfo { + + // Docs: https://electronjs.org/docs/api/structures/memory-info + + /** + * The maximum amount of memory that has ever been pinned to actual physical RAM. + */ + peakWorkingSetSize: number; + /** + * The amount of memory not shared by other processes, such as JS heap or HTML + * content. + * + * @platform win32 + */ + privateBytes?: number; + /** + * The amount of memory currently pinned to actual physical RAM. + */ + workingSetSize: number; + } + + interface MemoryUsageDetails { + + // Docs: https://electronjs.org/docs/api/structures/memory-usage-details + + count: number; + liveSize: number; + size: number; + } + + class Menu { + + // Docs: https://electronjs.org/docs/api/menu + + /** + * Emitted when a popup is closed either manually or with `menu.closePopup()`. + */ + on(event: 'menu-will-close', listener: (event: Event) => void): this; + once(event: 'menu-will-close', listener: (event: Event) => void): this; + addListener(event: 'menu-will-close', listener: (event: Event) => void): this; + removeListener(event: 'menu-will-close', listener: (event: Event) => void): this; + /** + * Emitted when `menu.popup()` is called. + */ + on(event: 'menu-will-show', listener: (event: Event) => void): this; + once(event: 'menu-will-show', listener: (event: Event) => void): this; + addListener(event: 'menu-will-show', listener: (event: Event) => void): this; + removeListener(event: 'menu-will-show', listener: (event: Event) => void): this; + /** + * Menu + */ + constructor(); + /** + * Generally, the `template` is an array of `options` for constructing a MenuItem. + * The usage can be referenced above. + * + * You can also attach other fields to the element of the `template` and they will + * become properties of the constructed menu items. + */ + static buildFromTemplate(template: Array<(MenuItemConstructorOptions) | (MenuItem)>): Menu; + /** + * The application menu, if set, or `null`, if not set. + * + * **Note:** The returned `Menu` instance doesn't support dynamic addition or + * removal of menu items. Instance properties can still be dynamically modified. + */ + static getApplicationMenu(): (Menu) | (null); + /** + * Sends the `action` to the first responder of application. This is used for + * emulating default macOS menu behaviors. Usually you would use the `role` + * property of a `MenuItem`. + * + * See the macOS Cocoa Event Handling Guide for more information on macOS' native + * actions. + * + * @platform darwin + */ + static sendActionToFirstResponder(action: string): void; + /** + * Sets `menu` as the application menu on macOS. On Windows and Linux, the `menu` + * will be set as each window's top menu. + * + * Also on Windows and Linux, you can use a `&` in the top-level item name to + * indicate which letter should get a generated accelerator. For example, using + * `&File` for the file menu would result in a generated `Alt-F` accelerator that + * opens the associated menu. The indicated character in the button label then gets + * an underline, and the `&` character is not displayed on the button label. + * + * In order to escape the `&` character in an item name, add a proceeding `&`. For + * example, `&&File` would result in `&File` displayed on the button label. + * + * Passing `null` will suppress the default menu. On Windows and Linux, this has + * the additional effect of removing the menu bar from the window. + * + * **Note:** The default menu will be created automatically if the app does not set + * one. It contains standard items such as `File`, `Edit`, `View`, `Window` and + * `Help`. + */ + static setApplicationMenu(menu: (Menu) | (null)): void; + /** + * Appends the `menuItem` to the menu. + */ + append(menuItem: MenuItem): void; + /** + * Closes the context menu in the `browserWindow`. + */ + closePopup(browserWindow?: BrowserWindow): void; + /** + * the item with the specified `id` + */ + getMenuItemById(id: string): (MenuItem) | (null); + /** + * Inserts the `menuItem` to the `pos` position of the menu. + */ + insert(pos: number, menuItem: MenuItem): void; + /** + * Pops up this menu as a context menu in the `BrowserWindow`. + */ + popup(options?: PopupOptions): void; + /** + * A `MenuItem[]` array containing the menu's items. + * + * Each `Menu` consists of multiple `MenuItem`s and each `MenuItem` can have a + * submenu. + */ + items: MenuItem[]; + } + + class MenuItem { + + // Docs: https://electronjs.org/docs/api/menu-item + + /** + * MenuItem + */ + constructor(options: MenuItemConstructorOptions); + /** + * An `Accelerator` (optional) indicating the item's accelerator, if set. + */ + accelerator?: Accelerator; + /** + * A `boolean` indicating whether the item is checked, this property can be + * dynamically changed. + * + * A `checkbox` menu item will toggle the `checked` property on and off when + * selected. + * + * A `radio` menu item will turn on its `checked` property when clicked, and will + * turn off that property for all adjacent items in the same menu. + * + * You can add a `click` function for additional behavior. + */ + checked: boolean; + /** + * A `Function` that is fired when the MenuItem receives a click event. It can be + * called with `menuItem.click(event, focusedWindow, focusedWebContents)`. + * + * * `event` KeyboardEvent + * * `focusedWindow` BrowserWindow + * * `focusedWebContents` WebContents + */ + click: Function; + /** + * A `number` indicating an item's sequential unique id. + */ + commandId: number; + /** + * A `boolean` indicating whether the item is enabled, this property can be + * dynamically changed. + */ + enabled: boolean; + /** + * A `NativeImage | string` (optional) indicating the item's icon, if set. + */ + icon?: (NativeImage) | (string); + /** + * A `string` indicating the item's unique id, this property can be dynamically + * changed. + */ + id: string; + /** + * A `string` indicating the item's visible label. + */ + label: string; + /** + * A `Menu` that the item is a part of. + */ + menu: Menu; + /** + * A `boolean` indicating if the accelerator should be registered with the system + * or just displayed. + * + * This property can be dynamically changed. + */ + registerAccelerator: boolean; + /** + * A `string` (optional) indicating the item's role, if set. Can be `undo`, `redo`, + * `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, + * `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, + * `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, + * `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, + * `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, + * `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, + * `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, + * `moveTabToNewWindow` or `windowMenu` + */ + role?: ('undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'toggleSpellChecker' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'startSpeaking' | 'stopSpeaking' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'shareMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'); + /** + * A `SharingItem` indicating the item to share when the `role` is `shareMenu`. + * + * This property can be dynamically changed. + * + * @platform darwin + */ + sharingItem: SharingItem; + /** + * A `string` indicating the item's sublabel. + */ + sublabel: string; + /** + * A `Menu` (optional) containing the menu item's submenu, if present. + */ + submenu?: Menu; + /** + * A `string` indicating the item's hover text. + * + * @platform darwin + */ + toolTip: string; + /** + * A `string` indicating the type of the item. Can be `normal`, `separator`, + * `submenu`, `checkbox` or `radio`. + */ + type: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'); + /** + * An `Accelerator | null` indicating the item's user-assigned accelerator for the + * menu item. + * + * **Note:** This property is only initialized after the `MenuItem` has been added + * to a `Menu`. Either via `Menu.buildFromTemplate` or via + * `Menu.append()/insert()`. Accessing before initialization will just return + * `null`. + * + * @platform darwin + */ + readonly userAccelerator: (Accelerator) | (null); + /** + * A `boolean` indicating whether the item is visible, this property can be + * dynamically changed. + */ + visible: boolean; + } + + class MessageChannelMain extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/message-channel-main + + /** + * A `MessagePortMain` property. + */ + port1: MessagePortMain; + /** + * A `MessagePortMain` property. + */ + port2: MessagePortMain; + } + + class MessagePortMain extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/message-port-main + + /** + * Emitted when the remote end of a MessagePortMain object becomes disconnected. + */ + on(event: 'close', listener: Function): this; + once(event: 'close', listener: Function): this; + addListener(event: 'close', listener: Function): this; + removeListener(event: 'close', listener: Function): this; + /** + * Emitted when a MessagePortMain object receives a message. + */ + on(event: 'message', listener: (messageEvent: MessageEvent) => void): this; + once(event: 'message', listener: (messageEvent: MessageEvent) => void): this; + addListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this; + removeListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this; + /** + * Disconnects the port, so it is no longer active. + */ + close(): void; + /** + * Sends a message from the port, and optionally, transfers ownership of objects to + * other browsing contexts. + */ + postMessage(message: any, transfer?: MessagePortMain[]): void; + /** + * Starts the sending of messages queued on the port. Messages will be queued until + * this method is called. + */ + start(): void; + } + + interface MimeTypedBuffer { + + // Docs: https://electronjs.org/docs/api/structures/mime-typed-buffer + + /** + * Charset of the buffer. + */ + charset?: string; + /** + * The actual Buffer content. + */ + data: Buffer; + /** + * MIME type of the buffer. + */ + mimeType?: string; + } + + interface MouseInputEvent extends InputEvent { + + // Docs: https://electronjs.org/docs/api/structures/mouse-input-event + + /** + * The button pressed, can be `left`, `middle`, `right`. + */ + button?: ('left' | 'middle' | 'right'); + clickCount?: number; + globalX?: number; + globalY?: number; + movementX?: number; + movementY?: number; + /** + * The type of the event, can be `mouseDown`, `mouseUp`, `mouseEnter`, + * `mouseLeave`, `contextMenu`, `mouseWheel` or `mouseMove`. + */ + type: ('mouseDown' | 'mouseUp' | 'mouseEnter' | 'mouseLeave' | 'contextMenu' | 'mouseWheel' | 'mouseMove'); + x: number; + y: number; + } + + interface MouseWheelInputEvent extends MouseInputEvent { + + // Docs: https://electronjs.org/docs/api/structures/mouse-wheel-input-event + + accelerationRatioX?: number; + accelerationRatioY?: number; + canScroll?: boolean; + deltaX?: number; + deltaY?: number; + hasPreciseScrollingDeltas?: boolean; + /** + * The type of the event, can be `mouseWheel`. + */ + type: ('mouseWheel'); + wheelTicksX?: number; + wheelTicksY?: number; + } + + class NativeImage { + + // Docs: https://electronjs.org/docs/api/native-image + + /** + * Creates an empty `NativeImage` instance. + */ + static createEmpty(): NativeImage; + /** + * Creates a new `NativeImage` instance from `buffer` that contains the raw bitmap + * pixel data returned by `toBitmap()`. The specific format is platform-dependent. + */ + static createFromBitmap(buffer: Buffer, options: CreateFromBitmapOptions): NativeImage; + /** + * Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or + * JPEG first. + */ + static createFromBuffer(buffer: Buffer, options?: CreateFromBufferOptions): NativeImage; + /** + * Creates a new `NativeImage` instance from `dataURL`. + */ + static createFromDataURL(dataURL: string): NativeImage; + /** + * Creates a new `NativeImage` instance from the NSImage that maps to the given + * image name. See `System Icons` for a list of possible values. + * + * The `hslShift` is applied to the image with the following rules: + * + * * `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map to 0 + * and 360 on the hue color wheel (red). + * * `hsl_shift[1]` (saturation): A saturation shift for the image, with the + * following key values: 0 = remove all color. 0.5 = leave unchanged. 1 = fully + * saturate the image. + * * `hsl_shift[2]` (lightness): A lightness shift for the image, with the + * following key values: 0 = remove all lightness (make all pixels black). 0.5 = + * leave unchanged. 1 = full lightness (make all pixels white). + * + * This means that `[-1, 0, 1]` will make the image completely white and `[-1, 1, + * 0]` will make the image completely black. + * + * In some cases, the `NSImageName` doesn't match its string representation; one + * example of this is `NSFolderImageName`, whose string representation would + * actually be `NSFolder`. Therefore, you'll need to determine the correct string + * representation for your image before passing it in. This can be done with the + * following: + * + * `echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); + * }' | clang -otest -x objective-c -framework Cocoa - && ./test` + * + * where `SYSTEM_IMAGE_NAME` should be replaced with any value from this list. + * + * @platform darwin + */ + static createFromNamedImage(imageName: string, hslShift?: number[]): NativeImage; + /** + * Creates a new `NativeImage` instance from a file located at `path`. This method + * returns an empty image if the `path` does not exist, cannot be read, or is not a + * valid image. + */ + static createFromPath(path: string): NativeImage; + /** + * fulfilled with the file's thumbnail preview image, which is a NativeImage. + * + * @platform darwin,win32 + */ + static createThumbnailFromPath(path: string, maxSize: Size): Promise<Electron.NativeImage>; + /** + * Add an image representation for a specific scale factor. This can be used to + * explicitly add different scale factor representations to an image. This can be + * called on empty images. + */ + addRepresentation(options: AddRepresentationOptions): void; + /** + * The cropped image. + */ + crop(rect: Rectangle): NativeImage; + /** + * 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. + */ + getAspectRatio(scaleFactor?: number): number; + /** + * A Buffer that contains the image's raw bitmap pixel data. + * + * The difference between `getBitmap()` and `toBitmap()` is that `getBitmap()` does + * not copy the bitmap data, so you have to use the returned Buffer immediately in + * current event loop tick; otherwise the data might be changed or destroyed. + */ + getBitmap(options?: BitmapOptions): Buffer; + /** + * A Buffer that stores C pointer to underlying native handle of the image. On + * macOS, a pointer to `NSImage` instance would be returned. + * + * Notice that the returned pointer is a weak pointer to the underlying native + * image instead of a copy, so you _must_ ensure that the associated `nativeImage` + * instance is kept around. + * + * @platform darwin + */ + getNativeHandle(): Buffer; + /** + * An array of all scale factors corresponding to representations for a given + * nativeImage. + */ + getScaleFactors(): number[]; + /** + * If `scaleFactor` is passed, this will return the size corresponding to the image + * representation most closely matching the passed value. + */ + getSize(scaleFactor?: number): Size; + /** + * Whether the image is empty. + */ + isEmpty(): boolean; + /** + * Whether the image is a template image. + */ + isTemplateImage(): boolean; + /** + * The resized image. + * + * If only the `height` or the `width` are specified then the current aspect ratio + * will be preserved in the resized image. + */ + resize(options: ResizeOptions): NativeImage; + /** + * Marks the image as a template image. + */ + setTemplateImage(option: boolean): void; + /** + * A Buffer that contains a copy of the image's raw bitmap pixel data. + */ + toBitmap(options?: ToBitmapOptions): Buffer; + /** + * The data URL of the image. + */ + toDataURL(options?: ToDataURLOptions): string; + /** + * A Buffer that contains the image's `JPEG` encoded data. + */ + toJPEG(quality: number): Buffer; + /** + * A Buffer that contains the image's `PNG` encoded data. + */ + toPNG(options?: ToPNGOptions): Buffer; + /** + * A `boolean` property that determines whether the image is considered a template + * image. + * + * Please note that this property only has an effect on macOS. + * + * @platform darwin + */ + isMacTemplateImage: boolean; + } + + interface NativeTheme extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/native-theme + + /** + * Emitted when something in the underlying NativeTheme has changed. This normally + * means that either the value of `shouldUseDarkColors`, + * `shouldUseHighContrastColors` or `shouldUseInvertedColorScheme` has changed. You + * will have to check them to determine which one has changed. + */ + on(event: 'updated', listener: Function): this; + once(event: 'updated', listener: Function): this; + addListener(event: 'updated', listener: Function): this; + removeListener(event: 'updated', listener: Function): this; + /** + * A `boolean` indicating whether Chromium is in forced colors mode, controlled by + * system accessibility settings. Currently, Windows high contrast is the only + * system setting that triggers forced colors mode. + * + * @platform win32 + */ + readonly inForcedColorsMode: boolean; + /** + * A `boolean` for if the OS / Chromium currently has a dark mode enabled or is + * being instructed to show a dark-style UI. If you want to modify this value you + * should use `themeSource` below. + * + */ + readonly shouldUseDarkColors: boolean; + /** + * A `boolean` for if the OS / Chromium currently has high-contrast mode enabled or + * is being instructed to show a high-contrast UI. + * + * @platform darwin,win32 + */ + readonly shouldUseHighContrastColors: boolean; + /** + * A `boolean` for if the OS / Chromium currently has an inverted color scheme or + * is being instructed to use an inverted color scheme. + * + * @platform darwin,win32 + */ + readonly shouldUseInvertedColorScheme: boolean; + /** + * A `string` property that can be `system`, `light` or `dark`. It is used to + * override and supersede the value that Chromium has chosen to use internally. + * + * Setting this property to `system` will remove the override and everything will + * be reset to the OS default. By default `themeSource` is `system`. + * + * Settings this property to `dark` will have the following effects: + * + * * `nativeTheme.shouldUseDarkColors` will be `true` when accessed + * * Any UI Electron renders on Linux and Windows including context menus, + * devtools, etc. will use the dark UI. + * * Any UI the OS renders on macOS including menus, window frames, etc. will use + * the dark UI. + * * The `prefers-color-scheme` CSS query will match `dark` mode. + * * The `updated` event will be emitted + * + * Settings this property to `light` will have the following effects: + * + * * `nativeTheme.shouldUseDarkColors` will be `false` when accessed + * * Any UI Electron renders on Linux and Windows including context menus, + * devtools, etc. will use the light UI. + * * Any UI the OS renders on macOS including menus, window frames, etc. will use + * the light UI. + * * The `prefers-color-scheme` CSS query will match `light` mode. + * * The `updated` event will be emitted + * + * The usage of this property should align with a classic "dark mode" state machine + * in your application where the user has three options. + * + * * `Follow OS` --> `themeSource = 'system'` + * * `Dark Mode` --> `themeSource = 'dark'` + * * `Light Mode` --> `themeSource = 'light'` + * + * Your application should then always use `shouldUseDarkColors` to determine what + * CSS to apply. + */ + themeSource: ('system' | 'light' | 'dark'); + } + + interface Net { + + // Docs: https://electronjs.org/docs/api/net + + /** + * Whether there is currently internet connection. + * + * A return value of `false` is a pretty strong indicator that the user won't be + * able to connect to remote sites. However, a return value of `true` is + * inconclusive; even if some link is up, it is uncertain whether a particular + * connection attempt to a particular remote site will be successful. + */ + isOnline(): boolean; + /** + * Creates a `ClientRequest` instance using the provided `options` which are + * directly forwarded to the `ClientRequest` constructor. The `net.request` method + * would be used to issue both secure and insecure HTTP requests according to the + * specified protocol scheme in the `options` object. + */ + request(options: (ClientRequestConstructorOptions) | (string)): ClientRequest; + /** + * A `boolean` property. Whether there is currently internet connection. + * + * A return value of `false` is a pretty strong indicator that the user won't be + * able to connect to remote sites. However, a return value of `true` is + * inconclusive; even if some link is up, it is uncertain whether a particular + * connection attempt to a particular remote site will be successful. + * + */ + readonly online: boolean; + } + + interface NetLog { + + // Docs: https://electronjs.org/docs/api/net-log + + /** + * resolves when the net log has begun recording. + * + * Starts recording network events to `path`. + */ + startLogging(path: string, options?: StartLoggingOptions): Promise<void>; + /** + * resolves when the net log has been flushed to disk. + * + * Stops recording network events. If not called, net logging will automatically + * end when app quits. + */ + stopLogging(): Promise<void>; + /** + * A `boolean` property that indicates whether network logs are currently being + * recorded. + * + */ + readonly currentlyLogging: boolean; + } + + interface NewWindowWebContentsEvent extends Event { + + // Docs: https://electronjs.org/docs/api/structures/new-window-web-contents-event + + newGuest?: BrowserWindow; + } + + class Notification extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/notification + + on(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated. + */ + index: number) => void): this; + once(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated. + */ + index: number) => void): this; + addListener(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated. + */ + index: number) => void): this; + removeListener(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated. + */ + index: number) => void): this; + /** + * Emitted when the notification is clicked by the user. + */ + on(event: 'click', listener: (event: Event) => void): this; + once(event: 'click', listener: (event: Event) => void): this; + addListener(event: 'click', listener: (event: Event) => void): this; + removeListener(event: 'click', listener: (event: Event) => void): this; + /** + * Emitted when the notification is closed by manual intervention from the user. + * + * This event is not guaranteed to be emitted in all cases where the notification + * is closed. + */ + on(event: 'close', listener: (event: Event) => void): this; + once(event: 'close', listener: (event: Event) => void): this; + addListener(event: 'close', listener: (event: Event) => void): this; + removeListener(event: 'close', listener: (event: Event) => void): this; + /** + * Emitted when an error is encountered while creating and showing the native + * notification. + * + * @platform win32 + */ + on(event: 'failed', listener: (event: Event, + /** + * The error encountered during execution of the `show()` method. + */ + error: string) => void): this; + once(event: 'failed', listener: (event: Event, + /** + * The error encountered during execution of the `show()` method. + */ + error: string) => void): this; + addListener(event: 'failed', listener: (event: Event, + /** + * The error encountered during execution of the `show()` method. + */ + error: string) => void): this; + removeListener(event: 'failed', listener: (event: Event, + /** + * The error encountered during execution of the `show()` method. + */ + error: string) => void): this; + /** + * Emitted when the user clicks the "Reply" button on a notification with + * `hasReply: true`. + * + * @platform darwin + */ + on(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field. + */ + reply: string) => void): this; + once(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field. + */ + reply: string) => void): this; + addListener(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field. + */ + reply: string) => void): this; + removeListener(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field. + */ + reply: string) => void): this; + /** + * Emitted when the notification is shown to the user, note this could be fired + * multiple times as a notification can be shown multiple times through the + * `show()` method. + */ + on(event: 'show', listener: (event: Event) => void): this; + once(event: 'show', listener: (event: Event) => void): this; + addListener(event: 'show', listener: (event: Event) => void): this; + removeListener(event: 'show', listener: (event: Event) => void): this; + /** + * Notification + */ + constructor(options?: NotificationConstructorOptions); + /** + * Whether or not desktop notifications are supported on the current system + */ + static isSupported(): boolean; + /** + * Dismisses the notification. + */ + close(): void; + /** + * Immediately shows the notification to the user, please note this means unlike + * the HTML5 Notification implementation, instantiating a `new Notification` does + * not immediately show it to the user, you need to call this method before the OS + * will display it. + * + * If the notification has been shown before, this method will dismiss the + * previously shown notification and create a new one with identical properties. + */ + show(): void; + /** + * A `NotificationAction[]` property representing the actions of the notification. + */ + actions: NotificationAction[]; + /** + * A `string` property representing the body of the notification. + */ + body: string; + /** + * A `string` property representing the close button text of the notification. + */ + closeButtonText: string; + /** + * A `boolean` property representing whether the notification has a reply action. + */ + hasReply: boolean; + /** + * A `string` property representing the reply placeholder of the notification. + */ + replyPlaceholder: string; + /** + * A `boolean` property representing whether the notification is silent. + */ + silent: boolean; + /** + * A `string` property representing the sound of the notification. + */ + sound: string; + /** + * A `string` property representing the subtitle of the notification. + */ + subtitle: string; + /** + * A `string` property representing the type of timeout duration for the + * notification. Can be 'default' or 'never'. + * + * If `timeoutType` is set to 'never', the notification never expires. It stays + * open until closed by the calling API or the user. + * + * @platform linux,win32 + */ + timeoutType: ('default' | 'never'); + /** + * A `string` property representing the title of the notification. + */ + title: string; + /** + * A `string` property representing the custom Toast XML of the notification. + * + * @platform win32 + */ + toastXml: string; + /** + * A `string` property representing the urgency level of the notification. Can be + * 'normal', 'critical', or 'low'. + * + * Default is 'low' - see NotifyUrgency for more information. + * + * @platform linux + */ + urgency: ('normal' | 'critical' | 'low'); + } + + interface NotificationAction { + + // Docs: https://electronjs.org/docs/api/structures/notification-action + + /** + * The label for the given action. + */ + text?: string; + /** + * The type of action, can be `button`. + */ + type: ('button'); + } + + interface NotificationResponse { + + // Docs: https://electronjs.org/docs/api/structures/notification-response + + /** + * The identifier string of the action that the user selected. + */ + actionIdentifier: string; + /** + * The delivery date of the notification. + */ + date: number; + /** + * The unique identifier for this notification request. + */ + identifier: string; + /** + * A dictionary of custom information associated with the notification. + */ + userInfo: Record<string, any>; + /** + * The text entered or chosen by the user. + */ + userText?: string; + } + + interface PaymentDiscount { + + // Docs: https://electronjs.org/docs/api/structures/payment-discount + + /** + * A string used to uniquely identify a discount offer for a product. + */ + identifier: string; + /** + * A string that identifies the key used to generate the signature. + */ + keyIdentifier: string; + /** + * A universally unique ID (UUID) value that you define. + */ + nonce: string; + /** + * A UTF-8 string representing the properties of a specific discount offer, + * cryptographically signed. + */ + signature: string; + /** + * The date and time of the signature's creation in milliseconds, formatted in Unix + * epoch time. + */ + timestamp: number; + } + + interface Point { + + // Docs: https://electronjs.org/docs/api/structures/point + + x: number; + y: number; + } + + interface PostBody { + + // Docs: https://electronjs.org/docs/api/structures/post-body + + /** + * The boundary used to separate multiple parts of the message. Only valid when + * `contentType` is `multipart/form-data`. + */ + boundary?: string; + /** + * The `content-type` header used for the data. One of + * `application/x-www-form-urlencoded` or `multipart/form-data`. Corresponds to the + * `enctype` attribute of the submitted HTML form. + */ + contentType: string; + /** + * The post data to be sent to the new window. + */ + data: Array<(UploadRawData) | (UploadFile)>; + } + + interface PowerMonitor extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/power-monitor + + /** + * Emitted when the system is about to lock the screen. + * + * @platform darwin,win32 + */ + on(event: 'lock-screen', listener: Function): this; + once(event: 'lock-screen', listener: Function): this; + addListener(event: 'lock-screen', listener: Function): this; + removeListener(event: 'lock-screen', listener: Function): this; + /** + * Emitted when the system changes to AC power. + * + * @platform darwin,win32 + */ + on(event: 'on-ac', listener: Function): this; + once(event: 'on-ac', listener: Function): this; + addListener(event: 'on-ac', listener: Function): this; + removeListener(event: 'on-ac', listener: Function): this; + /** + * Emitted when system changes to battery power. + * + * @platform darwin + */ + on(event: 'on-battery', listener: Function): this; + once(event: 'on-battery', listener: Function): this; + addListener(event: 'on-battery', listener: Function): this; + removeListener(event: 'on-battery', listener: Function): this; + /** + * Emitted when system is resuming. + */ + on(event: 'resume', listener: Function): this; + once(event: 'resume', listener: Function): this; + addListener(event: 'resume', listener: Function): this; + removeListener(event: 'resume', listener: Function): this; + /** + * Emitted when the system is about to reboot or shut down. If the event handler + * invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in + * order for the app to exit cleanly. If `e.preventDefault()` is called, the app + * should exit as soon as possible by calling something like `app.quit()`. + * + * @platform linux,darwin + */ + on(event: 'shutdown', listener: Function): this; + once(event: 'shutdown', listener: Function): this; + addListener(event: 'shutdown', listener: Function): this; + removeListener(event: 'shutdown', listener: Function): this; + /** + * Emitted when the system is suspending. + */ + on(event: 'suspend', listener: Function): this; + once(event: 'suspend', listener: Function): this; + addListener(event: 'suspend', listener: Function): this; + removeListener(event: 'suspend', listener: Function): this; + /** + * Emitted as soon as the systems screen is unlocked. + * + * @platform darwin,win32 + */ + on(event: 'unlock-screen', listener: Function): this; + once(event: 'unlock-screen', listener: Function): this; + addListener(event: 'unlock-screen', listener: Function): this; + removeListener(event: 'unlock-screen', listener: Function): this; + /** + * Emitted when a login session is activated. See documentation for more + * information. + * + * @platform darwin + */ + on(event: 'user-did-become-active', listener: Function): this; + once(event: 'user-did-become-active', listener: Function): this; + addListener(event: 'user-did-become-active', listener: Function): this; + removeListener(event: 'user-did-become-active', listener: Function): this; + /** + * Emitted when a login session is deactivated. See documentation for more + * information. + * + * @platform darwin + */ + on(event: 'user-did-resign-active', listener: Function): this; + once(event: 'user-did-resign-active', listener: Function): this; + addListener(event: 'user-did-resign-active', listener: Function): this; + removeListener(event: 'user-did-resign-active', listener: Function): this; + /** + * The system's current state. Can be `active`, `idle`, `locked` or `unknown`. + * + * Calculate the system idle state. `idleThreshold` is the amount of time (in + * seconds) before considered idle. `locked` is available on supported systems + * only. + */ + getSystemIdleState(idleThreshold: number): ('active' | 'idle' | 'locked' | 'unknown'); + /** + * Idle time in seconds + * + * Calculate system idle time in seconds. + */ + getSystemIdleTime(): number; + /** + * Whether the system is on battery power. + * + * To monitor for changes in this property, use the `on-battery` and `on-ac` + * events. + */ + isOnBatteryPower(): boolean; + /** + * A `boolean` property. True if the system is on battery power. + * + * See `powerMonitor.isOnBatteryPower()`. + */ + onBatteryPower: boolean; + } + + interface PowerSaveBlocker { + + // Docs: https://electronjs.org/docs/api/power-save-blocker + + /** + * Whether the corresponding `powerSaveBlocker` has started. + */ + isStarted(id: number): boolean; + /** + * The blocker ID that is assigned to this power blocker. + * + * Starts preventing the system from entering lower-power mode. Returns an integer + * identifying the power save blocker. + * + * **Note:** `prevent-display-sleep` has higher precedence over + * `prevent-app-suspension`. Only the highest precedence type takes effect. In + * other words, `prevent-display-sleep` always takes precedence over + * `prevent-app-suspension`. + * + * For example, an API calling A requests for `prevent-app-suspension`, and another + * calling B requests for `prevent-display-sleep`. `prevent-display-sleep` will be + * used until B stops its request. After that, `prevent-app-suspension` is used. + */ + start(type: 'prevent-app-suspension' | 'prevent-display-sleep'): number; + /** + * Stops the specified power save blocker. + */ + stop(id: number): void; + } + + interface PrinterInfo { + + // Docs: https://electronjs.org/docs/api/structures/printer-info + + /** + * a longer description of the printer's type. + */ + description: string; + /** + * the name of the printer as shown in Print Preview. + */ + displayName: string; + /** + * whether or not a given printer is set as the default printer on the OS. + */ + isDefault: boolean; + /** + * the name of the printer as understood by the OS. + */ + name: string; + /** + * an object containing a variable number of platform-specific printer information. + */ + options: Options; + /** + * the current status of the printer. + */ + status: number; + } + + interface ProcessMemoryInfo { + + // Docs: https://electronjs.org/docs/api/structures/process-memory-info + + /** + * The amount of memory not shared by other processes, such as JS heap or HTML + * content in Kilobytes. + */ + private: number; + /** + * The amount of memory currently pinned to actual physical RAM in Kilobytes. + * + * @platform linux,win32 + */ + residentSet: number; + /** + * The amount of memory shared between processes, typically memory consumed by the + * Electron code itself in Kilobytes. + */ + shared: number; + } + + interface ProcessMetric { + + // Docs: https://electronjs.org/docs/api/structures/process-metric + + /** + * CPU usage of the process. + */ + cpu: CPUUsage; + /** + * Creation time for this process. The time is represented as number of + * milliseconds since epoch. Since the `pid` can be reused after a process dies, it + * is useful to use both the `pid` and the `creationTime` to uniquely identify a + * process. + */ + creationTime: number; + /** + * One of the following values: + * + * @platform win32 + */ + integrityLevel?: ('untrusted' | 'low' | 'medium' | 'high' | 'unknown'); + /** + * Memory information for the process. + */ + memory: MemoryInfo; + /** + * The name of the process. Examples for utility: `Audio Service`, `Content + * Decryption Module Service`, `Network Service`, `Video Capture`, etc. + */ + name?: string; + /** + * Process id of the process. + */ + pid: number; + /** + * Whether the process is sandboxed on OS level. + * + * @platform darwin,win32 + */ + sandboxed?: boolean; + /** + * The non-localized name of the process. + */ + serviceName?: string; + /** + * Process type. One of the following values: + */ + type: ('Browser' | 'Tab' | 'Utility' | 'Zygote' | 'Sandbox helper' | 'GPU' | 'Pepper Plugin' | 'Pepper Plugin Broker' | 'Unknown'); + } + + interface Product { + + // Docs: https://electronjs.org/docs/api/structures/product + + /** + * The total size of the content, in bytes. + */ + contentLengths: number[]; + /** + * A string that identifies the version of the content. + */ + contentVersion: string; + /** + * 3 character code presenting a product's currency based on the ISO 4217 standard. + */ + currencyCode: string; + /** + * An array of discount offers + */ + discounts: ProductDiscount[]; + /** + * The total size of the content, in bytes. + */ + downloadContentLengths: number[]; + /** + * A string that identifies the version of the content. + */ + downloadContentVersion: string; + /** + * The locale formatted price of the product. + */ + formattedPrice: string; + /** + * The object containing introductory price information for the product. available + * for the product. + */ + introductoryPrice?: ProductDiscount; + /** + * A boolean value that indicates whether the App Store has downloadable content + * for this product. `true` if at least one file has been associated with the + * product. + */ + isDownloadable: boolean; + /** + * A description of the product. + */ + localizedDescription: string; + /** + * The name of the product. + */ + localizedTitle: string; + /** + * The cost of the product in the local currency. + */ + price: number; + /** + * The string that identifies the product to the Apple App Store. + */ + productIdentifier: string; + /** + * The identifier of the subscription group to which the subscription belongs. + */ + subscriptionGroupIdentifier: string; + /** + * The period details for products that are subscriptions. + */ + subscriptionPeriod?: ProductSubscriptionPeriod; + } + + interface ProductDiscount { + + // Docs: https://electronjs.org/docs/api/structures/product-discount + + /** + * A string used to uniquely identify a discount offer for a product. + */ + identifier: string; + /** + * An integer that indicates the number of periods the product discount is + * available. + */ + numberOfPeriods: number; + /** + * The payment mode for this product discount. Can be `payAsYouGo`, `payUpFront`, + * or `freeTrial`. + */ + paymentMode: ('payAsYouGo' | 'payUpFront' | 'freeTrial'); + /** + * The discount price of the product in the local currency. + */ + price: number; + /** + * The locale used to format the discount price of the product. + */ + priceLocale: string; + /** + * An object that defines the period for the product discount. + */ + subscriptionPeriod?: ProductSubscriptionPeriod; + /** + * The type of discount offer. + */ + type: number; + } + + interface ProductSubscriptionPeriod { + + // Docs: https://electronjs.org/docs/api/structures/product-subscription-period + + /** + * The number of units per subscription period. + */ + numberOfUnits: number; + /** + * The increment of time that a subscription period is specified in. Can be `day`, + * `week`, `month`, `year`. + */ + unit: ('day' | 'week' | 'month' | 'year'); + } + + interface Protocol { + + // Docs: https://electronjs.org/docs/api/protocol + + /** + * Whether the protocol was successfully intercepted + * + * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler + * which sends a `Buffer` as a response. + */ + interceptBufferProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (Buffer) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether the protocol was successfully intercepted + * + * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler + * which sends a file as a response. + */ + interceptFileProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether the protocol was successfully intercepted + * + * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler + * which sends a new HTTP request as a response. + */ + interceptHttpProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: ProtocolResponse) => void) => void): boolean; + /** + * Whether the protocol was successfully intercepted + * + * Same as `protocol.registerStreamProtocol`, except that it replaces an existing + * protocol handler. + */ + interceptStreamProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (NodeJS.ReadableStream) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether the protocol was successfully intercepted + * + * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler + * which sends a `string` as a response. + */ + interceptStringProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether `scheme` is already intercepted. + */ + isProtocolIntercepted(scheme: string): boolean; + /** + * Whether `scheme` is already registered. + */ + isProtocolRegistered(scheme: string): boolean; + /** + * Whether the protocol was successfully registered + * + * Registers a protocol of `scheme` that will send a `Buffer` as a response. + * + * The usage is the same with `registerFileProtocol`, except that the `callback` + * should be called with either a `Buffer` object or an object that has the `data` + * property. + * + * Example: + */ + registerBufferProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (Buffer) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether the protocol was successfully registered + * + * Registers a protocol of `scheme` that will send a file as the response. The + * `handler` will be called with `request` and `callback` where `request` is an + * incoming request for the `scheme`. + * + * To handle the `request`, the `callback` should be called with either the file's + * path or an object that has a `path` property, e.g. `callback(filePath)` or + * `callback({ path: filePath })`. The `filePath` must be an absolute path. + * + * By default the `scheme` is treated like `http:`, which is parsed differently + * from protocols that follow the "generic URI syntax" like `file:`. + */ + registerFileProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether the protocol was successfully registered + * + * Registers a protocol of `scheme` that will send an HTTP request as a response. + * + * The usage is the same with `registerFileProtocol`, except that the `callback` + * should be called with an object that has the `url` property. + */ + registerHttpProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: ProtocolResponse) => void) => void): boolean; + /** + * **Note:** This method can only be used before the `ready` event of the `app` + * module gets emitted and can be called only once. + * + * Registers the `scheme` as standard, secure, bypasses content security policy for + * resources, allows registering ServiceWorker, supports fetch API, and streaming + * video/audio. Specify a privilege with the value of `true` to enable the + * capability. + * + * An example of registering a privileged scheme, that bypasses Content Security + * Policy: + * + * A standard scheme adheres to what RFC 3986 calls generic URI syntax. For example + * `http` and `https` are standard schemes, while `file` is not. + * + * Registering a scheme as standard allows relative and absolute resources to be + * resolved correctly when served. Otherwise the scheme will behave like the `file` + * protocol, but without the ability to resolve relative URLs. + * + * For example when you load following page with custom protocol without + * registering it as standard scheme, the image will not be loaded because + * non-standard schemes can not recognize relative URLs: + * + * Registering a scheme as standard will allow access to files through the + * FileSystem API. Otherwise the renderer will throw a security error for the + * scheme. + * + * By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, + * cookies) are disabled for non standard schemes. So in general if you want to + * register a custom protocol to replace the `http` protocol, you have to register + * it as a standard scheme. + * + * Protocols that use streams (http and stream protocols) should set `stream: + * true`. The `<video>` and `<audio>` HTML elements expect protocols to buffer + * their responses by default. The `stream` flag configures those elements to + * correctly expect streaming responses. + */ + registerSchemesAsPrivileged(customSchemes: CustomScheme[]): void; + /** + * Whether the protocol was successfully registered + * + * Registers a protocol of `scheme` that will send a stream as a response. + * + * The usage is the same with `registerFileProtocol`, except that the `callback` + * should be called with either a `ReadableStream` object or an object that has the + * `data` property. + * + * Example: + * + * It is possible to pass any object that implements the readable stream API (emits + * `data`/`end`/`error` events). For example, here's how a file could be returned: + */ + registerStreamProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (NodeJS.ReadableStream) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether the protocol was successfully registered + * + * Registers a protocol of `scheme` that will send a `string` as a response. + * + * The usage is the same with `registerFileProtocol`, except that the `callback` + * should be called with either a `string` or an object that has the `data` + * property. + */ + registerStringProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; + /** + * Whether the protocol was successfully unintercepted + * + * Remove the interceptor installed for `scheme` and restore its original handler. + */ + uninterceptProtocol(scheme: string): boolean; + /** + * Whether the protocol was successfully unregistered + * + * Unregisters the custom protocol of `scheme`. + */ + unregisterProtocol(scheme: string): boolean; + } + + interface ProtocolRequest { + + // Docs: https://electronjs.org/docs/api/structures/protocol-request + + headers: Record<string, string>; + method: string; + referrer: string; + uploadData?: UploadData[]; + url: string; + } + + interface ProtocolResponse { + + // Docs: https://electronjs.org/docs/api/structures/protocol-response + + /** + * The charset of response body, default is `"utf-8"`. + */ + charset?: string; + /** + * The response body. When returning stream as response, this is a Node.js readable + * stream representing the response body. When returning `Buffer` as response, this + * is a `Buffer`. When returning `string` as response, this is a `string`. This is + * ignored for other types of responses. + */ + data?: (Buffer) | (string) | (NodeJS.ReadableStream); + /** + * When assigned, the `request` will fail with the `error` number . For the + * available error numbers you can use, please see the net error list. + */ + error?: number; + /** + * An object containing the response headers. The keys must be string, and values + * must be either string or Array of string. + */ + headers?: Record<string, (string) | (string[])>; + /** + * The HTTP `method`. This is only used for file and URL responses. + */ + method?: string; + /** + * The MIME type of response body, default is `"text/html"`. Setting `mimeType` + * would implicitly set the `content-type` header in response, but if + * `content-type` is already set in `headers`, the `mimeType` would be ignored. + */ + mimeType?: string; + /** + * Path to the file which would be sent as response body. This is only used for + * file responses. + */ + path?: string; + /** + * The `referrer` URL. This is only used for file and URL responses. + */ + referrer?: string; + /** + * The session used for requesting URL, by default the HTTP request will reuse the + * current session. Setting `session` to `null` would use a random independent + * session. This is only used for URL responses. + */ + session?: Session; + /** + * The HTTP response code, default is 200. + */ + statusCode?: number; + /** + * The data used as upload data. This is only used for URL responses when `method` + * is `"POST"`. + */ + uploadData?: ProtocolResponseUploadData; + /** + * Download the `url` and pipe the result as response body. This is only used for + * URL responses. + */ + url?: string; + } + + interface ProtocolResponseUploadData { + + // Docs: https://electronjs.org/docs/api/structures/protocol-response-upload-data + + /** + * MIME type of the content. + */ + contentType: string; + /** + * Content to be sent. + */ + data: (string) | (Buffer); + } + + interface PushNotifications extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/push-notifications + + /** + * Emitted when the app receives a remote notification while running. See: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * com/documentation/appkit/nsapplicationdelegate/1428430-application?language=objc + * + * @platform darwin + */ + on(event: 'received-apns-notification', listener: (userInfo: Record<string, any>) => void): this; + once(event: 'received-apns-notification', listener: (userInfo: Record<string, any>) => void): this; + addListener(event: 'received-apns-notification', listener: (userInfo: Record<string, any>) => void): this; + removeListener(event: 'received-apns-notification', listener: (userInfo: Record<string, any>) => void): this; + /** + * Registers the app with Apple Push Notification service (APNS) to receive Badge, + * Sound, and Alert 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: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * tion/appkit/nsapplication/1428476-registerforremotenotificationtyp?language=objc + * + * @platform darwin + */ + registerForAPNSNotifications(): Promise<string>; + /** + * Unregisters the app from notifications received from APNS. See: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * tion/appkit/nsapplication/1428747-unregisterforremotenotifications?language=objc + * + * @platform darwin + */ + unregisterForAPNSNotifications(): void; + } + + interface Rectangle { + + // Docs: https://electronjs.org/docs/api/structures/rectangle + + /** + * The height of the rectangle (must be an integer). + */ + height: number; + /** + * The width of the rectangle (must be an integer). + */ + width: number; + /** + * The x coordinate of the origin of the rectangle (must be an integer). + */ + x: number; + /** + * The y coordinate of the origin of the rectangle (must be an integer). + */ + y: number; + } + + interface Referrer { + + // Docs: https://electronjs.org/docs/api/structures/referrer + + /** + * Can be `default`, `unsafe-url`, `no-referrer-when-downgrade`, `no-referrer`, + * `origin`, `strict-origin-when-cross-origin`, `same-origin` or `strict-origin`. + * See the Referrer-Policy spec for more details on the meaning of these values. + */ + policy: ('default' | 'unsafe-url' | 'no-referrer-when-downgrade' | 'no-referrer' | 'origin' | 'strict-origin-when-cross-origin' | 'same-origin' | 'strict-origin'); + /** + * HTTP Referrer URL. + */ + url: string; + } + + interface SafeStorage extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/safe-storage + + /** + * the decrypted string. Decrypts the encrypted buffer obtained with + * `safeStorage.encryptString` back into a string. + * + * This function will throw an error if decryption fails. + */ + decryptString(encrypted: Buffer): string; + /** + * An array of bytes representing the encrypted string. + * + * This function will throw an error if encryption fails. + */ + encryptString(plainText: string): Buffer; + /** + * Whether encryption is available. + * + * On Linux, returns true if the app has emitted the `ready` event and the secret + * key is available. On MacOS, returns true if Keychain is available. On Windows, + * returns true once the app has emitted the `ready` event. + */ + isEncryptionAvailable(): boolean; + } + + interface Screen extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/screen + + /** + * Emitted when `newDisplay` has been added. + */ + on(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + once(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + addListener(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + removeListener(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + /** + * Emitted when one or more metrics change in a `display`. The `changedMetrics` is + * an array of strings that describe the changes. Possible changes are `bounds`, + * `workArea`, `scaleFactor` and `rotation`. + */ + on(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + once(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + addListener(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + removeListener(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + /** + * Emitted when `oldDisplay` has been removed. + */ + on(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + once(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + addListener(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + removeListener(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + /** + * Converts a screen DIP point to a screen physical point. The DPI scale is + * performed relative to the display containing the DIP point. + * + * @platform win32 + */ + dipToScreenPoint(point: Point): Point; + /** + * Converts a screen DIP rect to a screen physical rect. The DPI scale is performed + * relative to the display nearest to `window`. If `window` is null, scaling will + * be performed to the display nearest to `rect`. + * + * @platform win32 + */ + dipToScreenRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; + /** + * An array of displays that are currently available. + */ + getAllDisplays(): Display[]; + /** + * The current absolute position of the mouse pointer. + * + * **Note:** The return value is a DIP point, not a screen physical point. + */ + getCursorScreenPoint(): Point; + /** + * The display that most closely intersects the provided bounds. + */ + getDisplayMatching(rect: Rectangle): Display; + /** + * The display nearest the specified point. + */ + getDisplayNearestPoint(point: Point): Display; + /** + * The primary display. + */ + getPrimaryDisplay(): Display; + /** + * Converts a screen physical point to a screen DIP point. The DPI scale is + * performed relative to the display containing the physical point. + * + * @platform win32 + */ + screenToDipPoint(point: Point): Point; + /** + * Converts a screen physical rect to a screen DIP rect. The DPI scale is performed + * relative to the display nearest to `window`. If `window` is null, scaling will + * be performed to the display nearest to `rect`. + * + * @platform win32 + */ + screenToDipRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; + } + + interface ScrubberItem { + + // Docs: https://electronjs.org/docs/api/structures/scrubber-item + + /** + * The image to appear in this item. + */ + icon?: NativeImage; + /** + * The text to appear in this item. + */ + label?: string; + } + + interface SegmentedControlSegment { + + // Docs: https://electronjs.org/docs/api/structures/segmented-control-segment + + /** + * Whether this segment is selectable. Default: true. + */ + enabled?: boolean; + /** + * The image to appear in this segment. + */ + icon?: NativeImage; + /** + * The text to appear in this segment. + */ + label?: string; + } + + interface SerialPort { + + // Docs: https://electronjs.org/docs/api/structures/serial-port + + /** + * A stable identifier on Windows that can be used for device permissions. + */ + deviceInstanceId?: string; + /** + * A string suitable for display to the user for describing this device. + */ + displayName: string; + /** + * Unique identifier for the port. + */ + portId: string; + /** + * Name of the port. + */ + portName: string; + /** + * Optional USB product ID. + */ + productId: string; + /** + * The USB device serial number. + */ + serialNumber: string; + /** + * Represents a single serial port on macOS can be enumerated by multiple drivers. + */ + usbDriverName?: string; + /** + * Optional USB vendor ID. + */ + vendorId: string; + } + + interface ServiceWorkerInfo { + + // Docs: https://electronjs.org/docs/api/structures/service-worker-info + + /** + * The virtual ID of the process that this service worker is running in. This is + * not an OS level PID. This aligns with the ID set used for + * `webContents.getProcessId()`. + */ + renderProcessId: number; + /** + * The base URL that this service worker is active for. + */ + scope: string; + /** + * The full URL to the script that this service worker runs + */ + scriptUrl: string; + } + + class ServiceWorkers extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/service-workers + + /** + * Emitted when a service worker logs something to the console. + */ + on(event: 'console-message', listener: (event: Event, + /** + * Information about the console message + */ + messageDetails: MessageDetails) => void): this; + once(event: 'console-message', listener: (event: Event, + /** + * Information about the console message + */ + messageDetails: MessageDetails) => void): this; + addListener(event: 'console-message', listener: (event: Event, + /** + * Information about the console message + */ + messageDetails: MessageDetails) => void): this; + removeListener(event: 'console-message', listener: (event: Event, + /** + * Information about the console message + */ + messageDetails: MessageDetails) => void): this; + /** + * Emitted when a service worker has been registered. Can occur after a call to + * `navigator.serviceWorker.register('/sw.js')` successfully resolves or when a + * Chrome extension is loaded. + */ + on(event: 'registration-completed', listener: (event: Event, + /** + * Information about the registered service worker + */ + details: RegistrationCompletedDetails) => void): this; + once(event: 'registration-completed', listener: (event: Event, + /** + * Information about the registered service worker + */ + details: RegistrationCompletedDetails) => void): this; + addListener(event: 'registration-completed', listener: (event: Event, + /** + * Information about the registered service worker + */ + details: RegistrationCompletedDetails) => void): this; + removeListener(event: 'registration-completed', listener: (event: Event, + /** + * Information about the registered service worker + */ + details: RegistrationCompletedDetails) => void): this; + /** + * A ServiceWorkerInfo object where the keys are the service worker version ID and + * the values are the information about that service worker. + */ + getAllRunning(): Record<number, ServiceWorkerInfo>; + /** + * Information about this service worker + * + * If the service worker does not exist or is not running this method will throw an + * exception. + */ + getFromVersionID(versionId: number): ServiceWorkerInfo; + } + + class Session extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/session + + /** + * A session instance from `partition` string. When there is an existing `Session` + * with the same `partition`, it will be returned; otherwise a new `Session` + * instance will be created with `options`. + * + * If `partition` starts with `persist:`, the page will use a persistent session + * available to all pages in the app with the same `partition`. if there is no + * `persist:` prefix, the page will use an in-memory session. If the `partition` is + * empty then default session of the app will be returned. + * + * To create a `Session` with `options`, you have to ensure the `Session` with the + * `partition` has never been used before. There is no way to change the `options` + * of an existing `Session` object. + */ + static fromPartition(partition: string, options?: FromPartitionOptions): Session; + /** + * A `Session` object, the default session object of the app. + */ + static defaultSession: Session; + /** + * Emitted after an extension is loaded. This occurs whenever an extension is added + * to the "enabled" set of extensions. This includes: + * + * * Extensions being loaded from `Session.loadExtension`. + * * Extensions being reloaded: + * * from a crash. + * * if the extension requested it (`chrome.runtime.reload()`). + */ + on(event: 'extension-loaded', listener: (event: Event, + extension: Extension) => void): this; + once(event: 'extension-loaded', listener: (event: Event, + extension: Extension) => void): this; + addListener(event: 'extension-loaded', listener: (event: Event, + extension: Extension) => void): this; + removeListener(event: 'extension-loaded', listener: (event: Event, + extension: Extension) => void): this; + /** + * Emitted after an extension is loaded and all necessary browser state is + * initialized to support the start of the extension's background page. + */ + on(event: 'extension-ready', listener: (event: Event, + extension: Extension) => void): this; + once(event: 'extension-ready', listener: (event: Event, + extension: Extension) => void): this; + addListener(event: 'extension-ready', listener: (event: Event, + extension: Extension) => void): this; + removeListener(event: 'extension-ready', listener: (event: Event, + extension: Extension) => void): this; + /** + * Emitted after an extension is unloaded. This occurs when + * `Session.removeExtension` is called. + */ + on(event: 'extension-unloaded', listener: (event: Event, + extension: Extension) => void): this; + once(event: 'extension-unloaded', listener: (event: Event, + extension: Extension) => void): this; + addListener(event: 'extension-unloaded', listener: (event: Event, + extension: Extension) => void): this; + removeListener(event: 'extension-unloaded', listener: (event: Event, + extension: Extension) => void): this; + /** + * Emitted after `navigator.hid.requestDevice` has been called and + * `select-hid-device` has fired if a new device becomes available before the + * callback from `select-hid-device` is called. This event is intended for use + * when using a UI to ask users to pick a device so that the UI can be updated with + * the newly added device. + */ + on(event: 'hid-device-added', listener: (event: Event, + details: HidDeviceAddedDetails) => void): this; + once(event: 'hid-device-added', listener: (event: Event, + details: HidDeviceAddedDetails) => void): this; + addListener(event: 'hid-device-added', listener: (event: Event, + details: HidDeviceAddedDetails) => void): this; + removeListener(event: 'hid-device-added', listener: (event: Event, + details: HidDeviceAddedDetails) => void): this; + /** + * Emitted after `navigator.hid.requestDevice` has been called and + * `select-hid-device` has fired if a device has been removed before the callback + * from `select-hid-device` is called. This event is intended for use when using a + * UI to ask users to pick a device so that the UI can be updated to remove the + * specified device. + */ + on(event: 'hid-device-removed', listener: (event: Event, + details: HidDeviceRemovedDetails) => void): this; + once(event: 'hid-device-removed', listener: (event: Event, + details: HidDeviceRemovedDetails) => void): this; + addListener(event: 'hid-device-removed', listener: (event: Event, + details: HidDeviceRemovedDetails) => void): this; + removeListener(event: 'hid-device-removed', listener: (event: Event, + details: HidDeviceRemovedDetails) => void): this; + /** + * Emitted after `HIDDevice.forget()` has been called. This event can be used to + * help maintain persistent storage of permissions when + * `setDevicePermissionHandler` is used. + */ + on(event: 'hid-device-revoked', listener: (event: Event, + details: HidDeviceRevokedDetails) => void): this; + once(event: 'hid-device-revoked', listener: (event: Event, + details: HidDeviceRevokedDetails) => void): this; + addListener(event: 'hid-device-revoked', listener: (event: Event, + details: HidDeviceRevokedDetails) => void): this; + removeListener(event: 'hid-device-revoked', listener: (event: Event, + details: HidDeviceRevokedDetails) => void): this; + /** + * Emitted when a render process requests preconnection to a URL, generally due to + * a resource hint. + */ + on(event: 'preconnect', listener: (event: Event, + /** + * The URL being requested for preconnection by the renderer. + */ + preconnectUrl: string, + /** + * True if the renderer is requesting that the connection include credentials (see + * the spec for more details.) + */ + allowCredentials: boolean) => void): this; + once(event: 'preconnect', listener: (event: Event, + /** + * The URL being requested for preconnection by the renderer. + */ + preconnectUrl: string, + /** + * True if the renderer is requesting that the connection include credentials (see + * the spec for more details.) + */ + allowCredentials: boolean) => void): this; + addListener(event: 'preconnect', listener: (event: Event, + /** + * The URL being requested for preconnection by the renderer. + */ + preconnectUrl: string, + /** + * True if the renderer is requesting that the connection include credentials (see + * the spec for more details.) + */ + allowCredentials: boolean) => void): this; + removeListener(event: 'preconnect', listener: (event: Event, + /** + * The URL being requested for preconnection by the renderer. + */ + preconnectUrl: string, + /** + * True if the renderer is requesting that the connection include credentials (see + * the spec for more details.) + */ + allowCredentials: boolean) => void): this; + /** + * Emitted when a HID device needs to be selected when a call to + * `navigator.hid.requestDevice` is made. `callback` should be called with + * `deviceId` to be selected; passing no arguments to `callback` will cancel the + * request. Additionally, permissioning on `navigator.hid` can be further managed + * by using ses.setPermissionCheckHandler(handler) and + * ses.setDevicePermissionHandler(handler)`. + */ + on(event: 'select-hid-device', listener: (event: Event, + details: SelectHidDeviceDetails, + callback: (deviceId?: (string) | (null)) => void) => void): this; + once(event: 'select-hid-device', listener: (event: Event, + details: SelectHidDeviceDetails, + callback: (deviceId?: (string) | (null)) => void) => void): this; + addListener(event: 'select-hid-device', listener: (event: Event, + details: SelectHidDeviceDetails, + callback: (deviceId?: (string) | (null)) => void) => void): this; + removeListener(event: 'select-hid-device', listener: (event: Event, + details: SelectHidDeviceDetails, + callback: (deviceId?: (string) | (null)) => void) => void): this; + /** + * Emitted when a serial port needs to be selected when a call to + * `navigator.serial.requestPort` is made. `callback` should be called with + * `portId` to be selected, passing an empty string to `callback` will cancel the + * request. Additionally, permissioning on `navigator.serial` can be managed by + * using ses.setPermissionCheckHandler(handler) with the `serial` permission. + */ + on(event: 'select-serial-port', listener: (event: Event, + portList: SerialPort[], + webContents: WebContents, + callback: (portId: string) => void) => void): this; + once(event: 'select-serial-port', listener: (event: Event, + portList: SerialPort[], + webContents: WebContents, + callback: (portId: string) => void) => void): this; + addListener(event: 'select-serial-port', listener: (event: Event, + portList: SerialPort[], + webContents: WebContents, + callback: (portId: string) => void) => void): this; + removeListener(event: 'select-serial-port', listener: (event: Event, + portList: SerialPort[], + webContents: WebContents, + callback: (portId: string) => void) => void): this; + /** + * Emitted after `navigator.serial.requestPort` has been called and + * `select-serial-port` has fired if a new serial port becomes available before the + * callback from `select-serial-port` is called. This event is intended for use + * when using a UI to ask users to pick a port so that the UI can be updated with + * the newly added port. + */ + on(event: 'serial-port-added', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + once(event: 'serial-port-added', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + addListener(event: 'serial-port-added', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + removeListener(event: 'serial-port-added', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + /** + * Emitted after `navigator.serial.requestPort` has been called and + * `select-serial-port` has fired if a serial port has been removed before the + * callback from `select-serial-port` is called. This event is intended for use + * when using a UI to ask users to pick a port so that the UI can be updated to + * remove the specified port. + */ + on(event: 'serial-port-removed', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + once(event: 'serial-port-removed', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + addListener(event: 'serial-port-removed', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + removeListener(event: 'serial-port-removed', listener: (event: Event, + port: SerialPort, + webContents: WebContents) => void): this; + /** + * Emitted when a hunspell dictionary file starts downloading + */ + on(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + once(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + addListener(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + removeListener(event: 'spellcheck-dictionary-download-begin', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + /** + * Emitted when a hunspell dictionary file download fails. For details on the + * failure you should collect a netlog and inspect the download request. + */ + on(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + once(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + addListener(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + removeListener(event: 'spellcheck-dictionary-download-failure', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + /** + * Emitted when a hunspell dictionary file has been successfully downloaded + */ + on(event: 'spellcheck-dictionary-download-success', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + once(event: 'spellcheck-dictionary-download-success', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + addListener(event: 'spellcheck-dictionary-download-success', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + removeListener(event: 'spellcheck-dictionary-download-success', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + /** + * Emitted when a hunspell dictionary file has been successfully initialized. This + * occurs after the file has been downloaded. + */ + on(event: 'spellcheck-dictionary-initialized', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + once(event: 'spellcheck-dictionary-initialized', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + addListener(event: 'spellcheck-dictionary-initialized', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + removeListener(event: 'spellcheck-dictionary-initialized', listener: (event: Event, + /** + * The language code of the dictionary file + */ + languageCode: string) => void): this; + /** + * Emitted when Electron is about to download `item` in `webContents`. + * + * Calling `event.preventDefault()` will cancel the download and `item` will not be + * available from next tick of the process. + */ + on(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + once(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + addListener(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + removeListener(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + /** + * Whether the word was successfully written to the custom dictionary. This API + * will not work on non-persistent (in-memory) sessions. + * + * **Note:** On macOS and Windows 10 this word will be written to the OS custom + * dictionary as well + */ + addWordToSpellCheckerDictionary(word: string): boolean; + /** + * Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate + * authentication. + */ + allowNTLMCredentialsForDomains(domains: string): void; + /** + * resolves when the session’s HTTP authentication cache has been cleared. + */ + clearAuthCache(): Promise<void>; + /** + * resolves when the cache clear operation is complete. + * + * Clears the session’s HTTP cache. + */ + clearCache(): Promise<void>; + /** + * resolves when the code cache clear operation is complete. + */ + clearCodeCaches(options: ClearCodeCachesOptions): Promise<void>; + /** + * Resolves when the operation is complete. + * + * Clears the host resolver cache. + */ + clearHostResolverCache(): Promise<void>; + /** + * resolves when the storage data has been cleared. + */ + clearStorageData(options?: ClearStorageDataOptions): Promise<void>; + /** + * Resolves when all connections are closed. + * + * **Note:** It will terminate / fail all requests currently in flight. + */ + closeAllConnections(): Promise<void>; + /** + * Allows resuming `cancelled` or `interrupted` downloads from previous `Session`. + * The API will generate a DownloadItem that can be accessed with the will-download + * event. The DownloadItem will not have any `WebContents` associated with it and + * the initial state will be `interrupted`. The download will start only when the + * `resume` API is called on the DownloadItem. + */ + createInterruptedDownload(options: CreateInterruptedDownloadOptions): void; + /** + * Disables any network emulation already active for the `session`. Resets to the + * original network configuration. + */ + disableNetworkEmulation(): void; + /** + * Initiates a download of the resource at `url`. The API will generate a + * DownloadItem that can be accessed with the will-download event. + * + * **Note:** This does not perform any security checks that relate to a page's + * origin, unlike `webContents.downloadURL`. + */ + downloadURL(url: string): void; + /** + * Emulates network with the given configuration for the `session`. + */ + enableNetworkEmulation(options: EnableNetworkEmulationOptions): void; + /** + * Writes any unwritten DOMStorage data to disk. + */ + flushStorageData(): void; + /** + * Resolves when the all internal states of proxy service is reset and the latest + * proxy configuration is reapplied if it's already available. The pac script will + * be fetched from `pacScript` again if the proxy mode is `pac_script`. + */ + forceReloadProxyConfig(): Promise<void>; + /** + * A list of all loaded extensions. + * + * **Note:** This API cannot be called before the `ready` event of the `app` module + * is emitted. + */ + getAllExtensions(): Extension[]; + /** + * resolves with blob data. + */ + getBlobData(identifier: string): Promise<Buffer>; + /** + * the session's current cache size, in bytes. + */ + getCacheSize(): Promise<number>; + /** + * | `null` - The loaded extension with the given ID. + * + * **Note:** This API cannot be called before the `ready` event of the `app` module + * is emitted. + */ + getExtension(extensionId: string): Extension; + /** + * an array of paths to preload scripts that have been registered. + */ + getPreloads(): string[]; + /** + * An array of language codes the spellchecker is enabled for. If this list is + * empty the spellchecker will fallback to using `en-US`. By default on launch if + * this setting is an empty list Electron will try to populate this setting with + * the current OS locale. This setting is persisted across restarts. + * + * **Note:** On macOS the OS spellchecker is used and has its own list of + * languages. On macOS, this API will return whichever languages have been + * configured by the OS. + */ + getSpellCheckerLanguages(): string[]; + /** + * The absolute file system path where data for this session is persisted on disk. + * For in memory sessions this returns `null`. + */ + getStoragePath(): (string) | (null); + /** + * The user agent for this session. + */ + getUserAgent(): string; + /** + * Whether or not this session is a persistent one. The default `webContents` + * session of a `BrowserWindow` is persistent. When creating a session from a + * partition, session prefixed with `persist:` will be persistent, while others + * will be temporary. + */ + isPersistent(): boolean; + /** + * Whether the builtin spell checker is enabled. + */ + isSpellCheckerEnabled(): boolean; + /** + * An array of all words in app's custom dictionary. Resolves when the full + * dictionary is loaded from disk. + */ + listWordsInSpellCheckerDictionary(): Promise<string[]>; + /** + * resolves when the extension is loaded. + * + * This method will raise an exception if the extension could not be loaded. If + * there are warnings when installing the extension (e.g. if the extension requests + * an API that Electron does not support) then they will be logged to the console. + * + * Note that Electron does not support the full range of Chrome extensions APIs. + * See Supported Extensions APIs for more details on what is supported. + * + * Note that in previous versions of Electron, extensions that were loaded would be + * remembered for future runs of the application. This is no longer the case: + * `loadExtension` must be called on every boot of your app if you want the + * extension to be loaded. + * + * This API does not support loading packed (.crx) extensions. + * + * **Note:** This API cannot be called before the `ready` event of the `app` module + * is emitted. + * + * **Note:** Loading extensions into in-memory (non-persistent) sessions is not + * supported and will throw an error. + */ + loadExtension(path: string, options?: LoadExtensionOptions): Promise<Electron.Extension>; + /** + * Preconnects the given number of sockets to an origin. + */ + preconnect(options: PreconnectOptions): void; + /** + * Unloads an extension. + * + * **Note:** This API cannot be called before the `ready` event of the `app` module + * is emitted. + */ + removeExtension(extensionId: string): void; + /** + * Whether the word was successfully removed from the custom dictionary. This API + * will not work on non-persistent (in-memory) sessions. + * + * **Note:** On macOS and Windows 10 this word will be removed from the OS custom + * dictionary as well + */ + removeWordFromSpellCheckerDictionary(word: string): boolean; + /** + * Resolves with the proxy information for `url`. + */ + resolveProxy(url: string): Promise<string>; + /** + * Sets a handler to respond to Bluetooth pairing requests. This handler allows + * developers to handle devices that require additional validation before pairing. + * When a handler is not defined, any pairing on Linux or Windows that requires + * additional validation will be automatically cancelled. macOS does not require a + * handler because macOS handles the pairing automatically. To clear the handler, + * call `setBluetoothPairingHandler(null)`. + * + * @platform win32,linux + */ + setBluetoothPairingHandler(handler: ((details: BluetoothPairingHandlerHandlerDetails, callback: (response: Response) => void) => void) | (null)): void; + /** + * Sets the certificate verify proc for `session`, the `proc` will be called with + * `proc(request, callback)` whenever a server certificate verification is + * requested. Calling `callback(0)` accepts the certificate, calling `callback(-2)` + * rejects it. + * + * Calling `setCertificateVerifyProc(null)` will revert back to default certificate + * verify proc. + * + * > **NOTE:** The result of this procedure is cached by the network service. + */ + setCertificateVerifyProc(proc: ((request: Request, callback: (verificationResult: number) => void) => void) | (null)): void; + /** + * Sets the directory to store the generated JS code cache for this session. The + * directory is not required to be created by the user before this call, the + * runtime will create if it does not exist otherwise will use the existing + * directory. If directory cannot be created, then code cache will not be used and + * all operations related to code cache will fail silently inside the runtime. By + * default, the directory will be `Code Cache` under the respective user data + * folder. + */ + setCodeCachePath(path: string): void; + /** + * 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. 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 permissions (eg when + * handling the `select-hid-device` event) and then read from that storage with + * `setDevicePermissionHandler`. + */ + setDevicePermissionHandler(handler: ((details: DevicePermissionHandlerHandlerDetails) => boolean) | (null)): void; + /** + * Sets download saving directory. By default, the download directory will be the + * `Downloads` under the respective app folder. + */ + setDownloadPath(path: string): void; + /** + * Sets the handler which can be used to respond to permission checks for the + * `session`. Returning `true` will allow the permission and `false` will reject + * it. Please note that you must also implement `setPermissionRequestHandler` to + * get complete permission handling. Most web APIs do a permission check and then + * make a permission request if the check is denied. To clear the handler, call + * `setPermissionCheckHandler(null)`. + */ + setPermissionCheckHandler(handler: ((webContents: (WebContents) | (null), permission: string, requestingOrigin: string, details: PermissionCheckHandlerHandlerDetails) => boolean) | (null)): void; + /** + * Sets the handler which can be used to respond to permission requests for the + * `session`. Calling `callback(true)` will allow the permission and + * `callback(false)` will reject it. To clear the handler, call + * `setPermissionRequestHandler(null)`. Please note that you must also implement + * `setPermissionCheckHandler` to get complete permission handling. Most web APIs + * do a permission check and then make a permission request if the check is denied. + */ + setPermissionRequestHandler(handler: ((webContents: WebContents, permission: 'clipboard-read' | 'media' | 'display-capture' | 'mediaKeySystem' | 'geolocation' | 'notifications' | 'midi' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' | 'unknown', callback: (permissionGranted: boolean) => void, details: PermissionRequestHandlerHandlerDetails) => void) | (null)): void; + /** + * Adds scripts that will be executed on ALL web contents that are associated with + * this session just before normal `preload` scripts run. + */ + setPreloads(preloads: string[]): void; + /** + * Resolves when the proxy setting process is complete. + * + * Sets the proxy settings. + * + * When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, + * the `proxyRules` option is ignored and `pacScript` configuration is applied. + * + * You may need `ses.closeAllConnections` to close currently in flight connections + * to prevent pooled sockets using previous proxy from being reused by future + * requests. + * + * The `proxyRules` has to follow the rules below: + * + * For example: + * + * * `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and + * HTTP proxy `foopy2:80` for `ftp://` URLs. + * * `foopy:80` - Use HTTP proxy `foopy:80` for all URLs. + * * `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing + * over to `bar` if `foopy:80` is unavailable, and after that using no proxy. + * * `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs. + * * `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail + * over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable. + * * `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no + * proxy if `foopy` is unavailable. + * * `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use + * `socks4://foopy2` for all other URLs. + * + * The `proxyBypassRules` is a comma separated list of rules described below: + * + * * `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]` + * + * Match all hostnames that match the pattern HOSTNAME_PATTERN. + * + * Examples: "foobar.com", "*foobar.com", "*.foobar.com", "*foobar.com:99", + * "https://x.*.y.com:99" + * * `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]` + * + * Match a particular domain suffix. + * + * Examples: ".google.com", ".com", "http://.google.com" + * * `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]` + * + * Match URLs which are IP address literals. + * + * Examples: "127.0.1", "[0:0::1]", "[::1]", "http://[::1]:99" + * * `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS` + * + * Match any URL that is to an IP literal that falls between the given range. IP + * range is specified using CIDR notation. + * + * Examples: "192.168.1.1/16", "fefe:13::abc/33". + * * `<local>` + * + * Match local addresses. The meaning of `<local>` is whether the host matches one + * of: "127.0.0.1", "::1", "localhost". + */ + setProxy(config: Config): Promise<void>; + /** + * By default Electron will download hunspell dictionaries from the Chromium CDN. + * If you want to override this behavior you can use this API to point the + * dictionary downloader at your own hosted version of the hunspell dictionaries. + * We publish a `hunspell_dictionaries.zip` file with each release which contains + * the files you need to host here. + * + * The file server must be **case insensitive**. If you cannot do this, you must + * upload each file twice: once with the case it has in the ZIP file and once with + * the filename as all lowercase. + * + * If the files present in `hunspell_dictionaries.zip` are available at + * `https://example.com/dictionaries/language-code.bdic` then you should call this + * api with + * `ses.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/')`. + * Please note the trailing slash. The URL to the dictionaries is formed as + * `${url}${filename}`. + * + * **Note:** On macOS the OS spellchecker is used and therefore we do not download + * any dictionary files. This API is a no-op on macOS. + */ + setSpellCheckerDictionaryDownloadURL(url: string): void; + /** + * Sets whether to enable the builtin spell checker. + */ + setSpellCheckerEnabled(enable: boolean): void; + /** + * The built in spellchecker does not automatically detect what language a user is + * typing in. In order for the spell checker to correctly check their words you + * must call this API with an array of language codes. You can get the list of + * supported language codes with the `ses.availableSpellCheckerLanguages` property. + * + * **Note:** On macOS the OS spellchecker is used and will detect your language + * automatically. This API is a no-op on macOS. + */ + setSpellCheckerLanguages(languages: string[]): void; + /** + * Sets the SSL configuration for the session. All subsequent network requests will + * use the new configuration. Existing network connections (such as WebSocket + * connections) will not be terminated, but old sockets in the pool will not be + * reused for new connections. + */ + setSSLConfig(config: SSLConfigConfig): void; + /** + * Overrides the `userAgent` and `acceptLanguages` for this session. + * + * The `acceptLanguages` must a comma separated ordered list of language codes, for + * example `"en-US,fr,de,ko,zh-CN,ja"`. + * + * This doesn't affect existing `WebContents`, and each `WebContents` can use + * `webContents.setUserAgent` to override the session-wide user agent. + */ + setUserAgent(userAgent: string, acceptLanguages?: string): void; + /** + * A `string[]` array which consists of all the known available spell checker + * languages. Providing a language code to the `setSpellCheckerLanguages` API that + * isn't in this array will result in an error. + * + */ + readonly availableSpellCheckerLanguages: string[]; + /** + * A `Cookies` object for this session. + * + */ + readonly cookies: Cookies; + /** + * A `NetLog` object for this session. + * + */ + readonly netLog: NetLog; + /** + * A `Protocol` object for this session. + * + */ + readonly protocol: Protocol; + /** + * A `ServiceWorkers` object for this session. + * + */ + readonly serviceWorkers: ServiceWorkers; + /** + * A `boolean` indicating whether builtin spell checker is enabled. + */ + spellCheckerEnabled: boolean; + /** + * 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`. + * + */ + readonly storagePath: (string) | (null); + /** + * A `WebRequest` object for this session. + * + */ + readonly webRequest: WebRequest; + } + + interface SharedWorkerInfo { + + // Docs: https://electronjs.org/docs/api/structures/shared-worker-info + + /** + * The unique id of the shared worker. + */ + id: string; + /** + * The url of the shared worker. + */ + url: string; + } + + class ShareMenu extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/share-menu + + /** + * ShareMenu + */ + constructor(sharingItem: SharingItem); + /** + * Closes the context menu in the `browserWindow`. + */ + closePopup(browserWindow?: BrowserWindow): void; + /** + * Pops up this menu as a context menu in the `BrowserWindow`. + */ + popup(options?: PopupOptions): void; + } + + interface SharingItem { + + // Docs: https://electronjs.org/docs/api/structures/sharing-item + + /** + * An array of files to share. + */ + filePaths?: string[]; + /** + * An array of text to share. + */ + texts?: string[]; + /** + * An array of URLs to share. + */ + urls?: string[]; + } + + interface Shell { + + // Docs: https://electronjs.org/docs/api/shell + + /** + * Play the beep sound. + */ + beep(): void; + /** + * Open the given external protocol URL in the desktop's default manner. (For + * example, mailto: URLs in the user's default mail agent). + */ + openExternal(url: string, options?: OpenExternalOptions): Promise<void>; + /** + * Resolves with a string containing the error message corresponding to the failure + * if a failure occurred, otherwise "". + * + * Open the given file in the desktop's default manner. + */ + openPath(path: string): Promise<string>; + /** + * Resolves the shortcut link at `shortcutPath`. + * + * An exception will be thrown when any error happens. + * + * @platform win32 + */ + readShortcutLink(shortcutPath: string): ShortcutDetails; + /** + * Show the given file in a file manager. If possible, select the file. + */ + showItemInFolder(fullPath: string): void; + /** + * Resolves when the operation has been completed. Rejects if there was an error + * while deleting the requested item. + * + * This moves a path to the OS-specific trash location (Trash on macOS, Recycle Bin + * on Windows, and a desktop-environment-specific location on Linux). + */ + trashItem(path: string): Promise<void>; + /** + * Whether the shortcut was created successfully. + * + * Creates or updates a shortcut link at `shortcutPath`. + * + * @platform win32 + */ + writeShortcutLink(shortcutPath: string, operation: 'create' | 'update' | 'replace', options: ShortcutDetails): boolean; + /** + * Whether the shortcut was created successfully. + * + * Creates or updates a shortcut link at `shortcutPath`. + * + * @platform win32 + */ + writeShortcutLink(shortcutPath: string, options: ShortcutDetails): boolean; + } + + interface ShortcutDetails { + + // Docs: https://electronjs.org/docs/api/structures/shortcut-details + + /** + * The Application User Model ID. Default is empty. + */ + appUserModelId?: string; + /** + * The arguments to be applied to `target` when launching from this shortcut. + * Default is empty. + */ + args?: string; + /** + * The working directory. Default is empty. + */ + cwd?: string; + /** + * The description of the shortcut. Default is empty. + */ + description?: string; + /** + * The path to the icon, can be a DLL or EXE. `icon` and `iconIndex` have to be set + * together. Default is empty, which uses the target's icon. + */ + icon?: string; + /** + * The resource ID of icon when `icon` is a DLL or EXE. Default is 0. + */ + iconIndex?: number; + /** + * The target to launch from this shortcut. + */ + target: string; + /** + * The Application Toast Activator CLSID. Needed for participating in Action + * Center. + */ + toastActivatorClsid?: string; + } + + interface Size { + + // Docs: https://electronjs.org/docs/api/structures/size + + height: number; + width: number; + } + + interface SystemPreferences extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/system-preferences + + on(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + once(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + addListener(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + removeListener(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + on(event: 'color-changed', listener: (event: Event) => void): this; + once(event: 'color-changed', listener: (event: Event) => void): this; + addListener(event: 'color-changed', listener: (event: Event) => void): this; + removeListener(event: 'color-changed', listener: (event: Event) => void): this; + /** + * **Deprecated:** Should use the new `updated` event on the `nativeTheme` module. + * + * @deprecated + * @platform win32 + */ + on(event: 'high-contrast-color-scheme-changed', listener: (event: Event, + /** + * `true` if a high contrast theme is being used, `false` otherwise. + */ + highContrastColorScheme: boolean) => void): this; + once(event: 'high-contrast-color-scheme-changed', listener: (event: Event, + /** + * `true` if a high contrast theme is being used, `false` otherwise. + */ + highContrastColorScheme: boolean) => void): this; + addListener(event: 'high-contrast-color-scheme-changed', listener: (event: Event, + /** + * `true` if a high contrast theme is being used, `false` otherwise. + */ + highContrastColorScheme: boolean) => void): this; + removeListener(event: 'high-contrast-color-scheme-changed', listener: (event: Event, + /** + * `true` if a high contrast theme is being used, `false` otherwise. + */ + highContrastColorScheme: boolean) => void): this; + /** + * **Deprecated:** Should use the new `updated` event on the `nativeTheme` module. + * + * @deprecated + * @platform win32 + */ + on(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme (a high contrast color scheme with light text + * and dark backgrounds) is being used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + once(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme (a high contrast color scheme with light text + * and dark backgrounds) is being used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + addListener(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme (a high contrast color scheme with light text + * and dark backgrounds) is being used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + removeListener(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme (a high contrast color scheme with light text + * and dark backgrounds) is being used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + /** + * A promise that resolves with `true` if consent was granted and `false` if it was + * denied. If an invalid `mediaType` is passed, the promise will be rejected. If an + * access request was denied and later is changed through the System Preferences + * pane, a restart of the app will be required for the new permissions to take + * effect. If access has already been requested and denied, it _must_ be changed + * through the preference pane; an alert will not pop up and the promise will + * resolve with the existing access status. + * + * **Important:** In order to properly leverage this API, you must set the + * `NSMicrophoneUsageDescription` and `NSCameraUsageDescription` strings in your + * app's `Info.plist` file. The values for these keys will be used to populate the + * permission dialogs so that the user will be properly informed as to the purpose + * of the permission request. See Electron Application Distribution for more + * information about how to set these in the context of Electron. + * + * This user consent was not required until macOS 10.14 Mojave, so this method will + * always return `true` if your system is running 10.13 High Sierra or lower. + * + * @platform darwin + */ + askForMediaAccess(mediaType: 'microphone' | 'camera'): Promise<boolean>; + /** + * whether or not this device has the ability to use Touch ID. + * + * **NOTE:** This API will return `false` on macOS systems older than Sierra + * 10.12.2. + * + * @platform darwin + */ + canPromptTouchID(): boolean; + /** + * The users current system wide accent color preference in RGBA hexadecimal form. + * + * This API is only available on macOS 10.14 Mojave or newer. + * + * @platform win32,darwin + */ + getAccentColor(): string; + /** + * * `shouldRenderRichAnimation` boolean - Returns true if rich animations should + * be rendered. Looks at session type (e.g. remote desktop) and accessibility + * settings to give guidance for heavy animations. + * * `scrollAnimationsEnabledBySystem` boolean - Determines on a per-platform basis + * whether scroll animations (e.g. produced by home/end key) should be enabled. + * * `prefersReducedMotion` boolean - Determines whether the user desires reduced + * motion based on platform APIs. + * + * Returns an object with system animation settings. + */ + getAnimationSettings(): AnimationSettings; + /** + * | `null` - Can be `dark`, `light` or `unknown`. + * + * Gets the macOS appearance setting that you have declared you want for your + * application, maps to NSApplication.appearance. You can use the + * `setAppLevelAppearance` API to set this value. + * + * @deprecated + * @platform darwin + */ + getAppLevelAppearance(): ('dark' | 'light' | 'unknown'); + /** + * The system color setting in RGB hexadecimal form (`#ABCDEF`). See the Windows + * docs and the macOS docs for more details. + * + * The following colors are only available on macOS 10.14: `find-highlight`, + * `selected-content-background`, `separator`, + * `unemphasized-selected-content-background`, + * `unemphasized-selected-text-background`, and `unemphasized-selected-text`. + * + * @platform win32,darwin + */ + getColor(color: '3d-dark-shadow' | '3d-face' | '3d-highlight' | '3d-light' | '3d-shadow' | 'active-border' | 'active-caption' | 'active-caption-gradient' | 'app-workspace' | 'button-text' | 'caption-text' | 'desktop' | 'disabled-text' | 'highlight' | 'highlight-text' | 'hotlight' | 'inactive-border' | 'inactive-caption' | 'inactive-caption-gradient' | 'inactive-caption-text' | 'info-background' | 'info-text' | 'menu' | 'menu-highlight' | 'menubar' | 'menu-text' | 'scrollbar' | 'window' | 'window-frame' | 'window-text' | 'alternate-selected-control-text' | 'control-background' | 'control' | 'control-text' | 'disabled-control-text' | 'find-highlight' | 'grid' | 'header-text' | 'highlight' | 'keyboard-focus-indicator' | 'label' | 'link' | 'placeholder-text' | 'quaternary-label' | 'scrubber-textured-background' | 'secondary-label' | 'selected-content-background' | 'selected-control' | 'selected-control-text' | 'selected-menu-item-text' | 'selected-text-background' | 'selected-text' | 'separator' | 'shadow' | 'tertiary-label' | 'text-background' | 'text' | 'under-page-background' | 'unemphasized-selected-content-background' | 'unemphasized-selected-text-background' | 'unemphasized-selected-text' | 'window-background' | 'window-frame-text'): string; + /** + * Can be `dark`, `light` or `unknown`. + * + * Gets the macOS appearance setting that is currently applied to your application, + * maps to NSApplication.effectiveAppearance + * + * @platform darwin + */ + getEffectiveAppearance(): ('dark' | 'light' | 'unknown'); + /** + * Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`. + * + * This user consent was not required on macOS 10.13 High Sierra or lower so this + * method will always return `granted`. macOS 10.14 Mojave or higher requires + * consent for `microphone` and `camera` access. macOS 10.15 Catalina or higher + * requires consent for `screen` access. + * + * Windows 10 has a global setting controlling `microphone` and `camera` access for + * all win32 applications. It will always return `granted` for `screen` and for all + * media types on older versions of Windows. + * + * @platform win32,darwin + */ + getMediaAccessStatus(mediaType: 'microphone' | 'camera' | 'screen'): ('not-determined' | 'granted' | 'denied' | 'restricted' | 'unknown'); + /** + * The standard system color formatted as `#RRGGBBAA`. + * + * Returns one of several standard system colors that automatically adapt to + * vibrancy and changes in accessibility settings like 'Increase contrast' and + * 'Reduce transparency'. See Apple Documentation for more details. + * + * @platform darwin + */ + getSystemColor(color: 'blue' | 'brown' | 'gray' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'yellow'): string; + /** + * The value of `key` in `NSUserDefaults`. + * + * Some popular `key` and `type`s are: + * + * * `AppleInterfaceStyle`: `string` + * * `AppleAquaColorVariant`: `integer` + * * `AppleHighlightColor`: `string` + * * `AppleShowScrollBars`: `string` + * * `NSNavRecentPlaces`: `array` + * * `NSPreferredWebServices`: `dictionary` + * * `NSUserDictionaryReplacementItems`: `array` + * + * @platform darwin + */ + getUserDefault<Type extends keyof UserDefaultTypes>(key: string, type: Type): UserDefaultTypes[Type]; + /** + * `true` if DWM composition (Aero Glass) is enabled, and `false` otherwise. + * + * An example of using it to determine if you should create a transparent window or + * not (transparent windows won't work correctly when DWM composition is disabled): + * + * @platform win32 + */ + isAeroGlassEnabled(): boolean; + /** + * Whether the system is in Dark Mode. + * + * **Deprecated:** Should use the new `nativeTheme.shouldUseDarkColors` API. + * + * @deprecated + * @platform darwin,win32 + */ + isDarkMode(): boolean; + /** + * `true` if a high contrast theme is active, `false` otherwise. + * + * **Deprecated:** Should use the new `nativeTheme.shouldUseHighContrastColors` + * API. + * + * @deprecated + * @platform darwin,win32 + */ + isHighContrastColorScheme(): boolean; + /** + * `true` if an inverted color scheme (a high contrast color scheme with light text + * and dark backgrounds) is active, `false` otherwise. + * + * **Deprecated:** Should use the new `nativeTheme.shouldUseInvertedColorScheme` + * API. + * + * @deprecated + * @platform win32 + */ + isInvertedColorScheme(): boolean; + /** + * Whether the Swipe between pages setting is on. + * + * @platform darwin + */ + isSwipeTrackingFromScrollEventsEnabled(): boolean; + /** + * `true` if the current process is a trusted accessibility client and `false` if + * it is not. + * + * @platform darwin + */ + isTrustedAccessibilityClient(prompt: boolean): boolean; + /** + * Posts `event` as native notifications of macOS. The `userInfo` is an Object that + * contains the user information dictionary sent along with the notification. + * + * @platform darwin + */ + postLocalNotification(event: string, userInfo: Record<string, any>): void; + /** + * Posts `event` as native notifications of macOS. The `userInfo` is an Object that + * contains the user information dictionary sent along with the notification. + * + * @platform darwin + */ + postNotification(event: string, userInfo: Record<string, any>, deliverImmediately?: boolean): void; + /** + * Posts `event` as native notifications of macOS. The `userInfo` is an Object that + * contains the user information dictionary sent along with the notification. + * + * @platform darwin + */ + postWorkspaceNotification(event: string, userInfo: Record<string, any>): void; + /** + * resolves if the user has successfully authenticated with Touch ID. + * + * This API itself will not protect your user data; rather, it is a mechanism to + * allow you to do so. Native apps will need to set Access Control Constants like + * `kSecAccessControlUserPresence` on their keychain entry so that reading it would + * auto-prompt for Touch ID biometric consent. This could be done with + * `node-keytar`, such that one would store an encryption key with `node-keytar` + * and only fetch it if `promptTouchID()` resolves. + * + * **NOTE:** This API will return a rejected Promise on macOS systems older than + * Sierra 10.12.2. + * + * @platform darwin + */ + promptTouchID(reason: string): Promise<void>; + /** + * Add the specified defaults to your application's `NSUserDefaults`. + * + * @platform darwin + */ + registerDefaults(defaults: Record<string, (string) | (boolean) | (number)>): void; + /** + * Removes the `key` in `NSUserDefaults`. This can be used to restore the default + * or global value of a `key` previously set with `setUserDefault`. + * + * @platform darwin + */ + removeUserDefault(key: string): void; + /** + * Sets the appearance setting for your application, this should override the + * system default and override the value of `getEffectiveAppearance`. + * + * @deprecated + * @platform darwin + */ + setAppLevelAppearance(appearance: (('dark' | 'light')) | (null)): void; + /** + * Set the value of `key` in `NSUserDefaults`. + * + * Note that `type` should match actual type of `value`. An exception is thrown if + * they don't. + * + * Some popular `key` and `type`s are: + * + * * `ApplePressAndHoldEnabled`: `boolean` + * + * @platform darwin + */ + setUserDefault<Type extends keyof UserDefaultTypes>(key: string, type: Type, value: UserDefaultTypes[Type]): void; + /** + * The ID of this subscription + * + * Same as `subscribeNotification`, but uses `NSNotificationCenter` for local + * defaults. This is necessary for events such as + * `NSUserDefaultsDidChangeNotification`. + * + * If `event` is null, the `NSNotificationCenter` doesn’t use it as criteria for + * delivery to the observer. See docs for more information. + * + * @platform darwin + */ + subscribeLocalNotification(event: (string) | (null), callback: (event: string, userInfo: Record<string, unknown>, object: string) => void): number; + /** + * The ID of this subscription + * + * Subscribes to native notifications of macOS, `callback` will be called with + * `callback(event, userInfo)` when the corresponding `event` happens. The + * `userInfo` is an Object that contains the user information dictionary sent along + * with the notification. The `object` is the sender of the notification, and only + * supports `NSString` values for now. + * + * The `id` of the subscriber is returned, which can be used to unsubscribe the + * `event`. + * + * Under the hood this API subscribes to `NSDistributedNotificationCenter`, example + * values of `event` are: + * + * * `AppleInterfaceThemeChangedNotification` + * * `AppleAquaColorVariantChanged` + * * `AppleColorPreferencesChangedNotification` + * * `AppleShowScrollBarsSettingChanged` + * + * If `event` is null, the `NSDistributedNotificationCenter` doesn’t use it as + * criteria for delivery to the observer. See docs for more information. + * + * @platform darwin + */ + subscribeNotification(event: (string) | (null), callback: (event: string, userInfo: Record<string, unknown>, object: string) => void): number; + /** + * The ID of this subscription + * + * Same as `subscribeNotification`, but uses + * `NSWorkspace.sharedWorkspace.notificationCenter`. This is necessary for events + * such as `NSWorkspaceDidActivateApplicationNotification`. + * + * If `event` is null, the `NSWorkspaceNotificationCenter` doesn’t use it as + * criteria for delivery to the observer. See docs for more information. + * + * @platform darwin + */ + subscribeWorkspaceNotification(event: (string) | (null), callback: (event: string, userInfo: Record<string, unknown>, object: string) => void): number; + /** + * Same as `unsubscribeNotification`, but removes the subscriber from + * `NSNotificationCenter`. + * + * @platform darwin + */ + unsubscribeLocalNotification(id: number): void; + /** + * Removes the subscriber with `id`. + * + * @platform darwin + */ + unsubscribeNotification(id: number): void; + /** + * Same as `unsubscribeNotification`, but removes the subscriber from + * `NSWorkspace.sharedWorkspace.notificationCenter`. + * + * @platform darwin + */ + unsubscribeWorkspaceNotification(id: number): void; + /** + * A `string` property that can be `dark`, `light` or `unknown`. It determines the + * macOS appearance setting for your application. This maps to values in: + * NSApplication.appearance. Setting this will override the system default as well + * as the value of `getEffectiveAppearance`. + * + * Possible values that can be set are `dark` and `light`, and possible return + * values are `dark`, `light`, and `unknown`. + * + * This property is only available on macOS 10.14 Mojave or newer. + * + * @platform darwin + */ + appLevelAppearance: ('dark' | 'light' | 'unknown'); + /** + * A `string` property that can be `dark`, `light` or `unknown`. + * + * Returns the macOS appearance setting that is currently applied to your + * application, maps to NSApplication.effectiveAppearance + * + * @platform darwin + */ + readonly effectiveAppearance: ('dark' | 'light' | 'unknown'); + } + + interface Task { + + // Docs: https://electronjs.org/docs/api/structures/task + + /** + * The command line arguments when `program` is executed. + */ + arguments: string; + /** + * Description of this task. + */ + description: string; + /** + * The icon index in the icon file. If an icon file consists of two or more icons, + * set this value to identify the icon. If an icon file consists of one icon, this + * value is 0. + */ + iconIndex: number; + /** + * The absolute path to an icon to be displayed in a JumpList, which can be an + * arbitrary resource file that contains an icon. You can usually specify + * `process.execPath` to show the icon of the program. + */ + iconPath: string; + /** + * Path of the program to execute, usually you should specify `process.execPath` + * which opens the current program. + */ + program: string; + /** + * The string to be displayed in a JumpList. + */ + title: string; + /** + * The working directory. Default is empty. + */ + workingDirectory?: string; + } + + interface ThumbarButton { + + // Docs: https://electronjs.org/docs/api/structures/thumbar-button + + click: Function; + /** + * Control specific states and behaviors of the button. By default, it is + * `['enabled']`. + */ + flags?: string[]; + /** + * The icon showing in thumbnail toolbar. + */ + icon: NativeImage; + /** + * The text of the button's tooltip. + */ + tooltip?: string; + } + + class TouchBar { + + // Docs: https://electronjs.org/docs/api/touch-bar + + /** + * TouchBar + */ + constructor(options: TouchBarConstructorOptions); + /** + * A `TouchBarItem` that will replace the "esc" button on the touch bar when set. + * Setting to `null` restores the default "esc" button. Changing this value + * immediately updates the escape item in the touch bar. + */ + escapeItem: (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer | null); + /** + * A `typeof TouchBarButton` reference to the `TouchBarButton` class. + */ + static TouchBarButton: typeof TouchBarButton; + /** + * A `typeof TouchBarColorPicker` reference to the `TouchBarColorPicker` class. + */ + static TouchBarColorPicker: typeof TouchBarColorPicker; + /** + * A `typeof TouchBarGroup` reference to the `TouchBarGroup` class. + */ + static TouchBarGroup: typeof TouchBarGroup; + /** + * A `typeof TouchBarLabel` reference to the `TouchBarLabel` class. + */ + static TouchBarLabel: typeof TouchBarLabel; + /** + * A `typeof TouchBarOtherItemsProxy` reference to the `TouchBarOtherItemsProxy` + * class. + */ + static TouchBarOtherItemsProxy: typeof TouchBarOtherItemsProxy; + /** + * A `typeof TouchBarPopover` reference to the `TouchBarPopover` class. + */ + static TouchBarPopover: typeof TouchBarPopover; + /** + * A `typeof TouchBarScrubber` reference to the `TouchBarScrubber` class. + */ + static TouchBarScrubber: typeof TouchBarScrubber; + /** + * A `typeof TouchBarSegmentedControl` reference to the `TouchBarSegmentedControl` + * class. + */ + static TouchBarSegmentedControl: typeof TouchBarSegmentedControl; + /** + * A `typeof TouchBarSlider` reference to the `TouchBarSlider` class. + */ + static TouchBarSlider: typeof TouchBarSlider; + /** + * A `typeof TouchBarSpacer` reference to the `TouchBarSpacer` class. + */ + static TouchBarSpacer: typeof TouchBarSpacer; + } + + class TouchBarButton { + + // Docs: https://electronjs.org/docs/api/touch-bar-button + + /** + * TouchBarButton + */ + constructor(options: TouchBarButtonConstructorOptions); + /** + * A `string` representing the description of the button to be read by a screen + * reader. Will only be read by screen readers if no label is set. + */ + accessibilityLabel: string; + /** + * A `string` hex code representing the button's current background color. Changing + * this value immediately updates the button in the touch bar. + */ + backgroundColor: string; + /** + * A `boolean` representing whether the button is in an enabled state. + */ + enabled: boolean; + /** + * A `NativeImage` representing the button's current icon. Changing this value + * immediately updates the button in the touch bar. + */ + icon: NativeImage; + /** + * A `string` - Can be `left`, `right` or `overlay`. Defaults to `overlay`. + */ + iconPosition: ('left' | 'right' | 'overlay'); + /** + * A `string` representing the button's current text. Changing this value + * immediately updates the button in the touch bar. + */ + label: string; + } + + class TouchBarColorPicker extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-color-picker + + /** + * TouchBarColorPicker + */ + constructor(options: TouchBarColorPickerConstructorOptions); + /** + * A `string[]` array representing the color picker's available colors to select. + * Changing this value immediately updates the color picker in the touch bar. + */ + availableColors: string[]; + /** + * A `string` hex code representing the color picker's currently selected color. + * Changing this value immediately updates the color picker in the touch bar. + */ + selectedColor: string; + } + + class TouchBarGroup extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-group + + /** + * TouchBarGroup + */ + constructor(options: TouchBarGroupConstructorOptions); + } + + class TouchBarLabel extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-label + + /** + * TouchBarLabel + */ + constructor(options: TouchBarLabelConstructorOptions); + /** + * A `string` representing the description of the label to be read by a screen + * reader. + */ + accessibilityLabel: string; + /** + * A `string` representing the label's current text. Changing this value + * immediately updates the label in the touch bar. + */ + label: string; + /** + * A `string` hex code representing the label's current text color. Changing this + * value immediately updates the label in the touch bar. + */ + textColor: string; + } + + class TouchBarOtherItemsProxy extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-other-items-proxy + + /** + * TouchBarOtherItemsProxy + */ + constructor(); + } + + class TouchBarPopover extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-popover + + /** + * TouchBarPopover + */ + constructor(options: TouchBarPopoverConstructorOptions); + /** + * A `NativeImage` representing the popover's current button icon. Changing this + * value immediately updates the popover in the touch bar. + */ + icon: NativeImage; + /** + * A `string` representing the popover's current button text. Changing this value + * immediately updates the popover in the touch bar. + */ + label: string; + } + + class TouchBarScrubber extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-scrubber + + /** + * TouchBarScrubber + */ + constructor(options: TouchBarScrubberConstructorOptions); + /** + * A `boolean` representing whether this scrubber is continuous or not. Updating + * this value immediately updates the control in the touch bar. + */ + continuous: boolean; + /** + * A `ScrubberItem[]` array representing the items in this scrubber. Updating this + * value immediately updates the control in the touch bar. Updating deep properties + * inside this array **does not update the touch bar**. + */ + items: ScrubberItem[]; + /** + * A `string` representing the mode of this scrubber. Updating this value + * immediately updates the control in the touch bar. Possible values: + * + * * `fixed` - Maps to `NSScrubberModeFixed`. + * * `free` - Maps to `NSScrubberModeFree`. + */ + mode: ('fixed' | 'free'); + /** + * A `string` representing the style that selected items in the scrubber should + * have. This style is overlayed on top of the scrubber item instead of being + * placed behind it. Updating this value immediately updates the control in the + * touch bar. Possible values: + * + * * `background` - Maps to `[NSScrubberSelectionStyle roundedBackgroundStyle]`. + * * `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`. + * * `none` - Removes all styles. + */ + overlayStyle: ('background' | 'outline' | 'none'); + /** + * A `string` representing the style that selected items in the scrubber should + * have. Updating this value immediately updates the control in the touch bar. + * Possible values: + * + * * `background` - Maps to `[NSScrubberSelectionStyle roundedBackgroundStyle]`. + * * `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`. + * * `none` - Removes all styles. + */ + selectedStyle: ('background' | 'outline' | 'none'); + /** + * A `boolean` representing whether to show the left / right selection arrows in + * this scrubber. Updating this value immediately updates the control in the touch + * bar. + */ + showArrowButtons: boolean; + } + + class TouchBarSegmentedControl extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-segmented-control + + /** + * TouchBarSegmentedControl + */ + constructor(options: TouchBarSegmentedControlConstructorOptions); + /** + * A `string` representing the current selection mode of the control. Can be + * `single`, `multiple` or `buttons`. + */ + mode: ('single' | 'multiple' | 'buttons'); + /** + * A `SegmentedControlSegment[]` array representing the segments in this control. + * Updating this value immediately updates the control in the touch bar. Updating + * deep properties inside this array **does not update the touch bar**. + */ + segments: SegmentedControlSegment[]; + /** + * A `string` representing the controls current segment style. Updating this value + * immediately updates the control in the touch bar. + */ + segmentStyle: string; + /** + * An `Integer` representing the currently selected segment. Changing this value + * immediately updates the control in the touch bar. User interaction with the + * touch bar will update this value automatically. + */ + selectedIndex: number; + } + + class TouchBarSlider extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-slider + + /** + * TouchBarSlider + */ + constructor(options: TouchBarSliderConstructorOptions); + /** + * A `string` representing the slider's current text. Changing this value + * immediately updates the slider in the touch bar. + */ + label: string; + /** + * A `number` representing the slider's current maximum value. Changing this value + * immediately updates the slider in the touch bar. + */ + maxValue: number; + /** + * A `number` representing the slider's current minimum value. Changing this value + * immediately updates the slider in the touch bar. + */ + minValue: number; + /** + * A `number` representing the slider's current value. Changing this value + * immediately updates the slider in the touch bar. + */ + value: number; + } + + class TouchBarSpacer extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/touch-bar-spacer + + /** + * TouchBarSpacer + */ + constructor(options: TouchBarSpacerConstructorOptions); + /** + * A `string` representing the size of the spacer. Can be `small`, `large` or + * `flexible`. + */ + size: ('small' | 'large' | 'flexible'); + } + + interface TraceCategoriesAndOptions { + + // Docs: https://electronjs.org/docs/api/structures/trace-categories-and-options + + /** + * A filter to control what category groups should be traced. A filter can have an + * optional '-' prefix to exclude category groups that contain a matching category. + * Having both included and excluded category patterns in the same list is not + * supported. Examples: `test_MyTest*`, `test_MyTest*,test_OtherStuff`, + * `-excluded_category1,-excluded_category2`. + */ + categoryFilter: string; + /** + * Controls what kind of tracing is enabled, it is a comma-delimited sequence of + * the following strings: `record-until-full`, `record-continuously`, + * `trace-to-console`, `enable-sampling`, `enable-systrace`, e.g. + * `'record-until-full,enable-sampling'`. The first 3 options are trace recording + * modes and hence mutually exclusive. If more than one trace recording modes + * appear in the `traceOptions` string, the last one takes precedence. If none of + * the trace recording modes are specified, recording mode is `record-until-full`. + * The trace option will first be reset to the default option (`record_mode` set to + * `record-until-full`, `enable_sampling` and `enable_systrace` set to `false`) + * before options parsed from `traceOptions` are applied on it. + */ + traceOptions: string; + } + + interface TraceConfig { + + // Docs: https://electronjs.org/docs/api/structures/trace-config + + /** + * if true, filter event data according to a specific list of events that have been + * manually vetted to not include any PII. See the implementation in Chromium for + * specifics. + */ + enable_argument_filter?: boolean; + /** + * a list of tracing categories to exclude. Can include glob-like patterns using + * `*` at the end of the category name. See tracing categories for the list of + * categories. + */ + excluded_categories?: string[]; + /** + * a list of histogram names to report with the trace. + */ + histogram_names?: string[]; + /** + * a list of tracing categories to include. Can include glob-like patterns using + * `*` at the end of the category name. See tracing categories for the list of + * categories. + */ + included_categories?: string[]; + /** + * a list of process IDs to include in the trace. If not specified, trace all + * processes. + */ + included_process_ids?: number[]; + /** + * if the `disabled-by-default-memory-infra` category is enabled, this contains + * optional additional configuration for data collection. See the Chromium + * memory-infra docs for more information. + */ + memory_dump_config?: Record<string, any>; + /** + * Can be `record-until-full`, `record-continuously`, `record-as-much-as-possible` + * or `trace-to-console`. Defaults to `record-until-full`. + */ + recording_mode?: ('record-until-full' | 'record-continuously' | 'record-as-much-as-possible' | 'trace-to-console'); + /** + * maximum size of the trace recording buffer in events. + */ + trace_buffer_size_in_events?: number; + /** + * maximum size of the trace recording buffer in kilobytes. Defaults to 100MB. + */ + trace_buffer_size_in_kb?: number; + } + + interface Transaction { + + // Docs: https://electronjs.org/docs/api/structures/transaction + + /** + * The error code if an error occurred while processing the transaction. + */ + errorCode: number; + /** + * The error message if an error occurred while processing the transaction. + */ + errorMessage: string; + /** + * The identifier of the restored transaction by the App Store. + */ + originalTransactionIdentifier: string; + payment: Payment; + /** + * The date the transaction was added to the App Store’s payment queue. + */ + transactionDate: string; + /** + * A string that uniquely identifies a successful payment transaction. + */ + transactionIdentifier: string; + /** + * The transaction state, can be `purchasing`, `purchased`, `failed`, `restored` or + * `deferred`. + */ + transactionState: ('purchasing' | 'purchased' | 'failed' | 'restored' | 'deferred'); + } + + class Tray extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/tray + + /** + * Emitted when the tray balloon is clicked. + * + * @platform win32 + */ + on(event: 'balloon-click', listener: Function): this; + once(event: 'balloon-click', listener: Function): this; + addListener(event: 'balloon-click', listener: Function): this; + removeListener(event: 'balloon-click', listener: Function): this; + /** + * Emitted when the tray balloon is closed because of timeout or user manually + * closes it. + * + * @platform win32 + */ + on(event: 'balloon-closed', listener: Function): this; + once(event: 'balloon-closed', listener: Function): this; + addListener(event: 'balloon-closed', listener: Function): this; + removeListener(event: 'balloon-closed', listener: Function): this; + /** + * Emitted when the tray balloon shows. + * + * @platform win32 + */ + on(event: 'balloon-show', listener: Function): this; + once(event: 'balloon-show', listener: Function): this; + addListener(event: 'balloon-show', listener: Function): this; + removeListener(event: 'balloon-show', listener: Function): this; + /** + * Emitted when the tray icon is clicked. + */ + on(event: 'click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle, + /** + * The position of the event. + */ + position: Point) => void): this; + once(event: 'click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle, + /** + * The position of the event. + */ + position: Point) => void): this; + addListener(event: 'click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle, + /** + * The position of the event. + */ + position: Point) => void): this; + removeListener(event: 'click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle, + /** + * The position of the event. + */ + position: Point) => void): this; + /** + * Emitted when the tray icon is double clicked. + * + * @platform darwin,win32 + */ + on(event: 'double-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + once(event: 'double-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + addListener(event: 'double-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + removeListener(event: 'double-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + /** + * Emitted when a drag operation ends on the tray or ends at another location. + * + * @platform darwin + */ + on(event: 'drag-end', listener: Function): this; + once(event: 'drag-end', listener: Function): this; + addListener(event: 'drag-end', listener: Function): this; + removeListener(event: 'drag-end', listener: Function): this; + /** + * Emitted when a drag operation enters the tray icon. + * + * @platform darwin + */ + on(event: 'drag-enter', listener: Function): this; + once(event: 'drag-enter', listener: Function): this; + addListener(event: 'drag-enter', listener: Function): this; + removeListener(event: 'drag-enter', listener: Function): this; + /** + * Emitted when a drag operation exits the tray icon. + * + * @platform darwin + */ + on(event: 'drag-leave', listener: Function): this; + once(event: 'drag-leave', listener: Function): this; + addListener(event: 'drag-leave', listener: Function): this; + removeListener(event: 'drag-leave', listener: Function): this; + /** + * Emitted when any dragged items are dropped on the tray icon. + * + * @platform darwin + */ + on(event: 'drop', listener: Function): this; + once(event: 'drop', listener: Function): this; + addListener(event: 'drop', listener: Function): this; + removeListener(event: 'drop', listener: Function): this; + /** + * Emitted when dragged files are dropped in the tray icon. + * + * @platform darwin + */ + on(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + once(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + addListener(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + removeListener(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + /** + * Emitted when dragged text is dropped in the tray icon. + * + * @platform darwin + */ + on(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string. + */ + text: string) => void): this; + once(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string. + */ + text: string) => void): this; + addListener(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string. + */ + text: string) => void): this; + removeListener(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string. + */ + text: string) => void): this; + /** + * Emitted when the mouse clicks the tray icon. + * + * @platform darwin + */ + on(event: 'mouse-down', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + once(event: 'mouse-down', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + addListener(event: 'mouse-down', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + removeListener(event: 'mouse-down', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + /** + * Emitted when the mouse enters the tray icon. + * + * @platform darwin + */ + on(event: 'mouse-enter', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + once(event: 'mouse-enter', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + addListener(event: 'mouse-enter', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + removeListener(event: 'mouse-enter', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + /** + * Emitted when the mouse exits the tray icon. + * + * @platform darwin + */ + on(event: 'mouse-leave', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + once(event: 'mouse-leave', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + addListener(event: 'mouse-leave', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + removeListener(event: 'mouse-leave', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + /** + * Emitted when the mouse moves in the tray icon. + * + * @platform darwin,win32 + */ + on(event: 'mouse-move', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + once(event: 'mouse-move', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + addListener(event: 'mouse-move', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + removeListener(event: 'mouse-move', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + /** + * Emitted when the mouse is released from clicking the tray icon. + * + * Note: This will not be emitted if you have set a context menu for your Tray + * using `tray.setContextMenu`, as a result of macOS-level constraints. + * + * @platform darwin + */ + on(event: 'mouse-up', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + once(event: 'mouse-up', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + addListener(event: 'mouse-up', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + removeListener(event: 'mouse-up', listener: (event: KeyboardEvent, + /** + * The position of the event. + */ + position: Point) => void): this; + /** + * Emitted when the tray icon is right clicked. + * + * @platform darwin,win32 + */ + on(event: 'right-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + once(event: 'right-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + addListener(event: 'right-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + removeListener(event: 'right-click', listener: (event: KeyboardEvent, + /** + * The bounds of tray icon. + */ + bounds: Rectangle) => void): this; + /** + * Tray + */ + constructor(image: (NativeImage) | (string), guid?: string); + /** + * Closes an open context menu, as set by `tray.setContextMenu()`. + * + * @platform darwin,win32 + */ + closeContextMenu(): void; + /** + * Destroys the tray icon immediately. + */ + destroy(): void; + /** + * Displays a tray balloon. + * + * @platform win32 + */ + displayBalloon(options: DisplayBalloonOptions): void; + /** + * Returns focus to the taskbar notification area. Notification area icons should + * use this message when they have completed their UI operation. For example, if + * the icon displays a shortcut menu, but the user presses ESC to cancel it, use + * `tray.focus()` to return focus to the notification area. + * + * @platform win32 + */ + focus(): void; + /** + * The `bounds` of this tray icon as `Object`. + * + * @platform darwin,win32 + */ + getBounds(): Rectangle; + /** + * Whether double click events will be ignored. + * + * @platform darwin + */ + getIgnoreDoubleClickEvents(): boolean; + /** + * the title displayed next to the tray icon in the status bar + * + * @platform darwin + */ + getTitle(): string; + /** + * Whether the tray icon is destroyed. + */ + isDestroyed(): boolean; + /** + * Pops up the context menu of the tray icon. When `menu` is passed, the `menu` + * will be shown instead of the tray icon's context menu. + * + * The `position` is only available on Windows, and it is (0, 0) by default. + * + * @platform darwin,win32 + */ + popUpContextMenu(menu?: Menu, position?: Point): void; + /** + * Removes a tray balloon. + * + * @platform win32 + */ + removeBalloon(): void; + /** + * Sets the context menu for this icon. + */ + setContextMenu(menu: (Menu) | (null)): void; + /** + * Sets the option to ignore double click events. Ignoring these events allows you + * to detect every individual click of the tray icon. + * + * This value is set to false by default. + * + * @platform darwin + */ + setIgnoreDoubleClickEvents(ignore: boolean): void; + /** + * Sets the `image` associated with this tray icon. + */ + setImage(image: (NativeImage) | (string)): void; + /** + * Sets the `image` associated with this tray icon when pressed on macOS. + * + * @platform darwin + */ + setPressedImage(image: (NativeImage) | (string)): void; + /** + * Sets the title displayed next to the tray icon in the status bar (Support ANSI + * colors). + * + * @platform darwin + */ + setTitle(title: string, options?: TitleOptions): void; + /** + * Sets the hover text for this tray icon. + */ + setToolTip(toolTip: string): void; + } + + interface UploadData { + + // Docs: https://electronjs.org/docs/api/structures/upload-data + + /** + * UUID of blob data. Use ses.getBlobData method to retrieve the data. + */ + blobUUID?: string; + /** + * Content being sent. + */ + bytes: Buffer; + /** + * Path of file being uploaded. + */ + file?: string; + } + + interface UploadFile { + + // Docs: https://electronjs.org/docs/api/structures/upload-file + + /** + * Path of file to be uploaded. + */ + filePath: string; + /** + * Number of bytes to read from `offset`. Defaults to `0`. + */ + length: number; + /** + * Last Modification time in number of seconds since the UNIX epoch. + */ + modificationTime: number; + /** + * Defaults to `0`. + */ + offset: number; + /** + * `file`. + */ + type: 'file'; + } + + interface UploadRawData { + + // Docs: https://electronjs.org/docs/api/structures/upload-raw-data + + /** + * Data to be uploaded. + */ + bytes: Buffer; + /** + * `rawData`. + */ + type: 'rawData'; + } + + interface UserDefaultTypes { + + // Docs: https://electronjs.org/docs/api/structures/user-default-types + + array: Array<unknown>; + boolean: boolean; + dictionary: Record<string, unknown>; + double: number; + float: number; + integer: number; + string: string; + url: string; + } + + class WebContents extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/web-contents + + /** + * | undefined - A WebContents instance with the given TargetID, or `undefined` if + * there is no WebContents associated with the given TargetID. + * + * When communicating with the Chrome DevTools Protocol, it can be useful to lookup + * a WebContents instance based on its assigned TargetID. + */ + static fromDevToolsTargetId(targetId: string): WebContents; + /** + * | undefined - A WebContents instance with the given WebFrameMain, or `undefined` + * if there is no WebContents associated with the given WebFrameMain. + */ + static fromFrame(frame: WebFrameMain): WebContents; + /** + * | undefined - A WebContents instance with the given ID, or `undefined` if there + * is no WebContents associated with the given ID. + */ + static fromId(id: number): WebContents; + /** + * An array of all `WebContents` instances. This will contain web contents for all + * windows, webviews, opened devtools, and devtools extension background pages. + */ + static getAllWebContents(): WebContents[]; + /** + * | null - The web contents that is focused in this application, otherwise returns + * `null`. + */ + static getFocusedWebContents(): WebContents; + /** + * Emitted before dispatching the `keydown` and `keyup` events in the page. Calling + * `event.preventDefault` will prevent the page `keydown`/`keyup` events and the + * menu shortcuts. + * + * To only prevent the menu shortcuts, use `setIgnoreMenuShortcuts`: + */ + on(event: 'before-input-event', listener: (event: Event, + /** + * Input properties. + */ + input: Input) => void): this; + once(event: 'before-input-event', listener: (event: Event, + /** + * Input properties. + */ + input: Input) => void): this; + addListener(event: 'before-input-event', listener: (event: Event, + /** + * Input properties. + */ + input: Input) => void): this; + removeListener(event: 'before-input-event', listener: (event: Event, + /** + * Input properties. + */ + input: Input) => void): this; + /** + * Emitted when the `WebContents` loses focus. + */ + on(event: 'blur', listener: Function): this; + once(event: 'blur', listener: Function): this; + addListener(event: 'blur', listener: Function): this; + removeListener(event: 'blur', listener: Function): this; + /** + * Emitted when failed to verify the `certificate` for `url`. + * + * The usage is the same with the `certificate-error` event of `app`. + */ + on(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code. + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + once(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code. + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + addListener(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code. + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + removeListener(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code. + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void, + isMainFrame: boolean) => void): this; + /** + * Emitted when the associated window logs a console message. + */ + on(event: 'console-message', listener: (event: Event, + /** + * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and + * `error`. + */ + level: number, + /** + * The actual console message + */ + message: string, + /** + * The line number of the source that triggered this console message + */ + line: number, + sourceId: string) => void): this; + once(event: 'console-message', listener: (event: Event, + /** + * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and + * `error`. + */ + level: number, + /** + * The actual console message + */ + message: string, + /** + * The line number of the source that triggered this console message + */ + line: number, + sourceId: string) => void): this; + addListener(event: 'console-message', listener: (event: Event, + /** + * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and + * `error`. + */ + level: number, + /** + * The actual console message + */ + message: string, + /** + * The line number of the source that triggered this console message + */ + line: number, + sourceId: string) => void): this; + removeListener(event: 'console-message', listener: (event: Event, + /** + * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and + * `error`. + */ + level: number, + /** + * The actual console message + */ + message: string, + /** + * The line number of the source that triggered this console message + */ + line: number, + sourceId: string) => void): this; + /** + * Emitted when there is a new context menu that needs to be handled. + */ + on(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + once(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + addListener(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + removeListener(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + /** + * Emitted when the renderer process crashes or is killed. + * + * **Deprecated:** This event is superceded by the `render-process-gone` event + * which contains more information about why the render process disappeared. It + * isn't always because it crashed. The `killed` boolean can be replaced by + * checking `reason === 'killed'` when you switch to that event. + * + * @deprecated + */ + on(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + once(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + addListener(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + removeListener(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + /** + * Emitted when the cursor's type changes. The `type` parameter can be `default`, + * `crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`, + * `ne-resize`, `nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`, + * `ns-resize`, `ew-resize`, `nesw-resize`, `nwse-resize`, `col-resize`, + * `row-resize`, `m-panning`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`, + * `s-panning`, `se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`, + * `cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`, + * `not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing` or `custom`. + * + * If the `type` parameter is `custom`, the `image` parameter will hold the custom + * cursor image in a `NativeImage`, and `scale`, `size` and `hotspot` will hold + * additional information about the custom cursor. + */ + on(event: 'cursor-changed', listener: (event: Event, + type: string, + image: NativeImage, + /** + * scaling factor for the custom cursor. + */ + scale: number, + /** + * the size of the `image`. + */ + size: Size, + /** + * coordinates of the custom cursor's hotspot. + */ + hotspot: Point) => void): this; + once(event: 'cursor-changed', listener: (event: Event, + type: string, + image: NativeImage, + /** + * scaling factor for the custom cursor. + */ + scale: number, + /** + * the size of the `image`. + */ + size: Size, + /** + * coordinates of the custom cursor's hotspot. + */ + hotspot: Point) => void): this; + addListener(event: 'cursor-changed', listener: (event: Event, + type: string, + image: NativeImage, + /** + * scaling factor for the custom cursor. + */ + scale: number, + /** + * the size of the `image`. + */ + size: Size, + /** + * coordinates of the custom cursor's hotspot. + */ + hotspot: Point) => void): this; + removeListener(event: 'cursor-changed', listener: (event: Event, + type: string, + image: NativeImage, + /** + * scaling factor for the custom cursor. + */ + scale: number, + /** + * the size of the `image`. + */ + size: Size, + /** + * coordinates of the custom cursor's hotspot. + */ + hotspot: Point) => void): this; + /** + * Emitted when `webContents` is destroyed. + */ + on(event: 'destroyed', listener: Function): this; + once(event: 'destroyed', listener: Function): this; + addListener(event: 'destroyed', listener: Function): this; + removeListener(event: 'destroyed', listener: Function): this; + /** + * Emitted when DevTools is closed. + */ + on(event: 'devtools-closed', listener: Function): this; + once(event: 'devtools-closed', listener: Function): this; + addListener(event: 'devtools-closed', listener: Function): this; + removeListener(event: 'devtools-closed', listener: Function): this; + /** + * Emitted when DevTools is focused / opened. + */ + on(event: 'devtools-focused', listener: Function): this; + once(event: 'devtools-focused', listener: Function): this; + addListener(event: 'devtools-focused', listener: Function): this; + removeListener(event: 'devtools-focused', listener: Function): this; + /** + * Emitted when DevTools is opened. + */ + on(event: 'devtools-opened', listener: Function): this; + once(event: 'devtools-opened', listener: Function): this; + addListener(event: 'devtools-opened', listener: Function): this; + removeListener(event: 'devtools-opened', listener: Function): this; + /** + * Emitted when the devtools window instructs the webContents to reload + */ + on(event: 'devtools-reload-page', listener: Function): this; + once(event: 'devtools-reload-page', listener: Function): this; + addListener(event: 'devtools-reload-page', listener: Function): this; + removeListener(event: 'devtools-reload-page', listener: Function): this; + /** + * Emitted when a `<webview>` has been attached to this web contents. + */ + on(event: 'did-attach-webview', listener: (event: Event, + /** + * The guest web contents that is used by the `<webview>`. + */ + webContents: WebContents) => void): this; + once(event: 'did-attach-webview', listener: (event: Event, + /** + * The guest web contents that is used by the `<webview>`. + */ + webContents: WebContents) => void): this; + addListener(event: 'did-attach-webview', listener: (event: Event, + /** + * The guest web contents that is used by the `<webview>`. + */ + webContents: WebContents) => void): this; + removeListener(event: 'did-attach-webview', listener: (event: Event, + /** + * The guest web contents that is used by the `<webview>`. + */ + webContents: WebContents) => void): this; + /** + * Emitted when a page's theme color changes. This is usually due to encountering a + * meta tag: + */ + on(event: 'did-change-theme-color', listener: (event: Event, + /** + * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. + */ + color: (string) | (null)) => void): this; + once(event: 'did-change-theme-color', listener: (event: Event, + /** + * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. + */ + color: (string) | (null)) => void): this; + addListener(event: 'did-change-theme-color', listener: (event: Event, + /** + * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. + */ + color: (string) | (null)) => void): this; + removeListener(event: 'did-change-theme-color', listener: (event: Event, + /** + * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. + */ + color: (string) | (null)) => void): this; + /** + * Emitted _after_ successful creation of a window via `window.open` in the + * renderer. Not emitted if the creation of the window is canceled from + * `webContents.setWindowOpenHandler`. + * + * See `window.open()` for more details and how to use this in conjunction with + * `webContents.setWindowOpenHandler`. + */ + on(event: 'did-create-window', listener: (window: BrowserWindow, + details: DidCreateWindowDetails) => void): this; + once(event: 'did-create-window', listener: (window: BrowserWindow, + details: DidCreateWindowDetails) => void): this; + addListener(event: 'did-create-window', listener: (window: BrowserWindow, + details: DidCreateWindowDetails) => void): this; + removeListener(event: 'did-create-window', listener: (window: BrowserWindow, + details: DidCreateWindowDetails) => void): this; + /** + * This event is like `did-finish-load` but emitted when the load failed. The full + * list of error codes and their meaning is available here. + */ + on(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * This event is like `did-fail-load` but emitted when the load was cancelled (e.g. + * `window.stop()` was invoked). + */ + on(event: 'did-fail-provisional-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-fail-provisional-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-fail-provisional-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-fail-provisional-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * Emitted when the navigation is done, i.e. the spinner of the tab has stopped + * spinning, and the `onload` event was dispatched. + */ + on(event: 'did-finish-load', listener: Function): this; + once(event: 'did-finish-load', listener: Function): this; + addListener(event: 'did-finish-load', listener: Function): this; + removeListener(event: 'did-finish-load', listener: Function): this; + /** + * Emitted when a frame has done navigation. + */ + on(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * Emitted when any frame navigation is done. + * + * This event is not emitted for in-page navigations, such as clicking anchor links + * or updating the `window.location.hash`. Use `did-navigate-in-page` event for + * this purpose. + */ + on(event: 'did-frame-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations, + */ + httpStatusText: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-frame-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations, + */ + httpStatusText: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-frame-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations, + */ + httpStatusText: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-frame-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations, + */ + httpStatusText: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * Emitted when a main frame navigation is done. + * + * This event is not emitted for in-page navigations, such as clicking anchor links + * or updating the `window.location.hash`. Use `did-navigate-in-page` event for + * this purpose. + */ + on(event: 'did-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations + */ + httpStatusText: string) => void): this; + once(event: 'did-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations + */ + httpStatusText: string) => void): this; + addListener(event: 'did-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations + */ + httpStatusText: string) => void): this; + removeListener(event: 'did-navigate', listener: (event: Event, + url: string, + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number, + /** + * empty for non HTTP navigations + */ + httpStatusText: string) => void): this; + /** + * Emitted when an in-page navigation happened in any frame. + * + * When in-page navigation happens, the page URL changes but does not cause + * navigation outside of the page. Examples of this occurring are when anchor links + * are clicked or when the DOM `hashchange` event is triggered. + */ + on(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * Emitted after a server side redirect occurs during navigation. For example a + * 302 redirect. + * + * This event cannot be prevented, if you want to prevent redirects you should + * checkout out the `will-redirect` event above. + */ + on(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * Corresponds to the points in time when the spinner of the tab started spinning. + */ + on(event: 'did-start-loading', listener: Function): this; + once(event: 'did-start-loading', listener: Function): this; + addListener(event: 'did-start-loading', listener: Function): this; + removeListener(event: 'did-start-loading', listener: Function): this; + /** + * Emitted when any frame (including main) starts navigating. `isInPlace` will be + * `true` for in-page navigations. + */ + on(event: 'did-start-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-start-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-start-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-start-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * Corresponds to the points in time when the spinner of the tab stopped spinning. + */ + on(event: 'did-stop-loading', listener: Function): this; + once(event: 'did-stop-loading', listener: Function): this; + addListener(event: 'did-stop-loading', listener: Function): this; + removeListener(event: 'did-stop-loading', listener: Function): this; + /** + * Emitted when the document in the top-level frame is loaded. + */ + on(event: 'dom-ready', listener: (event: Event) => void): this; + once(event: 'dom-ready', listener: (event: Event) => void): this; + addListener(event: 'dom-ready', listener: (event: Event) => void): this; + removeListener(event: 'dom-ready', listener: (event: Event) => void): this; + /** + * Emitted when the window enters a full-screen state triggered by HTML API. + */ + on(event: 'enter-html-full-screen', listener: Function): this; + once(event: 'enter-html-full-screen', listener: Function): this; + addListener(event: 'enter-html-full-screen', listener: Function): this; + removeListener(event: 'enter-html-full-screen', listener: Function): this; + /** + * Emitted when the `WebContents` gains focus. + * + * Note that on macOS, having focus means the `WebContents` is the first responder + * of window, so switching focus between windows would not trigger the `focus` and + * `blur` events of `WebContents`, as the first responder of each window is not + * changed. + * + * The `focus` and `blur` events of `WebContents` should only be used to detect + * focus change between different `WebContents` and `BrowserView` in the same + * window. + */ + on(event: 'focus', listener: Function): this; + once(event: 'focus', listener: Function): this; + addListener(event: 'focus', listener: Function): this; + removeListener(event: 'focus', listener: Function): this; + /** + * Emitted when a result is available for [`webContents.findInPage`] request. + */ + on(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + once(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + addListener(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + removeListener(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + /** + * Emitted when the mainFrame, an `<iframe>`, or a nested `<iframe>` is loaded + * within the page. + */ + on(event: 'frame-created', listener: (event: Event, + details: FrameCreatedDetails) => void): this; + once(event: 'frame-created', listener: (event: Event, + details: FrameCreatedDetails) => void): this; + addListener(event: 'frame-created', listener: (event: Event, + details: FrameCreatedDetails) => void): this; + removeListener(event: 'frame-created', listener: (event: Event, + details: FrameCreatedDetails) => void): this; + /** + * Emitted when the renderer process sends an asynchronous message via + * `ipcRenderer.send()`. + * + * See also `webContents.ipc`, which provides an `IpcMain`-like interface for + * responding to IPC messages specifically from this WebContents. + */ + on(event: 'ipc-message', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + once(event: 'ipc-message', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + addListener(event: 'ipc-message', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + removeListener(event: 'ipc-message', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + /** + * Emitted when the renderer process sends a synchronous message via + * `ipcRenderer.sendSync()`. + * + * See also `webContents.ipc`, which provides an `IpcMain`-like interface for + * responding to IPC messages specifically from this WebContents. + */ + on(event: 'ipc-message-sync', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + once(event: 'ipc-message-sync', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + addListener(event: 'ipc-message-sync', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + removeListener(event: 'ipc-message-sync', listener: (event: Event, + channel: string, + ...args: any[]) => void): this; + /** + * Emitted when the window leaves a full-screen state triggered by HTML API. + */ + on(event: 'leave-html-full-screen', listener: Function): this; + once(event: 'leave-html-full-screen', listener: Function): this; + addListener(event: 'leave-html-full-screen', listener: Function): this; + removeListener(event: 'leave-html-full-screen', listener: Function): this; + /** + * Emitted when `webContents` wants to do basic auth. + * + * The usage is the same with the `login` event of `app`. + */ + on(event: 'login', listener: (event: Event, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + once(event: 'login', listener: (event: Event, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + addListener(event: 'login', listener: (event: Event, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + removeListener(event: 'login', listener: (event: Event, + authenticationResponseDetails: AuthenticationResponseDetails, + authInfo: AuthInfo, + callback: (username?: string, password?: string) => void) => void): this; + /** + * Emitted when media is paused or done playing. + */ + on(event: 'media-paused', listener: Function): this; + once(event: 'media-paused', listener: Function): this; + addListener(event: 'media-paused', listener: Function): this; + removeListener(event: 'media-paused', listener: Function): this; + /** + * Emitted when media starts playing. + */ + on(event: 'media-started-playing', listener: Function): this; + once(event: 'media-started-playing', listener: Function): this; + addListener(event: 'media-started-playing', listener: Function): this; + removeListener(event: 'media-started-playing', listener: Function): this; + /** + * Deprecated in favor of `webContents.setWindowOpenHandler`. + * + * Emitted when the page requests to open a new window for a `url`. It could be + * requested by `window.open` or an external link like `<a target='_blank'>`. + * + * By default a new `BrowserWindow` will be created for the `url`. + * + * Calling `event.preventDefault()` will prevent Electron from automatically + * creating a new `BrowserWindow`. If you call `event.preventDefault()` and + * manually create a new `BrowserWindow` then you must set `event.newGuest` to + * reference the new `BrowserWindow` instance, failing to do so may result in + * unexpected behavior. For example: + * + * @deprecated + */ + on(event: 'new-window', listener: (event: NewWindowWebContentsEvent, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: BrowserWindowConstructorOptions, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. Deprecated, and will now always be the empty array `[]`. + */ + additionalFeatures: string[], + /** + * The referrer that will be passed to the new window. May or may not result in the + * `Referer` header being sent, depending on the referrer policy. + */ + referrer: Referrer, + /** + * The post data that will be sent to the new window, along with the appropriate + * headers that will be set. If no post data is to be sent, the value will be + * `null`. Only defined when the window is being created by a form that set + * `target=_blank`. + */ + postBody: PostBody) => void): this; + once(event: 'new-window', listener: (event: NewWindowWebContentsEvent, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: BrowserWindowConstructorOptions, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. Deprecated, and will now always be the empty array `[]`. + */ + additionalFeatures: string[], + /** + * The referrer that will be passed to the new window. May or may not result in the + * `Referer` header being sent, depending on the referrer policy. + */ + referrer: Referrer, + /** + * The post data that will be sent to the new window, along with the appropriate + * headers that will be set. If no post data is to be sent, the value will be + * `null`. Only defined when the window is being created by a form that set + * `target=_blank`. + */ + postBody: PostBody) => void): this; + addListener(event: 'new-window', listener: (event: NewWindowWebContentsEvent, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: BrowserWindowConstructorOptions, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. Deprecated, and will now always be the empty array `[]`. + */ + additionalFeatures: string[], + /** + * The referrer that will be passed to the new window. May or may not result in the + * `Referer` header being sent, depending on the referrer policy. + */ + referrer: Referrer, + /** + * The post data that will be sent to the new window, along with the appropriate + * headers that will be set. If no post data is to be sent, the value will be + * `null`. Only defined when the window is being created by a form that set + * `target=_blank`. + */ + postBody: PostBody) => void): this; + removeListener(event: 'new-window', listener: (event: NewWindowWebContentsEvent, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: BrowserWindowConstructorOptions, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. Deprecated, and will now always be the empty array `[]`. + */ + additionalFeatures: string[], + /** + * The referrer that will be passed to the new window. May or may not result in the + * `Referer` header being sent, depending on the referrer policy. + */ + referrer: Referrer, + /** + * The post data that will be sent to the new window, along with the appropriate + * headers that will be set. If no post data is to be sent, the value will be + * `null`. Only defined when the window is being created by a form that set + * `target=_blank`. + */ + postBody: PostBody) => void): this; + /** + * Emitted when page receives favicon urls. + */ + on(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs. + */ + favicons: string[]) => void): this; + once(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs. + */ + favicons: string[]) => void): this; + addListener(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs. + */ + favicons: string[]) => void): this; + removeListener(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs. + */ + favicons: string[]) => void): this; + /** + * Fired when page title is set during navigation. `explicitSet` is false when + * title is synthesized from file url. + */ + on(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + once(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + addListener(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + removeListener(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + /** + * Emitted when a new frame is generated. Only the dirty area is passed in the + * buffer. + */ + on(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + once(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + addListener(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + removeListener(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + /** + * Emitted when a plugin process has crashed. + */ + on(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + once(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + addListener(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + removeListener(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + /** + * Emitted when the `WebContents` preferred size has changed. + * + * This event will only be emitted when `enablePreferredSizeMode` is set to `true` + * in `webPreferences`. + */ + on(event: 'preferred-size-changed', listener: (event: Event, + /** + * The minimum size needed to contain the layout of the documentβ€”without requiring + * scrolling. + */ + preferredSize: Size) => void): this; + once(event: 'preferred-size-changed', listener: (event: Event, + /** + * The minimum size needed to contain the layout of the documentβ€”without requiring + * scrolling. + */ + preferredSize: Size) => void): this; + addListener(event: 'preferred-size-changed', listener: (event: Event, + /** + * The minimum size needed to contain the layout of the documentβ€”without requiring + * scrolling. + */ + preferredSize: Size) => void): this; + removeListener(event: 'preferred-size-changed', listener: (event: Event, + /** + * The minimum size needed to contain the layout of the documentβ€”without requiring + * scrolling. + */ + preferredSize: Size) => void): this; + /** + * Emitted when the preload script `preloadPath` throws an unhandled exception + * `error`. + */ + on(event: 'preload-error', listener: (event: Event, + preloadPath: string, + error: Error) => void): this; + once(event: 'preload-error', listener: (event: Event, + preloadPath: string, + error: Error) => void): this; + addListener(event: 'preload-error', listener: (event: Event, + preloadPath: string, + error: Error) => void): this; + removeListener(event: 'preload-error', listener: (event: Event, + preloadPath: string, + error: Error) => void): this; + /** + * Emitted when the renderer process unexpectedly disappears. This is normally + * because it was crashed or killed. + */ + on(event: 'render-process-gone', listener: (event: Event, + details: RenderProcessGoneDetails) => void): this; + once(event: 'render-process-gone', listener: (event: Event, + details: RenderProcessGoneDetails) => void): this; + addListener(event: 'render-process-gone', listener: (event: Event, + details: RenderProcessGoneDetails) => void): this; + removeListener(event: 'render-process-gone', listener: (event: Event, + details: RenderProcessGoneDetails) => void): this; + /** + * Emitted when the unresponsive web page becomes responsive again. + */ + on(event: 'responsive', listener: Function): this; + once(event: 'responsive', listener: Function): this; + addListener(event: 'responsive', listener: Function): this; + removeListener(event: 'responsive', listener: Function): this; + /** + * Emitted when bluetooth device needs to be selected on call to + * `navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api + * `webBluetooth` should be enabled. If `event.preventDefault` is not called, first + * available device will be selected. `callback` should be called with `deviceId` + * to be selected, passing empty string to `callback` will cancel the request. + * + * If no event listener is added for this event, all bluetooth requests will be + * cancelled. + */ + on(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + once(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + addListener(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + removeListener(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + /** + * Emitted when a client certificate is requested. + * + * The usage is the same with the `select-client-certificate` event of `app`. + */ + on(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + once(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + addListener(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + removeListener(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + /** + * Emitted when the web page becomes unresponsive. + */ + on(event: 'unresponsive', listener: Function): this; + once(event: 'unresponsive', listener: Function): this; + addListener(event: 'unresponsive', listener: Function): this; + removeListener(event: 'unresponsive', listener: Function): this; + /** + * Emitted when mouse moves over a link or the keyboard moves the focus to a link. + */ + on(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + once(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + addListener(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + removeListener(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + /** + * Emitted when a `<webview>`'s web contents is being attached to this web + * contents. Calling `event.preventDefault()` will destroy the guest page. + * + * This event can be used to configure `webPreferences` for the `webContents` of a + * `<webview>` before it's loaded, and provides the ability to set settings that + * can't be set via `<webview>` attributes. + */ + on(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: WebPreferences, + /** + * The other `<webview>` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: Record<string, string>) => void): this; + once(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: WebPreferences, + /** + * The other `<webview>` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: Record<string, string>) => void): this; + addListener(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: WebPreferences, + /** + * The other `<webview>` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: Record<string, string>) => void): this; + removeListener(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: WebPreferences, + /** + * The other `<webview>` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: Record<string, string>) => void): this; + /** + * Emitted when a user or the page wants to start navigation. It can happen when + * the `window.location` object is changed or a user clicks a link in the page. + * + * This event will not emit when the navigation is started programmatically with + * APIs like `webContents.loadURL` and `webContents.back`. + * + * It is also not emitted for in-page navigations, such as clicking anchor links or + * updating the `window.location.hash`. Use `did-navigate-in-page` event for this + * purpose. + * + * Calling `event.preventDefault()` will prevent the navigation. + */ + on(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + once(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + addListener(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + removeListener(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + /** + * Emitted when a `beforeunload` event handler is attempting to cancel a page + * unload. + * + * Calling `event.preventDefault()` will ignore the `beforeunload` event handler + * and allow the page to be unloaded. + * + * **Note:** This will be emitted for `BrowserViews` but will _not_ be respected - + * this is because we have chosen not to tie the `BrowserView` lifecycle to its + * owning BrowserWindow should one exist per the specification. + */ + on(event: 'will-prevent-unload', listener: (event: Event) => void): this; + once(event: 'will-prevent-unload', listener: (event: Event) => void): this; + addListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; + removeListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; + /** + * Emitted when a server side redirect occurs during navigation. For example a 302 + * redirect. + * + * This event will be emitted after `did-start-navigation` and always before the + * `did-redirect-navigation` event for the same navigation. + * + * Calling `event.preventDefault()` will prevent the navigation (not just the + * redirect). + */ + on(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + /** + * Emitted when the user is requesting to change the zoom level using the mouse + * wheel. + */ + on(event: 'zoom-changed', listener: (event: Event, + /** + * Can be `in` or `out`. + */ + zoomDirection: ('in' | 'out')) => void): this; + once(event: 'zoom-changed', listener: (event: Event, + /** + * Can be `in` or `out`. + */ + zoomDirection: ('in' | 'out')) => void): this; + addListener(event: 'zoom-changed', listener: (event: Event, + /** + * Can be `in` or `out`. + */ + zoomDirection: ('in' | 'out')) => void): this; + removeListener(event: 'zoom-changed', listener: (event: Event, + /** + * Can be `in` or `out`. + */ + zoomDirection: ('in' | 'out')) => void): this; + /** + * Adds the specified path to DevTools workspace. Must be used after DevTools + * creation: + */ + addWorkSpace(path: string): void; + /** + * Begin subscribing for presentation events and captured frames, the `callback` + * will be called with `callback(image, dirtyRect)` when there is a presentation + * event. + * + * The `image` is an instance of NativeImage that stores the captured frame. + * + * The `dirtyRect` is an object with `x, y, width, height` properties that + * describes which part of the page was repainted. If `onlyDirty` is set to `true`, + * `image` will only contain the repainted area. `onlyDirty` defaults to `false`. + */ + beginFrameSubscription(onlyDirty: boolean, callback: (image: NativeImage, dirtyRect: Rectangle) => void): void; + /** + * Begin subscribing for presentation events and captured frames, the `callback` + * will be called with `callback(image, dirtyRect)` when there is a presentation + * event. + * + * The `image` is an instance of NativeImage that stores the captured frame. + * + * The `dirtyRect` is an object with `x, y, width, height` properties that + * describes which part of the page was repainted. If `onlyDirty` is set to `true`, + * `image` will only contain the repainted area. `onlyDirty` defaults to `false`. + */ + beginFrameSubscription(callback: (image: NativeImage, dirtyRect: Rectangle) => void): void; + /** + * Whether the browser can go back to previous web page. + */ + canGoBack(): boolean; + /** + * Whether the browser can go forward to next web page. + */ + canGoForward(): boolean; + /** + * Whether the web page can go to `offset`. + */ + canGoToOffset(offset: number): boolean; + /** + * Resolves with a NativeImage + * + * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the + * whole visible page. + */ + capturePage(rect?: Rectangle): Promise<Electron.NativeImage>; + /** + * Clears the navigation history. + */ + clearHistory(): void; + /** + * Closes the devtools. + */ + closeDevTools(): void; + /** + * Executes the editing command `copy` in web page. + */ + copy(): void; + /** + * Copy the image at the given position to the clipboard. + */ + copyImageAt(x: number, y: number): void; + /** + * Executes the editing command `cut` in web page. + */ + cut(): void; + /** + * Decrease the capturer count by one. The page will be set to hidden or occluded + * state when its browser window is hidden or occluded and the capturer count + * reaches zero. If you want to decrease the hidden capturer count instead you + * should set `stayHidden` to true. + */ + decrementCapturerCount(stayHidden?: boolean, stayAwake?: boolean): void; + /** + * Executes the editing command `delete` in web page. + */ + delete(): void; + /** + * Disable device emulation enabled by `webContents.enableDeviceEmulation`. + */ + disableDeviceEmulation(): void; + /** + * Initiates a download of the resource at `url` without navigating. The + * `will-download` event of `session` will be triggered. + */ + downloadURL(url: string): void; + /** + * Enable device emulation with the given parameters. + */ + enableDeviceEmulation(parameters: Parameters): void; + /** + * End subscribing for frame presentation events. + */ + endFrameSubscription(): void; + /** + * A promise that resolves with the result of the executed code or is rejected if + * the result of the code is a rejected promise. + * + * Evaluates `code` in page. + * + * In the browser window some HTML APIs like `requestFullScreen` can only be + * invoked by a gesture from the user. Setting `userGesture` to `true` will remove + * this limitation. + * + * Code execution will be suspended until web page stop loading. + */ + executeJavaScript(code: string, userGesture?: boolean): Promise<any>; + /** + * A promise that resolves with the result of the executed code or is rejected if + * the result of the code is a rejected promise. + * + * Works like `executeJavaScript` but evaluates `scripts` in an isolated context. + */ + executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean): Promise<any>; + /** + * The request id used for the request. + * + * Starts a request to find all matches for the `text` in the web page. The result + * of the request can be obtained by subscribing to `found-in-page` event. + */ + findInPage(text: string, options?: FindInPageOptions): number; + /** + * Focuses the web page. + */ + focus(): void; + /** + * Forcefully terminates the renderer process that is currently hosting this + * `webContents`. This will cause the `render-process-gone` event to be emitted + * with the `reason=killed || reason=crashed`. Please note that some webContents + * share renderer processes and therefore calling this method may also crash the + * host process for other webContents as well. + * + * Calling `reload()` immediately after calling this method will force the reload + * to occur in a new process. This should be used when this process is unstable or + * unusable, for instance in order to recover from the `unresponsive` event. + */ + forcefullyCrashRenderer(): void; + /** + * Information about all Shared Workers. + */ + getAllSharedWorkers(): SharedWorkerInfo[]; + /** + * whether or not this WebContents will throttle animations and timers when the + * page becomes backgrounded. This also affects the Page Visibility API. + */ + getBackgroundThrottling(): boolean; + /** + * If *offscreen rendering* is enabled returns the current frame rate. + */ + getFrameRate(): number; + /** + * The identifier of a WebContents stream. This identifier can be used with + * `navigator.mediaDevices.getUserMedia` using a `chromeMediaSource` of `tab`. The + * identifier is restricted to the web contents that it is registered to and is + * only valid for 10 seconds. + */ + getMediaSourceId(requestWebContents: WebContents): string; + /** + * The operating system `pid` of the associated renderer process. + */ + getOSProcessId(): number; + /** + * Get the system printer list. + * + * + * **Deprecated:** Should use the new `contents.getPrintersAsync` API. + * + * @deprecated + */ + getPrinters(): PrinterInfo[]; + /** + * Get the system printer list. + * + * Resolves with a `PrinterInfo[]` + */ + getPrintersAsync(): Promise<Electron.PrinterInfo[]>; + /** + * The Chromium internal `pid` of the associated renderer. Can be compared to the + * `frameProcessId` passed by frame specific navigation events (e.g. + * `did-frame-navigate`) + */ + getProcessId(): number; + /** + * The title of the current web page. + */ + getTitle(): string; + /** + * the type of the webContent. Can be `backgroundPage`, `window`, `browserView`, + * `remote`, `webview` or `offscreen`. + */ + getType(): ('backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'); + /** + * The URL of the current web page. + */ + getURL(): string; + /** + * The user agent for this web page. + */ + getUserAgent(): string; + /** + * Returns the WebRTC IP Handling Policy. + */ + getWebRTCIPHandlingPolicy(): string; + /** + * the current zoom factor. + */ + getZoomFactor(): number; + /** + * the current zoom level. + */ + getZoomLevel(): number; + /** + * Makes the browser go back a web page. + */ + goBack(): void; + /** + * Makes the browser go forward a web page. + */ + goForward(): void; + /** + * Navigates browser to the specified absolute web page index. + */ + goToIndex(index: number): void; + /** + * Navigates to the specified offset from the "current entry". + */ + goToOffset(offset: number): void; + /** + * Increase the capturer count by one. The page is considered visible when its + * browser window is hidden and the capturer count is non-zero. If you would like + * the page to stay hidden, you should ensure that `stayHidden` is set to true. + * + * This also affects the Page Visibility API. + */ + incrementCapturerCount(size?: Size, stayHidden?: boolean, stayAwake?: boolean): void; + /** + * A promise that resolves with a key for the inserted CSS that can later be used + * to remove the CSS via `contents.removeInsertedCSS(key)`. + * + * Injects CSS into the current web page and returns a unique key for the inserted + * stylesheet. + */ + insertCSS(css: string, options?: InsertCSSOptions): Promise<string>; + /** + * Inserts `text` to the focused element. + */ + insertText(text: string): Promise<void>; + /** + * Starts inspecting element at position (`x`, `y`). + */ + inspectElement(x: number, y: number): void; + /** + * Opens the developer tools for the service worker context. + */ + inspectServiceWorker(): void; + /** + * Opens the developer tools for the shared worker context. + */ + inspectSharedWorker(): void; + /** + * Inspects the shared worker based on its ID. + */ + inspectSharedWorkerById(workerId: string): void; + /** + * Schedules a full repaint of the window this web contents is in. + * + * If *offscreen rendering* is enabled invalidates the frame and generates a new + * one through the `'paint'` event. + */ + invalidate(): void; + /** + * Whether this page has been muted. + */ + isAudioMuted(): boolean; + /** + * Whether this page is being captured. It returns true when the capturer count is + * large then 0. + */ + isBeingCaptured(): boolean; + /** + * Whether the renderer process has crashed. + */ + isCrashed(): boolean; + /** + * Whether audio is currently playing. + */ + isCurrentlyAudible(): boolean; + /** + * Whether the web page is destroyed. + */ + isDestroyed(): boolean; + /** + * Whether the devtools view is focused . + */ + isDevToolsFocused(): boolean; + /** + * Whether the devtools is opened. + */ + isDevToolsOpened(): boolean; + /** + * Whether the web page is focused. + */ + isFocused(): boolean; + /** + * Whether web page is still loading resources. + */ + isLoading(): boolean; + /** + * Whether the main frame (and not just iframes or frames within it) is still + * loading. + */ + isLoadingMainFrame(): boolean; + /** + * Indicates whether *offscreen rendering* is enabled. + */ + isOffscreen(): boolean; + /** + * If *offscreen rendering* is enabled returns whether it is currently painting. + */ + isPainting(): boolean; + /** + * Whether the web page is waiting for a first-response from the main resource of + * the page. + */ + isWaitingForResponse(): boolean; + /** + * the promise will resolve when the page has finished loading (see + * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). + * + * Loads the given file in the window, `filePath` should be a path to an HTML file + * relative to the root of your application. For instance an app structure like + * this: + * + * Would require code like this + */ + loadFile(filePath: string, options?: LoadFileOptions): Promise<void>; + /** + * the promise will resolve when the page has finished loading (see + * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). + * A noop rejection handler is already attached, which avoids unhandled rejection + * errors. + * + * Loads the `url` in the window. The `url` must contain the protocol prefix, e.g. + * the `http://` or `file://`. If the load should bypass http cache then use the + * `pragma` header to achieve it. + */ + loadURL(url: string, options?: LoadURLOptions): Promise<void>; + /** + * Opens the devtools. + * + * When `contents` is a `<webview>` tag, the `mode` would be `detach` by default, + * explicitly passing an empty `mode` can force using last used dock state. + * + * On Windows, if Windows Control Overlay is enabled, Devtools will be opened with + * `mode: 'detach'`. + */ + openDevTools(options?: OpenDevToolsOptions): void; + /** + * Executes the editing command `paste` in web page. + */ + paste(): void; + /** + * Executes the editing command `pasteAndMatchStyle` in web page. + */ + pasteAndMatchStyle(): void; + /** + * Send a message to the renderer process, optionally transferring ownership of + * zero or more [`MessagePortMain`][] objects. + * + * The transferred `MessagePortMain` objects will be available in the renderer + * process by accessing the `ports` property of the emitted event. When they arrive + * in the renderer, they will be native DOM `MessagePort` objects. + * + * For example: + */ + postMessage(channel: string, message: any, transfer?: MessagePortMain[]): void; + /** + * When a custom `pageSize` is passed, Chromium attempts to validate platform + * specific minimum values for `width_microns` and `height_microns`. Width and + * height must both be minimum 353 microns but may be higher on some operating + * systems. + * + * Prints window's web page. When `silent` is set to `true`, Electron will pick the + * system's default printer if `deviceName` is empty and the default settings for + * printing. + * + * Use `page-break-before: always;` CSS style to force to print to a new page. + * + * Example usage: + */ + print(options?: WebContentsPrintOptions, callback?: (success: boolean, failureReason: string) => void): void; + /** + * Resolves with the generated PDF data. + * + * Prints the window's web page as PDF. + * + * The `landscape` will be ignored if `@page` CSS at-rule is used in the web page. + * + * An example of `webContents.printToPDF`: + * + * See Page.printToPdf for more information. + */ + printToPDF(options: PrintToPDFOptions): Promise<Buffer>; + /** + * Executes the editing command `redo` in web page. + */ + redo(): void; + /** + * Reloads the current web page. + */ + reload(): void; + /** + * Reloads current page and ignores cache. + */ + reloadIgnoringCache(): void; + /** + * Resolves if the removal was successful. + * + * Removes the inserted CSS from the current web page. The stylesheet is identified + * by its key, which is returned from `contents.insertCSS(css)`. + */ + removeInsertedCSS(key: string): Promise<void>; + /** + * Removes the specified path from DevTools workspace. + */ + removeWorkSpace(path: string): void; + /** + * Executes the editing command `replace` in web page. + */ + replace(text: string): void; + /** + * Executes the editing command `replaceMisspelling` in web page. + */ + replaceMisspelling(text: string): void; + /** + * resolves if the page is saved. + */ + savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML'): Promise<void>; + /** + * Executes the editing command `selectAll` in web page. + */ + selectAll(): void; + /** + * Send an asynchronous message to the renderer process via `channel`, along with + * arguments. Arguments will be serialized with the Structured Clone Algorithm, + * just like `postMessage`, so prototype chains will not be included. Sending + * Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. + * + * > **NOTE**: Sending non-standard JavaScript types such as DOM objects or special + * Electron objects will throw an exception. + * + * The renderer process can handle the message by listening to `channel` with the + * `ipcRenderer` module. + * + * An example of sending messages from the main process to the renderer process: + */ + send(channel: string, ...args: any[]): void; + /** + * Sends an input `event` to the page. **Note:** The `BrowserWindow` containing the + * contents needs to be focused for `sendInputEvent()` to work. + */ + sendInputEvent(inputEvent: (MouseInputEvent) | (MouseWheelInputEvent) | (KeyboardInputEvent)): void; + /** + * Send an asynchronous message to a specific frame in a renderer process via + * `channel`, along with arguments. Arguments will be serialized with the + * Structured Clone Algorithm, just like `postMessage`, so prototype chains will + * not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets + * will throw an exception. + * + * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + * Electron objects will throw an exception. + * + * The renderer process can handle the message by listening to `channel` with the + * `ipcRenderer` module. + * + * If you want to get the `frameId` of a given renderer context you should use the + * `webFrame.routingId` value. E.g. + * + * You can also read `frameId` from all incoming IPC messages in the main process. + */ + sendToFrame(frameId: (number) | ([number, number]), channel: string, ...args: any[]): void; + /** + * Mute the audio on the current web page. + */ + setAudioMuted(muted: boolean): void; + /** + * Controls whether or not this WebContents will throttle animations and timers + * when the page becomes backgrounded. This also affects the Page Visibility API. + */ + setBackgroundThrottling(allowed: boolean): void; + /** + * Uses the `devToolsWebContents` as the target `WebContents` to show devtools. + * + * The `devToolsWebContents` must not have done any navigation, and it should not + * be used for other purposes after the call. + * + * By default Electron manages the devtools by creating an internal `WebContents` + * with native view, which developers have very limited control of. With the + * `setDevToolsWebContents` method, developers can use any `WebContents` to show + * the devtools in it, including `BrowserWindow`, `BrowserView` and `<webview>` + * tag. + * + * Note that closing the devtools does not destroy the `devToolsWebContents`, it is + * caller's responsibility to destroy `devToolsWebContents`. + * + * An example of showing devtools in a `<webview>` tag: + * + * An example of showing devtools in a `BrowserWindow`: + */ + setDevToolsWebContents(devToolsWebContents: WebContents): void; + /** + * If *offscreen rendering* is enabled sets the frame rate to the specified number. + * Only values between 1 and 240 are accepted. + */ + setFrameRate(fps: number): void; + /** + * Ignore application menu shortcuts while this web contents is focused. + */ + setIgnoreMenuShortcuts(ignore: boolean): void; + /** + * Sets the image animation policy for this webContents. The policy only affects + * _new_ images, existing images that are currently being animated are unaffected. + * This is a known limitation in Chromium, you can force image animation to be + * recalculated with `img.src = img.src` which will result in no network traffic + * but will update the animation policy. + * + * This corresponds to the animationPolicy accessibility feature in Chromium. + */ + setImageAnimationPolicy(policy: 'animate' | 'animateOnce' | 'noAnimation'): void; + /** + * Overrides the user agent for this web page. + */ + setUserAgent(userAgent: string): void; + /** + * Sets the maximum and minimum pinch-to-zoom level. + * + * > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, + * call: + */ + setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): Promise<void>; + /** + * Setting the WebRTC IP handling policy allows you to control which IPs are + * exposed via WebRTC. See BrowserLeaks for more details. + */ + setWebRTCIPHandlingPolicy(policy: 'default' | 'default_public_interface_only' | 'default_public_and_private_interfaces' | 'disable_non_proxied_udp'): void; + /** + * Called before creating a window a new window is requested by the renderer, e.g. + * by `window.open()`, a link with `target="_blank"`, shift+clicking on a link, or + * submitting a form with `<form target="_blank">`. See `window.open()` for more + * details and how to use this in conjunction with `did-create-window`. + */ + setWindowOpenHandler(handler: (details: HandlerDetails) => ({action: 'deny'}) | ({action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions})): void; + /** + * Changes the zoom factor to the specified factor. Zoom factor is zoom percent + * divided by 100, so 300% = 3.0. + * + * The factor must be greater than 0.0. + */ + setZoomFactor(factor: number): void; + /** + * Changes the zoom level to the specified level. The original size is 0 and each + * increment above or below represents zooming 20% larger or smaller to default + * limits of 300% and 50% of original size, respectively. The formula for this is + * `scale := 1.2 ^ level`. + * + * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that + * the zoom level for a specific domain propagates across all instances of windows + * with the same domain. Differentiating the window URLs will make zoom work + * per-window. + */ + setZoomLevel(level: number): void; + /** + * Shows pop-up dictionary that searches the selected word on the page. + * + * @platform darwin + */ + showDefinitionForSelection(): void; + /** + * Sets the `item` as dragging item for current drag-drop operation, `file` is the + * absolute path of the file to be dragged, and `icon` is the image showing under + * the cursor when dragging. + */ + startDrag(item: Item): void; + /** + * If *offscreen rendering* is enabled and not painting, start painting. + */ + startPainting(): void; + /** + * Stops any pending navigation. + */ + stop(): void; + /** + * Stops any `findInPage` request for the `webContents` with the provided `action`. + */ + stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; + /** + * If *offscreen rendering* is enabled and painting, stop painting. + */ + stopPainting(): void; + /** + * Indicates whether the snapshot has been created successfully. + * + * Takes a V8 heap snapshot and saves it to `filePath`. + */ + takeHeapSnapshot(filePath: string): Promise<void>; + /** + * Toggles the developer tools. + */ + toggleDevTools(): void; + /** + * Executes the editing command `undo` in web page. + */ + undo(): void; + /** + * Executes the editing command `unselect` in web page. + */ + unselect(): void; + /** + * A `boolean` property that determines whether this page is muted. + */ + audioMuted: boolean; + /** + * A `boolean` property that determines whether or not this WebContents will + * throttle animations and timers when the page becomes backgrounded. This also + * affects the Page Visibility API. + */ + backgroundThrottling: boolean; + /** + * A `Debugger` instance for this webContents. + * + */ + readonly debugger: Debugger; + /** + * A `WebContents | null` property that represents the of DevTools `WebContents` + * associated with a given `WebContents`. + * + * **Note:** Users should never store this object because it may become `null` when + * the DevTools has been closed. + * + */ + readonly devToolsWebContents: (WebContents) | (null); + /** + * An `Integer` property that sets the frame rate of the web contents to the + * specified number. Only values between 1 and 240 are accepted. + * + * Only applicable if *offscreen rendering* is enabled. + */ + frameRate: number; + /** + * A `WebContents` instance that might own this `WebContents`. + * + */ + readonly hostWebContents: WebContents; + /** + * A `Integer` representing the unique ID of this WebContents. Each ID is unique + * among all `WebContents` instances of the entire Electron application. + * + */ + readonly id: number; + /** + * An `IpcMain` 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: + * + * * `contents.on('ipc-message')` + * * `contents.mainFrame.on(channel)` + * * `contents.ipc.on(channel)` + * * `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. + * + * * `contents.mainFrame.handle(channel)` + * * `contents.handle(channel)` + * * `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` + * interface. + * + */ + readonly ipc: IpcMain; + /** + * A `WebFrameMain` property that represents the top frame of the page's frame + * hierarchy. + * + */ + readonly mainFrame: WebFrameMain; + /** + * A `WebFrameMain` property that represents the frame that opened this + * WebContents, either with open(), or by navigating a link with a target + * attribute. + * + */ + readonly opener: WebFrameMain; + /** + * A `Session` used by this webContents. + * + */ + readonly session: Session; + /** + * A `string` property that determines the user agent for this web page. + */ + userAgent: string; + /** + * A `number` property that determines the zoom factor for this web contents. + * + * The zoom factor is the zoom percent divided by 100, so 300% = 3.0. + */ + zoomFactor: number; + /** + * A `number` property that determines the zoom level for this web contents. + * + * The original size is 0 and each increment above or below represents zooming 20% + * larger or smaller to default limits of 300% and 50% of original size, + * respectively. The formula for this is `scale := 1.2 ^ level`. + */ + zoomLevel: number; + } + + interface WebFrame extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/web-frame + + /** + * Attempts to free memory that is no longer being used (like images from a + * previous navigation). + * + * Note that blindly calling this method probably makes Electron slower since it + * will have to refill these emptied caches, you should only call it if an event in + * your app has occurred that makes you think your page is actually using less + * memory (i.e. you have navigated from a super heavy page to a mostly empty one, + * and intend to stay there). + */ + clearCache(): void; + /** + * A promise that resolves with the result of the executed code or is rejected if + * execution throws or results in a rejected promise. + * + * Evaluates `code` in page. + * + * In the browser window some HTML APIs like `requestFullScreen` can only be + * invoked by a gesture from the user. Setting `userGesture` to `true` will remove + * this limitation. + */ + executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise<any>; + /** + * A promise that resolves with the result of the executed code or is rejected if + * execution could not start. + * + * Works like `executeJavaScript` but evaluates `scripts` in an isolated context. + * + * Note that when the execution of script fails, the returned promise will not + * reject and the `result` would be `undefined`. This is because Chromium does not + * dispatch errors of isolated worlds to foreign worlds. + */ + executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise<any>; + /** + * A child of `webFrame` with the supplied `name`, `null` would be returned if + * there's no such frame or if the frame is not in the current renderer process. + */ + findFrameByName(name: string): WebFrame; + /** + * that has the supplied `routingId`, `null` if not found. + */ + findFrameByRoutingId(routingId: number): WebFrame; + /** + * The frame element in `webFrame's` document selected by `selector`, `null` would + * be returned if `selector` does not select a frame or if the frame is not in the + * current renderer process. + */ + getFrameForSelector(selector: string): WebFrame; + /** + * * `images` MemoryUsageDetails + * * `scripts` MemoryUsageDetails + * * `cssStyleSheets` MemoryUsageDetails + * * `xslStyleSheets` MemoryUsageDetails + * * `fonts` MemoryUsageDetails + * * `other` MemoryUsageDetails + * + * Returns an object describing usage information of Blink's internal memory + * caches. + * + * This will generate: + */ + getResourceUsage(): ResourceUsage; + /** + * A list of suggested words for a given word. If the word is spelled correctly, + * the result will be empty. + */ + getWordSuggestions(word: string): string[]; + /** + * The current zoom factor. + */ + getZoomFactor(): number; + /** + * The current zoom level. + */ + getZoomLevel(): number; + /** + * A key for the inserted CSS that can later be used to remove the CSS via + * `webFrame.removeInsertedCSS(key)`. + * + * Injects CSS into the current web page and returns a unique key for the inserted + * stylesheet. + */ + insertCSS(css: string, options?: InsertCSSOptions): string; + /** + * Inserts `text` to the focused element. + */ + insertText(text: string): void; + /** + * True if the word is misspelled according to the built in spellchecker, false + * otherwise. If no dictionary is loaded, always return false. + */ + isWordMisspelled(word: string): boolean; + /** + * Removes the inserted CSS from the current web page. The stylesheet is identified + * by its key, which is returned from `webFrame.insertCSS(css)`. + */ + removeInsertedCSS(key: string): void; + /** + * Set the security origin, content security policy and name of the isolated world. + * Note: If the `csp` is specified, then the `securityOrigin` also has to be + * specified. + */ + setIsolatedWorldInfo(worldId: number, info: Info): void; + /** + * Sets a provider for spell checking in input fields and text areas. + * + * If you want to use this method you must disable the builtin spellchecker when + * you construct the window. + * + * The `provider` must be an object that has a `spellCheck` method that accepts an + * array of individual words for spellchecking. The `spellCheck` function runs + * asynchronously and calls the `callback` function with an array of misspelt words + * when complete. + * + * An example of using node-spellchecker as provider: + */ + setSpellCheckProvider(language: string, provider: Provider): void; + /** + * Sets the maximum and minimum pinch-to-zoom level. + * + * > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, + * call: + * + * > **NOTE**: Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom + * shortcuts are controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem + * roles in the application Menu. To disable shortcuts, manually define the Menu + * and omit zoom roles from the definition. + */ + setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + /** + * Changes the zoom factor to the specified factor. Zoom factor is zoom percent + * divided by 100, so 300% = 3.0. + * + * The factor must be greater than 0.0. + */ + setZoomFactor(factor: number): void; + /** + * Changes the zoom level to the specified level. The original size is 0 and each + * increment above or below represents zooming 20% larger or smaller to default + * limits of 300% and 50% of original size, respectively. + * + * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that + * the zoom level for a specific domain propagates across all instances of windows + * with the same domain. Differentiating the window URLs will make zoom work + * per-window. + */ + setZoomLevel(level: number): void; + /** + * A `WebFrame | null` representing the first child frame of `webFrame`, the + * property would be `null` if `webFrame` has no children or if first child is not + * in the current renderer process. + * + */ + readonly firstChild: (WebFrame) | (null); + /** + * A `WebFrame | null` representing next sibling frame, the property would be + * `null` if `webFrame` is the last frame in its parent or if the next sibling is + * not in the current renderer process. + * + */ + readonly nextSibling: (WebFrame) | (null); + /** + * A `WebFrame | null` representing the frame which opened `webFrame`, the property + * would be `null` if there's no opener or opener is not in the current renderer + * process. + * + */ + readonly opener: (WebFrame) | (null); + /** + * A `WebFrame | null` representing parent frame of `webFrame`, the property would + * be `null` if `webFrame` is top or parent is not in the current renderer process. + * + */ + readonly parent: (WebFrame) | (null); + /** + * An `Integer` representing the unique frame id in the current renderer process. + * Distinct WebFrame instances that refer to the same underlying frame will have + * the same `routingId`. + * + */ + readonly routingId: number; + /** + * A `WebFrame | null` representing top frame in frame hierarchy to which + * `webFrame` belongs, the property would be `null` if top frame is not in the + * current renderer process. + * + */ + readonly top: (WebFrame) | (null); + } + + class WebFrameMain extends NodeEventEmitter { + + // Docs: https://electronjs.org/docs/api/web-frame-main + + /** + * A frame with the given process and routing IDs, or `undefined` if there is no + * WebFrameMain associated with the given IDs. + */ + static fromId(processId: number, routingId: number): (WebFrameMain) | (undefined); + /** + * Emitted when the document is loaded. + */ + on(event: 'dom-ready', listener: Function): this; + once(event: 'dom-ready', listener: Function): this; + addListener(event: 'dom-ready', listener: Function): this; + removeListener(event: 'dom-ready', listener: Function): this; + /** + * A promise that resolves with the result of the executed code or is rejected if + * execution throws or results in a rejected promise. + * + * Evaluates `code` in page. + * + * In the browser window some HTML APIs like `requestFullScreen` can only be + * invoked by a gesture from the user. Setting `userGesture` to `true` will remove + * this limitation. + */ + executeJavaScript(code: string, userGesture?: boolean): Promise<unknown>; + /** + * Send a message to the renderer process, optionally transferring ownership of + * zero or more [`MessagePortMain`][] objects. + * + * The transferred `MessagePortMain` objects will be available in the renderer + * process by accessing the `ports` property of the emitted event. When they arrive + * in the renderer, they will be native DOM `MessagePort` objects. + * + * For example: + */ + postMessage(channel: string, message: any, transfer?: MessagePortMain[]): void; + /** + * Whether the reload was initiated successfully. Only results in `false` when the + * frame has no history. + */ + reload(): boolean; + /** + * Send an asynchronous message to the renderer process via `channel`, along with + * arguments. Arguments will be serialized with the Structured Clone Algorithm, + * just like `postMessage`, so prototype chains will not be included. Sending + * Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. + * + * The renderer process can handle the message by listening to `channel` with the + * `ipcRenderer` module. + */ + send(channel: string, ...args: any[]): void; + /** + * A `WebFrameMain[]` collection containing the direct descendents of `frame`. + * + */ + readonly frames: WebFrameMain[]; + /** + * A `WebFrameMain[]` collection containing every frame in the subtree of `frame`, + * including itself. This can be useful when traversing through all frames. + * + */ + readonly framesInSubtree: WebFrameMain[]; + /** + * An `Integer` representing the id of the frame's internal FrameTreeNode instance. + * This id is browser-global and uniquely identifies a frame that hosts content. + * The identifier is fixed at the creation of the frame and stays constant for the + * lifetime of the frame. When the frame is removed, the id is not used again. + * + */ + readonly frameTreeNodeId: number; + /** + * An `IpcMain` instance scoped to the frame. + * + * IPC messages sent with `ipcRenderer.send`, `ipcRenderer.sendSync` or + * `ipcRenderer.postMessage` will be delivered in the following order: + * + * * `contents.on('ipc-message')` + * * `contents.mainFrame.on(channel)` + * * `contents.ipc.on(channel)` + * * `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. + * + * * `contents.mainFrame.handle(channel)` + * * `contents.handle(channel)` + * * `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` interface may be more convenient when + * `nodeIntegrationInSubFrames` is not enabled. + * + */ + readonly ipc: IpcMain; + /** + * A `string` representing the frame name. + * + */ + readonly name: string; + /** + * A `string` representing the current origin of the frame, serialized according to + * RFC 6454. This may be different from the URL. For instance, if the frame is a + * child window opened to `about:blank`, then `frame.origin` will return the parent + * frame's origin, while `frame.url` will return the empty string. Pages without a + * scheme/host/port triple origin will have the serialized origin of `"null"` (that + * is, the string containing the letters n, u, l, l). + * + */ + readonly origin: string; + /** + * An `Integer` representing the operating system `pid` of the process which owns + * this frame. + * + */ + readonly osProcessId: number; + /** + * A `WebFrameMain | null` representing parent frame of `frame`, the property would + * be `null` if `frame` is the top frame in the frame hierarchy. + * + */ + readonly parent: (WebFrameMain) | (null); + /** + * An `Integer` representing the Chromium internal `pid` of the process which owns + * this frame. This is not the same as the OS process ID; to read that use + * `frame.osProcessId`. + * + */ + readonly processId: number; + /** + * An `Integer` representing the unique frame id in the current renderer process. + * Distinct `WebFrameMain` instances that refer to the same underlying frame will + * have the same `routingId`. + * + */ + readonly routingId: number; + /** + * A `WebFrameMain | null` representing top frame in the frame hierarchy to which + * `frame` belongs. + * + */ + readonly top: (WebFrameMain) | (null); + /** + * A `string` representing the current URL of the frame. + * + */ + readonly url: string; + /** + * A `string` representing the visibility state of the frame. + * + * See also how the Page Visibility API is affected by other Electron APIs. + * + */ + readonly visibilityState: string; + } + + class WebRequest { + + // Docs: https://electronjs.org/docs/api/web-request + + /** + * The `listener` will be called with `listener(details)` when a server initiated + * redirect is about to occur. + */ + onBeforeRedirect(filter: WebRequestFilter, listener: ((details: OnBeforeRedirectListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` when a server initiated + * redirect is about to occur. + */ + onBeforeRedirect(listener: ((details: OnBeforeRedirectListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details, callback)` when a request + * is about to occur. + * + * The `uploadData` is an array of `UploadData` objects. + * + * The `callback` has to be called with an `response` object. + * + * Some examples of valid `urls`: + */ + onBeforeRequest(filter: WebRequestFilter, listener: ((details: OnBeforeRequestListenerDetails, callback: (response: CallbackResponse) => void) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details, callback)` when a request + * is about to occur. + * + * The `uploadData` is an array of `UploadData` objects. + * + * The `callback` has to be called with an `response` object. + * + * Some examples of valid `urls`: + */ + onBeforeRequest(listener: ((details: OnBeforeRequestListenerDetails, callback: (response: CallbackResponse) => void) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details, callback)` before sending + * an HTTP request, once the request headers are available. This may occur after a + * TCP connection is made to the server, but before any http data is sent. + * + * The `callback` has to be called with a `response` object. + */ + onBeforeSendHeaders(filter: WebRequestFilter, listener: ((details: OnBeforeSendHeadersListenerDetails, callback: (beforeSendResponse: BeforeSendResponse) => void) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details, callback)` before sending + * an HTTP request, once the request headers are available. This may occur after a + * TCP connection is made to the server, but before any http data is sent. + * + * The `callback` has to be called with a `response` object. + */ + onBeforeSendHeaders(listener: ((details: OnBeforeSendHeadersListenerDetails, callback: (beforeSendResponse: BeforeSendResponse) => void) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` when a request is + * completed. + */ + onCompleted(filter: WebRequestFilter, listener: ((details: OnCompletedListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` when a request is + * completed. + */ + onCompleted(listener: ((details: OnCompletedListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` when an error occurs. + */ + onErrorOccurred(filter: WebRequestFilter, listener: ((details: OnErrorOccurredListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` when an error occurs. + */ + onErrorOccurred(listener: ((details: OnErrorOccurredListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details, callback)` when HTTP + * response headers of a request have been received. + * + * The `callback` has to be called with a `response` object. + */ + onHeadersReceived(filter: WebRequestFilter, listener: ((details: OnHeadersReceivedListenerDetails, callback: (headersReceivedResponse: HeadersReceivedResponse) => void) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details, callback)` when HTTP + * response headers of a request have been received. + * + * The `callback` has to be called with a `response` object. + */ + onHeadersReceived(listener: ((details: OnHeadersReceivedListenerDetails, callback: (headersReceivedResponse: HeadersReceivedResponse) => void) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` when first byte of the + * response body is received. For HTTP requests, this means that the status line + * and response headers are available. + */ + onResponseStarted(filter: WebRequestFilter, listener: ((details: OnResponseStartedListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` when first byte of the + * response body is received. For HTTP requests, this means that the status line + * and response headers are available. + */ + onResponseStarted(listener: ((details: OnResponseStartedListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` just before a request is + * going to be sent to the server, modifications of previous `onBeforeSendHeaders` + * response are visible by the time this listener is fired. + */ + onSendHeaders(filter: WebRequestFilter, listener: ((details: OnSendHeadersListenerDetails) => void) | (null)): void; + /** + * The `listener` will be called with `listener(details)` just before a request is + * going to be sent to the server, modifications of previous `onBeforeSendHeaders` + * response are visible by the time this listener is fired. + */ + onSendHeaders(listener: ((details: OnSendHeadersListenerDetails) => void) | (null)): void; + } + + interface WebRequestFilter { + + // Docs: https://electronjs.org/docs/api/structures/web-request-filter + + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface WebSource { + + // Docs: https://electronjs.org/docs/api/structures/web-source + + code: string; + url?: string; + } + + interface WebviewTag extends HTMLElement { + + // Docs: https://electronjs.org/docs/api/webview-tag + + /** + * Fired when a load has committed. This includes navigation within the current + * document as well as subframe document-level loads, but does not include + * asynchronous resource loads. + */ + addEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void): this; + /** + * Fired when the navigation is done, i.e. the spinner of the tab will stop + * spinning, and the `onload` event is dispatched. + */ + addEventListener(event: 'did-finish-load', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-finish-load', listener: (event: Event) => void): this; + /** + * This event is like `did-finish-load`, but fired when the load failed or was + * cancelled, e.g. `window.stop()` is invoked. + */ + addEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void): this; + /** + * Fired when a frame has done navigation. + */ + addEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void): this; + /** + * Corresponds to the points in time when the spinner of the tab starts spinning. + */ + addEventListener(event: 'did-start-loading', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-start-loading', listener: (event: Event) => void): this; + /** + * Corresponds to the points in time when the spinner of the tab stops spinning. + */ + addEventListener(event: 'did-stop-loading', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-stop-loading', listener: (event: Event) => void): this; + /** + * Fired when attached to the embedder web contents. + */ + addEventListener(event: 'did-attach', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-attach', listener: (event: Event) => void): this; + /** + * Fired when document in the given frame is loaded. + */ + addEventListener(event: 'dom-ready', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'dom-ready', listener: (event: Event) => void): this; + /** + * Fired when page title is set during navigation. `explicitSet` is false when + * title is synthesized from file url. + */ + addEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void): this; + /** + * Fired when page receives favicon urls. + */ + addEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void): this; + /** + * Fired when page enters fullscreen triggered by HTML API. + */ + addEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void): this; + /** + * Fired when page leaves fullscreen triggered by HTML API. + */ + addEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void): this; + /** + * Fired when the guest window logs a console message. + * + * The following example code forwards all log messages to the embedder's console + * without regard for log level or other properties. + */ + addEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void): this; + /** + * Fired when a result is available for `webview.findInPage` request. + */ + addEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void): this; + /** + * Fired when the guest page attempts to open a new browser window. + * + * The following example code opens the new url in system's default browser. + */ + addEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void): this; + /** + * Emitted when a user or the page wants to start navigation. It can happen when + * the `window.location` object is changed or a user clicks a link in the page. + * + * This event will not emit when the navigation is started programmatically with + * APIs like `<webview>.loadURL` and `<webview>.back`. + * + * It is also not emitted during in-page navigation, such as clicking anchor links + * or updating the `window.location.hash`. Use `did-navigate-in-page` event for + * this purpose. + * + * Calling `event.preventDefault()` does __NOT__ have any effect. + */ + addEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void): this; + /** + * Emitted when any frame (including main) starts navigating. `isInPlace` will be + * `true` for in-page navigations. + */ + addEventListener(event: 'did-start-navigation', listener: (event: DidStartNavigationEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-start-navigation', listener: (event: DidStartNavigationEvent) => void): this; + /** + * Emitted after a server side redirect occurs during navigation. For example a 302 + * redirect. + */ + addEventListener(event: 'did-redirect-navigation', listener: (event: DidRedirectNavigationEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-redirect-navigation', listener: (event: DidRedirectNavigationEvent) => void): this; + /** + * Emitted when a navigation is done. + * + * This event is not emitted for in-page navigations, such as clicking anchor links + * or updating the `window.location.hash`. Use `did-navigate-in-page` event for + * this purpose. + */ + addEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void): this; + /** + * Emitted when any frame navigation is done. + * + * This event is not emitted for in-page navigations, such as clicking anchor links + * or updating the `window.location.hash`. Use `did-navigate-in-page` event for + * this purpose. + */ + addEventListener(event: 'did-frame-navigate', listener: (event: DidFrameNavigateEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-frame-navigate', listener: (event: DidFrameNavigateEvent) => void): this; + /** + * Emitted when an in-page navigation happened. + * + * When in-page navigation happens, the page URL changes but does not cause + * navigation outside of the page. Examples of this occurring are when anchor links + * are clicked or when the DOM `hashchange` event is triggered. + */ + addEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void): this; + /** + * Fired when the guest page attempts to close itself. + * + * The following example code navigates the `webview` to `about:blank` when the + * guest attempts to close itself. + */ + addEventListener(event: 'close', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'close', listener: (event: Event) => void): this; + /** + * Fired when the guest page has sent an asynchronous message to embedder page. + * + * With `sendToHost` method and `ipc-message` event you can communicate between + * guest page and embedder page: + */ + addEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void): this; + /** + * Fired when the renderer process is crashed. + */ + addEventListener(event: 'crashed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'crashed', listener: (event: Event) => void): this; + /** + * Fired when a plugin process is crashed. + */ + addEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void): this; + /** + * Fired when the WebContents is destroyed. + */ + addEventListener(event: 'destroyed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'destroyed', listener: (event: Event) => void): this; + /** + * Emitted when media starts playing. + */ + addEventListener(event: 'media-started-playing', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'media-started-playing', listener: (event: Event) => void): this; + /** + * Emitted when media is paused or done playing. + */ + addEventListener(event: 'media-paused', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'media-paused', listener: (event: Event) => void): this; + /** + * Emitted when a page's theme color changes. This is usually due to encountering a + * meta tag: + */ + addEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void): this; + /** + * Emitted when mouse moves over a link or the keyboard moves the focus to a link. + */ + addEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void): this; + /** + * Emitted when DevTools is opened. + */ + addEventListener(event: 'devtools-opened', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'devtools-opened', listener: (event: Event) => void): this; + /** + * Emitted when DevTools is closed. + */ + addEventListener(event: 'devtools-closed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'devtools-closed', listener: (event: Event) => void): this; + /** + * Emitted when DevTools is focused / opened. + */ + addEventListener(event: 'devtools-focused', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'devtools-focused', listener: (event: Event) => void): this; + /** + * Emitted when there is a new context menu that needs to be handled. + */ + addEventListener(event: 'context-menu', listener: (event: ContextMenuEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'context-menu', listener: (event: ContextMenuEvent) => void): this; + addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; + /** + * Whether the guest page can go back. + */ + canGoBack(): boolean; + /** + * Whether the guest page can go forward. + */ + canGoForward(): boolean; + /** + * Whether the guest page can go to `offset`. + */ + canGoToOffset(offset: number): boolean; + /** + * Resolves with a NativeImage + * + * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the + * whole visible page. + */ + capturePage(rect?: Rectangle): Promise<Electron.NativeImage>; + /** + * Clears the navigation history. + */ + clearHistory(): void; + /** + * Closes the DevTools window of guest page. + */ + closeDevTools(): void; + /** + * Executes editing command `copy` in page. + */ + copy(): void; + /** + * Executes editing command `cut` in page. + */ + cut(): void; + /** + * Executes editing command `delete` in page. + */ + delete(): void; + /** + * Initiates a download of the resource at `url` without navigating. + */ + downloadURL(url: string): void; + /** + * A promise that resolves with the result of the executed code or is rejected if + * the result of the code is a rejected promise. + * + * Evaluates `code` in page. If `userGesture` is set, it will create the user + * gesture context in the page. HTML APIs like `requestFullScreen`, which require + * user action, can take advantage of this option for automation. + */ + executeJavaScript(code: string, userGesture?: boolean): Promise<any>; + /** + * The request id used for the request. + * + * Starts a request to find all matches for the `text` in the web page. The result + * of the request can be obtained by subscribing to `found-in-page` event. + */ + findInPage(text: string, options?: FindInPageOptions): number; + /** + * The title of guest page. + */ + getTitle(): string; + /** + * The URL of guest page. + */ + getURL(): string; + /** + * The user agent for guest page. + */ + getUserAgent(): string; + /** + * The WebContents ID of this `webview`. + */ + getWebContentsId(): number; + /** + * the current zoom factor. + */ + getZoomFactor(): number; + /** + * the current zoom level. + */ + getZoomLevel(): number; + /** + * Makes the guest page go back. + */ + goBack(): void; + /** + * Makes the guest page go forward. + */ + goForward(): void; + /** + * Navigates to the specified absolute index. + */ + goToIndex(index: number): void; + /** + * Navigates to the specified offset from the "current entry". + */ + goToOffset(offset: number): void; + /** + * A promise that resolves with a key for the inserted CSS that can later be used + * to remove the CSS via `<webview>.removeInsertedCSS(key)`. + * + * Injects CSS into the current web page and returns a unique key for the inserted + * stylesheet. + */ + insertCSS(css: string): Promise<string>; + /** + * Inserts `text` to the focused element. + */ + insertText(text: string): Promise<void>; + /** + * Starts inspecting element at position (`x`, `y`) of guest page. + */ + inspectElement(x: number, y: number): void; + /** + * Opens the DevTools for the service worker context present in the guest page. + */ + inspectServiceWorker(): void; + /** + * Opens the DevTools for the shared worker context present in the guest page. + */ + inspectSharedWorker(): void; + /** + * Whether guest page has been muted. + */ + isAudioMuted(): boolean; + /** + * Whether the renderer process has crashed. + */ + isCrashed(): boolean; + /** + * Whether audio is currently playing. + */ + isCurrentlyAudible(): boolean; + /** + * Whether DevTools window of guest page is focused. + */ + isDevToolsFocused(): boolean; + /** + * Whether guest page has a DevTools window attached. + */ + isDevToolsOpened(): boolean; + /** + * Whether guest page is still loading resources. + */ + isLoading(): boolean; + /** + * Whether the main frame (and not just iframes or frames within it) is still + * loading. + */ + isLoadingMainFrame(): boolean; + /** + * Whether the guest page is waiting for a first-response for the main resource of + * the page. + */ + isWaitingForResponse(): boolean; + /** + * The promise will resolve when the page has finished loading (see + * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). + * + * Loads the `url` in the webview, the `url` must contain the protocol prefix, e.g. + * the `http://` or `file://`. + */ + loadURL(url: string, options?: LoadURLOptions): Promise<void>; + /** + * Opens a DevTools window for guest page. + */ + openDevTools(): void; + /** + * Executes editing command `paste` in page. + */ + paste(): void; + /** + * Executes editing command `pasteAndMatchStyle` in page. + */ + pasteAndMatchStyle(): void; + /** + * Prints `webview`'s web page. Same as `webContents.print([options])`. + */ + print(options?: WebviewTagPrintOptions): Promise<void>; + /** + * Resolves with the generated PDF data. + * + * Prints `webview`'s web page as PDF, Same as `webContents.printToPDF(options)`. + */ + printToPDF(options: PrintToPDFOptions): Promise<Uint8Array>; + /** + * Executes editing command `redo` in page. + */ + redo(): void; + /** + * Reloads the guest page. + */ + reload(): void; + /** + * Reloads the guest page and ignores cache. + */ + reloadIgnoringCache(): void; + /** + * Resolves if the removal was successful. + * + * Removes the inserted CSS from the current web page. The stylesheet is identified + * by its key, which is returned from `<webview>.insertCSS(css)`. + */ + removeInsertedCSS(key: string): Promise<void>; + /** + * Executes editing command `replace` in page. + */ + replace(text: string): void; + /** + * Executes editing command `replaceMisspelling` in page. + */ + replaceMisspelling(text: string): void; + /** + * Executes editing command `selectAll` in page. + */ + selectAll(): void; + /** + * Send an asynchronous message to renderer process via `channel`, you can also + * send arbitrary arguments. The renderer process can handle the message by + * listening to the `channel` event with the `ipcRenderer` module. + * + * See webContents.send for examples. + */ + send(channel: string, ...args: any[]): Promise<void>; + /** + * Sends an input `event` to the page. + * + * See webContents.sendInputEvent for detailed description of `event` object. + */ + sendInputEvent(event: (MouseInputEvent) | (MouseWheelInputEvent) | (KeyboardInputEvent)): Promise<void>; + /** + * Send an asynchronous message to renderer process via `channel`, you can also + * send arbitrary arguments. The renderer process can handle the message by + * listening to the `channel` event with the `ipcRenderer` module. + * + * See webContents.sendToFrame for examples. + */ + sendToFrame(frameId: [number, number], channel: string, ...args: any[]): Promise<void>; + /** + * Set guest page muted. + */ + setAudioMuted(muted: boolean): void; + /** + * Overrides the user agent for the guest page. + */ + setUserAgent(userAgent: string): void; + /** + * Sets the maximum and minimum pinch-to-zoom level. + */ + setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): Promise<void>; + /** + * Changes the zoom factor to the specified factor. Zoom factor is zoom percent + * divided by 100, so 300% = 3.0. + */ + setZoomFactor(factor: number): void; + /** + * Changes the zoom level to the specified level. The original size is 0 and each + * increment above or below represents zooming 20% larger or smaller to default + * limits of 300% and 50% of original size, respectively. The formula for this is + * `scale := 1.2 ^ level`. + * + * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that + * the zoom level for a specific domain propagates across all instances of windows + * with the same domain. Differentiating the window URLs will make zoom work + * per-window. + */ + setZoomLevel(level: number): void; + /** + * Shows pop-up dictionary that searches the selected word on the page. + * + * @platform darwin + */ + showDefinitionForSelection(): void; + /** + * Stops any pending navigation. + */ + stop(): void; + /** + * Stops any `findInPage` request for the `webview` with the provided `action`. + */ + stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; + /** + * Executes editing command `undo` in page. + */ + undo(): void; + /** + * Executes editing command `unselect` in page. + */ + unselect(): void; + /** + * A `boolean`. When this attribute is present the guest page will be allowed to + * open new windows. Popups are disabled by default. + */ + allowpopups: boolean; + /** + * A `string` which is a list of strings which specifies the blink features to be + * disabled separated by `,`. The full list of supported feature strings can be + * found in the RuntimeEnabledFeatures.json5 file. + */ + disableblinkfeatures: string; + /** + * A `boolean`. When this attribute is present the guest page will have web + * security disabled. Web security is enabled by default. + */ + disablewebsecurity: boolean; + /** + * A `string` which is a list of strings which specifies the blink features to be + * enabled separated by `,`. The full list of supported feature strings can be + * found in the RuntimeEnabledFeatures.json5 file. + */ + enableblinkfeatures: string; + /** + * A `string` that sets the referrer URL for the guest page. + */ + httpreferrer: string; + /** + * A `boolean`. When this attribute is present the guest page in `webview` will + * have node integration and can use node APIs like `require` and `process` to + * access low level system resources. Node integration is disabled by default in + * the guest page. + */ + nodeintegration: boolean; + /** + * A `boolean` for the experimental option for enabling NodeJS support in + * sub-frames such as iframes inside the `webview`. All your preloads will load for + * every iframe, you can use `process.isMainFrame` to determine if you are in the + * main frame or not. This option is disabled by default in the guest page. + */ + nodeintegrationinsubframes: boolean; + /** + * A `string` that sets the session used by the page. If `partition` starts with + * `persist:`, the page will use a persistent session available to all pages in the + * app with the same `partition`. if there is no `persist:` prefix, the page will + * use an in-memory session. By assigning the same `partition`, multiple pages can + * share the same session. If the `partition` is unset then default session of the + * app will be used. + * + * This value can only be modified before the first navigation, since the session + * of an active renderer process cannot change. Subsequent attempts to modify the + * value will fail with a DOM exception. + */ + partition: string; + /** + * A `boolean`. When this attribute is present the guest page in `webview` will be + * able to use browser plugins. Plugins are disabled by default. + */ + plugins: boolean; + /** + * A `string` that specifies a script that will be loaded before other scripts run + * in the guest page. The protocol of script's URL must be `file:` (even when using + * `asar:` archives) because it will be loaded by Node's `require` under the hood, + * which treats `asar:` archives as virtual directories. + * + * When the guest page doesn't have node integration this script will still have + * access to all Node APIs, but global objects injected by Node will be deleted + * after this script has finished executing. + */ + preload: string; + /** + * A `string` representing the visible URL. Writing to this attribute initiates + * top-level navigation. + * + * Assigning `src` its own value will reload the current page. + * + * The `src` attribute can also accept data URLs, such as `data:text/plain,Hello, + * world!`. + */ + src: string; + /** + * A `string` that sets the user agent for the guest page before the page is + * navigated to. Once the page is loaded, use the `setUserAgent` method to change + * the user agent. + */ + useragent: string; + /** + * A `string` which is a comma separated list of strings which specifies the web + * preferences to be set on the webview. The full list of supported preference + * strings can be found in BrowserWindow. + * + * The string follows the same format as the features string in `window.open`. A + * name by itself is given a `true` boolean value. A preference can be set to + * another value by including an `=`, followed by the value. Special values `yes` + * and `1` are interpreted as `true`, while `no` and `0` are interpreted as + * `false`. + */ + webpreferences: string; + } + + interface AboutPanelOptionsOptions { + /** + * The app's name. + */ + applicationName?: string; + /** + * The app's version. + */ + applicationVersion?: string; + /** + * Copyright information. + */ + copyright?: string; + /** + * The app's build version number. + * + * @platform darwin + */ + version?: string; + /** + * Credit information. + * + * @platform darwin,win32 + */ + credits?: string; + /** + * List of app authors. + * + * @platform linux + */ + authors?: string[]; + /** + * The app's website. + * + * @platform linux + */ + website?: string; + /** + * Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as + * 64x64 pixels while retaining aspect ratio. + * + * @platform linux,win32 + */ + iconPath?: string; + } + + interface AddRepresentationOptions { + /** + * The scale factor to add the image representation for. + */ + scaleFactor?: number; + /** + * Defaults to 0. Required if a bitmap buffer is specified as `buffer`. + */ + width?: number; + /** + * Defaults to 0. Required if a bitmap buffer is specified as `buffer`. + */ + height?: number; + /** + * The buffer containing the raw image data. + */ + buffer?: Buffer; + /** + * The data URL containing either a base 64 encoded PNG or JPEG image. + */ + dataURL?: string; + } + + interface AnimationSettings { + /** + * Returns true if rich animations should be rendered. Looks at session type (e.g. + * remote desktop) and accessibility settings to give guidance for heavy + * animations. + */ + shouldRenderRichAnimation: boolean; + /** + * Determines on a per-platform basis whether scroll animations (e.g. produced by + * home/end key) should be enabled. + */ + scrollAnimationsEnabledBySystem: boolean; + /** + * Determines whether the user desires reduced motion based on platform APIs. + */ + prefersReducedMotion: boolean; + } + + interface AppDetailsOptions { + /** + * Window's App User Model ID. It has to be set, otherwise the other options will + * have no effect. + */ + appId?: string; + /** + * Window's Relaunch Icon. + */ + appIconPath?: string; + /** + * Index of the icon in `appIconPath`. Ignored when `appIconPath` is not set. + * Default is `0`. + */ + appIconIndex?: number; + /** + * Window's Relaunch Command. + */ + relaunchCommand?: string; + /** + * Window's Relaunch Display Name. + */ + relaunchDisplayName?: string; + } + + interface ApplicationInfoForProtocolReturnValue { + /** + * the display icon of the app handling the protocol. + */ + icon: NativeImage; + /** + * installation path of the app handling the protocol. + */ + path: string; + /** + * display name of the app handling the protocol. + */ + name: string; + } + + interface AuthenticationResponseDetails { + url: string; + } + + interface AuthInfo { + isProxy: boolean; + scheme: string; + host: string; + port: number; + realm: string; + } + + interface AutoResizeOptions { + /** + * If `true`, the view's width will grow and shrink together with the window. + * `false` by default. + */ + width?: boolean; + /** + * If `true`, the view's height will grow and shrink together with the window. + * `false` by default. + */ + height?: boolean; + /** + * If `true`, the view's x position and width will grow and shrink proportionally + * with the window. `false` by default. + */ + horizontal?: boolean; + /** + * If `true`, the view's y position and height will grow and shrink proportionally + * with the window. `false` by default. + */ + vertical?: boolean; + } + + interface BeforeSendResponse { + cancel?: boolean; + /** + * When provided, request will be made with these headers. + */ + requestHeaders?: Record<string, (string) | (string[])>; + } + + interface BitmapOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface BlinkMemoryInfo { + /** + * Size of all allocated objects in Kilobytes. + */ + allocated: number; + /** + * Total allocated space in Kilobytes. + */ + total: number; + } + + interface BluetoothPairingHandlerHandlerDetails { + deviceId: string; + /** + * The type of pairing prompt being requested. One of the following values: + */ + pairingKind: ('confirm' | 'confirmPin' | 'providePin'); + frame: WebFrameMain; + /** + * The pin value to verify if `pairingKind` is `confirmPin`. + */ + pin?: string; + } + + interface BrowserViewConstructorOptions { + /** + * See BrowserWindow. + */ + webPreferences?: WebPreferences; + } + + interface BrowserWindowConstructorOptions { + /** + * Window's width in pixels. Default is `800`. + */ + width?: number; + /** + * Window's height in pixels. Default is `600`. + */ + height?: number; + /** + * (**required** if y is used) Window's left offset from screen. Default is to + * center the window. + */ + x?: number; + /** + * (**required** if x is used) Window's top offset from screen. Default is to + * center the window. + */ + y?: number; + /** + * The `width` and `height` would be used as web page's size, which means the + * actual window's size will include window frame's size and be slightly larger. + * Default is `false`. + */ + useContentSize?: boolean; + /** + * Show window in the center of the screen. Default is `false`. + */ + center?: boolean; + /** + * Window's minimum width. Default is `0`. + */ + minWidth?: number; + /** + * Window's minimum height. Default is `0`. + */ + minHeight?: number; + /** + * Window's maximum width. Default is no limit. + */ + maxWidth?: number; + /** + * Window's maximum height. Default is no limit. + */ + maxHeight?: number; + /** + * Whether window is resizable. Default is `true`. + */ + resizable?: boolean; + /** + * Whether window is movable. This is not implemented on Linux. Default is `true`. + * + * @platform darwin,win32 + */ + movable?: boolean; + /** + * Whether window is minimizable. This is not implemented on Linux. Default is + * `true`. + * + * @platform darwin,win32 + */ + minimizable?: boolean; + /** + * Whether window is maximizable. This is not implemented on Linux. Default is + * `true`. + * + * @platform darwin,win32 + */ + maximizable?: boolean; + /** + * Whether window is closable. This is not implemented on Linux. Default is `true`. + * + * @platform darwin,win32 + */ + closable?: boolean; + /** + * Whether the window can be focused. Default is `true`. On Windows setting + * `focusable: false` also implies setting `skipTaskbar: true`. On Linux setting + * `focusable: false` makes the window stop interacting with wm, so the window will + * always stay on top in all workspaces. + */ + focusable?: boolean; + /** + * Whether the window should always stay on top of other windows. Default is + * `false`. + */ + alwaysOnTop?: boolean; + /** + * Whether the window should show in fullscreen. When explicitly set to `false` the + * fullscreen button will be hidden or disabled on macOS. Default is `false`. + */ + fullscreen?: boolean; + /** + * Whether the window can be put into fullscreen mode. On macOS, also whether the + * maximize/zoom button should toggle full screen mode or maximize window. Default + * is `true`. + */ + fullscreenable?: boolean; + /** + * Use pre-Lion fullscreen on macOS. Default is `false`. + * + * @platform darwin + */ + simpleFullscreen?: boolean; + /** + * Whether to show the window in taskbar. Default is `false`. + * + * @platform darwin,win32 + */ + skipTaskbar?: boolean; + /** + * Whether the window is in kiosk mode. Default is `false`. + */ + kiosk?: boolean; + /** + * Default window title. Default is `"Electron"`. If the HTML tag `<title>` is + * defined in the HTML file loaded by `loadURL()`, this property will be ignored. + */ + title?: string; + /** + * The window icon. On Windows it is recommended to use `ICO` icons to get best + * visual effects, you can also leave it undefined so the executable's icon will be + * used. + */ + icon?: (NativeImage) | (string); + /** + * Whether window should be shown when created. Default is `true`. + */ + show?: boolean; + /** + * Whether the renderer should be active when `show` is `false` and it has just + * been created. In order for `document.visibilityState` to work correctly on + * first load with `show: false` you should set this to `false`. Setting this to + * `false` will cause the `ready-to-show` event to not fire. Default is `true`. + */ + paintWhenInitiallyHidden?: boolean; + /** + * Specify `false` to create a frameless window. Default is `true`. + */ + frame?: boolean; + /** + * Specify parent window. Default is `null`. + */ + parent?: BrowserWindow; + /** + * Whether this is a modal window. This only works when the window is a child + * window. Default is `false`. + */ + modal?: boolean; + /** + * Whether clicking an inactive window will also click through to the web contents. + * Default is `false` on macOS. This option is not configurable on other platforms. + * + * @platform darwin + */ + acceptFirstMouse?: boolean; + /** + * Whether to hide cursor when typing. Default is `false`. + */ + disableAutoHideCursor?: boolean; + /** + * Auto hide the menu bar unless the `Alt` key is pressed. Default is `false`. + */ + autoHideMenuBar?: boolean; + /** + * Enable the window to be resized larger than screen. Only relevant for macOS, as + * other OSes allow larger-than-screen windows by default. Default is `false`. + * + * @platform darwin + */ + enableLargerThanScreen?: boolean; + /** + * The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color + * format. Alpha in #AARRGGBB format is supported if `transparent` is set to + * `true`. Default is `#FFF` (white). See win.setBackgroundColor for more + * information. + */ + backgroundColor?: string; + /** + * Whether window should have a shadow. Default is `true`. + */ + hasShadow?: boolean; + /** + * Set the initial opacity of the window, between 0.0 (fully transparent) and 1.0 + * (fully opaque). This is only implemented on Windows and macOS. + * + * @platform darwin,win32 + */ + opacity?: number; + /** + * Forces using dark theme for the window, only works on some GTK+3 desktop + * environments. Default is `false`. + */ + darkTheme?: boolean; + /** + * Makes the window transparent. Default is `false`. On Windows, does not work + * unless the window is frameless. + */ + transparent?: boolean; + /** + * The type of window, default is normal window. See more about this below. + */ + type?: string; + /** + * Specify how the material appearance should reflect window activity state on + * macOS. Must be used with the `vibrancy` property. Possible values are: + * + * @platform darwin + */ + visualEffectState?: ('followWindow' | 'active' | 'inactive'); + /** + * The style of window title bar. Default is `default`. Possible values are: + * + * @platform darwin,win32 + */ + titleBarStyle?: ('default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover'); + /** + * Set a custom position for the traffic light buttons in frameless windows. + * + * @platform darwin + */ + trafficLightPosition?: Point; + /** + * Whether frameless window should have rounded corners on macOS. Default is + * `true`. Setting this property to `false` will prevent the window from being + * fullscreenable. + * + * @platform darwin + */ + roundedCorners?: boolean; + /** + * Shows the title in the title bar in full screen mode on macOS for `hiddenInset` + * titleBarStyle. Default is `false`. + * + * @deprecated + * @platform darwin + */ + fullscreenWindowTitle?: boolean; + /** + * Use `WS_THICKFRAME` style for frameless windows on Windows, which adds standard + * window frame. Setting it to `false` will remove window shadow and window + * animations. Default is `true`. + */ + thickFrame?: boolean; + /** + * Add a type of vibrancy effect to the window, only on macOS. Can be + * `appearance-based`, `light`, `dark`, `titlebar`, `selection`, `menu`, `popover`, + * `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, + * `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. Please + * note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` + * are deprecated and have been removed in macOS Catalina (10.15). + * + * @platform darwin + */ + vibrancy?: ('appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark' | 'header' | 'sheet' | 'window' | 'hud' | 'fullscreen-ui' | 'tooltip' | 'content' | 'under-window' | 'under-page'); + /** + * Controls the behavior on macOS when option-clicking the green stoplight button + * on the toolbar or by clicking the Window > Zoom menu item. If `true`, the window + * will grow to the preferred width of the web page when zoomed, `false` will cause + * it to zoom to the width of the screen. This will also affect the behavior when + * calling `maximize()` directly. Default is `false`. + * + * @platform darwin + */ + zoomToPageWidth?: boolean; + /** + * Tab group name, allows opening the window as a native tab on macOS 10.12+. + * Windows with the same tabbing identifier will be grouped together. This also + * adds a native new tab button to your window's tab bar and allows your `app` and + * window to receive the `new-window-for-tab` event. + * + * @platform darwin + */ + tabbingIdentifier?: string; + /** + * Settings of web page's features. + */ + webPreferences?: WebPreferences; + /** + * When using a frameless window in conjunction with + * `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so + * that the standard window controls ("traffic lights" on macOS) are visible, this + * property enables the Window Controls Overlay JavaScript APIs and CSS Environment + * Variables. Specifying `true` will result in an overlay with default system + * colors. Default is `false`. + */ + titleBarOverlay?: (TitleBarOverlay) | (boolean); + } + + interface CallbackResponse { + cancel?: boolean; + /** + * The original request is prevented from being sent or completed and is instead + * redirected to the given URL. + */ + redirectURL?: string; + } + + interface CertificateTrustDialogOptions { + /** + * The certificate to trust/import. + */ + certificate: Certificate; + /** + * The message to display to the user. + */ + message: string; + } + + interface ClearCodeCachesOptions { + /** + * An array of url corresponding to the resource whose generated code cache needs + * to be removed. If the list is empty then all entries in the cache directory will + * be removed. + */ + urls?: string[]; + } + + interface ClearStorageDataOptions { + /** + * Should follow `window.location.origin`’s representation `scheme://host:port`. + */ + origin?: string; + /** + * The types of storages to clear, can contain: `appcache`, `cookies`, + * `filesystem`, `indexdb`, `localstorage`, `shadercache`, `websql`, + * `serviceworkers`, `cachestorage`. If not specified, clear all storage types. + */ + storages?: string[]; + /** + * The types of quotas to clear, can contain: `temporary`, `persistent`, + * `syncable`. If not specified, clear all quotas. + */ + quotas?: string[]; + } + + interface ClientRequestConstructorOptions { + /** + * The HTTP request method. Defaults to the GET method. + */ + method?: string; + /** + * The request URL. Must be provided in the absolute form with the protocol scheme + * specified as http or https. + */ + url?: string; + /** + * The `Session` instance with which the request is associated. + */ + session?: Session; + /** + * The name of the `partition` with which the request is associated. Defaults to + * the empty string. The `session` option supersedes `partition`. Thus if a + * `session` is explicitly specified, `partition` is ignored. + */ + partition?: string; + /** + * Can be `include` or `omit`. Whether to send credentials with this request. If + * set to `include`, credentials from the session associated with the request will + * be used. If set to `omit`, credentials will not be sent with the request (and + * the `'login'` event will not be triggered in the event of a 401). This matches + * the behavior of the fetch option of the same name. If this option is not + * specified, authentication data from the session will be sent, and cookies will + * not be sent (unless `useSessionCookies` is set). + */ + credentials?: ('include' | 'omit'); + /** + * Whether to send cookies with this request from the provided session. If + * `credentials` is specified, this option has no effect. Default is `false`. + */ + useSessionCookies?: boolean; + /** + * Can be `http:` or `https:`. The protocol scheme in the form 'scheme:'. Defaults + * to 'http:'. + */ + protocol?: string; + /** + * The server host provided as a concatenation of the hostname and the port number + * 'hostname:port'. + */ + host?: string; + /** + * The server host name. + */ + hostname?: string; + /** + * The server's listening port number. + */ + port?: number; + /** + * The path part of the request URL. + */ + path?: string; + /** + * Can be `follow`, `error` or `manual`. The redirect mode for this request. When + * mode is `error`, any redirection will be aborted. When mode is `manual` the + * redirection will be cancelled unless `request.followRedirect` is invoked + * synchronously during the `redirect` event. Defaults to `follow`. + */ + redirect?: ('follow' | 'error' | 'manual'); + /** + * The origin URL of the request. + */ + origin?: string; + } + + interface Config { + /** + * The proxy mode. Should be one of `direct`, `auto_detect`, `pac_script`, + * `fixed_servers` or `system`. If it's unspecified, it will be automatically + * determined based on other specified options. + */ + mode?: ('direct' | 'auto_detect' | 'pac_script' | 'fixed_servers' | 'system'); + /** + * The URL associated with the PAC file. + */ + pacScript?: string; + /** + * Rules indicating which proxies to use. + */ + proxyRules?: string; + /** + * Rules indicating which URLs should bypass the proxy settings. + */ + proxyBypassRules?: string; + } + + interface ConfigureHostResolverOptions { + /** + * Whether the built-in host resolver is used in preference to getaddrinfo. When + * enabled, the built-in resolver will attempt to use the system's DNS settings to + * do DNS lookups itself. Enabled by default on macOS, disabled by default on + * Windows and Linux. + */ + enableBuiltInResolver?: boolean; + /** + * Can be "off", "automatic" or "secure". Configures the DNS-over-HTTP mode. When + * "off", no DoH lookups will be performed. When "automatic", DoH lookups will be + * performed first if DoH is available, and insecure DNS lookups will be performed + * as a fallback. When "secure", only DoH lookups will be performed. Defaults to + * "automatic". + */ + secureDnsMode?: string; + /** + * A list of DNS-over-HTTP server templates. See RFC8484 Β§ 3 for details on the + * template format. Most servers support the POST method; the template for such + * servers is simply a URI. Note that for some DNS providers, the resolver will + * automatically upgrade to DoH unless DoH is explicitly disabled, even if there + * are no DoH servers provided in this list. + */ + secureDnsServers?: string[]; + /** + * Controls whether additional DNS query types, e.g. HTTPS (DNS type 65) will be + * allowed besides the traditional A and AAAA queries when a request is being made + * via insecure DNS. Has no effect on Secure DNS which always allows additional + * types. Defaults to true. + */ + enableAdditionalDnsQueryTypes?: boolean; + } + + interface ConsoleMessageEvent extends Event { + /** + * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and + * `error`. + */ + level: number; + /** + * The actual console message + */ + message: string; + /** + * The line number of the source that triggered this console message + */ + line: number; + sourceId: string; + } + + interface ContextMenuEvent extends Event { + params: Params; + } + + interface ContextMenuParams { + /** + * x coordinate. + */ + x: number; + /** + * y coordinate. + */ + y: number; + /** + * Frame from which the context menu was invoked. + */ + frame: WebFrameMain; + /** + * URL of the link that encloses the node the context menu was invoked on. + */ + linkURL: string; + /** + * Text associated with the link. May be an empty string if the contents of the + * link are an image. + */ + linkText: string; + /** + * URL of the top level page that the context menu was invoked on. + */ + pageURL: string; + /** + * URL of the subframe that the context menu was invoked on. + */ + frameURL: string; + /** + * Source URL for the element that the context menu was invoked on. Elements with + * source URLs are images, audio and video. + */ + srcURL: string; + /** + * Type of the node the context menu was invoked on. Can be `none`, `image`, + * `audio`, `video`, `canvas`, `file` or `plugin`. + */ + mediaType: ('none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'); + /** + * Whether the context menu was invoked on an image which has non-empty contents. + */ + hasImageContents: boolean; + /** + * Whether the context is editable. + */ + isEditable: boolean; + /** + * Text of the selection that the context menu was invoked on. + */ + selectionText: string; + /** + * Title text of the selection that the context menu was invoked on. + */ + titleText: string; + /** + * Alt text of the selection that the context menu was invoked on. + */ + altText: string; + /** + * Suggested filename to be used when saving file through 'Save Link As' option of + * context menu. + */ + suggestedFilename: string; + /** + * Rect representing the coordinates in the document space of the selection. + */ + selectionRect: Rectangle; + /** + * Start position of the selection text. + */ + selectionStartOffset: number; + /** + * The referrer policy of the frame on which the menu is invoked. + */ + referrerPolicy: Referrer; + /** + * The misspelled word under the cursor, if any. + */ + misspelledWord: string; + /** + * An array of suggested words to show the user to replace the `misspelledWord`. + * Only available if there is a misspelled word and spellchecker is enabled. + */ + dictionarySuggestions: string[]; + /** + * The character encoding of the frame on which the menu was invoked. + */ + frameCharset: string; + /** + * If the context menu was invoked on an input field, the type of that field. + * Possible values are `none`, `plainText`, `password`, `other`. + */ + inputFieldType: string; + /** + * If the context is editable, whether or not spellchecking is enabled. + */ + spellcheckEnabled: boolean; + /** + * Input source that invoked the context menu. Can be `none`, `mouse`, `keyboard`, + * `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, + * `adjustSelection`, or `adjustSelectionReset`. + */ + menuSourceType: ('none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu' | 'longPress' | 'longTap' | 'touchHandle' | 'stylus' | 'adjustSelection' | 'adjustSelectionReset'); + /** + * The flags for the media element the context menu was invoked on. + */ + mediaFlags: MediaFlags; + /** + * These flags indicate whether the renderer believes it is able to perform the + * corresponding action. + */ + editFlags: EditFlags; + } + + interface ContinueActivityDetails { + /** + * A string identifying the URL of the webpage accessed by the activity on another + * device, if available. + */ + webpageURL?: string; + } + + interface CookiesGetFilter { + /** + * Retrieves cookies which are associated with `url`. Empty implies retrieving + * cookies of all URLs. + */ + url?: string; + /** + * Filters cookies by name. + */ + name?: string; + /** + * Retrieves cookies whose domains match or are subdomains of `domains`. + */ + domain?: string; + /** + * Retrieves cookies whose path matches `path`. + */ + path?: string; + /** + * Filters cookies by their Secure property. + */ + secure?: boolean; + /** + * Filters out session or persistent cookies. + */ + session?: boolean; + } + + interface CookiesSetDetails { + /** + * The URL to associate the cookie with. The promise will be rejected if the URL is + * invalid. + */ + url: string; + /** + * The name of the cookie. Empty by default if omitted. + */ + name?: string; + /** + * The value of the cookie. Empty by default if omitted. + */ + value?: string; + /** + * The domain of the cookie; this will be normalized with a preceding dot so that + * it's also valid for subdomains. Empty by default if omitted. + */ + domain?: string; + /** + * The path of the cookie. Empty by default if omitted. + */ + path?: string; + /** + * Whether the cookie should be marked as Secure. Defaults to false unless Same + * Site=None attribute is used. + */ + secure?: boolean; + /** + * Whether the cookie should be marked as HTTP only. Defaults to false. + */ + httpOnly?: boolean; + /** + * The expiration date of the cookie as the number of seconds since the UNIX epoch. + * If omitted then the cookie becomes a session cookie and will not be retained + * between sessions. + */ + expirationDate?: number; + /** + * The Same Site policy to apply to this cookie. Can be `unspecified`, + * `no_restriction`, `lax` or `strict`. Default is `lax`. + */ + sameSite?: ('unspecified' | 'no_restriction' | 'lax' | 'strict'); + } + + interface CrashReporterStartOptions { + /** + * URL that crash reports will be sent to as POST. Required unless `uploadToServer` + * is `false`. + */ + submitURL?: string; + /** + * Defaults to `app.name`. + */ + productName?: string; + /** + * Deprecated alias for `{ globalExtra: { _companyName: ... } }`. + * + * @deprecated + */ + companyName?: string; + /** + * Whether crash reports should be sent to the server. If false, crash reports will + * be collected and stored in the crashes directory, but not uploaded. Default is + * `true`. + */ + uploadToServer?: boolean; + /** + * If true, crashes generated in the main process will not be forwarded to the + * system crash handler. Default is `false`. + */ + ignoreSystemCrashHandler?: boolean; + /** + * If true, limit the number of crashes uploaded to 1/hour. Default is `false`. + * + * @platform darwin,win32 + */ + rateLimit?: boolean; + /** + * If true, crash reports will be compressed and uploaded with `Content-Encoding: + * gzip`. Default is `true`. + */ + compress?: boolean; + /** + * Extra string key/value annotations that will be sent along with crash reports + * that are generated in the main process. Only string values are supported. + * Crashes generated in child processes will not contain these extra parameters to + * crash reports generated from child processes, call `addExtraParameter` from the + * child process. + */ + extra?: Record<string, string>; + /** + * Extra string key/value annotations that will be sent along with any crash + * reports generated in any process. These annotations cannot be changed once the + * crash reporter has been started. If a key is present in both the global extra + * parameters and the process-specific extra parameters, then the global one will + * take precedence. By default, `productName` and the app version are included, as + * well as the Electron version. + */ + globalExtra?: Record<string, string>; + } + + interface CreateFromBitmapOptions { + width: number; + height: number; + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface CreateFromBufferOptions { + /** + * Required for bitmap buffers. + */ + width?: number; + /** + * Required for bitmap buffers. + */ + height?: number; + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface CreateInterruptedDownloadOptions { + /** + * Absolute path of the download. + */ + path: string; + /** + * Complete URL chain for the download. + */ + urlChain: string[]; + mimeType?: string; + /** + * Start range for the download. + */ + offset: number; + /** + * Total length of the download. + */ + length: number; + /** + * Last-Modified header value. + */ + lastModified?: string; + /** + * ETag header value. + */ + eTag?: string; + /** + * Time when download was started in number of seconds since UNIX epoch. + */ + startTime?: number; + } + + interface Data { + text?: string; + html?: string; + image?: NativeImage; + rtf?: string; + /** + * The title of the URL at `text`. + */ + bookmark?: string; + } + + interface Details { + /** + * Process type. One of the following values: + */ + type: ('Utility' | 'Zygote' | 'Sandbox helper' | 'GPU' | 'Pepper Plugin' | 'Pepper Plugin Broker' | 'Unknown'); + /** + * The reason the child process is gone. Possible values: + */ + reason: ('clean-exit' | 'abnormal-exit' | 'killed' | 'crashed' | 'oom' | 'launch-failed' | 'integrity-failure'); + /** + * The exit code for the process (e.g. status from waitpid if on posix, from + * GetExitCodeProcess on Windows). + */ + exitCode: number; + /** + * The non-localized name of the process. + */ + serviceName?: string; + /** + * The name of the process. Examples for utility: `Audio Service`, `Content + * Decryption Module Service`, `Network Service`, `Video Capture`, etc. + */ + name?: string; + } + + interface DevicePermissionHandlerHandlerDetails { + /** + * The type of device that permission is being requested on, can be `hid` or + * `serial`. + */ + deviceType: ('hid' | 'serial'); + /** + * The origin URL of the device permission check. + */ + origin: string; + /** + * the device that permission is being requested for. + */ + device: (HIDDevice) | (SerialPort); + } + + interface DidChangeThemeColorEvent extends Event { + themeColor: string; + } + + interface DidCreateWindowDetails { + /** + * URL for the created window. + */ + url: string; + /** + * Name given to the created window in the `window.open()` call. + */ + frameName: string; + /** + * The options used to create the BrowserWindow. They are merged in increasing + * precedence: parsed options from the `features` string from `window.open()`, + * security-related webPreferences inherited from the parent, and options given by + * `webContents.setWindowOpenHandler`. Unrecognized options are not filtered out. + */ + options: BrowserWindowConstructorOptions; + /** + * The referrer that will be passed to the new window. May or may not result in the + * `Referer` header being sent, depending on the referrer policy. + */ + referrer: Referrer; + /** + * The post data that will be sent to the new window, along with the appropriate + * headers that will be set. If no post data is to be sent, the value will be + * `null`. Only defined when the window is being created by a form that set + * `target=_blank`. + */ + postBody?: PostBody; + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); + } + + interface DidFailLoadEvent extends Event { + errorCode: number; + errorDescription: string; + validatedURL: string; + isMainFrame: boolean; + } + + interface DidFrameFinishLoadEvent extends Event { + isMainFrame: boolean; + } + + interface DidFrameNavigateEvent extends Event { + url: string; + /** + * -1 for non HTTP navigations + */ + httpResponseCode: number; + /** + * empty for non HTTP navigations, + */ + httpStatusText: string; + isMainFrame: boolean; + frameProcessId: number; + frameRoutingId: number; + } + + interface DidNavigateEvent extends Event { + url: string; + } + + interface DidNavigateInPageEvent extends Event { + isMainFrame: boolean; + url: string; + } + + interface DidRedirectNavigationEvent extends Event { + url: string; + isInPlace: boolean; + isMainFrame: boolean; + frameProcessId: number; + frameRoutingId: number; + } + + interface DidStartNavigationEvent extends Event { + url: string; + isInPlace: boolean; + isMainFrame: boolean; + frameProcessId: number; + frameRoutingId: number; + } + + interface DisplayBalloonOptions { + /** + * Icon to use when `iconType` is `custom`. + */ + icon?: (NativeImage) | (string); + /** + * Can be `none`, `info`, `warning`, `error` or `custom`. Default is `custom`. + */ + iconType?: ('none' | 'info' | 'warning' | 'error' | 'custom'); + title: string; + content: string; + /** + * The large version of the icon should be used. Default is `true`. Maps to + * `NIIF_LARGE_ICON`. + */ + largeIcon?: boolean; + /** + * Do not play the associated sound. Default is `false`. Maps to `NIIF_NOSOUND`. + */ + noSound?: boolean; + /** + * Do not display the balloon notification if the current user is in "quiet time". + * Default is `false`. Maps to `NIIF_RESPECT_QUIET_TIME`. + */ + respectQuietTime?: boolean; + } + + interface EnableNetworkEmulationOptions { + /** + * Whether to emulate network outage. Defaults to false. + */ + offline?: boolean; + /** + * RTT in ms. Defaults to 0 which will disable latency throttling. + */ + latency?: number; + /** + * Download rate in Bps. Defaults to 0 which will disable download throttling. + */ + downloadThroughput?: number; + /** + * Upload rate in Bps. Defaults to 0 which will disable upload throttling. + */ + uploadThroughput?: number; + } + + interface FeedURLOptions { + url: string; + /** + * HTTP request headers. + * + * @platform darwin + */ + headers?: Record<string, string>; + /** + * Can be `json` or `default`, see the Squirrel.Mac README for more information. + * + * @platform darwin + */ + serverType?: ('json' | 'default'); + } + + interface FileIconOptions { + size: ('small' | 'normal' | 'large'); + } + + interface FindInPageOptions { + /** + * Whether to search forward or backward, defaults to `true`. + */ + forward?: boolean; + /** + * Whether to begin a new text finding session with this request. Should be `true` + * for initial requests, and `false` for follow-up requests. Defaults to `false`. + */ + findNext?: boolean; + /** + * Whether search should be case-sensitive, defaults to `false`. + */ + matchCase?: boolean; + } + + interface FocusOptions { + /** + * Make the receiver the active app even if another app is currently active. + * + * @platform darwin + */ + steal: boolean; + } + + interface FoundInPageEvent extends Event { + result: FoundInPageResult; + } + + interface FrameCreatedDetails { + frame: WebFrameMain; + } + + interface FromPartitionOptions { + /** + * Whether to enable cache. + */ + cache: boolean; + } + + interface HandlerDetails { + /** + * The _resolved_ version of the URL passed to `window.open()`. e.g. opening a + * window with `window.open('foo')` will yield something like + * `https://the-origin/the/current/path/foo`. + */ + url: string; + /** + * Name of the window provided in `window.open()` + */ + frameName: string; + /** + * Comma separated list of window features provided to `window.open()`. + */ + features: string; + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` or `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); + /** + * The referrer that will be passed to the new window. May or may not result in the + * `Referer` header being sent, depending on the referrer policy. + */ + referrer: Referrer; + /** + * The post data that will be sent to the new window, along with the appropriate + * headers that will be set. If no post data is to be sent, the value will be + * `null`. Only defined when the window is being created by a form that set + * `target=_blank`. + */ + postBody?: PostBody; + } + + interface HeadersReceivedResponse { + cancel?: boolean; + /** + * When provided, the server is assumed to have responded with these headers. + */ + responseHeaders?: Record<string, (string) | (string[])>; + /** + * Should be provided when overriding `responseHeaders` to change header status + * otherwise original response header's status will be used. + */ + statusLine?: string; + } + + interface HeapStatistics { + totalHeapSize: number; + totalHeapSizeExecutable: number; + totalPhysicalSize: number; + totalAvailableSize: number; + usedHeapSize: number; + heapSizeLimit: number; + mallocedMemory: number; + peakMallocedMemory: number; + doesZapGarbage: boolean; + } + + interface HidDeviceAddedDetails { + device: HIDDevice[]; + frame: WebFrameMain; + } + + interface HidDeviceRemovedDetails { + device: HIDDevice[]; + frame: WebFrameMain; + } + + interface HidDeviceRevokedDetails { + device: HIDDevice[]; + /** + * The origin that the device has been revoked from. + */ + origin?: string; + } + + interface IgnoreMouseEventsOptions { + /** + * If true, forwards mouse move messages to Chromium, enabling mouse related events + * such as `mouseleave`. Only used when `ignore` is true. If `ignore` is false, + * forwarding is always disabled regardless of this value. + * + * @platform darwin,win32 + */ + forward?: boolean; + } + + interface ImportCertificateOptions { + /** + * Path for the pkcs12 file. + */ + certificate: string; + /** + * Passphrase for the certificate. + */ + password: string; + } + + interface Info { + /** + * Security origin for the isolated world. + */ + securityOrigin?: string; + /** + * Content Security Policy for the isolated world. + */ + csp?: string; + /** + * Name for isolated world. Useful in devtools. + */ + name?: string; + } + + interface Input { + /** + * Either `keyUp` or `keyDown`. + */ + type: string; + /** + * Equivalent to KeyboardEvent.key. + */ + key: string; + /** + * Equivalent to KeyboardEvent.code. + */ + code: string; + /** + * Equivalent to KeyboardEvent.repeat. + */ + isAutoRepeat: boolean; + /** + * Equivalent to KeyboardEvent.isComposing. + */ + isComposing: boolean; + /** + * Equivalent to KeyboardEvent.shiftKey. + */ + shift: boolean; + /** + * Equivalent to KeyboardEvent.controlKey. + */ + control: boolean; + /** + * Equivalent to KeyboardEvent.altKey. + */ + alt: boolean; + /** + * Equivalent to KeyboardEvent.metaKey. + */ + meta: boolean; + /** + * Equivalent to KeyboardEvent.location. + */ + location: number; + /** + * See InputEvent.modifiers. + */ + modifiers: string[]; + } + + interface InsertCSSOptions { + /** + * Can be either 'user' or 'author'. Sets the cascade origin of the inserted + * stylesheet. Default is 'author'. + */ + cssOrigin?: string; + } + + interface IpcMessageEvent extends Event { + /** + * pair of `[processId, frameId]`. + */ + frameId: [number, number]; + channel: string; + args: any[]; + } + + interface Item { + /** + * The path to the file being dragged. + */ + file: string; + /** + * The paths to the files being dragged. (`files` will override `file` field) + */ + files?: string[]; + /** + * The image must be non-empty on macOS. + */ + icon: (NativeImage) | (string); + } + + interface JumpListSettings { + /** + * The minimum number of items that will be shown in the Jump List (for a more + * detailed description of this value see the MSDN docs). + */ + minItems: number; + /** + * Array of `JumpListItem` objects that correspond to items that the user has + * explicitly removed from custom categories in the Jump List. These items must not + * be re-added to the Jump List in the **next** call to `app.setJumpList()`, + * Windows will not display any custom category that contains any of the removed + * items. + */ + removedItems: JumpListItem[]; + } + + interface LoadCommitEvent extends Event { + url: string; + isMainFrame: boolean; + } + + interface LoadExtensionOptions { + /** + * Whether to allow the extension to read local files over `file://` protocol and + * inject content scripts into `file://` pages. This is required e.g. for loading + * devtools extensions on `file://` URLs. Defaults to false. + */ + allowFileAccess: boolean; + } + + interface LoadFileOptions { + /** + * Passed to `url.format()`. + */ + query?: Record<string, string>; + /** + * Passed to `url.format()`. + */ + search?: string; + /** + * Passed to `url.format()`. + */ + hash?: string; + } + + interface LoadURLOptions { + /** + * An HTTP Referrer url. + */ + httpReferrer?: (string) | (Referrer); + /** + * A user agent originating the request. + */ + userAgent?: string; + /** + * Extra headers separated by "\n" + */ + extraHeaders?: string; + postData?: Array<(UploadRawData) | (UploadFile)>; + /** + * Base url (with trailing path separator) for files to be loaded by the data url. + * This is needed only if the specified `url` is a data url and needs to load other + * files. + */ + baseURLForDataURL?: string; + } + + interface LoginItemSettings { + /** + * `true` if the app is set to open at login. + */ + openAtLogin: boolean; + /** + * `true` if the app is set to open as hidden at login. This setting is not + * available on MAS builds. + * + * @platform darwin + */ + openAsHidden: boolean; + /** + * `true` if the app was opened at login automatically. This setting is not + * available on MAS builds. + * + * @platform darwin + */ + wasOpenedAtLogin: boolean; + /** + * `true` if the app was opened as a hidden login item. This indicates that the app + * should not open any windows at startup. This setting is not available on MAS + * builds. + * + * @platform darwin + */ + wasOpenedAsHidden: boolean; + /** + * `true` if the app was opened as a login item that should restore the state from + * the previous session. This indicates that the app should restore the windows + * that were open the last time the app was closed. This setting is not available + * on MAS builds. + * + * @platform darwin + */ + restoreState: boolean; + /** + * `true` if app is set to open at login and its run key is not deactivated. This + * differs from `openAtLogin` as it ignores the `args` option, this property will + * be true if the given executable would be launched at login with **any** + * arguments. + * + * @platform win32 + */ + executableWillLaunchAtLogin: boolean; + launchItems: LaunchItems[]; + } + + interface LoginItemSettingsOptions { + /** + * The executable path to compare against. Defaults to `process.execPath`. + * + * @platform win32 + */ + path?: string; + /** + * The command-line arguments to compare against. Defaults to an empty array. + * + * @platform win32 + */ + args?: string[]; + } + + interface MenuItemConstructorOptions { + /** + * Will be called with `click(menuItem, browserWindow, event)` when the menu item + * is clicked. + */ + click?: (menuItem: MenuItem, browserWindow: (BrowserWindow) | (undefined), event: KeyboardEvent) => void; + /** + * Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, + * `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, + * `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, + * `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, + * 'showSubstitutions', 'toggleSmartQuotes', 'toggleSmartDashes', + * 'toggleTextReplacement', `startSpeaking`, `stopSpeaking`, `zoom`, `front`, + * `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, + * `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, + * `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action + * of the menu item, when specified the `click` property will be ignored. See + * roles. + */ + role?: ('undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'toggleSpellChecker' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'showSubstitutions' | 'toggleSmartQuotes' | 'toggleSmartDashes' | 'toggleTextReplacement' | 'startSpeaking' | 'stopSpeaking' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'shareMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'); + /** + * Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. + */ + type?: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'); + label?: string; + sublabel?: string; + /** + * Hover text for this menu item. + * + * @platform darwin + */ + toolTip?: string; + accelerator?: Accelerator; + icon?: (NativeImage) | (string); + /** + * If false, the menu item will be greyed out and unclickable. + */ + enabled?: boolean; + /** + * default is `true`, and when `false` will prevent the accelerator from triggering + * the item if the item is not visible`. + * + * @platform darwin + */ + acceleratorWorksWhenHidden?: boolean; + /** + * If false, the menu item will be entirely hidden. + */ + visible?: boolean; + /** + * Should only be specified for `checkbox` or `radio` type menu items. + */ + checked?: boolean; + /** + * If false, the accelerator won't be registered with the system, but it will still + * be displayed. Defaults to true. + * + * @platform linux,win32 + */ + registerAccelerator?: boolean; + /** + * The item to share when the `role` is `shareMenu`. + * + * @platform darwin + */ + sharingItem?: SharingItem; + /** + * Should be specified for `submenu` type menu items. If `submenu` is specified, + * the `type: 'submenu'` can be omitted. If the value is not a `Menu` then it will + * be automatically converted to one using `Menu.buildFromTemplate`. + */ + submenu?: (MenuItemConstructorOptions[]) | (Menu); + /** + * Unique within a single menu. If defined then it can be used as a reference to + * this item by the position attribute. + */ + id?: string; + /** + * Inserts this item before the item with the specified label. If the referenced + * item doesn't exist the item will be inserted at the end of the menu. Also + * implies that the menu item in question should be placed in the same β€œgroup” as + * the item. + */ + before?: string[]; + /** + * Inserts this item after the item with the specified label. If the referenced + * item doesn't exist the item will be inserted at the end of the menu. + */ + after?: string[]; + /** + * Provides a means for a single context menu to declare the placement of their + * containing group before the containing group of the item with the specified + * label. + */ + beforeGroupContaining?: string[]; + /** + * Provides a means for a single context menu to declare the placement of their + * containing group after the containing group of the item with the specified + * label. + */ + afterGroupContaining?: string[]; + } + + interface MessageBoxOptions { + /** + * Content of the message box. + */ + message: string; + /** + * Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, + * `"question"` displays the same icon as `"info"`, unless you set an icon using + * the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same + * warning icon. + */ + type?: string; + /** + * Array of texts for buttons. On Windows, an empty array will result in one button + * labeled "OK". + */ + buttons?: string[]; + /** + * Index of the button in the buttons array which will be selected by default when + * the message box opens. + */ + defaultId?: number; + /** + * Pass an instance of AbortSignal to optionally close the message box, the message + * box will behave as if it was cancelled by the user. On macOS, `signal` does not + * work with message boxes that do not have a parent window, since those message + * boxes run synchronously due to platform limitations. + */ + signal?: AbortSignal; + /** + * Title of the message box, some platforms will not show it. + */ + title?: string; + /** + * Extra information of the message. + */ + detail?: string; + /** + * If provided, the message box will include a checkbox with the given label. + */ + checkboxLabel?: string; + /** + * Initial checked state of the checkbox. `false` by default. + */ + checkboxChecked?: boolean; + icon?: (NativeImage) | (string); + /** + * Custom width of the text in the message box. + * + * @platform darwin + */ + textWidth?: number; + /** + * The index of the button to be used to cancel the dialog, via the `Esc` key. By + * default this is assigned to the first button with "cancel" or "no" as the label. + * If no such labeled buttons exist and this option is not set, `0` will be used as + * the return value. + */ + cancelId?: number; + /** + * On Windows Electron will try to figure out which one of the `buttons` are common + * buttons (like "Cancel" or "Yes"), and show the others as command links in the + * dialog. This can make the dialog appear in the style of modern Windows apps. If + * you don't like this behavior, you can set `noLink` to `true`. + */ + noLink?: boolean; + /** + * Normalize the keyboard access keys across platforms. Default is `false`. + * Enabling this assumes `&` is used in the button labels for the placement of the + * keyboard shortcut access key and labels will be converted so they work correctly + * on each platform, `&` characters are removed on macOS, converted to `_` on + * Linux, and left untouched on Windows. For example, a button label of `Vie&w` + * will be converted to `Vie_w` on Linux and `View` on macOS and can be selected + * via `Alt-W` on Windows and Linux. + */ + normalizeAccessKeys?: boolean; + } + + interface MessageBoxReturnValue { + /** + * The index of the clicked button. + */ + response: number; + /** + * The checked state of the checkbox if `checkboxLabel` was set. Otherwise `false`. + */ + checkboxChecked: boolean; + } + + interface MessageBoxSyncOptions { + /** + * Content of the message box. + */ + message: string; + /** + * Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, + * `"question"` displays the same icon as `"info"`, unless you set an icon using + * the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same + * warning icon. + */ + type?: string; + /** + * Array of texts for buttons. On Windows, an empty array will result in one button + * labeled "OK". + */ + buttons?: string[]; + /** + * Index of the button in the buttons array which will be selected by default when + * the message box opens. + */ + defaultId?: number; + /** + * Title of the message box, some platforms will not show it. + */ + title?: string; + /** + * Extra information of the message. + */ + detail?: string; + icon?: (NativeImage) | (string); + /** + * Custom width of the text in the message box. + * + * @platform darwin + */ + textWidth?: number; + /** + * The index of the button to be used to cancel the dialog, via the `Esc` key. By + * default this is assigned to the first button with "cancel" or "no" as the label. + * If no such labeled buttons exist and this option is not set, `0` will be used as + * the return value. + */ + cancelId?: number; + /** + * On Windows Electron will try to figure out which one of the `buttons` are common + * buttons (like "Cancel" or "Yes"), and show the others as command links in the + * dialog. This can make the dialog appear in the style of modern Windows apps. If + * you don't like this behavior, you can set `noLink` to `true`. + */ + noLink?: boolean; + /** + * Normalize the keyboard access keys across platforms. Default is `false`. + * Enabling this assumes `&` is used in the button labels for the placement of the + * keyboard shortcut access key and labels will be converted so they work correctly + * on each platform, `&` characters are removed on macOS, converted to `_` on + * Linux, and left untouched on Windows. For example, a button label of `Vie&w` + * will be converted to `Vie_w` on Linux and `View` on macOS and can be selected + * via `Alt-W` on Windows and Linux. + */ + normalizeAccessKeys?: boolean; + } + + interface MessageDetails { + /** + * The actual console message + */ + message: string; + /** + * The version ID of the service worker that sent the log message + */ + versionId: number; + /** + * The type of source for this message. Can be `javascript`, `xml`, `network`, + * `console-api`, `storage`, `rendering`, `security`, `deprecation`, `worker`, + * `violation`, `intervention`, `recommendation` or `other`. + */ + source: ('javascript' | 'xml' | 'network' | 'console-api' | 'storage' | 'rendering' | 'security' | 'deprecation' | 'worker' | 'violation' | 'intervention' | 'recommendation' | 'other'); + /** + * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and + * `error`. + */ + level: number; + /** + * The URL the message came from + */ + sourceUrl: string; + /** + * The line number of the source that triggered this console message + */ + lineNumber: number; + } + + interface MessageEvent { + data: any; + ports: MessagePortMain[]; + } + + interface MoveToApplicationsFolderOptions { + /** + * A handler for potential conflict in move failure. + */ + conflictHandler?: (conflictType: 'exists' | 'existsAndRunning') => boolean; + } + + interface NewWindowEvent extends Event { + url: string; + frameName: string; + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); + /** + * The options which should be used for creating the new `BrowserWindow`. + */ + options: BrowserWindowConstructorOptions; + } + + interface NotificationConstructorOptions { + /** + * A title for the notification, which will be shown at the top of the notification + * window when it is shown. + */ + title?: string; + /** + * A subtitle for the notification, which will be displayed below the title. + * + * @platform darwin + */ + subtitle?: string; + /** + * The body text of the notification, which will be displayed below the title or + * subtitle. + */ + body?: string; + /** + * Whether or not to emit an OS notification noise when showing the notification. + */ + silent?: boolean; + /** + * An icon to use in the notification. + */ + icon?: (string) | (NativeImage); + /** + * Whether or not to add an inline reply option to the notification. + * + * @platform darwin + */ + hasReply?: boolean; + /** + * The timeout duration of the notification. Can be 'default' or 'never'. + * + * @platform linux,win32 + */ + timeoutType?: ('default' | 'never'); + /** + * The placeholder to write in the inline reply input field. + * + * @platform darwin + */ + replyPlaceholder?: string; + /** + * The name of the sound file to play when the notification is shown. + * + * @platform darwin + */ + sound?: string; + /** + * The urgency level of the notification. Can be 'normal', 'critical', or 'low'. + * + * @platform linux + */ + urgency?: ('normal' | 'critical' | 'low'); + /** + * Actions to add to the notification. Please read the available actions and + * limitations in the `NotificationAction` documentation. + * + * @platform darwin + */ + actions?: NotificationAction[]; + /** + * A custom title for the close button of an alert. An empty string will cause the + * default localized text to be used. + * + * @platform darwin + */ + closeButtonText?: string; + /** + * A custom description of the Notification on Windows superseding all properties + * above. Provides full customization of design and behavior of the notification. + * + * @platform win32 + */ + toastXml?: string; + } + + interface OnBeforeRedirectListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + redirectURL: string; + statusCode: number; + statusLine: string; + /** + * The server IP address that the request was actually sent to. + */ + ip?: string; + fromCache: boolean; + responseHeaders?: Record<string, string[]>; + } + + interface OnBeforeRequestListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + uploadData: UploadData[]; + } + + interface OnBeforeSendHeadersListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + uploadData?: UploadData[]; + requestHeaders: Record<string, string>; + } + + interface OnCompletedListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + responseHeaders?: Record<string, string[]>; + fromCache: boolean; + statusCode: number; + statusLine: string; + error: string; + } + + interface OnErrorOccurredListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + fromCache: boolean; + /** + * The error description. + */ + error: string; + } + + interface OnHeadersReceivedListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + statusLine: string; + statusCode: number; + responseHeaders?: Record<string, string[]>; + } + + interface OnResponseStartedListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + responseHeaders?: Record<string, string[]>; + /** + * Indicates whether the response was fetched from disk cache. + */ + fromCache: boolean; + statusCode: number; + statusLine: string; + } + + interface OnSendHeadersListenerDetails { + id: number; + url: string; + method: string; + webContentsId?: number; + webContents?: WebContents; + frame?: WebFrameMain; + /** + * Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, + * `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`. + */ + resourceType: ('mainFrame' | 'subFrame' | 'stylesheet' | 'script' | 'image' | 'font' | 'object' | 'xhr' | 'ping' | 'cspReport' | 'media' | 'webSocket' | 'other'); + referrer: string; + timestamp: number; + requestHeaders: Record<string, string>; + } + + interface OpenDevToolsOptions { + /** + * Opens the devtools with specified dock state, can be `left`, `right`, `bottom`, + * `undocked`, `detach`. Defaults to last used dock state. In `undocked` mode it's + * possible to dock back. In `detach` mode it's not. + */ + mode: ('left' | 'right' | 'bottom' | 'undocked' | 'detach'); + /** + * Whether to bring the opened devtools window to the foreground. The default is + * `true`. + */ + activate?: boolean; + } + + interface OpenDialogOptions { + title?: string; + defaultPath?: string; + /** + * Custom label for the confirmation button, when left empty the default label will + * be used. + */ + buttonLabel?: string; + filters?: FileFilter[]; + /** + * Contains which features the dialog should use. The following values are + * supported: + */ + properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory' | 'dontAddToRecent'>; + /** + * Message to display above input boxes. + * + * @platform darwin + */ + message?: string; + /** + * Create security scoped bookmarks when packaged for the Mac App Store. + * + * @platform darwin,mas + */ + securityScopedBookmarks?: boolean; + } + + interface OpenDialogReturnValue { + /** + * whether or not the dialog was canceled. + */ + canceled: boolean; + /** + * An array of file paths chosen by the user. If the dialog is cancelled this will + * be an empty array. + */ + filePaths: string[]; + /** + * An array matching the `filePaths` array of base64 encoded strings which contains + * security scoped bookmark data. `securityScopedBookmarks` must be enabled for + * this to be populated. (For return values, see table here.) + * + * @platform darwin,mas + */ + bookmarks?: string[]; + } + + interface OpenDialogSyncOptions { + title?: string; + defaultPath?: string; + /** + * Custom label for the confirmation button, when left empty the default label will + * be used. + */ + buttonLabel?: string; + filters?: FileFilter[]; + /** + * Contains which features the dialog should use. The following values are + * supported: + */ + properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory' | 'dontAddToRecent'>; + /** + * Message to display above input boxes. + * + * @platform darwin + */ + message?: string; + /** + * Create security scoped bookmarks when packaged for the Mac App Store. + * + * @platform darwin,mas + */ + securityScopedBookmarks?: boolean; + } + + interface OpenExternalOptions { + /** + * `true` to bring the opened application to the foreground. The default is `true`. + * + * @platform darwin + */ + activate?: boolean; + /** + * The working directory. + * + * @platform win32 + */ + workingDirectory?: string; + } + + interface Options { + } + + interface PageFaviconUpdatedEvent extends Event { + /** + * Array of URLs. + */ + favicons: string[]; + } + + interface PageTitleUpdatedEvent extends Event { + title: string; + explicitSet: boolean; + } + + interface Parameters { + /** + * Specify the screen type to emulate (default: `desktop`): + */ + screenPosition: ('desktop' | 'mobile'); + /** + * Set the emulated screen size (screenPosition == mobile). + */ + screenSize: Size; + /** + * Position the view on the screen (screenPosition == mobile) (default: `{ x: 0, y: + * 0 }`). + */ + viewPosition: Point; + /** + * Set the device scale factor (if zero defaults to original device scale factor) + * (default: `0`). + */ + deviceScaleFactor: number; + /** + * Set the emulated view size (empty means no override) + */ + viewSize: Size; + /** + * Scale of emulated view inside available space (not in fit to view mode) + * (default: `1`). + */ + scale: number; + } + + interface Payment { + /** + * The identifier of the purchased product. + */ + productIdentifier: string; + /** + * The quantity purchased. + */ + quantity: number; + /** + * An opaque identifier for the user’s account on your system. + */ + applicationUsername: string; + /** + * The details of the discount offer to apply to the payment. + */ + paymentDiscount?: PaymentDiscount; + } + + interface PermissionCheckHandlerHandlerDetails { + /** + * The origin of the frame embedding the frame that made the permission check. + * Only set for cross-origin sub frames making permission checks. + */ + embeddingOrigin?: string; + /** + * The security origin of the `media` check. + */ + securityOrigin?: string; + /** + * The type of media access being requested, can be `video`, `audio` or `unknown` + */ + mediaType?: ('video' | 'audio' | 'unknown'); + /** + * The last URL the requesting frame loaded. This is not provided for cross-origin + * sub frames making permission checks. + */ + requestingUrl?: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; + } + + interface PermissionRequestHandlerHandlerDetails { + /** + * The url of the `openExternal` request. + */ + externalURL?: string; + /** + * The security origin of the `media` request. + */ + securityOrigin?: string; + /** + * The types of media access being requested, elements can be `video` or `audio` + */ + mediaTypes?: Array<'video' | 'audio'>; + /** + * The last URL the requesting frame loaded + */ + requestingUrl: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; + } + + interface PluginCrashedEvent extends Event { + name: string; + version: string; + } + + interface PopupOptions { + /** + * Default is the focused window. + */ + window?: BrowserWindow; + /** + * Default is the current mouse cursor position. Must be declared if `y` is + * declared. + */ + x?: number; + /** + * Default is the current mouse cursor position. Must be declared if `x` is + * declared. + */ + y?: number; + /** + * The index of the menu item to be positioned under the mouse cursor at the + * specified coordinates. Default is -1. + * + * @platform darwin + */ + positioningItem?: number; + /** + * Called when menu is closed. + */ + callback?: () => void; + } + + interface PreconnectOptions { + /** + * URL for preconnect. Only the origin is relevant for opening the socket. + */ + url: string; + /** + * number of sockets to preconnect. Must be between 1 and 6. Defaults to 1. + */ + numSockets?: number; + } + + interface PrintToPDFOptions { + /** + * Paper orientation.`true` for landscape, `false` for portrait. Defaults to false. + */ + landscape?: boolean; + /** + * Whether to display header and footer. Defaults to false. + */ + displayHeaderFooter?: boolean; + /** + * Whether to print background graphics. Defaults to false. + */ + printBackground?: boolean; + /** + * Scale of the webpage rendering. Defaults to 1. + */ + scale?: number; + /** + * 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`. + */ + pageSize?: (string) | (Size); + margins?: Margins; + /** + * Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, + * which means print all pages. + */ + pageRanges?: string; + /** + * 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. + */ + headerTemplate?: string; + /** + * HTML template for the print footer. Should use the same format as the + * `headerTemplate`. + */ + footerTemplate?: string; + /** + * 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. + */ + preferCSSPageSize?: boolean; + } + + interface Privileges { + /** + * Default false. + */ + standard?: boolean; + /** + * Default false. + */ + secure?: boolean; + /** + * Default false. + */ + bypassCSP?: boolean; + /** + * Default false. + */ + allowServiceWorkers?: boolean; + /** + * Default false. + */ + supportFetchAPI?: boolean; + /** + * Default false. + */ + corsEnabled?: boolean; + /** + * Default false. + */ + stream?: boolean; + } + + interface ProgressBarOptions { + /** + * Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or + * `paused`. + * + * @platform win32 + */ + mode: ('none' | 'normal' | 'indeterminate' | 'error' | 'paused'); + } + + interface Provider { + spellCheck: (words: string[], callback: (misspeltWords: string[]) => void) => void; + } + + interface ReadBookmark { + title: string; + url: string; + } + + interface RegistrationCompletedDetails { + /** + * The base URL that a service worker is registered for + */ + scope: string; + } + + interface RelaunchOptions { + args?: string[]; + execPath?: string; + } + + interface RenderProcessGoneDetails { + /** + * The reason the render process is gone. Possible values: + */ + reason: ('clean-exit' | 'abnormal-exit' | 'killed' | 'crashed' | 'oom' | 'launch-failed' | 'integrity-failure'); + /** + * The exit code of the process, unless `reason` is `launch-failed`, in which case + * `exitCode` will be a platform-specific launch failure error code. + */ + exitCode: number; + } + + interface Request { + hostname: string; + certificate: Certificate; + validatedCertificate: Certificate; + /** + * `true` if Chromium recognises the root CA as a standard root. If it isn't then + * it's probably the case that this certificate was generated by a MITM proxy whose + * root has been installed locally (for example, by a corporate proxy). This should + * not be trusted if the `verificationResult` is not `OK`. + */ + isIssuedByKnownRoot: boolean; + /** + * `OK` if the certificate is trusted, otherwise an error like `CERT_REVOKED`. + */ + verificationResult: string; + /** + * Error code. + */ + errorCode: number; + } + + interface ResizeOptions { + /** + * Defaults to the image's width. + */ + width?: number; + /** + * Defaults to the image's height. + */ + height?: number; + /** + * The desired quality of the resize image. Possible values are `good`, `better`, + * or `best`. The default is `best`. These values express a desired quality/speed + * tradeoff. They are translated into an algorithm-specific method that depends on + * the capabilities (CPU, GPU) of the underlying platform. It is possible for all + * three methods to be mapped to the same algorithm on a given platform. + */ + quality?: string; + } + + interface ResourceUsage { + images: MemoryUsageDetails; + scripts: MemoryUsageDetails; + cssStyleSheets: MemoryUsageDetails; + xslStyleSheets: MemoryUsageDetails; + fonts: MemoryUsageDetails; + other: MemoryUsageDetails; + } + + interface Response { + /** + * `false` should be passed in if the dialog is canceled. If the `pairingKind` is + * `confirm` or `confirmPin`, this value should indicate if the pairing is + * confirmed. If the `pairingKind` is `providePin` the value should be `true` when + * a value is provided. + */ + confirmed: boolean; + /** + * When the `pairingKind` is `providePin` this value should be the required pin for + * the Bluetooth device. + */ + pin?: (string) | (null); + } + + interface Result { + requestId: number; + /** + * Position of the active match. + */ + activeMatchOrdinal: number; + /** + * Number of Matches. + */ + matches: number; + /** + * Coordinates of first match region. + */ + selectionArea: Rectangle; + finalUpdate: boolean; + } + + interface SaveDialogOptions { + /** + * The dialog title. Cannot be displayed on some _Linux_ desktop environments. + */ + title?: string; + /** + * Absolute directory path, absolute file path, or file name to use by default. + */ + defaultPath?: string; + /** + * Custom label for the confirmation button, when left empty the default label will + * be used. + */ + buttonLabel?: string; + filters?: FileFilter[]; + /** + * Message to display above text fields. + * + * @platform darwin + */ + message?: string; + /** + * Custom label for the text displayed in front of the filename text field. + * + * @platform darwin + */ + nameFieldLabel?: string; + /** + * Show the tags input box, defaults to `true`. + * + * @platform darwin + */ + showsTagField?: boolean; + properties?: Array<'showHiddenFiles' | 'createDirectory' | 'treatPackageAsDirectory' | 'showOverwriteConfirmation' | 'dontAddToRecent'>; + /** + * Create a security scoped bookmark when packaged for the Mac App Store. If this + * option is enabled and the file doesn't already exist a blank file will be + * created at the chosen path. + * + * @platform darwin,mas + */ + securityScopedBookmarks?: boolean; + } + + interface SaveDialogReturnValue { + /** + * whether or not the dialog was canceled. + */ + canceled: boolean; + /** + * If the dialog is canceled, this will be `undefined`. + */ + filePath?: string; + /** + * Base64 encoded string which contains the security scoped bookmark data for the + * saved file. `securityScopedBookmarks` must be enabled for this to be present. + * (For return values, see table here.) + * + * @platform darwin,mas + */ + bookmark?: string; + } + + interface SaveDialogSyncOptions { + /** + * The dialog title. Cannot be displayed on some _Linux_ desktop environments. + */ + title?: string; + /** + * Absolute directory path, absolute file path, or file name to use by default. + */ + defaultPath?: string; + /** + * Custom label for the confirmation button, when left empty the default label will + * be used. + */ + buttonLabel?: string; + filters?: FileFilter[]; + /** + * Message to display above text fields. + * + * @platform darwin + */ + message?: string; + /** + * Custom label for the text displayed in front of the filename text field. + * + * @platform darwin + */ + nameFieldLabel?: string; + /** + * Show the tags input box, defaults to `true`. + * + * @platform darwin + */ + showsTagField?: boolean; + properties?: Array<'showHiddenFiles' | 'createDirectory' | 'treatPackageAsDirectory' | 'showOverwriteConfirmation' | 'dontAddToRecent'>; + /** + * Create a security scoped bookmark when packaged for the Mac App Store. If this + * option is enabled and the file doesn't already exist a blank file will be + * created at the chosen path. + * + * @platform darwin,mas + */ + securityScopedBookmarks?: boolean; + } + + interface SelectHidDeviceDetails { + deviceList: HIDDevice[]; + frame: WebFrameMain; + } + + interface Settings { + /** + * `true` to open the app at login, `false` to remove the app as a login item. + * Defaults to `false`. + */ + openAtLogin?: boolean; + /** + * `true` to open the app as hidden. Defaults to `false`. The user can edit this + * setting from the System Preferences so + * `app.getLoginItemSettings().wasOpenedAsHidden` should be checked when the app is + * opened to know the current value. This setting is not available on MAS builds. + * + * @platform darwin + */ + openAsHidden?: boolean; + /** + * The executable to launch at login. Defaults to `process.execPath`. + * + * @platform win32 + */ + path?: string; + /** + * The command-line arguments to pass to the executable. Defaults to an empty + * array. Take care to wrap paths in quotes. + * + * @platform win32 + */ + args?: string[]; + /** + * `true` will change the startup approved registry key and `enable / disable` the + * App in Task Manager and Windows Settings. Defaults to `true`. + * + * @platform win32 + */ + enabled?: boolean; + /** + * value name to write into registry. Defaults to the app's AppUserModelId(). Set + * the app's login item settings. + * + * @platform win32 + */ + name?: string; + } + + interface SourcesOptions { + /** + * An array of strings that lists the types of desktop sources to be captured, + * available types are `screen` and `window`. + */ + types: string[]; + /** + * The size that the media source thumbnail should be scaled to. Default is `150` x + * `150`. Set width or height to 0 when you do not need the thumbnails. This will + * save the processing time required for capturing the content of each window and + * screen. + */ + thumbnailSize?: Size; + /** + * Set to true to enable fetching window icons. The default value is false. When + * false the appIcon property of the sources return null. Same if a source has the + * type screen. + */ + fetchWindowIcons?: boolean; + } + + interface SSLConfigConfig { + /** + * Can be `tls1`, `tls1.1`, `tls1.2` or `tls1.3`. The minimum SSL version to allow + * when connecting to remote servers. Defaults to `tls1`. + */ + minVersion?: string; + /** + * Can be `tls1.2` or `tls1.3`. The maximum SSL version to allow when connecting to + * remote servers. Defaults to `tls1.3`. + */ + maxVersion?: string; + /** + * List of cipher suites which should be explicitly prevented from being used in + * addition to those disabled by the net built-in policy. Supported literal forms: + * 0xAABB, where AA is `cipher_suite[0]` and BB is `cipher_suite[1]`, as defined in + * RFC 2246, Section 7.4.1.2. Unrecognized but parsable cipher suites in this form + * will not return an error. Ex: To disable TLS_RSA_WITH_RC4_128_MD5, specify + * 0x0004, while to disable TLS_ECDH_ECDSA_WITH_RC4_128_SHA, specify 0xC002. Note + * that TLSv1.3 ciphers cannot be disabled using this mechanism. + */ + disabledCipherSuites?: number[]; + } + + interface StartLoggingOptions { + /** + * What kinds of data should be captured. By default, only metadata about requests + * will be captured. Setting this to `includeSensitive` will include cookies and + * authentication data. Setting it to `everything` will include all bytes + * transferred on sockets. Can be `default`, `includeSensitive` or `everything`. + */ + captureMode?: ('default' | 'includeSensitive' | 'everything'); + /** + * When the log grows beyond this size, logging will automatically stop. Defaults + * to unlimited. + */ + maxFileSize?: number; + } + + interface SystemMemoryInfo { + /** + * The total amount of physical memory in Kilobytes available to the system. + */ + total: number; + /** + * The total amount of memory not being used by applications or disk cache. + */ + free: number; + /** + * The total amount of swap memory in Kilobytes available to the system. + * + * @platform win32,linux + */ + swapTotal: number; + /** + * The free amount of swap memory in Kilobytes available to the system. + * + * @platform win32,linux + */ + swapFree: number; + } + + interface TitleBarOverlayOptions { + /** + * The CSS color of the Window Controls Overlay when enabled. + * + * @platform win32 + */ + color?: string; + /** + * The CSS color of the symbols on the Window Controls Overlay when enabled. + * + * @platform win32 + */ + symbolColor?: string; + /** + * The height of the title bar and Window Controls Overlay in pixels. + * + * @platform win32 + */ + height?: number; + } + + interface TitleOptions { + /** + * The font family variant to display, can be `monospaced` or `monospacedDigit`. + * `monospaced` is available in macOS 10.15+ and `monospacedDigit` is available in + * macOS 10.11+. When left blank, the title uses the default system font. + */ + fontType?: ('monospaced' | 'monospacedDigit'); + } + + interface ToBitmapOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface ToDataURLOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface ToPNGOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface TouchBarButtonConstructorOptions { + /** + * Button text. + */ + label?: string; + /** + * A short description of the button for use by screenreaders like VoiceOver. + */ + accessibilityLabel?: string; + /** + * Button background color in hex format, i.e `#ABCDEF`. + */ + backgroundColor?: string; + /** + * Button icon. + */ + icon?: (NativeImage) | (string); + /** + * Can be `left`, `right` or `overlay`. Defaults to `overlay`. + */ + iconPosition?: ('left' | 'right' | 'overlay'); + /** + * Function to call when the button is clicked. + */ + click?: () => void; + /** + * Whether the button is in an enabled state. Default is `true`. + */ + enabled?: boolean; + } + + interface TouchBarColorPickerConstructorOptions { + /** + * Array of hex color strings to appear as possible colors to select. + */ + availableColors?: string[]; + /** + * The selected hex color in the picker, i.e `#ABCDEF`. + */ + selectedColor?: string; + /** + * Function to call when a color is selected. + */ + change?: (color: string) => void; + } + + interface TouchBarConstructorOptions { + items?: Array<(TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer)>; + escapeItem?: (TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer) | (null); + } + + interface TouchBarGroupConstructorOptions { + /** + * Items to display as a group. + */ + items: TouchBar; + } + + interface TouchBarLabelConstructorOptions { + /** + * Text to display. + */ + label?: string; + /** + * A short description of the button for use by screenreaders like VoiceOver. + */ + accessibilityLabel?: string; + /** + * Hex color of text, i.e `#ABCDEF`. + */ + textColor?: string; + } + + interface TouchBarPopoverConstructorOptions { + /** + * Popover button text. + */ + label?: string; + /** + * Popover button icon. + */ + icon?: NativeImage; + /** + * Items to display in the popover. + */ + items: TouchBar; + /** + * `true` to display a close button on the left of the popover, `false` to not show + * it. Default is `true`. + */ + showCloseButton?: boolean; + } + + interface TouchBarScrubberConstructorOptions { + /** + * An array of items to place in this scrubber. + */ + items: ScrubberItem[]; + /** + * Called when the user taps an item that was not the last tapped item. + */ + select?: (selectedIndex: number) => void; + /** + * Called when the user taps any item. + */ + highlight?: (highlightedIndex: number) => void; + /** + * Selected item style. Can be `background`, `outline` or `none`. Defaults to + * `none`. + */ + selectedStyle?: ('background' | 'outline' | 'none'); + /** + * Selected overlay item style. Can be `background`, `outline` or `none`. Defaults + * to `none`. + */ + overlayStyle?: ('background' | 'outline' | 'none'); + /** + * Whether to show arrow buttons. Defaults to `false` and is only shown if `items` + * is non-empty. + */ + showArrowButtons?: boolean; + /** + * Can be `fixed` or `free`. The default is `free`. + */ + mode?: ('fixed' | 'free'); + /** + * Defaults to `true`. + */ + continuous?: boolean; + } + + interface TouchBarSegmentedControlConstructorOptions { + /** + * Style of the segments: + */ + segmentStyle?: ('automatic' | 'rounded' | 'textured-rounded' | 'round-rect' | 'textured-square' | 'capsule' | 'small-square' | 'separated'); + /** + * The selection mode of the control: + */ + mode?: ('single' | 'multiple' | 'buttons'); + /** + * An array of segments to place in this control. + */ + segments: SegmentedControlSegment[]; + /** + * The index of the currently selected segment, will update automatically with user + * interaction. When the mode is `multiple` it will be the last selected item. + */ + selectedIndex?: number; + /** + * Called when the user selects a new segment. + */ + change?: (selectedIndex: number, isSelected: boolean) => void; + } + + interface TouchBarSliderConstructorOptions { + /** + * Label text. + */ + label?: string; + /** + * Selected value. + */ + value?: number; + /** + * Minimum value. + */ + minValue?: number; + /** + * Maximum value. + */ + maxValue?: number; + /** + * Function to call when the slider is changed. + */ + change?: (newValue: number) => void; + } + + interface TouchBarSpacerConstructorOptions { + /** + * Size of spacer, possible values are: + */ + size?: ('small' | 'large' | 'flexible'); + } + + interface TraceBufferUsageReturnValue { + value: number; + percentage: number; + } + + interface UpdateTargetUrlEvent extends Event { + url: string; + } + + interface UploadProgress { + /** + * Whether the request is currently active. If this is false no other properties + * will be set + */ + active: boolean; + /** + * Whether the upload has started. If this is false both `current` and `total` will + * be set to 0. + */ + started: boolean; + /** + * The number of bytes that have been uploaded so far + */ + current: number; + /** + * The number of bytes that will be uploaded this request + */ + total: number; + } + + interface VisibleOnAllWorkspacesOptions { + /** + * Sets whether the window should be visible above fullscreen windows. + * + * @platform darwin + */ + visibleOnFullScreen?: boolean; + /** + * Calling setVisibleOnAllWorkspaces will by default transform the process type + * between UIElementApplication and ForegroundApplication to ensure the correct + * behavior. However, this will hide the window and dock for a short time every + * time it is called. If your window is already of type UIElementApplication, you + * can bypass this transformation by passing true to skipTransformProcessType. + * + * @platform darwin + */ + skipTransformProcessType?: boolean; + } + + interface WebContentsPrintOptions { + /** + * Don't ask user for print settings. Default is `false`. + */ + silent?: boolean; + /** + * Prints the background color and image of the web page. Default is `false`. + */ + printBackground?: boolean; + /** + * Set the printer device name to use. Must be the system-defined name and not the + * 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. + */ + deviceName?: string; + /** + * Set whether the printed web page will be in color or grayscale. Default is + * `true`. + */ + color?: boolean; + margins?: Margins; + /** + * Whether the web page should be printed in landscape mode. Default is `false`. + */ + landscape?: boolean; + /** + * The scale factor of the web page. + */ + scaleFactor?: number; + /** + * The number of pages to print per page sheet. + */ + pagesPerSheet?: number; + /** + * Whether the web page should be collated. + */ + collate?: boolean; + /** + * The number of copies of the web page to print. + */ + copies?: number; + /** + * The page range to print. On macOS, only one range is honored. + */ + pageRanges?: PageRanges[]; + /** + * Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or + * `longEdge`. + */ + duplexMode?: ('simplex' | 'shortEdge' | 'longEdge'); + dpi?: Record<string, number>; + /** + * string to be printed as page header. + */ + header?: string; + /** + * string to be printed as page footer. + */ + footer?: string; + /** + * Specify page size of the printed document. Can be `A3`, `A4`, `A5`, `Legal`, + * `Letter`, `Tabloid` or an Object containing `height` and `width`. + */ + pageSize?: (string) | (Size); + } + + interface WebviewTagPrintOptions { + /** + * Don't ask user for print settings. Default is `false`. + */ + silent?: boolean; + /** + * Prints the background color and image of the web page. Default is `false`. + */ + printBackground?: boolean; + /** + * Set the printer device name to use. Must be the system-defined name and not the + * 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. + */ + deviceName?: string; + /** + * Set whether the printed web page will be in color or grayscale. Default is + * `true`. + */ + color?: boolean; + margins?: Margins; + /** + * Whether the web page should be printed in landscape mode. Default is `false`. + */ + landscape?: boolean; + /** + * The scale factor of the web page. + */ + scaleFactor?: number; + /** + * The number of pages to print per page sheet. + */ + pagesPerSheet?: number; + /** + * Whether the web page should be collated. + */ + collate?: boolean; + /** + * The number of copies of the web page to print. + */ + copies?: number; + /** + * The page range to print. + */ + pageRanges?: PageRanges[]; + /** + * Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or + * `longEdge`. + */ + duplexMode?: ('simplex' | 'shortEdge' | 'longEdge'); + dpi?: Record<string, number>; + /** + * string to be printed as page header. + */ + header?: string; + /** + * string to be printed as page footer. + */ + footer?: string; + /** + * Specify page size of the printed document. Can be `A3`, `A4`, `A5`, `Legal`, + * `Letter`, `Tabloid` or an Object containing `height` in microns. + */ + pageSize?: (string) | (Size); + } + + interface WillNavigateEvent extends Event { + url: string; + } + + interface WillResizeDetails { + /** + * The edge of the window being dragged for resizing. Can be `bottom`, `left`, + * `right`, `top-left`, `top-right`, `bottom-left` or `bottom-right`. + */ + edge: ('bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'); + } + + interface EditFlags { + /** + * Whether the renderer believes it can undo. + */ + canUndo: boolean; + /** + * Whether the renderer believes it can redo. + */ + canRedo: boolean; + /** + * Whether the renderer believes it can cut. + */ + canCut: boolean; + /** + * Whether the renderer believes it can copy. + */ + canCopy: boolean; + /** + * Whether the renderer believes it can paste. + */ + canPaste: boolean; + /** + * Whether the renderer believes it can delete. + */ + canDelete: boolean; + /** + * Whether the renderer believes it can select all. + */ + canSelectAll: boolean; + /** + * Whether the renderer believes it can edit text richly. + */ + canEditRichly: boolean; + } + + interface FoundInPageResult { + requestId: number; + /** + * Position of the active match. + */ + activeMatchOrdinal: number; + /** + * Number of Matches. + */ + matches: number; + /** + * Coordinates of first match region. + */ + selectionArea: Rectangle; + finalUpdate: boolean; + } + + interface LaunchItems { + /** + * name value of a registry entry. + * + * @platform win32 + */ + name: string; + /** + * The executable to an app that corresponds to a registry entry. + * + * @platform win32 + */ + path: string; + /** + * the command-line arguments to pass to the executable. + * + * @platform win32 + */ + args: string[]; + /** + * one of `user` or `machine`. Indicates whether the registry entry is under + * `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. + * + * @platform win32 + */ + scope: string; + /** + * `true` if the app registry key is startup approved and therefore shows as + * `enabled` in Task Manager and Windows settings. + * + * @platform win32 + */ + enabled: boolean; + } + + interface Margins { + /** + * Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, + * you will also need to specify `top`, `bottom`, `left`, and `right`. + */ + marginType?: ('default' | 'none' | 'printableArea' | 'custom'); + /** + * The top margin of the printed web page, in pixels. + */ + top?: number; + /** + * The bottom margin of the printed web page, in pixels. + */ + bottom?: number; + /** + * The left margin of the printed web page, in pixels. + */ + left?: number; + /** + * The right margin of the printed web page, in pixels. + */ + right?: number; + } + + interface MediaFlags { + /** + * Whether the media element has crashed. + */ + inError: boolean; + /** + * Whether the media element is paused. + */ + isPaused: boolean; + /** + * Whether the media element is muted. + */ + isMuted: boolean; + /** + * Whether the media element has audio. + */ + hasAudio: boolean; + /** + * Whether the media element is looping. + */ + isLooping: boolean; + /** + * Whether the media element's controls are visible. + */ + isControlsVisible: boolean; + /** + * Whether the media element's controls are toggleable. + */ + canToggleControls: boolean; + /** + * Whether the media element can be printed. + */ + canPrint: boolean; + /** + * Whether or not the media element can be downloaded. + */ + canSave: boolean; + /** + * Whether the media element can show picture-in-picture. + */ + canShowPictureInPicture: boolean; + /** + * Whether the media element is currently showing picture-in-picture. + */ + isShowingPictureInPicture: boolean; + /** + * Whether the media element can be rotated. + */ + canRotate: boolean; + /** + * Whether the media element can be looped. + */ + canLoop: boolean; + } + + interface PageRanges { + /** + * Index of the first page to print (0-based). + */ + from: number; + /** + * Index of the last page to print (inclusive) (0-based). + */ + to: number; + } + + interface Params { + /** + * x coordinate. + */ + x: number; + /** + * y coordinate. + */ + y: number; + /** + * URL of the link that encloses the node the context menu was invoked on. + */ + linkURL: string; + /** + * Text associated with the link. May be an empty string if the contents of the + * link are an image. + */ + linkText: string; + /** + * URL of the top level page that the context menu was invoked on. + */ + pageURL: string; + /** + * URL of the subframe that the context menu was invoked on. + */ + frameURL: string; + /** + * Source URL for the element that the context menu was invoked on. Elements with + * source URLs are images, audio and video. + */ + srcURL: string; + /** + * Type of the node the context menu was invoked on. Can be `none`, `image`, + * `audio`, `video`, `canvas`, `file` or `plugin`. + */ + mediaType: ('none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'); + /** + * Whether the context menu was invoked on an image which has non-empty contents. + */ + hasImageContents: boolean; + /** + * Whether the context is editable. + */ + isEditable: boolean; + /** + * Text of the selection that the context menu was invoked on. + */ + selectionText: string; + /** + * Title text of the selection that the context menu was invoked on. + */ + titleText: string; + /** + * Alt text of the selection that the context menu was invoked on. + */ + altText: string; + /** + * Suggested filename to be used when saving file through 'Save Link As' option of + * context menu. + */ + suggestedFilename: string; + /** + * Rect representing the coordinates in the document space of the selection. + */ + selectionRect: Rectangle; + /** + * Start position of the selection text. + */ + selectionStartOffset: number; + /** + * The referrer policy of the frame on which the menu is invoked. + */ + referrerPolicy: Referrer; + /** + * The misspelled word under the cursor, if any. + */ + misspelledWord: string; + /** + * An array of suggested words to show the user to replace the `misspelledWord`. + * Only available if there is a misspelled word and spellchecker is enabled. + */ + dictionarySuggestions: string[]; + /** + * The character encoding of the frame on which the menu was invoked. + */ + frameCharset: string; + /** + * If the context menu was invoked on an input field, the type of that field. + * Possible values are `none`, `plainText`, `password`, `other`. + */ + inputFieldType: string; + /** + * If the context is editable, whether or not spellchecking is enabled. + */ + spellcheckEnabled: boolean; + /** + * Input source that invoked the context menu. Can be `none`, `mouse`, `keyboard`, + * `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, + * `adjustSelection`, or `adjustSelectionReset`. + */ + menuSourceType: ('none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu' | 'longPress' | 'longTap' | 'touchHandle' | 'stylus' | 'adjustSelection' | 'adjustSelectionReset'); + /** + * The flags for the media element the context menu was invoked on. + */ + mediaFlags: MediaFlags; + /** + * These flags indicate whether the renderer believes it is able to perform the + * corresponding action. + */ + editFlags: EditFlags; + } + + interface TitleBarOverlay { + /** + * The CSS color of the Window Controls Overlay when enabled. Default is the system + * color. + * + * @platform win32 + */ + color?: string; + /** + * The CSS color of the symbols on the Window Controls Overlay when enabled. + * Default is the system color. + * + * @platform win32 + */ + symbolColor?: string; + /** + * The height of the title bar and Window Controls Overlay in pixels. Default is + * system height. + * + * @platform darwin,win32 + */ + height?: number; + } + + interface WebPreferences { + /** + * Whether to enable DevTools. If it is set to `false`, can not use + * `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. + */ + devTools?: boolean; + /** + * Whether node integration is enabled. Default is `false`. + */ + nodeIntegration?: boolean; + /** + * Whether node integration is enabled in web workers. Default is `false`. More + * about this can be found in Multithreading. + */ + nodeIntegrationInWorker?: boolean; + /** + * Experimental option for enabling Node.js support in sub-frames such as iframes + * and child windows. All your preloads will load for every iframe, you can use + * `process.isMainFrame` to determine if you are in the main frame or not. + */ + nodeIntegrationInSubFrames?: boolean; + /** + * Specifies a script that will be loaded before other scripts run in the page. + * This script will always have access to node APIs no matter whether node + * integration is turned on or off. The value should be the absolute file path to + * the script. When node integration is turned off, the preload script can + * reintroduce Node global symbols back to the global scope. See example here. + */ + preload?: string; + /** + * If set, this will sandbox the renderer associated with the window, making it + * compatible with the Chromium OS-level sandbox and disabling the Node.js engine. + * This is not the same as the `nodeIntegration` option and the APIs available to + * the preload script are more limited. Read more about the option here. + */ + sandbox?: boolean; + /** + * Sets the session used by the page. Instead of passing the Session object + * directly, you can also choose to use the `partition` option instead, which + * accepts a partition string. When both `session` and `partition` are provided, + * `session` will be preferred. Default is the default session. + */ + session?: Session; + /** + * Sets the session used by the page according to the session's partition string. + * If `partition` starts with `persist:`, the page will use a persistent session + * available to all pages in the app with the same `partition`. If there is no + * `persist:` prefix, the page will use an in-memory session. By assigning the same + * `partition`, multiple pages can share the same session. Default is the default + * session. + */ + partition?: string; + /** + * The default zoom factor of the page, `3.0` represents `300%`. Default is `1.0`. + */ + zoomFactor?: number; + /** + * Enables JavaScript support. Default is `true`. + */ + javascript?: boolean; + /** + * When `false`, it will disable the same-origin policy (usually using testing + * websites by people), and set `allowRunningInsecureContent` to `true` if this + * options has not been set by user. Default is `true`. + */ + webSecurity?: boolean; + /** + * Allow an https page to run JavaScript, CSS or plugins from http URLs. Default is + * `false`. + */ + allowRunningInsecureContent?: boolean; + /** + * Enables image support. Default is `true`. + */ + images?: boolean; + /** + * Specifies how to run image animations (E.g. GIFs). Can be `animate`, + * `animateOnce` or `noAnimation`. Default is `animate`. + */ + imageAnimationPolicy?: ('animate' | 'animateOnce' | 'noAnimation'); + /** + * Make TextArea elements resizable. Default is `true`. + */ + textAreasAreResizable?: boolean; + /** + * Enables WebGL support. Default is `true`. + */ + webgl?: boolean; + /** + * Whether plugins should be enabled. Default is `false`. + */ + plugins?: boolean; + /** + * Enables Chromium's experimental features. Default is `false`. + */ + experimentalFeatures?: boolean; + /** + * Enables scroll bounce (rubber banding) effect on macOS. Default is `false`. + * + * @platform darwin + */ + scrollBounce?: boolean; + /** + * A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` + * to enable. The full list of supported feature strings can be found in the + * RuntimeEnabledFeatures.json5 file. + */ + enableBlinkFeatures?: string; + /** + * A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` + * to disable. The full list of supported feature strings can be found in the + * RuntimeEnabledFeatures.json5 file. + */ + disableBlinkFeatures?: string; + /** + * Sets the default font for the font-family. + */ + defaultFontFamily?: DefaultFontFamily; + /** + * Defaults to `16`. + */ + defaultFontSize?: number; + /** + * Defaults to `13`. + */ + defaultMonospaceFontSize?: number; + /** + * Defaults to `0`. + */ + minimumFontSize?: number; + /** + * Defaults to `ISO-8859-1`. + */ + defaultEncoding?: string; + /** + * Whether to throttle animations and timers when the page becomes background. This + * also affects the Page Visibility API. Defaults to `true`. + */ + backgroundThrottling?: boolean; + /** + * Whether to enable offscreen rendering for the browser window. Defaults to + * `false`. See the offscreen rendering tutorial for more details. + */ + offscreen?: boolean; + /** + * Whether to run Electron APIs and the specified `preload` script in a separate + * JavaScript context. Defaults to `true`. The context that the `preload` script + * runs in will only have access to its own dedicated `document` and `window` + * globals, as well as its own set of JavaScript builtins (`Array`, `Object`, + * `JSON`, etc.), which are all invisible to the loaded content. The Electron API + * will only be available in the `preload` script and not the loaded page. This + * option should be used when loading potentially untrusted remote content to + * ensure the loaded content cannot tamper with the `preload` script and any + * Electron APIs being used. This option uses the same technique used by Chrome + * Content Scripts. You can access this context in the dev tools by selecting the + * 'Electron Isolated Context' entry in the combo box at the top of the Console + * tab. + */ + contextIsolation?: boolean; + /** + * Whether to enable the `<webview>` tag. Defaults to `false`. **Note:** The + * `preload` script configured for the `<webview>` will have node integration + * enabled when it is executed so you should ensure remote/untrusted content is not + * able to create a `<webview>` tag with a possibly malicious `preload` script. You + * can use the `will-attach-webview` event on webContents to strip away the + * `preload` script and to validate or alter the `<webview>`'s initial settings. + */ + webviewTag?: boolean; + /** + * A list of strings that will be appended to `process.argv` in the renderer + * process of this app. Useful for passing small bits of data down to renderer + * process preload scripts. + */ + additionalArguments?: string[]; + /** + * Whether to enable browser style consecutive dialog protection. Default is + * `false`. + */ + safeDialogs?: boolean; + /** + * The message to display when consecutive dialog protection is triggered. If not + * defined the default message would be used, note that currently the default + * message is in English and not localized. + */ + safeDialogsMessage?: string; + /** + * Whether to disable dialogs completely. Overrides `safeDialogs`. Default is + * `false`. + */ + disableDialogs?: boolean; + /** + * Whether dragging and dropping a file or link onto the page causes a navigation. + * Default is `false`. + */ + navigateOnDragDrop?: boolean; + /** + * Autoplay policy to apply to content in the window, can be + * `no-user-gesture-required`, `user-gesture-required`, + * `document-user-activation-required`. Defaults to `no-user-gesture-required`. + */ + autoplayPolicy?: ('no-user-gesture-required' | 'user-gesture-required' | 'document-user-activation-required'); + /** + * Whether to prevent the window from resizing when entering HTML Fullscreen. + * Default is `false`. + */ + disableHtmlFullscreenWindowResize?: boolean; + /** + * An alternative title string provided only to accessibility tools such as screen + * readers. This string is not directly visible to users. + */ + accessibleTitle?: string; + /** + * Whether to enable the builtin spellchecker. Default is `true`. + */ + spellcheck?: boolean; + /** + * Whether to enable the WebSQL api. Default is `true`. + */ + enableWebSQL?: boolean; + /** + * Enforces the v8 code caching policy used by blink. Accepted values are + */ + v8CacheOptions?: ('none' | 'code' | 'bypassHeatCheck' | 'bypassHeatCheckAndEagerCompile'); + /** + * Whether to enable preferred size mode. The preferred size is the minimum size + * needed to contain the layout of the documentβ€”without requiring scrolling. + * Enabling this will cause the `preferred-size-changed` event to be emitted on the + * `WebContents` when the preferred size changes. Default is `false`. + */ + enablePreferredSizeMode?: boolean; + } + interface DefaultFontFamily { + /** + * Defaults to `Times New Roman`. + */ + standard?: string; + /** + * Defaults to `Times New Roman`. + */ + serif?: string; + /** + * Defaults to `Arial`. + */ + sansSerif?: string; + /** + * Defaults to `Courier New`. + */ + monospace?: string; + /** + * Defaults to `Script`. + */ + cursive?: string; + /** + * Defaults to `Impact`. + */ + fantasy?: string; + } + + interface RemoteMainInterface { + app: App; + autoUpdater: AutoUpdater; + BrowserView: typeof BrowserView; + BrowserWindow: typeof BrowserWindow; + clipboard: Clipboard; + contentTracing: ContentTracing; + crashReporter: CrashReporter; + desktopCapturer: DesktopCapturer; + dialog: Dialog; + globalShortcut: GlobalShortcut; + inAppPurchase: InAppPurchase; + ipcMain: IpcMain; + Menu: typeof Menu; + MenuItem: typeof MenuItem; + MessageChannelMain: typeof MessageChannelMain; + nativeImage: typeof NativeImage; + nativeTheme: NativeTheme; + net: Net; + netLog: NetLog; + Notification: typeof Notification; + powerMonitor: PowerMonitor; + powerSaveBlocker: PowerSaveBlocker; + protocol: Protocol; + pushNotifications: PushNotifications; + safeStorage: SafeStorage; + screen: Screen; + session: typeof Session; + ShareMenu: typeof ShareMenu; + shell: Shell; + systemPreferences: SystemPreferences; + TouchBar: typeof TouchBar; + Tray: typeof Tray; + webContents: typeof WebContents; + webFrameMain: typeof WebFrameMain; + } + + + + namespace Common { + const clipboard: Clipboard; + type Clipboard = Electron.Clipboard; + const crashReporter: CrashReporter; + type CrashReporter = Electron.CrashReporter; + const nativeImage: typeof NativeImage; + type NativeImage = Electron.NativeImage; + const shell: Shell; + type Shell = Electron.Shell; + type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; + type AddRepresentationOptions = Electron.AddRepresentationOptions; + type AnimationSettings = Electron.AnimationSettings; + type AppDetailsOptions = Electron.AppDetailsOptions; + type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; + type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; + type AuthInfo = Electron.AuthInfo; + type AutoResizeOptions = Electron.AutoResizeOptions; + type BeforeSendResponse = Electron.BeforeSendResponse; + type BitmapOptions = Electron.BitmapOptions; + type BlinkMemoryInfo = Electron.BlinkMemoryInfo; + type BluetoothPairingHandlerHandlerDetails = Electron.BluetoothPairingHandlerHandlerDetails; + type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; + type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; + type CallbackResponse = Electron.CallbackResponse; + type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; + type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; + type ClearStorageDataOptions = Electron.ClearStorageDataOptions; + type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; + type Config = Electron.Config; + type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; + type ConsoleMessageEvent = Electron.ConsoleMessageEvent; + type ContextMenuEvent = Electron.ContextMenuEvent; + type ContextMenuParams = Electron.ContextMenuParams; + type ContinueActivityDetails = Electron.ContinueActivityDetails; + type CookiesGetFilter = Electron.CookiesGetFilter; + type CookiesSetDetails = Electron.CookiesSetDetails; + type CrashReporterStartOptions = Electron.CrashReporterStartOptions; + type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; + type CreateFromBufferOptions = Electron.CreateFromBufferOptions; + type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; + type Data = Electron.Data; + type Details = Electron.Details; + type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; + type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; + type DidCreateWindowDetails = Electron.DidCreateWindowDetails; + type DidFailLoadEvent = Electron.DidFailLoadEvent; + type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; + type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; + type DidNavigateEvent = Electron.DidNavigateEvent; + type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; + type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; + type DidStartNavigationEvent = Electron.DidStartNavigationEvent; + type DisplayBalloonOptions = Electron.DisplayBalloonOptions; + type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; + type FeedURLOptions = Electron.FeedURLOptions; + type FileIconOptions = Electron.FileIconOptions; + type FindInPageOptions = Electron.FindInPageOptions; + type FocusOptions = Electron.FocusOptions; + type FoundInPageEvent = Electron.FoundInPageEvent; + type FrameCreatedDetails = Electron.FrameCreatedDetails; + type FromPartitionOptions = Electron.FromPartitionOptions; + type HandlerDetails = Electron.HandlerDetails; + type HeadersReceivedResponse = Electron.HeadersReceivedResponse; + type HeapStatistics = Electron.HeapStatistics; + type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; + type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; + type HidDeviceRevokedDetails = Electron.HidDeviceRevokedDetails; + type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; + type ImportCertificateOptions = Electron.ImportCertificateOptions; + type Info = Electron.Info; + type Input = Electron.Input; + type InsertCSSOptions = Electron.InsertCSSOptions; + type IpcMessageEvent = Electron.IpcMessageEvent; + type Item = Electron.Item; + type JumpListSettings = Electron.JumpListSettings; + type LoadCommitEvent = Electron.LoadCommitEvent; + type LoadExtensionOptions = Electron.LoadExtensionOptions; + type LoadFileOptions = Electron.LoadFileOptions; + type LoadURLOptions = Electron.LoadURLOptions; + type LoginItemSettings = Electron.LoginItemSettings; + type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; + type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; + type MessageBoxOptions = Electron.MessageBoxOptions; + type MessageBoxReturnValue = Electron.MessageBoxReturnValue; + type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; + type MessageDetails = Electron.MessageDetails; + type MessageEvent = Electron.MessageEvent; + type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; + type NewWindowEvent = Electron.NewWindowEvent; + type NotificationConstructorOptions = Electron.NotificationConstructorOptions; + type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; + type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; + type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; + type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; + type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; + type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; + type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; + type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; + type OpenDevToolsOptions = Electron.OpenDevToolsOptions; + type OpenDialogOptions = Electron.OpenDialogOptions; + type OpenDialogReturnValue = Electron.OpenDialogReturnValue; + type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; + type OpenExternalOptions = Electron.OpenExternalOptions; + type Options = Electron.Options; + type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; + type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; + type Parameters = Electron.Parameters; + type Payment = Electron.Payment; + type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; + type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; + type PluginCrashedEvent = Electron.PluginCrashedEvent; + type PopupOptions = Electron.PopupOptions; + type PreconnectOptions = Electron.PreconnectOptions; + type PrintToPDFOptions = Electron.PrintToPDFOptions; + type Privileges = Electron.Privileges; + type ProgressBarOptions = Electron.ProgressBarOptions; + type Provider = Electron.Provider; + type ReadBookmark = Electron.ReadBookmark; + type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; + type RelaunchOptions = Electron.RelaunchOptions; + type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; + type Request = Electron.Request; + type ResizeOptions = Electron.ResizeOptions; + type ResourceUsage = Electron.ResourceUsage; + type Response = Electron.Response; + type Result = Electron.Result; + type SaveDialogOptions = Electron.SaveDialogOptions; + type SaveDialogReturnValue = Electron.SaveDialogReturnValue; + type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; + type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; + type Settings = Electron.Settings; + type SourcesOptions = Electron.SourcesOptions; + type SSLConfigConfig = Electron.SSLConfigConfig; + type StartLoggingOptions = Electron.StartLoggingOptions; + type SystemMemoryInfo = Electron.SystemMemoryInfo; + type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; + type TitleOptions = Electron.TitleOptions; + type ToBitmapOptions = Electron.ToBitmapOptions; + type ToDataURLOptions = Electron.ToDataURLOptions; + type ToPNGOptions = Electron.ToPNGOptions; + type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; + type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; + type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; + type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; + type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; + type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; + type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; + type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; + type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; + type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; + type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; + type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; + type UploadProgress = Electron.UploadProgress; + type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; + type WebContentsPrintOptions = Electron.WebContentsPrintOptions; + type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; + type WillNavigateEvent = Electron.WillNavigateEvent; + type WillResizeDetails = Electron.WillResizeDetails; + type EditFlags = Electron.EditFlags; + type FoundInPageResult = Electron.FoundInPageResult; + type LaunchItems = Electron.LaunchItems; + type Margins = Electron.Margins; + type MediaFlags = Electron.MediaFlags; + type PageRanges = Electron.PageRanges; + type Params = Electron.Params; + type TitleBarOverlay = Electron.TitleBarOverlay; + type WebPreferences = Electron.WebPreferences; + type DefaultFontFamily = Electron.DefaultFontFamily; + type BluetoothDevice = Electron.BluetoothDevice; + type Certificate = Electron.Certificate; + type CertificatePrincipal = Electron.CertificatePrincipal; + type Cookie = Electron.Cookie; + type CPUUsage = Electron.CPUUsage; + type CrashReport = Electron.CrashReport; + type CustomScheme = Electron.CustomScheme; + type DesktopCapturerSource = Electron.DesktopCapturerSource; + type Display = Electron.Display; + type Event = Electron.Event; + type Extension = Electron.Extension; + type ExtensionInfo = Electron.ExtensionInfo; + type FileFilter = Electron.FileFilter; + type FilePathWithHeaders = Electron.FilePathWithHeaders; + type GPUFeatureStatus = Electron.GPUFeatureStatus; + type HIDDevice = Electron.HIDDevice; + type InputEvent = Electron.InputEvent; + type IOCounters = Electron.IOCounters; + type IpcMainEvent = Electron.IpcMainEvent; + type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; + type IpcRendererEvent = Electron.IpcRendererEvent; + type JumpListCategory = Electron.JumpListCategory; + type JumpListItem = Electron.JumpListItem; + type KeyboardEvent = Electron.KeyboardEvent; + type KeyboardInputEvent = Electron.KeyboardInputEvent; + type MemoryInfo = Electron.MemoryInfo; + type MemoryUsageDetails = Electron.MemoryUsageDetails; + type MimeTypedBuffer = Electron.MimeTypedBuffer; + type MouseInputEvent = Electron.MouseInputEvent; + type MouseWheelInputEvent = Electron.MouseWheelInputEvent; + type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; + type NotificationAction = Electron.NotificationAction; + type NotificationResponse = Electron.NotificationResponse; + type PaymentDiscount = Electron.PaymentDiscount; + type Point = Electron.Point; + type PostBody = Electron.PostBody; + type PrinterInfo = Electron.PrinterInfo; + type ProcessMemoryInfo = Electron.ProcessMemoryInfo; + type ProcessMetric = Electron.ProcessMetric; + type Product = Electron.Product; + type ProductDiscount = Electron.ProductDiscount; + type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; + type ProtocolRequest = Electron.ProtocolRequest; + type ProtocolResponse = Electron.ProtocolResponse; + type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; + type Rectangle = Electron.Rectangle; + type Referrer = Electron.Referrer; + type ScrubberItem = Electron.ScrubberItem; + type SegmentedControlSegment = Electron.SegmentedControlSegment; + type SerialPort = Electron.SerialPort; + type ServiceWorkerInfo = Electron.ServiceWorkerInfo; + type SharedWorkerInfo = Electron.SharedWorkerInfo; + type SharingItem = Electron.SharingItem; + type ShortcutDetails = Electron.ShortcutDetails; + type Size = Electron.Size; + type Task = Electron.Task; + type ThumbarButton = Electron.ThumbarButton; + type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; + type TraceConfig = Electron.TraceConfig; + type Transaction = Electron.Transaction; + type UploadData = Electron.UploadData; + type UploadFile = Electron.UploadFile; + type UploadRawData = Electron.UploadRawData; + type UserDefaultTypes = Electron.UserDefaultTypes; + type WebRequestFilter = Electron.WebRequestFilter; + type WebSource = Electron.WebSource; + } + + namespace Main { + const app: App; + type App = Electron.App; + const autoUpdater: AutoUpdater; + type AutoUpdater = Electron.AutoUpdater; + class BrowserView extends Electron.BrowserView {} + class BrowserWindow extends Electron.BrowserWindow {} + type ClientRequest = Electron.ClientRequest; + type CommandLine = Electron.CommandLine; + const contentTracing: ContentTracing; + type ContentTracing = Electron.ContentTracing; + type Cookies = Electron.Cookies; + type Debugger = Electron.Debugger; + const desktopCapturer: DesktopCapturer; + type DesktopCapturer = Electron.DesktopCapturer; + const dialog: Dialog; + type Dialog = Electron.Dialog; + type Dock = Electron.Dock; + type DownloadItem = Electron.DownloadItem; + const globalShortcut: GlobalShortcut; + type GlobalShortcut = Electron.GlobalShortcut; + const inAppPurchase: InAppPurchase; + type InAppPurchase = Electron.InAppPurchase; + type IncomingMessage = Electron.IncomingMessage; + const ipcMain: IpcMain; + type IpcMain = Electron.IpcMain; + class Menu extends Electron.Menu {} + class MenuItem extends Electron.MenuItem {} + class MessageChannelMain extends Electron.MessageChannelMain {} + type MessagePortMain = Electron.MessagePortMain; + const nativeTheme: NativeTheme; + type NativeTheme = Electron.NativeTheme; + const net: Net; + type Net = Electron.Net; + const netLog: NetLog; + type NetLog = Electron.NetLog; + class Notification extends Electron.Notification {} + const powerMonitor: PowerMonitor; + type PowerMonitor = Electron.PowerMonitor; + const powerSaveBlocker: PowerSaveBlocker; + type PowerSaveBlocker = Electron.PowerSaveBlocker; + const protocol: Protocol; + type Protocol = Electron.Protocol; + const pushNotifications: PushNotifications; + type PushNotifications = Electron.PushNotifications; + const safeStorage: SafeStorage; + type SafeStorage = Electron.SafeStorage; + const screen: Screen; + type Screen = Electron.Screen; + type ServiceWorkers = Electron.ServiceWorkers; + const session: typeof Session; + type Session = Electron.Session; + class ShareMenu extends Electron.ShareMenu {} + const systemPreferences: SystemPreferences; + type SystemPreferences = Electron.SystemPreferences; + class TouchBar extends Electron.TouchBar {} + type TouchBarButton = Electron.TouchBarButton; + type TouchBarColorPicker = Electron.TouchBarColorPicker; + type TouchBarGroup = Electron.TouchBarGroup; + type TouchBarLabel = Electron.TouchBarLabel; + type TouchBarOtherItemsProxy = Electron.TouchBarOtherItemsProxy; + type TouchBarPopover = Electron.TouchBarPopover; + type TouchBarScrubber = Electron.TouchBarScrubber; + type TouchBarSegmentedControl = Electron.TouchBarSegmentedControl; + type TouchBarSlider = Electron.TouchBarSlider; + type TouchBarSpacer = Electron.TouchBarSpacer; + class Tray extends Electron.Tray {} + const webContents: typeof WebContents; + type WebContents = Electron.WebContents; + const webFrameMain: typeof WebFrameMain; + type WebFrameMain = Electron.WebFrameMain; + type WebRequest = Electron.WebRequest; + type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; + type AddRepresentationOptions = Electron.AddRepresentationOptions; + type AnimationSettings = Electron.AnimationSettings; + type AppDetailsOptions = Electron.AppDetailsOptions; + type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; + type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; + type AuthInfo = Electron.AuthInfo; + type AutoResizeOptions = Electron.AutoResizeOptions; + type BeforeSendResponse = Electron.BeforeSendResponse; + type BitmapOptions = Electron.BitmapOptions; + type BlinkMemoryInfo = Electron.BlinkMemoryInfo; + type BluetoothPairingHandlerHandlerDetails = Electron.BluetoothPairingHandlerHandlerDetails; + type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; + type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; + type CallbackResponse = Electron.CallbackResponse; + type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; + type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; + type ClearStorageDataOptions = Electron.ClearStorageDataOptions; + type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; + type Config = Electron.Config; + type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; + type ConsoleMessageEvent = Electron.ConsoleMessageEvent; + type ContextMenuEvent = Electron.ContextMenuEvent; + type ContextMenuParams = Electron.ContextMenuParams; + type ContinueActivityDetails = Electron.ContinueActivityDetails; + type CookiesGetFilter = Electron.CookiesGetFilter; + type CookiesSetDetails = Electron.CookiesSetDetails; + type CrashReporterStartOptions = Electron.CrashReporterStartOptions; + type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; + type CreateFromBufferOptions = Electron.CreateFromBufferOptions; + type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; + type Data = Electron.Data; + type Details = Electron.Details; + type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; + type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; + type DidCreateWindowDetails = Electron.DidCreateWindowDetails; + type DidFailLoadEvent = Electron.DidFailLoadEvent; + type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; + type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; + type DidNavigateEvent = Electron.DidNavigateEvent; + type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; + type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; + type DidStartNavigationEvent = Electron.DidStartNavigationEvent; + type DisplayBalloonOptions = Electron.DisplayBalloonOptions; + type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; + type FeedURLOptions = Electron.FeedURLOptions; + type FileIconOptions = Electron.FileIconOptions; + type FindInPageOptions = Electron.FindInPageOptions; + type FocusOptions = Electron.FocusOptions; + type FoundInPageEvent = Electron.FoundInPageEvent; + type FrameCreatedDetails = Electron.FrameCreatedDetails; + type FromPartitionOptions = Electron.FromPartitionOptions; + type HandlerDetails = Electron.HandlerDetails; + type HeadersReceivedResponse = Electron.HeadersReceivedResponse; + type HeapStatistics = Electron.HeapStatistics; + type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; + type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; + type HidDeviceRevokedDetails = Electron.HidDeviceRevokedDetails; + type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; + type ImportCertificateOptions = Electron.ImportCertificateOptions; + type Info = Electron.Info; + type Input = Electron.Input; + type InsertCSSOptions = Electron.InsertCSSOptions; + type IpcMessageEvent = Electron.IpcMessageEvent; + type Item = Electron.Item; + type JumpListSettings = Electron.JumpListSettings; + type LoadCommitEvent = Electron.LoadCommitEvent; + type LoadExtensionOptions = Electron.LoadExtensionOptions; + type LoadFileOptions = Electron.LoadFileOptions; + type LoadURLOptions = Electron.LoadURLOptions; + type LoginItemSettings = Electron.LoginItemSettings; + type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; + type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; + type MessageBoxOptions = Electron.MessageBoxOptions; + type MessageBoxReturnValue = Electron.MessageBoxReturnValue; + type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; + type MessageDetails = Electron.MessageDetails; + type MessageEvent = Electron.MessageEvent; + type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; + type NewWindowEvent = Electron.NewWindowEvent; + type NotificationConstructorOptions = Electron.NotificationConstructorOptions; + type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; + type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; + type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; + type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; + type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; + type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; + type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; + type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; + type OpenDevToolsOptions = Electron.OpenDevToolsOptions; + type OpenDialogOptions = Electron.OpenDialogOptions; + type OpenDialogReturnValue = Electron.OpenDialogReturnValue; + type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; + type OpenExternalOptions = Electron.OpenExternalOptions; + type Options = Electron.Options; + type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; + type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; + type Parameters = Electron.Parameters; + type Payment = Electron.Payment; + type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; + type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; + type PluginCrashedEvent = Electron.PluginCrashedEvent; + type PopupOptions = Electron.PopupOptions; + type PreconnectOptions = Electron.PreconnectOptions; + type PrintToPDFOptions = Electron.PrintToPDFOptions; + type Privileges = Electron.Privileges; + type ProgressBarOptions = Electron.ProgressBarOptions; + type Provider = Electron.Provider; + type ReadBookmark = Electron.ReadBookmark; + type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; + type RelaunchOptions = Electron.RelaunchOptions; + type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; + type Request = Electron.Request; + type ResizeOptions = Electron.ResizeOptions; + type ResourceUsage = Electron.ResourceUsage; + type Response = Electron.Response; + type Result = Electron.Result; + type SaveDialogOptions = Electron.SaveDialogOptions; + type SaveDialogReturnValue = Electron.SaveDialogReturnValue; + type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; + type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; + type Settings = Electron.Settings; + type SourcesOptions = Electron.SourcesOptions; + type SSLConfigConfig = Electron.SSLConfigConfig; + type StartLoggingOptions = Electron.StartLoggingOptions; + type SystemMemoryInfo = Electron.SystemMemoryInfo; + type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; + type TitleOptions = Electron.TitleOptions; + type ToBitmapOptions = Electron.ToBitmapOptions; + type ToDataURLOptions = Electron.ToDataURLOptions; + type ToPNGOptions = Electron.ToPNGOptions; + type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; + type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; + type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; + type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; + type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; + type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; + type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; + type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; + type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; + type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; + type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; + type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; + type UploadProgress = Electron.UploadProgress; + type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; + type WebContentsPrintOptions = Electron.WebContentsPrintOptions; + type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; + type WillNavigateEvent = Electron.WillNavigateEvent; + type WillResizeDetails = Electron.WillResizeDetails; + type EditFlags = Electron.EditFlags; + type FoundInPageResult = Electron.FoundInPageResult; + type LaunchItems = Electron.LaunchItems; + type Margins = Electron.Margins; + type MediaFlags = Electron.MediaFlags; + type PageRanges = Electron.PageRanges; + type Params = Electron.Params; + type TitleBarOverlay = Electron.TitleBarOverlay; + type WebPreferences = Electron.WebPreferences; + type DefaultFontFamily = Electron.DefaultFontFamily; + type BluetoothDevice = Electron.BluetoothDevice; + type Certificate = Electron.Certificate; + type CertificatePrincipal = Electron.CertificatePrincipal; + type Cookie = Electron.Cookie; + type CPUUsage = Electron.CPUUsage; + type CrashReport = Electron.CrashReport; + type CustomScheme = Electron.CustomScheme; + type DesktopCapturerSource = Electron.DesktopCapturerSource; + type Display = Electron.Display; + type Event = Electron.Event; + type Extension = Electron.Extension; + type ExtensionInfo = Electron.ExtensionInfo; + type FileFilter = Electron.FileFilter; + type FilePathWithHeaders = Electron.FilePathWithHeaders; + type GPUFeatureStatus = Electron.GPUFeatureStatus; + type HIDDevice = Electron.HIDDevice; + type InputEvent = Electron.InputEvent; + type IOCounters = Electron.IOCounters; + type IpcMainEvent = Electron.IpcMainEvent; + type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; + type IpcRendererEvent = Electron.IpcRendererEvent; + type JumpListCategory = Electron.JumpListCategory; + type JumpListItem = Electron.JumpListItem; + type KeyboardEvent = Electron.KeyboardEvent; + type KeyboardInputEvent = Electron.KeyboardInputEvent; + type MemoryInfo = Electron.MemoryInfo; + type MemoryUsageDetails = Electron.MemoryUsageDetails; + type MimeTypedBuffer = Electron.MimeTypedBuffer; + type MouseInputEvent = Electron.MouseInputEvent; + type MouseWheelInputEvent = Electron.MouseWheelInputEvent; + type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; + type NotificationAction = Electron.NotificationAction; + type NotificationResponse = Electron.NotificationResponse; + type PaymentDiscount = Electron.PaymentDiscount; + type Point = Electron.Point; + type PostBody = Electron.PostBody; + type PrinterInfo = Electron.PrinterInfo; + type ProcessMemoryInfo = Electron.ProcessMemoryInfo; + type ProcessMetric = Electron.ProcessMetric; + type Product = Electron.Product; + type ProductDiscount = Electron.ProductDiscount; + type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; + type ProtocolRequest = Electron.ProtocolRequest; + type ProtocolResponse = Electron.ProtocolResponse; + type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; + type Rectangle = Electron.Rectangle; + type Referrer = Electron.Referrer; + type ScrubberItem = Electron.ScrubberItem; + type SegmentedControlSegment = Electron.SegmentedControlSegment; + type SerialPort = Electron.SerialPort; + type ServiceWorkerInfo = Electron.ServiceWorkerInfo; + type SharedWorkerInfo = Electron.SharedWorkerInfo; + type SharingItem = Electron.SharingItem; + type ShortcutDetails = Electron.ShortcutDetails; + type Size = Electron.Size; + type Task = Electron.Task; + type ThumbarButton = Electron.ThumbarButton; + type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; + type TraceConfig = Electron.TraceConfig; + type Transaction = Electron.Transaction; + type UploadData = Electron.UploadData; + type UploadFile = Electron.UploadFile; + type UploadRawData = Electron.UploadRawData; + type UserDefaultTypes = Electron.UserDefaultTypes; + type WebRequestFilter = Electron.WebRequestFilter; + type WebSource = Electron.WebSource; + } + + namespace Renderer { + const contextBridge: ContextBridge; + type ContextBridge = Electron.ContextBridge; + const ipcRenderer: IpcRenderer; + type IpcRenderer = Electron.IpcRenderer; + const webFrame: WebFrame; + type WebFrame = Electron.WebFrame; + type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; + type AddRepresentationOptions = Electron.AddRepresentationOptions; + type AnimationSettings = Electron.AnimationSettings; + type AppDetailsOptions = Electron.AppDetailsOptions; + type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; + type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; + type AuthInfo = Electron.AuthInfo; + type AutoResizeOptions = Electron.AutoResizeOptions; + type BeforeSendResponse = Electron.BeforeSendResponse; + type BitmapOptions = Electron.BitmapOptions; + type BlinkMemoryInfo = Electron.BlinkMemoryInfo; + type BluetoothPairingHandlerHandlerDetails = Electron.BluetoothPairingHandlerHandlerDetails; + type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; + type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; + type CallbackResponse = Electron.CallbackResponse; + type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; + type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; + type ClearStorageDataOptions = Electron.ClearStorageDataOptions; + type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; + type Config = Electron.Config; + type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; + type ConsoleMessageEvent = Electron.ConsoleMessageEvent; + type ContextMenuEvent = Electron.ContextMenuEvent; + type ContextMenuParams = Electron.ContextMenuParams; + type ContinueActivityDetails = Electron.ContinueActivityDetails; + type CookiesGetFilter = Electron.CookiesGetFilter; + type CookiesSetDetails = Electron.CookiesSetDetails; + type CrashReporterStartOptions = Electron.CrashReporterStartOptions; + type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; + type CreateFromBufferOptions = Electron.CreateFromBufferOptions; + type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; + type Data = Electron.Data; + type Details = Electron.Details; + type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; + type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; + type DidCreateWindowDetails = Electron.DidCreateWindowDetails; + type DidFailLoadEvent = Electron.DidFailLoadEvent; + type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; + type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; + type DidNavigateEvent = Electron.DidNavigateEvent; + type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; + type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; + type DidStartNavigationEvent = Electron.DidStartNavigationEvent; + type DisplayBalloonOptions = Electron.DisplayBalloonOptions; + type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; + type FeedURLOptions = Electron.FeedURLOptions; + type FileIconOptions = Electron.FileIconOptions; + type FindInPageOptions = Electron.FindInPageOptions; + type FocusOptions = Electron.FocusOptions; + type FoundInPageEvent = Electron.FoundInPageEvent; + type FrameCreatedDetails = Electron.FrameCreatedDetails; + type FromPartitionOptions = Electron.FromPartitionOptions; + type HandlerDetails = Electron.HandlerDetails; + type HeadersReceivedResponse = Electron.HeadersReceivedResponse; + type HeapStatistics = Electron.HeapStatistics; + type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; + type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; + type HidDeviceRevokedDetails = Electron.HidDeviceRevokedDetails; + type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; + type ImportCertificateOptions = Electron.ImportCertificateOptions; + type Info = Electron.Info; + type Input = Electron.Input; + type InsertCSSOptions = Electron.InsertCSSOptions; + type IpcMessageEvent = Electron.IpcMessageEvent; + type Item = Electron.Item; + type JumpListSettings = Electron.JumpListSettings; + type LoadCommitEvent = Electron.LoadCommitEvent; + type LoadExtensionOptions = Electron.LoadExtensionOptions; + type LoadFileOptions = Electron.LoadFileOptions; + type LoadURLOptions = Electron.LoadURLOptions; + type LoginItemSettings = Electron.LoginItemSettings; + type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; + type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; + type MessageBoxOptions = Electron.MessageBoxOptions; + type MessageBoxReturnValue = Electron.MessageBoxReturnValue; + type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; + type MessageDetails = Electron.MessageDetails; + type MessageEvent = Electron.MessageEvent; + type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; + type NewWindowEvent = Electron.NewWindowEvent; + type NotificationConstructorOptions = Electron.NotificationConstructorOptions; + type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; + type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; + type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; + type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; + type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; + type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; + type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; + type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; + type OpenDevToolsOptions = Electron.OpenDevToolsOptions; + type OpenDialogOptions = Electron.OpenDialogOptions; + type OpenDialogReturnValue = Electron.OpenDialogReturnValue; + type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; + type OpenExternalOptions = Electron.OpenExternalOptions; + type Options = Electron.Options; + type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; + type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; + type Parameters = Electron.Parameters; + type Payment = Electron.Payment; + type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; + type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; + type PluginCrashedEvent = Electron.PluginCrashedEvent; + type PopupOptions = Electron.PopupOptions; + type PreconnectOptions = Electron.PreconnectOptions; + type PrintToPDFOptions = Electron.PrintToPDFOptions; + type Privileges = Electron.Privileges; + type ProgressBarOptions = Electron.ProgressBarOptions; + type Provider = Electron.Provider; + type ReadBookmark = Electron.ReadBookmark; + type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; + type RelaunchOptions = Electron.RelaunchOptions; + type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; + type Request = Electron.Request; + type ResizeOptions = Electron.ResizeOptions; + type ResourceUsage = Electron.ResourceUsage; + type Response = Electron.Response; + type Result = Electron.Result; + type SaveDialogOptions = Electron.SaveDialogOptions; + type SaveDialogReturnValue = Electron.SaveDialogReturnValue; + type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; + type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; + type Settings = Electron.Settings; + type SourcesOptions = Electron.SourcesOptions; + type SSLConfigConfig = Electron.SSLConfigConfig; + type StartLoggingOptions = Electron.StartLoggingOptions; + type SystemMemoryInfo = Electron.SystemMemoryInfo; + type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; + type TitleOptions = Electron.TitleOptions; + type ToBitmapOptions = Electron.ToBitmapOptions; + type ToDataURLOptions = Electron.ToDataURLOptions; + type ToPNGOptions = Electron.ToPNGOptions; + type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; + type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; + type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; + type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; + type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; + type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; + type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; + type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; + type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; + type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; + type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; + type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; + type UploadProgress = Electron.UploadProgress; + type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; + type WebContentsPrintOptions = Electron.WebContentsPrintOptions; + type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; + type WillNavigateEvent = Electron.WillNavigateEvent; + type WillResizeDetails = Electron.WillResizeDetails; + type EditFlags = Electron.EditFlags; + type FoundInPageResult = Electron.FoundInPageResult; + type LaunchItems = Electron.LaunchItems; + type Margins = Electron.Margins; + type MediaFlags = Electron.MediaFlags; + type PageRanges = Electron.PageRanges; + type Params = Electron.Params; + type TitleBarOverlay = Electron.TitleBarOverlay; + type WebPreferences = Electron.WebPreferences; + type DefaultFontFamily = Electron.DefaultFontFamily; + type BluetoothDevice = Electron.BluetoothDevice; + type Certificate = Electron.Certificate; + type CertificatePrincipal = Electron.CertificatePrincipal; + type Cookie = Electron.Cookie; + type CPUUsage = Electron.CPUUsage; + type CrashReport = Electron.CrashReport; + type CustomScheme = Electron.CustomScheme; + type DesktopCapturerSource = Electron.DesktopCapturerSource; + type Display = Electron.Display; + type Event = Electron.Event; + type Extension = Electron.Extension; + type ExtensionInfo = Electron.ExtensionInfo; + type FileFilter = Electron.FileFilter; + type FilePathWithHeaders = Electron.FilePathWithHeaders; + type GPUFeatureStatus = Electron.GPUFeatureStatus; + type HIDDevice = Electron.HIDDevice; + type InputEvent = Electron.InputEvent; + type IOCounters = Electron.IOCounters; + type IpcMainEvent = Electron.IpcMainEvent; + type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; + type IpcRendererEvent = Electron.IpcRendererEvent; + type JumpListCategory = Electron.JumpListCategory; + type JumpListItem = Electron.JumpListItem; + type KeyboardEvent = Electron.KeyboardEvent; + type KeyboardInputEvent = Electron.KeyboardInputEvent; + type MemoryInfo = Electron.MemoryInfo; + type MemoryUsageDetails = Electron.MemoryUsageDetails; + type MimeTypedBuffer = Electron.MimeTypedBuffer; + type MouseInputEvent = Electron.MouseInputEvent; + type MouseWheelInputEvent = Electron.MouseWheelInputEvent; + type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; + type NotificationAction = Electron.NotificationAction; + type NotificationResponse = Electron.NotificationResponse; + type PaymentDiscount = Electron.PaymentDiscount; + type Point = Electron.Point; + type PostBody = Electron.PostBody; + type PrinterInfo = Electron.PrinterInfo; + type ProcessMemoryInfo = Electron.ProcessMemoryInfo; + type ProcessMetric = Electron.ProcessMetric; + type Product = Electron.Product; + type ProductDiscount = Electron.ProductDiscount; + type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; + type ProtocolRequest = Electron.ProtocolRequest; + type ProtocolResponse = Electron.ProtocolResponse; + type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; + type Rectangle = Electron.Rectangle; + type Referrer = Electron.Referrer; + type ScrubberItem = Electron.ScrubberItem; + type SegmentedControlSegment = Electron.SegmentedControlSegment; + type SerialPort = Electron.SerialPort; + type ServiceWorkerInfo = Electron.ServiceWorkerInfo; + type SharedWorkerInfo = Electron.SharedWorkerInfo; + type SharingItem = Electron.SharingItem; + type ShortcutDetails = Electron.ShortcutDetails; + type Size = Electron.Size; + type Task = Electron.Task; + type ThumbarButton = Electron.ThumbarButton; + type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; + type TraceConfig = Electron.TraceConfig; + type Transaction = Electron.Transaction; + type UploadData = Electron.UploadData; + type UploadFile = Electron.UploadFile; + type UploadRawData = Electron.UploadRawData; + type UserDefaultTypes = Electron.UserDefaultTypes; + type WebRequestFilter = Electron.WebRequestFilter; + type WebSource = Electron.WebSource; + } + + namespace CrossProcessExports { const app: App; + type App = Electron.App; const autoUpdater: AutoUpdater; + type AutoUpdater = Electron.AutoUpdater; + class BrowserView extends Electron.BrowserView {} + class BrowserWindow extends Electron.BrowserWindow {} + type ClientRequest = Electron.ClientRequest; const clipboard: Clipboard; + type Clipboard = Electron.Clipboard; + type CommandLine = Electron.CommandLine; const contentTracing: ContentTracing; + type ContentTracing = Electron.ContentTracing; const contextBridge: ContextBridge; + type ContextBridge = Electron.ContextBridge; + type Cookies = Electron.Cookies; const crashReporter: CrashReporter; + type CrashReporter = Electron.CrashReporter; + type Debugger = Electron.Debugger; const desktopCapturer: DesktopCapturer; + type DesktopCapturer = Electron.DesktopCapturer; const dialog: Dialog; + type Dialog = Electron.Dialog; + type Dock = Electron.Dock; + type DownloadItem = Electron.DownloadItem; const globalShortcut: GlobalShortcut; + type GlobalShortcut = Electron.GlobalShortcut; const inAppPurchase: InAppPurchase; + type InAppPurchase = Electron.InAppPurchase; + type IncomingMessage = Electron.IncomingMessage; const ipcMain: IpcMain; + type IpcMain = Electron.IpcMain; const ipcRenderer: IpcRenderer; + type IpcRenderer = Electron.IpcRenderer; + class Menu extends Electron.Menu {} + class MenuItem extends Electron.MenuItem {} + class MessageChannelMain extends Electron.MessageChannelMain {} + type MessagePortMain = Electron.MessagePortMain; const nativeImage: typeof NativeImage; + type NativeImage = Electron.NativeImage; const nativeTheme: NativeTheme; + type NativeTheme = Electron.NativeTheme; const net: Net; + type Net = Electron.Net; const netLog: NetLog; + type NetLog = Electron.NetLog; + class Notification extends Electron.Notification {} const powerMonitor: PowerMonitor; + type PowerMonitor = Electron.PowerMonitor; const powerSaveBlocker: PowerSaveBlocker; + type PowerSaveBlocker = Electron.PowerSaveBlocker; const protocol: Protocol; + type Protocol = Electron.Protocol; + const pushNotifications: PushNotifications; + type PushNotifications = Electron.PushNotifications; const safeStorage: SafeStorage; + type SafeStorage = Electron.SafeStorage; const screen: Screen; + type Screen = Electron.Screen; + type ServiceWorkers = Electron.ServiceWorkers; const session: typeof Session; + type Session = Electron.Session; + class ShareMenu extends Electron.ShareMenu {} const shell: Shell; + type Shell = Electron.Shell; const systemPreferences: SystemPreferences; + type SystemPreferences = Electron.SystemPreferences; + class TouchBar extends Electron.TouchBar {} + type TouchBarButton = Electron.TouchBarButton; + type TouchBarColorPicker = Electron.TouchBarColorPicker; + type TouchBarGroup = Electron.TouchBarGroup; + type TouchBarLabel = Electron.TouchBarLabel; + type TouchBarOtherItemsProxy = Electron.TouchBarOtherItemsProxy; + type TouchBarPopover = Electron.TouchBarPopover; + type TouchBarScrubber = Electron.TouchBarScrubber; + type TouchBarSegmentedControl = Electron.TouchBarSegmentedControl; + type TouchBarSlider = Electron.TouchBarSlider; + type TouchBarSpacer = Electron.TouchBarSpacer; + class Tray extends Electron.Tray {} const webContents: typeof WebContents; + type WebContents = Electron.WebContents; const webFrame: WebFrame; + type WebFrame = Electron.WebFrame; const webFrameMain: typeof WebFrameMain; + type WebFrameMain = Electron.WebFrameMain; + type WebRequest = Electron.WebRequest; + type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; + type AddRepresentationOptions = Electron.AddRepresentationOptions; + type AnimationSettings = Electron.AnimationSettings; + type AppDetailsOptions = Electron.AppDetailsOptions; + type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; + type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; + type AuthInfo = Electron.AuthInfo; + type AutoResizeOptions = Electron.AutoResizeOptions; + type BeforeSendResponse = Electron.BeforeSendResponse; + type BitmapOptions = Electron.BitmapOptions; + type BlinkMemoryInfo = Electron.BlinkMemoryInfo; + type BluetoothPairingHandlerHandlerDetails = Electron.BluetoothPairingHandlerHandlerDetails; + type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; + type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; + type CallbackResponse = Electron.CallbackResponse; + type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; + type ClearCodeCachesOptions = Electron.ClearCodeCachesOptions; + type ClearStorageDataOptions = Electron.ClearStorageDataOptions; + type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; + type Config = Electron.Config; + type ConfigureHostResolverOptions = Electron.ConfigureHostResolverOptions; + type ConsoleMessageEvent = Electron.ConsoleMessageEvent; + type ContextMenuEvent = Electron.ContextMenuEvent; + type ContextMenuParams = Electron.ContextMenuParams; + type ContinueActivityDetails = Electron.ContinueActivityDetails; + type CookiesGetFilter = Electron.CookiesGetFilter; + type CookiesSetDetails = Electron.CookiesSetDetails; + type CrashReporterStartOptions = Electron.CrashReporterStartOptions; + type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; + type CreateFromBufferOptions = Electron.CreateFromBufferOptions; + type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; + type Data = Electron.Data; + type Details = Electron.Details; + type DevicePermissionHandlerHandlerDetails = Electron.DevicePermissionHandlerHandlerDetails; + type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; + type DidCreateWindowDetails = Electron.DidCreateWindowDetails; + type DidFailLoadEvent = Electron.DidFailLoadEvent; + type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; + type DidFrameNavigateEvent = Electron.DidFrameNavigateEvent; + type DidNavigateEvent = Electron.DidNavigateEvent; + type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; + type DidRedirectNavigationEvent = Electron.DidRedirectNavigationEvent; + type DidStartNavigationEvent = Electron.DidStartNavigationEvent; + type DisplayBalloonOptions = Electron.DisplayBalloonOptions; + type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; + type FeedURLOptions = Electron.FeedURLOptions; + type FileIconOptions = Electron.FileIconOptions; + type FindInPageOptions = Electron.FindInPageOptions; + type FocusOptions = Electron.FocusOptions; + type FoundInPageEvent = Electron.FoundInPageEvent; + type FrameCreatedDetails = Electron.FrameCreatedDetails; + type FromPartitionOptions = Electron.FromPartitionOptions; + type HandlerDetails = Electron.HandlerDetails; + type HeadersReceivedResponse = Electron.HeadersReceivedResponse; + type HeapStatistics = Electron.HeapStatistics; + type HidDeviceAddedDetails = Electron.HidDeviceAddedDetails; + type HidDeviceRemovedDetails = Electron.HidDeviceRemovedDetails; + type HidDeviceRevokedDetails = Electron.HidDeviceRevokedDetails; + type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; + type ImportCertificateOptions = Electron.ImportCertificateOptions; + type Info = Electron.Info; + type Input = Electron.Input; + type InsertCSSOptions = Electron.InsertCSSOptions; + type IpcMessageEvent = Electron.IpcMessageEvent; + type Item = Electron.Item; + type JumpListSettings = Electron.JumpListSettings; + type LoadCommitEvent = Electron.LoadCommitEvent; + type LoadExtensionOptions = Electron.LoadExtensionOptions; + type LoadFileOptions = Electron.LoadFileOptions; + type LoadURLOptions = Electron.LoadURLOptions; + type LoginItemSettings = Electron.LoginItemSettings; + type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; + type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; + type MessageBoxOptions = Electron.MessageBoxOptions; + type MessageBoxReturnValue = Electron.MessageBoxReturnValue; + type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; + type MessageDetails = Electron.MessageDetails; + type MessageEvent = Electron.MessageEvent; + type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; + type NewWindowEvent = Electron.NewWindowEvent; + type NotificationConstructorOptions = Electron.NotificationConstructorOptions; + type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; + type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; + type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; + type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; + type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; + type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; + type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; + type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; + type OpenDevToolsOptions = Electron.OpenDevToolsOptions; + type OpenDialogOptions = Electron.OpenDialogOptions; + type OpenDialogReturnValue = Electron.OpenDialogReturnValue; + type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; + type OpenExternalOptions = Electron.OpenExternalOptions; + type Options = Electron.Options; + type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; + type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; + type Parameters = Electron.Parameters; + type Payment = Electron.Payment; + type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; + type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; + type PluginCrashedEvent = Electron.PluginCrashedEvent; + type PopupOptions = Electron.PopupOptions; + type PreconnectOptions = Electron.PreconnectOptions; + type PrintToPDFOptions = Electron.PrintToPDFOptions; + type Privileges = Electron.Privileges; + type ProgressBarOptions = Electron.ProgressBarOptions; + type Provider = Electron.Provider; + type ReadBookmark = Electron.ReadBookmark; + type RegistrationCompletedDetails = Electron.RegistrationCompletedDetails; + type RelaunchOptions = Electron.RelaunchOptions; + type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; + type Request = Electron.Request; + type ResizeOptions = Electron.ResizeOptions; + type ResourceUsage = Electron.ResourceUsage; + type Response = Electron.Response; + type Result = Electron.Result; + type SaveDialogOptions = Electron.SaveDialogOptions; + type SaveDialogReturnValue = Electron.SaveDialogReturnValue; + type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; + type SelectHidDeviceDetails = Electron.SelectHidDeviceDetails; + type Settings = Electron.Settings; + type SourcesOptions = Electron.SourcesOptions; + type SSLConfigConfig = Electron.SSLConfigConfig; + type StartLoggingOptions = Electron.StartLoggingOptions; + type SystemMemoryInfo = Electron.SystemMemoryInfo; + type TitleBarOverlayOptions = Electron.TitleBarOverlayOptions; + type TitleOptions = Electron.TitleOptions; + type ToBitmapOptions = Electron.ToBitmapOptions; + type ToDataURLOptions = Electron.ToDataURLOptions; + type ToPNGOptions = Electron.ToPNGOptions; + type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; + type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; + type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; + type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; + type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; + type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; + type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; + type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; + type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; + type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; + type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; + type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; + type UploadProgress = Electron.UploadProgress; + type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; + type WebContentsPrintOptions = Electron.WebContentsPrintOptions; + type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; + type WillNavigateEvent = Electron.WillNavigateEvent; + type WillResizeDetails = Electron.WillResizeDetails; + type EditFlags = Electron.EditFlags; + type FoundInPageResult = Electron.FoundInPageResult; + type LaunchItems = Electron.LaunchItems; + type Margins = Electron.Margins; + type MediaFlags = Electron.MediaFlags; + type PageRanges = Electron.PageRanges; + type Params = Electron.Params; + type TitleBarOverlay = Electron.TitleBarOverlay; + type WebPreferences = Electron.WebPreferences; + type DefaultFontFamily = Electron.DefaultFontFamily; + type BluetoothDevice = Electron.BluetoothDevice; + type Certificate = Electron.Certificate; + type CertificatePrincipal = Electron.CertificatePrincipal; + type Cookie = Electron.Cookie; + type CPUUsage = Electron.CPUUsage; + type CrashReport = Electron.CrashReport; + type CustomScheme = Electron.CustomScheme; + type DesktopCapturerSource = Electron.DesktopCapturerSource; + type Display = Electron.Display; + type Event = Electron.Event; + type Extension = Electron.Extension; + type ExtensionInfo = Electron.ExtensionInfo; + type FileFilter = Electron.FileFilter; + type FilePathWithHeaders = Electron.FilePathWithHeaders; + type GPUFeatureStatus = Electron.GPUFeatureStatus; + type HIDDevice = Electron.HIDDevice; + type InputEvent = Electron.InputEvent; + type IOCounters = Electron.IOCounters; + type IpcMainEvent = Electron.IpcMainEvent; + type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; + type IpcRendererEvent = Electron.IpcRendererEvent; + type JumpListCategory = Electron.JumpListCategory; + type JumpListItem = Electron.JumpListItem; + type KeyboardEvent = Electron.KeyboardEvent; + type KeyboardInputEvent = Electron.KeyboardInputEvent; + type MemoryInfo = Electron.MemoryInfo; + type MemoryUsageDetails = Electron.MemoryUsageDetails; + type MimeTypedBuffer = Electron.MimeTypedBuffer; + type MouseInputEvent = Electron.MouseInputEvent; + type MouseWheelInputEvent = Electron.MouseWheelInputEvent; + type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; + type NotificationAction = Electron.NotificationAction; + type NotificationResponse = Electron.NotificationResponse; + type PaymentDiscount = Electron.PaymentDiscount; + type Point = Electron.Point; + type PostBody = Electron.PostBody; + type PrinterInfo = Electron.PrinterInfo; + type ProcessMemoryInfo = Electron.ProcessMemoryInfo; + type ProcessMetric = Electron.ProcessMetric; + type Product = Electron.Product; + type ProductDiscount = Electron.ProductDiscount; + type ProductSubscriptionPeriod = Electron.ProductSubscriptionPeriod; + type ProtocolRequest = Electron.ProtocolRequest; + type ProtocolResponse = Electron.ProtocolResponse; + type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; + type Rectangle = Electron.Rectangle; + type Referrer = Electron.Referrer; + type ScrubberItem = Electron.ScrubberItem; + type SegmentedControlSegment = Electron.SegmentedControlSegment; + type SerialPort = Electron.SerialPort; + type ServiceWorkerInfo = Electron.ServiceWorkerInfo; + type SharedWorkerInfo = Electron.SharedWorkerInfo; + type SharingItem = Electron.SharingItem; + type ShortcutDetails = Electron.ShortcutDetails; + type Size = Electron.Size; + type Task = Electron.Task; + type ThumbarButton = Electron.ThumbarButton; + type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; + type TraceConfig = Electron.TraceConfig; + type Transaction = Electron.Transaction; + type UploadData = Electron.UploadData; + type UploadFile = Electron.UploadFile; + type UploadRawData = Electron.UploadRawData; + type UserDefaultTypes = Electron.UserDefaultTypes; + type WebRequestFilter = Electron.WebRequestFilter; + type WebSource = Electron.WebSource; + } + + const app: App; + const autoUpdater: AutoUpdater; + const clipboard: Clipboard; + const contentTracing: ContentTracing; + const contextBridge: ContextBridge; + const crashReporter: CrashReporter; + const desktopCapturer: DesktopCapturer; + const dialog: Dialog; + const globalShortcut: GlobalShortcut; + const inAppPurchase: InAppPurchase; + const ipcMain: IpcMain; + const ipcRenderer: IpcRenderer; + const nativeImage: typeof NativeImage; + const nativeTheme: NativeTheme; + const net: Net; + const netLog: NetLog; + const powerMonitor: PowerMonitor; + const powerSaveBlocker: PowerSaveBlocker; + const protocol: Protocol; + const pushNotifications: PushNotifications; + const safeStorage: SafeStorage; + const screen: Screen; + const session: typeof Session; + const shell: Shell; + const systemPreferences: SystemPreferences; + const webContents: typeof WebContents; + const webFrame: WebFrame; + const webFrameMain: typeof WebFrameMain; } declare module 'electronite' { - export = Electron.CrossProcessExports; + export = Electron.CrossProcessExports; } declare module 'electronite/main' { - export = Electron.Main + export = Electron.Main } declare module 'electronite/common' { - export = Electron.Common + export = Electron.Common } declare module 'electronite/renderer' { - export = Electron.Renderer + export = Electron.Renderer } interface NodeRequireFunction { - (moduleName: 'electronite'): typeof Electron.CrossProcessExports; - (moduleName: 'electronite/main'): typeof Electron.Main; - (moduleName: 'electronite/common'): typeof Electron.Common; - (moduleName: 'electronite/renderer'): typeof Electron.Renderer; + (moduleName: 'electronite'): typeof Electron.CrossProcessExports; + (moduleName: 'electronite/main'): typeof Electron.Main; + (moduleName: 'electronite/common'): typeof Electron.Common; + (moduleName: 'electronite/renderer'): typeof Electron.Renderer; } interface NodeRequire { - (moduleName: 'electronite'): typeof Electron.CrossProcessExports; - (moduleName: 'electronite/main'): typeof Electron.Main; - (moduleName: 'electronite/common'): typeof Electron.Common; - (moduleName: 'electronite/renderer'): typeof Electron.Renderer; + (moduleName: 'electronite'): typeof Electron.CrossProcessExports; + (moduleName: 'electronite/main'): typeof Electron.Main; + (moduleName: 'electronite/common'): typeof Electron.Common; + (moduleName: 'electronite/renderer'): typeof Electron.Renderer; } interface File { - /** - * The real path to the file on the users filesystem - */ - path: string; + /** + * The real path to the file on the users filesystem + */ + path: string; } declare module 'original-fs' { - import * as fs from 'fs'; - export = fs; + import * as fs from 'fs'; + export = fs; } interface Document { - createElement(tagName: 'webview'): Electron.WebviewTag; + createElement(tagName: 'webview'): Electron.WebviewTag; } declare namespace NodeJS { - interface Process extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/process - - /** - * Emitted when Electron has loaded its internal initialization script and is - * beginning to load the web page or the main script. - */ - on(event: 'loaded', listener: Function): this; - once(event: 'loaded', listener: Function): this; - addListener(event: 'loaded', listener: Function): this; - removeListener(event: 'loaded', listener: Function): this; - /** - * Causes the main thread of the current process crash. - */ - crash(): void; - /** - * * `allocated` Integer - Size of all allocated objects in Kilobytes. - * * `total` Integer - Total allocated space in Kilobytes. - * - * Returns an object with Blink memory information. It can be useful for debugging - * rendering / DOM related memory issues. Note that all values are reported in - * Kilobytes. - */ - getBlinkMemoryInfo(): Electron.BlinkMemoryInfo; - getCPUUsage(): Electron.CPUUsage; - /** - * The number of milliseconds since epoch, or `null` if the information is - * unavailable - * - * Indicates the creation time of the application. The time is represented as - * number of milliseconds since epoch. It returns null if it is unable to get the - * process creation time. - */ - getCreationTime(): (number) | (null); - /** - * * `totalHeapSize` Integer - * * `totalHeapSizeExecutable` Integer - * * `totalPhysicalSize` Integer - * * `totalAvailableSize` Integer - * * `usedHeapSize` Integer - * * `heapSizeLimit` Integer - * * `mallocedMemory` Integer - * * `peakMallocedMemory` Integer - * * `doesZapGarbage` boolean - * - * Returns an object with V8 heap statistics. Note that all statistics are reported - * in Kilobytes. - */ - getHeapStatistics(): Electron.HeapStatistics; - getIOCounters(): Electron.IOCounters; - /** - * Resolves with a ProcessMemoryInfo - * - * Returns an object giving memory usage statistics about the current process. Note - * that all statistics are reported in Kilobytes. This api should be called after - * app ready. - * - * Chromium does not provide `residentSet` value for macOS. This is because macOS - * performs in-memory compression of pages that haven't been recently used. As a - * result the resident set size value is not what one would expect. `private` - * memory is more representative of the actual pre-compression memory usage of the - * process on macOS. - */ - getProcessMemoryInfo(): Promise<Electron.ProcessMemoryInfo>; - /** - * * `total` Integer - The total amount of physical memory in Kilobytes available - * to the system. - * * `free` Integer - The total amount of memory not being used by applications or - * disk cache. - * * `swapTotal` Integer _Windows_ _Linux_ - The total amount of swap memory in - * Kilobytes available to the system. - * * `swapFree` Integer _Windows_ _Linux_ - The free amount of swap memory in - * Kilobytes available to the system. - * - * Returns an object giving memory usage statistics about the entire system. Note - * that all statistics are reported in Kilobytes. - */ - getSystemMemoryInfo(): Electron.SystemMemoryInfo; - /** - * The version of the host operating system. - * - * Example: - * - * **Note:** It returns the actual operating system version instead of kernel - * version on macOS unlike `os.release()`. - */ - getSystemVersion(): string; - /** - * Causes the main thread of the current process hang. - */ - hang(): void; - /** - * Sets the file descriptor soft limit to `maxDescriptors` or the OS hard limit, - * whichever is lower for the current process. - * - * @platform darwin,linux - */ - setFdLimit(maxDescriptors: number): void; - /** - * Indicates whether the snapshot has been created successfully. - * - * Takes a V8 heap snapshot and saves it to `filePath`. - */ - takeHeapSnapshot(filePath: string): boolean; - /** - * A `string` representing Chrome's version string. - * - */ - readonly chrome: string; - /** - * A `string` (optional) representing a globally unique ID of the current - * JavaScript context. Each frame has its own JavaScript context. When - * contextIsolation is enabled, the isolated world also has a separate JavaScript - * context. This property is only available in the renderer process. - * - */ - readonly contextId?: string; - /** - * A `boolean` that indicates whether the current renderer context has - * `contextIsolation` enabled. It is `undefined` in the main process. - * - */ - readonly contextIsolated: boolean; - /** - * A `boolean`. When app is started by being passed as parameter to the default - * app, this property is `true` in the main process, otherwise it is `undefined`. - * - */ - readonly defaultApp: boolean; - /** - * A `string` representing Electron's version string. - * - */ - readonly electron: string; - /** - * A `boolean`, `true` when the current renderer context is the "main" renderer - * frame. If you want the ID of the current frame you should use - * `webFrame.routingId`. - * - */ - readonly isMainFrame: boolean; - /** - * A `boolean`. For Mac App Store build, this property is `true`, for other builds - * it is `undefined`. - * - */ - readonly mas: boolean; - /** - * A `boolean` that controls ASAR support inside your application. Setting this to - * `true` will disable the support for `asar` archives in Node's built-in modules. - */ - noAsar: boolean; - /** - * A `boolean` that controls whether or not deprecation warnings are printed to - * `stderr`. Setting this to `true` will silence deprecation warnings. This - * property is used instead of the `--no-deprecation` command line flag. - */ - noDeprecation: boolean; - /** - * A `string` representing the path to the resources directory. - * - */ - readonly resourcesPath: string; - /** - * A `boolean`. When the renderer process is sandboxed, this property is `true`, - * otherwise it is `undefined`. - * - */ - readonly sandboxed: boolean; - /** - * A `boolean` that controls whether or not deprecation warnings will be thrown as - * exceptions. Setting this to `true` will throw errors for deprecations. This - * property is used instead of the `--throw-deprecation` command line flag. - */ - throwDeprecation: boolean; - /** - * A `boolean` that controls whether or not deprecations printed to `stderr` - * include their stack trace. Setting this to `true` will print stack traces for - * deprecations. This property is instead of the `--trace-deprecation` command line - * flag. - */ - traceDeprecation: boolean; - /** - * A `boolean` that controls whether or not process warnings printed to `stderr` - * include their stack trace. Setting this to `true` will print stack traces for - * process warnings (including deprecations). This property is instead of the - * `--trace-warnings` command line flag. - */ - traceProcessWarnings: boolean; - /** - * A `string` representing the current process's type, can be: - * - * * `browser` - The main process - * * `renderer` - A renderer process - * * `worker` - In a web worker - * - */ - readonly type: ('browser' | 'renderer' | 'worker'); - /** - * A `boolean`. If the app is running as a Windows Store app (appx), this property - * is `true`, for otherwise it is `undefined`. - * - */ - readonly windowsStore: boolean; - } - interface ProcessVersions { - readonly electron: string; - readonly chrome: string; - } + interface Process extends NodeJS.EventEmitter { + + // Docs: https://electronjs.org/docs/api/process + + /** + * Emitted when Electron has loaded its internal initialization script and is + * beginning to load the web page or the main script. + */ + on(event: 'loaded', listener: Function): this; + once(event: 'loaded', listener: Function): this; + addListener(event: 'loaded', listener: Function): this; + removeListener(event: 'loaded', listener: Function): this; + /** + * Causes the main thread of the current process crash. + */ + crash(): void; + /** + * * `allocated` Integer - Size of all allocated objects in Kilobytes. + * * `total` Integer - Total allocated space in Kilobytes. + * + * Returns an object with Blink memory information. It can be useful for debugging + * rendering / DOM related memory issues. Note that all values are reported in + * Kilobytes. + */ + getBlinkMemoryInfo(): Electron.BlinkMemoryInfo; + getCPUUsage(): Electron.CPUUsage; + /** + * The number of milliseconds since epoch, or `null` if the information is + * unavailable + * + * Indicates the creation time of the application. The time is represented as + * number of milliseconds since epoch. It returns null if it is unable to get the + * process creation time. + */ + getCreationTime(): (number) | (null); + /** + * * `totalHeapSize` Integer + * * `totalHeapSizeExecutable` Integer + * * `totalPhysicalSize` Integer + * * `totalAvailableSize` Integer + * * `usedHeapSize` Integer + * * `heapSizeLimit` Integer + * * `mallocedMemory` Integer + * * `peakMallocedMemory` Integer + * * `doesZapGarbage` boolean + * + * Returns an object with V8 heap statistics. Note that all statistics are reported + * in Kilobytes. + */ + getHeapStatistics(): Electron.HeapStatistics; + getIOCounters(): Electron.IOCounters; + /** + * Resolves with a ProcessMemoryInfo + * + * Returns an object giving memory usage statistics about the current process. Note + * that all statistics are reported in Kilobytes. This api should be called after + * app ready. + * + * Chromium does not provide `residentSet` value for macOS. This is because macOS + * performs in-memory compression of pages that haven't been recently used. As a + * result the resident set size value is not what one would expect. `private` + * memory is more representative of the actual pre-compression memory usage of the + * process on macOS. + */ + getProcessMemoryInfo(): Promise<Electron.ProcessMemoryInfo>; + /** + * * `total` Integer - The total amount of physical memory in Kilobytes available + * to the system. + * * `free` Integer - The total amount of memory not being used by applications or + * disk cache. + * * `swapTotal` Integer _Windows_ _Linux_ - The total amount of swap memory in + * Kilobytes available to the system. + * * `swapFree` Integer _Windows_ _Linux_ - The free amount of swap memory in + * Kilobytes available to the system. + * + * Returns an object giving memory usage statistics about the entire system. Note + * that all statistics are reported in Kilobytes. + */ + getSystemMemoryInfo(): Electron.SystemMemoryInfo; + /** + * The version of the host operating system. + * + * Example: + * + * **Note:** It returns the actual operating system version instead of kernel + * version on macOS unlike `os.release()`. + */ + getSystemVersion(): string; + /** + * Causes the main thread of the current process hang. + */ + hang(): void; + /** + * Sets the file descriptor soft limit to `maxDescriptors` or the OS hard limit, + * whichever is lower for the current process. + * + * @platform darwin,linux + */ + setFdLimit(maxDescriptors: number): void; + /** + * Indicates whether the snapshot has been created successfully. + * + * Takes a V8 heap snapshot and saves it to `filePath`. + */ + takeHeapSnapshot(filePath: string): boolean; + /** + * A `string` representing Chrome's version string. + * + */ + readonly chrome: string; + /** + * A `string` (optional) representing a globally unique ID of the current + * JavaScript context. Each frame has its own JavaScript context. When + * contextIsolation is enabled, the isolated world also has a separate JavaScript + * context. This property is only available in the renderer process. + * + */ + readonly contextId?: string; + /** + * A `boolean` that indicates whether the current renderer context has + * `contextIsolation` enabled. It is `undefined` in the main process. + * + */ + readonly contextIsolated: boolean; + /** + * A `boolean`. When app is started by being passed as parameter to the default + * app, this property is `true` in the main process, otherwise it is `undefined`. + * + */ + readonly defaultApp: boolean; + /** + * A `string` representing Electron's version string. + * + */ + readonly electron: string; + /** + * A `boolean`, `true` when the current renderer context is the "main" renderer + * frame. If you want the ID of the current frame you should use + * `webFrame.routingId`. + * + */ + readonly isMainFrame: boolean; + /** + * A `boolean`. For Mac App Store build, this property is `true`, for other builds + * it is `undefined`. + * + */ + readonly mas: boolean; + /** + * A `boolean` that controls ASAR support inside your application. Setting this to + * `true` will disable the support for `asar` archives in Node's built-in modules. + */ + noAsar: boolean; + /** + * A `boolean` that controls whether or not deprecation warnings are printed to + * `stderr`. Setting this to `true` will silence deprecation warnings. This + * property is used instead of the `--no-deprecation` command line flag. + */ + noDeprecation: boolean; + /** + * A `string` representing the path to the resources directory. + * + */ + readonly resourcesPath: string; + /** + * A `boolean`. When the renderer process is sandboxed, this property is `true`, + * otherwise it is `undefined`. + * + */ + readonly sandboxed: boolean; + /** + * A `boolean` that controls whether or not deprecation warnings will be thrown as + * exceptions. Setting this to `true` will throw errors for deprecations. This + * property is used instead of the `--throw-deprecation` command line flag. + */ + throwDeprecation: boolean; + /** + * A `boolean` that controls whether or not deprecations printed to `stderr` + * include their stack trace. Setting this to `true` will print stack traces for + * deprecations. This property is instead of the `--trace-deprecation` command line + * flag. + */ + traceDeprecation: boolean; + /** + * A `boolean` that controls whether or not process warnings printed to `stderr` + * include their stack trace. Setting this to `true` will print stack traces for + * process warnings (including deprecations). This property is instead of the + * `--trace-warnings` command line flag. + */ + traceProcessWarnings: boolean; + /** + * A `string` representing the current process's type, can be: + * + * * `browser` - The main process + * * `renderer` - A renderer process + * * `worker` - In a web worker + * + */ + readonly type: ('browser' | 'renderer' | 'worker'); + /** + * A `boolean`. If the app is running as a Windows Store app (appx), this property + * is `true`, for otherwise it is `undefined`. + * + */ + readonly windowsStore: boolean; + } + interface ProcessVersions { + readonly electron: string; + readonly chrome: string; + } } \ No newline at end of file diff --git a/docs/development/Electronite/electronite-tools-2.bat b/docs/development/Electronite/electronite-tools-2.bat new file mode 100755 index 0000000000000..662087d19b52e --- /dev/null +++ b/docs/development/Electronite/electronite-tools-2.bat @@ -0,0 +1,157 @@ +echo off +set ELECTRONITE_REPO="https://github.com/unfoldingWord/electronite" +set Path=%Path%;%HOMEDRIVE%%HOMEPATH%\.electron_build_tools\third_party\depot_tools;%HOMEDRIVE%%HOMEPATH%\.electron_build_tools\src +echo "Path = %Path%" +set working_dir=%cd% +set GIT_CACHE_PATH=%working_dir%\git_cache +mkdir %GIT_CACHE_PATH% + +rem sccache no longer supported in Electron +rem set SCCACHE_BUCKET=electronjs-sccache +rem set SCCACHE_TWO_TIER=true + +set DEPOT_TOOLS_WIN_TOOLCHAIN=0 +set NINJA_STATUS="[%%r processes, %%f/%%t @ %%o/s : %%es] " +echo "GIT_CACHE_PATH=%GIT_CACHE_PATH%" +echo "SCCACHE_BUCKET=%SCCACHE_BUCKET%" +echo "working_dir=%working_dir%" + +echo "%date% - %time%" > start_time.txt + +rem TODO: configure environment variables. + +rem ------------------------ +rem check command to execute +rem ------------------------ +if %1.==. goto MissingArgs + +rem ------------- +rem start command +rem ------------- +if "%1" == "get" goto Get +if "%1" == "build" goto Build +if "%1" == "release" goto Release +goto MissingTag + +:Get +rem #################### +rem fetch code +rem #################### +if %2.==. goto MissingTag +set checkout_tag=%2 + +rem make sure depot_tools is clean +echo Preparing depot_tools +FOR /F "tokens=* USEBACKQ" %%F IN (`where gclient.bat`) DO ( + set depot_tools_dir=%%~dpF +) +echo depot_tools_dir=%depot_tools_dir%" +cd %depot_tools_dir% && call git reset HEAD --hard && echo depot_tools is ready +cd %working_dir% + +rem fetch code +echo Fetching code. This will take a long time and download up to 16GB. +echo Deleting src folder. +if exist src rmdir /Q /S src +echo Deleted src folder. + +call gclient config --name "src/electron" --unmanaged %ELECTRONITE_REPO% +call gclient sync --with_branch_heads --with_tags --nohooks --noprehooks +cd src\electron +echo Checking out %checkout_tag% in %cd% +call git fetch --all +call git checkout %checkout_tag% +cd .. + +rem echo Show Changes +rem call git status +echo Commit all Changes so sync with patches will not fail? +rem this is a hack so that Windows sync will not fail when there are uncommitted changes after git checkout +call git add -A +call git commit -m "commit changes" --author="A U Thor <author@example.com>" +cd .. + +echo Applying electron patches +call gclient sync --with_branch_heads --with_tags + +echo Applying graphite patches +cd .\src +git apply .\electron\docs\development\Electronite\add_graphite_cpp_std_iterator.patch +cd .. + +goto End + +:Build +rem #################### +rem build release +rem #################### +set build_x64=false +if "%2" == "" set build_x64=true + +echo Building release +cd src +set CHROMIUM_BUILDTOOLS_PATH=%cd%\buildtools + +if %build_x64% == false ( + echo Generating %2 configuration... + call gn gen out/Release-%2 --args="target_cpu=\"%2\" import(\"//electron/build/args/release.gn\")" + call ninja -C out/Release-%2 electron +) else ( + echo Generating configuration... + call gn gen out/Release --args="import(\"//electron/build/args/release.gn\")" + call ninja -C out/Release electron +) + +goto End + +:Release +rem #################### +rem create distributable +rem #################### +set build_x64=false +if "%2" == "" set build_x64=true + +echo Making release +cd src + +if %build_x64% == false ( + echo Creating %2 distributable + electron\script\strip-binaries.py -d out\Release-%2 + call ninja -C out\Release-%2 electron:electron_dist_zip +) else ( + echo Creating distributable + electron\script\strip-binaries.py -d out\Release + call ninja -C out\Release electron:electron_dist_zip +) + +goto End + +rem #################### +rem help text +rem #################### + +:MissingArgs + echo *********************** + echo * Electronite Tools * + echo *********************** + echo This is a set of tools for compiling electronite. + echo The source for electronite is at https://github.com/unfoldingWord-dev/electronite. + echo Usage: ./electronite-tools.sh ^<command^> + echo where ^<command^> is one of: + echo get ^<ref^> - fetches all of the code. + echo Where ^<ref^> is a branch or tag. + echo build [arch] - compiles Electronite. The default arch is x64, but you can specify x86. + echo release [arch] - creates the distributable. The default arch is x64, but you can specify x86. + echo For detailed instructions on building Electron + echo see https://github.com/electron/electron/blob/master/docs/development/build-instructions-gn.md + goto End + +:MissingTag + echo Missing the ^<ref^> to checkout. Please specify a tag or branch name. + goto End + +:End + +cd %working_dir% + +echo "%date% - %time%" > end_time.txt diff --git a/docs/development/Electronite/electronite-tools-2.sh b/docs/development/Electronite/electronite-tools-2.sh new file mode 100755 index 0000000000000..91b58959c6630 --- /dev/null +++ b/docs/development/Electronite/electronite-tools-2.sh @@ -0,0 +1,140 @@ +#!/bin/bash +set -e + +ELECTRONITE_REPO="https://github.com/unfoldingWord/electronite" +COMMAND=$1 + +# Configure environment variables and paths +export PATH=$PATH:~/.electron_build_tools/third_party/depot_tools:~/.electron_build_tools/src +echo "PATH = $PATH" +export GIT_CACHE_PATH=`pwd`/git_cache +mkdir -p "${GIT_CACHE_PATH}" + +# sccache no longer supported in Electron +# export SCCACHE_BUCKET="electronjs-sccache" +# export SCCACHE_TWO_TIER=true + +export NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " +echo "GIT_CACHE_PATH=${GIT_CACHE_PATH}" +echo "SCCACHE_BUCKET=${SCCACHE_BUCKET}" + + +########################## +# fetch code +########################## +if [ "$COMMAND" == "get" ]; then + if [ $# -ge 2 ]; then + BRANCH=$2 + else + echo "Missing the <ref> to checkout. Please specify a tag or branch name." + exit 0 + fi + + if [ -d ./src ]; then + echo "Deleting old work folders in the background. This may take a long time with about 49GB and 850K files." + mv src src.old + # run in background + rm -rf src.old& + fi + + echo "Fetching code. This will take a long time and download up to 16GB." + gclient config --name "src/electron" --unmanaged $ELECTRONITE_REPO + gclient sync --with_branch_heads --with_tags --nohooks --noprehooks + cd src/electron + echo "Checking out $BRANCH" + git fetch --all + git checkout $BRANCH + cd - + echo "Applying electron patches" + gclient sync --with_branch_heads --with_tags + echo "Applying graphite patches" + cd ./src + git apply ./electron/docs/development/Electronite/add_graphite_cpp_std_iterator.patch + cd .. + exit 0 +fi + +########################## +# build release +########################## +if [ "$COMMAND" == "build" ]; then + if [ $# -ge 2 ]; then + TARGET=$2 + RELEASE_TARGET="-${TARGET}" + export GN_EXTRA_ARGS="${GN_EXTRA_ARGS} target_cpu = \"${TARGET}\"" + echo "Building for ${TARGET}" + if [ "$TARGET" == "arm64" ] && [ "`uname`" == "Linux" ]; then + export GN_EXTRA_ARGS="${GN_EXTRA_ARGS} fatal_linker_warnings = false enable_linux_installer = false" + fi + echo "Building for \"${TARGET}\", extra args: \"${GN_EXTRA_ARGS}\"" + else + RELEASE_TARGET="" + echo "Building for default \"x64\", extra args: \"${GN_EXTRA_ARGS}\"" + fi + + echo "Building target: ${RELEASE_TARGET}" + + cd src + export CHROMIUM_BUILDTOOLS_PATH=`pwd`/buildtools +# export GN_EXTRA_ARGS="${GN_EXTRA_ARGS} cc_wrapper=\"${PWD}/electron/external_binaries/sccache\"" + echo "Generating configuration..." + gn gen out/Release${RELEASE_TARGET} --args="import(\"//electron/build/args/release.gn\") $GN_EXTRA_ARGS" + ninja -C out/Release${RELEASE_TARGET} electron + cd - + exit 0 +fi + +########################## +# create distributable +########################## +if [ "$COMMAND" == "release" ]; then + if [ $# -ge 2 ]; then + TARGET="$2" + RELEASE_TARGET="-${TARGET}" + STRIP_EXTRA_ARGS=--target-cpu=$TARGET + export GN_EXTRA_ARGS="${GN_EXTRA_ARGS} target_cpu=\"${TARGET}\"" + echo "Releasing for \"${TARGET}\", extra args: \"${STRIP_EXTRA_ARGS}\"" + else + RELEASE_TARGET="" + STRIP_EXTRA_ARGS="" + echo "Releasing for default \"x64\", extra args: \"${STRIP_EXTRA_ARGS}\"" + fi + + echo "Releasing: ${RELEASE_TARGET}" + + echo "Creating distributable" + cd src + if [ "`uname`" != "Darwin" ]; then + ./electron/script/strip-binaries.py ${STRIP_EXTRA_ARGS} -d out/Release${RELEASE_TARGET} + fi + ninja -C out/Release${RELEASE_TARGET} electron:electron_dist_zip + exit 0 +fi + +########################## +# help +########################## +if [ "$COMMAND" == "" ]; then + echo "*********************** +* Electronite Tools * +*********************** +This is a set of tools for compiling Electronite. +The source for Electronite is at https://github.com/unfoldingWord-dev/electronite. + +Usage: ./electronite-tools.sh <command> + +where <command> is one of: + + get <ref> - fetches all of the code. + Where <ref> is a branch or tag. + + build <target> - compiles Electronite, target is optional, defaults to x64, + Could be arm64. + + release <target> - creates the distributable. Use same target as + previous build. + +For detailed instructions on building Electron +see https://github.com/electron/electron/blob/master/docs/development/build-instructions-gn.md +" +fi \ No newline at end of file diff --git a/docs/development/Electronite/electronite.patch b/docs/development/Electronite/electronite.patch index 0da91209a8159..87eeb8f59d812 100644 --- a/docs/development/Electronite/electronite.patch +++ b/docs/development/Electronite/electronite.patch @@ -2,7 +2,7 @@ diff --git a/DEPS b/DEPS index 5047b6b16..3c928c079 100644 --- a/DEPS +++ b/DEPS -@@ -27,12 +27,14 @@ vars = { +@@ -11,12 +11,14 @@ vars = { '0e5d146ba13101a1302d59ea6e6e0b3cace4ae38', 'pyyaml_version': '3.12', @@ -17,7 +17,7 @@ index 5047b6b16..3c928c079 100644 # KEEP IN SYNC WITH utils.js FILE 'yarn_version': '1.15.2', -@@ -48,6 +50,7 @@ vars = { +@@ -32,6 +34,7 @@ vars = { 'checkout_node': True, 'checkout_nan': True, 'checkout_pgo_profiles': True, @@ -25,7 +25,7 @@ index 5047b6b16..3c928c079 100644 # It's only needed to parse the native tests configurations. 'checkout_pyyaml': False, -@@ -98,6 +101,10 @@ deps = { +@@ -82,6 +85,10 @@ deps = { 'url': (Var("yaml_git")) + '/pyyaml.git@' + (Var("pyyaml_version")), 'condition': 'checkout_pyyaml and process_deps', }, @@ -36,7 +36,7 @@ index 5047b6b16..3c928c079 100644 'src/third_party/squirrel.mac': { 'url': Var("squirrel_git") + '/Squirrel.Mac.git@' + Var("squirrel.mac_version"), 'condition': 'process_deps', -@@ -127,6 +134,16 @@ pre_deps_hooks = [ +@@ -111,6 +118,16 @@ pre_deps_hooks = [ 'src/electron/patches/config.json', ], }, @@ -57,8 +57,8 @@ diff --git a/patches/chromium/.patches b/patches/chromium/.patches index c7311e348..7f9c36e22 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches -@@ -115,3 +115,4 @@ fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch - remove_incorrect_width_height_adjustments.patch +@@ -105,3 +105,4 @@ fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch + build_make_libcxx_abi_unstable_false_for_electron.patch introduce_ozoneplatform_electron_can_call_x11_property.patch make_gtk_getlibgtk_public.patch +add_graphite.patch diff --git a/docs/development/README.md b/docs/development/README.md index 6ddbbcdbae800..fcf147f1cac0f 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -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 reponsibilities can be found in the [governance repo](https://github.com/electron/governance). +Details about each group and their responsibilities can be found in the [governance repo](https://github.com/electron/governance). ## Patches in Electron diff --git a/docs/development/build-instructions-gn.md b/docs/development/build-instructions-gn.md index 70b5c48ed857c..cd955743df3b9 100644 --- a/docs/development/build-instructions-gn.md +++ b/docs/development/build-instructions-gn.md @@ -196,12 +196,12 @@ If you test other combinations and find them to work, please update this documen See the GN reference for allowable values of [`target_os`][target_os values] and [`target_cpu`][target_cpu values]. -[target_os values]: https://gn.googlesource.com/gn/+/master/docs/reference.md#built_in-predefined-variables-target_os_the-desired-operating-system-for-the-build-possible-values -[target_cpu values]: https://gn.googlesource.com/gn/+/master/docs/reference.md#built_in-predefined-variables-target_cpu_the-desired-cpu-architecture-for-the-build-possible-values +[target_os values]: https://gn.googlesource.com/gn/+/main/docs/reference.md#built_in-predefined-variables-target_os_the-desired-operating-system-for-the-build-possible-values +[target_cpu values]: https://gn.googlesource.com/gn/+/main/docs/reference.md#built_in-predefined-variables-target_cpu_the-desired-cpu-architecture-for-the-build-possible-values #### Windows on Arm (experimental) -To cross-compile for Windows on Arm, [follow Chromium's guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/master/docs/windows_build_instructions.md#Visual-Studio) to get the necessary dependencies, SDK and libraries, then build with `ELECTRON_BUILDING_WOA=1` in your environment before running `gclient sync`. +To cross-compile for Windows on Arm, [follow Chromium's guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/windows_build_instructions.md#Visual-Studio) to get the necessary dependencies, SDK and libraries, then build with `ELECTRON_BUILDING_WOA=1` in your environment before running `gclient sync`. ```bat set ELECTRON_BUILDING_WOA=1 diff --git a/docs/development/build-instructions-linux.md b/docs/development/build-instructions-linux.md index 3bdd96863ceba..8bfd6349a511a 100644 --- a/docs/development/build-instructions-linux.md +++ b/docs/development/build-instructions-linux.md @@ -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 gtk3-devel libnotify-devel \ - libgnome-keyring-devel xorg-x11-server-utils libcap-devel \ +$ sudo dnf install clang dbus-devel gperf gtk3-devel \ + libnotify-devel libgnome-keyring-devel libcap-devel \ cups-devel libXtst-devel alsa-lib-devel libXrandr-devel \ - nss-devel python-dbusmock openjdk-8-jre + nss-devel python-dbusmock ``` On Arch Linux / Manjaro, install the following libraries: @@ -82,7 +82,7 @@ $ sudo apt-get install libc6-dev-arm64-cross linux-libc-dev-arm64-cross \ g++-aarch64-linux-gnu ``` -And to cross-compile for `arm` or `ia32` targets, you should pass the +And to cross-compile for `arm` or targets, you should pass the `target_cpu` parameter to `gn gen`: ```sh diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 49e436197d851..171679ddab5ba 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -9,14 +9,12 @@ Follow the guidelines below for building **Electron itself** on Windows, for the * Windows 10 / Server 2012 R2 or higher * Visual Studio 2017 15.7.2 or higher - [download VS 2019 Community Edition for free](https://www.visualstudio.com/vs/) - * See [the Chromium build documentation](https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md#visual-studio) for more details on which Visual Studio + * See [the Chromium build documentation](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md#visual-studio) for more details on which Visual Studio components are required. * If your Visual Studio is installed in a directory other than the default, you'll need to set a few environment variables to point the toolchains to your installation path. * `vs2019_install = DRIVE:\path\to\Microsoft Visual Studio\2019\Community`, replacing `2019` and `Community` with your installed versions and replacing `DRIVE:` with the drive that Visual Studio is on. Often, this will be `C:`. * `WINDOWSSDKDIR = DRIVE:\path\to\Windows Kits\10`, replacing `DRIVE:` with the drive that Windows Kits is on. Often, this will be `C:`. - * [Python for Windows (pywin32) Extensions](https://pypi.org/project/pywin32/#files) - is also needed in order to run the build process. * [Node.js](https://nodejs.org/download/) * [Git](https://git-scm.com) * Debugging Tools for Windows of Windows SDK 10.0.15063.468 if you plan on diff --git a/docs/development/debugging.md b/docs/development/debugging.md index 775a31199b95e..7fc7c0bc13eaf 100644 --- a/docs/development/debugging.md +++ b/docs/development/debugging.md @@ -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, amonst other things. +You might use this to print out variable values, function names, and line numbers, amongst 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 interrrupting the program. +Chromium contains a helper to print stack traces to console without interrupting the program. ```cpp #include "base/debug/stack_trace.h" diff --git a/docs/development/issues.md b/docs/development/issues.md index ec0ad5dc04f36..1eb530111c7a8 100644 --- a/docs/development/issues.md +++ b/docs/development/issues.md @@ -24,7 +24,7 @@ contribute: ## Asking for General Help -["Finding Support"](../tutorial/support.md#finding-support) has a +[The Electron website](https://electronjs.org/community) has a list of resources for getting programming help, reporting security issues, contributing, and more. Please use the issue tracker for bugs only! diff --git a/docs/faq.md b/docs/faq.md index 174104aee9b0c..84b3b5cf6e201 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -135,7 +135,7 @@ is only available in renderer processes. If [sub-pixel anti-aliasing](https://alienryderflex.com/sub_pixel/) is deactivated, then fonts on LCD screens can look blurry. Example: -![subpixel rendering example] +![Subpixel rendering example](images/subpixel-rendering-screenshot.gif) Sub-pixel anti-aliasing needs a non-transparent background of the layer containing the font glyphs. (See [this issue](https://github.com/electron/electron/issues/6344#issuecomment-420371918) for more info). @@ -161,4 +161,3 @@ Notice that just setting the background in the CSS does not have the desired eff [indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API [message-port]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort [browser-window]: api/browser-window.md -[subpixel rendering example]: images/subpixel-rendering-screenshot.gif diff --git a/docs/fiddles/communication/two-processes/asynchronous-messages/index.html b/docs/fiddles/communication/two-processes/asynchronous-messages/index.html deleted file mode 100644 index 43d23a29087f2..0000000000000 --- a/docs/fiddles/communication/two-processes/asynchronous-messages/index.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="UTF-8"> - </head> - <body> - <div> - <div> - <h1>Asynchronous messages</h1> - <i>Supports: Win, macOS, Linux <span>|</span> Process: Both</i> - <div> - <div> - <button id="async-msg">Ping</button> - <span id="async-reply"></span> - </div> - <p>Using <code>ipc</code> to send messages between processes asynchronously is the preferred method since it will return when finished without blocking other operations in the same process.</p> - - <p>This example sends a "ping" from this process (renderer) to the main process. The main process then replies with "pong".</p> - </div> - </div> - </div> - <script> - // You can also require other files to run in this process - require('./renderer.js') - </script> - </body> -</html> diff --git a/docs/fiddles/communication/two-processes/asynchronous-messages/main.js b/docs/fiddles/communication/two-processes/asynchronous-messages/main.js deleted file mode 100644 index 942f7022f8590..0000000000000 --- a/docs/fiddles/communication/two-processes/asynchronous-messages/main.js +++ /dev/null @@ -1,29 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Asynchronous messages', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) - -ipcMain.on('asynchronous-message', (event, arg) => { - event.sender.send('asynchronous-reply', 'pong') -}) diff --git a/docs/fiddles/communication/two-processes/asynchronous-messages/renderer.js b/docs/fiddles/communication/two-processes/asynchronous-messages/renderer.js deleted file mode 100644 index 40ed596201ad2..0000000000000 --- a/docs/fiddles/communication/two-processes/asynchronous-messages/renderer.js +++ /dev/null @@ -1,12 +0,0 @@ -const { ipcRenderer } = require('electron') - -const asyncMsgBtn = document.getElementById('async-msg') - -asyncMsgBtn.addEventListener('click', () => { - ipcRenderer.send('asynchronous-message', 'ping') -}) - -ipcRenderer.on('asynchronous-reply', (event, arg) => { - const message = `Asynchronous message reply: ${arg}` - document.getElementById('async-reply').innerHTML = message -}) diff --git a/docs/fiddles/communication/two-processes/synchronous-messages/index.html b/docs/fiddles/communication/two-processes/synchronous-messages/index.html deleted file mode 100644 index 055fcf3473ce1..0000000000000 --- a/docs/fiddles/communication/two-processes/synchronous-messages/index.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="UTF-8"> - </head> - <body> - <div> - <div> - <h1>Synchronous messages</h1> - <i>Supports: Win, macOS, Linux <span>|</span> Process: Both</i> - <div> - <div> - <button id="sync-msg">Ping</button> - <span id="sync-reply"></span> - </div> - <p>You can use the <code>ipc</code> module to send synchronous messages between processes as well, but note that the synchronous nature of this method means that it <b>will block</b> other operations while completing its task.</p> - - <p>This example sends a synchronous message, "ping", from this process (renderer) to the main process. The main process then replies with "pong".</p> - </div> - </div> - </div> - <script> - // You can also require other files to run in this process - require('./renderer.js') - </script> - </body> -</html> \ No newline at end of file diff --git a/docs/fiddles/communication/two-processes/synchronous-messages/main.js b/docs/fiddles/communication/two-processes/synchronous-messages/main.js deleted file mode 100644 index 1adb7c02c9f11..0000000000000 --- a/docs/fiddles/communication/two-processes/synchronous-messages/main.js +++ /dev/null @@ -1,29 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron') - -let mainWindow = null - -function createWindow () { - const windowOptions = { - width: 600, - height: 400, - title: 'Synchronous Messages', - webPreferences: { - nodeIntegration: true - } - } - - mainWindow = new BrowserWindow(windowOptions) - mainWindow.loadFile('index.html') - - mainWindow.on('closed', () => { - mainWindow = null - }) -} - -app.whenReady().then(() => { - createWindow() -}) - -ipcMain.on('synchronous-message', (event, arg) => { - event.returnValue = 'pong' -}) \ No newline at end of file diff --git a/docs/fiddles/communication/two-processes/synchronous-messages/renderer.js b/docs/fiddles/communication/two-processes/synchronous-messages/renderer.js deleted file mode 100644 index 4769b6f97f714..0000000000000 --- a/docs/fiddles/communication/two-processes/synchronous-messages/renderer.js +++ /dev/null @@ -1,9 +0,0 @@ -const { ipcRenderer } = require('electron') - -const syncMsgBtn = document.getElementById('sync-msg') - -syncMsgBtn.addEventListener('click', () => { - const reply = ipcRenderer.sendSync('synchronous-message', 'ping') - const message = `Synchronous message reply: ${reply}` - document.getElementById('sync-reply').innerHTML = message -}) \ No newline at end of file diff --git a/docs/fiddles/features/drag-and-drop/preload.js b/docs/fiddles/features/drag-and-drop/preload.js index 4609e12c75528..7e698ebb54ff2 100644 --- a/docs/fiddles/features/drag-and-drop/preload.js +++ b/docs/fiddles/features/drag-and-drop/preload.js @@ -1,5 +1,4 @@ const { contextBridge, ipcRenderer } = require('electron') -const path = require('path') contextBridge.exposeInMainWorld('electron', { startDrag: (fileName) => { diff --git a/docs/fiddles/features/web-bluetooth/main.js b/docs/fiddles/features/web-bluetooth/main.js index b3cc55a438198..5d560579cc05f 100644 --- a/docs/fiddles/features/web-bluetooth/main.js +++ b/docs/fiddles/features/web-bluetooth/main.js @@ -1,10 +1,13 @@ -const {app, BrowserWindow} = require('electron') +const {app, BrowserWindow, ipcMain} = require('electron') const path = require('path') function createWindow () { const mainWindow = new BrowserWindow({ width: 800, - height: 600 + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } }) mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => { @@ -14,6 +17,18 @@ function createWindow () { } }) + // Listen for a message from the renderer to get the response for the Bluetooth pairing. + ipcMain.on('bluetooth-pairing-response', (event, response) => { + bluetoothPinCallback(response) + }) + + mainWindow.webContents.session.setBluetoothPairingHandler((details, callback) => { + + bluetoothPinCallback = callback + // Send a message to the renderer to prompt the user to confirm the pairing. + mainWindow.webContents.send('bluetooth-pairing-request', details) + }) + mainWindow.loadFile('index.html') } diff --git a/docs/fiddles/features/web-bluetooth/preload.js b/docs/fiddles/features/web-bluetooth/preload.js new file mode 100644 index 0000000000000..0c21fcce93881 --- /dev/null +++ b/docs/fiddles/features/web-bluetooth/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('electronAPI', { + bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', callback), + bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response) +}) \ No newline at end of file diff --git a/docs/fiddles/features/web-bluetooth/renderer.js b/docs/fiddles/features/web-bluetooth/renderer.js index e5830955599af..080fb6105b287 100644 --- a/docs/fiddles/features/web-bluetooth/renderer.js +++ b/docs/fiddles/features/web-bluetooth/renderer.js @@ -5,4 +5,30 @@ async function testIt() { document.getElementById('device-name').innerHTML = device.name || `ID: ${device.id}` } -document.getElementById('clickme').addEventListener('click',testIt) \ No newline at end of file +document.getElementById('clickme').addEventListener('click',testIt) + +window.electronAPI.bluetoothPairingRequest((event, details) => { + const response = {} + + switch (details.pairingKind) { + case 'confirm': { + response.confirmed = confirm(`Do you want to connect to device ${details.deviceId}?`) + break + } + case 'confirmPin': { + response.confirmed = confirm(`Does the pin ${details.pin} match the pin displayed on device ${details.deviceId}?`) + break + } + case 'providePin': { + const pin = prompt(`Please provide a pin for ${details.deviceId}.`) + if (pin) { + response.pin = pin + response.confirmed = true + } else { + response.confirmed = false + } + } + } + + window.electronAPI.bluetoothPairingResponse(response) +}) \ No newline at end of file diff --git a/docs/fiddles/features/web-hid/main.js b/docs/fiddles/features/web-hid/main.js index cb61e188a0fd0..3304457db822f 100644 --- a/docs/fiddles/features/web-hid/main.js +++ b/docs/fiddles/features/web-hid/main.js @@ -8,20 +8,24 @@ function createWindow () { }) mainWindow.webContents.session.on('select-hid-device', (event, details, callback) => { + //Add events to handle devices being added or removed before the callback on + //`select-hid-device` is called. + mainWindow.webContents.session.on('hid-device-added', (event, device) => { + console.log('hid-device-added FIRED WITH', device) + //Optionally update details.deviceList + }) + + mainWindow.webContents.session.on('hid-device-removed', (event, device) => { + console.log('hid-device-removed FIRED WITH', device) + //Optionally update details.deviceList + }) + event.preventDefault() if (details.deviceList && details.deviceList.length > 0) { callback(details.deviceList[0].deviceId) } }) - mainWindow.webContents.session.on('hid-device-added', (event, device) => { - console.log('hid-device-added FIRED WITH', device) - }) - - mainWindow.webContents.session.on('hid-device-removed', (event, device) => { - console.log('hid-device-removed FIRED WITH', device) - }) - mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { if (permission === 'hid' && details.securityOrigin === 'file:///') { return true diff --git a/docs/fiddles/features/web-serial/main.js b/docs/fiddles/features/web-serial/main.js index c6bd996724d2e..7150ec60651e9 100644 --- a/docs/fiddles/features/web-serial/main.js +++ b/docs/fiddles/features/web-serial/main.js @@ -8,6 +8,19 @@ function createWindow () { }) mainWindow.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => { + + //Add listeners to handle ports being added or removed before the callback for `select-serial-port` + //is called. + mainWindow.webContents.session.on('serial-port-added', (event, port) => { + console.log('serial-port-added FIRED WITH', port) + //Optionally update portList to add the new port + }) + + mainWindow.webContents.session.on('serial-port-removed', (event, port) => { + console.log('serial-port-removed FIRED WITH', port) + //Optionally update portList to remove the port + }) + event.preventDefault() if (portList && portList.length > 0) { callback(portList[0].portId) @@ -16,24 +29,20 @@ function createWindow () { } }) - mainWindow.webContents.session.on('serial-port-added', (event, port) => { - console.log('serial-port-added FIRED WITH', port) - }) - - mainWindow.webContents.session.on('serial-port-removed', (event, port) => { - console.log('serial-port-removed FIRED WITH', port) - }) - mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { if (permission === 'serial' && details.securityOrigin === 'file:///') { return true } + + return false }) mainWindow.webContents.session.setDevicePermissionHandler((details) => { if (details.deviceType === 'serial' && details.origin === 'file://') { return true } + + return false }) mainWindow.loadFile('index.html') diff --git a/docs/fiddles/tutorial-first-app/index.html b/docs/fiddles/tutorial-first-app/index.html new file mode 100644 index 0000000000000..3d677b7c97b5b --- /dev/null +++ b/docs/fiddles/tutorial-first-app/index.html @@ -0,0 +1,21 @@ +<!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! + + +

Hello from Electron renderer!

+

πŸ‘‹

+

+ + + diff --git a/docs/fiddles/tutorial-first-app/main.js b/docs/fiddles/tutorial-first-app/main.js new file mode 100644 index 0000000000000..10d57a0696f0f --- /dev/null +++ b/docs/fiddles/tutorial-first-app/main.js @@ -0,0 +1,26 @@ +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(); + } +}); diff --git a/docs/fiddles/tutorial-preload/index.html b/docs/fiddles/tutorial-preload/index.html new file mode 100644 index 0000000000000..3d677b7c97b5b --- /dev/null +++ b/docs/fiddles/tutorial-preload/index.html @@ -0,0 +1,21 @@ + + + + + + + Hello from Electron renderer! + + +

Hello from Electron renderer!

+

πŸ‘‹

+

+ + + diff --git a/docs/fiddles/tutorial-preload/main.js b/docs/fiddles/tutorial-preload/main.js new file mode 100644 index 0000000000000..6b7184900e6dd --- /dev/null +++ b/docs/fiddles/tutorial-preload/main.js @@ -0,0 +1,30 @@ +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(); + } +}); diff --git a/docs/fiddles/tutorial-preload/preload.js b/docs/fiddles/tutorial-preload/preload.js new file mode 100644 index 0000000000000..e0dbdce1b8b2f --- /dev/null +++ b/docs/fiddles/tutorial-preload/preload.js @@ -0,0 +1,7 @@ +const { contextBridge } = require('electron'); + +contextBridge.exposeInMainWorld('versions', { + node: () => process.versions.node, + chrome: () => process.versions.chrome, + electron: () => process.versions.electron, +}); diff --git a/docs/fiddles/tutorial-preload/renderer.js b/docs/fiddles/tutorial-preload/renderer.js new file mode 100644 index 0000000000000..7585229a91781 --- /dev/null +++ b/docs/fiddles/tutorial-preload/renderer.js @@ -0,0 +1,2 @@ +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()})`; diff --git a/docs/glossary.md b/docs/glossary.md index a4bfa2a96071f..893c598c52b80 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -91,7 +91,7 @@ An IPC system for communicating intra- or inter-process, and that's important because Chrome is keen on being able to split its work into separate processes or not, depending on memory pressures etc. -See https://chromium.googlesource.com/chromium/src/+/master/mojo/README.md +See https://chromium.googlesource.com/chromium/src/+/main/mojo/README.md See also: [IPC](#ipc) diff --git a/docs/images/gatekeeper.png b/docs/images/gatekeeper.png index ed4b15ec7e8d2..22567135b7da1 100644 Binary files a/docs/images/gatekeeper.png and b/docs/images/gatekeeper.png differ diff --git a/docs/images/message-notification-renderer.png b/docs/images/message-notification-renderer.png deleted file mode 100644 index 87c8a876a2b4f..0000000000000 Binary files a/docs/images/message-notification-renderer.png and /dev/null differ diff --git a/docs/images/online-event-detection.png b/docs/images/online-event-detection.png deleted file mode 100644 index 4f16489a7271c..0000000000000 Binary files a/docs/images/online-event-detection.png and /dev/null differ diff --git a/docs/images/preload-example.png b/docs/images/preload-example.png new file mode 100644 index 0000000000000..9f330b32de9ca Binary files /dev/null and b/docs/images/preload-example.png differ diff --git a/docs/images/tutorial-release-schedule.svg b/docs/images/tutorial-release-schedule.svg deleted file mode 100644 index 6fa6539167894..0000000000000 --- a/docs/images/tutorial-release-schedule.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - master - - - - - 2.0 - - v2.0.0-beta0 - - v2.0.0 - - - - - 2.1 - - v2.1.0-beta0 - - v2.1.0-beta1 - - v2.1.0 - - - - - 3.0 - - v3.0.0-beta0 - - v3.0.0 - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - bug fix - - - - - - feature - - - - feature - - - - feature - - - - - chromiumupdate - - - - ~1 week - - - - ~1 week - - - - ~1 week - - - - \ No newline at end of file diff --git a/docs/images/windows-taskbar-icon-overlay.png b/docs/images/windows-taskbar-icon-overlay.png new file mode 100644 index 0000000000000..fb9a86d530bb1 Binary files /dev/null and b/docs/images/windows-taskbar-icon-overlay.png differ diff --git a/docs/images/windows-taskbar-jumplist.png b/docs/images/windows-taskbar-jumplist.png new file mode 100644 index 0000000000000..7660abcbb1051 Binary files /dev/null and b/docs/images/windows-taskbar-jumplist.png differ diff --git a/docs/images/windows-taskbar-thumbnail-toolbar.png b/docs/images/windows-taskbar-thumbnail-toolbar.png new file mode 100644 index 0000000000000..41a251e8d7b36 Binary files /dev/null and b/docs/images/windows-taskbar-thumbnail-toolbar.png differ diff --git a/docs/tutorial/application-distribution.md b/docs/tutorial/application-distribution.md index fb5dc918dad91..6f5d86290dc0d 100644 --- a/docs/tutorial/application-distribution.md +++ b/docs/tutorial/application-distribution.md @@ -1,26 +1,26 @@ -# Application Distribution +--- +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 +--- -## 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. +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 -You can use the following tools to distribute your application: - -* [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) +There are a couple tools out there that exist to package and distribute your Electron app. +We recommend using [Electron Forge](./forge-overview.md). You can check out +its [documentation](https://www.electronforge.io) directly, or refer to the [Packaging and Distribution](./tutorial-5-packaging.md) +part of the Electron tutorial. -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. +## Manual packaging -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). +If you prefer the manual approach, there are 2 ways to distribute your application: -## Manual distribution +- With prebuilt binaries +- With an app source code archive ### With prebuilt binaries @@ -29,21 +29,19 @@ 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. +::: -*On macOS:* - -```plaintext +```plain title='macOS' electron/Electron.app/Contents/Resources/app/ β”œβ”€β”€ package.json β”œβ”€β”€ main.js └── index.html ``` -*On Windows and Linux:* - -```plaintext +```plain title='Windows and Linux' electron/resources/app β”œβ”€β”€ package.json β”œβ”€β”€ main.js @@ -54,7 +52,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 +### With an app source code archive (asar) 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 @@ -65,16 +63,12 @@ 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. -*On macOS:* - -```plaintext +```plain title='macOS' electron/Electron.app/Contents/Resources/ └── app.asar ``` -*On Windows and Linux:* - -```plaintext +```plain title='Windows' electron/resources/ └── app.asar ``` @@ -87,47 +81,44 @@ 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. -#### 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: +- **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: -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` + - `Electron.app/Contents/Info.plist` + - `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` -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. + 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. -The structure of a renamed app would be like: + The structure of a renamed app would be like: -```plaintext +```plain MyApp.app/Contents β”œβ”€β”€ Info.plist β”œβ”€β”€ MacOS/ -β”‚Β Β  └── MyApp +β”‚ └── MyApp └── Frameworks/ └── MyApp Helper.app β”œβ”€β”€ Info.plist └── MacOS/ - Β Β  └── MyApp Helper + └── MyApp Helper ``` -#### Windows +:::note -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 +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 diff --git a/docs/tutorial/asar-archives.md b/docs/tutorial/asar-archives.md new file mode 100644 index 0000000000000..23b987f42ee50 --- /dev/null +++ b/docs/tutorial/asar-archives.md @@ -0,0 +1,175 @@ +--- +title: ASAR Archives +description: What is ASAR archive and how does it affect the application. +slug: asar-archives +hide_title: false +--- + +After creating an [application distribution](application-distribution.md), the +app's source code are usually bundled into an [ASAR +archive](https://github.com/electron/asar), which is a simple extensive archive +format designed for Electron apps. By bundling the app we can mitigate issues +around long path names on Windows, speed up `require` and conceal your source +code from cursory inspection. + +The bundled app runs in a virtual file system and most APIs would just work +normally, but for some cases you might want to work on ASAR archives explicitly +due to a few caveats. + +## Using ASAR Archives + +In Electron there are two sets of APIs: Node APIs provided by Node.js and Web +APIs provided by Chromium. Both APIs support reading files from ASAR archives. + +### Node API + +With special patches in Electron, Node APIs like `fs.readFile` and `require` +treat ASAR archives as virtual directories, and the files in it as normal +files in the filesystem. + +For example, suppose we have an `example.asar` archive under `/path/to`: + +```sh +$ asar list /path/to/example.asar +/app.js +/file.txt +/dir/module.js +/static/index.html +/static/main.css +/static/jquery.min.js +``` + +Read a file in the ASAR archive: + +```javascript +const fs = require('fs') +fs.readFileSync('/path/to/example.asar/file.txt') +``` + +List all files under the root of the archive: + +```javascript +const fs = require('fs') +fs.readdirSync('/path/to/example.asar') +``` + +Use a module from the archive: + +```javascript +require('./path/to/example.asar/dir/module.js') +``` + +You can also display a web page in an ASAR archive with `BrowserWindow`: + +```javascript +const { BrowserWindow } = require('electron') +const win = new BrowserWindow() + +win.loadURL('file:///path/to/example.asar/static/index.html') +``` + +### Web API + +In a web page, files in an archive can be requested with the `file:` protocol. +Like the Node API, ASAR archives are treated as directories. + +For example, to get a file with `$.get`: + +```html + +``` + +### Treating an ASAR archive as a Normal File + +For some cases like verifying the ASAR archive's checksum, we need to read the +content of an ASAR archive as a file. For this purpose you can use the built-in +`original-fs` module which provides original `fs` APIs without `asar` support: + +```javascript +const originalFs = require('original-fs') +originalFs.readFileSync('/path/to/example.asar') +``` + +You can also set `process.noAsar` to `true` to disable the support for `asar` in +the `fs` module: + +```javascript +const fs = require('fs') +process.noAsar = true +fs.readFileSync('/path/to/example.asar') +``` + +## Limitations of the Node API + +Even though we tried hard to make ASAR archives in the Node API work like +directories as much as possible, there are still limitations due to the +low-level nature of the Node API. + +### Archives Are Read-only + +The archives can not be modified so all Node APIs that can modify files will not +work with ASAR archives. + +### Working Directory Can Not Be Set to Directories in Archive + +Though ASAR archives are treated as directories, there are no actual +directories in the filesystem, so you can never set the working directory to +directories in ASAR archives. Passing them as the `cwd` option of some APIs +will also cause errors. + +### Extra Unpacking on Some APIs + +Most `fs` APIs can read a file or get a file's information from ASAR archives +without unpacking, but for some APIs that rely on passing the real file path to +underlying system calls, Electron will extract the needed file into a +temporary file and pass the path of the temporary file to the APIs to make them +work. This adds a little overhead for those APIs. + +APIs that requires extra unpacking are: + +* `child_process.execFile` +* `child_process.execFileSync` +* `fs.open` +* `fs.openSync` +* `process.dlopen` - Used by `require` on native modules + +### Fake Stat Information of `fs.stat` + +The `Stats` object returned by `fs.stat` and its friends on files in `asar` +archives is generated by guessing, because those files do not exist on the +filesystem. So you should not trust the `Stats` object except for getting file +size and checking file type. + +### Executing Binaries Inside ASAR archive + +There are Node APIs that can execute binaries like `child_process.exec`, +`child_process.spawn` and `child_process.execFile`, but only `execFile` is +supported to execute binaries inside ASAR archive. + +This is because `exec` and `spawn` accept `command` instead of `file` as input, +and `command`s are executed under shell. There is no reliable way to determine +whether a command uses a file in asar archive, and even if we do, we can not be +sure whether we can replace the path in command without side effects. + +## Adding Unpacked Files to ASAR archives + +As stated above, some Node APIs will unpack the file to the filesystem when +called. Apart from the performance issues, various anti-virus scanners might +be triggered by this behavior. + +As a workaround, you can leave various files unpacked using the `--unpack` option. +In the following example, shared libraries of native Node.js modules will not be +packed: + +```sh +$ asar pack app app.asar --unpack *.node +``` + +After running the command, you will notice that a folder named `app.asar.unpacked` +was created together with the `app.asar` file. It contains the unpacked files +and should be shipped together with the `app.asar` archive. diff --git a/docs/tutorial/asar-integrity.md b/docs/tutorial/asar-integrity.md new file mode 100644 index 0000000000000..63320cea31336 --- /dev/null +++ b/docs/tutorial/asar-integrity.md @@ -0,0 +1,53 @@ +--- +title: 'ASAR Integrity' +description: 'An experimental feature that ensures the validity of ASAR contents at runtime.' +slug: asar-integrity +hide_title: false +--- + +## Platform Support + +Currently ASAR integrity checking is only supported on macOS. + +## Requirements + +### Electron Forge / Electron Packager + +If you are using `>= electron-packager@15.4.0` or `>= @electron-forge/core@6.0.0-beta.61` then all these requirements are met for you automatically and you can skip to [Toggling the Fuse](#toggling-the-fuse). + +### Other build systems + +In order to enable ASAR integrity checking you need to ensure that your `app.asar` file was generated by a version of the `asar` npm package that supports asar integrity. Support was introduced in version `3.1.0`. + +Your must then populate a valid `ElectronAsarIntegrity` dictionary block in your packaged apps `Info.plist`. An example is included below. + +```plist +ElectronAsarIntegrity + + Resources/app.asar + + algorithm + SHA256 + hash + 9d1f61ea03c4bb62b4416387a521101b81151da0cfbe18c9f8c8b818c5cebfac + + +``` + +Valid `algorithm` values are currently `SHA256` only. The `hash` is a hash of the ASAR header using the given algorithm. The `asar` package exposes a `getRawHeader` method whose result can then be hashed to generate this value. + +## Toggling the Fuse + +ASAR integrity checking is currently disabled by default and can be enabled by toggling a fuse. See [Electron Fuses](fuses.md) for more information on what Electron Fuses are and how they work. When enabling this fuse you typically also want to enable the `onlyLoadAppFromAsar` fuse otherwise the validity checking can be bypassed via the Electron app code search path. + +```js +require('@electron/fuses').flipFuses( + // E.g. /a/b/Foo.app + pathToPackagedApp, + { + version: FuseVersion.V1, + [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, + [FuseV1Options.OnlyLoadAppFromAsar]: true + } +) +``` diff --git a/docs/tutorial/boilerplates-and-clis.md b/docs/tutorial/boilerplates-and-clis.md index 304254285180e..f344ae1b25979 100644 --- a/docs/tutorial/boilerplates-and-clis.md +++ b/docs/tutorial/boilerplates-and-clis.md @@ -26,10 +26,8 @@ beginners, using a command line tool is likely to be helpful*. ## electron-forge -A "complete tool for building modern Electron applications". Electron Forge -unifies the existing (and well maintained) build tools for Electron development -into a cohesive package so that anyone can jump right in to Electron -development. +Electron Forge is a tool for packaging and publishing Electron applications. It unifies Electron's tooling ecosystem +into a single extensible interface so that anyone can jump right into making Electron apps. Forge comes with [a ready-to-use template](https://electronforge.io/templates) using Webpack as a bundler. It includes an example typescript configuration and provides two configuration files to enable easy customization. It uses the same core modules used by the greater Electron community (like [`electron-packager`](https://github.com/electron/electron-packager)) – diff --git a/docs/tutorial/code-signing.md b/docs/tutorial/code-signing.md index d591fe617c89b..06fae1eaf7252 100644 --- a/docs/tutorial/code-signing.md +++ b/docs/tutorial/code-signing.md @@ -1,14 +1,20 @@ -# Code Signing +--- +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 is a security technology that you use to certify that an app was -created by you. +created by you. You should sign your application so it does not trigger any +operating system security checks. -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 @@ -16,20 +22,19 @@ 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 @@ -42,99 +47,23 @@ notarizing your app: Electron's ecosystem favors configuration and freedom, so there are multiple ways to get your application signed and notarized. -## `electron-forge` +### Using 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 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 -{ - "name": "my-app", - "version": "0.0.1", - "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": "my-apple-id-password", - } - } - } - } -} -``` - -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 - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.debugger - - - -``` - -Note that up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required -as well. However, it should not be used anymore if it can be avoided. +Detailed instructions on how to configure your application can be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-macos). -To see all of this in action, check out Electron Fiddle's source code, -[especially its `electron-forge` configuration -file](https://github.com/electron/fiddle/blob/master/forge.config.js). - -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 -com.apple.security.device.audio-input - -com.apple.security.device.camera - -``` - -If these are not present in your app's entitlements when you invoke, for example: - -```js -const { systemPreferences } = require('electron') +### Using Electron Packager -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. - -## `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). - -## `electron-packager` - -If you're not using an integrated build pipeline like Forge or Builder, you +If you're not using an integrated build pipeline like Forge, 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') @@ -155,11 +84,11 @@ packager({ }) ``` -The `plist` file referenced here needs the following macOS-specific entitlements +The `entitlements.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 +```xml title="entitlements.plist" @@ -175,11 +104,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. -## Mac App Store +### Signing Mac App Store applications See the [Mac App Store Guide]. -# Signing Windows builds +## Signing Windows builds Before signing Windows builds, you must do the following: @@ -190,31 +119,111 @@ 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, Google - is your friend πŸ˜„ +- [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! πŸ˜„ + +:::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. +::: + +### Using Electron Forge + +Electron Forge is the recommended way to sign your `Squirrel.Windows` and `WiX MSI` installers. Detailed instructions on how to configure your application can be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-macos). + +### 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]. -There are a number of tools for signing your packaged app: +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. -* [`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 +```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). -## Windows Store +### Signing Windows Store applications 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 -[Xcode]: https://developer.apple.com/xcode +[`electron-wix-msi`]: https://github.com/felixrieseberg/electron-wix-msi +[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 +[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 diff --git a/docs/tutorial/devices.md b/docs/tutorial/devices.md index c5a81fc994f90..6f11fec760208 100644 --- a/docs/tutorial/devices.md +++ b/docs/tutorial/devices.md @@ -16,6 +16,10 @@ with bluetooth devices. In order to use this API in Electron, developers will need to handle the [`select-bluetooth-device` event on the webContents](../api/web-contents.md#event-select-bluetooth-device) associated with the device request. +Additionally, [`ses.setBluetoothPairingHandler(handler)`](../api/session.md#sessetbluetoothpairinghandlerhandler-windows-linux) +can be used to handle pairing to bluetooth devices on Windows or Linux when +additional validation such as a pin is needed. + ### Example This example demonstrates an Electron application that automatically selects @@ -36,12 +40,14 @@ the WebHID API: can be used to select a HID device when a call to `navigator.hid.requestDevice` is made. Additionally the [`hid-device-added`](../api/session.md#event-hid-device-added) and [`hid-device-removed`](../api/session.md#event-hid-device-removed) events - on the Session can be used to handle devices being plugged in or unplugged during the - `navigator.hid.requestDevice` process. + on the Session can be used to handle devices being plugged in or unplugged + when handling the `select-hid-device` event. + **Note:** These events only fire until the callback from `select-hid-device` + is called. They are not intended to be used as a generic hid device listener. * [`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 permision through + the default behavior of Electron is to store granted device permission 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 @@ -82,12 +88,15 @@ There are several additional APIs for working with the Web Serial API: * The [`serial-port-added`](../api/session.md#event-serial-port-added) and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events - on the Session can be used to handle devices being plugged in or unplugged during the - `navigator.serial.requestPort` process. + on the Session can be used to handle devices being plugged in or unplugged + when handling the `select-serial-port` event. + **Note:** These events only fire until the callback from `select-serial-port` + is called. They are not intended to be used as a generic serial port + listener. * [`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 permision through + the default behavior of Electron is to store granted device permission 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 diff --git a/docs/tutorial/distribution-overview.md b/docs/tutorial/distribution-overview.md new file mode 100644 index 0000000000000..1c78837c144d2 --- /dev/null +++ b/docs/tutorial/distribution-overview.md @@ -0,0 +1,54 @@ +--- +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 like Electron Forge +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. + + + +[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 diff --git a/docs/tutorial/electron-timelines.md b/docs/tutorial/electron-timelines.md index 16418ab398c51..6af3e41815f35 100644 --- a/docs/tutorial/electron-timelines.md +++ b/docs/tutorial/electron-timelines.md @@ -1,30 +1,102 @@ -# Electron Release Timelines +# Electron Releases -Special notes: +Electron frequently releases major versions alongside every other Chromium release. +This document focuses on the release cadence and version support policy. +For a more in-depth guide on our git branches and how Electron uses semantic versions, +check out our [Electron Versioning](./electron-versioning.md) doc. -* The `-beta.1` and `stable` dates are our solid release dates. -* We strive for weekly beta releases, however we often release more betas than scheduled. +## Timeline + +| Electron | Alpha | Beta | Stable | Chrome | Node | Supported | +| ------- | ----- | ------- | ------ | ------ | ---- | ---- | +| 2.0.0 | -- | 2018-Feb-21 | 2018-May-01 | M61 | v8.9 | 🚫 | +| 3.0.0 | -- | 2018-Jun-21 | 2018-Sep-18 | M66 | v10.2 | 🚫 | +| 4.0.0 | -- | 2018-Oct-11 | 2018-Dec-20 | M69 | v10.11 | 🚫 | +| 5.0.0 | -- | 2019-Jan-22 | 2019-Apr-24 | M73 | v12.0 | 🚫 | +| 6.0.0 | -- | 2019-May-01 | 2019-Jul-30 | M76 | v12.4 | 🚫 | +| 7.0.0 | -- | 2019-Aug-01 | 2019-Oct-22 | M78 | v12.8 | 🚫 | +| 8.0.0 | -- | 2019-Oct-24 | 2020-Feb-04 | M80 | v12.13 | 🚫 | +| 9.0.0 | -- | 2020-Feb-06 | 2020-May-19 | M83 | v12.14 | 🚫 | +| 10.0.0 | -- | 2020-May-21 | 2020-Aug-25 | M85 | v12.16 | 🚫 | +| 11.0.0 | -- | 2020-Aug-27 | 2020-Nov-17 | M87 | v12.18 | 🚫 | +| 12.0.0 | -- | 2020-Nov-19 | 2021-Mar-02 | M89 | v14.16 | 🚫 | +| 13.0.0 | -- | 2021-Mar-04 | 2021-May-25 | M91 | v14.16 | 🚫 | +| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | 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 | 🚫 | +| 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 | βœ… | + +**Notes:** + +* The `-alpha.1`, `-beta.1`, and `stable` dates are our solid release dates. +* We strive for weekly alpha/beta releases, but we often release more than scheduled. * All dates are our goals but there may be reasons for adjusting the stable deadline, such as security bugs. -* Take a look at the [5.0.0 Timeline blog post](https://electronjs.org/blog/electron-5-0-timeline) for info about publicizing our release dates. -* Since Electron 6.0, we've been targeting every other Chromium version and releasing our stable on the same day as Chrome stable. You can reference Chromium's release schedule [here](https://chromiumdash.appspot.com/schedule). See [Electron's new release cadence blog post](https://www.electronjs.org/blog/12-week-cadence) for more details on our release schedule. -* Starting in Electron 16.0, we will release on an 8-week cadence. See [Electron's new 8-week cadence blog post](https://www.electronjs.org/blog/8-week-cadence) for more details. - -| Electron | Alpha | Beta | Stable | Chrome | Node | -| ------- | ----- | ------- | ------ | ------ | ---- | -| 2.0.0 | -- | 2018-Feb-21 | 2018-May-01 | M61 | v8.9 | -| 3.0.0 | -- | 2018-Jun-21 | 2018-Sep-18 | M66 | v10.2 | -| 4.0.0 | -- | 2018-Oct-11 | 2018-Dec-20 | M69 | v10.11 | -| 5.0.0 | -- | 2019-Jan-22 | 2019-Apr-24 | M73 | v12.0 | -| 6.0.0 | -- | 2019-May-01 | 2019-Jul-30 | M76 | v12.4 | -| 7.0.0 | -- | 2019-Aug-01 | 2019-Oct-22 | M78 | v12.8 | -| 8.0.0 | -- | 2019-Oct-24 | 2020-Feb-04 | M80 | v12.13 | -| 9.0.0 | -- | 2020-Feb-06 | 2020-May-19 | M83 | v12.14 | -| 10.0.0 | -- | 2020-May-21 | 2020-Aug-25 | M85 | v12.16 | -| 11.0.0 | -- | 2020-Aug-27 | 2020-Nov-17 | M87 | v12.18 | -| 12.0.0 | -- | 2020-Nov-19 | 2021-Mar-02 | M89 | v14.16 | -| 13.0.0 | -- | 2021-Mar-04 | 2021-May-25 | M91 | v14.16 | -| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | 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 | -| 18.0.0 | 2022-Feb-03 | 2022-Mar-03 | 2022-Mar-29 | M100 | TBD | + +**Historical changes:** + +* Since Electron 5, Electron has been publicizing its release dates ([see blog post](https://electronjs.org/blog/electron-5-0-timeline)). +* Since Electron 6, Electron major versions have been targeting every other Chromium major version. Each Electron stable should happen on the same day as Chrome stable ([see blog post](https://www.electronjs.org/blog/12-week-cadence)). +* Since Electron 16, Electron has been releasing major versions on an 8-week cadence in accordance to Chrome's change to a 4-week release cadence ([see blog post](https://www.electronjs.org/blog/8-week-cadence)). + +:::info Chrome release dates + +Chromium has the own public release schedule [here](https://chromiumdash.appspot.com/schedule). + +::: + +## Version support policy + +:::info + +Beginning in September 2021 (Electron 15), the Electron team +will temporarily support the latest **four** stable major versions. This +extended support is intended to help Electron developers transition to +the [new 8-week release cadence](https://electronjs.org/blog/8-week-cadence), +and will continue until the release of Electron 19. At that time, +the Electron team will drop support back to the latest three stable major versions. + +::: + +The latest three *stable* major versions are supported by the Electron team. +For example, if the latest release is 6.1.x, then the 5.0.x as well +as the 4.2.x series are supported. We only support the latest minor release +for each stable release series. This means that in the case of a security fix, +6.1.x will receive the fix, but we will not release a new version of 6.0.x. + +The latest stable release unilaterally receives all fixes from `main`, +and the version prior to that receives the vast majority of those fixes +as time and bandwidth warrants. The oldest supported release line will receive +only security fixes directly. + +### Breaking API changes + +When an API is changed or removed in a way that breaks existing functionality, the +previous functionality will be supported for a minimum of two major versions when +possible before being removed. For example, if a function takes three arguments, +and that number is reduced to two in major version 10, the three-argument version would +continue to work until, at minimum, major version 12. Past the minimum two-version +threshold, we will attempt to support backwards compatibility beyond two versions +until the maintainers feel the maintenance burden is too high to continue doing so. + +### End-of-life + +When a release branch reaches the end of its support cycle, the series +will be deprecated in NPM and a final end-of-support release will be +made. This release will add a warning to inform that an unsupported +version of Electron is in use. + +These steps are to help app developers learn when a branch they're +using becomes unsupported, but without being excessively intrusive +to end users. + +If an application has exceptional circumstances and needs to stay +on an unsupported series of Electron, developers can silence the +end-of-support warning by omitting the final release from the app's +`package.json` `devDependencies`. For example, since the 1-6-x series +ended with an end-of-support 1.6.18 release, developers could choose +to stay in the 1-6-x series without warnings with `devDependency` of +`"electron": 1.6.0 - 1.6.17`. diff --git a/docs/tutorial/electron-versioning.md b/docs/tutorial/electron-versioning.md index f450feeb1968d..0948a557df83e 100644 --- a/docs/tutorial/electron-versioning.md +++ b/docs/tutorial/electron-versioning.md @@ -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 the [SemVer](#semver) spec +1. Strict use of 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 @@ -48,7 +48,7 @@ Stabilization branches are branches that run parallel to `main`, taking in only Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`. -We allow for multiple stabilization branches to exist simultaneously, one for each supported version. For more details on which versions are supported, see our [Electron Release Timelines](./electron-timelines.md) doc. +We allow for multiple stabilization branches to exist simultaneously, one for each supported version. For more details on which versions are supported, see our [Electron Releases](./electron-timelines.md) doc. ![Multiple Stability Branches](../images/versioning-sketch-2.png) @@ -107,6 +107,15 @@ A few examples of how various SemVer ranges will pick up new releases: ![Semvers and Releases](../images/versioning-sketch-7.png) +### Backport request process + +All supported release lines will accept external pull requests to backport +fixes previously merged to `main`, though this may be on a case-by-case +basis for some older supported lines. All contested decisions around release +line backports will be resolved by the +[Releases Working Group](https://github.com/electron/governance/tree/main/wg-releases) +as an agenda item at their weekly meeting the week the backport PR is raised. + ## Feature flags Feature flags are a common practice in Chromium, and are well-established in the web-development ecosystem. In the context of Electron, a feature flag or **soft branch** must have the following properties: diff --git a/docs/tutorial/examples.md b/docs/tutorial/examples.md new file mode 100644 index 0000000000000..b88bbc028b221 --- /dev/null +++ b/docs/tutorial/examples.md @@ -0,0 +1,56 @@ +--- +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 | 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. | + + + +## 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 diff --git a/docs/tutorial/forge-overview.md b/docs/tutorial/forge-overview.md new file mode 100644 index 0000000000000..e297e700c4fdc --- /dev/null +++ b/docs/tutorial/forge-overview.md @@ -0,0 +1,36 @@ +# Distributing Apps With Electron Forge + +Electron Forge is a tool for packaging and publishing Electron applications. +It unifies Electron's build tooling ecosystem into +a single extensible interface so that anyone can jump right into making Electron apps. + +## Getting started + +The [Electron Forge docs] contain detailed information on taking your application +from source code to your end users' machines. +This includes: + +* Packaging your application [(package)] +* Generating executables and installers for each OS [(make)], and, +* Publishing these files to online platforms to download [(publish)]. + +For beginners, we recommend following through Electron's [tutorial] to develop, build, +package and publish your first Electron app. If you have already developed an app on your machine +and want to start on packaging and distribution, start from [step 5] of the tutorial. + +## Getting help + +* 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 Forge, please check the [GitHub 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. + +[Electron Forge Docs]: https://www.electronforge.io/ +[step 5]: ./tutorial-5-packaging.md +[(package)]: https://www.electronforge.io/cli#package +[(make)]: https://www.electronforge.io/cli#make +[(publish)]: https://www.electronforge.io/cli#publish +[GitHub issue tracker]: https://github.com/electron-userland/electron-forge/issues +[discord]: https://discord.gg/APGC3k5yaH +[tutorial]: https://www.electronjs.org/docs/latest/tutorial/tutorial-prerequisites diff --git a/docs/tutorial/fuses.md b/docs/tutorial/fuses.md index 099c8d0bcd0ef..d933a841c46c5 100644 --- a/docs/tutorial/fuses.md +++ b/docs/tutorial/fuses.md @@ -8,6 +8,59 @@ For a subset of Electron functionality it makes sense to disable certain feature Fuses are the solution to this problem, at a high level they are "magic bits" in the Electron binary that can be flipped when packaging your Electron app to enable / disable certain features / restrictions. Because they are flipped at package time before you code sign your app the OS becomes responsible for ensuring those bits aren't flipped back via OS level code signing validation (Gatekeeper / App Locker). +## Current Fuses + +### `runAsNode` + +**Default:** Enabled +**@electron/fuses:** `FuseV1Options.RunAsNode` + +The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function. + +### `cookieEncryption` + +**Default:** Disabled +**@electron/fuses:** `FuseV1Options.EnableCookieEncryption` + +The cookieEncryption fuse toggles whether the cookie store on disk is encrypted using OS level cryptography keys. By default the sqlite database that Chromium uses to store cookies stores the values in plaintext. If you wish to ensure your apps cookies are encrypted in the same way Chrome does then you should enable this fuse. Please note it is a one-way transition, if you enable this fuse existing unencrypted cookies will be encrypted-on-write but if you then disable the fuse again your cookie store will effectively be corrupt and useless. Most apps can safely enable this fuse. + +### `nodeOptions` + +**Default:** Enabled +**@electron/fuses:** `FuseV1Options.EnableNodeOptionsEnvironmentVariable` + +The nodeOptions fuse toggles whether the [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#node_optionsoptions) environment variable is respected or not. This environment variable can be used to pass all kinds of custom options to the Node.js runtime and isn't typically used by apps in production. Most apps can safely disable this fuse. + +### `nodeCliInspect` + +**Default:** Enabled +**@electron/fuses:** `FuseV1Options.EnableNodeCliInspectArguments` + +The nodeCliInspect fuse toggles whether the `--inspect`, `--inspect-brk`, etc. flags are respected or not. When disabled it also ensures that `SIGUSR1` signal does not initialize the main process inspector. Most apps can safely disable this fuse. + +### `embeddedAsarIntegrityValidation` + +**Default:** Disabled +**@electron/fuses:** `FuseV1Options.EnableEmbeddedAsarIntegrityValidation` + +The embeddedAsarIntegrityValidation fuse toggles an experimental feature on macOS that validates the content of the `app.asar` file when it is loaded. This feature is designed to have a minimal performance impact but may marginally slow down file reads from inside the `app.asar` archive. + +For more information on how to use asar integrity validation please read the [Asar Integrity](asar-integrity.md) documentation. + +### `onlyLoadAppFromAsar` + +**Default:** Disabled +**@electron/fuses:** `FuseV1Options.OnlyLoadAppFromAsar` + +The onlyLoadAppFromAsar fuse changes the search system that Electron uses to locate your app code. By default Electron will search in the following order `app.asar` -> `app` -> `default_app.asar`. When this fuse is enabled the search order becomes a single entry `app.asar` thus ensuring that when combined with the `embeddedAsarIntegrityValidation` fuse it is impossible to load non-validated code. + +### `loadBrowserProcessSpecificV8Snapshot` + +**Default:** Disabled +**@electron/fuses:** `FuseV1Options.LoadBrowserProcessSpecificV8Snapshot` + +The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is used for the browser process. By default Electron's processes will all use the same V8 snapshot file. When this fuse is enabled the browser process uses the file called `browser_v8_context_snapshot.bin` for its V8 snapshot. The other processes will use the V8 snapshot file that they normally do. + ## How do I flip the fuses? ### The easy way @@ -20,11 +73,18 @@ require('@electron/fuses').flipFuses( require('electron'), // Fuses to flip { - runAsNode: false + version: FuseVersion.V1, + [FuseV1Options.RunAsNode]: false } ) ``` +You can validate the fuses have been flipped or check the fuse status of an arbitrary Electron app using the fuses CLI. + +```bash + npx @electron/fuses read --app /Applications/Foo.app +``` + ### The hard way #### Quick Glossary diff --git a/docs/tutorial/in-app-purchases.md b/docs/tutorial/in-app-purchases.md index ced192ba296cc..d913df54827a2 100644 --- a/docs/tutorial/in-app-purchases.md +++ b/docs/tutorial/in-app-purchases.md @@ -116,7 +116,7 @@ inAppPurchase.getProducts(PRODUCT_IDS).then(products => { console.log(`The price of ${product.localizedTitle} is ${product.formattedPrice}.`) }) - // Ask the user which product he/she wants to purchase. + // Ask the user which product they want to purchase. const selectedProduct = products[0] const selectedQuantity = 1 diff --git a/docs/tutorial/introduction.md b/docs/tutorial/introduction.md index fe26df6498f8f..581435524079c 100644 --- a/docs/tutorial/introduction.md +++ b/docs/tutorial/introduction.md @@ -1,10 +1,11 @@ -# Introduction +--- +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 +--- -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? +# 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 @@ -12,20 +13,12 @@ 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. -## Prerequisites - -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] +## Getting started -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. +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. ## Running examples with Electron Fiddle @@ -39,21 +32,45 @@ 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. + + +[tutorial]: tutorial-1-prerequisites.md +[api documentation]: ../api/app.md [chromium]: https://www.chromium.org/ -[node]: https://nodejs.org/ -[mdn-guide]: https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web -[node-guide]: https://nodejs.dev/learn -[comic]: https://www.google.com/googlebooks/chrome/ +[discord]: https://discord.gg/electronjs +[examples]: examples.md [fiddle]: https://electronjs.org/fiddle [issue-tracker]: https://github.com/electron/electron/issues -[discord]: https://discord.gg/electronjs +[node]: https://nodejs.org/ diff --git a/docs/tutorial/message-ports.md b/docs/tutorial/message-ports.md index 9f1e9bf467aff..583ced73c438e 100644 --- a/docs/tutorial/message-ports.md +++ b/docs/tutorial/message-ports.md @@ -8,8 +8,7 @@ your app. Here is a very brief example of what a MessagePort is and how it works: -```js -// renderer.js /////////////////////////////////////////////////////////////// +```js title='renderer.js (Renderer Process)' // MessagePorts are created in pairs. A connected pair of message ports is // called a channel. const channel = new MessageChannel() @@ -28,8 +27,7 @@ port2.postMessage({ answer: 42 }) ipcRenderer.postMessage('port', null, [port1]) ``` -```js -// main.js /////////////////////////////////////////////////////////////////// +```js title='main.js (Main Process)' // In the main process, we receive the port. ipcMain.on('port', (event) => { // When we receive a MessagePort in the main process, it becomes a @@ -84,14 +82,84 @@ 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 = new 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.electronMessagePort 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 -// main.js /////////////////////////////////////////////////////////////////// +```js title='main.js (Main Process)' const { BrowserWindow, app, ipcMain, MessageChannelMain } = require('electron') app.whenReady().then(async () => { @@ -129,8 +197,7 @@ app.whenReady().then(async () => { }) ``` -```html - +```html title='worker.html' ``` -```html - +```html title='app.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. + + + +[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 + + + +[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 diff --git a/docs/tutorial/tutorial-4-adding-features.md b/docs/tutorial/tutorial-4-adding-features.md new file mode 100644 index 0000000000000..b5fd630ed6e3c --- /dev/null +++ b/docs/tutorial/tutorial-4-adding-features.md @@ -0,0 +1,77 @@ +--- +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. + + + +[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 + + + +[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 diff --git a/docs/tutorial/tutorial-5-packaging.md b/docs/tutorial/tutorial-5-packaging.md new file mode 100644 index 0000000000000..032511145e746 --- /dev/null +++ b/docs/tutorial/tutorial-5-packaging.md @@ -0,0 +1,232 @@ +--- +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. + +::: + +:::tip Creating and Adding Application Icons + +Setting custom application icons requires a few additions to your config. Check out [Forge's icon tutorial] for more information. + +::: + +:::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. + + + + +```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" + } + } + //... + } + } + //... +} +``` + + + + +```json title='package.json' {6-14} +{ + //... + "config": { + "forge": { + //... + "makers": [ + { + "name": "@electron-forge/maker-squirrel", + "config": { + "certificateFile": "./cert.pfx", + "certificatePassword": "this-is-a-secret" + } + } + ] + //... + } + } + //... +} +``` + + + + +## 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 +[Forge's icon tutorial]: https://www.electronforge.io/guides/create-and-add-icons + + + +[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 diff --git a/docs/tutorial/tutorial-6-publishing-updating.md b/docs/tutorial/tutorial-6-publishing-updating.md new file mode 100644 index 0000000000000..dc0fdc31f24a1 --- /dev/null +++ b/docs/tutorial/tutorial-6-publishing-updating.md @@ -0,0 +1,251 @@ +--- +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 + + + +[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 diff --git a/docs/tutorial/updates.md b/docs/tutorial/updates.md index 83174b3e4b747..530d9658d496d 100644 --- a/docs/tutorial/updates.md +++ b/docs/tutorial/updates.md @@ -1,11 +1,16 @@ -# Updating Applications - -There are several ways to update an Electron application. The easiest and -officially supported one is taking advantage of the built-in +--- +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 +--- + +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 [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 @@ -13,72 +18,77 @@ 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 -- Builds are code-signed +- Builds are published to [GitHub Releases][gh-releases] +- Builds are [code-signed](./code-signing.md) 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: +Install the module using your Node.js package manager of choice: -```sh +```sh npm2yarn npm install update-electron-app ``` -Invoke the updater from your app's main process file: +Then, invoke the updater from your app's main process file: -```js +```js title="main.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]. -## Deploying an Update Server +## Using other update services 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! -```javascript +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' const { app, autoUpdater, dialog } = require('electron') ``` -Next, construct the URL of the update server and tell +Next, construct the URL of the update server feed and tell [autoUpdater](../api/auto-updater.md) about it: -```javascript +```javascript title='main.js' const server = 'https://your-deployment-url.com' const url = `${server}/update/${process.platform}/${app.getVersion()}` @@ -87,32 +97,32 @@ autoUpdater.setFeedURL({ url }) As the final step, check for updates. The example below will check every minute: -```javascript +```javascript title='main.js' setInterval(() => { autoUpdater.checkForUpdates() }, 60000) ``` -Once your application is [packaged](../tutorial/application-distribution.md), +Once your application is [packaged](./application-distribution.md), it will receive an update for each new [GitHub Release](https://help.github.com/articles/creating-releases/) that you publish. -## Applying Updates +### Step 3: Notifying users when updates are available 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 +```javascript title="main.js" 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) => { @@ -125,16 +135,22 @@ Also make sure that errors are [being handled](../api/auto-updater.md#event-error). Here's an example for logging them to `stderr`: -```javascript -autoUpdater.on('error', message => { +```javascript title="main.js" +autoUpdater.on('error', (message) => { console.error('There was a problem updating the application') console.error(message) }) ``` -## Handling Updates Manually +:::info 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 diff --git a/docs/tutorial/window-customization.md b/docs/tutorial/window-customization.md index 7a3a98616770b..49721f35efb67 100644 --- a/docs/tutorial/window-customization.md +++ b/docs/tutorial/window-customization.md @@ -115,9 +115,9 @@ const win = new BrowserWindow({ }) ``` -On Windows, you can also specify the color of the overlay and its symbols by setting -`titleBarOverlay` to an object with the `color` and `symbolColor` properties. If an option -is not specified, the color will default to its system color for the window control buttons: +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. + +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: ```javascript title='main.js' // on Windows @@ -126,7 +126,8 @@ const win = new BrowserWindow({ titleBarStyle: 'hidden', titleBarOverlay: { color: '#2f3241', - symbolColor: '#74b1be' + symbolColor: '#74b1be', + height: 60 } }) ``` @@ -135,6 +136,10 @@ const win = new BrowserWindow({ > color and dimension values from a renderer using a set of readonly > [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. +### Limitations + +* Transparent colors are currently not supported. Progress updates for this feature can be found in PR [#33567](https://github.com/electron/electron/issues/33567). + ## Create transparent windows By setting the `transparent` option to `true`, you can make a fully transparent window. diff --git a/docs/tutorial/windows-taskbar.md b/docs/tutorial/windows-taskbar.md index 444c712b3607b..92f4498b154f8 100644 --- a/docs/tutorial/windows-taskbar.md +++ b/docs/tutorial/windows-taskbar.md @@ -41,10 +41,9 @@ as quoted from [MSDN][msdn-jumplist]: > confuse the user who does not expect that portion of the destination list to > change. -![IE](https://i-msdn.sec.s-msft.com/dynimg/IC420539.png) +![Taskbar JumpList](../images/windows-taskbar-jumplist.png) -> NOTE: The screenshot above is an example of general tasks of -Internet Explorer +> NOTE: The screenshot above is an example of general tasks for Microsoft Edge 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 @@ -109,7 +108,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. -![player](https://i-msdn.sec.s-msft.com/dynimg/IC420540.png) +![Thumbnail toolbar](../images/windows-taskbar-thumbnail-toolbar.png) > NOTE: The screenshot above is an example of thumbnail toolbar of Windows Media Player @@ -176,7 +175,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](https://i-msdn.sec.s-msft.com/dynimg/IC420441.png) +![Overlay on taskbar button](../images/windows-taskbar-icon-overlay.png) > NOTE: The screenshot above is an example of overlay on a taskbar button diff --git a/electron_paks.gni b/electron_paks.gni index f87b78714f6d4..107feff5a86d5 100644 --- a/electron_paks.gni +++ b/electron_paks.gni @@ -19,14 +19,12 @@ template("electron_repack_percent") { # All sources should also have deps for completeness. sources = [ "$root_gen_dir/components/components_resources_${percent}_percent.pak", - "$root_gen_dir/content/app/resources/content_resources_${percent}_percent.pak", "$root_gen_dir/third_party/blink/public/resources/blink_scaled_resources_${percent}_percent.pak", "$root_gen_dir/ui/resources/ui_resources_${percent}_percent.pak", ] deps = [ "//components/resources", - "//content/app/resources", "//third_party/blink/public:scaled_resources_${percent}_percent", "//ui/resources", ] @@ -54,6 +52,8 @@ template("electron_extra_paks") { ]) output = "${invoker.output_dir}/resources.pak" sources = [ + "$root_gen_dir/chrome/browser_resources.pak", + "$root_gen_dir/chrome/common_resources.pak", "$root_gen_dir/chrome/dev_ui_browser_resources.pak", "$root_gen_dir/components/components_resources.pak", "$root_gen_dir/content/browser/resources/media/media_internals_resources.pak", @@ -65,11 +65,12 @@ template("electron_extra_paks") { "$root_gen_dir/net/net_resources.pak", "$root_gen_dir/third_party/blink/public/resources/blink_resources.pak", "$root_gen_dir/third_party/blink/public/resources/inspector_overlay_resources.pak", - "$root_gen_dir/ui/resources/webui_resources.pak", "$target_gen_dir/electron_resources.pak", ] deps = [ "//chrome/browser:dev_ui_browser_resources", + "//chrome/browser:resources", + "//chrome/common:resources", "//components/resources", "//content:content_resources", "//content:dev_ui_content_resources", @@ -173,20 +174,28 @@ template("electron_paks") { } source_patterns = [ + "${root_gen_dir}/chrome/locale_settings_", "${root_gen_dir}/chrome/platform_locale_settings_", + "${root_gen_dir}/chrome/generated_resources_", + "${root_gen_dir}/components/strings/components_locale_settings_", "${root_gen_dir}/components/strings/components_strings_", - "${root_gen_dir}/third_party/blink/public/strings/blink_accessibility_strings_", - "${root_gen_dir}/third_party/blink/public/strings/blink_strings_", "${root_gen_dir}/device/bluetooth/strings/bluetooth_strings_", + "${root_gen_dir}/extensions/strings/extensions_strings_", "${root_gen_dir}/services/strings/services_strings_", + "${root_gen_dir}/third_party/blink/public/strings/blink_accessibility_strings_", + "${root_gen_dir}/third_party/blink/public/strings/blink_strings_", "${root_gen_dir}/ui/strings/app_locale_settings_", "${root_gen_dir}/ui/strings/ax_strings_", "${root_gen_dir}/ui/strings/ui_strings_", ] deps = [ + "//chrome/app:generated_resources", + "//chrome/app/resources:locale_settings", "//chrome/app/resources:platform_locale_settings", + "//components/strings:components_locale_settings", "//components/strings:components_strings", "//device/bluetooth/strings", + "//extensions/strings", "//services/strings", "//third_party/blink/public/strings", "//third_party/blink/public/strings:accessibility_strings", @@ -199,7 +208,7 @@ template("electron_paks") { output_dir = "${invoker.output_dir}/locales" if (is_mac) { - output_locales = locales_as_mac_outputs + output_locales = locales_as_apple_outputs } else { output_locales = platform_pak_locales } diff --git a/electron_resources.grd b/electron_resources.grd index 08eb971b39249..8e492ad82347d 100644 --- a/electron_resources.grd +++ b/electron_resources.grd @@ -11,15 +11,8 @@ - - - - - - diff --git a/electron_strings.grdp b/electron_strings.grdp deleted file mode 100644 index 5068141716d7a..0000000000000 --- a/electron_strings.grdp +++ /dev/null @@ -1,160 +0,0 @@ - - - - - Close - - - Minimize - - - Maximize - - - Restore - - - - - Printing Service - - - The selected printer is not available or not installed correctly. <br> Check your printer or try selecting another printer. - - - Untitled Document - - - - - Entire Screen - - - {SCREEN_INDEX, plural, =1{Screen #} other{Screen #}} - - - - - Image Files - - - Audio Files - - - Video Files - - - Custom Files - - - download - - - - - - Picture in Picture - - - - - Picture in picture - - - - Pause - - - Play - - - Play from the beginning - - - Back to video player - - - Mute - - - Unmute - - - Skip Ad - - - Mute microphone - - - Unmute microphone - - - Turn on camera - - - Turn off camera - - - Hang up - - - Close - - - Resize - - - Toggle video to play or pause - - - Toggle mute - - - Next track - - - Previous track - - - en-US - - - en-US,en - - - - Windows Utilities - - - - More actions - - - - $199+ - - - {MAX_UNREAD_NOTIFICATIONS, plural, =1 {More than 1 unread notification} other {More than # unread notifications}} - - - Unread Notifications - - - {UNREAD_NOTIFICATIONS, plural, =1 {1 Unread Notification} other {# Unread Notifications}} - - - Unknown Device ($11234:abcd) - - - - Unlabeled graphic - - - - - Unlabeled image - - - - diff --git a/filenames.auto.gni b/filenames.auto.gni index 82a36d7a46360..57d9f4d1384ee 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -40,6 +40,7 @@ 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", @@ -141,6 +142,7 @@ auto_filenames = { "lib/common/define-properties.ts", "lib/common/ipc-messages.ts", "lib/common/web-view-methods.ts", + "lib/common/webpack-globals-provider.ts", "lib/renderer/api/context-bridge.ts", "lib/renderer/api/crash-reporter.ts", "lib/renderer/api/ipc-renderer.ts", @@ -212,6 +214,7 @@ 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", diff --git a/filenames.gni b/filenames.gni index f7c6ce5dff438..9fda05b41f983 100644 --- a/filenames.gni +++ b/filenames.gni @@ -23,6 +23,7 @@ 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", @@ -85,6 +86,8 @@ 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", @@ -105,6 +108,8 @@ filenames = { "shell/browser/ui/win/notify_icon.h", "shell/browser/ui/win/taskbar_host.cc", "shell/browser/ui/win/taskbar_host.h", + "shell/browser/win/dark_mode.cc", + "shell/browser/win/dark_mode.h", "shell/browser/win/scoped_hstring.cc", "shell/browser/win/scoped_hstring.h", "shell/common/api/electron_api_native_image_win.cc", @@ -124,6 +129,7 @@ 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", @@ -165,6 +171,8 @@ 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", @@ -289,6 +297,8 @@ 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", @@ -406,8 +416,6 @@ 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", @@ -566,6 +574,7 @@ filenames = { "shell/common/gin_converters/gfx_converter.h", "shell/common/gin_converters/guid_converter.h", "shell/common/gin_converters/gurl_converter.h", + "shell/common/gin_converters/hid_device_info_converter.h", "shell/common/gin_converters/image_converter.cc", "shell/common/gin_converters/image_converter.h", "shell/common/gin_converters/message_box_converter.cc", @@ -638,8 +647,6 @@ 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", diff --git a/filenames.hunspell.gni b/filenames.hunspell.gni index 0c91ae1db77c2..64574354e4244 100644 --- a/filenames.hunspell.gni +++ b/filenames.hunspell.gni @@ -7,11 +7,16 @@ hunspell_dictionaries = [ "//third_party/hunspell_dictionaries/da-DK-3-0.bdic", "//third_party/hunspell_dictionaries/de-DE-3-0.bdic", "//third_party/hunspell_dictionaries/el-GR-3-0.bdic", - "//third_party/hunspell_dictionaries/en-AU-9-0.bdic", - "//third_party/hunspell_dictionaries/en-CA-9-0.bdic", - "//third_party/hunspell_dictionaries/en-GB-9-0.bdic", - "//third_party/hunspell_dictionaries/en-GB-oxendict-9-0.bdic", - "//third_party/hunspell_dictionaries/en-US-9-0.bdic", + "//third_party/hunspell_dictionaries/en-AU-10-0.bdic", + "//third_party/hunspell_dictionaries/en-AU-10-1.bdic", + "//third_party/hunspell_dictionaries/en-CA-10-0.bdic", + "//third_party/hunspell_dictionaries/en-CA-10-1.bdic", + "//third_party/hunspell_dictionaries/en-GB-10-0.bdic", + "//third_party/hunspell_dictionaries/en-GB-10-1.bdic", + "//third_party/hunspell_dictionaries/en-GB-oxendict-10-0.bdic", + "//third_party/hunspell_dictionaries/en-GB-oxendict-10-1.bdic", + "//third_party/hunspell_dictionaries/en-US-10-0.bdic", + "//third_party/hunspell_dictionaries/en-US-10-1.bdic", "//third_party/hunspell_dictionaries/es-ES-3-0.bdic", "//third_party/hunspell_dictionaries/et-EE-3-0.bdic", "//third_party/hunspell_dictionaries/fa-IR-9-0.bdic", @@ -46,6 +51,7 @@ hunspell_dictionaries = [ "//third_party/hunspell_dictionaries/tg-TG-5-0.bdic", "//third_party/hunspell_dictionaries/tr-TR-4-0.bdic", "//third_party/hunspell_dictionaries/uk-UA-4-0.bdic", + "//third_party/hunspell_dictionaries/uk-UA-5-0.bdic", "//third_party/hunspell_dictionaries/vi-VN-3-0.bdic", "//third_party/hunspell_dictionaries/xx-XX-3-0.bdic", ] diff --git a/filenames.libcxx.gni b/filenames.libcxx.gni index b14a775f99962..e2f5c15d90e64 100644 --- a/filenames.libcxx.gni +++ b/filenames.libcxx.gni @@ -1,64 +1,503 @@ 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/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_clamp.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_permutation.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_next_permutation.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_prev_permutation.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.h", + "//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_rotate_copy.h", + "//buildtools/third_party/libc++/trunk/include/__algorithm/ranges_sample.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/uniform_random_bit_generator_adaptor.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/__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/__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/hash.h", + "//buildtools/third_party/libc++/trunk/include/__fwd/pair.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/__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/__libcpp_version", + "//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/__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/__nullptr", + "//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/__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/view.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/__split_buffer", "//buildtools/third_party/libc++/trunk/include/__std_stream", - "//buildtools/third_party/libc++/trunk/include/__string", + "//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/__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", @@ -68,11 +507,157 @@ 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/can_extract_key.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/dependent_type.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_char_like_type.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_implicitly_default_constructible.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_swappable.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_const_lvalue_ref.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/maybe_const.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_const_ref.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/result_of.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/convert_to_integral.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/__verbose_abort", "//buildtools/third_party/libc++/trunk/include/algorithm", "//buildtools/third_party/libc++/trunk/include/any", "//buildtools/third_party/libc++/trunk/include/array", @@ -99,6 +684,7 @@ 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", @@ -111,6 +697,7 @@ 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", @@ -122,7 +709,6 @@ 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", @@ -167,7 +753,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", + "//buildtools/third_party/libc++/trunk/include/module.modulemap.in", "//buildtools/third_party/libc++/trunk/include/mutex", "//buildtools/third_party/libc++/trunk/include/new", "//buildtools/third_party/libc++/trunk/include/numbers", @@ -187,6 +773,7 @@ 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", @@ -205,6 +792,7 @@ 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", diff --git a/filenames.libcxxabi.gni b/filenames.libcxxabi.gni index 813f95070a2fa..69bb490ccd89a 100644 --- a/filenames.libcxxabi.gni +++ b/filenames.libcxxabi.gni @@ -1,4 +1,5 @@ libcxxabi_headers = [ + "//buildtools/third_party/libc++abi/trunk/include/CMakeLists.txt", "//buildtools/third_party/libc++abi/trunk/include/__cxxabi_config.h", "//buildtools/third_party/libc++abi/trunk/include/cxxabi.h", ] diff --git a/lib/browser/.eslintrc.json b/lib/browser/.eslintrc.json index 27d223a509d96..dab1dafc3f26e 100644 --- a/lib/browser/.eslintrc.json +++ b/lib/browser/.eslintrc.json @@ -18,4 +18,4 @@ } ] } -} \ No newline at end of file +} diff --git a/lib/browser/api/app.ts b/lib/browser/api/app.ts index f952dcd0194b3..346b48c9fc4ba 100644 --- a/lib/browser/api/app.ts +++ b/lib/browser/api/app.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; -import { Menu } from 'electron/main'; +import { Menu, deprecate } from 'electron/main'; const bindings = process._linkedBinding('electron_browser_app'); const commandLine = process._linkedBinding('electron_common_command_line'); @@ -111,3 +111,7 @@ for (const name of events) { webContents.emit(name, event, ...args); }); } + +// Deprecation. +deprecate.event(app, 'gpu-process-crashed', 'child-process-gone'); +deprecate.event(app, 'renderer-process-crashed', 'render-process-gone'); diff --git a/lib/browser/api/auto-updater/squirrel-update-win.ts b/lib/browser/api/auto-updater/squirrel-update-win.ts index 82d867f4f8fc6..5d8a998b4e1c5 100644 --- a/lib/browser/api/auto-updater/squirrel-update-win.ts +++ b/lib/browser/api/auto-updater/squirrel-update-win.ts @@ -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 alread running process + // Process spawned, same args: Attach events to already running process // Process spawned, different args: Return with error // No process spawned: Spawn new process if (spawnedProcess && !isSameArgs(args)) { diff --git a/lib/browser/api/browser-window.ts b/lib/browser/api/browser-window.ts index d20ea0bda5571..053e09ab63690 100644 --- a/lib/browser/api/browser-window.ts +++ b/lib/browser/api/browser-window.ts @@ -72,9 +72,8 @@ BrowserWindow.getAllWindows = () => { BrowserWindow.getFocusedWindow = () => { for (const window of BrowserWindow.getAllWindows()) { - const hasWC = window.webContents && !window.webContents.isDestroyed(); - if (!window.isDestroyed() && hasWC) { - if (window.isFocused() || window.isDevToolsFocused()) return window; + if (!window.isDestroyed() && window.webContents && !window.webContents.isDestroyed()) { + if (window.isFocused() || window.webContents.isDevToolsFocused()) return window; } } return null; diff --git a/lib/browser/api/ipc-main.ts b/lib/browser/api/ipc-main.ts index 20c7fb9dc5cf6..40aa4efd90aeb 100644 --- a/lib/browser/api/ipc-main.ts +++ b/lib/browser/api/ipc-main.ts @@ -2,7 +2,4 @@ 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; diff --git a/lib/browser/api/menu.ts b/lib/browser/api/menu.ts index cdd3b73452f33..1499ce7e42d7f 100644 --- a/lib/browser/api/menu.ts +++ b/lib/browser/api/menu.ts @@ -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 accessable to items. + // Make menu accessible to items. item.overrideReadOnlyProperty('menu', this); // Remember the items. diff --git a/lib/browser/api/module-list.ts b/lib/browser/api/module-list.ts index b9e3340cd2955..be516aec2885a 100644 --- a/lib/browser/api/module-list.ts +++ b/lib/browser/api/module-list.ts @@ -22,6 +22,7 @@ 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') }, diff --git a/lib/browser/api/native-theme.ts b/lib/browser/api/native-theme.ts index 08fd92b209dc5..593fc9d815a3f 100644 --- a/lib/browser/api/native-theme.ts +++ b/lib/browser/api/native-theme.ts @@ -1,3 +1,3 @@ -const { nativeTheme } = process._linkedBinding('electron_common_native_theme'); +const { nativeTheme } = process._linkedBinding('electron_browser_native_theme'); module.exports = nativeTheme; diff --git a/lib/browser/api/net.ts b/lib/browser/api/net.ts index 454505ede04f2..6438eb0230c16 100644 --- a/lib/browser/api/net.ts +++ b/lib/browser/api/net.ts @@ -36,17 +36,14 @@ const discardableDuplicateHeaders = new Set([ ]); class IncomingMessage extends Readable { - _shouldPush: boolean; - _data: (Buffer | null)[]; + _shouldPush: boolean = false; + _data: (Buffer | null)[] = []; _responseHead: NodeJS.ResponseHead; - _resume: (() => void) | null; + _resume: (() => void) | null = null; constructor (responseHead: NodeJS.ResponseHead) { super(); - this._shouldPush = false; - this._data = []; this._responseHead = responseHead; - this._resume = null; } get statusCode () { @@ -198,7 +195,7 @@ class ChunkedBodyStream extends Writable { this._downstream = pipe; if (this._pendingChunk) { const doneWriting = (maybeError: Error | void) => { - // If the underlying request has been aborted, we honeslty don't care about the error + // If the underlying request has been aborted, we honestly don't care about the error // all work should cease as soon as we abort anyway, this error is probably a // "mojo pipe disconnected" error (code=9) if (this._clientRequest._aborted) return; diff --git a/lib/browser/api/notification.ts b/lib/browser/api/notification.ts index 63141d438bbcc..6739267afe047 100644 --- a/lib/browser/api/notification.ts +++ b/lib/browser/api/notification.ts @@ -1,7 +1,7 @@ const { Notification: ElectronNotification, isSupported -} = process._linkedBinding('electron_common_notification'); +} = process._linkedBinding('electron_browser_notification'); ElectronNotification.isSupported = isSupported; diff --git a/lib/browser/api/push-notifications.ts b/lib/browser/api/push-notifications.ts new file mode 100644 index 0000000000000..346ae93c6b0da --- /dev/null +++ b/lib/browser/api/push-notifications.ts @@ -0,0 +1,3 @@ +const { pushNotifications } = process._linkedBinding('electron_browser_push_notifications'); + +export default pushNotifications; diff --git a/lib/browser/api/screen.ts b/lib/browser/api/screen.ts index 0c01e88c42b9b..c18e93d20d392 100644 --- a/lib/browser/api/screen.ts +++ b/lib/browser/api/screen.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'events'; -const { createScreen } = process._linkedBinding('electron_common_screen'); +const { createScreen } = process._linkedBinding('electron_browser_screen'); let _screen: Electron.Screen; diff --git a/lib/browser/api/web-contents.ts b/lib/browser/api/web-contents.ts index 99bcd4c1cb7c4..1890bdb018509 100644 --- a/lib/browser/api/web-contents.ts +++ b/lib/browser/api/web-contents.ts @@ -9,12 +9,15 @@ 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 initalized +// session is not used here, the purpose is to make sure session is initialized // 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; @@ -63,6 +66,20 @@ const PDFPageSizes: Record = { } } as const; +const paperFormats: Record = { + 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. @@ -76,42 +93,6 @@ 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'); @@ -146,13 +127,6 @@ 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', @@ -193,136 +167,136 @@ WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (worldId let pendingPromise: Promise | undefined; WebContents.prototype.printToPDF = async function (options) { const printSettings: Record = { - ...defaultPrintingSetting, - requestID: getNextId() + requestID: getNextId(), + landscape: false, + displayHeaderFooter: false, + headerTemplate: '', + footerTemplate: '', + printBackground: false, + scale: 1.0, + paperWidth: 8.5, + paperHeight: 11.0, + marginTop: 0.0, + marginBottom: 0.0, + marginLeft: 0.0, + marginRight: 0.0, + pageRanges: '', + preferCSSPageSize: false }; if (options.landscape !== undefined) { if (typeof options.landscape !== 'boolean') { - const error = new Error('landscape must be a Boolean'); - return Promise.reject(error); + return Promise.reject(new Error('landscape must be a Boolean')); } printSettings.landscape = options.landscape; } - if (options.scaleFactor !== undefined) { - if (typeof options.scaleFactor !== 'number') { - const error = new Error('scaleFactor must be a Number'); - return Promise.reject(error); + if (options.displayHeaderFooter !== undefined) { + if (typeof options.displayHeaderFooter !== 'boolean') { + return Promise.reject(new Error('displayHeaderFooter must be a Boolean')); } - printSettings.scaleFactor = options.scaleFactor; + printSettings.displayHeaderFooter = options.displayHeaderFooter; } - if (options.marginsType !== undefined) { - if (typeof options.marginsType !== 'number') { - const error = new Error('marginsType must be a Number'); - return Promise.reject(error); + if (options.printBackground !== undefined) { + if (typeof options.printBackground !== 'boolean') { + return Promise.reject(new Error('printBackground must be a Boolean')); } - printSettings.marginsType = options.marginsType; + printSettings.shouldPrintBackgrounds = options.printBackground; } - if (options.printSelectionOnly !== undefined) { - if (typeof options.printSelectionOnly !== 'boolean') { - const error = new Error('printSelectionOnly must be a Boolean'); - return Promise.reject(error); + if (options.scale !== undefined) { + if (typeof options.scale !== 'number') { + return Promise.reject(new Error('scale must be a Number')); } - printSettings.shouldPrintSelectionOnly = options.printSelectionOnly; + printSettings.scale = options.scale; } - if (options.printBackground !== undefined) { - if (typeof options.printBackground !== 'boolean') { - const error = new Error('printBackground must be a Boolean'); - return Promise.reject(error); + 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')); } - printSettings.shouldPrintBackgrounds = options.printBackground; } - if (options.pageRanges !== undefined) { - 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); + const { margins } = options; + if (margins !== undefined) { + if (typeof margins !== 'object') { + return Promise.reject(new Error('margins must be an Object')); } - if (typeof pageRanges.from !== 'number') { - const error = new Error('pageRanges.from must be a Number'); - return Promise.reject(error); + 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 (typeof pageRanges.to !== 'number') { - const error = new Error('pageRanges.to must be a Number'); - return Promise.reject(error); + if (margins.bottom !== undefined) { + if (typeof margins.bottom !== 'number') { + return Promise.reject(new Error('margins.bottom must be a Number')); + } + printSettings.marginBottom = margins.bottom; } - // Chromium uses 1-based page ranges, so increment each by 1. - printSettings.pageRange = [{ - from: pageRanges.from + 1, - to: pageRanges.to + 1 - }]; - } - - 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); + if (margins.left !== undefined) { + if (typeof margins.left !== 'number') { + return Promise.reject(new Error('margins.left must be a Number')); } - printSettings.title = headerFooter.title; + printSettings.marginLeft = margins.left; + } - if (typeof headerFooter.url !== 'string') { - const error = new Error('headerFooter.url must be a String'); - return Promise.reject(error); + if (margins.right !== undefined) { + if (typeof margins.right !== 'number') { + return Promise.reject(new Error('margins.right must be a Number')); } - printSettings.url = headerFooter.url; - } else { - const error = new Error('headerFooter must be an Object'); - return Promise.reject(error); + printSettings.marginRight = margins.right; } } - // 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); - } + if (options.pageRanges !== undefined) { + if (typeof options.pageRanges !== 'string') { + return Promise.reject(new Error('printBackground must be a String')); + } + printSettings.pageRanges = options.pageRanges; + } - // 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); - } + if (options.headerTemplate !== undefined) { + if (typeof options.headerTemplate !== 'string') { + return Promise.reject(new Error('headerTemplate must be a String')); + } + printSettings.headerTemplate = options.headerTemplate; + } - 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); + if (options.footerTemplate !== undefined) { + if (typeof options.footerTemplate !== 'string') { + return Promise.reject(new Error('footerTemplate must be a String')); } - } else { - printSettings.mediaSize = PDFPageSizes.A4; + 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; } - // 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)); @@ -492,41 +466,52 @@ WebContents.prototype.loadURL = function (url, options) { return p; }; -WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => ({action: 'allow'} | {action: 'deny', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions})) { +WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => ({action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions, outlivesOpener?: boolean})) { this._windowOpenHandler = handler; }; -WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event, details: Electron.HandlerDetails): BrowserWindowConstructorOptions | null { +WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event, details: Electron.HandlerDetails): {browserWindowConstructorOptions: BrowserWindowConstructorOptions | null, outlivesOpener: boolean} { + const defaultResponse = { + browserWindowConstructorOptions: null, + outlivesOpener: false + }; if (!this._windowOpenHandler) { - return null; + return defaultResponse; } + const response = this._windowOpenHandler(details); if (typeof response !== 'object') { event.preventDefault(); console.error(`The window open handler response must be an object, but was instead of type '${typeof response}'.`); - return null; + return defaultResponse; } if (response === null) { event.preventDefault(); console.error('The window open handler response must be an object, but was instead null.'); - return null; + return defaultResponse; } if (response.action === 'deny') { event.preventDefault(); - return null; + return defaultResponse; } else if (response.action === 'allow') { if (typeof response.overrideBrowserWindowOptions === 'object' && response.overrideBrowserWindowOptions !== null) { - return response.overrideBrowserWindowOptions; + return { + browserWindowConstructorOptions: response.overrideBrowserWindowOptions, + outlivesOpener: typeof response.outlivesOpener === 'boolean' ? response.outlivesOpener : false + }; } else { - return {}; + return { + browserWindowConstructorOptions: {}, + outlivesOpener: typeof response.outlivesOpener === 'boolean' ? response.outlivesOpener : false + }; } } else { event.preventDefault(); console.error('The window open handler response must be an object with an \'action\' property of \'allow\' or \'deny\'.'); - return null; + return defaultResponse; } }; @@ -551,6 +536,11 @@ const addReturnValueToEvent = (event: Electron.IpcMainEvent) => { }); }; +const getWebFrameForEvent = (event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent) => { + if (!event.processId || !event.frameId) return null; + return webFrameMainBinding.fromIdOrNull(event.processId, event.frameId); +}; + const commandLine = process._linkedBinding('electron_common_command_line'); const environment = process._linkedBinding('electron_common_environment'); @@ -561,7 +551,7 @@ const loggingEnabled = () => { // Add JavaScript wrappers for WebContents class. WebContents.prototype._init = function () { const prefs = this.getLastWebPreferences() || {}; - if (!prefs.nodeIntegration && (prefs.preload != null || prefs.preloadURL != null) && prefs.sandbox == null) { + if (!prefs.nodeIntegration && prefs.preload != null && prefs.sandbox == null) { deprecate.log('The default sandbox option for windows without nodeIntegration is changing. Presently, by default, when a window has a preload script, it defaults to being unsandboxed. In Electron 20, this default will be changing, and all windows that have nodeIntegration: false (which is the default) will be sandboxed by default. If your preload script doesn\'t use Node, no action is needed. If your preload script does use Node, either refactor it to move Node usage to the main process, or specify sandbox: false in your WebPreferences.'); } // Read off the ID at construction time, so that it's accessible even after @@ -574,6 +564,12 @@ 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); @@ -582,6 +578,9 @@ WebContents.prototype._init = function () { } else { addReplyToEvent(event); this.emit('ipc-message', event, channel, ...args); + const maybeWebFrame = getWebFrameForEvent(event); + maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, ...args); + ipc.emit(channel, event, ...args); ipcMain.emit(channel, event, ...args); } }); @@ -593,8 +592,10 @@ WebContents.prototype._init = function () { console.error(`Error occurred in handler for '${channel}':`, error); event.sendReply({ error: error.toString() }); }; - const target = internal ? ipcMainInternal : ipcMain; - if ((target as any)._invokeHandlers.has(channel)) { + const maybeWebFrame = getWebFrameForEvent(event); + const targets: (ElectronInternal.IpcMainInternal| null)[] = internal ? [ipcMainInternal] : [maybeWebFrame && maybeWebFrame.ipc, ipc, ipcMain]; + const target = targets.find(target => target && (target as any)._invokeHandlers.has(channel)); + if (target) { (target as any)._invokeHandlers.get(channel)(event, ...args); } else { event._throw(`No handler registered for '${channel}'`); @@ -608,10 +609,13 @@ WebContents.prototype._init = function () { ipcMainInternal.emit(channel, event, ...args); } else { addReplyToEvent(event); - if (this.listenerCount('ipc-message-sync') === 0 && ipcMain.listenerCount(channel) === 0) { + const maybeWebFrame = getWebFrameForEvent(event); + if (this.listenerCount('ipc-message-sync') === 0 && ipc.listenerCount(channel) === 0 && ipcMain.listenerCount(channel) === 0 && (!maybeWebFrame || maybeWebFrame.ipc.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); } }); @@ -619,6 +623,9 @@ 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 = getWebFrameForEvent(event); + maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, message); + ipc.emit(channel, event, message); ipcMain.emit(channel, event, message); }); @@ -656,7 +663,16 @@ WebContents.prototype._init = function () { postBody, disposition }; - const options = this._callWindowOpenHandler(event, details); + + let result: ReturnType; + try { + result = this._callWindowOpenHandler(event, details); + } catch (err) { + event.preventDefault(); + throw err; + } + + const options = result.browserWindowConstructorOptions; if (!event.defaultPrevented) { openGuestWindow({ event, @@ -665,12 +681,14 @@ WebContents.prototype._init = function () { referrer, postData, overrideBrowserWindowOptions: options || {}, - windowOpenArgs: details + windowOpenArgs: details, + outlivesOpener: result.outlivesOpener }); } }); let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null; + let windowOpenOutlivesOpenerOption: boolean = false; this.on('-will-add-new-contents' as any, (event: ElectronInternal.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => { const postBody = postData ? { data: postData, @@ -684,7 +702,17 @@ WebContents.prototype._init = function () { referrer, postBody }; - windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details); + + let result: ReturnType; + try { + result = this._callWindowOpenHandler(event, details); + } catch (err) { + event.preventDefault(); + throw err; + } + + windowOpenOutlivesOpenerOption = result.outlivesOpener; + windowOpenOverriddenOptions = result.browserWindowConstructorOptions; if (!event.defaultPrevented) { const secureOverrideWebPreferences = windowOpenOverriddenOptions ? { // Allow setting of backgroundColor as a webPreference even though @@ -715,7 +743,10 @@ WebContents.prototype._init = function () { _userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string, referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => { const overriddenOptions = windowOpenOverriddenOptions || undefined; + const outlivesOpener = windowOpenOutlivesOpenerOption; windowOpenOverriddenOptions = null; + // false is the default + windowOpenOutlivesOpenerOption = false; if ((disposition !== 'foreground-tab' && disposition !== 'new-window' && disposition !== 'background-tab')) { @@ -735,7 +766,8 @@ WebContents.prototype._init = function () { url, frameName, features: rawFeatures - } + }, + outlivesOpener }); }); } @@ -806,6 +838,10 @@ export function fromId (id: string) { return binding.fromId(id); } +export function fromFrame (frame: Electron.WebFrameMain) { + return binding.fromFrame(frame); +} + export function fromDevToolsTargetId (targetId: string) { return binding.fromDevToolsTargetId(targetId); } diff --git a/lib/browser/api/web-frame-main.ts b/lib/browser/api/web-frame-main.ts index 2f75ee615a697..95e4a2fa4d636 100644 --- a/lib/browser/api/web-frame-main.ts +++ b/lib/browser/api/web-frame-main.ts @@ -1,7 +1,16 @@ 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'); diff --git a/lib/browser/default-menu.ts b/lib/browser/default-menu.ts index b91a7caea4d92..b37e3425b3364 100644 --- a/lib/browser/default-menu.ts +++ b/lib/browser/default-menu.ts @@ -31,7 +31,7 @@ export const setDefaultApplicationMenu = () => { { label: 'Community Discussions', click: async () => { - await shell.openExternal('https://discord.com/invite/APGC3k5yaH'); + await shell.openExternal('https://discord.gg/electronjs'); } }, { diff --git a/lib/browser/guest-view-manager.ts b/lib/browser/guest-view-manager.ts index c973586e807d5..2d88a0a017ea7 100644 --- a/lib/browser/guest-view-manager.ts +++ b/lib/browser/guest-view-manager.ts @@ -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; @@ -15,6 +15,7 @@ interface GuestInstance { const webViewManager = process._linkedBinding('electron_browser_web_view_manager'); const eventBinding = process._linkedBinding('electron_browser_event'); +const netBinding = process._linkedBinding('electron_browser_net'); const supportedWebViewEvents = Object.keys(webViewEvents); @@ -45,11 +46,12 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record) { // Create a new guest instance. const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record) { + 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 }); @@ -107,11 +121,8 @@ 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 = params.instanceId; + this.viewInstanceId = instanceId; // Only load URL and set size on first attach if (previouslyAttached) { @@ -119,7 +130,7 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n } if (params.src) { - this.loadURL(params.src, params.opts); + this.loadURL(params.src, makeLoadURLOptions(params)); } embedder.emit('did-attach-webview', event, guest); }); @@ -172,78 +183,25 @@ 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) { // 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 true; + + return guestInstanceId; }; // Remove an guest-embedder relationship. diff --git a/lib/browser/guest-window-manager.ts b/lib/browser/guest-window-manager.ts index 9815865f72499..7aa91a15c9134 100644 --- a/lib/browser/guest-window-manager.ts +++ b/lib/browser/guest-window-manager.ts @@ -5,7 +5,7 @@ * out-of-process (cross-origin) are created here. "Embedder" roughly means * "parent." */ -import { BrowserWindow } from 'electron/main'; +import { BrowserWindow, deprecate } from 'electron/main'; import type { BrowserWindowConstructorOptions, Referrer, WebContents, LoadURLOptions } from 'electron/main'; import { parseFeatures } from '@electron/internal/browser/parse-features-string'; @@ -29,7 +29,7 @@ const getGuestWindowByFrameName = (name: string) => frameNamesToWindow.get(name) * user to preventDefault() on the passed event (which ends up calling * DestroyWebContents). */ -export function openGuestWindow ({ event, embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs }: { +export function openGuestWindow ({ event, embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs, outlivesOpener }: { event: { sender: WebContents, defaultPrevented: boolean }, embedder: WebContents, guest?: WebContents, @@ -38,9 +38,10 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition postData?: PostData, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions, windowOpenArgs: WindowOpenArgs, + outlivesOpener: boolean, }): BrowserWindow | undefined { const { url, frameName, features } = windowOpenArgs; - const { options: browserWindowOptions } = makeBrowserWindowOptions({ + const browserWindowOptions = makeBrowserWindowOptions({ embedder, features, overrideOptions: overrideBrowserWindowOptions @@ -77,7 +78,20 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition ...browserWindowOptions }); - handleWindowLifecycleEvents({ embedder, frameName, guest: window }); + if (!guest) { + // When we open a new window from a link (via OpenURLFromTab), + // the browser process is responsible for initiating navigation + // in the new window. + window.loadURL(url, { + httpReferrer: referrer, + ...(postData && { + postData, + extraHeaders: formatPostDataHeaders(postData as Electron.UploadRawData[]) + }) + }); + } + + handleWindowLifecycleEvents({ embedder, frameName, guest: window, outlivesOpener }); embedder.emit('did-create-window', window, { url, frameName, options: browserWindowOptions, disposition, referrer, postData }); @@ -90,10 +104,11 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition * too is the guest destroyed; this is Electron convention and isn't based in * browser behavior. */ -const handleWindowLifecycleEvents = function ({ embedder, guest, frameName }: { +const handleWindowLifecycleEvents = function ({ embedder, guest, frameName, outlivesOpener }: { embedder: WebContents, guest: BrowserWindow, - frameName: string + frameName: string, + outlivesOpener: boolean }) { const closedByEmbedder = function () { guest.removeListener('closed', closedByUser); @@ -101,9 +116,14 @@ const handleWindowLifecycleEvents = function ({ embedder, guest, frameName }: { }; const closedByUser = function () { - embedder.removeListener('current-render-view-deleted' as any, closedByEmbedder); + // Embedder might have been closed + if (!embedder.isDestroyed() && !outlivesOpener) { + embedder.removeListener('current-render-view-deleted' as any, closedByEmbedder); + } }; - embedder.once('current-render-view-deleted' as any, closedByEmbedder); + if (!outlivesOpener) { + embedder.once('current-render-view-deleted' as any, closedByEmbedder); + } guest.once('closed', closedByUser); if (frameName) { @@ -135,6 +155,10 @@ function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, ...parseContentTypeFormat(postData) } : null; + if (embedder.listenerCount('new-window') > 0) { + deprecate.log('The new-window event is deprecated and will be removed. Please use contents.setWindowOpenHandler() instead.'); + } + embedder.emit( 'new-window', event, @@ -163,7 +187,8 @@ function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, handleWindowLifecycleEvents({ embedder: event.sender, guest: newGuest, - frameName + frameName, + outlivesOpener: false }); } return true; @@ -190,23 +215,21 @@ function makeBrowserWindowOptions ({ embedder, features, overrideOptions }: { const { options: parsedOptions, webPreferences: parsedWebPreferences } = parseFeatures(features); return { - options: { - show: true, - width: 800, - height: 600, - ...parsedOptions, - ...overrideOptions, - // Note that for normal code path an existing WebContents created by - // Chromium will be used, with web preferences parsed in the - // |-will-add-new-contents| event. - // The |webPreferences| here is only used by the |new-window| event. - webPreferences: makeWebPreferences({ - embedder, - insecureParsedWebPreferences: parsedWebPreferences, - secureOverrideWebPreferences: overrideOptions && overrideOptions.webPreferences - }) - } as Electron.BrowserViewConstructorOptions - }; + show: true, + width: 800, + height: 600, + ...parsedOptions, + ...overrideOptions, + // Note that for normal code path an existing WebContents created by + // Chromium will be used, with web preferences parsed in the + // |-will-add-new-contents| event. + // The |webPreferences| here is only used by the |new-window| event. + webPreferences: makeWebPreferences({ + embedder, + insecureParsedWebPreferences: parsedWebPreferences, + secureOverrideWebPreferences: overrideOptions && overrideOptions.webPreferences + }) + } as Electron.BrowserViewConstructorOptions; } export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = {}, insecureParsedWebPreferences: parsedWebPreferences = {} }: { @@ -235,6 +258,15 @@ export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = { }; } +function formatPostDataHeaders (postData: PostData) { + if (!postData) return; + + const { contentType, boundary } = parseContentTypeFormat(postData); + if (boundary != null) { return `content-type: ${contentType}; boundary=${boundary}`; } + + return `content-type: ${contentType}`; +} + const MULTIPART_CONTENT_TYPE = 'multipart/form-data'; const URL_ENCODED_CONTENT_TYPE = 'application/x-www-form-urlencoded'; diff --git a/lib/browser/ipc-main-impl.ts b/lib/browser/ipc-main-impl.ts index 9118f03e19498..0349cc00c0b4e 100644 --- a/lib/browser/ipc-main-impl.ts +++ b/lib/browser/ipc-main-impl.ts @@ -4,6 +4,13 @@ import { IpcMainInvokeEvent } from 'electron/main'; export class IpcMainImpl extends EventEmitter { private _invokeHandlers: Map 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}'`); diff --git a/lib/browser/ipc-main-internal.ts b/lib/browser/ipc-main-internal.ts index f6c24537d324c..0925f1ef87485 100644 --- a/lib/browser/ipc-main-internal.ts +++ b/lib/browser/ipc-main-internal.ts @@ -1,6 +1,3 @@ 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', () => {}); diff --git a/lib/browser/rpc-server.ts b/lib/browser/rpc-server.ts index d8a80802060b7..48e6ca16b5955 100644 --- a/lib/browser/rpc-server.ts +++ b/lib/browser/rpc-server.ts @@ -68,6 +68,10 @@ ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_SANDBOX_LOAD, async function (event }; }); +ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_NONSANDBOX_LOAD, function (event) { + return { preloadPaths: event.sender._getPreloadPaths() }; +}); + ipcMainInternal.on(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, function (event, preloadPath: string, error: Error) { event.sender.emit('preload-error', event, preloadPath, error); }); diff --git a/lib/common/.eslintrc.json b/lib/common/.eslintrc.json new file mode 100644 index 0000000000000..42964484b5c34 --- /dev/null +++ b/lib/common/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": [ + "electron", + "electron/main", + "electron/renderer" + ], + "patterns": [ + "./*", + "../*", + "@electron/internal/browser/*", + "@electron/internal/isolated_renderer/*", + "@electron/internal/renderer/*", + "@electron/internal/sandboxed_worker/*", + "@electron/internal/worker/*" + ] + } + ] + } +} diff --git a/lib/common/api/clipboard.ts b/lib/common/api/clipboard.ts index dd03b4f279d68..55f7958bc7963 100644 --- a/lib/common/api/clipboard.ts +++ b/lib/common/api/clipboard.ts @@ -1,5 +1,6 @@ import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; +// eslint-disable-next-line no-restricted-imports import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils'; const clipboard = process._linkedBinding('electron_common_clipboard'); diff --git a/lib/common/ipc-messages.ts b/lib/common/ipc-messages.ts index b920c79c48c59..3a85d592691c9 100644 --- a/lib/common/ipc-messages.ts +++ b/lib/common/ipc-messages.ts @@ -3,12 +3,12 @@ export const enum IPC_MESSAGES { BROWSER_GET_LAST_WEB_PREFERENCES = 'BROWSER_GET_LAST_WEB_PREFERENCES', BROWSER_PRELOAD_ERROR = 'BROWSER_PRELOAD_ERROR', BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD', + BROWSER_NONSANDBOX_LOAD = 'BROWSER_NONSANDBOX_LOAD', BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE', BROWSER_GET_PROCESS_MEMORY_INFO = 'BROWSER_GET_PROCESS_MEMORY_INFO', 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', diff --git a/lib/isolated_renderer/.eslintrc.json b/lib/isolated_renderer/.eslintrc.json new file mode 100644 index 0000000000000..cb5f6cadaa4f3 --- /dev/null +++ b/lib/isolated_renderer/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": [ + "electron", + "electron/main" + ], + "patterns": [ + "./*", + "../*", + "@electron/internal/browser/*" + ] + } + ] + } +} diff --git a/lib/renderer/.eslintrc.json b/lib/renderer/.eslintrc.json new file mode 100644 index 0000000000000..cb5f6cadaa4f3 --- /dev/null +++ b/lib/renderer/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": [ + "electron", + "electron/main" + ], + "patterns": [ + "./*", + "../*", + "@electron/internal/browser/*" + ] + } + ] + } +} diff --git a/lib/renderer/common-init.ts b/lib/renderer/common-init.ts index 4ceff37416d59..bfec34419ddd3 100644 --- a/lib/renderer/common-init.ts +++ b/lib/renderer/common-init.ts @@ -1,4 +1,4 @@ -import { ipcRenderer } from 'electron'; +import { ipcRenderer } from 'electron/renderer'; import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; import type * as webViewInitModule from '@electron/internal/renderer/web-view/web-view-init'; diff --git a/lib/renderer/init.ts b/lib/renderer/init.ts index 9807348568976..7047c4ffea927 100644 --- a/lib/renderer/init.ts +++ b/lib/renderer/init.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; import type * as ipcRendererInternalModule from '@electron/internal/renderer/ipc-renderer-internal'; +import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils'; const Module = require('module'); @@ -38,6 +39,7 @@ require('../common/reset-search-paths'); require('@electron/internal/common/init'); const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal') as typeof ipcRendererInternalModule; +const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils') as typeof ipcRendererUtilsModule; process.getProcessMemoryInfo = () => { return ipcRendererInternal.invoke(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO); @@ -48,15 +50,8 @@ const { hasSwitch, getSwitchValue } = process._linkedBinding('electron_common_co const { mainFrame } = process._linkedBinding('electron_renderer_web_frame'); const nodeIntegration = mainFrame.getWebPreference('nodeIntegration'); -const preloadScript = mainFrame.getWebPreference('preload'); -const preloadScripts = mainFrame.getWebPreference('preloadScripts'); const appPath = hasSwitch('app-path') ? getSwitchValue('app-path') : null; -// The webContents preload script is loaded after the session preload scripts. -if (preloadScript) { - preloadScripts.push(preloadScript); -} - // Common renderer initialization require('@electron/internal/renderer/common-init'); @@ -127,8 +122,9 @@ if (nodeIntegration) { } } +const { preloadPaths } = ipcRendererUtils.invokeSync(IPC_MESSAGES.BROWSER_NONSANDBOX_LOAD); // Load the preload scripts. -for (const preloadScript of preloadScripts) { +for (const preloadScript of preloadPaths) { try { Module._load(preloadScript); } catch (error) { diff --git a/lib/renderer/inspector.ts b/lib/renderer/inspector.ts index 346de2030ef40..8dd941d30619a 100644 --- a/lib/renderer/inspector.ts +++ b/lib/renderer/inspector.ts @@ -2,7 +2,7 @@ import { internalContextBridge } from '@electron/internal/renderer/api/context-b import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'; import { webFrame } from 'electron/renderer'; -import { IPC_MESSAGES } from '../common/ipc-messages'; +import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; const { contextIsolationEnabled } = internalContextBridge; diff --git a/lib/renderer/security-warnings.ts b/lib/renderer/security-warnings.ts index 30cb0cc63b6d6..0aadfb632d19f 100644 --- a/lib/renderer/security-warnings.ts +++ b/lib/renderer/security-warnings.ts @@ -1,7 +1,8 @@ -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; diff --git a/lib/renderer/web-frame-init.ts b/lib/renderer/web-frame-init.ts index 37225cfb3428a..ac4db7f9a74dc 100644 --- a/lib/renderer/web-frame-init.ts +++ b/lib/renderer/web-frame-init.ts @@ -1,4 +1,4 @@ -import { webFrame, WebFrame } from 'electron'; +import { webFrame, WebFrame } from 'electron/renderer'; import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'; import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; diff --git a/lib/renderer/web-view/guest-view-internal.ts b/lib/renderer/web-view/guest-view-internal.ts index d8b9b61c135f6..893a6e2305b8c 100644 --- a/lib/renderer/web-view/guest-view-internal.ts +++ b/lib/renderer/web-view/guest-view-internal.ts @@ -6,30 +6,15 @@ const { mainFrame: webFrame } = process._linkedBinding('electron_renderer_web_fr export interface GuestViewDelegate { dispatchEvent (eventName: string, props: Record): void; - reset(): void; } -const DEPRECATED_EVENTS: Record = { - '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}`); } diff --git a/lib/renderer/web-view/web-view-element.ts b/lib/renderer/web-view/web-view-element.ts index 84ac5a9ba79c4..ee290ce09b0fc 100644 --- a/lib/renderer/web-view/web-view-element.ts +++ b/lib/renderer/web-view/web-view-element.ts @@ -55,8 +55,7 @@ const defineWebViewElement = (hooks: WebViewImplHooks) => { } if (!internal.elementAttached) { hooks.guestViewInternal.registerEvents(internal.viewInstanceId, { - dispatchEvent: internal.dispatchEvent.bind(internal), - reset: internal.reset.bind(internal) + dispatchEvent: internal.dispatchEvent.bind(internal) }); internal.elementAttached = true; (internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse(); diff --git a/lib/renderer/web-view/web-view-impl.ts b/lib/renderer/web-view/web-view-impl.ts index 691b477e1bdb2..f3cad33534539 100644 --- a/lib/renderer/web-view/web-view-impl.ts +++ b/lib/renderer/web-view/web-view-impl.ts @@ -191,7 +191,7 @@ export class WebViewImpl { attachGuestInstance (guestInstanceId: number) { if (guestInstanceId === -1) { - // Do nothing + this.dispatchEvent('destroyed'); return; } diff --git a/lib/sandboxed_renderer/.eslintrc.json b/lib/sandboxed_renderer/.eslintrc.json new file mode 100644 index 0000000000000..cb5f6cadaa4f3 --- /dev/null +++ b/lib/sandboxed_renderer/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": [ + "electron", + "electron/main" + ], + "patterns": [ + "./*", + "../*", + "@electron/internal/browser/*" + ] + } + ] + } +} diff --git a/lib/worker/.eslintrc.json b/lib/worker/.eslintrc.json new file mode 100644 index 0000000000000..cb5f6cadaa4f3 --- /dev/null +++ b/lib/worker/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "rules": { + "no-restricted-imports": [ + "error", + { + "paths": [ + "electron", + "electron/main" + ], + "patterns": [ + "./*", + "../*", + "@electron/internal/browser/*" + ] + } + ] + } +} diff --git a/npm/install.js b/npm/install.js index 932bfa6c150c3..864ca633fd30f 100755 --- a/npm/install.js +++ b/npm/install.js @@ -71,15 +71,28 @@ function isInstalled () { // unzips and makes path.txt point at the correct executable function extractFile (zipPath) { return new Promise((resolve, reject) => { - extract(zipPath, { dir: path.join(__dirname, 'dist') }, err => { - if (err) return reject(err); - - fs.writeFile(path.join(__dirname, 'path.txt'), platformPath, err => { - if (err) return reject(err); - - resolve(); - }); - }); + const distPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(__dirname, 'dist'); + + extract(zipPath, { dir: path.join(__dirname, 'dist') }) + .then(() => { + // If the zip contains an "electron.d.ts" file, + // move that up + const srcTypeDefPath = path.join(distPath, 'electron.d.ts'); + const targetTypeDefPath = path.join(__dirname, 'electron.d.ts'); + const hasTypeDefinitions = fs.existsSync(srcTypeDefPath); + + if (hasTypeDefinitions) { + try { + fs.renameSync(srcTypeDefPath, targetTypeDefPath); + } catch (err) { + reject(err); + } + } + + // Write a "path.txt" file. + return fs.promises.writeFile(path.join(__dirname, 'path.txt'), platformPath); + }) + .catch((err) => reject(err)); }); } diff --git a/npm/package.json b/npm/package.json index d97e6704cf4e3..3926e40a17fcc 100644 --- a/npm/package.json +++ b/npm/package.json @@ -8,11 +8,11 @@ "postinstall": "node install.js" }, "dependencies": { - "@electron/get": "^1.13.0", + "@electron/get": "^1.14.1", "@types/node": "^16.11.26", - "extract-zip": "^1.0.3" + "extract-zip": "^2.0.1" }, "engines": { - "node": ">= 8.6" + "node": ">= 10.17.0" } } diff --git a/package.json b/package.json index c60152a81d20b..3a5ba0eaadaad 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "electron", - "version": "18.2.1", + "version": "21.2.0", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { "@azure/storage-blob": "^12.9.0", - "@electron/docs-parser": "^0.12.3", + "@electron/docs-parser": "^0.12.4", "@electron/typescript-definitions": "^8.9.5", "@octokit/auth-app": "^2.10.0", "@octokit/rest": "^18.0.3", @@ -47,14 +47,14 @@ "express": "^4.16.4", "folder-hash": "^2.1.1", "fs-extra": "^9.0.1", - "got": "^6.3.0", - "husky": "^6.0.0", + "got": "^11.8.5", + "husky": "^8.0.1", "klaw": "^3.0.0", "lint": "^1.1.2", "lint-staged": "^10.2.11", "markdownlint": "^0.21.1", "markdownlint-cli": "^0.25.0", - "minimist": "^1.2.5", + "minimist": "^1.2.6", "null-loader": "^4.0.0", "pre-flight": "^1.1.0", "remark-cli": "^10.0.0", @@ -77,7 +77,7 @@ "scripts": { "asar": "asar", "generate-version-json": "node script/generate-version-json.js", - "lint": "node ./script/lint.js && npm run lint:clang-format && npm run lint:docs", + "lint": "node ./script/lint.js && npm run lint:docs", "lint:js": "node ./script/lint.js --js", "lint:clang-format": "python3 script/run-clang-format.py -r -c shell/ || (echo \"\\nCode not formatted correctly.\" && exit 1)", "lint:clang-tidy": "ts-node ./script/run-clang-tidy.ts", @@ -94,6 +94,7 @@ "gn-typescript-definitions": "npm run create-typescript-definitions && shx cp electron.d.ts", "pre-flight": "pre-flight", "gn-check": "node ./script/gn-check.js", + "gn-format": "python3 script/run-gn-format.py", "precommit": "lint-staged", "preinstall": "node -e 'process.exit(0)'", "prepack": "check-for-leaks", @@ -124,7 +125,7 @@ ], "*.{gn,gni}": [ "npm run gn-check", - "python3 script/run-gn-format.py" + "npm run gn-format" ], "*.py": [ "node script/lint.js --py --fix --only --" @@ -141,5 +142,8 @@ "DEPS": [ "node script/gen-hunspell-filenames.js" ] + }, + "resolutions": { + "nan": "nodejs/nan#16fa32231e2ccd89d2804b3f765319128b20c4ac" } } \ No newline at end of file diff --git a/patches/boringssl/expose_aes-cfb.patch b/patches/boringssl/expose_aes-cfb.patch index 767013b5404cc..f7c95c952449b 100644 --- a/patches/boringssl/expose_aes-cfb.patch +++ b/patches/boringssl/expose_aes-cfb.patch @@ -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 2458847e5640fe955a9971aa77c27251e5091db5..a0b3ac5f6b55921a542f27108beca93d6372c6fc 100644 +index 380d25d9c2a8efb0636db5749a8e3b1ba6908ad5..7a5aa1c142e15cf06e63882e83d82a93c0d38785 100644 --- a/include/openssl/cipher.h +++ b/include/openssl/cipher.h -@@ -448,6 +448,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_ecb(void); +@@ -460,6 +460,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); diff --git a/patches/chromium/.patches b/patches/chromium/.patches index 8ae95d6179781..c4566ca063778 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -12,7 +12,6 @@ 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 @@ -21,15 +20,11 @@ resource_file_conflict.patch scroll_bounce_flag.patch mas_blink_no_private_api.patch mas_no_private_api.patch -mas-cfisobjc.patch mas-cgdisplayusesforcetogray.patch -mas-audiodeviceduck.patch mas_disable_remote_layer.patch mas_disable_remote_accessibility.patch mas_disable_custom_window_frame.patch -mas_avoid_usage_of_abort_report_np.patch -mas_avoid_usage_of_pthread_fchdir_np.patch -mas_avoid_usage_of_setapplicationisdaemon_and.patch +mas_avoid_usage_of_private_macos_apis.patch mas_use_public_apis_to_determine_if_a_font_is_a_system_font.patch chrome_key_systems.patch add_didinstallconditionalfeatures.patch @@ -58,7 +53,6 @@ feat_add_set_theme_source_to_allow_apps_to.patch add_webmessageportconverter_entangleandinjectmessageportchannel.patch ignore_rc_check.patch remove_usage_of_incognito_apis_in_the_spellchecker.patch -chore_use_electron_resources_not_chrome_for_spellchecker.patch allow_disabling_blink_scheduler_throttling_per_renderview.patch hack_plugin_response_interceptor_to_point_to_electron.patch feat_add_support_for_overriding_the_base_spellchecker_download_url.patch @@ -80,11 +74,8 @@ 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 -fix_use_electron_generated_resources.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 @@ -102,18 +93,36 @@ chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch process_singleton.patch fix_expose_decrementcapturercount_in_web_contents_impl.patch add_ui_scopedcliboardwriter_writeunsaferawdata.patch -mas_gate_private_enterprise_APIs.patch +feat_add_data_parameter_to_processsingleton.patch load_v8_snapshot_in_browser_process.patch -fix_patch_out_permissions_checks_in_exclusive_access.patch +fix_adapt_exclusive_access_for_electron_needs.patch fix_aspect_ratio_with_max_size.patch fix_dont_delete_SerialPortManager_on_main_thread.patch -feat_add_data_transfer_to_requestsingleinstancelock.patch fix_crash_when_saving_edited_pdf_files.patch port_autofill_colors_to_the_color_pipeline.patch build_disable_partition_alloc_on_mac.patch fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch -remove_incorrect_width_height_adjustments.patch +build_make_libcxx_abi_unstable_false_for_electron.patch introduce_ozoneplatform_electron_can_call_x11_property.patch make_gtk_getlibgtk_public.patch -cherry-pick-e2b8856012e0.patch add_graphite.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 +fix_revert_emulationhandler_update_functions_to_early_return.patch +fix_return_v8_value_from_localframe_requestexecutescript.patch +disable_optimization_guide_for_preconnect_feature.patch +fix_the_gn_gen_for_components_segmentation_platform.patch +fix_crash_loading_non-standard_schemes_in_iframes.patch +create_browser_v8_snapshot_file_name_fuse.patch +cherry-pick-c83640db21b5.patch +fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch diff --git a/patches/chromium/accelerator.patch b/patches/chromium/accelerator.patch index 04f4464c2dbbf..4786fa2f37a82 100644 --- a/patches/chromium/accelerator.patch +++ b/patches/chromium/accelerator.patch @@ -10,7 +10,7 @@ This patch makes three changes to Accelerator::GetShortcutText to improve shortc 3. Ctrl-Shift-= and Ctrl-Plus show up as such diff --git a/ui/base/accelerators/accelerator.cc b/ui/base/accelerators/accelerator.cc -index 2468b2c5881821d6f8e24a0e7c42243427b384ad..7e44c97edabf5ae012ff4f84d1404d8f223a13fe 100644 +index e032433d7096a941132c25528781ecbf375eb9af..33d88f947bc9a0a4795f1584e114952f942b277b 100644 --- a/ui/base/accelerators/accelerator.cc +++ b/ui/base/accelerators/accelerator.cc @@ -11,6 +11,7 @@ @@ -44,7 +44,7 @@ index 2468b2c5881821d6f8e24a0e7c42243427b384ad..7e44c97edabf5ae012ff4f84d1404d8f } #if BUILDFLAG(IS_MAC) -@@ -451,7 +461,7 @@ std::u16string Accelerator::ApplyLongFormModifiers( +@@ -445,7 +455,7 @@ std::u16string Accelerator::ApplyLongFormModifiers( const std::u16string& shortcut) const { std::u16string result = shortcut; @@ -53,7 +53,7 @@ index 2468b2c5881821d6f8e24a0e7c42243427b384ad..7e44c97edabf5ae012ff4f84d1404d8f result = ApplyModifierToAcceleratorString(result, IDS_APP_SHIFT_KEY); // Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut. -@@ -459,7 +469,7 @@ std::u16string Accelerator::ApplyLongFormModifiers( +@@ -453,7 +463,7 @@ std::u16string Accelerator::ApplyLongFormModifiers( // more information. if (IsCtrlDown()) result = ApplyModifierToAcceleratorString(result, IDS_APP_CTRL_KEY); diff --git a/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch b/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch index 14d1535fe63f8..78b99613ad424 100644 --- a/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch +++ b/patches/chromium/add_contentgpuclient_precreatemessageloop_callback.patch @@ -10,7 +10,7 @@ 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 9f840287967b50ec1db3a9d27973429ab231a486..731a279e395a8762a25a115665bff99be428de3d 100644 +index d435206f773dd30086ae81868412bc28029935d8..a0856c214d962199a2e51c7bd14f0f676d35507e 100644 --- a/content/gpu/gpu_main.cc +++ b/content/gpu/gpu_main.cc @@ -239,6 +239,10 @@ int GpuMain(MainFunctionParams parameters) { @@ -24,16 +24,16 @@ index 9f840287967b50ec1db3a9d27973429ab231a486..731a279e395a8762a25a115665bff99b // 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 -@@ -345,7 +349,6 @@ int GpuMain(MainFunctionParams parameters) { - GpuProcess gpu_process(io_thread_priority); - #endif +@@ -323,7 +327,6 @@ int GpuMain(MainFunctionParams parameters) { + const_cast(&command_line), gpu_preferences); + const bool dead_on_arrival = !init_success; - auto* client = GetContentClient()->gpu(); - if (client) - client->PostIOThreadCreated(gpu_process.io_task_runner()); - + if (client) { + client->PostSandboxInitialized(); + } diff --git a/content/public/gpu/content_gpu_client.h b/content/public/gpu/content_gpu_client.h -index 04274b751b498456fc4b269bfbc6399b4f27d3ed..2fb98baf0df4e191e5e18fd7055cc2d92a2156df 100644 +index a5d868b9e409c986bc85dfd71bb0363b5fa22145..9abe1cf5b2cc8ce60387ddf81b7c13aff9c178c4 100644 --- a/content/public/gpu/content_gpu_client.h +++ b/content/public/gpu/content_gpu_client.h @@ -29,6 +29,10 @@ class CONTENT_EXPORT ContentGpuClient { diff --git a/patches/chromium/add_didinstallconditionalfeatures.patch b/patches/chromium/add_didinstallconditionalfeatures.patch index b76baf2e4e6ba..71ebf42a19af7 100644 --- a/patches/chromium/add_didinstallconditionalfeatures.patch +++ b/patches/chromium/add_didinstallconditionalfeatures.patch @@ -10,10 +10,10 @@ 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 a92e09dc651a5f1a9bbae2572fad32233afcd46c..f99b652dda817b62615d2b3f00b4ae4b438ec44d 100644 +index 7d169540590b83924766b1d423dc1bc46ab35250..f5bbb6ab26bd714d667236071a2eb0a5794a5631 100644 --- a/content/public/renderer/render_frame_observer.h +++ b/content/public/renderer/render_frame_observer.h -@@ -129,6 +129,8 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener, +@@ -136,6 +136,8 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener, virtual void DidHandleOnloadEvents() {} virtual void DidCreateScriptContext(v8::Local context, int32_t world_id) {} @@ -23,10 +23,10 @@ index a92e09dc651a5f1a9bbae2572fad32233afcd46c..f99b652dda817b62615d2b3f00b4ae4b int32_t world_id) {} virtual void DidClearWindowObject() {} diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc -index 4473c5e812a4a598f3e2f2bb06f78def5791af24..44c0ec9815aafd61182fd18a9d125e185d7196bc 100644 +index 8199122b2d759aa8b27affabe67b108fb9a16c38..97cf24ad5f4a64322f242b0c339a807e3edb23fc 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc -@@ -4455,6 +4455,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local context, +@@ -4345,6 +4345,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local context, observer.DidCreateScriptContext(context, world_id); } @@ -40,11 +40,11 @@ index 4473c5e812a4a598f3e2f2bb06f78def5791af24..44c0ec9815aafd61182fd18a9d125e18 int world_id) { for (auto& observer : observers_) diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h -index 21b90bbb8fe8ddc03eb20538be423a5396d18eb3..f9c735038f733d990783dd66ffe8c74f824c78f2 100644 +index c8e822502d1b18c701a303024c3cba7e434d7829..89a048fbdaec8a8ea184790b78b0c63cfda7d171 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h -@@ -597,6 +597,8 @@ class CONTENT_EXPORT RenderFrameImpl - blink::WebLocalFrameClient::LazyLoadBehavior lazy_load_behavior) override; +@@ -588,6 +588,8 @@ class CONTENT_EXPORT RenderFrameImpl + uint32_t ng_call_count) override; void DidCreateScriptContext(v8::Local context, int world_id) override; + void DidInstallConditionalFeatures(v8::Local context, @@ -53,10 +53,10 @@ index 21b90bbb8fe8ddc03eb20538be423a5396d18eb3..f9c735038f733d990783dd66ffe8c74f 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 3d6e0c0395ff7c92d8908c5151b467beec3a7516..2fadd6d9b2e3747eacea08973d8d3c7aa9c15f26 100644 +index 4ef7353157272a623cea6b086b84da72ca795fca..548f6afd429695088bd83743fa6f6c1cd4197276 100644 --- a/third_party/blink/public/web/web_local_frame_client.h +++ b/third_party/blink/public/web/web_local_frame_client.h -@@ -599,6 +599,9 @@ class BLINK_EXPORT WebLocalFrameClient { +@@ -584,6 +584,9 @@ class BLINK_EXPORT WebLocalFrameClient { virtual void DidCreateScriptContext(v8::Local, int32_t world_id) {} @@ -67,10 +67,10 @@ index 3d6e0c0395ff7c92d8908c5151b467beec3a7516..2fadd6d9b2e3747eacea08973d8d3c7a virtual void WillReleaseScriptContext(v8::Local, 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 aa4b510137d60e6fb924f4f1a6554fe06c19ad75..816b6260020a6cbb6880b0eed197743ccd9002f5 100644 +index c8af53d40eaa1dd3a0067948a8cda80d1599cee3..4de918ee52efa7ec27a21aa2f57616d31dfd07d1 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 -@@ -205,6 +205,7 @@ void LocalWindowProxy::Initialize() { +@@ -209,6 +209,7 @@ void LocalWindowProxy::Initialize() { } InstallConditionalFeatures(); @@ -79,10 +79,10 @@ index aa4b510137d60e6fb924f4f1a6554fe06c19ad75..816b6260020a6cbb6880b0eed197743c 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 0dda1f7cd77c47f7e61ba48dd20429c13679b543..2f73aacda1bafe07775213e232eda56c4b33325b 100644 +index 83a62e23b1d395b0aa545de5b828c24196cccc6d..0ca8163eb9ab87aead27bc8b2ee9e614d7e1d8c7 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client.h +++ b/third_party/blink/renderer/core/frame/local_frame_client.h -@@ -308,6 +308,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient { +@@ -301,6 +301,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient { virtual void DidCreateScriptContext(v8::Local, int32_t world_id) = 0; @@ -92,10 +92,10 @@ index 0dda1f7cd77c47f7e61ba48dd20429c13679b543..2f73aacda1bafe07775213e232eda56c 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 5297ad63f1c76240d57a64cc5ea64cbf8c7e1b95..006da6072db12da1632f9d45ecb5710136573641 100644 +index 2ac22a0410eea7f67cc7eb066879da649f7c6a0e..53ec3d177afbd75b4e67c6ab847094994c291dcb 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 -@@ -274,6 +274,13 @@ void LocalFrameClientImpl::DidCreateScriptContext( +@@ -273,6 +273,13 @@ void LocalFrameClientImpl::DidCreateScriptContext( web_frame_->Client()->DidCreateScriptContext(context, world_id); } @@ -110,10 +110,10 @@ index 5297ad63f1c76240d57a64cc5ea64cbf8c7e1b95..006da6072db12da1632f9d45ecb57101 v8::Local 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 708414fca139eb8328e425d909a48ca97038e442..48b2a0e129ec166ebd4c9bbd32330b0cc43dbeb2 100644 +index c974fa2f7c7f9c2aa5f075ec4aeb887d0b104453..b4ed9b2fadcfad7676387045b8581eb8d33e89e8 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 -@@ -78,6 +78,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient { +@@ -80,6 +80,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient { void DidCreateScriptContext(v8::Local, int32_t world_id) override; @@ -123,10 +123,10 @@ index 708414fca139eb8328e425d909a48ca97038e442..48b2a0e129ec166ebd4c9bbd32330b0c 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 4b639069d5d9173f0c35fe7656356031ba424a61..3da6699b40bf4f91e6d76a37e5fa8f680f7a7850 100644 +index a2d7e97958d378dc5d37524f2f5516205c010749..e3f605938b3eea7f1c4dfac8e3c25014ebd15476 100644 --- a/third_party/blink/renderer/core/loader/empty_clients.h +++ b/third_party/blink/renderer/core/loader/empty_clients.h -@@ -357,6 +357,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient { +@@ -367,6 +367,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient { void DidCreateScriptContext(v8::Local, int32_t world_id) override {} diff --git a/patches/chromium/add_electron_deps_to_license_credits_file.patch b/patches/chromium/add_electron_deps_to_license_credits_file.patch new file mode 100644 index 0000000000000..e789eaad6a8d0 --- /dev/null +++ b/patches/chromium/add_electron_deps_to_license_credits_file.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Charles Kerr +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 diff --git a/patches/chromium/add_graphite.patch b/patches/chromium/add_graphite.patch index 68fb9e166bf79..3bbfaa4e752fb 100644 --- a/patches/chromium/add_graphite.patch +++ b/patches/chromium/add_graphite.patch @@ -28,7 +28,7 @@ diff --git a/third_party/blink/renderer/platform/fonts/web_font_decoder.cc b/thi index 6e388c9135c64..e6eea739ac230 100644 --- a/third_party/blink/renderer/platform/fonts/web_font_decoder.cc +++ b/third_party/blink/renderer/platform/fonts/web_font_decoder.cc -@@ -95,6 +95,11 @@ ots::TableAction BlinkOTSContext::GetTableAction(uint32_t tag) { +@@ -102,6 +102,11 @@ ots::TableAction BlinkOTSContext::GetTableAction(uint32_t tag) { const uint32_t kCblcTag = OTS_TAG('C', 'B', 'L', 'C'); const uint32_t kColrTag = OTS_TAG('C', 'O', 'L', 'R'); const uint32_t kCpalTag = OTS_TAG('C', 'P', 'A', 'L'); @@ -40,7 +40,7 @@ index 6e388c9135c64..e6eea739ac230 100644 const uint32_t kCff2Tag = OTS_TAG('C', 'F', 'F', '2'); const uint32_t kSbixTag = OTS_TAG('s', 'b', 'i', 'x'); #if HB_VERSION_ATLEAST(1, 0, 0) -@@ -121,6 +126,12 @@ ots::TableAction BlinkOTSContext::GetTableAction(uint32_t tag) { +@@ -128,6 +133,12 @@ ots::TableAction BlinkOTSContext::GetTableAction(uint32_t tag) { // Windows Color Emoji Tables case kColrTag: case kCpalTag: diff --git a/patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch b/patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch new file mode 100644 index 0000000000000..372cd21f99c5c --- /dev/null +++ b/patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch @@ -0,0 +1,176 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: msizanoen1 +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 dd42b1e87cf30413f96fdcfed9d8dc8c04fd537a..6c0612fb0f0dca32486d04491f9cd49a428836d1 100644 +--- a/ui/gtk/gtk_ui.cc ++++ b/ui/gtk/gtk_ui.cc +@@ -500,13 +500,15 @@ std::unique_ptr 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(solid_frame); ++ provider = std::make_unique(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 CreateNavButtonProvider() override; +- ui::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame) override; ++ ui::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame, bool maximized) override; + base::flat_map 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 solid_frame_provider_; + std::unique_ptr transparent_frame_provider_; ++ std::unique_ptr solid_maximized_frame_provider_; ++ std::unique_ptr 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 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 GetKeyboardLayoutMap() = 0; diff --git a/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch b/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch index 01c36b3c68ded..d269e9a1c9409 100644 --- a/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch +++ b/patches/chromium/add_ui_scopedcliboardwriter_writeunsaferawdata.patch @@ -8,7 +8,7 @@ was removed as part of the Raw Clipboard API scrubbing. https://bugs.chromium.org/p/chromium/issues/detail?id=1217643 diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc -index 3009acd40eee36bc3d4dd8642f0ce5e6476da973..1d52ce84184a3ca94e4e0f04d331bf56d75e07d0 100644 +index 1eb1d0fe4696f26e7de43fc8797c283e9e6db042..766f8d8df866ce7fbc337cecceb715cced39643c 100644 --- a/ui/base/clipboard/scoped_clipboard_writer.cc +++ b/ui/base/clipboard/scoped_clipboard_writer.cc @@ -227,6 +227,16 @@ void ScopedClipboardWriter::WriteEncodedDataTransferEndpointForTesting( @@ -29,7 +29,7 @@ index 3009acd40eee36bc3d4dd8642f0ce5e6476da973..1d52ce84184a3ca94e4e0f04d331bf56 objects_.clear(); platform_representations_.clear(); diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h -index c47909313da0d7cd8a2b3cd670327011af66e3fb..0d259c21507f38124dfa46aceeacfda76cfd4a38 100644 +index 96f5bf8b6b5f3ed5ab25e15845f0de455eb68e0b..e6718a893e1bc5c970245c8265c95dda5d5fa2ff 100644 --- a/ui/base/clipboard/scoped_clipboard_writer.h +++ b/ui/base/clipboard/scoped_clipboard_writer.h @@ -84,6 +84,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter { diff --git a/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch b/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch index d27950925164f..7b9ff9388c669 100644 --- a/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch +++ b/patches/chromium/allow_disabling_blink_scheduler_throttling_per_renderview.patch @@ -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 56c08919ab626a8a7b3bcb892ee94cdee2a106fc..b85bdf4ed574a149a6502e8d21e54f2ee80777a5 100644 +index 5c03f1194643c6f7302131404f7d869502f1e18b..fa990e6a444d5321213d956b01ba89ef21d57bd2 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc -@@ -647,6 +647,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) { +@@ -659,6 +659,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) { GetWidget()->GetAssociatedFrameWidget()->SetBackgroundOpaque(opaque); } @@ -22,24 +22,24 @@ index 56c08919ab626a8a7b3bcb892ee94cdee2a106fc..b85bdf4ed574a149a6502e8d21e54f2e return is_active(); } diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h -index 9e32df9f5fd765895c8470c3922a62f754e7d409..9bac2321d65d9e54ce88fffafd72a74803ed2c87 100644 +index dfefe47c77c723c1cfdc6abe0e8ff96bc5ec6ddd..8d195ec46b9a6ea830c1ff36ee740b3b8be2b341 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h -@@ -135,6 +135,7 @@ class CONTENT_EXPORT RenderViewHostImpl - bool IsRenderViewLive() override; - void WriteIntoTrace(perfetto::TracedValue context) override; +@@ -137,6 +137,7 @@ class CONTENT_EXPORT RenderViewHostImpl + void EnablePreferredSizeMode() override; + void WriteIntoTrace(perfetto::TracedProto context) const override; + void SetSchedulerThrottling(bool allowed) override; void SendWebPreferencesToRenderer(); void SendRendererPreferencesToRenderer( const blink::RendererPreferences& preferences); diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h -index 787077d71c04d571aa825bec0a549c5fad2b8574..4b05b80802ba97a46eed60e509b503fc8375016b 100644 +index 2e4af843d7d0bbef5b7e6357de73355068b38948..77c69de4a541c56389ae11330f67c5fb6bbc4d2a 100644 --- a/content/public/browser/render_view_host.h +++ b/content/public/browser/render_view_host.h -@@ -74,6 +74,9 @@ class CONTENT_EXPORT RenderViewHost { - // Write a representation of this object into a trace. - virtual void WriteIntoTrace(perfetto::TracedValue context) = 0; +@@ -77,6 +77,9 @@ class CONTENT_EXPORT RenderViewHost { + virtual void WriteIntoTrace( + perfetto::TracedProto context) const = 0; + // Disable/Enable scheduler throttling. + virtual void SetSchedulerThrottling(bool allowed) = 0; @@ -47,36 +47,23 @@ index 787077d71c04d571aa825bec0a549c5fad2b8574..4b05b80802ba97a46eed60e509b503fc private: // 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 4e8d36420d6edc1725a840e1b9f123041d21abe4..dd198cb7bf02e509833c6b4c7d8e5d65d20d46dc 100644 ---- a/content/renderer/render_view_impl.h -+++ b/content/renderer/render_view_impl.h -@@ -152,6 +152,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 befd736a9cf362514b9a2ee475dc4a814c85a87b..24b2617f56673a3075697802cf5b574b0c766610 100644 +index 6ff7c34463f3ce5011ea8711d23f9cd11da38d8b..2b8e313dfac2ea9fad0583bb5e98d0c385e8584a 100644 --- a/third_party/blink/public/mojom/page/page.mojom +++ b/third_party/blink/public/mojom/page/page.mojom -@@ -97,4 +97,7 @@ interface PageBroadcast { - - // Sent to whole page, but should only be used by the main frame. - SetPageBaseBackgroundColor(skia.mojom.SkColor? color); +@@ -137,4 +137,7 @@ interface PageBroadcast { + mojo_base.mojom.UnguessableToken devtools_frame_token, + RemoteFrameInterfacesFromBrowser remote_frame_interfaces, + RemoteMainFrameInterfaces remote_main_frame_interfaces); + + // Whether to enable the Renderer scheduler background throttling. + SetSchedulerThrottling(bool allowed); }; diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h -index 14d4a00293ab0b11e733676844ce483992d6cd8e..c6c2dbb9dddd1eaa21e8c7b276d871a3898463fa 100644 +index 3af33a4d699b5bbfb0a1abac9408ad322a47a5ac..30bc8aa73fb46a0306ccc837a99cc4d58daef99d 100644 --- a/third_party/blink/public/web/web_view.h +++ b/third_party/blink/public/web/web_view.h -@@ -368,6 +368,7 @@ class WebView { +@@ -366,6 +366,7 @@ class WebView { // Scheduling ----------------------------------------------------------- virtual PageScheduler* Scheduler() const = 0; @@ -85,10 +72,10 @@ index 14d4a00293ab0b11e733676844ce483992d6cd8e..c6c2dbb9dddd1eaa21e8c7b276d871a3 // 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 b9d5a13bcdf981064f9970fdb8017fed5f93b35e..182f70b2b3bd9cbc6548d4c17caad797e5dad0ce 100644 +index 231f76d07d8a0d3d060b30e0ff6eabe4aa33d755..40aa3b1a5c569e66b6f5d1630afe248c40d5715b 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc -@@ -3668,6 +3668,13 @@ PageScheduler* WebViewImpl::Scheduler() const { +@@ -3787,6 +3787,13 @@ PageScheduler* WebViewImpl::Scheduler() const { return GetPage()->GetPageScheduler(); } @@ -102,7 +89,7 @@ index b9d5a13bcdf981064f9970fdb8017fed5f93b35e..182f70b2b3bd9cbc6548d4c17caad797 void WebViewImpl::SetVisibilityState( mojom::blink::PageVisibilityState visibility_state, bool is_initial_state) { -@@ -3679,7 +3686,8 @@ void WebViewImpl::SetVisibilityState( +@@ -3798,7 +3805,8 @@ void WebViewImpl::SetVisibilityState( } GetPage()->SetVisibilityState(visibility_state, is_initial_state); GetPage()->GetPageScheduler()->SetPageVisible( @@ -113,10 +100,10 @@ index b9d5a13bcdf981064f9970fdb8017fed5f93b35e..182f70b2b3bd9cbc6548d4c17caad797 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 5107ef421138e136b20b25b7bbcc1f0bb246bb66..043266205142e59f88c4c2f2ae6b58bb009f2d9c 100644 +index 08cc81481cbe4fe40a7df6316db765fa2eac7fda..c5dfefd84b44de5a2c28afb2b9bd8035647da12b 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h -@@ -420,6 +420,7 @@ class CORE_EXPORT WebViewImpl final : public WebView, +@@ -425,6 +425,7 @@ class CORE_EXPORT WebViewImpl final : public WebView, LocalDOMWindow* PagePopupWindow() const; PageScheduler* Scheduler() const override; @@ -124,7 +111,7 @@ index 5107ef421138e136b20b25b7bbcc1f0bb246bb66..043266205142e59f88c4c2f2ae6b58bb void SetVisibilityState(mojom::blink::PageVisibilityState visibility_state, bool is_initial_state) override; mojom::blink::PageVisibilityState GetVisibilityState() override; -@@ -857,6 +858,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, +@@ -875,6 +876,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, // If true, we send IPC messages when |preferred_size_| changes. bool send_preferred_size_changes_ = false; diff --git a/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch b/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch index 763b2ecf84401..5bf9d19e0f1d6 100644 --- a/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch +++ b/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch @@ -8,19 +8,18 @@ WebPreferences of in-process child windows, rather than relying on process-level command line switches, as before. diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc -index 30e237f886b41bdf528b2a0e81054d15fb323f1f..43f7920cf6ff12d8a48ddef5440814a42266e8c5 100644 +index e5c9ebda8156c1a7c32f7eb0661dff40f022c264..8840d4be4b49b27dfb257866f6a074efc34ff869 100644 --- a/third_party/blink/common/web_preferences/web_preferences.cc +++ b/third_party/blink/common/web_preferences/web_preferences.cc -@@ -145,6 +145,20 @@ WebPreferences::WebPreferences() - fake_no_alloc_direct_call_for_testing_enabled(false), +@@ -143,6 +143,19 @@ WebPreferences::WebPreferences() v8_cache_options(blink::mojom::V8CacheOptions::kDefault), record_whole_document(false), + stylus_handwriting_enabled(false), + // Begin Electron-specific WebPreferences. + context_isolation(false), + is_webview(false), + hidden_page(false), + offscreen(false), -+ preload(base::FilePath::StringType()), + node_integration(false), + node_integration_in_worker(false), + node_integration_in_sub_frames(false), @@ -33,24 +32,13 @@ index 30e237f886b41bdf528b2a0e81054d15fb323f1f..43f7920cf6ff12d8a48ddef5440814a4 accelerated_video_decode_enabled(false), animation_policy( diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc -index d278453a261fe2dd3bacce433e35d50879b555a7..140f8d6273d944bfe36831d27aef757d89240b56 100644 +index cfd107cf7257b5c0c2482baba8964e1d2508fc8b..6a2e25a3d7700df9c59952ff19c9ce62d391005c 100644 --- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc +++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc -@@ -22,6 +22,10 @@ bool StructTraitssans_serif_font_family_map) || - !data.ReadCursiveFontFamilyMap(&out->cursive_font_family_map) || - !data.ReadFantasyFontFamilyMap(&out->fantasy_font_family_map) || -+ // Begin Electron-specific WebPreferences. -+ !data.ReadPreloads(&out->preloads) || -+ !data.ReadPreload(&out->preload) || -+ // End Electron-specific WebPreferences. - !data.ReadLazyFrameLoadingDistanceThresholdsPx( - &out->lazy_frame_loading_distance_thresholds_px) || - !data.ReadLazyImageLoadingDistanceThresholdsPx( -@@ -151,6 +155,19 @@ bool StructTraitsv8_cache_options = data.v8_cache_options(); out->record_whole_document = data.record_whole_document(); + out->stylus_handwriting_enabled = data.stylus_handwriting_enabled(); + // Begin Electron-specific WebPreferences. + out->context_isolation = data.context_isolation(); + out->is_webview = data.is_webview(); @@ -63,12 +51,12 @@ index d278453a261fe2dd3bacce433e35d50879b555a7..140f8d6273d944bfe36831d27aef757d + out->enable_plugins = data.enable_plugins(); + out->enable_websql = data.enable_websql(); + out->webview_tag = data.webview_tag(); -+ // End Electron-specific WebPreferences.s ++ // End Electron-specific WebPreferences. out->cookie_enabled = data.cookie_enabled(); out->accelerated_video_decode_enabled = data.accelerated_video_decode_enabled(); diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h -index 8509f720c5afb816c6cbb2313dd566a24236a790..b9f0f79d96c58a7769939610bb72f8b2bcd3be94 100644 +index adbb4f0de4d787ac7710de06de2bf3b32dc6491f..c68a71ca2e272874420d309f2154cf89cf99b7ec 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences.h +++ b/third_party/blink/public/common/web_preferences/web_preferences.h @@ -10,6 +10,7 @@ @@ -79,17 +67,15 @@ index 8509f720c5afb816c6cbb2313dd566a24236a790..b9f0f79d96c58a7769939610bb72f8b2 #include "net/nqe/effective_connection_type.h" #include "third_party/blink/public/common/common_export.h" #include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-shared.h" -@@ -160,6 +161,22 @@ struct BLINK_COMMON_EXPORT WebPreferences { - blink::mojom::V8CacheOptions v8_cache_options; - bool record_whole_document; - +@@ -159,6 +160,19 @@ struct BLINK_COMMON_EXPORT WebPreferences { + // If true, stylus handwriting recognition to text input will be available in + // editable input fields which are non-password type. + bool stylus_handwriting_enabled; + // Begin Electron-specific WebPreferences. -+ std::vector preloads; + bool context_isolation; + bool is_webview; + bool hidden_page; + bool offscreen; -+ base::FilePath preload; + bool node_integration; + bool node_integration_in_worker; + bool node_integration_in_sub_frames; @@ -98,12 +84,11 @@ index 8509f720c5afb816c6cbb2313dd566a24236a790..b9f0f79d96c58a7769939610bb72f8b2 + bool enable_websql; + bool webview_tag; + // End Electron-specific WebPreferences. -+ + // This flags corresponds to a Page's Settings' setCookieEnabled state. It // only controls whether or not the "document.cookie" field is properly - // connected to the backing store, for instance if you wanted to be able to diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h -index a6291be3e953ceaee1d996e4b30a6ae78916bc7a..c3baf95c5d9b6a6ace56bcde9e1dc8179f18eaa0 100644 +index fa2db0ccc2d9f72aa4976816548df31f83c2ef54..ab896b217be1f8695c6d05414252a37c8086369d 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h +++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h @@ -6,6 +6,7 @@ @@ -114,15 +99,11 @@ index a6291be3e953ceaee1d996e4b30a6ae78916bc7a..c3baf95c5d9b6a6ace56bcde9e1dc817 #include "mojo/public/cpp/bindings/struct_traits.h" #include "net/nqe/effective_connection_type.h" #include "third_party/blink/public/common/common_export.h" -@@ -441,6 +442,60 @@ struct BLINK_COMMON_EXPORT StructTraits& preloads(const blink::web_pref::WebPreferences& r) { -+ return r.preloads; -+ } -+ + static bool context_isolation(const blink::web_pref::WebPreferences& r) { + return r.context_isolation; + } @@ -139,10 +120,6 @@ index a6291be3e953ceaee1d996e4b30a6ae78916bc7a..c3baf95c5d9b6a6ace56bcde9e1dc817 + return r.offscreen; + } + -+ static const base::FilePath& preload(const blink::web_pref::WebPreferences& r) { -+ return r.preload; -+ } -+ + static bool node_integration(const blink::web_pref::WebPreferences& r) { + return r.node_integration; + } @@ -176,7 +153,7 @@ index a6291be3e953ceaee1d996e4b30a6ae78916bc7a..c3baf95c5d9b6a6ace56bcde9e1dc817 return r.cookie_enabled; } diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom -index 96dd9fd56e44e66c5ea24d9df7c6cbff25409d6c..e0d113b4dee6a72f350b8494448f516be01d0468 100644 +index 656ed9364bc7b5874273797f3587d5d74f2c6bdb..e8e990b10890cca95ecc8927222e622eee8b888f 100644 --- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom +++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom @@ -10,6 +10,7 @@ import "third_party/blink/public/mojom/v8_cache_options.mojom"; @@ -187,17 +164,15 @@ index 96dd9fd56e44e66c5ea24d9df7c6cbff25409d6c..e0d113b4dee6a72f350b8494448f516b enum PointerType { kPointerNone = 1, // 1 << 0 -@@ -212,6 +213,22 @@ struct WebPreferences { - V8CacheOptions v8_cache_options; - bool record_whole_document; - +@@ -210,6 +211,19 @@ struct WebPreferences { + // If true, stylus handwriting recognition to text input will be available in + // editable input fields which are non-password type. + bool stylus_handwriting_enabled; + // Begin Electron-specific WebPreferences. -+ array preloads; + bool context_isolation; + bool is_webview; + bool hidden_page; + bool offscreen; -+ mojo_base.mojom.FilePath preload; + bool node_integration; + bool node_integration_in_worker; + bool node_integration_in_sub_frames; @@ -206,7 +181,6 @@ index 96dd9fd56e44e66c5ea24d9df7c6cbff25409d6c..e0d113b4dee6a72f350b8494448f516b + bool enable_websql; + bool webview_tag; + // End Electron-specific WebPreferences. -+ + // This flags corresponds to a Page's Settings' setCookieEnabled state. It // only controls whether or not the "document.cookie" field is properly - // connected to the backing store, for instance if you wanted to be able to diff --git a/patches/chromium/allow_new_privileges_in_unsandboxed_child_processes.patch b/patches/chromium/allow_new_privileges_in_unsandboxed_child_processes.patch index 617c5e656d99e..3e7cca104eec5 100644 --- a/patches/chromium/allow_new_privileges_in_unsandboxed_child_processes.patch +++ b/patches/chromium/allow_new_privileges_in_unsandboxed_child_processes.patch @@ -6,10 +6,10 @@ Subject: allow new privileges in unsandboxed child processes This allows unsandboxed renderers to launch setuid processes on Linux. diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc -index f60ad777ab7698a4518d3b1b61ade29e7c618a3a..c7781bdb49f8a92aa9ee1d8dd1af03fa9cf2dfe3 100644 +index 16d838b710d4f717733f4aa8f92f144922969b3b..ff2c78c7b803159dde97dafdb799d9b8761dc3fd 100644 --- a/content/browser/child_process_launcher_helper_linux.cc +++ b/content/browser/child_process_launcher_helper_linux.cc -@@ -53,6 +53,18 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread( +@@ -54,6 +54,18 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread( if (GetProcessType() == switches::kRendererProcess) { const int sandbox_fd = SandboxHostLinux::GetInstance()->GetChildSocket(); options->fds_to_remap.push_back(std::make_pair(sandbox_fd, GetSandboxFD())); @@ -27,4 +27,4 @@ index f60ad777ab7698a4518d3b1b61ade29e7c618a3a..c7781bdb49f8a92aa9ee1d8dd1af03fa + } } - options->environment = delegate_->GetEnvironment(); + for (const auto& remapped_fd : file_data_->additional_remapped_fds) { diff --git a/patches/chromium/allow_setting_secondary_label_via_simplemenumodel.patch b/patches/chromium/allow_setting_secondary_label_via_simplemenumodel.patch index 8ce5997c5cb9f..ae09b284c270f 100644 --- a/patches/chromium/allow_setting_secondary_label_via_simplemenumodel.patch +++ b/patches/chromium/allow_setting_secondary_label_via_simplemenumodel.patch @@ -6,7 +6,7 @@ Subject: Allow setting secondary label via SimpleMenuModel Builds on https://chromium-review.googlesource.com/c/chromium/src/+/2208976 diff --git a/ui/base/models/simple_menu_model.cc b/ui/base/models/simple_menu_model.cc -index 746dffb1defec9d776f681d41325a65b02cbdd0f..05a7f20f10e3ff514aa3b3b5386980ddfcc586eb 100644 +index 6e1ed6b05b9358a46c796ac175a6556703477a1f..f138d6dc153694c2c3fbb8c98d9557e5bab8214e 100644 --- a/ui/base/models/simple_menu_model.cc +++ b/ui/base/models/simple_menu_model.cc @@ -53,6 +53,11 @@ std::u16string SimpleMenuModel::Delegate::GetLabelForCommandId( @@ -21,36 +21,36 @@ index 746dffb1defec9d776f681d41325a65b02cbdd0f..05a7f20f10e3ff514aa3b3b5386980dd ImageModel SimpleMenuModel::Delegate::GetIconForCommandId( int command_id) const { return ImageModel(); -@@ -304,6 +309,11 @@ void SimpleMenuModel::SetLabel(int index, const std::u16string& label) { +@@ -311,6 +316,11 @@ void SimpleMenuModel::SetLabel(size_t index, const std::u16string& label) { MenuItemsChanged(); } -+void SimpleMenuModel::SetSecondaryLabel(int index, const std::u16string& secondary_label) { ++void SimpleMenuModel::SetSecondaryLabel(size_t index, const std::u16string& secondary_label) { + items_[ValidateItemIndex(index)].secondary_label = secondary_label; + MenuItemsChanged(); +} + - void SimpleMenuModel::SetMinorText(int index, + void SimpleMenuModel::SetMinorText(size_t index, const std::u16string& minor_text) { items_[ValidateItemIndex(index)].minor_text = minor_text; -@@ -396,6 +406,12 @@ std::u16string SimpleMenuModel::GetLabelAt(int index) const { +@@ -404,6 +414,12 @@ std::u16string SimpleMenuModel::GetLabelAt(size_t index) const { return items_[ValidateItemIndex(index)].label; } -+std::u16string SimpleMenuModel::GetSecondaryLabelAt(int index) const { ++std::u16string SimpleMenuModel::GetSecondaryLabelAt(size_t index) const { + if (IsItemDynamicAt(index)) + return delegate_->GetSecondaryLabelForCommandId(GetCommandIdAt(index)); + return items_[ValidateItemIndex(index)].secondary_label; +} + - std::u16string SimpleMenuModel::GetMinorTextAt(int index) const { + std::u16string SimpleMenuModel::GetMinorTextAt(size_t index) const { return items_[ValidateItemIndex(index)].minor_text; } diff --git a/ui/base/models/simple_menu_model.h b/ui/base/models/simple_menu_model.h -index bd2ebaf9f84946c708eba13c18869afadd2fdbb0..880d6f12ad188c5f8abf037b3b8d27fcf1fc2cb6 100644 +index 7ecb2f6cae709af8c512cfb6cac71d449a9b39c4..b7781d44125c1d66dba90bc39f9f17b194a85665 100644 --- a/ui/base/models/simple_menu_model.h +++ b/ui/base/models/simple_menu_model.h -@@ -49,6 +49,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { +@@ -50,6 +50,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { // Some command ids have labels and icons that change over time. virtual bool IsItemForCommandIdDynamic(int command_id) const; virtual std::u16string GetLabelForCommandId(int command_id) const; @@ -58,25 +58,25 @@ index bd2ebaf9f84946c708eba13c18869afadd2fdbb0..880d6f12ad188c5f8abf037b3b8d27fc // Gets the icon for the item with the specified id. virtual ImageModel GetIconForCommandId(int command_id) const; -@@ -160,6 +161,9 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { +@@ -167,6 +168,9 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { // Sets the label for the item at |index|. - void SetLabel(int index, const std::u16string& label); + void SetLabel(size_t index, const std::u16string& label); + // Sets the secondary_label for the item at |index|. -+ void SetSecondaryLabel(int index, const std::u16string& secondary_label); ++ void SetSecondaryLabel(size_t index, const std::u16string& secondary_label); + // Sets the minor text for the item at |index|. - void SetMinorText(int index, const std::u16string& minor_text); + void SetMinorText(size_t index, const std::u16string& minor_text); -@@ -199,6 +203,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { - ui::MenuSeparatorType GetSeparatorTypeAt(int index) const override; - int GetCommandIdAt(int index) const override; - std::u16string GetLabelAt(int index) const override; -+ std::u16string GetSecondaryLabelAt(int index) const override; - std::u16string GetMinorTextAt(int index) const override; - ImageModel GetMinorIconAt(int index) const override; - bool IsItemDynamicAt(int index) const override; -@@ -238,6 +243,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { +@@ -206,6 +210,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { + ui::MenuSeparatorType GetSeparatorTypeAt(size_t index) const override; + int GetCommandIdAt(size_t index) const override; + std::u16string GetLabelAt(size_t index) const override; ++ std::u16string GetSecondaryLabelAt(size_t index) const override; + std::u16string GetMinorTextAt(size_t index) const override; + ImageModel GetMinorIconAt(size_t index) const override; + bool IsItemDynamicAt(size_t index) const override; +@@ -246,6 +251,7 @@ class COMPONENT_EXPORT(UI_BASE) SimpleMenuModel : public MenuModel { int command_id = 0; ItemType type = TYPE_COMMAND; std::u16string label; diff --git a/patches/chromium/blink_file_path.patch b/patches/chromium/blink_file_path.patch index ace4aa5924cca..8185b75732fb6 100644 --- a/patches/chromium/blink_file_path.patch +++ b/patches/chromium/blink_file_path.patch @@ -7,10 +7,10 @@ This is used by editors to obtain the filesystem path from a dragged file. See documentation at https://electronjs.org/docs/api/file-object diff --git a/third_party/blink/renderer/core/fileapi/file.h b/third_party/blink/renderer/core/fileapi/file.h -index 72d6b7e109779c9785130ebb0e1e23202c5bc68d..e12c4acfd87f1d698d7c8c8459e7231ee03789fd 100644 +index c061962bec620d2da0e217d8f55b7db57d120f97..59d9946ecfb7d68b41f539ce7c29c7398e00e9b2 100644 --- a/third_party/blink/renderer/core/fileapi/file.h +++ b/third_party/blink/renderer/core/fileapi/file.h -@@ -212,6 +212,9 @@ class CORE_EXPORT File final : public Blob { +@@ -211,6 +211,9 @@ class CORE_EXPORT File final : public Blob { } const String& name() const { return name_; } diff --git a/patches/chromium/blink_local_frame.patch b/patches/chromium/blink_local_frame.patch index e7484d16d1661..f92f01efc91b9 100644 --- a/patches/chromium/blink_local_frame.patch +++ b/patches/chromium/blink_local_frame.patch @@ -15,10 +15,10 @@ Refs changes in: This patch reverts the changes to fix associated crashes in Electron. diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc -index 09e6436422169ac05d5f0561f12984c86dc7af5e..7b2263f4c7fa2dffbaf5b630f4d5a83d9b68f9a5 100644 +index 0e50579d9b1c989beee4113d6762d32b8074efb4..bbcd21ddc38a799fe4226447f9b3447f1ea54feb 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc -@@ -122,14 +122,6 @@ bool Frame::Detach(FrameDetachType type) { +@@ -124,14 +124,6 @@ bool Frame::Detach(FrameDetachType type) { DCHECK(!IsDetached()); @@ -33,7 +33,7 @@ index 09e6436422169ac05d5f0561f12984c86dc7af5e..7b2263f4c7fa2dffbaf5b630f4d5a83d if (type == FrameDetachType::kRemove) { if (provisional_frame_) { provisional_frame_->Detach(FrameDetachType::kRemove); -@@ -153,6 +145,14 @@ bool Frame::Detach(FrameDetachType type) { +@@ -155,6 +147,14 @@ bool Frame::Detach(FrameDetachType type) { GetWindowProxyManager()->ClearForSwap(); } @@ -49,10 +49,10 @@ index 09e6436422169ac05d5f0561f12984c86dc7af5e..7b2263f4c7fa2dffbaf5b630f4d5a83d // its owning reference back to our owning LocalFrame. client_->Detached(type); diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc -index db69148e0756ed36bcf3a04f1ace69cc166261a6..bcf072a6d8bc46e5c71d9ef3f248b6af69693ac9 100644 +index 90cf3971e573aaec7a85ccf4b6fff9f931924bdc..bb4e80de2930b2e3213cc7c4469bb2875760ebee 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc -@@ -538,10 +538,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { +@@ -547,10 +547,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { } DCHECK(!view_ || !view_->IsAttached()); @@ -63,7 +63,7 @@ index db69148e0756ed36bcf3a04f1ace69cc166261a6..bcf072a6d8bc46e5c71d9ef3f248b6af if (!Client()) return false; -@@ -587,6 +583,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { +@@ -596,6 +592,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) { DCHECK(!view_->IsAttached()); Client()->WillBeDetached(); diff --git a/patches/chromium/boringssl_build_gn.patch b/patches/chromium/boringssl_build_gn.patch index 05fde5454844e..ff94bf807a8e2 100644 --- a/patches/chromium/boringssl_build_gn.patch +++ b/patches/chromium/boringssl_build_gn.patch @@ -6,7 +6,7 @@ Subject: boringssl BUILD.gn Build BoringSSL with some extra functions that nodejs needs. diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn -index f222ae94a5a10ced84e41ef84560af46a910577f..c18d26de9a63befca3c77fe5ecd93975a016797f 100644 +index efcbdf378b61af0a4b0f2cd784160d95439e84e1..fc6bba3fdd71ee40bb38f7d95a2f4dccd82d3e17 100644 --- a/third_party/boringssl/BUILD.gn +++ b/third_party/boringssl/BUILD.gn @@ -44,6 +44,20 @@ config("no_asm_config") { diff --git a/patches/chromium/breakpad_allow_getting_string_values_for_crash_keys.patch b/patches/chromium/breakpad_allow_getting_string_values_for_crash_keys.patch index 0cd9d06f2e8de..9c2342ded0f3b 100644 --- a/patches/chromium/breakpad_allow_getting_string_values_for_crash_keys.patch +++ b/patches/chromium/breakpad_allow_getting_string_values_for_crash_keys.patch @@ -13,7 +13,7 @@ on linux. If removing this patch doesn't cause a compile failure, it's fine to delete! diff --git a/components/crash/core/common/crash_key.h b/components/crash/core/common/crash_key.h -index c0771b00922c1f21ec9dba726c5c7cd51c267d69..d731c7bf168c4b8df0a46da40c9164b4ac6239f3 100644 +index bf88c1180ee507c97e2613d4aba12a8e87fcfcd3..fae2b77315784f9167c0fcf4cc5330520c14b862 100644 --- a/components/crash/core/common/crash_key.h +++ b/components/crash/core/common/crash_key.h @@ -219,6 +219,10 @@ class CrashKeyStringCombined : public internal::CrashKeyStringCombinedImpl { diff --git a/patches/chromium/breakpad_treat_node_processes_as_browser_processes.patch b/patches/chromium/breakpad_treat_node_processes_as_browser_processes.patch index 1222c47289414..f10afcbb1f251 100644 --- a/patches/chromium/breakpad_treat_node_processes_as_browser_processes.patch +++ b/patches/chromium/breakpad_treat_node_processes_as_browser_processes.patch @@ -10,10 +10,10 @@ breakpad independently, as a "browser" process. This patches crash annotation. diff --git a/components/crash/core/app/breakpad_linux.cc b/components/crash/core/app/breakpad_linux.cc -index 43f6d476f3ee2759cf41c492f932522994e7ddec..8df14f416ee321e1259433715a61fa6025207d80 100644 +index 1fa85302da7a64abc42fd9558ddbcaf68b387517..62d15f57e4c5a0a24aa730e8979fb1e9537fecd3 100644 --- a/components/crash/core/app/breakpad_linux.cc +++ b/components/crash/core/app/breakpad_linux.cc -@@ -718,8 +718,13 @@ bool CrashDone(const MinidumpDescriptor& minidump, +@@ -719,8 +719,13 @@ bool CrashDone(const MinidumpDescriptor& minidump, log_path[log_path_len] = '\0'; info.log_filename = log_path; #endif @@ -29,7 +29,7 @@ index 43f6d476f3ee2759cf41c492f932522994e7ddec..8df14f416ee321e1259433715a61fa60 info.distro = base::g_linux_distro; info.distro_length = my_strlen(base::g_linux_distro); info.upload = upload; -@@ -2025,8 +2030,13 @@ void InitCrashReporter(const std::string& process_type) { +@@ -2027,8 +2032,13 @@ void InitCrashReporter(const std::string& process_type) { process_type == kWebViewSingleProcessType || process_type == kBrowserProcessType || #endif @@ -40,6 +40,6 @@ index 43f6d476f3ee2759cf41c492f932522994e7ddec..8df14f416ee321e1259433715a61fa60 + g_is_node = true; + } + - #if !BUILDFLAG(IS_CHROMEOS_ASH) + #if !BUILDFLAG(IS_CHROMEOS) SetUploadURL(GetCrashReporterClient()->GetUploadUrl()); #endif diff --git a/patches/chromium/build_add_electron_tracing_category.patch b/patches/chromium/build_add_electron_tracing_category.patch index 22145207fe628..beea0817b40cb 100644 --- a/patches/chromium/build_add_electron_tracing_category.patch +++ b/patches/chromium/build_add_electron_tracing_category.patch @@ -8,10 +8,10 @@ categories in use are known / declared. This patch is required for us to introduce a new Electron category for Electron-specific tracing. diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h -index 107516329273ee4a6cc49433b69f307b1264362b..0c9555a04233d07a186e34ada8b7615095854950 100644 +index be712614ac5be3573427247d7032432f18e47a15..4ad49e65f6139b43a8f9d1041dfdd4b6951ca7a7 100644 --- a/base/trace_event/builtin_categories.h +++ b/base/trace_event/builtin_categories.h -@@ -78,6 +78,7 @@ +@@ -80,6 +80,7 @@ X("drmcursor") \ X("dwrite") \ X("DXVA_Decoding") \ diff --git a/patches/chromium/build_disable_partition_alloc_on_mac.patch b/patches/chromium/build_disable_partition_alloc_on_mac.patch index a6e101d19e16b..c3a8068824ee9 100644 --- a/patches/chromium/build_disable_partition_alloc_on_mac.patch +++ b/patches/chromium/build_disable_partition_alloc_on_mac.patch @@ -9,7 +9,7 @@ and can be removed when the crash in fork is resolved. Related issue: https://github.com/electron/electron/issues/32718 diff --git a/base/allocator/allocator.gni b/base/allocator/allocator.gni -index 8fa0c36007a0ae0e4553709d27a8231efb08459b..3c4f93fc98b5002572adc78cb9a21b3e78c9f3e0 100644 +index 674def40cfdc83432d0f3ced8ab3f570dc9e8b1b..96e5e5e145715218724f93041060df60d709839a 100644 --- a/base/allocator/allocator.gni +++ b/base/allocator/allocator.gni @@ -20,7 +20,7 @@ _disable_partition_alloc = is_component_build || (is_win && is_debug) diff --git a/patches/chromium/build_disable_print_content_analysis.patch b/patches/chromium/build_disable_print_content_analysis.patch new file mode 100644 index 0000000000000..ae1dfdc82ce17 --- /dev/null +++ b/patches/chromium/build_disable_print_content_analysis.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: VerteDinde +Date: Sun, 1 May 2022 18:01:42 -0700 +Subject: build: disable print_content_analysis + +Print Content Analysis enables enterprise users to scan to-be-printed +pages and documents for sensitive data if the OnPrintEnterpriseConnector +policy is enabled. A conversation with the Chromium team confirmed +this feature was intended for enterprise Chrome users and not embedders, +so we're disabling it to prevent build issues/additional unneeded files. + +This patch can be removed when enable_print_content_analysis can be more +easily enabled or disabled by default with buildflags. + +diff --git a/printing/buildflags/buildflags.gni b/printing/buildflags/buildflags.gni +index e57b8edde3b3e8f7a9cd580e2bcd039f1beebdff..f49cbaa980674444ccaee4a615dc99e9c630f7b8 100644 +--- a/printing/buildflags/buildflags.gni ++++ b/printing/buildflags/buildflags.gni +@@ -36,7 +36,7 @@ declare_args() { + + # Enable snapshotting a page when printing for its content to be analyzed for + # sensitive content by enterprise users. +- enable_print_content_analysis = is_chromeos || is_win || is_linux || is_mac ++ enable_print_content_analysis = is_chromeos + } + + declare_args() { diff --git a/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch b/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch index 8fe824bd51d18..66ec8aaf66484 100644 --- a/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch +++ b/patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch @@ -11,10 +11,10 @@ if we ever align our .pak file generation with Chrome we can remove this patch. diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn -index f2c4feac76e96575de3627b7e8f2373b4fb30411..f5fa6b21594c97a08d1aefd790a4846d9b3e1a45 100644 +index 0223183c4e869e835429a52ad7d9eb381a2d21f5..47162ccaa75ea637b7ce5ed0fed976862b14c427 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn -@@ -171,11 +171,16 @@ if (!is_android && !is_mac) { +@@ -176,11 +176,16 @@ if (!is_android && !is_mac) { "common/crash_keys.h", ] @@ -33,10 +33,10 @@ index f2c4feac76e96575de3627b7e8f2373b4fb30411..f5fa6b21594c97a08d1aefd790a4846d "//base", "//build:branding_buildflags", diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn -index 492cd8e11e28e0b427aca227665295a3052af765..760d2171c5083820fbbf66ce5d7d3c80930b9e88 100644 +index bb193ea0cb1df492e52a5023bd84852bfc3985ce..f89c54a1f73f26ca142a2764fd235111e6cbeff0 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn -@@ -4501,7 +4501,7 @@ static_library("browser") { +@@ -4623,7 +4623,7 @@ static_library("browser") { # On Windows, the hashes are embedded in //chrome:chrome_initial rather # than here in :chrome_dll. @@ -46,18 +46,18 @@ index 492cd8e11e28e0b427aca227665295a3052af765..760d2171c5083820fbbf66ce5d7d3c80 sources += [ "certificate_viewer_stub.cc" ] } diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn -index 028d269850e66db444591cda7005a0f8434193e9..cc0d14cd9798c6bbee80581c95eb8281ce7fb6ba 100644 +index ade95f3592fc54e69ec8717c7542ef2eae645056..c339589fc723be5ad49cca88bddbd9ae8a649644 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn -@@ -5722,7 +5722,6 @@ test("unit_tests") { +@@ -6038,7 +6038,6 @@ test("unit_tests") { deps += [ "//chrome:other_version", - "//chrome:packed_resources_integrity", "//chrome//services/util_win:unit_tests", "//chrome/app:chrome_dll_resources", - "//chrome/browser:chrome_process_finder", -@@ -5745,6 +5744,10 @@ test("unit_tests") { + "//chrome/app:crash_reporter_client_win_unit_tests", +@@ -6063,6 +6062,10 @@ test("unit_tests") { "//ui/resources", ] @@ -68,23 +68,23 @@ index 028d269850e66db444591cda7005a0f8434193e9..cc0d14cd9798c6bbee80581c95eb8281 ldflags = [ "/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll", "/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll", -@@ -6438,7 +6441,6 @@ test("unit_tests") { +@@ -6964,7 +6967,7 @@ test("unit_tests") { } deps += [ - "//chrome:packed_resources_integrity_hash", - "//chrome/browser:cart_db_content_proto", - "//chrome/browser:coupon_db_content_proto", ++ # "//chrome:packed_resources_integrity_hash", + "//chrome/browser/autofill_assistant/password_change/vector_icons:vector_icons", + "//chrome/browser/enterprise/connectors/analysis:features", "//chrome/browser/media/router:test_support", -@@ -6483,6 +6485,11 @@ test("unit_tests") { - "//ui/native_theme:test_support", - "//ui/webui/resources/js/browser_command:mojo_bindings", - ] -+ -+ if (!is_electron_build) { -+ deps += [ "//chrome:packed_resources_integrity_hash" ] -+ } +@@ -7083,6 +7086,10 @@ test("unit_tests") { + } + } + ++ if (!is_electron_build) { ++ deps += [ "//chrome:packed_resources_integrity_hash" ] ++ } + - if (is_chromeos_ash) { - deps += [ - "//ash/assistant/model", + if (is_chromeos_ash) { + sources -= [ + "../browser/policy/cloud/user_policy_signin_service_unittest.cc", diff --git a/patches/chromium/build_gn.patch b/patches/chromium/build_gn.patch index 8155d69721913..a8ab854a62f91 100644 --- a/patches/chromium/build_gn.patch +++ b/patches/chromium/build_gn.patch @@ -14,7 +14,7 @@ tradeoff is that switching from MAS_BUILD to !MAS_BUILD or vice-versa will rebuild the entire tree. diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn -index fcc7e12834733fa0927c35708de9665db4c59eba..faac97db5a2c86f1fcc89c3c045ef74b7b2b878a 100644 +index c737e53c2ce7237974f6c749eae60ba1de7ec2c1..26ba3ae4a77bc8f525c2ad927ff2956c028ef337 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -123,6 +123,9 @@ if (current_os == "") { @@ -27,7 +27,7 @@ index fcc7e12834733fa0927c35708de9665db4c59eba..faac97db5a2c86f1fcc89c3c045ef74b # Set to enable the official build level of optimization. This has nothing # to do with branding, but enables an additional level of optimization above # release (!is_debug). This might be better expressed as a tri-state -@@ -346,6 +349,7 @@ default_compiler_configs = [ +@@ -348,6 +351,7 @@ default_compiler_configs = [ "//build/config/compiler/pgo:default_pgo_flags", "//build/config/coverage:default_coverage", "//build/config/sanitizers:default_sanitizer_flags", diff --git a/patches/chromium/build_libc_as_static_library.patch b/patches/chromium/build_libc_as_static_library.patch index 6466ffaee38c7..1724d3fa2ba8a 100644 --- a/patches/chromium/build_libc_as_static_library.patch +++ b/patches/chromium/build_libc_as_static_library.patch @@ -7,7 +7,7 @@ Build libc++ as static library to compile and pass nan tests diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn -index 7915346430db72d18474d7a011b8dc7637c3f281..cd736d988f9c5e37dc24c724268fe115e00914d9 100644 +index 01f5a1713c28f077e624fe1ea1c84fa3b514d660..3837b9ccf00b2d9f0b655a2c08e96d5020b0afbf 100644 --- a/buildtools/third_party/libc++/BUILD.gn +++ b/buildtools/third_party/libc++/BUILD.gn @@ -44,7 +44,11 @@ config("winver") { @@ -30,7 +30,7 @@ index 7915346430db72d18474d7a011b8dc7637c3f281..cd736d988f9c5e37dc24c724268fe115 + "//electron:libcxx_objects_zip", "//third_party/catapult/devil:devil", ] - if (is_linux && !is_chromeos) { + if (is_linux) { diff --git a/buildtools/third_party/libc++abi/BUILD.gn b/buildtools/third_party/libc++abi/BUILD.gn index 40f1285f14c0843405e0ee51879b8742285a006d..5be895d3e36df53a5960006a1513f1322400fd23 100644 --- a/buildtools/third_party/libc++abi/BUILD.gn diff --git a/patches/chromium/build_make_libcxx_abi_unstable_false_for_electron.patch b/patches/chromium/build_make_libcxx_abi_unstable_false_for_electron.patch new file mode 100644 index 0000000000000..9aa331ea94321 --- /dev/null +++ b/patches/chromium/build_make_libcxx_abi_unstable_false_for_electron.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Charles Kerr +Date: Tue, 22 Mar 2022 16:24:44 -0500 +Subject: build: make libcxx_abi_unstable false for electron + +https://nornagon.medium.com/a-libc-odyssey-973e51649063 + +diff --git a/build/config/c++/BUILD.gn b/build/config/c++/BUILD.gn +index 5d222aaccd15cbcdd413094e33bd48fd3798de8f..a2653637c2735b268dc4e6174536565d9add17bf 100644 +--- a/build/config/c++/BUILD.gn ++++ b/build/config/c++/BUILD.gn +@@ -29,10 +29,12 @@ config("runtime_library") { + # on Windows, the increase is great enough that we go above the 4GB size + # limit for PDBs (https://crbug.com/1327710#c5). To fix this, we set + # _LIBCPP_ABI_NAMESPACE to a shorter value. +- defines += [ +- "_LIBCPP_ABI_NAMESPACE=Cr", +- "_LIBCPP_ABI_VERSION=2", +- ] ++ defines += [ "_LIBCPP_ABI_NAMESPACE=Cr" ] ++ ++ if (!is_electron_build) { ++ # This breaks native node modules ++ defines += [ "_LIBCPP_ABI_VERSION=2" ] ++ } + + if (!libcxx_is_shared) { + # Don't leak any symbols on a static build. diff --git a/patches/chromium/can_create_window.patch b/patches/chromium/can_create_window.patch index 660737f07dcf6..6a4ef1c6c1dbd 100644 --- a/patches/chromium/can_create_window.patch +++ b/patches/chromium/can_create_window.patch @@ -9,10 +9,10 @@ potentially prevent a window from being created. TODO(loc): this patch is currently broken. diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc -index 36a8fa8d3e981707e6688379813560ba94209ab3..e36a19c847912b007a94464321bb83b15bdcdafd 100644 +index 753d3cb544f812689616ce7bd05d24844f20883c..1f58d6a342b0c1e0c5fd4d525a684a166f11a69d 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc -@@ -6706,6 +6706,7 @@ void RenderFrameHostImpl::CreateNewWindow( +@@ -7313,6 +7313,7 @@ void RenderFrameHostImpl::CreateNewWindow( last_committed_origin_, params->window_container_type, params->target_url, params->referrer.To(), params->frame_name, params->disposition, *params->features, @@ -21,10 +21,10 @@ index 36a8fa8d3e981707e6688379813560ba94209ab3..e36a19c847912b007a94464321bb83b1 &no_javascript_access); diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index f28855f738e3b98196813a6d306ba30f7f294cb2..5afb01c9de253053243a1add87269a9d848b5297 100644 +index 8e1c0feede6dc599c0bc78d6278726b16c7931df..2b393e7e7089d17a0906610c3c8979c20928a5f6 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -3925,6 +3925,14 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -4012,6 +4012,14 @@ FrameTree* WebContentsImpl::CreateNewWindow( } auto* new_contents_impl = new_contents.get(); @@ -39,7 +39,7 @@ index f28855f738e3b98196813a6d306ba30f7f294cb2..5afb01c9de253053243a1add87269a9d new_contents_impl->GetController().SetSessionStorageNamespace( partition_config, session_storage_namespace); -@@ -3967,12 +3975,6 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -4056,12 +4064,6 @@ FrameTree* WebContentsImpl::CreateNewWindow( AddWebContentsDestructionObserver(new_contents_impl); } @@ -53,13 +53,13 @@ index f28855f738e3b98196813a6d306ba30f7f294cb2..5afb01c9de253053243a1add87269a9d new_contents_impl, opener, params.target_url, params.referrer.To(), params.disposition, diff --git a/content/common/frame.mojom b/content/common/frame.mojom -index ace032dc2ffac27fbdddee5a4b13c3c3e36ba5ae..80f7dd56fdaa94a9880995b2b5393af0414eef29 100644 +index 4eee5f6c069c83039bf0acee71056d8ed4ea92eb..9212926fba9d06296c9c46a95519b6ed777569ee 100644 --- a/content/common/frame.mojom +++ b/content/common/frame.mojom -@@ -550,6 +550,10 @@ struct CreateNewWindowParams { +@@ -574,6 +574,10 @@ struct CreateNewWindowParams { - // Governs how downloads are handled if `target_url` results in a download. - blink.mojom.NavigationDownloadPolicy download_policy; + // Additional parameters for creating picture-in-picture windows. + blink.mojom.PictureInPictureWindowOptions? pip_options; + + // Extra fields added by Electron. + string raw_features; @@ -68,10 +68,10 @@ index ace032dc2ffac27fbdddee5a4b13c3c3e36ba5ae..80f7dd56fdaa94a9880995b2b5393af0 // Operation result when the renderer asks the browser to create a new window. diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc -index a0a9f51b7e62b13f62467f14e3e9245cb6fc8d84..329cbc6f8c822c6f6deac4f341baec41228dca7b 100644 +index a9c96d4b463929143c7de0ec29d4afee5315fd92..2750d9f6c377b36fd1684077d9eec1cde78c856c 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc -@@ -577,6 +577,8 @@ bool ContentBrowserClient::CanCreateWindow( +@@ -617,6 +617,8 @@ bool ContentBrowserClient::CanCreateWindow( const std::string& frame_name, WindowOpenDisposition disposition, const blink::mojom::WindowFeatures& features, @@ -81,10 +81,10 @@ index a0a9f51b7e62b13f62467f14e3e9245cb6fc8d84..329cbc6f8c822c6f6deac4f341baec41 bool opener_suppressed, bool* no_javascript_access) { diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h -index 3bbb6a39eeb719b94d0e212ea8da5051ff55d441..ceb2bb900e122840505aa8d3911923cffc9a907e 100644 +index bac29d867e465c87f69ea4f28eac118718db0992..7eb47e0c73c7f0d8a0cadcf5b8163f8a5154faea 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h -@@ -169,6 +169,7 @@ class NetworkService; +@@ -163,6 +163,7 @@ class NetworkService; class TrustedURLLoaderHeaderClient; } // namespace mojom struct ResourceRequest; @@ -92,7 +92,7 @@ index 3bbb6a39eeb719b94d0e212ea8da5051ff55d441..ceb2bb900e122840505aa8d3911923cf } // namespace network namespace sandbox { -@@ -960,6 +961,8 @@ class CONTENT_EXPORT ContentBrowserClient { +@@ -999,6 +1000,8 @@ class CONTENT_EXPORT ContentBrowserClient { const std::string& frame_name, WindowOpenDisposition disposition, const blink::mojom::WindowFeatures& features, @@ -102,7 +102,7 @@ index 3bbb6a39eeb719b94d0e212ea8da5051ff55d441..ceb2bb900e122840505aa8d3911923cf bool opener_suppressed, bool* no_javascript_access); diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc -index f132199113778f6b50972419b61a187e6272300c..7bb1680553c405a9016cfd67eca5fa3c6439b692 100644 +index 74847a4fbd4d0d897ce6aecd1b39e30bc226f8f4..3ddcc2d403a68fdc2b4b0246899cd9507ecc6195 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc @@ -26,6 +26,17 @@ namespace content { @@ -124,7 +124,7 @@ index f132199113778f6b50972419b61a187e6272300c..7bb1680553c405a9016cfd67eca5fa3c const OpenURLParams& params) { return nullptr; diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h -index f889d0bf33cf218a68bf5a9422aecaed23fa260a..3330876f623e5b2cb600b1ce1fd10b3375568613 100644 +index 0274e3bb5cc62ce2c52be68a50b57c339fc5bba7..1ea3e1fdf067ea54ce54d31f494ac2bf42b2de3f 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h @@ -16,6 +16,7 @@ @@ -135,7 +135,7 @@ index f889d0bf33cf218a68bf5a9422aecaed23fa260a..3330876f623e5b2cb600b1ce1fd10b33 #include "content/public/browser/eye_dropper.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/media_stream_request.h" -@@ -339,6 +340,13 @@ class CONTENT_EXPORT WebContentsDelegate { +@@ -338,6 +339,13 @@ class CONTENT_EXPORT WebContentsDelegate { const StoragePartitionConfig& partition_config, SessionStorageNamespace* session_storage_namespace); @@ -149,34 +149,26 @@ index f889d0bf33cf218a68bf5a9422aecaed23fa260a..3330876f623e5b2cb600b1ce1fd10b33 // Notifies the delegate about the creation of a new WebContents. This // typically happens when popups are created. virtual void WebContentsCreated(WebContents* source_contents, -diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc -index 83517883144a77a0c775ce2d146b4e85ef79ea97..aa65517a568aa0b324b2c8cca8f60bb532ba085a 100644 ---- a/content/renderer/render_view_impl.cc -+++ b/content/renderer/render_view_impl.cc -@@ -32,6 +32,7 @@ - #include "third_party/blink/public/platform/impression_conversions.h" - #include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h" - #include "third_party/blink/public/platform/url_conversion.h" -+#include "third_party/blink/public/platform/web_url_request_util.h" - #include "third_party/blink/public/web/modules/mediastream/web_media_stream_device_observer.h" - #include "third_party/blink/public/web/web_frame_widget.h" - #include "third_party/blink/public/web/web_local_frame.h" -@@ -291,6 +292,10 @@ WebView* RenderViewImpl::CreateView( - params->impression = blink::ConvertWebImpressionToImpression(*impression); - } +diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc +index d70f6df69aa604972755d1cfe0cfcd2b0369f68c..8199122b2d759aa8b27affabe67b108fb9a16c38 100644 +--- a/content/renderer/render_frame_impl.cc ++++ b/content/renderer/render_frame_impl.cc +@@ -6196,6 +6196,10 @@ WebView* RenderFrameImpl::CreateNewWindow( + /*openee_can_access_opener_origin=*/true, + !GetWebFrame()->IsAllowedToDownload(), GetWebFrame()->IsAdFrame()); + params->raw_features = features.raw_features.Utf8( + WTF::UTF8ConversionMode::kStrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD); + params->body = GetRequestBodyForWebURLRequest(request); + - params->download_policy.ApplyDownloadFramePolicy( - /*is_opener_navigation=*/false, request.HasUserGesture(), - // `openee_can_access_opener_origin` only matters for opener navigations, + // We preserve this information before sending the message since |params| is + // moved on send. + bool is_background_tab = diff --git a/content/web_test/browser/web_test_content_browser_client.cc b/content/web_test/browser/web_test_content_browser_client.cc -index 54b62065d148ab860a49dc03daaf7680ff00d778..3008d3efe89585a562ae55734938b10ef8b0074e 100644 +index 40b82385697d8721ef6da3d0c77544d6d0ca400c..3a2d5207fb2eeea4b016012b09c3668af8dc35b4 100644 --- a/content/web_test/browser/web_test_content_browser_client.cc +++ b/content/web_test/browser/web_test_content_browser_client.cc -@@ -440,6 +440,8 @@ bool WebTestContentBrowserClient::CanCreateWindow( +@@ -482,6 +482,8 @@ bool WebTestContentBrowserClient::CanCreateWindow( const std::string& frame_name, WindowOpenDisposition disposition, const blink::mojom::WindowFeatures& features, @@ -186,10 +178,10 @@ index 54b62065d148ab860a49dc03daaf7680ff00d778..3008d3efe89585a562ae55734938b10e bool opener_suppressed, bool* no_javascript_access) { diff --git a/content/web_test/browser/web_test_content_browser_client.h b/content/web_test/browser/web_test_content_browser_client.h -index d4eb4d482b2641585d501131c64b90cc9dbcfd18..132a5d86279b9a2cb4364b9c6d3e89e12d55052e 100644 +index 4805dd035772fcaea60a1a91eb9911d5c0ce93a9..3b752ea509149f04fd6d10f6977bd29791f6a5d6 100644 --- a/content/web_test/browser/web_test_content_browser_client.h +++ b/content/web_test/browser/web_test_content_browser_client.h -@@ -80,6 +80,8 @@ class WebTestContentBrowserClient : public ShellContentBrowserClient { +@@ -81,6 +81,8 @@ class WebTestContentBrowserClient : public ShellContentBrowserClient { const std::string& frame_name, WindowOpenDisposition disposition, const blink::mojom::WindowFeatures& features, @@ -199,13 +191,13 @@ index d4eb4d482b2641585d501131c64b90cc9dbcfd18..132a5d86279b9a2cb4364b9c6d3e89e1 bool opener_suppressed, bool* no_javascript_access) override; diff --git a/third_party/blink/public/web/web_window_features.h b/third_party/blink/public/web/web_window_features.h -index 84d32491a56528a84b4395fba1d54cdbb38d522b..09998a83c449ef8cd9f360fbcdcf7edc0bbfa4a9 100644 +index 34570168ccb123f5102dcf8fa6bbf98e7c373ec6..192701e56d258da41b3724292853885e4daf3420 100644 --- a/third_party/blink/public/web/web_window_features.h +++ b/third_party/blink/public/web/web_window_features.h @@ -34,6 +34,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" - #include "third_party/blink/public/platform/web_impression.h" + #include "third_party/blink/public/common/navigation/impression.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -213,21 +205,22 @@ index 84d32491a56528a84b4395fba1d54cdbb38d522b..09998a83c449ef8cd9f360fbcdcf7edc @@ -68,6 +69,8 @@ struct WebWindowFeatures { // Represents the attribution source declared by Attribution Reporting related // window features, if any. - absl::optional impression; + absl::optional impression; + + String raw_features; }; } // namespace blink diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc -index 030cc373443766b6485a888f5627885f535e06fc..7bc60b17a0f1aeb208f6d7d85cd6fa537c44c54a 100644 +index 5bf3339038b6a8498221d1bd222ec340d78d1b92..c4be7a96144ac53be856fbf52dff8e990aa736aa 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc -@@ -2050,6 +2050,7 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate, - +@@ -2091,6 +2091,8 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate, WebWindowFeatures window_features = - GetWindowFeaturesFromString(features, incumbent_window); -+ window_features.raw_features = features; + GetWindowFeaturesFromString(features, entered_window, completed_url); - FrameLoadRequest frame_request(incumbent_window, - ResourceRequest(completed_url)); ++ window_features.raw_features = features; ++ + // In fenced frames, we should always use `noopener`. + if (GetFrame()->IsInFencedFrameTree()) { + window_features.noopener = true; diff --git a/patches/chromium/cherry-pick-c83640db21b5.patch b/patches/chromium/cherry-pick-c83640db21b5.patch new file mode 100644 index 0000000000000..28911679eccf1 --- /dev/null +++ b/patches/chromium/cherry-pick-c83640db21b5.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Wed, 5 Oct 2022 06:03:23 +0000 +Subject: build: set DTSDKBuild correctly when generating plist files + +Currently we set DTSDKBuild to the version of the SDK used to build +Chromium. This value is supposed to be the build version (this is +what xcode sets it to for instance). We read this value out of the +SDK directly and use it instead. + +Change-Id: Ieb7990f13095683ad8c026f027b2605ae39523a4 + +diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni +index 43577925d2ef9cd79970d8307104e0abc1756583..0819d4cc1b17f216eae8c1a562b0301ba6298d57 100644 +--- a/build/config/mac/mac_sdk.gni ++++ b/build/config/mac/mac_sdk.gni +@@ -40,6 +40,11 @@ declare_args() { + # will fail. + mac_sdk_official_version = "12.3" + ++ # The SDK build version used when making official builds. This is a single ++ # exact version found at "System/Library/CoreServices/SystemVersion.plist" ++ # inside the SDK. ++ mac_sdk_official_build_version = "21E226" ++ + # Production builds should use hermetic Xcode. If you want to do production + # builds with system Xcode to test new SDKs, set this. + # Don't set this on any bots. +@@ -103,11 +108,13 @@ if (use_system_xcode) { + find_sdk_args = [ + "--print_sdk_path", + "--print_bin_path", ++ "--print_sdk_build", + mac_sdk_min, + ] + find_sdk_lines = + exec_script("//build/mac/find_sdk.py", find_sdk_args, "list lines") +- mac_sdk_version = find_sdk_lines[2] ++ mac_sdk_version = find_sdk_lines[3] ++ mac_sdk_build_version = find_sdk_lines[2] + if (mac_sdk_path == "") { + mac_sdk_path = find_sdk_lines[0] + mac_bin_path = find_sdk_lines[1] +@@ -116,6 +123,7 @@ if (use_system_xcode) { + } + } else { + mac_sdk_version = mac_sdk_official_version ++ mac_sdk_build_version = mac_sdk_official_build_version + _dev = _hermetic_xcode_path + "/Contents/Developer" + _sdk = "MacOSX${mac_sdk_version}.sdk" + mac_sdk_path = _dev + "/Platforms/MacOSX.platform/Developer/SDKs/$_sdk" +diff --git a/build/config/mac/rules.gni b/build/config/mac/rules.gni +index 03073f830401c4891376a3b59e2e7a870e3d34b7..04d403054c1a83fcbbc70be7cfd239ecbec315d3 100644 +--- a/build/config/mac/rules.gni ++++ b/build/config/mac/rules.gni +@@ -41,7 +41,7 @@ template("mac_info_plist") { + apple_info_plist(target_name) { + format = "xml1" + extra_substitutions = [ +- "MAC_SDK_BUILD=$mac_sdk_version", ++ "MAC_SDK_BUILD=$mac_sdk_build_version", + "MAC_SDK_NAME=$mac_sdk_name$mac_sdk_version", + "MACOSX_DEPLOYMENT_TARGET=$mac_deployment_target", + "CHROMIUM_MIN_SYSTEM_VERSION=$mac_min_system_version", +diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py +index d86f3109357a9246d570cb02992dc82552ba7c20..b2400c7e8c70957e364444f509880900ce3b641f 100755 +--- a/build/mac/find_sdk.py ++++ b/build/mac/find_sdk.py +@@ -24,6 +24,7 @@ Sample Output: + from __future__ import print_function + + import os ++import plistlib + import re + import subprocess + import sys +@@ -51,6 +52,9 @@ def main(): + parser.add_option("--print_bin_path", + action="store_true", dest="print_bin_path", default=False, + help="Additionally print the path the toolchain bin dir.") ++ parser.add_option("--print_sdk_build", ++ action="store_true", dest="print_sdk_build", default=False, ++ help="Additionally print the build version of the SDK.") + options, args = parser.parse_args() + if len(args) != 1: + parser.error('Please specify a minimum SDK version') +@@ -80,20 +84,30 @@ def main(): + if not sdks: + raise Exception('No %s+ SDK found' % min_sdk_version) + best_sdk = sorted(sdks, key=parse_version)[0] ++ sdk_name = 'MacOSX' + best_sdk + '.sdk' ++ sdk_path = os.path.join(sdk_dir, sdk_name) + + if options.print_sdk_path: +- sdk_name = 'MacOSX' + best_sdk + '.sdk' +- print(os.path.join(sdk_dir, sdk_name)) ++ print(sdk_path) + + if options.print_bin_path: + bin_path = 'Toolchains/XcodeDefault.xctoolchain/usr/bin/' + print(os.path.join(dev_dir, bin_path)) + +- return best_sdk ++ if options.print_sdk_build: ++ system_version_plist = os.path.join(sdk_path, ++ 'System/Library/CoreServices/SystemVersion.plist') ++ with open(system_version_plist, 'rb') as f: ++ system_version_info = plistlib.load(f) ++ if 'ProductBuildVersion' not in system_version_info: ++ raise Exception('Failed to determine ProductBuildVersion' + ++ 'for SDK at path %s' % system_version_plist) ++ print(system_version_info['ProductBuildVersion']) ++ ++ print(best_sdk) + + + if __name__ == '__main__': + if sys.platform != 'darwin': + raise Exception("This script only runs on Mac") +- print(main()) +- sys.exit(0) ++ sys.exit(main()) diff --git a/patches/chromium/cherry-pick-e2b8856012e0.patch b/patches/chromium/cherry-pick-e2b8856012e0.patch deleted file mode 100644 index 29addf1a159d5..0000000000000 --- a/patches/chromium/cherry-pick-e2b8856012e0.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Xiaocheng Hu -Date: Mon, 18 Apr 2022 01:14:45 +0000 -Subject: Sanitize DragData markup before inserting it into document - -(cherry picked from commit 5164a0fe3391283663e1196cf4576ec233985e89) - -Fixed: 1315040 -Change-Id: I8a0ddfb983d12c185f7e943d3d5277788199b011 -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3579670 -Quick-Run: Xiaocheng Hu -Auto-Submit: Xiaocheng Hu -Reviewed-by: Kent Tamura -Commit-Queue: Kent Tamura -Cr-Original-Commit-Position: refs/heads/main@{#991324} -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3588887 -Bot-Commit: Rubber Stamper -Cr-Commit-Position: refs/branch-heads/4951@{#831} -Cr-Branched-From: 27de6227ca357da0d57ae2c7b18da170c4651438-refs/heads/main@{#982481} - -diff --git a/third_party/blink/renderer/core/page/drag_data.cc b/third_party/blink/renderer/core/page/drag_data.cc -index 2ce56b1fefe016ac34a1a3011a595fab342abfa5..4fb86bc645386ee806544ee3647b0a333cd8afc4 100644 ---- a/third_party/blink/renderer/core/page/drag_data.cc -+++ b/third_party/blink/renderer/core/page/drag_data.cc -@@ -131,8 +131,8 @@ DocumentFragment* DragData::AsFragment(LocalFrame* frame) const { - platform_drag_data_->HtmlAndBaseURL(html, base_url); - DCHECK(frame->GetDocument()); - if (DocumentFragment* fragment = -- CreateFragmentFromMarkup(*frame->GetDocument(), html, base_url, -- kDisallowScriptingAndPluginContent)) -+ CreateSanitizedFragmentFromMarkupWithContext( -+ *frame->GetDocument(), html, 0, html.length(), base_url)) - return fragment; - } - -diff --git a/third_party/blink/web_tests/editing/pasteboard/drag-and-drop-svg-use-sanitize.html b/third_party/blink/web_tests/editing/pasteboard/drag-and-drop-svg-use-sanitize.html -new file mode 100644 -index 0000000000000000000000000000000000000000..58551d28341d851dbd99322e2a5d3af68b3b0c72 ---- /dev/null -+++ b/third_party/blink/web_tests/editing/pasteboard/drag-and-drop-svg-use-sanitize.html -@@ -0,0 +1,47 @@ -+ -+ -+ -+ -+
Drag from
-+
Drag to
-+ -+ diff --git a/patches/chromium/chore_add_electron_deps_to_gitignores.patch b/patches/chromium/chore_add_electron_deps_to_gitignores.patch new file mode 100644 index 0000000000000..f17521282d3c7 --- /dev/null +++ b/patches/chromium/chore_add_electron_deps_to_gitignores.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Tue, 26 Jul 2022 00:05:29 -0700 +Subject: chore: add electron deps to gitignores + +Makes things like "git status" quicker when developing electron locally + +diff --git a/.gitignore b/.gitignore +index 651d8ec7d8e98e7588f8f182018188ab234d5c5a..1fc645a7f748d3cad8ca2f4fa9897454cb937a4c 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -230,6 +230,7 @@ vs-chromium-project.txt + /delegate_execute + /device/serial/device_serial_mojo.xml + /docs/website ++/electron + /google_apis/gcm/gcm.xml + /google_apis/internal + /googleurl +diff --git a/third_party/.gitignore b/third_party/.gitignore +index 63611fc675a17af16dc20cbd9b20e28db63a7ead..eb369ac8b3bc0c2344491438b67e1618d2efb244 100644 +--- a/third_party/.gitignore ++++ b/third_party/.gitignore +@@ -83,6 +83,7 @@ + /directxsdk + /dom_distiller_js/dist + /eigen3/src ++/electron_node + /elfutils/src + /emoji-segmenter/src + /emoji-metadata/src +@@ -179,6 +180,7 @@ + /mocha + /mockito/src + /nacl_sdk_binaries/ ++/nan + /nasm + /nearby/src + /neon_2_sse/src +@@ -242,6 +244,7 @@ + /speex + /sqlite/src + /sqlite4java/lib/ ++/squirrel.mac + /subresource-filter-ruleset/data/UnindexedRules + /swift-format + /swiftshader/ diff --git a/patches/chromium/chore_allow_chromium_to_handle_synthetic_mouse_events_for_touch.patch b/patches/chromium/chore_allow_chromium_to_handle_synthetic_mouse_events_for_touch.patch new file mode 100644 index 0000000000000..5274875a7f85e --- /dev/null +++ b/patches/chromium/chore_allow_chromium_to_handle_synthetic_mouse_events_for_touch.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 +Date: Fri, 29 Jul 2022 00:29:35 +0900 +Subject: chore: allow chromium to handle synthetic mouse events for touch + +With WCO, allow chromium to handle synthetic mouse events generated for touch +actions in the non-client caption area. + +diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +index 2b1fa6a345247fdbb17bd2381ab9e74a8af40b8d..f11cefe945c33c82cafe7ac0d496f3fcfbc48931 100644 +--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc ++++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +@@ -1169,6 +1169,10 @@ void DesktopWindowTreeHostWin::HandleWindowScaleFactorChanged( + } + } + ++bool DesktopWindowTreeHostWin::HandleMouseEventForCaption(UINT message) const { ++ return false; ++} ++ + DesktopNativeCursorManager* + DesktopWindowTreeHostWin::GetSingletonDesktopNativeCursorManager() { + return new DesktopNativeCursorManagerWin(); +diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +index 0aae49ec83b88057434af5bbfb54b10e53469918..058e5dc978e76a71fa02dc9e275592f3c39befea 100644 +--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h ++++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +@@ -263,6 +263,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin + void HandleWindowSizeChanging() override; + void HandleWindowSizeUnchanged() override; + void HandleWindowScaleFactorChanged(float window_scale_factor) override; ++ bool HandleMouseEventForCaption(UINT message) const override; + + Widget* GetWidget(); + const Widget* GetWidget() const; +diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc +index 2dbe61a4bdf6556f6db101e47d81d37417736bd1..dec439f15a7995b14ccf4ef95651413911b5fc4f 100644 +--- a/ui/views/win/hwnd_message_handler.cc ++++ b/ui/views/win/hwnd_message_handler.cc +@@ -3137,15 +3137,19 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, + SetMsgHandled(FALSE); + // We must let Windows handle the caption buttons if it's drawing them, or + // they won't work. ++ bool simulate_mouse_event_for_caption = false; + if (delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN && + (hittest == HTCLOSE || hittest == HTMINBUTTON || + hittest == HTMAXBUTTON)) { +- SetMsgHandled(FALSE); ++ simulate_mouse_event_for_caption = ++ delegate_->HandleMouseEventForCaption(message); ++ if (!simulate_mouse_event_for_caption) ++ SetMsgHandled(FALSE); + } + // Let resize events fall through. Ignore everything else, as we're either + // letting Windows handle it above or we've already handled the equivalent + // touch message. +- if (!IsHitTestOnResizeHandle(hittest)) ++ if (!IsHitTestOnResizeHandle(hittest) && !simulate_mouse_event_for_caption) + return 0; + } + +diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h +index 5dbb192d0840ca0ded61397c399b774a8cb05cce..098a9c3140e9e140fdc8f0dc9cf4e8ec84451221 100644 +--- a/ui/views/win/hwnd_message_handler_delegate.h ++++ b/ui/views/win/hwnd_message_handler_delegate.h +@@ -258,6 +258,10 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate { + // Called when the window scale factor has changed. + virtual void HandleWindowScaleFactorChanged(float window_scale_factor) = 0; + ++ // Called when synthetic mouse event is generated for touch event on ++ // caption buttons. ++ virtual bool HandleMouseEventForCaption(UINT message) const = 0; ++ + protected: + virtual ~HWNDMessageHandlerDelegate() = default; + }; diff --git a/patches/chromium/chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch b/patches/chromium/chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch index a1ba014a796d3..380b7d15612c7 100644 --- a/patches/chromium/chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch +++ b/patches/chromium/chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch @@ -10,10 +10,10 @@ In Electron that can be simplified to webContents.isFocused() which maps to "is This can't be upstreamed but the patch is minimal. diff --git a/chrome/browser/resources/cryptotoken/webrequestsender.js b/chrome/browser/resources/cryptotoken/webrequestsender.js -index 67385e25a9233ce7a5077e69e9be1f457252ea5d..3e6864e6ea3374874598a0175746451126ddb165 100644 +index 8ea2d1c6d7269d25cd34a61d971d35c81b561670..8609defbb5de5c11614858586a9100974aed067c 100644 --- a/chrome/browser/resources/cryptotoken/webrequestsender.js +++ b/chrome/browser/resources/cryptotoken/webrequestsender.js -@@ -141,10 +141,11 @@ function tabInForeground(tabId) { +@@ -142,10 +142,11 @@ function tabInForeground(tabId) { reject(); return; } @@ -29,7 +29,7 @@ index 67385e25a9233ce7a5077e69e9be1f457252ea5d..3e6864e6ea3374874598a01757464511 chrome.tabs.get(tabId, function(tab) { if (chrome.runtime.lastError) { resolve(false); -@@ -154,9 +155,13 @@ function tabInForeground(tabId) { +@@ -155,9 +156,13 @@ function tabInForeground(tabId) { resolve(false); return; } diff --git a/patches/chromium/chore_expose_v8_initialization_isolate_callbacks.patch b/patches/chromium/chore_expose_v8_initialization_isolate_callbacks.patch deleted file mode 100644 index a0affa82eec7a..0000000000000 --- a/patches/chromium/chore_expose_v8_initialization_isolate_callbacks.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Mon, 5 Oct 2020 13:43:59 -0700 -Subject: chore: expose v8 initialization isolate callbacks - -This commit is necessary in order to ensure consistent behavior from -v8 Isolate callbacks in contexts which Node.js does not control. If -we're running with contextIsolation enabled, we should be falling back -to Blink's logic. This will be upstreamed in some form. - -diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc -index 10f34d87d74d81de91cbd006665465cee6c0d21e..93f09cd74b225a8b0c2d2f5280636513e852e8ff 100644 ---- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc -+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc -@@ -446,8 +446,9 @@ CodeGenerationCheckCallbackInMainThread(v8::Local context, - return {true, std::move(stringified_source)}; - } - --bool V8Initializer::WasmCodeGenerationCheckCallbackInMainThread(v8::Local context, -- v8::Local source) { -+bool V8Initializer::WasmCodeGenerationCheckCallbackInMainThread( -+ v8::Local context, -+ v8::Local source) { - if (ExecutionContext* execution_context = ToExecutionContext(context)) { - if (ContentSecurityPolicy* policy = - execution_context->GetContentSecurityPolicy()) { -diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.h b/third_party/blink/renderer/bindings/core/v8/v8_initializer.h -index 932c6aad3df51dd6790e55bf708703767843dc5e..6865fd33e62f766c5a162ded8627c332bf2ed173 100644 ---- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.h -+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.h -@@ -69,8 +69,8 @@ class CORE_EXPORT V8Initializer { - static void MessageHandlerInWorker(v8::Local, - v8::Local); - static bool WasmCodeGenerationCheckCallbackInMainThread( -- v8::Local context, -- v8::Local source); -+ v8::Local context, -+ v8::Local source); - }; - - } // namespace blink diff --git a/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch b/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch index f9c57ed263f14..6a20c695f0e15 100644 --- a/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch +++ b/patches/chromium/chore_provide_iswebcontentscreationoverridden_with_full_params.patch @@ -35,7 +35,7 @@ index 5b4d70991e19edcdfee731c56251932bf43e535f..4d996e3821410b2325ef85499f8c307c #endif // CHROME_BROWSER_ANDROID_DOCUMENT_DOCUMENT_WEB_CONTENTS_DELEGATE_H_ diff --git a/chrome/browser/media/offscreen_tab.cc b/chrome/browser/media/offscreen_tab.cc -index 27452df45433e4aeb7b9008f8e5b91dd4b5f50db..5c6f9936e6d3d2647d7efbc70efda8551c5516c7 100644 +index 3289268d3ddb3fbb625b8498c2f84370c37acdff..89920af3e44257b6091bb558537fe07d2bb2d899 100644 --- a/chrome/browser/media/offscreen_tab.cc +++ b/chrome/browser/media/offscreen_tab.cc @@ -285,8 +285,7 @@ bool OffscreenTab::IsWebContentsCreationOverridden( @@ -49,7 +49,7 @@ index 27452df45433e4aeb7b9008f8e5b91dd4b5f50db..5c6f9936e6d3d2647d7efbc70efda855 // uses this to spawn new windows/tabs, which is also not allowed for // offscreen tabs. diff --git a/chrome/browser/media/offscreen_tab.h b/chrome/browser/media/offscreen_tab.h -index 88b68339823142f9b2b2d4730d6ebc1033ac86a3..e2d53e1b233adced355be667d006d5d2ba3d5110 100644 +index faa684c429e8cd5817c043db48dcbea33c6c8782..8b5991bc8279585cc0749f6816aa8a03a2c4e558 100644 --- a/chrome/browser/media/offscreen_tab.h +++ b/chrome/browser/media/offscreen_tab.h @@ -107,8 +107,7 @@ class OffscreenTab final : public ProfileObserver, @@ -63,10 +63,10 @@ index 88b68339823142f9b2b2d4730d6ebc1033ac86a3..e2d53e1b233adced355be667d006d5d2 content::RenderFrameHost* requesting_frame, const blink::mojom::FullscreenOptions& options) final; diff --git a/chrome/browser/ui/ash/ash_web_view_impl.cc b/chrome/browser/ui/ash/ash_web_view_impl.cc -index 4df94c57d6be19d6e76430391386e84d2816d94a..f1c0c6e8bec7ef17292c2a5a3b33800f402c889b 100644 +index a3083a16b1317cc58b87e13f30498bcf3e475eaf..50deda6f7ee9b2cbf57288d54a30a44022be808a 100644 --- a/chrome/browser/ui/ash/ash_web_view_impl.cc +++ b/chrome/browser/ui/ash/ash_web_view_impl.cc -@@ -77,10 +77,9 @@ bool AshWebViewImpl::IsWebContentsCreationOverridden( +@@ -96,10 +96,9 @@ bool AshWebViewImpl::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -80,10 +80,10 @@ index 4df94c57d6be19d6e76430391386e84d2816d94a..f1c0c6e8bec7ef17292c2a5a3b33800f /*from_user_gesture=*/true); return true; diff --git a/chrome/browser/ui/ash/ash_web_view_impl.h b/chrome/browser/ui/ash/ash_web_view_impl.h -index fd2bccf8f718683b55646ef200aaacc2df6ac485..b62b61fbcf4b8f1eff26546c5da020f88e4599fa 100644 +index f0333177f885000fb22818ffa30a0c4ad520a161..03e82957f9d7bf009dcbf5fcd43718c9d2ac9bb8 100644 --- a/chrome/browser/ui/ash/ash_web_view_impl.h +++ b/chrome/browser/ui/ash/ash_web_view_impl.h -@@ -46,8 +46,7 @@ class AshWebViewImpl : public ash::AshWebView, +@@ -47,8 +47,7 @@ class AshWebViewImpl : public ash::AshWebView, content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -94,7 +94,7 @@ index fd2bccf8f718683b55646ef200aaacc2df6ac485..b62b61fbcf4b8f1eff26546c5da020f8 content::WebContents* source, const content::OpenURLParams& params) override; diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc -index 6688ba8ba2fb7d930773144cdbc43f1f6fa2b685..22015c7b9b50e1264551ce226757f90e29191d8f 100644 +index 1318d5e04d5448d2b357454c3ce4207264288760..3b0324c35d5b18ed2e29264aae860c4887cdd382 100644 --- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc +++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc @@ -71,8 +71,7 @@ class ChromeKeyboardContentsDelegate : public content::WebContentsDelegate, @@ -108,10 +108,10 @@ index 6688ba8ba2fb7d930773144cdbc43f1f6fa2b685..22015c7b9b50e1264551ce226757f90e } diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc -index 04e327d970b872f0a9c505a0b99c6273900930f9..5993b3cb0cbe76cd266dee074effd736efa8fc50 100644 +index 244584b4df1fb85241212c44cca7da3e87c174f3..1e6239c111b0ea765388f384385789537f473237 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc -@@ -1767,12 +1767,11 @@ bool Browser::IsWebContentsCreationOverridden( +@@ -1811,12 +1811,11 @@ bool Browser::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -127,10 +127,10 @@ index 04e327d970b872f0a9c505a0b99c6273900930f9..5993b3cb0cbe76cd266dee074effd736 WebContents* Browser::CreateCustomWebContents( diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h -index a63ba24be314eb4372d7dda7206dee4b52730d1e..f9bcaa001bfed987edd0ebb001f5cda0e0aca4aa 100644 +index 38ee0d848089a4abefa357e47169da871753df6e..53332516617dc196ce21d674ab6987c6de8438e0 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h -@@ -808,8 +808,7 @@ class Browser : public TabStripModelObserver, +@@ -852,8 +852,7 @@ class Browser : public TabStripModelObserver, content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -183,7 +183,7 @@ index ed23267cd9f28f4e02d8374177f0bb697547cc2a..a979719f75ab4c9b49775ec3df5eff13 } content::WebContents* CreateCustomWebContents( diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc -index 1911b0558fad1d5834befa98e57a978e6e0b72da..cb85515f79617a32e2809ad6eb7f55e4ecc36b3f 100644 +index 1a6bbeea689901e23717d660e67f8d1abb21f799..85f7b42e7aadce3abcae9f9596403f9856771993 100644 --- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc +++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc @@ -170,14 +170,13 @@ bool WebContentsDelegateAndroid::IsWebContentsCreationOverridden( @@ -218,10 +218,10 @@ index 2930898b03d7b7ef86d13733cec3cbe84105c166..76625339f42a867c8b68840253e91648 void SetContentsBounds(content::WebContents* source, const gfx::Rect& bounds) override; diff --git a/components/offline_pages/content/background_loader/background_loader_contents.cc b/components/offline_pages/content/background_loader/background_loader_contents.cc -index 2834e3ee5778185741779a473cf5157788a76cc5..64fcddc952065e574a84edd99e5b1b80febd3d26 100644 +index 186711550a45f4bf383cdceeabac9e1f46aeca89..df1ecec4bf56de72a6164644d3094557a7a52896 100644 --- a/components/offline_pages/content/background_loader/background_loader_contents.cc +++ b/components/offline_pages/content/background_loader/background_loader_contents.cc -@@ -81,8 +81,7 @@ bool BackgroundLoaderContents::IsWebContentsCreationOverridden( +@@ -83,8 +83,7 @@ bool BackgroundLoaderContents::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -246,10 +246,10 @@ index c6bd5c19f8a7ceec17c9e32af5296a9617f3a619..02199b439fba7fdc617b7f7980d958b7 void AddNewContents(content::WebContents* source, std::unique_ptr new_contents, diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index 1734f93f7d06faf2c28d65d23bbc6c17f72e0b59..b19517ceafabde2ad88e83af97b9768b8a03fb60 100644 +index 47b85a2bd890485dec96e23fb2cb8f8553f5c4e2..7f04a05eec8780e735e0458c75103d9f2e9b858b 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -3873,8 +3873,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -3938,8 +3938,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( if (delegate_ && delegate_->IsWebContentsCreationOverridden( source_site_instance, params.window_container_type, @@ -260,7 +260,7 @@ index 1734f93f7d06faf2c28d65d23bbc6c17f72e0b59..b19517ceafabde2ad88e83af97b9768b static_cast(delegate_->CreateCustomWebContents( opener, source_site_instance, is_new_browsing_instance, diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc -index 7bb1680553c405a9016cfd67eca5fa3c6439b692..3aa2cca04340098859e1072eaa80a46a8e0463b1 100644 +index 3ddcc2d403a68fdc2b4b0246899cd9507ecc6195..eecc92f2ffce2c2eeb5fde977da6b94a29923b67 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc @@ -134,8 +134,7 @@ bool WebContentsDelegate::IsWebContentsCreationOverridden( @@ -274,10 +274,10 @@ index 7bb1680553c405a9016cfd67eca5fa3c6439b692..3aa2cca04340098859e1072eaa80a46a } diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h -index 3330876f623e5b2cb600b1ce1fd10b3375568613..a9f48c6577afef8876cd8304ff5a66405b7d8343 100644 +index 1ea3e1fdf067ea54ce54d31f494ac2bf42b2de3f..aa9af63f6d4708660496e5892f00766281be22c9 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h -@@ -318,8 +318,7 @@ class CONTENT_EXPORT WebContentsDelegate { +@@ -317,8 +317,7 @@ class CONTENT_EXPORT WebContentsDelegate { SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -288,10 +288,10 @@ index 3330876f623e5b2cb600b1ce1fd10b3375568613..a9f48c6577afef8876cd8304ff5a6640 // Allow delegate to creates a custom WebContents when // WebContents::CreateNewWindow() is called. This function is only called diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc -index ce83daee0eb44d72caaf1e7e250ce0c3fadb827c..ed0b508a5d6cdd4433a8117ef2032ce8e1d99273 100644 +index add3f3f73b1e44401b31330cd06f8c9211c62516..a64b0d6dac663b23e6cec32c2898ae88157ad602 100644 --- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc +++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc -@@ -213,8 +213,7 @@ bool ExtensionOptionsGuest::IsWebContentsCreationOverridden( +@@ -199,8 +199,7 @@ bool ExtensionOptionsGuest::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -302,7 +302,7 @@ index ce83daee0eb44d72caaf1e7e250ce0c3fadb827c..ed0b508a5d6cdd4433a8117ef2032ce8 // view is used for displaying embedded extension options, we want any // external links to be opened in a new tab, not in a new guest view so we diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.h b/extensions/browser/guest_view/extension_options/extension_options_guest.h -index 7350382146178f58960a9bf68cd959076d2d9790..a70a94d14bdfa993feab60b8e4f32e1002cf38cc 100644 +index f1c474143b087988b8084ad1bdf01b8ba80327e8..47ffb7d406eb04622fffce9f0671eddab4ff8fe3 100644 --- a/extensions/browser/guest_view/extension_options/extension_options_guest.h +++ b/extensions/browser/guest_view/extension_options/extension_options_guest.h @@ -58,8 +58,7 @@ class ExtensionOptionsGuest @@ -316,10 +316,10 @@ index 7350382146178f58960a9bf68cd959076d2d9790..a70a94d14bdfa993feab60b8e4f32e10 content::RenderFrameHost* opener, content::SiteInstance* source_site_instance, diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc -index 0b01120f6a6053ab03355c93216d703d0958aeab..a1c6c5a4b507bbf50668d7ed2febe97aca942c1d 100644 +index 75a2534e3be7102a221378afbfef3df8e6a8555e..495fc687379c6456384acc3a1864c5f0c49ad47f 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc -@@ -388,8 +388,7 @@ bool MimeHandlerViewGuest::IsWebContentsCreationOverridden( +@@ -399,8 +399,7 @@ bool MimeHandlerViewGuest::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -330,10 +330,10 @@ index 0b01120f6a6053ab03355c93216d703d0958aeab..a1c6c5a4b507bbf50668d7ed2febe97a } diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h -index ef6faf317dd4168adf6fd530a7da0b80f9166dec..f401659a81d4aeaf71039d71eb8fec4844497334 100644 +index 26dc86a7534d9296f1b1f772ec95f5313c61061c..925152a6c1fb645dfff5bd7238b620a8344de734 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h -@@ -171,8 +171,7 @@ class MimeHandlerViewGuest +@@ -170,8 +170,7 @@ class MimeHandlerViewGuest content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -343,11 +343,11 @@ index ef6faf317dd4168adf6fd530a7da0b80f9166dec..f401659a81d4aeaf71039d71eb8fec48 content::WebContents* CreateCustomWebContents( content::RenderFrameHost* opener, content::SiteInstance* source_site_instance, -diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc -index 424c5f89440dccc29f3431e034d0a4fd4f647a00..8d40d0bd30fc28e841eedb3f34be3c033db62449 100644 ---- a/fuchsia/engine/browser/frame_impl.cc -+++ b/fuchsia/engine/browser/frame_impl.cc -@@ -402,8 +402,7 @@ bool FrameImpl::IsWebContentsCreationOverridden( +diff --git a/fuchsia_web/webengine/browser/frame_impl.cc b/fuchsia_web/webengine/browser/frame_impl.cc +index b9e21613a8ae3409477d659b0e12181e4db015c3..9d454bd8f8bde3624dd28f8effc0b7fc8a2b4f41 100644 +--- a/fuchsia_web/webengine/browser/frame_impl.cc ++++ b/fuchsia_web/webengine/browser/frame_impl.cc +@@ -412,8 +412,7 @@ bool FrameImpl::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -357,11 +357,11 @@ index 424c5f89440dccc29f3431e034d0a4fd4f647a00..8d40d0bd30fc28e841eedb3f34be3c03 // Specify a generous upper bound for unacknowledged popup windows, so that we // can catch bad client behavior while not interfering with normal operation. constexpr size_t kMaxPendingWebContentsCount = 10; -diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h -index f2054bca778784c223beb02de150cfeb31c52907..53bf6bc205e9c631597bfbda46f4a0b5b4bb72ed 100644 ---- a/fuchsia/engine/browser/frame_impl.h -+++ b/fuchsia/engine/browser/frame_impl.h -@@ -307,8 +307,7 @@ class FrameImpl : public fuchsia::web::Frame, +diff --git a/fuchsia_web/webengine/browser/frame_impl.h b/fuchsia_web/webengine/browser/frame_impl.h +index 0661fd642dcee69a7c8f955490dadf32dc0eb468..e3fa74da87513fbfcd035fa872dc938db96c2766 100644 +--- a/fuchsia_web/webengine/browser/frame_impl.h ++++ b/fuchsia_web/webengine/browser/frame_impl.h +@@ -310,8 +310,7 @@ class WEB_ENGINE_EXPORT FrameImpl : public fuchsia::web::Frame, content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -372,10 +372,10 @@ index f2054bca778784c223beb02de150cfeb31c52907..53bf6bc205e9c631597bfbda46f4a0b5 int opener_render_process_id, int opener_render_frame_id, diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc -index 2214ba7726f105e62bdc92bd0e6142ea9fa6ed72..2b9b804106317bfc914efacc7adfd282563e4c8b 100644 +index aa488570851f68e892b024c901f31b658929fc72..efe6a6bc939a6bdea0eaca65e12242e23f3e6d59 100644 --- a/headless/lib/browser/headless_web_contents_impl.cc +++ b/headless/lib/browser/headless_web_contents_impl.cc -@@ -176,8 +176,7 @@ class HeadlessWebContentsImpl::Delegate : public content::WebContentsDelegate { +@@ -179,8 +179,7 @@ class HeadlessWebContentsImpl::Delegate : public content::WebContentsDelegate { content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, @@ -386,10 +386,10 @@ index 2214ba7726f105e62bdc92bd0e6142ea9fa6ed72..2b9b804106317bfc914efacc7adfd282 ->options() ->block_new_web_contents(); diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc -index 1c3eebdc2cc3f5d8f110562eb3e18a1f45521c4f..11b7b0c6617c40c766d64cd0d4e60d22e569bfb1 100644 +index fb5239100bdc35d2d5cf47765c1bf1b285b20cf5..b4b2609ddbe0a0adfccffb4f4a0a56849579dd2d 100644 --- a/ui/views/controls/webview/web_dialog_view.cc +++ b/ui/views/controls/webview/web_dialog_view.cc -@@ -426,8 +426,7 @@ bool WebDialogView::IsWebContentsCreationOverridden( +@@ -427,8 +427,7 @@ bool WebDialogView::IsWebContentsCreationOverridden( content::SiteInstance* source_site_instance, content::mojom::WindowContainerType window_container_type, const GURL& opener_url, diff --git a/patches/chromium/chore_use_electron_resources_not_chrome_for_spellchecker.patch b/patches/chromium/chore_use_electron_resources_not_chrome_for_spellchecker.patch deleted file mode 100644 index edcaa6164cf93..0000000000000 --- a/patches/chromium/chore_use_electron_resources_not_chrome_for_spellchecker.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Attard -Date: Wed, 23 Oct 2019 14:17:18 -0700 -Subject: chore: use electron resources not chrome for spellchecker - -spellchecker uses a few IDS_ resources. We need to load these from -Electrons grit header instead of Chromes - -diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn -index 9917fcf771ecbfceaba4c02164de620d2aaf0775..492cd8e11e28e0b427aca227665295a3052af765 100644 ---- a/chrome/browser/BUILD.gn -+++ b/chrome/browser/BUILD.gn -@@ -7088,6 +7088,7 @@ static_library("browser") { - deps += [ - "//components/spellcheck/browser", - "//components/spellcheck/common", -+ "//electron:resources", - ] - - if (!is_android) { -diff --git a/chrome/browser/spellchecker/spellcheck_factory.cc b/chrome/browser/spellchecker/spellcheck_factory.cc -index 7c3b6a69acb16186add5d467dbc22360d90d46d4..703e2ce60f4f35f9c71e8b503ffd62f9ea8f365a 100644 ---- a/chrome/browser/spellchecker/spellcheck_factory.cc -+++ b/chrome/browser/spellchecker/spellcheck_factory.cc -@@ -7,7 +7,7 @@ - #include "build/build_config.h" - #include "chrome/browser/profiles/incognito_helpers.h" - #include "chrome/browser/spellchecker/spellcheck_service.h" --#include "chrome/grit/locale_settings.h" -+#include "electron/grit/electron_resources.h" - #include "components/keyed_service/content/browser_context_dependency_manager.h" - #include "components/pref_registry/pref_registry_syncable.h" - #include "components/prefs/pref_service.h" -diff --git a/components/language/core/browser/BUILD.gn b/components/language/core/browser/BUILD.gn -index fdba4ca90882656d6ba369dae48d5dfc13991cb8..fb3b759362275aafd4ed01a7865a4dd0dfaad727 100644 ---- a/components/language/core/browser/BUILD.gn -+++ b/components/language/core/browser/BUILD.gn -@@ -30,6 +30,7 @@ static_library("browser") { - "//components/pref_registry", - "//components/prefs", - "//components/strings", -+ "//electron:resources", - "//ui/base", - ] - } -diff --git a/components/language/core/browser/language_prefs.cc b/components/language/core/browser/language_prefs.cc -index 26f86d67c32b2a022698ae5ea5509912d2ccfacb..d48844d49308d67ee7bfa823335c7443173badbe 100644 ---- a/components/language/core/browser/language_prefs.cc -+++ b/components/language/core/browser/language_prefs.cc -@@ -22,7 +22,7 @@ - #include "components/pref_registry/pref_registry_syncable.h" - #include "components/prefs/pref_service.h" - #include "components/prefs/scoped_user_pref_update.h" --#include "components/strings/grit/components_locale_settings.h" -+#include "electron/grit/electron_resources.h" - #include "ui/base/l10n/l10n_util.h" - - namespace language { diff --git a/patches/chromium/chrome_key_systems.patch b/patches/chromium/chrome_key_systems.patch index e1eba13e55ffa..9dd19626a1871 100644 --- a/patches/chromium/chrome_key_systems.patch +++ b/patches/chromium/chrome_key_systems.patch @@ -7,7 +7,7 @@ Disable persiste licence support check for widevine cdm, as its not supported in the current version of chrome. diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc -index 0cdaa37db5a4c992c8051a6e4370f61b3e4559a3..58108239e1b5aad967eff63d8eed10a560726c6e 100644 +index 30da015cffeb945973d0045ce297467ab16d7db6..53e7bd0f7dbff8c620a5827abb3ba871703a4f06 100644 --- a/chrome/renderer/media/chrome_key_systems.cc +++ b/chrome/renderer/media/chrome_key_systems.cc @@ -17,7 +17,9 @@ @@ -20,18 +20,18 @@ index 0cdaa37db5a4c992c8051a6e4370f61b3e4559a3..58108239e1b5aad967eff63d8eed10a5 #include "components/cdm/renderer/external_clear_key_key_system_properties.h" #include "components/cdm/renderer/widevine_key_system_properties.h" #include "content/public/renderer/render_thread.h" -@@ -230,12 +232,14 @@ SupportedCodecs GetSupportedCodecs(const media::CdmCapability& capability) { +@@ -235,12 +237,14 @@ SupportedCodecs GetSupportedCodecs(const media::CdmCapability& capability) { - // Returns persistent-license session support. - EmeSessionTypeSupport GetPersistentLicenseSupport(bool supported_by_the_cdm) { + // Returns whether persistent-license session can be supported. + bool CanSupportPersistentLicense() { +#if 0 // Do not support persistent-license if the process cannot persist data. // TODO(crbug.com/457487): Have a better plan on this. See bug for details. if (ChromeRenderThreadObserver::is_incognito_process()) { DVLOG(2) << __func__ << ": Not supported in incognito process."; - return EmeSessionTypeSupport::NOT_SUPPORTED; + return false; } +#endif - if (!supported_by_the_cdm) { - DVLOG(2) << __func__ << ": Not supported by the CDM."; + // On ChromeOS, platform verification is similar to CDM host verification. + #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) || BUILDFLAG(IS_CHROMEOS) diff --git a/patches/chromium/command-ismediakey.patch b/patches/chromium/command-ismediakey.patch index 3a7e3c694cc04..b52c74a4d8775 100644 --- a/patches/chromium/command-ismediakey.patch +++ b/patches/chromium/command-ismediakey.patch @@ -52,10 +52,10 @@ index ed2ac20679a9357c9493224ec5e08837c7860d6e..7f9a97e11395e5521e100694cd37bcd9 NotifyKeyPressed(ui::Accelerator(key_code, modifiers)); } diff --git a/chrome/browser/extensions/global_shortcut_listener_ozone.h b/chrome/browser/extensions/global_shortcut_listener_ozone.h -index eb3f3431a3774c3a05afd4c7350f3801e9c8c684..b8970ef9ddb69d6a9fc6d106293e760535b6f4b3 100644 +index a2cec20e0ba434afa5e15bf60327c6a6f9b551f9..f58796ff2050883879225a22ed0b3f0c1aacf824 100644 --- a/chrome/browser/extensions/global_shortcut_listener_ozone.h +++ b/chrome/browser/extensions/global_shortcut_listener_ozone.h -@@ -45,7 +45,8 @@ class GlobalShortcutListenerOzone +@@ -46,7 +46,8 @@ class GlobalShortcutListenerOzone void OnKeyPressed(ui::KeyboardCode key_code, bool is_alt_down, bool is_ctrl_down, @@ -66,7 +66,7 @@ index eb3f3431a3774c3a05afd4c7350f3801e9c8c684..b8970ef9ddb69d6a9fc6d106293e7605 bool is_listening_ = false; diff --git a/chrome/browser/extensions/global_shortcut_listener_win.cc b/chrome/browser/extensions/global_shortcut_listener_win.cc -index 0f344ee352a48497e77a72bb298146c61e7fcf2a..3bad4263ea552fc63445bf5613f8add746a3a374 100644 +index 2778a18b6c28f3342c6b43d1de71fbbd46c72f06..85af551f87b8b0f9aed7a2a395ecf79f81f5a0a1 100644 --- a/chrome/browser/extensions/global_shortcut_listener_win.cc +++ b/chrome/browser/extensions/global_shortcut_listener_win.cc @@ -62,6 +62,8 @@ void GlobalShortcutListenerWin::OnWndProc(HWND hwnd, @@ -87,10 +87,10 @@ index 0f344ee352a48497e77a72bb298146c61e7fcf2a..3bad4263ea552fc63445bf5613f8add7 // Create an observer that registers a hot key for |accelerator|. std::unique_ptr observer = diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc -index 4e9e4f4d21fbe650d8f32254a3b450074a038751..ac923f436cbdd6ded0629da4e4c659d94258e55b 100644 +index 3f37f08ccc06137317164e96e8934a0202fa5550..b954f8dde00d4f5257223c464e9145a6bef48900 100644 --- a/content/browser/media/media_keys_listener_manager_impl.cc +++ b/content/browser/media/media_keys_listener_manager_impl.cc -@@ -296,6 +296,11 @@ void MediaKeysListenerManagerImpl::UpdateSystemMediaControlsEnabledControls() { +@@ -297,6 +297,11 @@ void MediaKeysListenerManagerImpl::UpdateSystemMediaControlsEnabledControls() { case ui::VKEY_MEDIA_STOP: system_media_controls_->SetIsStopEnabled(should_enable); break; @@ -117,10 +117,10 @@ index 1145e1f3d79482b5bb468c3128431ac674310e5f..e9f595045e0c076e0735f27dfc38bfbc } // namespace ui diff --git a/ui/base/accelerators/media_keys_listener_mac.mm b/ui/base/accelerators/media_keys_listener_mac.mm -index ada705fb42e88d4bfa05b212c84111be9057a50e..a866b975687dd08ad88031a63f161b3164e82455 100644 +index 87a53282aa3afa3fe8469272d8b1ee37dcadf845..55c36da933165c8f86dd2ab440733f4b20bee378 100644 --- a/ui/base/accelerators/media_keys_listener_mac.mm +++ b/ui/base/accelerators/media_keys_listener_mac.mm -@@ -32,6 +32,12 @@ KeyboardCode MediaKeyCodeToKeyboardCode(int key_code) { +@@ -34,6 +34,12 @@ KeyboardCode MediaKeyCodeToKeyboardCode(int key_code) { case NX_KEYTYPE_NEXT: case NX_KEYTYPE_FAST: return VKEY_MEDIA_NEXT_TRACK; @@ -133,7 +133,7 @@ index ada705fb42e88d4bfa05b212c84111be9057a50e..a866b975687dd08ad88031a63f161b31 } return VKEY_UNKNOWN; } -@@ -192,7 +198,10 @@ static CGEventRef EventTapCallback(CGEventTapProxy proxy, +@@ -194,7 +200,10 @@ static CGEventRef EventTapCallback(CGEventTapProxy proxy, int key_code = (data1 & 0xFFFF0000) >> 16; if (key_code != NX_KEYTYPE_PLAY && key_code != NX_KEYTYPE_NEXT && key_code != NX_KEYTYPE_PREVIOUS && key_code != NX_KEYTYPE_FAST && @@ -146,10 +146,10 @@ index ada705fb42e88d4bfa05b212c84111be9057a50e..a866b975687dd08ad88031a63f161b31 } diff --git a/ui/base/x/x11_global_shortcut_listener.cc b/ui/base/x/x11_global_shortcut_listener.cc -index a772666160a71e8e31242e25a8f3383ad9b914bf..7ed78ff875ccf9c38a480d0d59f4688ada1a3ad3 100644 +index 898e15a25c99ad25221c41594803521565ff4432..664337941023e800c9605f987d0e1d65bb0a444d 100644 --- a/ui/base/x/x11_global_shortcut_listener.cc +++ b/ui/base/x/x11_global_shortcut_listener.cc -@@ -32,11 +32,13 @@ const x11::ModMask kModifiersMasks[] = { +@@ -31,11 +31,13 @@ const x11::ModMask kModifiersMasks[] = { x11::ModMask GetNativeModifiers(bool is_alt_down, bool is_ctrl_down, @@ -165,7 +165,7 @@ index a772666160a71e8e31242e25a8f3383ad9b914bf..7ed78ff875ccf9c38a480d0d59f4688a } } // namespace -@@ -82,8 +84,9 @@ uint32_t XGlobalShortcutListener::DispatchEvent(const PlatformEvent& event) { +@@ -81,8 +83,9 @@ uint32_t XGlobalShortcutListener::DispatchEvent(const PlatformEvent& event) { bool XGlobalShortcutListener::RegisterAccelerator(KeyboardCode key_code, bool is_alt_down, bool is_ctrl_down, @@ -177,7 +177,7 @@ index a772666160a71e8e31242e25a8f3383ad9b914bf..7ed78ff875ccf9c38a480d0d59f4688a auto keysym = XKeysymForWindowsKeyCode(key_code, false); auto keycode = connection_->KeysymToKeycode(keysym); -@@ -108,7 +111,7 @@ bool XGlobalShortcutListener::RegisterAccelerator(KeyboardCode key_code, +@@ -107,7 +110,7 @@ bool XGlobalShortcutListener::RegisterAccelerator(KeyboardCode key_code, } registered_combinations_.insert( @@ -186,7 +186,7 @@ index a772666160a71e8e31242e25a8f3383ad9b914bf..7ed78ff875ccf9c38a480d0d59f4688a return true; } -@@ -116,8 +119,9 @@ bool XGlobalShortcutListener::RegisterAccelerator(KeyboardCode key_code, +@@ -115,8 +118,9 @@ bool XGlobalShortcutListener::RegisterAccelerator(KeyboardCode key_code, void XGlobalShortcutListener::UnregisterAccelerator(KeyboardCode key_code, bool is_alt_down, bool is_ctrl_down, @@ -198,7 +198,7 @@ index a772666160a71e8e31242e25a8f3383ad9b914bf..7ed78ff875ccf9c38a480d0d59f4688a auto keysym = XKeysymForWindowsKeyCode(key_code, false); auto keycode = connection_->KeysymToKeycode(keysym); -@@ -125,7 +129,7 @@ void XGlobalShortcutListener::UnregisterAccelerator(KeyboardCode key_code, +@@ -124,7 +128,7 @@ void XGlobalShortcutListener::UnregisterAccelerator(KeyboardCode key_code, connection_->UngrabKey({keycode, x_root_window_, modifiers | mask}); registered_combinations_.erase( @@ -207,7 +207,7 @@ index a772666160a71e8e31242e25a8f3383ad9b914bf..7ed78ff875ccf9c38a480d0d59f4688a } void XGlobalShortcutListener::OnKeyPressEvent(const KeyEvent& event) { -@@ -135,14 +139,15 @@ void XGlobalShortcutListener::OnKeyPressEvent(const KeyEvent& event) { +@@ -134,14 +138,15 @@ void XGlobalShortcutListener::OnKeyPressEvent(const KeyEvent& event) { const bool is_alt_down = event.flags() & EF_ALT_DOWN; const bool is_ctrl_down = event.flags() & EF_CONTROL_DOWN; const bool is_shift_down = event.flags() & EF_SHIFT_DOWN; @@ -226,10 +226,10 @@ index a772666160a71e8e31242e25a8f3383ad9b914bf..7ed78ff875ccf9c38a480d0d59f4688a } // namespace ui diff --git a/ui/base/x/x11_global_shortcut_listener.h b/ui/base/x/x11_global_shortcut_listener.h -index 9e472d76423a748cbf6257c6656d8fd69853dd93..404a294b9cf3dd6744ece0b5c1e611bbab207e78 100644 +index bfb82e38a9ccc7459ccb427d512df821517a328b..7f1d5876a51fa53e539b2bab8d2f020f26d39ceb 100644 --- a/ui/base/x/x11_global_shortcut_listener.h +++ b/ui/base/x/x11_global_shortcut_listener.h -@@ -40,18 +40,21 @@ class COMPONENT_EXPORT(UI_BASE_X) XGlobalShortcutListener +@@ -41,18 +41,21 @@ class COMPONENT_EXPORT(UI_BASE_X) XGlobalShortcutListener virtual void OnKeyPressed(KeyboardCode key_code, bool is_alt_down, bool is_ctrl_down, @@ -254,7 +254,7 @@ index 9e472d76423a748cbf6257c6656d8fd69853dd93..404a294b9cf3dd6744ece0b5c1e611bb private: // Due to how system key grabbing works on X11, we have to be a bit greedy and -@@ -60,7 +63,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XGlobalShortcutListener +@@ -61,7 +64,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XGlobalShortcutListener // and filter the incoming events against that registry before notifying the // observer. This tuple describes the meaningful parts of the event; booleans // 1, 2, and 3 hold states of Alt, Control, and Shift keys, respectively. @@ -333,10 +333,10 @@ index 0f1980abdcaf30e23f580b937ecb2c422bf2a357..112967622cb8a6263c7a88dd8d09f48f } // namespace ui diff --git a/ui/ozone/public/platform_global_shortcut_listener.h b/ui/ozone/public/platform_global_shortcut_listener.h -index a5b539d4e7461c4ca9faa08fef086fc28a4ebd3a..f3aacc605f07807a5b83b496bd8a87933981d4f3 100644 +index 5b6ceb2e23d306e446cad5a6b6e7adf37334410a..d4fbca17a11bd52deaf746e052eeeb12d8a4594e 100644 --- a/ui/ozone/public/platform_global_shortcut_listener.h +++ b/ui/ozone/public/platform_global_shortcut_listener.h -@@ -19,7 +19,8 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformGlobalShortcutListenerDelegate { +@@ -20,7 +20,8 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformGlobalShortcutListenerDelegate { virtual void OnKeyPressed(KeyboardCode key_code, bool is_alt_down, bool is_ctrl_down, @@ -346,7 +346,7 @@ index a5b539d4e7461c4ca9faa08fef086fc28a4ebd3a..f3aacc605f07807a5b83b496bd8a8793 // Called back when the platform implementation is destroyed. virtual void OnPlatformListenerDestroyed() = 0; -@@ -51,11 +52,13 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformGlobalShortcutListener { +@@ -52,11 +53,13 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformGlobalShortcutListener { virtual bool RegisterAccelerator(KeyboardCode key_code, bool is_alt_down, bool is_ctrl_down, diff --git a/patches/chromium/crash_allow_disabling_compression_on_linux.patch b/patches/chromium/crash_allow_disabling_compression_on_linux.patch index 6f4a3b926bbc6..d61b71b8cfd92 100644 --- a/patches/chromium/crash_allow_disabling_compression_on_linux.patch +++ b/patches/chromium/crash_allow_disabling_compression_on_linux.patch @@ -13,10 +13,10 @@ Ultimately we should remove the option to disable compression, and subsequently remove this patch. diff --git a/components/crash/core/app/breakpad_linux.cc b/components/crash/core/app/breakpad_linux.cc -index 8df14f416ee321e1259433715a61fa6025207d80..1d7f38d3f89d9c7f110cc9eb880264464787eb32 100644 +index 62d15f57e4c5a0a24aa730e8979fb1e9537fecd3..77fd14f5e9a4330364da4e7e5ee089c9196b4939 100644 --- a/components/crash/core/app/breakpad_linux.cc +++ b/components/crash/core/app/breakpad_linux.cc -@@ -110,6 +110,8 @@ void SetUploadURL(const std::string& url) { +@@ -111,6 +111,8 @@ void SetUploadURL(const std::string& url) { DCHECK(!g_upload_url); g_upload_url = strdup(url.c_str()); } @@ -25,9 +25,9 @@ index 8df14f416ee321e1259433715a61fa6025207d80..1d7f38d3f89d9c7f110cc9eb88026446 #endif bool g_is_node = false; -@@ -1322,56 +1324,60 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info, +@@ -1324,56 +1326,60 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info, - #else // BUILDFLAG(IS_CHROMEOS_ASH) + #else // BUILDFLAG(IS_CHROMEOS) - // Compress |dumpfile| with gzip. - const pid_t gzip_child = sys_fork(); @@ -127,7 +127,7 @@ index 8df14f416ee321e1259433715a61fa6025207d80..1d7f38d3f89d9c7f110cc9eb88026446 static const char header_msg[] = "--header=Content-Type: multipart/form-data; boundary="; const size_t header_content_type_size = -@@ -1398,7 +1404,8 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info, +@@ -1400,7 +1406,8 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info, static const char kWgetBinary[] = "/usr/bin/wget"; const char* args[] = { kWgetBinary, @@ -137,9 +137,9 @@ index 8df14f416ee321e1259433715a61fa6025207d80..1d7f38d3f89d9c7f110cc9eb88026446 header_content_type, post_file, g_upload_url, -@@ -2039,6 +2046,7 @@ void InitCrashReporter(const std::string& process_type) { +@@ -2041,6 +2048,7 @@ void InitCrashReporter(const std::string& process_type) { - #if !BUILDFLAG(IS_CHROMEOS_ASH) + #if !BUILDFLAG(IS_CHROMEOS) SetUploadURL(GetCrashReporterClient()->GetUploadUrl()); + g_compress_uploads = GetCrashReporterClient()->GetShouldCompressUploads(); #endif diff --git a/patches/chromium/crash_allow_setting_more_options.patch b/patches/chromium/crash_allow_setting_more_options.patch index c16edea8ac147..0d5a296c8366a 100644 --- a/patches/chromium/crash_allow_setting_more_options.patch +++ b/patches/chromium/crash_allow_setting_more_options.patch @@ -9,10 +9,10 @@ rate-limiting, compression and global annotations. This should be upstreamed. diff --git a/components/crash/core/app/breakpad_linux.cc b/components/crash/core/app/breakpad_linux.cc -index 823e49a234e3dd31bf6527c2e4efa96f3d23f1f2..43f6d476f3ee2759cf41c492f932522994e7ddec 100644 +index 6aa864db880408bf7021ac58673f4d8d489426b4..1fa85302da7a64abc42fd9558ddbcaf68b387517 100644 --- a/components/crash/core/app/breakpad_linux.cc +++ b/components/crash/core/app/breakpad_linux.cc -@@ -112,6 +112,7 @@ void SetUploadURL(const std::string& url) { +@@ -113,6 +113,7 @@ void SetUploadURL(const std::string& url) { } #endif @@ -21,10 +21,10 @@ index 823e49a234e3dd31bf6527c2e4efa96f3d23f1f2..43f6d476f3ee2759cf41c492f9325229 uint64_t g_process_start_time = 0; pid_t g_pid = 0; diff --git a/components/crash/core/app/crash_reporter_client.cc b/components/crash/core/app/crash_reporter_client.cc -index 82b7f241e26184240260d0b6287ded159681e15b..abbb267f6a40de0cdf4d09700f9dd444a575fbdf 100644 +index 463f92a6e547006a46119f52203482dd6695a84a..34e6f087613d76947ae463fda2b107fad6ec14e9 100644 --- a/components/crash/core/app/crash_reporter_client.cc +++ b/components/crash/core/app/crash_reporter_client.cc -@@ -141,6 +141,17 @@ bool CrashReporterClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) { +@@ -145,6 +145,17 @@ bool CrashReporterClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) { return false; } @@ -43,7 +43,7 @@ index 82b7f241e26184240260d0b6287ded159681e15b..abbb267f6a40de0cdf4d09700f9dd444 unsigned int CrashReporterClient::GetCrashDumpPercentage() { return 100; diff --git a/components/crash/core/app/crash_reporter_client.h b/components/crash/core/app/crash_reporter_client.h -index 24e53fa62c2c4a11494ad3d43f0c5a806930fcdd..9b691baa6cc90cc3f9ada307c43f44c4353e2487 100644 +index 2532e99f00b39777cd9640c76704f7430d39502e..323e039e4591a4099b187f7a0097b4ee8be11a9f 100644 --- a/components/crash/core/app/crash_reporter_client.h +++ b/components/crash/core/app/crash_reporter_client.h @@ -5,6 +5,7 @@ @@ -54,7 +54,7 @@ index 24e53fa62c2c4a11494ad3d43f0c5a806930fcdd..9b691baa6cc90cc3f9ada307c43f44c4 #include #include "build/build_config.h" -@@ -146,6 +147,19 @@ class CrashReporterClient { +@@ -151,6 +152,19 @@ class CrashReporterClient { // that case, |breakpad_enabled| is set to the value enforced by policies. virtual bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled); @@ -75,10 +75,10 @@ index 24e53fa62c2c4a11494ad3d43f0c5a806930fcdd..9b691baa6cc90cc3f9ada307c43f44c4 // Used by WebView to sample crashes without generating the unwanted dumps. If // the returned value is less than 100, crash dumping will be sampled to that diff --git a/components/crash/core/app/crashpad_linux.cc b/components/crash/core/app/crashpad_linux.cc -index dc2b18b322350121768571b7997d632a10220ac9..3e3ee0f721a2316d324fb31e17ba97ff24d9e6d7 100644 +index a80a792f1cb2c996b77443a3383663b4687ae044..2b1453353ce93632b378d4b25295b5cb14df9b2c 100644 --- a/components/crash/core/app/crashpad_linux.cc +++ b/components/crash/core/app/crashpad_linux.cc -@@ -180,6 +180,7 @@ bool PlatformCrashpadInitialization( +@@ -170,6 +170,7 @@ bool PlatformCrashpadInitialization( // where crash_reporter provides it's own values for lsb-release. annotations["lsb-release"] = base::GetLinuxDistro(); #endif @@ -86,7 +86,7 @@ index dc2b18b322350121768571b7997d632a10220ac9..3e3ee0f721a2316d324fb31e17ba97ff std::vector arguments; if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) { -@@ -201,6 +202,13 @@ bool PlatformCrashpadInitialization( +@@ -191,6 +192,13 @@ bool PlatformCrashpadInitialization( } #endif @@ -97,9 +97,9 @@ index dc2b18b322350121768571b7997d632a10220ac9..3e3ee0f721a2316d324fb31e17ba97ff + arguments.push_back("--no-upload-gzip"); + } + - bool result = - client.StartHandler(handler_path, *database_path, metrics_path, url, - annotations, arguments, false, false); + CHECK(client.StartHandler(handler_path, *database_path, metrics_path, url, + annotations, arguments, false, false)); + } else { diff --git a/components/crash/core/app/crashpad_mac.mm b/components/crash/core/app/crashpad_mac.mm index dc041c43371fd58e3121ef6bc423aadb644bb8d0..a1fa566775724b4a1662a939fda3f0a59bf46b96 100644 --- a/components/crash/core/app/crashpad_mac.mm @@ -128,10 +128,10 @@ index dc041c43371fd58e3121ef6bc423aadb644bb8d0..a1fa566775724b4a1662a939fda3f0a5 arguments.push_back("--monitor-self"); } diff --git a/components/crash/core/app/crashpad_win.cc b/components/crash/core/app/crashpad_win.cc -index 1a8f42cb4e2ea493642d8b264d0be5c3da358793..e972272de54107aaed6143e3f3569ba56bd3cf3e 100644 +index ae8801a7fc877241313de84a6ae0698d4f2adf69..9ae249bfe41da9743adc7f60d69be0f003ca31e2 100644 --- a/components/crash/core/app/crashpad_win.cc +++ b/components/crash/core/app/crashpad_win.cc -@@ -89,6 +89,7 @@ bool PlatformCrashpadInitialization( +@@ -91,6 +91,7 @@ bool PlatformCrashpadInitialization( std::map process_annotations; GetPlatformCrashpadAnnotations(&process_annotations); @@ -139,7 +139,7 @@ index 1a8f42cb4e2ea493642d8b264d0be5c3da358793..e972272de54107aaed6143e3f3569ba5 std::string url = crash_reporter_client->GetUploadUrl(); -@@ -127,6 +128,13 @@ bool PlatformCrashpadInitialization( +@@ -129,6 +130,13 @@ bool PlatformCrashpadInitialization( std::vector arguments(start_arguments); diff --git a/patches/chromium/crashpad_pid_check.patch b/patches/chromium/crashpad_pid_check.patch index 597472b3ec79d..5560d4b3ec9f8 100644 --- a/patches/chromium/crashpad_pid_check.patch +++ b/patches/chromium/crashpad_pid_check.patch @@ -16,7 +16,7 @@ https://github.com/electron/electron/pull/18483#discussion_r292703588 https://github.com/electron/electron/pull/18483#issuecomment-501090683 diff --git a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc -index 92d5c5d47cfa5bd70300bb8bbc16ab944cd93509..87c14718221a83d531d15abf1f1d2d1bbc020e77 100644 +index 6890a01cc4b333927be6c36ff3392706020f57a3..36da005deed5893989585427216fd1e16d5e9f0c 100644 --- a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc +++ b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc @@ -446,9 +446,16 @@ bool ExceptionHandlerServer::ServiceClientConnection( diff --git a/patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch b/patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch new file mode 100644 index 0000000000000..5eaff40c1c9ca --- /dev/null +++ b/patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ryan Manuel +Date: Thu, 4 Aug 2022 22:37:01 -0500 +Subject: Create browser v8 snapshot file name fuse + +By default, chromium sets up one v8 snapshot to be used in all v8 contexts. This patch allows consumers +to have a dedicated browser process v8 snapshot defined by the file `browser_v8_context_snapshot.bin`. + +diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc +index 14ca983c91cfe495ebd2859866a7f434d0a9ab02..a3e5764a1920c8a6bf1ce21e02d0ac743b027a40 100644 +--- a/content/app/content_main_runner_impl.cc ++++ b/content/app/content_main_runner_impl.cc +@@ -37,6 +37,7 @@ + #include "base/process/memory.h" + #include "base/process/process.h" + #include "base/process/process_handle.h" ++#include "base/strings/string_piece.h" + #include "base/strings/string_number_conversions.h" + #include "base/strings/string_util.h" + #include "base/task/thread_pool/thread_pool_instance.h" +@@ -232,8 +233,13 @@ std::string GetSnapshotDataDescriptor(const base::CommandLine& command_line) { + + #endif + +-void LoadV8SnapshotFile(const base::CommandLine& command_line) { ++void LoadV8SnapshotFile(const raw_ptr delegate, const base::CommandLine& command_line) { + const gin::V8SnapshotFileType snapshot_type = GetSnapshotType(command_line); ++ base::StringPiece browser_v8_snapshot_file_name = delegate->GetBrowserV8SnapshotFilename(); ++ if (!browser_v8_snapshot_file_name.empty()) { ++ gin::V8Initializer::LoadV8SnapshotFromFileName(browser_v8_snapshot_file_name, snapshot_type); ++ return; ++ } + #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) + base::FileDescriptorStore& file_descriptor_store = + base::FileDescriptorStore::GetInstance(); +@@ -262,11 +268,12 @@ bool ShouldLoadV8Snapshot(const base::CommandLine& command_line, + + #endif // V8_USE_EXTERNAL_STARTUP_DATA + +-void LoadV8SnapshotIfNeeded(const base::CommandLine& command_line, ++void LoadV8SnapshotIfNeeded(const raw_ptr delegate, ++ const base::CommandLine& command_line, + const std::string& process_type) { + #if defined(V8_USE_EXTERNAL_STARTUP_DATA) + if (ShouldLoadV8Snapshot(command_line, process_type)) +- LoadV8SnapshotFile(command_line); ++ LoadV8SnapshotFile(delegate, command_line); + #endif // V8_USE_EXTERNAL_STARTUP_DATA + } + +@@ -925,7 +932,7 @@ int ContentMainRunnerImpl::Initialize(ContentMainParams params) { + return TerminateForFatalInitializationError(); + #endif // BUILDFLAG(IS_ANDROID) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) + +- LoadV8SnapshotIfNeeded(command_line, process_type); ++ LoadV8SnapshotIfNeeded(delegate_, command_line, process_type); + + blink::TrialTokenValidator::SetOriginTrialPolicyGetter( + base::BindRepeating([]() -> blink::OriginTrialPolicy* { +diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc +index 5450eb6ba565164953b778f861d8fc75a06b6115..3f15d5a83d6e8011da09da178a0a9dfd2dd95d30 100644 +--- a/content/public/app/content_main_delegate.cc ++++ b/content/public/app/content_main_delegate.cc +@@ -5,6 +5,7 @@ + #include "content/public/app/content_main_delegate.h" + + #include "base/check.h" ++#include "base/strings/string_piece.h" + #include "build/build_config.h" + #include "content/public/browser/content_browser_client.h" + #include "content/public/common/content_client.h" +@@ -83,6 +84,10 @@ absl::optional ContentMainDelegate::PostEarlyInitialization( + return absl::nullopt; + } + ++base::StringPiece ContentMainDelegate::GetBrowserV8SnapshotFilename() { ++ return base::StringPiece(); ++} ++ + ContentClient* ContentMainDelegate::CreateContentClient() { + return new ContentClient(); + } +diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h +index f40146c4ed20e63dd09450e43c26736171f02ed4..5e3246a1346bd0210e7b83842a17dcc1986c8647 100644 +--- a/content/public/app/content_main_delegate.h ++++ b/content/public/app/content_main_delegate.h +@@ -9,6 +9,7 @@ + #include + #include + ++#include "base/strings/string_piece.h" + #include "build/build_config.h" + #include "content/common/content_export.h" + #include "content/public/common/main_function_params.h" +@@ -154,6 +155,8 @@ class CONTENT_EXPORT ContentMainDelegate { + virtual bool ShouldHandleConsoleControlEvents(); + #endif + ++ virtual base::StringPiece GetBrowserV8SnapshotFilename(); ++ + protected: + friend class ContentClientCreator; + friend class ContentClientInitializer; +diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc +index 5530d975303cc96701e4b70ffbcaf6e7c02bb016..edd9959cc0fd23711e19de4aee104199a8a3599e 100644 +--- a/gin/v8_initializer.cc ++++ b/gin/v8_initializer.cc +@@ -496,8 +496,7 @@ void V8Initializer::GetV8ExternalSnapshotData(const char** snapshot_data_out, + + #if defined(V8_USE_EXTERNAL_STARTUP_DATA) + +-// static +-void V8Initializer::LoadV8Snapshot(V8SnapshotFileType snapshot_file_type) { ++void V8Initializer::LoadV8SnapshotFromFileName(base::StringPiece file_name, V8SnapshotFileType snapshot_file_type) { + if (g_mapped_snapshot) { + // TODO(crbug.com/802962): Confirm not loading different type of snapshot + // files in a process. +@@ -506,10 +505,17 @@ void V8Initializer::LoadV8Snapshot(V8SnapshotFileType snapshot_file_type) { + + base::MemoryMappedFile::Region file_region; + base::File file = +- OpenV8File(GetSnapshotFileName(snapshot_file_type), &file_region); ++ OpenV8File(file_name.data(), &file_region); + LoadV8SnapshotFromFile(std::move(file), &file_region, snapshot_file_type); + } + ++// static ++void V8Initializer::LoadV8Snapshot(V8SnapshotFileType snapshot_file_type) { ++ const char* file_name = GetSnapshotFileName(snapshot_file_type); ++ ++ LoadV8SnapshotFromFileName(file_name, snapshot_file_type); ++} ++ + // static + void V8Initializer::LoadV8SnapshotFromFile( + base::File snapshot_file, +diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h +index 13a120c7fe8e69a44793473f3124c33d572a07a3..acb294780873c1d84546eb2b9acc00f86838361d 100644 +--- a/gin/v8_initializer.h ++++ b/gin/v8_initializer.h +@@ -9,6 +9,7 @@ + + #include "base/files/file.h" + #include "base/files/memory_mapped_file.h" ++#include "base/strings/string_piece.h" + #include "build/build_config.h" + #include "gin/array_buffer.h" + #include "gin/gin_export.h" +@@ -42,6 +43,7 @@ class GIN_EXPORT V8Initializer { + int* snapshot_size_out); + + #if defined(V8_USE_EXTERNAL_STARTUP_DATA) ++ static void LoadV8SnapshotFromFileName(base::StringPiece file_name, V8SnapshotFileType snapshot_file_type); + // Load V8 snapshot from default resources, if they are available. + static void LoadV8Snapshot( + V8SnapshotFileType snapshot_file_type = V8SnapshotFileType::kDefault); diff --git a/patches/chromium/custom_protocols_plzserviceworker.patch b/patches/chromium/custom_protocols_plzserviceworker.patch new file mode 100644 index 0000000000000..c0c4dd9f08a42 --- /dev/null +++ b/patches/chromium/custom_protocols_plzserviceworker.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 +Date: Fri, 20 May 2022 00:29:34 +0900 +Subject: custom_protocols_plzserviceworker.patch + +Allow registering custom protocols to handle service worker main script fetching with PlzServiceWorker. + +Refs https://bugs.chromium.org/p/chromium/issues/detail?id=996511 + +diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc +index 654219d75727c189d377cf14e25a8abdc1002204..3e243964f429c3afcb874b208c672991dd3468bf 100644 +--- a/content/browser/service_worker/service_worker_context_wrapper.cc ++++ b/content/browser/service_worker/service_worker_context_wrapper.cc +@@ -1649,6 +1649,28 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( + loader_factory_bundle_info = + context()->loader_factory_bundle_for_update_check()->Clone(); + ++ // Give the embedder a chance to register custom schemes that can ++ // handle loading the service worker main script. ++ // Previous registration triggered by ++ // ServiceWorkerContextWrapper::CreateNonNetworkPendingURLLoaderFactoryBundleForUpdateCheck ++ // happens early on browser startup before the JS in the main process ++ // is run by the embedder. ++ auto* factory_bundle = static_cast( ++ loader_factory_bundle_info.get()); ++ ContentBrowserClient::NonNetworkURLLoaderFactoryMap non_network_factories; ++ GetContentClient() ++ ->browser() ++ ->RegisterNonNetworkServiceWorkerUpdateURLLoaderFactories( ++ storage_partition_->browser_context(), &non_network_factories); ++ for (auto& pair : non_network_factories) { ++ const std::string& scheme = pair.first; ++ mojo::PendingRemote& factory_remote = ++ pair.second; ++ ++ factory_bundle->pending_scheme_specific_factories().emplace( ++ scheme, std::move(factory_remote)); ++ } ++ + if (base::FeatureList::IsEnabled( + features::kEnableServiceWorkersForChromeUntrusted) && + scope.scheme_piece() == kChromeUIUntrustedScheme) { +@@ -1669,9 +1691,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest( + browser_context(), scope_origin)) { + config->RegisterURLDataSource(browser_context()); + +- static_cast( +- loader_factory_bundle_info.get()) +- ->pending_scheme_specific_factories() ++ factory_bundle->pending_scheme_specific_factories() + .emplace(kChromeUIUntrustedScheme, + CreateWebUIServiceWorkerLoaderFactory( + browser_context(), kChromeUIUntrustedScheme, diff --git a/patches/chromium/dcheck.patch b/patches/chromium/dcheck.patch index 5374f0423050e..a7f845049f8af 100644 --- a/patches/chromium/dcheck.patch +++ b/patches/chromium/dcheck.patch @@ -16,20 +16,6 @@ example, the checks might be disabled for a whole build target, but actually only one or two specific checks fail. Then it's better to simply comment out the failing checks and allow the rest of the target to have them enabled. -diff --git a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc -index 183503c7d9891b7e651f0cac4b2dc97157b61928..1630a0a49a4b88ceda0ee14980236dc614b42c67 100644 ---- a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc -+++ b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc -@@ -511,8 +511,7 @@ void MobileFriendlinessChecker::NotifyInvalidatePaint( - ->GetPageScaleConstraintsSet() - .FinalConstraints() - .initial_scale; -- DCHECK_GT(initial_scale, 0); -- -+ // DCHECK_GT(initial_scale, 0); - double actual_font_size = - style.FontSize() * initial_scale / viewport_scalar; - double area = text->PhysicalAreaSize(); diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc index fe8d191217e24b08d36339dbf047beaeb6bd6538..870db0552544e3e89d9498c22ec3db81b46df741 100644 --- a/ui/base/clipboard/clipboard_win.cc diff --git a/patches/chromium/desktop_media_list.patch b/patches/chromium/desktop_media_list.patch index de4da5324bf23..5a439ea80d375 100644 --- a/patches/chromium/desktop_media_list.patch +++ b/patches/chromium/desktop_media_list.patch @@ -8,10 +8,10 @@ Subject: desktop_media_list.patch * Ensure "OnRefreshComplete()" even if there are no items in the list diff --git a/chrome/browser/media/webrtc/desktop_media_list.h b/chrome/browser/media/webrtc/desktop_media_list.h -index 57cfc646f8ea545271c22d79ec158a04b148bc9c..c5339603930f68e7019ca33d8b9f148cf4ac86af 100644 +index 03af516b6c85523c51a70dac281dbd732c10ea7e..b6f91fbd15181dff4d8ddc4be2b66c2a5012f495 100644 --- a/chrome/browser/media/webrtc/desktop_media_list.h +++ b/chrome/browser/media/webrtc/desktop_media_list.h -@@ -94,7 +94,8 @@ class DesktopMediaList { +@@ -96,7 +96,8 @@ class DesktopMediaList { // once per DesktopMediaList instance. It should not be called after // StartUpdating(), and StartUpdating() should not be called until |callback| // has been called. @@ -22,10 +22,10 @@ index 57cfc646f8ea545271c22d79ec158a04b148bc9c..c5339603930f68e7019ca33d8b9f148c virtual int GetSourceCount() const = 0; virtual const Source& GetSource(int index) const = 0; diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.cc b/chrome/browser/media/webrtc/desktop_media_list_base.cc -index 24bd95b79479c21182a0d1a61364e1794f900261..2b2a7494ee9bd88fd5c8ebf50a5e29738b2dffd0 100644 +index ac1e7854dc9ae629a499fac7626ec456e18c7867..087da9bbfb9081b94ca8ea8d245871dc3601b1a7 100644 --- a/chrome/browser/media/webrtc/desktop_media_list_base.cc +++ b/chrome/browser/media/webrtc/desktop_media_list_base.cc -@@ -63,12 +63,12 @@ void DesktopMediaListBase::StartUpdating(DesktopMediaListObserver* observer) { +@@ -65,12 +65,12 @@ void DesktopMediaListBase::StartUpdating(DesktopMediaListObserver* observer) { Refresh(true); } @@ -41,10 +41,10 @@ index 24bd95b79479c21182a0d1a61364e1794f900261..2b2a7494ee9bd88fd5c8ebf50a5e2973 int DesktopMediaListBase::GetSourceCount() const { diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.h b/chrome/browser/media/webrtc/desktop_media_list_base.h -index c56bc6dcc73cf0e0d5e0e64d45436ccac833cd66..69aaecca38ede55ee71310698710e3f17b04abff 100644 +index 1150cf5fd95cb19d926a9af6d65472b680f53859..0fc3455f4966dd2047329adc308526dadcc64f1b 100644 --- a/chrome/browser/media/webrtc/desktop_media_list_base.h +++ b/chrome/browser/media/webrtc/desktop_media_list_base.h -@@ -36,7 +36,7 @@ class DesktopMediaListBase : public DesktopMediaList { +@@ -39,7 +39,7 @@ class DesktopMediaListBase : public DesktopMediaList { void SetThumbnailSize(const gfx::Size& thumbnail_size) override; void SetViewDialogWindowId(content::DesktopMediaID dialog_id) override; void StartUpdating(DesktopMediaListObserver* observer) override; @@ -54,10 +54,10 @@ index c56bc6dcc73cf0e0d5e0e64d45436ccac833cd66..69aaecca38ede55ee71310698710e3f1 const Source& GetSource(int index) const override; DesktopMediaList::Type GetMediaListType() const override; diff --git a/chrome/browser/media/webrtc/fake_desktop_media_list.cc b/chrome/browser/media/webrtc/fake_desktop_media_list.cc -index b1db454db6b7982962541cef18c09425b8f5fa5a..1e37f85d7f786807af331ccc347d84d9b4d7177c 100644 +index 2bf801156b93305705914d3dcb7dcbbebd03c096..6ea87e4471ab64c838b705c64be6bc10d74b213e 100644 --- a/chrome/browser/media/webrtc/fake_desktop_media_list.cc +++ b/chrome/browser/media/webrtc/fake_desktop_media_list.cc -@@ -75,7 +75,8 @@ void FakeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { +@@ -77,7 +77,8 @@ void FakeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { thumbnail_ = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); } @@ -82,19 +82,10 @@ index 1e4a652634fbde2ca9a256baca840bbc5a0e001f..546f5bc3a2f79035f0eec196d9e704b8 const Source& GetSource(int index) const override; DesktopMediaList::Type GetMediaListType() const override; diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc -index 6d8c9d940bb4488ffedc1eb8c543c065bb3953c9..2026b926eee56f6b235963b23ab86b2743eaed90 100644 +index d2297c082f482219f35c3acf5bcc8dadf18bbafb..97b1589793962b2b601a78ef5118256903ee65f9 100644 --- a/chrome/browser/media/webrtc/native_desktop_media_list.cc +++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc -@@ -18,7 +18,7 @@ - #include "build/build_config.h" - #include "build/chromeos_buildflags.h" - #include "chrome/browser/media/webrtc/desktop_media_list.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "content/public/browser/browser_task_traits.h" - #include "content/public/browser/browser_thread.h" - #include "content/public/common/content_features.h" -@@ -127,8 +127,9 @@ BOOL CALLBACK AllHwndCollector(HWND hwnd, LPARAM param) { +@@ -139,8 +139,9 @@ BOOL CALLBACK AllHwndCollector(HWND hwnd, LPARAM param) { #endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_MAC) @@ -105,7 +96,7 @@ index 6d8c9d940bb4488ffedc1eb8c543c065bb3953c9..2026b926eee56f6b235963b23ab86b27 #endif } // namespace -@@ -415,6 +416,9 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() { +@@ -427,6 +428,9 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() { FROM_HERE, base::BindOnce(&NativeDesktopMediaList::UpdateNativeThumbnailsFinished, media_list_)); @@ -115,7 +106,7 @@ index 6d8c9d940bb4488ffedc1eb8c543c065bb3953c9..2026b926eee56f6b235963b23ab86b27 } void NativeDesktopMediaList::Worker::OnCaptureResult( -@@ -628,6 +632,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows( +@@ -642,6 +646,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows( FROM_HERE, base::BindOnce(&Worker::RefreshThumbnails, base::Unretained(worker_.get()), std::move(native_ids), thumbnail_size_)); diff --git a/patches/chromium/disable-redraw-lock.patch b/patches/chromium/disable-redraw-lock.patch index 678825807237a..86f7dcc317504 100644 --- a/patches/chromium/disable-redraw-lock.patch +++ b/patches/chromium/disable-redraw-lock.patch @@ -15,10 +15,10 @@ the redraw locking mechanism, which fixes these issues. The electron issue can be found at https://github.com/electron/electron/issues/1821 diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index bf32a083d0f0873e112debe0e88ab1be8125a417..8ca72461bb7b42f1bc0da249a36f0fcf9ab6f13c 100644 +index 29e812d41d5c8b1384db2231c625a39579fed6dc..b0d12e9b64cc7aa5448e88f540e7a594fca3c80e 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -308,6 +308,10 @@ constexpr int kSynthesizedMouseMessagesTimeDifference = 500; +@@ -309,6 +309,10 @@ constexpr int kSynthesizedMouseMessagesTimeDifference = 500; } // namespace @@ -29,15 +29,17 @@ index bf32a083d0f0873e112debe0e88ab1be8125a417..8ca72461bb7b42f1bc0da249a36f0fcf // A scoping class that prevents a window from being able to redraw in response // to invalidations that may occur within it for the lifetime of the object. // -@@ -359,6 +363,7 @@ class HWNDMessageHandler::ScopedRedrawLock { +@@ -359,7 +363,8 @@ class HWNDMessageHandler::ScopedRedrawLock { + hwnd_(owner_->hwnd()), cancel_unlock_(false), should_lock_(owner_->IsVisible() && !owner->HasChildRenderingWindow() && - ::IsWindow(hwnd_) && -+ !owner_->HasNativeFrame() && +- ::IsWindow(hwnd_) && !owner_->IsHeadless() && ++ ::IsWindow(hwnd_) && !owner_->HasNativeFrame() && ++ !owner_->IsHeadless() && (!(GetWindowLong(hwnd_, GWL_STYLE) & WS_CAPTION) || !ui::win::IsAeroGlassEnabled())) { if (should_lock_) -@@ -986,6 +991,10 @@ HWNDMessageHandler::RegisterUnadjustedMouseEvent() { +@@ -1053,6 +1058,10 @@ HWNDMessageHandler::RegisterUnadjustedMouseEvent() { return scoped_enable; } @@ -49,10 +51,10 @@ index bf32a083d0f0873e112debe0e88ab1be8125a417..8ca72461bb7b42f1bc0da249a36f0fcf // HWNDMessageHandler, gfx::WindowImpl overrides: diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h -index f4efdc7174b90e57fb332f031530545e493a2e0d..9d45f97b930831a703efab2bbdf10afb61140c7f 100644 +index cdc283b7e1aa89c8a273c4df97ad8aea55024743..caa02c07b371569be5ac5ac3ce7efe40359cd017 100644 --- a/ui/views/win/hwnd_message_handler.h +++ b/ui/views/win/hwnd_message_handler.h -@@ -205,6 +205,8 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl, +@@ -207,6 +207,8 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl, using TouchIDs = std::set; enum class DwmFrameState { kOff, kOn }; diff --git a/patches/chromium/disable_color_correct_rendering.patch b/patches/chromium/disable_color_correct_rendering.patch index 81c325867337b..e0ce3e006d1cb 100644 --- a/patches/chromium/disable_color_correct_rendering.patch +++ b/patches/chromium/disable_color_correct_rendering.patch @@ -20,21 +20,22 @@ to deal with color spaces. That is being tracked at https://crbug.com/634542 and https://crbug.com/711107. diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc -index 3824e500fd88105e9c6d459f23097b2b4f0686ed..927ede7608a5c6992e9f9fb05e4b8e43b7e10cf8 100644 +index 5542037a338e34800d86c3ca9cbaf0511fa60570..e5011a2b9d2127c1e17730db54f9574f1ed1d287 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc -@@ -1889,6 +1889,9 @@ void LayerTreeHostImpl::SetIsLikelyToRequireADraw( +@@ -1873,6 +1873,10 @@ void LayerTreeHostImpl::SetIsLikelyToRequireADraw( TargetColorParams LayerTreeHostImpl::GetTargetColorParams( gfx::ContentColorUsage content_color_usage) const { TargetColorParams params; + if (!settings_.enable_color_correct_rendering) { ++ params.color_space = gfx::ColorSpace(); + return params; + } // If we are likely to software composite the resource, we use sRGB because // software compositing is unable to perform color conversion. diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h -index 64f1a3a3cb8d82235ff04f5c01a7cf571d8ba00c..ffa8d1a53870663647e423975f00e5650c6ab579 100644 +index 809fb46cc34db308e0ec73197859045ba639407c..9360695cd920de372529206212f795f299405fcf 100644 --- a/cc/trees/layer_tree_settings.h +++ b/cc/trees/layer_tree_settings.h @@ -93,6 +93,8 @@ class CC_EXPORT LayerTreeSettings { @@ -47,7 +48,7 @@ index 64f1a3a3cb8d82235ff04f5c01a7cf571d8ba00c..ffa8d1a53870663647e423975f00e565 // Image Decode Service and raster tiles without images until the decode is // ready. diff --git a/components/viz/common/display/renderer_settings.h b/components/viz/common/display/renderer_settings.h -index d8e2bd1e55a52e86dda5c1b69c425b49e16538bd..80e2c77066f24e99a1894faadbf1d030a188ffa9 100644 +index bc48a50a7664f12a454997db54d893cde9b04881..810a8ce52bf9ac74f47a710f8b332980754996f5 100644 --- a/components/viz/common/display/renderer_settings.h +++ b/components/viz/common/display/renderer_settings.h @@ -24,6 +24,7 @@ class VIZ_COMMON_EXPORT RendererSettings { @@ -59,7 +60,7 @@ index d8e2bd1e55a52e86dda5c1b69c425b49e16538bd..80e2c77066f24e99a1894faadbf1d030 bool force_antialiasing = false; bool force_blending_with_shaders = false; diff --git a/components/viz/host/renderer_settings_creation.cc b/components/viz/host/renderer_settings_creation.cc -index 6a830ec9f29b9764cd425f0681dafbb18d90b457..a7a095ceb9e626c79db21e0d16c8ef47da860679 100644 +index 9d34ced366026eb7cdd00ce40a4eb1af56180d39..abf67f8246bfa37df08cd2216c388dd316fb6499 100644 --- a/components/viz/host/renderer_settings_creation.cc +++ b/components/viz/host/renderer_settings_creation.cc @@ -17,6 +17,7 @@ @@ -79,159 +80,11 @@ index 6a830ec9f29b9764cd425f0681dafbb18d90b457..a7a095ceb9e626c79db21e0d16c8ef47 renderer_settings.partial_swap_enabled = !command_line->HasSwitch(switches::kUIDisablePartialSwap); -diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc -index deb95d2f0728b27af6115674094cc1b7a8e25807..339fe73954f33fb7bbc17f88b949187690aca71c 100644 ---- a/components/viz/service/display/gl_renderer.cc -+++ b/components/viz/service/display/gl_renderer.cc -@@ -87,6 +87,9 @@ - - using gpu::gles2::GLES2Interface; - -+#define PATCH_CS(color_space) \ -+ (settings_->enable_color_correct_rendering ? color_space : gfx::ColorSpace()) -+ - namespace viz { - namespace { - -@@ -684,8 +687,9 @@ void GLRenderer::DoDrawQuad(const DrawQuad* quad, - void GLRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad) { - SetBlendEnabled(quad->ShouldDrawWithBlending()); - -- SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB(), -- CurrentRenderPassColorSpace()); -+ SetUseProgram(ProgramKey::DebugBorder(), -+ PATCH_CS(gfx::ColorSpace::CreateSRGB()), -+ PATCH_CS(CurrentRenderPassColorSpace())); - - // Use the full quad_rect for debug quads to not move the edges based on - // partial swaps. -@@ -1675,7 +1679,8 @@ void GLRenderer::ChooseRPDQProgram(DrawRenderPassDrawQuadParams* params, - params->use_color_matrix, tint_gl_composited_content_, - params->apply_shader_based_rounded_corner && - ShouldApplyRoundedCorner(params->quad)), -- params->contents_and_bypass_color_space, target_color_space); -+ PATCH_CS(params->contents_and_bypass_color_space), -+ PATCH_CS(target_color_space)); - } - - void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) { -@@ -2148,7 +2153,8 @@ void GLRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad, - SetUseProgram(ProgramKey::SolidColor(use_aa ? USE_AA : NO_AA, - tint_gl_composited_content_, - ShouldApplyRoundedCorner(quad)), -- CurrentRenderPassColorSpace(), CurrentRenderPassColorSpace()); -+ PATCH_CS(CurrentRenderPassColorSpace()), -+ PATCH_CS(CurrentRenderPassColorSpace())); - - gfx::ColorSpace quad_color_space = gfx::ColorSpace::CreateSRGB(); - SkColor4f color_f = SkColor4f::FromColor(color); -@@ -2156,7 +2162,7 @@ void GLRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad, - // Apply color transform if the color space or source and target do not match. - if (quad_color_space != CurrentRenderPassColorSpace()) { - const gfx::ColorTransform* color_transform = -- GetColorTransform(quad_color_space, CurrentRenderPassColorSpace()); -+ GetColorTransform(PATCH_CS(quad_color_space), PATCH_CS(CurrentRenderPassColorSpace())); - gfx::ColorTransform::TriStim col(color_f.fR, color_f.fG, color_f.fB); - color_transform->Transform(&col, 1); - color_f.fR = col.x(); -@@ -2378,7 +2384,8 @@ void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad, - : NON_PREMULTIPLIED_ALPHA, - false, false, tint_gl_composited_content_, - ShouldApplyRoundedCorner(quad)), -- quad_resource_lock.color_space(), CurrentRenderPassColorSpace()); -+ PATCH_CS(quad_resource_lock.color_space()), -+ PATCH_CS(CurrentRenderPassColorSpace())); - - if (current_program_->tint_color_matrix_location() != -1) { - auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix(); -@@ -2477,7 +2484,8 @@ void GLRenderer::DrawContentQuadNoAA(const ContentDrawQuadBase* quad, - !quad->ShouldDrawWithBlending(), has_tex_clamp_rect, - tint_gl_composited_content_, - ShouldApplyRoundedCorner(quad)), -- quad_resource_lock.color_space(), CurrentRenderPassColorSpace()); -+ PATCH_CS(quad_resource_lock.color_space()), -+ PATCH_CS(CurrentRenderPassColorSpace())); - - if (current_program_->tint_color_matrix_location() != -1) { - auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix(); -@@ -2587,7 +2595,8 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad, - // The source color space should never be RGB. - DCHECK_NE(src_color_space, src_color_space.GetAsFullRangeRGB()); - -- gfx::ColorSpace dst_color_space = CurrentRenderPassColorSpace(); -+ gfx::ColorSpace dst_color_space = -+ PATCH_CS(CurrentRenderPassColorSpace()); - - #if BUILDFLAG(IS_WIN) - // Force sRGB output on Windows for overlay candidate video quads to match -@@ -2768,7 +2777,8 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad, - - SetUseProgram(ProgramKey::VideoStream(tex_coord_precision, - ShouldApplyRoundedCorner(quad)), -- lock.color_space(), CurrentRenderPassColorSpace()); -+ PATCH_CS(lock.color_space()), -+ PATCH_CS(CurrentRenderPassColorSpace())); - - DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); - gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id()); -@@ -2839,8 +2849,8 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) { - draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR); - - // Bind the program to the GL state. -- SetUseProgram(draw_cache_.program_key, locked_quad.color_space(), -- CurrentRenderPassColorSpace(), -+ SetUseProgram(draw_cache_.program_key, PATCH_CS(locked_quad.color_space()), -+ PATCH_CS(CurrentRenderPassColorSpace()), - /*adjust_src_white_level=*/draw_cache_.is_video_frame, - locked_quad.hdr_metadata()); - -@@ -3697,7 +3707,9 @@ void GLRenderer::SetUseProgram(const ProgramKey& program_key_no_color, - const gfx::ColorSpace& dst_color_space, - bool adjust_src_white_level, - absl::optional hdr_metadata) { -- DCHECK(dst_color_space.IsValid()); -+ if (settings_->enable_color_correct_rendering) { -+ DCHECK(dst_color_space.IsValid()); -+ } - gfx::ColorSpace adjusted_src_color_space = src_color_space; - if (adjust_src_white_level && src_color_space.IsHDR()) { - // TODO(b/183236148): consider using the destination's HDR static metadata -@@ -4085,9 +4097,9 @@ void GLRenderer::CopyRenderPassDrawQuadToOverlayResource( - cc::MathUtil::CheckedRoundUp(iosurface_height, iosurface_multiple); - } - -- *overlay_texture = -- FindOrCreateOverlayTexture(params.quad->render_pass_id, iosurface_width, -- iosurface_height, RootRenderPassColorSpace()); -+ *overlay_texture = FindOrCreateOverlayTexture( -+ params.quad->render_pass_id, iosurface_width, iosurface_height, -+ PATCH_CS(RootRenderPassColorSpace())); - *new_bounds = gfx::RectF(updated_dst_rect.origin(), - gfx::SizeF((*overlay_texture)->texture.size())); - -@@ -4307,8 +4319,9 @@ void GLRenderer::FlushOverdrawFeedback(const gfx::Rect& output_rect) { - - PrepareGeometry(SHARED_BINDING); - -- SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB(), -- CurrentRenderPassColorSpace()); -+ SetUseProgram(ProgramKey::DebugBorder(), -+ PATCH_CS(gfx::ColorSpace::CreateSRGB()), -+ PATCH_CS(CurrentRenderPassColorSpace())); - - gfx::Transform render_matrix; - render_matrix.Translate(0.5 * output_rect.width() + output_rect.x(), -@@ -4514,3 +4527,5 @@ bool GLRenderer::ColorTransformKey::operator<( - } - - } // namespace viz -+ -+#undef PATCH_CS diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc -index f5d73922086b5b27907fd393d4d4204a574c3b25..5b09f5ef5f04b519ed4148498c82d003c9fd6c91 100644 +index 3f413731440ea6597001c8da03c1ac3c49bb60b2..fe1f2373f0b5f5e8eed2e0966910a6454db776d4 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc -@@ -227,6 +227,7 @@ GpuTerminationStatus ConvertToGpuTerminationStatus( +@@ -228,6 +228,7 @@ GpuTerminationStatus ConvertToGpuTerminationStatus( // Command-line switches to propagate to the GPU process. static const char* const kSwitchNames[] = { @@ -240,10 +93,10 @@ index f5d73922086b5b27907fd393d4d4204a574c3b25..5b09f5ef5f04b519ed4148498c82d003 sandbox::policy::switches::kGpuSandboxAllowSysVShm, sandbox::policy::switches::kGpuSandboxFailuresFatal, diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc -index 5f2451eefad211c85460eb457ad3d6e184540d59..d9d8352c6b1b8db8d86ad1ed1d4a3d300a999fa6 100644 +index 368d47247ced2320e0627e9cce3cf05e59ea9f39..c675f0f37fa75dd0a39d503564c7ac265614d4e9 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc -@@ -196,6 +196,7 @@ +@@ -199,6 +199,7 @@ #include "ui/accessibility/accessibility_switches.h" #include "ui/base/ui_base_switches.h" #include "ui/display/display_switches.h" @@ -251,7 +104,7 @@ index 5f2451eefad211c85460eb457ad3d6e184540d59..d9d8352c6b1b8db8d86ad1ed1d4a3d30 #include "ui/gl/gl_switches.h" #include "url/gurl.h" #include "url/origin.h" -@@ -3293,6 +3294,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( +@@ -3205,6 +3206,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( // Propagate the following switches to the renderer command line (along // with any associated values) if present in the browser command line. static const char* const kSwitchNames[] = { @@ -260,7 +113,7 @@ index 5f2451eefad211c85460eb457ad3d6e184540d59..d9d8352c6b1b8db8d86ad1ed1d4a3d30 sandbox::policy::switches::kDisableSeccompFilterSandbox, sandbox::policy::switches::kNoSandbox, diff --git a/third_party/blink/renderer/platform/graphics/canvas_color_params.cc b/third_party/blink/renderer/platform/graphics/canvas_color_params.cc -index 6260d73068636f4a8d4c73c161a4ffe165b267d0..2686ef0dfb7d8b667647d11fece5aa8e1be76fe5 100644 +index 75d7af9a79d4e7f2cd39e45496ab5fff66407638..35b0bb908245330fbdc5205caa3299bf6fd8f7b4 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_color_params.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_color_params.cc @@ -4,6 +4,7 @@ @@ -279,7 +132,18 @@ index 6260d73068636f4a8d4c73c161a4ffe165b267d0..2686ef0dfb7d8b667647d11fece5aa8e namespace blink { -@@ -118,6 +120,11 @@ uint8_t CanvasColorParams::BytesPerPixel() const { +@@ -19,6 +21,10 @@ namespace blink { + // Level 4 specification. + gfx::ColorSpace PredefinedColorSpaceToGfxColorSpace( + PredefinedColorSpace color_space) { ++ auto* cmd_line = base::CommandLine::ForCurrentProcess(); ++ if (cmd_line->HasSwitch(switches::kDisableColorCorrectRendering)) { ++ return gfx::ColorSpace(); ++ } + switch (color_space) { + case PredefinedColorSpace::kSRGB: + return gfx::ColorSpace::CreateSRGB(); +@@ -118,6 +124,11 @@ uint8_t CanvasColorParams::BytesPerPixel() const { } gfx::ColorSpace CanvasColorParams::GetStorageGfxColorSpace() const { @@ -292,7 +156,7 @@ index 6260d73068636f4a8d4c73c161a4ffe165b267d0..2686ef0dfb7d8b667647d11fece5aa8e } diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc -index 49ef0d352cfb6163499fa42416187595c7011a68..d5bc620847872fcba96f6941be529428755d83a2 100644 +index ba6ab6961dec25a3f9c572341d24f341c8f58358..ba8cfd2a2572368fc14073a53f8544f269089894 100644 --- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc +++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc @@ -24,6 +24,7 @@ @@ -303,7 +167,7 @@ index 49ef0d352cfb6163499fa42416187595c7011a68..d5bc620847872fcba96f6941be529428 #include "ui/native_theme/native_theme_features.h" #include "ui/native_theme/overlay_scrollbar_constants_aura.h" -@@ -184,6 +185,9 @@ cc::LayerTreeSettings GenerateLayerTreeSettings( +@@ -178,6 +179,9 @@ cc::LayerTreeSettings GenerateLayerTreeSettings( settings.main_frame_before_activation_enabled = cmd.HasSwitch(cc::switches::kEnableMainFrameBeforeActivation); @@ -314,10 +178,10 @@ index 49ef0d352cfb6163499fa42416187595c7011a68..d5bc620847872fcba96f6941be529428 // is what the renderer uses if its not threaded. settings.enable_checker_imaging = diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc -index 298321f1aabcf4328fd39b856694a8a6459bfa24..4be245d082cd9d833db72b29e3d652120ecb913e 100644 +index 961b730933d285ccea7b81b8c21dd5bb0ecea56a..d6e536924f0b397d3e8808298d2b9fdd6025411f 100644 --- a/ui/gfx/mac/io_surface.cc +++ b/ui/gfx/mac/io_surface.cc -@@ -21,6 +21,7 @@ +@@ -20,6 +20,7 @@ #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/color_space.h" #include "ui/gfx/icc_profile.h" @@ -325,14 +189,14 @@ index 298321f1aabcf4328fd39b856694a8a6459bfa24..4be245d082cd9d833db72b29e3d65212 namespace gfx { -@@ -143,6 +144,14 @@ void IOSurfaceMachPortTraits::Release(mach_port_t port) { +@@ -142,6 +143,14 @@ void IOSurfaceMachPortTraits::Release(mach_port_t port) { // Common method used by IOSurfaceSetColorSpace and IOSurfaceCanSetColorSpace. bool IOSurfaceSetColorSpace(IOSurfaceRef io_surface, const ColorSpace& color_space) { + auto* cmd_line = base::CommandLine::ForCurrentProcess(); + if (cmd_line->HasSwitch(switches::kDisableColorCorrectRendering)) { + base::ScopedCFTypeRef system_icc( -+ CGColorSpaceCopyICCProfile(base::mac::GetSystemColorSpace())); ++ CGColorSpaceCopyICCData(base::mac::GetSystemColorSpace())); + IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"), system_icc); + return true; + } @@ -340,7 +204,7 @@ index 298321f1aabcf4328fd39b856694a8a6459bfa24..4be245d082cd9d833db72b29e3d65212 // Allow but ignore invalid color spaces. if (!color_space.IsValid()) return true; -@@ -313,6 +322,15 @@ IOSurfaceRef CreateIOSurface(const gfx::Size& size, +@@ -312,6 +321,15 @@ IOSurfaceRef CreateIOSurface(const gfx::Size& size, DCHECK_EQ(kIOReturnSuccess, r); } @@ -348,16 +212,16 @@ index 298321f1aabcf4328fd39b856694a8a6459bfa24..4be245d082cd9d833db72b29e3d65212 + if (cmd_line->HasSwitch(switches::kDisableColorCorrectRendering)) { + CGColorSpaceRef color_space = base::mac::GetSystemColorSpace(); + base::ScopedCFTypeRef color_space_icc( -+ CGColorSpaceCopyICCProfile(color_space)); ++ CGColorSpaceCopyICCData(color_space)); + IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), color_space_icc); + return surface; + } + // Ensure that all IOSurfaces start as sRGB. - if (__builtin_available(macos 10.12, *)) { - IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB); + IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB); + diff --git a/ui/gfx/switches.cc b/ui/gfx/switches.cc -index be932ac3094a441cd5d9afa2ffd2c6d4a64ce559..a6aa9b4c6ba958eb81276911368cd053b9fb59f8 100644 +index 0e8044c6d87008c51fd165c6ef8bdc3687d6cc29..78015868927602b5225f252f0a9182f61b8431dc 100644 --- a/ui/gfx/switches.cc +++ b/ui/gfx/switches.cc @@ -11,6 +11,8 @@ namespace switches { @@ -370,7 +234,7 @@ index be932ac3094a441cd5d9afa2ffd2c6d4a64ce559..a6aa9b4c6ba958eb81276911368cd053 // sharpness, kerning, hinting and layout. const char kDisableFontSubpixelPositioning[] = diff --git a/ui/gfx/switches.h b/ui/gfx/switches.h -index 442809de1631081efbe062922539318f5172a5ae..b8e5c7e53d58a06175105c9396a7d976bda7a4bd 100644 +index e8e5d44e246364dd45594efb442c129676c14270..252096ee18ca33f4b98f68beb1f534e1c2ab805e 100644 --- a/ui/gfx/switches.h +++ b/ui/gfx/switches.h @@ -12,6 +12,7 @@ diff --git a/patches/chromium/disable_compositor_recycling.patch b/patches/chromium/disable_compositor_recycling.patch index 23daa8d150e30..cd20c93d4784f 100644 --- a/patches/chromium/disable_compositor_recycling.patch +++ b/patches/chromium/disable_compositor_recycling.patch @@ -6,10 +6,10 @@ Subject: fix: disabling compositor recycling Compositor recycling is useful for Chrome because there can be many tabs and spinning up a compositor for each one would be costly. In practice, Chrome uses the parent compositor code path of browser_compositor_view_mac.mm; the NSView of each tab is detached when it's hidden and attached when it's shown. For Electron, there is no parent compositor, so we're forced into the "own compositor" code path, which seems to be non-optimal and pretty ruthless in terms of the release of resources. Electron has no real concept of multiple tabs per window, so it should be okay to disable this ruthless recycling altogether in Electron. diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm -index 58002d37ba340f84f47e2522c0d7bf7c1a64c5d2..bc0a73f08e77bf13eb1cafa55f955e6083071104 100644 +index f28dcfe0721239ca9341a0db80e8626a515c34d8..ed10d28ed53a9debdfd26723e17b325b26249ab9 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm -@@ -510,7 +510,11 @@ +@@ -517,7 +517,11 @@ return; host()->WasHidden(); diff --git a/patches/chromium/disable_freezing_flags_after_init_in_node.patch b/patches/chromium/disable_freezing_flags_after_init_in_node.patch new file mode 100644 index 0000000000000..cf6502b77a868 --- /dev/null +++ b/patches/chromium/disable_freezing_flags_after_init_in_node.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Rose +Date: Mon, 20 Jun 2022 14:53:37 -0700 +Subject: disable freezing flags after init in node + +This was introduced in +https://chromium-review.googlesource.com/c/chromium/src/+/3687671. + +When running node in the renderer, flags are updated after initialization, so +freezing the flags in Blink causes node initialization to fail. + +If possible, it would be ideal to do this without a patch. +https://bugs.chromium.org/p/v8/issues/detail?id=12887 suggests that there may +at some point be an API to "unfreeze" the flags, or we may be able to refactor +node initialization to not update flags after V8 initialization. + +diff --git a/content/renderer/render_process_impl.cc b/content/renderer/render_process_impl.cc +index 207cda4b937282a3a719e4285f21066b4d1322f6..4367002caa2b3fd5885204a16f1802f67cde3ebc 100644 +--- a/content/renderer/render_process_impl.cc ++++ b/content/renderer/render_process_impl.cc +@@ -222,7 +222,8 @@ RenderProcessImpl::RenderProcessImpl() + SetV8FlagIfNotFeature(features::kWebAssemblyDynamicTiering, + "--no-wasm-dynamic-tiering"); + +- v8::V8::SetFlagsFromString("--freeze-flags-after-init"); ++ // Freezing flags after init conflicts with node in the renderer. ++ v8::V8::SetFlagsFromString("--no-freeze-flags-after-init"); + + #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(ARCH_CPU_X86_64) + if (base::FeatureList::IsEnabled(features::kWebAssemblyTrapHandler)) { diff --git a/patches/chromium/disable_hidden.patch b/patches/chromium/disable_hidden.patch index 85883eba90ea9..f86b8471da647 100644 --- a/patches/chromium/disable_hidden.patch +++ b/patches/chromium/disable_hidden.patch @@ -6,10 +6,10 @@ Subject: disable_hidden.patch Electron uses this to disable background throttling for hidden windows. diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc -index f127b930806bc8e7b6fe8efb89eab6c43466326f..59dda38e5781132472991979d90317dfaa96028f 100644 +index 311dd906e497f5ba8a19037e629aa58c44773e67..457ba67603442e8ae9ea75be1cb3b4bf32ed4c4f 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc -@@ -803,6 +803,9 @@ void RenderWidgetHostImpl::WasHidden() { +@@ -810,6 +810,9 @@ void RenderWidgetHostImpl::WasHidden() { if (is_hidden_) return; @@ -20,12 +20,12 @@ index f127b930806bc8e7b6fe8efb89eab6c43466326f..59dda38e5781132472991979d90317df blink::mojom::PointerLockResult::kWrongDocument); diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h -index 5cc97c9c8305bf23b7cdf39ea68c304fac20b479..a6a65a251711394a33fb02bd66c2eeb7b559f711 100644 +index 527463920c3d259ca0f30c70a5a860394d0cf4e9..2b50994469ee8ede3b4417650386e26553436e6e 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h -@@ -877,6 +877,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl - void OnLocalSurfaceIdChanged( - const cc::RenderFrameMetadata& metadata) override; +@@ -883,6 +883,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl + + SiteInstanceGroup* GetSiteInstanceGroup(); + // Electron: Prevents the widget from getting hidden. + bool disable_hidden_ = false; @@ -34,10 +34,10 @@ index 5cc97c9c8305bf23b7cdf39ea68c304fac20b479..a6a65a251711394a33fb02bd66c2eeb7 // |routing_id| must not be MSG_ROUTING_NONE. // If this object outlives |delegate|, DetachDelegate() must be called when diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc -index a819dcf960a4c70c0c8cd57710971de2c41e13ca..bbc3671c3fa8e058b8f107d601233735c0822297 100644 +index 9d1301a55acdc5f70550c7222cd31f8338f0e7f4..82e9c9ba7c7cade143aeffdd1e123131d7568698 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc -@@ -619,7 +619,7 @@ void RenderWidgetHostViewAura::HideImpl() { +@@ -594,7 +594,7 @@ void RenderWidgetHostViewAura::HideImpl() { DCHECK(visibility_ == Visibility::HIDDEN || visibility_ == Visibility::OCCLUDED); diff --git a/patches/chromium/disable_optimization_guide_for_preconnect_feature.patch b/patches/chromium/disable_optimization_guide_for_preconnect_feature.patch new file mode 100644 index 0000000000000..725c9f03956a6 --- /dev/null +++ b/patches/chromium/disable_optimization_guide_for_preconnect_feature.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt +Date: Thu, 1 Sep 2022 11:31:24 -0400 +Subject: disable optimization guide for preconnect feature + +The optimization guide component +(https://source.chromium.org/chromium/chromium/src/+/main:components/optimization_guide/) +is not enabled for Electron, but the preconnect feature uses the resource prefetch +predictor code which includes this component. This patch disables the optimization guide +component code in the resource prefetch predictor code since it is unused and including +it causes compilation problems on Windows. + +diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc +index c4b64a7812bac4534371887eb7e0a07ec9cab8ff..b827d69964d824540ea70f66c467e91be8391e6c 100644 +--- a/chrome/browser/predictors/resource_prefetch_predictor.cc ++++ b/chrome/browser/predictors/resource_prefetch_predictor.cc +@@ -100,10 +100,12 @@ PreconnectPrediction& PreconnectPrediction::operator=( + PreconnectPrediction& PreconnectPrediction::operator=( + PreconnectPrediction&& other) = default; + ++#if 0 + OptimizationGuidePrediction::OptimizationGuidePrediction() = default; + OptimizationGuidePrediction::OptimizationGuidePrediction( + const OptimizationGuidePrediction& prediction) = default; + OptimizationGuidePrediction::~OptimizationGuidePrediction() = default; ++#endif + + //////////////////////////////////////////////////////////////////////////////// + // ResourcePrefetchPredictor static functions. +diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h +index 53a23990019accc0504a25dae935c53348c7eaa7..ef6667ce8bbc062dbfb8d2e2cdb6886b3e994b76 100644 +--- a/chrome/browser/predictors/resource_prefetch_predictor.h ++++ b/chrome/browser/predictors/resource_prefetch_predictor.h +@@ -26,7 +26,9 @@ + #include "components/history/core/browser/history_service_observer.h" + #include "components/history/core/browser/history_types.h" + #include "components/keyed_service/core/keyed_service.h" ++#if 0 + #include "components/optimization_guide/content/browser/optimization_guide_decider.h" ++#endif + #include "components/sqlite_proto/key_value_data.h" + #include "net/base/network_isolation_key.h" + #include "services/network/public/mojom/fetch_api.mojom-forward.h" +@@ -110,6 +112,7 @@ struct PreconnectPrediction { + std::vector prefetch_requests; + }; + ++#if 0 + // Stores a result of a prediction from the optimization guide. + struct OptimizationGuidePrediction { + OptimizationGuidePrediction(); +@@ -121,6 +124,7 @@ struct OptimizationGuidePrediction { + std::vector predicted_subresources; + absl::optional optimization_guide_prediction_arrived; + }; ++#endif + + // Contains logic for learning what can be prefetched and for kicking off + // speculative prefetching. diff --git a/patches/chromium/disable_unload_metrics.patch b/patches/chromium/disable_unload_metrics.patch index cc1a3911ab8ab..b9a96fd79cc60 100644 --- a/patches/chromium/disable_unload_metrics.patch +++ b/patches/chromium/disable_unload_metrics.patch @@ -24,10 +24,10 @@ This patch temporarily disables the metrics so we can have green CI, and we should continue seeking for a real fix. diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc -index a460f4643881a0bd70a863884aa50ae76e25c3b7..0635d66dad36e2d6042dd317962527793f5b96f7 100644 +index 8caea1c8d54c59efc5f7b758e78638042f7db23c..579c335888f4df61cfeb08e01ecef09ad1b3a92f 100644 --- a/content/browser/renderer_host/navigator.cc +++ b/content/browser/renderer_host/navigator.cc -@@ -1159,6 +1159,7 @@ void Navigator::RecordNavigationMetrics( +@@ -1200,6 +1200,7 @@ void Navigator::RecordNavigationMetrics( .InMilliseconds()); } @@ -35,7 +35,7 @@ index a460f4643881a0bd70a863884aa50ae76e25c3b7..0635d66dad36e2d6042dd31796252779 // If this is a same-process navigation and we have timestamps for unload // durations, fill those metrics out as well. if (params.unload_start && params.unload_end && -@@ -1205,6 +1206,7 @@ void Navigator::RecordNavigationMetrics( +@@ -1250,6 +1251,7 @@ void Navigator::RecordNavigationMetrics( first_before_unload_start_time) .InMilliseconds()); } diff --git a/patches/chromium/don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch b/patches/chromium/don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch index 6bd042bd527b8..21ba62c9fe028 100644 --- a/patches/chromium/don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch +++ b/patches/chromium/don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch @@ -3,13 +3,14 @@ From: John Kleinschmidt Date: Wed, 16 Jun 2021 11:30:28 -0400 Subject: Don't run PCScan functions if PCScan is disabled -PCScan should not be invoked if PCScan is disabled. Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/2916657. +PCScan should not be invoked if PCScan is disabled. +Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/2965109. diff --git a/base/allocator/partition_allocator/memory_reclaimer.cc b/base/allocator/partition_allocator/memory_reclaimer.cc -index 63819bf2593894bd763547d58cfae31d821bd7eb..a4ee9520cfc11125837e42955f8f6f6c3f21bf9e 100644 +index 1e54559bd5f9a2ee889b921379d70c51e902502d..6797a076b612ad4ed6d5ce7d9868d944fae3694f 100644 --- a/base/allocator/partition_allocator/memory_reclaimer.cc +++ b/base/allocator/partition_allocator/memory_reclaimer.cc -@@ -67,7 +67,7 @@ void PartitionAllocMemoryReclaimer::Reclaim(int flags) { +@@ -66,7 +66,7 @@ void MemoryReclaimer::Reclaim(int flags) { // // Lastly decommit empty slot spans and lastly try to discard unused pages at // the end of the remaining active slots. @@ -17,12 +18,12 @@ index 63819bf2593894bd763547d58cfae31d821bd7eb..a4ee9520cfc11125837e42955f8f6f6c +#if PA_STARSCAN_ENABLE_STARSCAN_ON_RECLAIM && defined(PA_ALLOW_PCSCAN) { using PCScan = internal::PCScan; - const auto invocation_mode = flags & PartitionPurgeAggressiveReclaim + const auto invocation_mode = flags & PurgeFlags::kAggressiveReclaim diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc -index 4bfe2501309e832dc9962d5f4642c6b7c782f83d..c45f1207be984fae9aee2cc5b9a7c405ed5ed96e 100644 +index 714232b0c2707d6c256e634ff784c18322bf0a85..48c8d0051c427954fe7265fee9cd0c6b5f473984 100644 --- a/base/threading/platform_thread_posix.cc +++ b/base/threading/platform_thread_posix.cc -@@ -43,6 +43,7 @@ +@@ -44,6 +44,7 @@ #endif #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) @@ -30,29 +31,29 @@ index 4bfe2501309e832dc9962d5f4642c6b7c782f83d..c45f1207be984fae9aee2cc5b9a7c405 #include "base/allocator/partition_allocator/starscan/pcscan.h" #include "base/allocator/partition_allocator/starscan/stack/stack.h" #endif -@@ -76,7 +77,7 @@ void* ThreadFunc(void* params) { +@@ -77,7 +78,7 @@ void* ThreadFunc(void* params) { base::DisallowSingleton(); #if !BUILDFLAG(IS_NACL) -#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) +#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && defined(PA_ALLOW_PCSCAN) - internal::PCScan::NotifyThreadCreated(internal::GetStackPointer()); + partition_alloc::internal::PCScan::NotifyThreadCreated( + partition_alloc::internal::GetStackPointer()); #endif - -@@ -102,7 +103,7 @@ void* ThreadFunc(void* params) { +@@ -104,7 +105,7 @@ void* ThreadFunc(void* params) { PlatformThread::CurrentHandle().platform_handle(), PlatformThread::CurrentId()); -#if !BUILDFLAG(IS_NACL) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) +#if !BUILDFLAG(IS_NACL) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && defined(PA_ALLOW_PCSCAN) - internal::PCScan::NotifyThreadDestroyed(); + partition_alloc::internal::PCScan::NotifyThreadDestroyed(); #endif diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc -index c965c9764ad38a8b52b727ca98fe41f00ab6707d..7d44c4e63b2b4ccf595b5e2a0212fb6c4eb2b5bd 100644 +index 960d0100e1857592ee24b2da22e0253ab06098c1..dca9fb72fb69386ffb0910e13f841fa698250b66 100644 --- a/base/threading/platform_thread_win.cc +++ b/base/threading/platform_thread_win.cc -@@ -29,6 +29,7 @@ +@@ -30,6 +30,7 @@ #include #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) @@ -60,21 +61,21 @@ index c965c9764ad38a8b52b727ca98fe41f00ab6707d..7d44c4e63b2b4ccf595b5e2a0212fb6c #include "base/allocator/partition_allocator/starscan/pcscan.h" #include "base/allocator/partition_allocator/starscan/stack/stack.h" #endif -@@ -105,7 +106,7 @@ DWORD __stdcall ThreadFunc(void* params) { +@@ -115,7 +116,7 @@ DWORD __stdcall ThreadFunc(void* params) { FALSE, DUPLICATE_SAME_ACCESS); -#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) +#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && defined(PA_ALLOW_PCSCAN) - internal::PCScan::NotifyThreadCreated(internal::GetStackPointer()); + partition_alloc::internal::PCScan::NotifyThreadCreated( + partition_alloc::internal::GetStackPointer()); #endif - -@@ -125,7 +126,7 @@ DWORD __stdcall ThreadFunc(void* params) { +@@ -136,7 +137,7 @@ DWORD __stdcall ThreadFunc(void* params) { PlatformThread::CurrentId()); } -#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) +#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && defined(PA_ALLOW_PCSCAN) - internal::PCScan::NotifyThreadDestroyed(); + partition_alloc::internal::PCScan::NotifyThreadDestroyed(); #endif diff --git a/patches/chromium/don_t_use_potentially_null_getwebframe_-_view_when_get_blink.patch b/patches/chromium/don_t_use_potentially_null_getwebframe_-_view_when_get_blink.patch deleted file mode 100644 index 017e3d5431128..0000000000000 --- a/patches/chromium/don_t_use_potentially_null_getwebframe_-_view_when_get_blink.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Attard -Date: Fri, 18 Dec 2020 15:19:39 -0800 -Subject: Don't use potentially null "GetWebFrame()->View()" when get blink - prefs - -For whatever reason (still haven't narrowed it down to an exact test case) when using OOPIFs the "GetWebFrame()->View()" call during "RenderFrameCreated" call be nullptr. Accessing the prefs via the render_view though still works. - -This regressed in https://chromium-review.googlesource.com/c/chromium/src/+/2572256 - -Upstream: https://chromium-review.googlesource.com/c/chromium/src/+/2598393 - -diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc -index 44c0ec9815aafd61182fd18a9d125e185d7196bc..a77c39adfc687d43004341d4ca9e6fa676c814f5 100644 ---- a/content/renderer/render_frame_impl.cc -+++ b/content/renderer/render_frame_impl.cc -@@ -2394,7 +2394,7 @@ const blink::WebView* RenderFrameImpl::GetWebView() const { - } - - const blink::web_pref::WebPreferences& RenderFrameImpl::GetBlinkPreferences() { -- return GetWebView()->GetWebPreferences(); -+ return render_view_->GetWebView()->GetWebPreferences(); - } - - const blink::RendererPreferences& RenderFrameImpl::GetRendererPreferences() diff --git a/patches/chromium/enable_reset_aspect_ratio.patch b/patches/chromium/enable_reset_aspect_ratio.patch index a124b5b3d2ae1..cc467f7b1764c 100644 --- a/patches/chromium/enable_reset_aspect_ratio.patch +++ b/patches/chromium/enable_reset_aspect_ratio.patch @@ -6,7 +6,7 @@ Subject: feat: enable setting aspect ratio to 0 Make SetAspectRatio accept 0 as valid input, which would reset to null. diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc -index a1de50d6b0f699d0651c369cafafdd5bb542242d..65b9f5e5f81e8ef8b591ef2e027e095df11c0d7b 100644 +index b6d243983474cfc2c314b555ccc1de4d833a7f00..2b1fa6a345247fdbb17bd2381ab9e74a8af40b8d 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc @@ -530,7 +530,7 @@ void DesktopWindowTreeHostWin::SetOpacity(float opacity) { @@ -19,10 +19,10 @@ index a1de50d6b0f699d0651c369cafafdd5bb542242d..65b9f5e5f81e8ef8b591ef2e027e095d aspect_ratio.height()); } diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index 8ca72461bb7b42f1bc0da249a36f0fcf9ab6f13c..9ca11a19e66e34585b4b11e89cc3b789a4389b5e 100644 +index b0d12e9b64cc7aa5448e88f540e7a594fca3c80e..91e45df23e659d705839fa3798ad3452bac012e5 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -936,8 +936,11 @@ void HWNDMessageHandler::SetFullscreen(bool fullscreen) { +@@ -1003,8 +1003,11 @@ void HWNDMessageHandler::SetFullscreen(bool fullscreen) { } void HWNDMessageHandler::SetAspectRatio(float aspect_ratio) { diff --git a/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch b/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch index c05e1e16aceef..d7180a32d1724 100644 --- a/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch +++ b/patches/chromium/export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch @@ -9,7 +9,7 @@ correctly tagged with MAP_JIT we need to use gins page allocator instead of the default V8 allocator. This probably can't be usptreamed. diff --git a/gin/public/v8_platform.h b/gin/public/v8_platform.h -index c9b535eb083c250f4f874d8e6bd0c29ea9f3a10f..f220b8669507a4aea616b0dfbabda509647b714c 100644 +index 2f2e0d67c7141e5daad2d50031c71a542677e108..c53bd76fcd3703cb483949d5ec53f24f482317e5 100644 --- a/gin/public/v8_platform.h +++ b/gin/public/v8_platform.h @@ -30,6 +30,7 @@ class GIN_EXPORT V8Platform : public v8::Platform { @@ -21,10 +21,10 @@ index c9b535eb083c250f4f874d8e6bd0c29ea9f3a10f..f220b8669507a4aea616b0dfbabda509 v8::ZoneBackingAllocator* GetZoneBackingAllocator() override; #endif diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc -index a7dad3d1053c3101183b9686adbccaa5cf3a87fc..24da1fde55c345cb58829539aec381af9af57bae 100644 +index b02ab8b6ac701d948daac73bd89bc1fc6533d60c..36c096b4c053eae9326c8ccb7ed6aea07b68c3e5 100644 --- a/gin/v8_platform.cc +++ b/gin/v8_platform.cc -@@ -368,6 +368,10 @@ PageAllocator* V8Platform::GetPageAllocator() { +@@ -367,6 +367,10 @@ PageAllocator* V8Platform::GetPageAllocator() { return g_page_allocator.Pointer(); } diff --git a/patches/chromium/expose_setuseragent_on_networkcontext.patch b/patches/chromium/expose_setuseragent_on_networkcontext.patch index ac077f2964070..561fd2959781f 100644 --- a/patches/chromium/expose_setuseragent_on_networkcontext.patch +++ b/patches/chromium/expose_setuseragent_on_networkcontext.patch @@ -33,10 +33,10 @@ index 14c71cc69388da46f62d9835e2a06fef0870da02..9481ea08401ae29ae9c1d960491b05b3 } // namespace net diff --git a/services/network/network_context.cc b/services/network/network_context.cc -index a4cd97599e2f131fe0d97ee49a44ed5b748739b7..074ce8a372ad4d54661071cfa37632b5d1bbf067 100644 +index f25c1baa5142d53a882b864a67d94e9e0911f0bf..4dbbc74ddb359047f1dd9e158b8dcaf63bde3790 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc -@@ -1343,6 +1343,13 @@ void NetworkContext::SetNetworkConditions( +@@ -1412,6 +1412,13 @@ void NetworkContext::SetNetworkConditions( std::move(network_conditions)); } @@ -51,22 +51,22 @@ index a4cd97599e2f131fe0d97ee49a44ed5b748739b7..074ce8a372ad4d54661071cfa37632b5 // This may only be called on NetworkContexts created with the constructor // that calls MakeURLRequestContext(). diff --git a/services/network/network_context.h b/services/network/network_context.h -index 06a36a156501b252e91037ebac45c29c2995f624..cb5435028a537baa5e1dbbab9137e6547b9ed712 100644 +index a9a1beed6c8e59abb9065701f34f155905781a2a..5ced53f2e875091cdaf6a38384de4f7890cd71e9 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h -@@ -282,6 +282,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext +@@ -300,6 +300,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext void CloseIdleConnections(CloseIdleConnectionsCallback callback) override; void SetNetworkConditions(const base::UnguessableToken& throttling_profile_id, mojom::NetworkConditionsPtr conditions) override; + void SetUserAgent(const std::string& new_user_agent) override; void SetAcceptLanguage(const std::string& new_accept_language) override; void SetEnableReferrers(bool enable_referrers) override; - #if BUILDFLAG(IS_CHROMEOS) + void SetEnablePreconnect(bool enable_preconnect) override; diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom -index ae0a20a7a33e5a313f5545985a34e9cb93220996..aeb0ac8731689e5495ab039d30ac3e88acab9293 100644 +index e47bbfac56cd6c787ba3e7c0518a5326386a19b6..105011c25861fe00cc8e72fe8f310ee5118725c3 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom -@@ -1081,6 +1081,9 @@ interface NetworkContext { +@@ -1106,6 +1106,9 @@ interface NetworkContext { SetNetworkConditions(mojo_base.mojom.UnguessableToken throttling_profile_id, NetworkConditions? conditions); @@ -77,14 +77,14 @@ index ae0a20a7a33e5a313f5545985a34e9cb93220996..aeb0ac8731689e5495ab039d30ac3e88 SetAcceptLanguage(string new_accept_language); diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h -index d143a82b1fd021bb03b760b91e87c7714f5395b9..3c18369ff3ab80430e21caac03373605dad64a88 100644 +index 52f08526b9988beae7ec5b0fa44ced84d38f73ce..3f55bfcf0ed5dd83e73984cb3ba16cfa1fb7b685 100644 --- a/services/network/test/test_network_context.h +++ b/services/network/test/test_network_context.h -@@ -136,6 +136,7 @@ class TestNetworkContext : public mojom::NetworkContext { +@@ -134,6 +134,7 @@ class TestNetworkContext : public mojom::NetworkContext { void CloseIdleConnections(CloseIdleConnectionsCallback callback) override {} void SetNetworkConditions(const base::UnguessableToken& throttling_profile_id, mojom::NetworkConditionsPtr conditions) override {} + void SetUserAgent(const std::string& new_user_agent) override {} void SetAcceptLanguage(const std::string& new_accept_language) override {} void SetEnableReferrers(bool enable_referrers) override {} - #if BUILDFLAG(IS_CHROMEOS) + void SetEnablePreconnect(bool enable_preconnect) override {} diff --git a/patches/chromium/extend_apply_webpreferences.patch b/patches/chromium/extend_apply_webpreferences.patch index c09e711620b05..95c55e850c28a 100644 --- a/patches/chromium/extend_apply_webpreferences.patch +++ b/patches/chromium/extend_apply_webpreferences.patch @@ -12,18 +12,18 @@ Ideally we could add an embedder observer pattern here but that can be done in future work. 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 182f70b2b3bd9cbc6548d4c17caad797e5dad0ce..f78d5246a9e5f17089d47f95da22e922b6699057 100644 +index 40aa3b1a5c569e66b6f5d1630afe248c40d5715b..d61f63d5c16f3d93b301f1a338ae329b6f034753 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc -@@ -158,6 +158,7 @@ - #include "third_party/blink/renderer/core/timing/dom_window_performance.h" +@@ -164,6 +164,7 @@ #include "third_party/blink/renderer/core/timing/window_performance.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" + #include "third_party/blink/renderer/platform/fonts/generic_font_family_settings.h" +#include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/graphics/image.h" #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h" -@@ -1776,6 +1777,7 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs, +@@ -1807,6 +1808,7 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs, #if BUILDFLAG(IS_MAC) web_view_impl->SetMaximumLegibleScale( prefs.default_maximum_page_scale_factor); diff --git a/patches/chromium/feat_add_data_parameter_to_processsingleton.patch b/patches/chromium/feat_add_data_parameter_to_processsingleton.patch new file mode 100644 index 0000000000000..d78049c092ce3 --- /dev/null +++ b/patches/chromium/feat_add_data_parameter_to_processsingleton.patch @@ -0,0 +1,347 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Raymond Zhao +Date: Tue, 7 Sep 2021 14:54:25 -0700 +Subject: feat: Add data parameter to ProcessSingleton + +This patch adds an additional_data parameter to the constructor of +ProcessSingleton, so that the second instance can send additional +data over to the first instance while requesting the ProcessSingleton +lock. + +On the Electron side, we then expose an extra parameter to the +app.requestSingleInstanceLock API so that users can pass in a JSON +object for the second instance to send to the first instance. + +diff --git a/chrome/browser/process_singleton.h b/chrome/browser/process_singleton.h +index 5a64220aaf1309832dc0ad543e353de67fe0a779..55a2a78ce166a65cd11b26e0aa31968f6a10bec8 100644 +--- a/chrome/browser/process_singleton.h ++++ b/chrome/browser/process_singleton.h +@@ -18,6 +18,7 @@ + #include "base/files/file_path.h" + #include "base/memory/ref_counted.h" + #include "base/process/process.h" ++#include "base/containers/span.h" + #include "ui/gfx/native_widget_types.h" + + #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) +@@ -99,22 +100,25 @@ class ProcessSingleton { + // handled within the current browser instance or false if the remote process + // should handle it (i.e., because the current process is shutting down). + using NotificationCallback = +- base::RepeatingCallback; ++ base::RepeatingCallback additional_data)>; + + #if BUILDFLAG(IS_WIN) + ProcessSingleton(const std::string& program_name, + const base::FilePath& user_data_dir, ++ const base::span additional_data, + bool is_sandboxed, + const NotificationCallback& notification_callback); + #else + ProcessSingleton(const base::FilePath& user_data_dir, ++ const base::span additional_data, + const NotificationCallback& notification_callback); ++#endif + + ProcessSingleton(const ProcessSingleton&) = delete; + ProcessSingleton& operator=(const ProcessSingleton&) = delete; + +-#endif + ~ProcessSingleton(); + + // Notify another process, if available. Otherwise sets ourselves as the +@@ -177,7 +181,10 @@ class ProcessSingleton { + #endif + + private: ++ // A callback to run when the first instance receives data from the second. + NotificationCallback notification_callback_; // Handler for notifications. ++ // Custom data to pass to the other instance during notify. ++ base::span additional_data_; + + #if BUILDFLAG(IS_WIN) + bool EscapeVirtualization(const base::FilePath& user_data_dir); +diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc +index 2de07460462632680f9b16a019744527dcee5125..f7e7edd645f212750704d45a2967f584fab81b35 100644 +--- a/chrome/browser/process_singleton_posix.cc ++++ b/chrome/browser/process_singleton_posix.cc +@@ -607,6 +607,7 @@ class ProcessSingleton::LinuxWatcher + // |reader| is for sending back ACK message. + void HandleMessage(const std::string& current_dir, + const std::vector& argv, ++ const std::vector additional_data, + SocketReader* reader); + + private: +@@ -661,13 +662,16 @@ void ProcessSingleton::LinuxWatcher::StartListening(int socket) { + } + + void ProcessSingleton::LinuxWatcher::HandleMessage( +- const std::string& current_dir, const std::vector& argv, ++ const std::string& current_dir, ++ const std::vector& argv, ++ const std::vector additional_data, + SocketReader* reader) { + DCHECK(ui_task_runner_->BelongsToCurrentThread()); + DCHECK(reader); + + if (parent_->notification_callback_.Run(base::CommandLine(argv), +- base::FilePath(current_dir))) { ++ base::FilePath(current_dir), ++ std::move(additional_data))) { + // Send back "ACK" message to prevent the client process from starting up. + reader->FinishWithACK(kACKToken, std::size(kACKToken) - 1); + } else { +@@ -715,7 +719,8 @@ void ProcessSingleton::LinuxWatcher::SocketReader:: + } + } + +- // Validate the message. The shortest message is kStartToken\0x\0x ++ // Validate the message. The shortest message kStartToken\0\00 ++ // The shortest message with additional data is kStartToken\0\00\00\0. + const size_t kMinMessageLength = std::size(kStartToken) + 4; + if (bytes_read_ < kMinMessageLength) { + buf_[bytes_read_] = 0; +@@ -745,10 +750,28 @@ void ProcessSingleton::LinuxWatcher::SocketReader:: + tokens.erase(tokens.begin()); + tokens.erase(tokens.begin()); + ++ size_t num_args; ++ base::StringToSizeT(tokens[0], &num_args); ++ std::vector command_line(tokens.begin() + 1, tokens.begin() + 1 + num_args); ++ ++ std::vector additional_data; ++ if (tokens.size() >= 3 + num_args) { ++ size_t additional_data_size; ++ base::StringToSizeT(tokens[1 + num_args], &additional_data_size); ++ std::string remaining_args = base::JoinString( ++ base::make_span(tokens.begin() + 2 + num_args, tokens.end()), ++ std::string(1, kTokenDelimiter)); ++ const uint8_t* additional_data_bits = ++ reinterpret_cast(remaining_args.c_str()); ++ additional_data = std::vector( ++ additional_data_bits, additional_data_bits + additional_data_size); ++ } ++ + // Return to the UI thread to handle opening a new browser tab. + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&ProcessSingleton::LinuxWatcher::HandleMessage, +- parent_, current_dir, tokens, this)); ++ parent_, current_dir, command_line, ++ std::move(additional_data), this)); + fd_watch_controller_.reset(); + + // LinuxWatcher::HandleMessage() is in charge of destroying this SocketReader +@@ -777,8 +800,10 @@ void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK( + // + ProcessSingleton::ProcessSingleton( + const base::FilePath& user_data_dir, ++ const base::span additional_data, + const NotificationCallback& notification_callback) + : notification_callback_(notification_callback), ++ additional_data_(additional_data), + current_pid_(base::GetCurrentProcId()), + watcher_(new LinuxWatcher(this)) { + socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename); +@@ -897,7 +922,8 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( + sizeof(socket_timeout)); + + // Found another process, prepare our command line +- // format is "START\0\0\0...\0". ++ // format is "START\0\0\0\0...\0 ++ // \0\0". + std::string to_send(kStartToken); + to_send.push_back(kTokenDelimiter); + +@@ -907,11 +933,21 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( + to_send.append(current_dir.value()); + + const std::vector& argv = cmd_line.argv(); ++ to_send.push_back(kTokenDelimiter); ++ to_send.append(base::NumberToString(argv.size())); + for (auto it = argv.begin(); it != argv.end(); ++it) { + to_send.push_back(kTokenDelimiter); + to_send.append(*it); + } + ++ size_t data_to_send_size = additional_data_.size_bytes(); ++ if (data_to_send_size) { ++ to_send.push_back(kTokenDelimiter); ++ to_send.append(base::NumberToString(data_to_send_size)); ++ to_send.push_back(kTokenDelimiter); ++ to_send.append(reinterpret_cast(additional_data_.data()), data_to_send_size); ++ } ++ + // Send the message + if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { + // Try to kill the other process, because it might have been dead. +diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc +index 0c87fc8ccb4511904f19b76ae5e03a5df6664391..c34d4fe10781e6b9286a43176f7312da4e815caf 100644 +--- a/chrome/browser/process_singleton_win.cc ++++ b/chrome/browser/process_singleton_win.cc +@@ -80,10 +80,12 @@ BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { + + bool ParseCommandLine(const COPYDATASTRUCT* cds, + base::CommandLine* parsed_command_line, +- base::FilePath* current_directory) { ++ base::FilePath* current_directory, ++ std::vector* parsed_additional_data) { + // We should have enough room for the shortest command (min_message_size) + // and also be a multiple of wchar_t bytes. The shortest command +- // possible is L"START\0\0" (empty current directory and command line). ++ // possible is L"START\0\0" (empty command line, current directory, ++ // and additional data). + static const int min_message_size = 7; + if (cds->cbData < min_message_size * sizeof(wchar_t) || + cds->cbData % sizeof(wchar_t) != 0) { +@@ -133,6 +135,37 @@ bool ParseCommandLine(const COPYDATASTRUCT* cds, + const std::wstring cmd_line = + msg.substr(second_null + 1, third_null - second_null); + *parsed_command_line = base::CommandLine::FromString(cmd_line); ++ ++ const std::wstring::size_type fourth_null = ++ msg.find_first_of(L'\0', third_null + 1); ++ if (fourth_null == std::wstring::npos || ++ fourth_null == msg.length()) { ++ // No additional data was provided. ++ return true; ++ } ++ ++ // Get length of the additional data. ++ const std::wstring additional_data_length_string = ++ msg.substr(third_null + 1, fourth_null - third_null); ++ size_t additional_data_length; ++ base::StringToSizeT(additional_data_length_string, &additional_data_length); ++ ++ const std::wstring::size_type fifth_null = ++ msg.find_first_of(L'\0', fourth_null + 1); ++ if (fifth_null == std::wstring::npos || ++ fifth_null == msg.length()) { ++ LOG(WARNING) << "Invalid format for start command, we need a string in 6 " ++ "parts separated by NULLs"; ++ } ++ ++ // Get the actual additional data. ++ const std::wstring additional_data = ++ msg.substr(fourth_null + 1, fifth_null - fourth_null); ++ const uint8_t* additional_data_bytes = ++ reinterpret_cast(additional_data.c_str()); ++ *parsed_additional_data = std::vector(additional_data_bytes, ++ additional_data_bytes + additional_data_length); ++ + return true; + } + return false; +@@ -154,13 +187,14 @@ bool ProcessLaunchNotification( + + base::CommandLine parsed_command_line(base::CommandLine::NO_PROGRAM); + base::FilePath current_directory; +- if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) { ++ std::vector additional_data; ++ if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory, &additional_data)) { + *result = TRUE; + return true; + } + +- *result = notification_callback.Run(parsed_command_line, current_directory) ? +- TRUE : FALSE; ++ *result = notification_callback.Run(parsed_command_line, ++ current_directory, std::move(additional_data)) ? TRUE : FALSE; + return true; + } + +@@ -261,9 +295,11 @@ bool ProcessSingleton::EscapeVirtualization( + ProcessSingleton::ProcessSingleton( + const std::string& program_name, + const base::FilePath& user_data_dir, ++ const base::span additional_data, + bool is_app_sandboxed, + const NotificationCallback& notification_callback) + : notification_callback_(notification_callback), ++ additional_data_(additional_data), + program_name_(program_name), + is_app_sandboxed_(is_app_sandboxed), + is_virtualized_(false), +@@ -290,7 +326,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { + return PROCESS_NONE; + } + +- switch (chrome::AttemptToNotifyRunningChrome(remote_window_)) { ++ switch (chrome::AttemptToNotifyRunningChrome(remote_window_, additional_data_)) { + case chrome::NOTIFY_SUCCESS: + return PROCESS_NOTIFIED; + case chrome::NOTIFY_FAILED: +diff --git a/chrome/browser/win/chrome_process_finder.cc b/chrome/browser/win/chrome_process_finder.cc +index b64ed1d155a30582e48c9cdffcee9d0f25a53a6a..cfdb2d75532d270e3dd548eb7475a6cdbddf1016 100644 +--- a/chrome/browser/win/chrome_process_finder.cc ++++ b/chrome/browser/win/chrome_process_finder.cc +@@ -36,7 +36,9 @@ HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) { + return base::win::MessageWindow::FindWindow(user_data_dir.value()); + } + +-NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) { ++NotifyChromeResult AttemptToNotifyRunningChrome( ++ HWND remote_window, ++ const base::span additional_data) { + TRACE_EVENT0("startup", "AttemptToNotifyRunningChrome"); + + DCHECK(remote_window); +@@ -50,7 +52,8 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) { + } + + // Send the command line to the remote chrome window. +- // Format is "START\0<<>>\0<<>>". ++ // Format is ++ // "START\0\0\0\0". + std::wstring to_send(L"START\0", 6); // want the NULL in the string. + base::FilePath cur_dir; + if (!base::GetCurrentDirectory(&cur_dir)) { +@@ -64,6 +67,22 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) { + base::CommandLine::ForCurrentProcess()->GetCommandLineString()); + to_send.append(L"\0", 1); // Null separator. + ++ size_t additional_data_size = additional_data.size_bytes(); ++ if (additional_data_size) { ++ // Send over the size, because the reinterpret cast to wchar_t could ++ // add padding. ++ to_send.append(base::UTF8ToWide(base::NumberToString(additional_data_size))); ++ to_send.append(L"\0", 1); // Null separator. ++ ++ size_t padded_size = additional_data_size / sizeof(wchar_t); ++ if (additional_data_size % sizeof(wchar_t) != 0) { ++ padded_size++; ++ } ++ to_send.append(reinterpret_cast(additional_data.data()), ++ padded_size); ++ to_send.append(L"\0", 1); // Null separator. ++ } ++ + // Allow the current running browser window to make itself the foreground + // window (otherwise it will just flash in the taskbar). + ::AllowSetForegroundWindow(process_id); +diff --git a/chrome/browser/win/chrome_process_finder.h b/chrome/browser/win/chrome_process_finder.h +index 5516673cee019f6060077091e59498bf9038cd6e..8edea5079b46c2cba67833114eb9c21d85cfc22d 100644 +--- a/chrome/browser/win/chrome_process_finder.h ++++ b/chrome/browser/win/chrome_process_finder.h +@@ -7,6 +7,7 @@ + + #include + ++#include "base/containers/span.h" + #include "base/time/time.h" + + namespace base { +@@ -27,7 +28,9 @@ HWND FindRunningChromeWindow(const base::FilePath& user_data_dir); + // Attempts to send the current command line to an already running instance of + // Chrome via a WM_COPYDATA message. + // Returns true if a running Chrome is found and successfully notified. +-NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window); ++NotifyChromeResult AttemptToNotifyRunningChrome( ++ HWND remote_window, ++ const base::span additional_data); + + // Changes the notification timeout to |new_timeout|, returns the old timeout. + base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout); diff --git a/patches/chromium/feat_add_data_transfer_to_requestsingleinstancelock.patch b/patches/chromium/feat_add_data_transfer_to_requestsingleinstancelock.patch deleted file mode 100644 index ed81a384b5bd6..0000000000000 --- a/patches/chromium/feat_add_data_transfer_to_requestsingleinstancelock.patch +++ /dev/null @@ -1,612 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Raymond Zhao -Date: Tue, 7 Sep 2021 14:54:25 -0700 -Subject: feat: Add data transfer mechanism to requestSingleInstanceLock flow - -This patch adds code that allows for the second instance to send -additional data to the first instance, and for the first instance -to send additional data back to the second instance, during the -app.requestSingleInstanceLock call. - -Firstly, this patch adds an additional_data parameter -to the constructor of ProcessSingleton, so that the second instance -can send additional data over to the first instance -while requesting the ProcessSingleton lock. - -Then, we add additional processing to the second-instance event, both -so the first instance can receive additional data from the second -instance, but also so the second instance can send back additional -data to the first instance if needed. - -diff --git a/chrome/browser/process_singleton.h b/chrome/browser/process_singleton.h -index 5a64220aaf1309832dc0ad543e353de67fe0a779..a568dd10d1ef8679d66f4cdc6a471c251cbcd4eb 100644 ---- a/chrome/browser/process_singleton.h -+++ b/chrome/browser/process_singleton.h -@@ -18,6 +18,7 @@ - #include "base/files/file_path.h" - #include "base/memory/ref_counted.h" - #include "base/process/process.h" -+#include "base/containers/span.h" - #include "ui/gfx/native_widget_types.h" - - #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) -@@ -93,6 +94,9 @@ class ProcessSingleton { - - static constexpr int kNumNotifyResults = LAST_VALUE + 1; - -+ using NotificationAckCallback = -+ base::RepeatingCallback* ack_data)>; -+ - // Implement this callback to handle notifications from other processes. The - // callback will receive the command line and directory with which the other - // Chrome process was launched. Return true if the command line will be -@@ -100,21 +104,27 @@ class ProcessSingleton { - // should handle it (i.e., because the current process is shutting down). - using NotificationCallback = - base::RepeatingCallback; -+ const base::FilePath& current_directory, -+ const std::vector additional_data, -+ const NotificationAckCallback& ack_callback)>; - - #if BUILDFLAG(IS_WIN) - ProcessSingleton(const std::string& program_name, - const base::FilePath& user_data_dir, -+ const base::span additional_data, - bool is_sandboxed, -- const NotificationCallback& notification_callback); -+ const NotificationCallback& notification_callback, -+ const NotificationAckCallback& ack_notification_callback); - #else - ProcessSingleton(const base::FilePath& user_data_dir, -- const NotificationCallback& notification_callback); -+ const base::span additional_data, -+ const NotificationCallback& notification_callback, -+ const NotificationAckCallback& ack_notification_callback); -+#endif - - ProcessSingleton(const ProcessSingleton&) = delete; - ProcessSingleton& operator=(const ProcessSingleton&) = delete; - --#endif - ~ProcessSingleton(); - - // Notify another process, if available. Otherwise sets ourselves as the -@@ -177,7 +187,13 @@ class ProcessSingleton { - #endif - - private: -- NotificationCallback notification_callback_; // Handler for notifications. -+ // A callback to run when the first instance receives data from the second. -+ NotificationCallback notification_callback_; -+ // A callback to run when the second instance -+ // receives an acknowledgement from the first. -+ NotificationAckCallback notification_ack_callback_; -+ // Custom data to pass to the other instance during notify. -+ base::span additional_data_; - - #if BUILDFLAG(IS_WIN) - bool EscapeVirtualization(const base::FilePath& user_data_dir); -@@ -190,6 +206,7 @@ class ProcessSingleton { - HANDLE lock_file_; - base::FilePath user_data_dir_; - ShouldKillRemoteProcessCallback should_kill_remote_process_callback_; -+ HANDLE ack_pipe_; - #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) - // Return true if the given pid is one of our child processes. - // Assumes that the current pid is the root of all pids of the current -diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc -index 7d3a441bdb64268ed5fbfa7bf589fb35a2fd1b75..b23c16fde275fdba559abb1f30e42f65ddbfc332 100644 ---- a/chrome/browser/process_singleton_posix.cc -+++ b/chrome/browser/process_singleton_posix.cc -@@ -148,7 +148,7 @@ const char kACKToken[] = "ACK"; - const char kShutdownToken[] = "SHUTDOWN"; - const char kTokenDelimiter = '\0'; - const int kMaxMessageLength = 32 * 1024; --const int kMaxACKMessageLength = base::size(kShutdownToken) - 1; -+const int kMaxACKMessageLength = kMaxMessageLength; - - bool g_disable_prompt = false; - bool g_skip_is_chrome_process_check = false; -@@ -614,6 +614,7 @@ class ProcessSingleton::LinuxWatcher - // |reader| is for sending back ACK message. - void HandleMessage(const std::string& current_dir, - const std::vector& argv, -+ const std::vector additional_data, - SocketReader* reader); - - private: -@@ -638,6 +639,9 @@ class ProcessSingleton::LinuxWatcher - // The ProcessSingleton that owns us. - ProcessSingleton* const parent_; - -+ bool ack_callback_called_ = false; -+ void AckCallback(SocketReader* reader, const base::span* response); -+ - std::set, base::UniquePtrComparator> readers_; - }; - -@@ -668,16 +672,21 @@ void ProcessSingleton::LinuxWatcher::StartListening(int socket) { - } - - void ProcessSingleton::LinuxWatcher::HandleMessage( -- const std::string& current_dir, const std::vector& argv, -+ const std::string& current_dir, -+ const std::vector& argv, -+ const std::vector additional_data, - SocketReader* reader) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - DCHECK(reader); - -- if (parent_->notification_callback_.Run(base::CommandLine(argv), -- base::FilePath(current_dir))) { -- // Send back "ACK" message to prevent the client process from starting up. -- reader->FinishWithACK(kACKToken, base::size(kACKToken) - 1); -- } else { -+ auto wrapped_ack_callback = -+ base::BindRepeating(&ProcessSingleton::LinuxWatcher::AckCallback, -+ base::Unretained(this), reader); -+ ack_callback_called_ = false; -+ if (!parent_->notification_callback_.Run(base::CommandLine(argv), -+ base::FilePath(current_dir), -+ std::move(additional_data), -+ wrapped_ack_callback)) { - LOG(WARNING) << "Not handling interprocess notification as browser" - " is shutting down"; - // Send back "SHUTDOWN" message, so that the client process can start up -@@ -687,6 +696,22 @@ void ProcessSingleton::LinuxWatcher::HandleMessage( - } - } - -+void ProcessSingleton::LinuxWatcher::AckCallback( -+ SocketReader* reader, -+ const base::span* response) { -+ // Send back "ACK" message to prevent the client process from starting up. -+ if (!ack_callback_called_) { -+ ack_callback_called_ = true; -+ std::string ack_message; -+ ack_message.append(kACKToken, base::size(kACKToken) - 1); -+ if (response && response->size_bytes()) { -+ ack_message.append(reinterpret_cast(response->data()), -+ response->size_bytes()); -+ } -+ reader->FinishWithACK(ack_message.c_str(), ack_message.size()); -+ } -+} -+ - void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(reader); -@@ -722,7 +747,8 @@ void ProcessSingleton::LinuxWatcher::SocketReader:: - } - } - -- // Validate the message. The shortest message is kStartToken\0x\0x -+ // Validate the message. The shortest message kStartToken\0\00 -+ // The shortest message with additional data is kStartToken\0\00\00\0. - const size_t kMinMessageLength = base::size(kStartToken) + 4; - if (bytes_read_ < kMinMessageLength) { - buf_[bytes_read_] = 0; -@@ -752,10 +778,28 @@ void ProcessSingleton::LinuxWatcher::SocketReader:: - tokens.erase(tokens.begin()); - tokens.erase(tokens.begin()); - -+ size_t num_args; -+ base::StringToSizeT(tokens[0], &num_args); -+ std::vector command_line(tokens.begin() + 1, tokens.begin() + 1 + num_args); -+ -+ std::vector additional_data; -+ if (tokens.size() >= 3 + num_args) { -+ size_t additional_data_size; -+ base::StringToSizeT(tokens[1 + num_args], &additional_data_size); -+ std::string remaining_args = base::JoinString( -+ base::make_span(tokens.begin() + 2 + num_args, tokens.end()), -+ std::string(1, kTokenDelimiter)); -+ const uint8_t* additional_data_bits = -+ reinterpret_cast(remaining_args.c_str()); -+ additional_data = std::vector(additional_data_bits, -+ additional_data_bits + additional_data_size); -+ } -+ - // Return to the UI thread to handle opening a new browser tab. - ui_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&ProcessSingleton::LinuxWatcher::HandleMessage, -- parent_, current_dir, tokens, this)); -+ parent_, current_dir, command_line, -+ std::move(additional_data), this)); - fd_watch_controller_.reset(); - - // LinuxWatcher::HandleMessage() is in charge of destroying this SocketReader -@@ -784,8 +828,12 @@ void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK( - // - ProcessSingleton::ProcessSingleton( - const base::FilePath& user_data_dir, -- const NotificationCallback& notification_callback) -+ const base::span additional_data, -+ const NotificationCallback& notification_callback, -+ const NotificationAckCallback& notification_ack_callback) - : notification_callback_(notification_callback), -+ notification_ack_callback_(notification_ack_callback), -+ additional_data_(additional_data), - current_pid_(base::GetCurrentProcId()), - watcher_(new LinuxWatcher(this)) { - socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename); -@@ -904,7 +952,8 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( - sizeof(socket_timeout)); - - // Found another process, prepare our command line -- // format is "START\0\0\0...\0". -+ // format is "START\0\0\0\0...\0 -+ // \0\0". - std::string to_send(kStartToken); - to_send.push_back(kTokenDelimiter); - -@@ -914,11 +963,21 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( - to_send.append(current_dir.value()); - - const std::vector& argv = cmd_line.argv(); -+ to_send.push_back(kTokenDelimiter); -+ to_send.append(base::NumberToString(argv.size())); - for (auto it = argv.begin(); it != argv.end(); ++it) { - to_send.push_back(kTokenDelimiter); - to_send.append(*it); - } - -+ size_t data_to_send_size = additional_data_.size_bytes(); -+ if (data_to_send_size) { -+ to_send.push_back(kTokenDelimiter); -+ to_send.append(base::NumberToString(data_to_send_size)); -+ to_send.push_back(kTokenDelimiter); -+ to_send.append(reinterpret_cast(additional_data_.data()), data_to_send_size); -+ } -+ - // Send the message - if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { - // Try to kill the other process, because it might have been dead. -@@ -960,6 +1019,17 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( - linux_ui->NotifyWindowManagerStartupComplete(); - #endif - -+ size_t ack_data_len = len - (base::size(kACKToken) - 1); -+ if (ack_data_len) { -+ const uint8_t* raw_ack_data = -+ reinterpret_cast(buf + base::size(kACKToken) - 1); -+ base::span ack_data = -+ base::make_span(raw_ack_data, raw_ack_data + ack_data_len); -+ notification_ack_callback_.Run(&ack_data); -+ } else { -+ notification_ack_callback_.Run(nullptr); -+ } -+ - // Assume the other process is handling the request. - return PROCESS_NOTIFIED; - } -diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc -index 0ea5eb3e3cf055d981ab73486115bac53287f2d7..6225f09da02ce231e9a2a6a8d874818eae1cc79e 100644 ---- a/chrome/browser/process_singleton_win.cc -+++ b/chrome/browser/process_singleton_win.cc -@@ -21,6 +21,7 @@ - #include "base/strings/string_number_conversions.h" - #include "base/strings/utf_string_conversions.h" - #include "base/time/time.h" -+#include "base/timer/timer.h" - #include "base/trace_event/base_tracing.h" - #include "base/win/registry.h" - #include "base/win/scoped_handle.h" -@@ -45,6 +46,14 @@ - namespace { - - const char kLockfile[] = "lockfile"; -+const LPCWSTR kPipeName = L"\\\\.\\pipe\\electronAckPipe"; -+const DWORD kPipeTimeout = 10000; -+const DWORD kMaxMessageLength = 32 * 1024; -+ -+std::unique_ptr> g_ack_data; -+base::OneShotTimer g_ack_timer; -+HANDLE g_write_ack_pipe; -+bool g_write_ack_callback_called = false; - - // A helper class that acquires the given |mutex| while the AutoLockMutex is in - // scope. -@@ -80,10 +89,12 @@ BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { - - bool ParseCommandLine(const COPYDATASTRUCT* cds, - base::CommandLine* parsed_command_line, -- base::FilePath* current_directory) { -+ base::FilePath* current_directory, -+ std::vector* parsed_additional_data) { - // We should have enough room for the shortest command (min_message_size) - // and also be a multiple of wchar_t bytes. The shortest command -- // possible is L"START\0\0" (empty current directory and command line). -+ // possible is L"START\0\0" (empty command line, current directory, -+ // and additional data). - static const int min_message_size = 7; - if (cds->cbData < min_message_size * sizeof(wchar_t) || - cds->cbData % sizeof(wchar_t) != 0) { -@@ -133,11 +144,82 @@ bool ParseCommandLine(const COPYDATASTRUCT* cds, - const std::wstring cmd_line = - msg.substr(second_null + 1, third_null - second_null); - *parsed_command_line = base::CommandLine::FromString(cmd_line); -+ -+ const std::wstring::size_type fourth_null = -+ msg.find_first_of(L'\0', third_null + 1); -+ if (fourth_null == std::wstring::npos || -+ fourth_null == msg.length()) { -+ // No additional data was provided. -+ return true; -+ } -+ -+ // Get length of the additional data. -+ const std::wstring additional_data_length_string = -+ msg.substr(third_null + 1, fourth_null - third_null); -+ size_t additional_data_length; -+ base::StringToSizeT(additional_data_length_string, &additional_data_length); -+ -+ const std::wstring::size_type fifth_null = -+ msg.find_first_of(L'\0', fourth_null + 1); -+ if (fifth_null == std::wstring::npos || -+ fifth_null == msg.length()) { -+ LOG(WARNING) << "Invalid format for start command, we need a string in 6 " -+ "parts separated by NULLs"; -+ } -+ -+ // Get the actual additional data. -+ const std::wstring additional_data = -+ msg.substr(fourth_null + 1, fifth_null - fourth_null); -+ const uint8_t* additional_data_bytes = -+ reinterpret_cast(additional_data.c_str()); -+ *parsed_additional_data = std::vector(additional_data_bytes, -+ additional_data_bytes + additional_data_length); -+ - return true; - } - return false; - } - -+void StoreAck(const base::span* ack_data) { -+ if (ack_data) { -+ g_ack_data = std::make_unique>(ack_data->begin(), -+ ack_data->end()); -+ } else { -+ g_ack_data = nullptr; -+ } -+} -+ -+void SendBackAck() { -+ // This is the first instance sending the ack back to the second instance. -+ if (!g_write_ack_callback_called) { -+ g_write_ack_callback_called = true; -+ const uint8_t* data_buffer = nullptr; -+ DWORD data_to_send_size = 0; -+ if (g_ack_data) { -+ data_buffer = g_ack_data->data(); -+ DWORD ack_data_size = g_ack_data->size() * sizeof(uint8_t); -+ data_to_send_size = (ack_data_size < kMaxMessageLength) ? ack_data_size : kMaxMessageLength; -+ } -+ -+ ::ConnectNamedPipe(g_write_ack_pipe, NULL); -+ -+ DWORD bytes_written = 0; -+ ::WriteFile(g_write_ack_pipe, -+ (LPCVOID)data_buffer, -+ data_to_send_size, -+ &bytes_written, -+ NULL); -+ DCHECK(bytes_written == data_to_send_size); -+ -+ ::FlushFileBuffers(g_write_ack_pipe); -+ ::DisconnectNamedPipe(g_write_ack_pipe); -+ -+ if (g_ack_data) { -+ g_ack_data.reset(); -+ } -+ } -+} -+ - bool ProcessLaunchNotification( - const ProcessSingleton::NotificationCallback& notification_callback, - UINT message, -@@ -151,16 +233,35 @@ bool ProcessLaunchNotification( - - // Handle the WM_COPYDATA message from another process. - const COPYDATASTRUCT* cds = reinterpret_cast(lparam); -- - base::CommandLine parsed_command_line(base::CommandLine::NO_PROGRAM); - base::FilePath current_directory; -- if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) { -+ std::vector additional_data; -+ if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory, -+ &additional_data)) { - *result = TRUE; - return true; - } - -- *result = notification_callback.Run(parsed_command_line, current_directory) ? -- TRUE : FALSE; -+ // notification_callback.Run waits for StoreAck to -+ // run to completion before moving onwards. -+ // Therefore, we cannot directly send the SendBackAck -+ // callback instead, as it would hang the program -+ // during the ConnectNamedPipe call. -+ g_write_ack_callback_called = false; -+ *result = notification_callback.Run(parsed_command_line, current_directory, -+ std::move(additional_data), -+ base::BindRepeating(&StoreAck)) -+ ? TRUE -+ : FALSE; -+ if (*result) { -+ // If *result is TRUE, we return NOTIFY_SUCCESS. -+ // Only for that case does the second process read -+ // the acknowledgement. Therefore, only send back -+ // the acknowledgement if *result is TRUE, -+ // otherwise the program hangs during the ConnectNamedPipe call. -+ g_ack_timer.Start(FROM_HERE, base::Seconds(0), -+ base::BindOnce(&SendBackAck)); -+ } - return true; - } - -@@ -254,9 +355,13 @@ bool ProcessSingleton::EscapeVirtualization( - ProcessSingleton::ProcessSingleton( - const std::string& program_name, - const base::FilePath& user_data_dir, -+ const base::span additional_data, - bool is_app_sandboxed, -- const NotificationCallback& notification_callback) -+ const NotificationCallback& notification_callback, -+ const NotificationAckCallback& notification_ack_callback) - : notification_callback_(notification_callback), -+ notification_ack_callback_(notification_ack_callback), -+ additional_data_(additional_data), - program_name_(program_name), - is_app_sandboxed_(is_app_sandboxed), - is_virtualized_(false), -@@ -271,6 +376,37 @@ ProcessSingleton::~ProcessSingleton() { - ::CloseHandle(lock_file_); - } - -+void ReadAck(const ProcessSingleton::NotificationAckCallback& ack_callback) { -+ // We are reading the ack from the first instance. -+ // First, wait for the pipe. -+ ::WaitNamedPipe(kPipeName, NMPWAIT_USE_DEFAULT_WAIT); -+ -+ HANDLE read_ack_pipe = ::CreateFile(kPipeName, -+ GENERIC_READ, -+ FILE_SHARE_READ, -+ NULL, -+ OPEN_EXISTING, -+ FILE_ATTRIBUTE_NORMAL, -+ NULL); -+ CHECK(read_ack_pipe != INVALID_HANDLE_VALUE); -+ -+ DWORD bytes_read; -+ uint8_t read_ack_buffer[kMaxMessageLength]; -+ ::ReadFile(read_ack_pipe, -+ (LPVOID)read_ack_buffer, -+ kMaxMessageLength, -+ &bytes_read, -+ NULL); -+ -+ if (!bytes_read) { -+ ack_callback.Run(nullptr); -+ } else { -+ base::span out_span(read_ack_buffer, read_ack_buffer + bytes_read); -+ ack_callback.Run(&out_span); -+ } -+ ::CloseHandle(read_ack_pipe); -+} -+ - // Code roughly based on Mozilla. - ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { - TRACE_EVENT0("startup", "ProcessSingleton::NotifyOtherProcess"); -@@ -283,8 +419,9 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { - return PROCESS_NONE; - } - -- switch (chrome::AttemptToNotifyRunningChrome(remote_window_)) { -+ switch (chrome::AttemptToNotifyRunningChrome(remote_window_, additional_data_)) { - case chrome::NOTIFY_SUCCESS: -+ ReadAck(notification_ack_callback_); - return PROCESS_NOTIFIED; - case chrome::NOTIFY_FAILED: - remote_window_ = NULL; -@@ -422,6 +559,18 @@ bool ProcessSingleton::Create() { - << "Lock file can not be created! Error code: " << error; - - if (lock_file_ != INVALID_HANDLE_VALUE) { -+ // We are the first instance. Create a pipe to send out ack data. -+ ack_pipe_ = ::CreateNamedPipe(kPipeName, -+ PIPE_ACCESS_OUTBOUND, -+ PIPE_TYPE_BYTE | PIPE_REJECT_REMOTE_CLIENTS, -+ PIPE_UNLIMITED_INSTANCES, -+ kMaxMessageLength, -+ 0, -+ kPipeTimeout, -+ NULL); -+ CHECK(ack_pipe_ != INVALID_HANDLE_VALUE); -+ g_write_ack_pipe = ack_pipe_; -+ - // Set the window's title to the path of our user data directory so - // other Chrome instances can decide if they should forward to us. - TRACE_EVENT0("startup", "ProcessSingleton::Create:CreateWindow"); -@@ -449,6 +598,7 @@ bool ProcessSingleton::Create() { - } - - void ProcessSingleton::Cleanup() { -+ ::CloseHandle(ack_pipe_); - } - - void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting( -diff --git a/chrome/browser/win/chrome_process_finder.cc b/chrome/browser/win/chrome_process_finder.cc -index b64ed1d155a30582e48c9cdffcee9d0f25a53a6a..ce851d09d501ebcc6d6c4065e746e869d5275b2b 100644 ---- a/chrome/browser/win/chrome_process_finder.cc -+++ b/chrome/browser/win/chrome_process_finder.cc -@@ -36,9 +36,10 @@ HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) { - return base::win::MessageWindow::FindWindow(user_data_dir.value()); - } - --NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) { -+NotifyChromeResult AttemptToNotifyRunningChrome( -+ HWND remote_window, -+ const base::span additional_data) { - TRACE_EVENT0("startup", "AttemptToNotifyRunningChrome"); -- - DCHECK(remote_window); - DWORD process_id = 0; - DWORD thread_id = GetWindowThreadProcessId(remote_window, &process_id); -@@ -50,7 +51,8 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) { - } - - // Send the command line to the remote chrome window. -- // Format is "START\0<<>>\0<<>>". -+ // Format is -+ // "START\0\0\0\0". - std::wstring to_send(L"START\0", 6); // want the NULL in the string. - base::FilePath cur_dir; - if (!base::GetCurrentDirectory(&cur_dir)) { -@@ -64,6 +66,22 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) { - base::CommandLine::ForCurrentProcess()->GetCommandLineString()); - to_send.append(L"\0", 1); // Null separator. - -+ size_t additional_data_size = additional_data.size_bytes(); -+ if (additional_data_size) { -+ // Send over the size, because the reinterpret cast to wchar_t could -+ // add padding. -+ to_send.append(base::UTF8ToWide(base::NumberToString(additional_data_size))); -+ to_send.append(L"\0", 1); // Null separator. -+ -+ size_t padded_size = additional_data_size / sizeof(wchar_t); -+ if (additional_data_size % sizeof(wchar_t) != 0) { -+ padded_size++; -+ } -+ to_send.append(reinterpret_cast(additional_data.data()), -+ padded_size); -+ to_send.append(L"\0", 1); // Null separator. -+ } -+ - // Allow the current running browser window to make itself the foreground - // window (otherwise it will just flash in the taskbar). - ::AllowSetForegroundWindow(process_id); -diff --git a/chrome/browser/win/chrome_process_finder.h b/chrome/browser/win/chrome_process_finder.h -index 5516673cee019f6060077091e59498bf9038cd6e..8edea5079b46c2cba67833114eb9c21d85cfc22d 100644 ---- a/chrome/browser/win/chrome_process_finder.h -+++ b/chrome/browser/win/chrome_process_finder.h -@@ -7,6 +7,7 @@ - - #include - -+#include "base/containers/span.h" - #include "base/time/time.h" - - namespace base { -@@ -27,7 +28,9 @@ HWND FindRunningChromeWindow(const base::FilePath& user_data_dir); - // Attempts to send the current command line to an already running instance of - // Chrome via a WM_COPYDATA message. - // Returns true if a running Chrome is found and successfully notified. --NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window); -+NotifyChromeResult AttemptToNotifyRunningChrome( -+ HWND remote_window, -+ const base::span additional_data); - - // Changes the notification timeout to |new_timeout|, returns the old timeout. - base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout); diff --git a/patches/chromium/feat_add_onclose_to_messageport.patch b/patches/chromium/feat_add_onclose_to_messageport.patch index cf52cfa05ff50..70559ec9c26f6 100644 --- a/patches/chromium/feat_add_onclose_to_messageport.patch +++ b/patches/chromium/feat_add_onclose_to_messageport.patch @@ -10,10 +10,10 @@ get this standardised, but in lieu of that, this makes MessagePort a whole bunch more useful! diff --git a/third_party/blink/renderer/core/messaging/message_port.cc b/third_party/blink/renderer/core/messaging/message_port.cc -index c5714d115210488cb531c1e54de540f429636638..6f67b21803fcdc2498ef207878d1541e04822fca 100644 +index 747ce956e2622e1bb881cf281365419743ef933f..43196369af48b7393919d2624451aa3528ed1c0a 100644 --- a/third_party/blink/renderer/core/messaging/message_port.cc +++ b/third_party/blink/renderer/core/messaging/message_port.cc -@@ -161,6 +161,7 @@ void MessagePort::close() { +@@ -167,6 +167,7 @@ void MessagePort::close() { Entangle(pipe.TakePort0()); } closed_ = true; @@ -22,7 +22,7 @@ index c5714d115210488cb531c1e54de540f429636638..6f67b21803fcdc2498ef207878d1541e void MessagePort::Entangle(MessagePortDescriptor port) { diff --git a/third_party/blink/renderer/core/messaging/message_port.h b/third_party/blink/renderer/core/messaging/message_port.h -index c5e0fefac929d4a484488761741d42f2b002f7a1..83d7901d99ad01ba039ea1ffa3dbee2595fc31ff 100644 +index 30d13d1e47e3acc7df6ce5c627fd7b3a32c3edc4..f9baba3c6d13992508da48a13c97bb10c8ec56e0 100644 --- a/third_party/blink/renderer/core/messaging/message_port.h +++ b/third_party/blink/renderer/core/messaging/message_port.h @@ -120,6 +120,13 @@ class CORE_EXPORT MessagePort : public EventTargetWithInlineData, diff --git a/patches/chromium/feat_add_set_can_resize_mutator.patch b/patches/chromium/feat_add_set_can_resize_mutator.patch new file mode 100644 index 0000000000000..5b2adba9ecd49 --- /dev/null +++ b/patches/chromium/feat_add_set_can_resize_mutator.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> +Date: Tue, 2 Aug 2022 09:30:36 -0700 +Subject: feat: Add set_can_resize mutator + +Adds a set_can_resize mutator to WidgetDelegate that +doesn't emit the OnSizeConstraintsChanged event. +This way, we can call set_can_resize from Electron before +the widget is initialized to set the value earlier, +and in turn, avoid showing a frame at startup +for frameless applications. + +diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h +index 431d19f2543a9011de76b941982603ff98afa041..32e07e0c9686e6942a40c4d4775a03068cfd33b5 100644 +--- a/ui/views/widget/widget_delegate.h ++++ b/ui/views/widget/widget_delegate.h +@@ -323,6 +323,10 @@ class VIEWS_EXPORT WidgetDelegate { + // be cycled through with keyboard focus. + virtual void GetAccessiblePanes(std::vector* panes) {} + ++ // A setter for the can_resize parameter that doesn't ++ // emit any events. ++ void set_can_resize(bool can_resize) { params_.can_resize = can_resize; } ++ + // Setters for data parameters of the WidgetDelegate. If you use these + // setters, there is no need to override the corresponding virtual getters. + void SetAccessibleRole(ax::mojom::Role role); diff --git a/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch b/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch index fbd9cec05e06c..4ce0b49181b6a 100644 --- a/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch +++ b/patches/chromium/feat_add_set_theme_source_to_allow_apps_to.patch @@ -13,10 +13,10 @@ uses internally for things like menus and devtools. We can remove this patch once it has in some shape been upstreamed. diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc -index 5376b01ad03c346ecc1c5d47ff125103dbc05eb8..a60ce1d4fe6b7132d7adac1a7687c7185d1abee3 100644 +index d7be414239f8e120c3b833a5f12ef06d0b3e57b5..eb6f2cd02483a7cf398fc6631f6b46cf336b481e 100644 --- a/ui/native_theme/native_theme.cc +++ b/ui/native_theme/native_theme.cc -@@ -114,6 +114,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors, +@@ -124,6 +124,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors, NativeTheme::~NativeTheme() = default; bool NativeTheme::ShouldUseDarkColors() const { @@ -26,12 +26,12 @@ index 5376b01ad03c346ecc1c5d47ff125103dbc05eb8..a60ce1d4fe6b7132d7adac1a7687c718 } diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h -index e46bc2cf64ca554c0e21a4e0851ad092f504e080..0ffe583d56ddc3abec8c848c1cd5dbc3623acb5b 100644 +index bd6a77d5f0f5dd93ea57455651d3cc5024dc45fb..63f4bee073cdcb5b37662b60a9bb0386d7f480c0 100644 --- a/ui/native_theme/native_theme.h +++ b/ui/native_theme/native_theme.h -@@ -389,6 +389,23 @@ class NATIVE_THEME_EXPORT NativeTheme { - scoped_refptr custom_theme) - const; +@@ -406,6 +406,23 @@ class NATIVE_THEME_EXPORT NativeTheme { + custom_theme, + bool use_custom_frame = true) const; + + enum ThemeSource { @@ -53,8 +53,8 @@ index e46bc2cf64ca554c0e21a4e0851ad092f504e080..0ffe583d56ddc3abec8c848c1cd5dbc3 // Returns a shared instance of the native theme that should be used for web // rendering. Do not use it in a normal application context (i.e. browser). // The returned object should not be deleted by the caller. This function is -@@ -558,6 +575,7 @@ class NATIVE_THEME_EXPORT NativeTheme { - bool forced_colors_ = false; +@@ -584,6 +601,7 @@ class NATIVE_THEME_EXPORT NativeTheme { + PageColors page_colors_ = PageColors::kOff; PreferredColorScheme preferred_color_scheme_ = PreferredColorScheme::kLight; PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference; + ThemeSource theme_source_ = ThemeSource::kSystem; @@ -62,10 +62,10 @@ index e46bc2cf64ca554c0e21a4e0851ad092f504e080..0ffe583d56ddc3abec8c848c1cd5dbc3 SEQUENCE_CHECKER(sequence_checker_); }; diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc -index 6b9fb74004eba57fdff396124214356f4bcf0852..70807b315f805baab2574148520323ce78f624cb 100644 +index b4840142322aa216369985a52567727f4e6806b7..63d77806ed6ed324d37e715319288c843c16f7a0 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc -@@ -618,6 +618,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const { +@@ -621,6 +621,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const { // ...unless --force-dark-mode was specified in which case caveat emptor. if (InForcedColorsMode() && !IsForcedDarkMode()) return false; diff --git a/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch b/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch index 8aec002466d42..bde6d8fe143bc 100644 --- a/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch +++ b/patches/chromium/feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch @@ -12,25 +12,12 @@ This patch adds a list of "streaming protocols" to the MultibufferDataSource in other protocols to register their streaming behavior. MultibufferDataSource::AssumeFullyBuffered() then refers to the list so that it can correctly determine the data source's settings. -diff --git a/third_party/blink/public/platform/media/multi_buffer_data_source.h b/third_party/blink/public/platform/media/multi_buffer_data_source.h -index fd2441add0c816c5031ed0e9321d2be7e0937161..c324d855b26f6dcb63d127d7ddafa509cb1074e4 100644 ---- a/third_party/blink/public/platform/media/multi_buffer_data_source.h -+++ b/third_party/blink/public/platform/media/multi_buffer_data_source.h -@@ -33,6 +33,8 @@ namespace blink { - class BufferedDataSourceHost; - class MultiBufferReader; - -+void BLINK_PLATFORM_EXPORT AddStreamingScheme(const char* new_scheme); -+ - // A data source capable of loading URLs and buffering the data using an - // in-memory sliding window. - // diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc -index ba3e8d75ce49614e26dd77692166a11b614a5d9c..4c3170ecb94716ec2869c363381759cbf08f3ae6 100644 +index c881e7951d10c48faac556661018423dff12b102..0f5408f3ddc65b856e62a05d3fe48a4397827cba 100644 --- a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc +++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc -@@ -10,8 +10,10 @@ - #include "base/callback_helpers.h" +@@ -11,8 +11,10 @@ + #include "base/containers/adapters.h" #include "base/cxx17_backports.h" #include "base/location.h" +#include "base/no_destructor.h" @@ -39,8 +26,8 @@ index ba3e8d75ce49614e26dd77692166a11b614a5d9c..4c3170ecb94716ec2869c363381759cb +#include "base/strings/string_util.h" #include "media/base/media_log.h" #include "net/base/net_errors.h" - #include "third_party/blink/public/platform/media/buffered_data_source_host_impl.h" -@@ -60,8 +62,20 @@ const int kUpdateBufferSizeFrequency = 32; + #include "third_party/blink/renderer/platform/media/buffered_data_source_host_impl.h" +@@ -61,8 +63,20 @@ const int kUpdateBufferSizeFrequency = 32; // How long to we delay a seek after a read? constexpr base::TimeDelta kSeekDelay = base::Milliseconds(20); @@ -61,7 +48,7 @@ index ba3e8d75ce49614e26dd77692166a11b614a5d9c..4c3170ecb94716ec2869c363381759cb class MultiBufferDataSource::ReadOperation { public: ReadOperation() = delete; -@@ -153,7 +167,14 @@ bool MultiBufferDataSource::media_has_played() const { +@@ -154,7 +168,14 @@ bool MultiBufferDataSource::media_has_played() const { bool MultiBufferDataSource::AssumeFullyBuffered() const { DCHECK(url_data_); @@ -69,7 +56,7 @@ index ba3e8d75ce49614e26dd77692166a11b614a5d9c..4c3170ecb94716ec2869c363381759cb + + const std::string scheme = url_data_->url().scheme(); + for (const std::string& streaming_scheme : *GetStreamingSchemes()) { -+ if (base::LowerCaseEqualsASCII(scheme, streaming_scheme)) { ++ if (base::EqualsCaseInsensitiveASCII(scheme, streaming_scheme)) { + return false; + } + } @@ -77,3 +64,16 @@ index ba3e8d75ce49614e26dd77692166a11b614a5d9c..4c3170ecb94716ec2869c363381759cb } void MultiBufferDataSource::SetReader(MultiBufferReader* reader) { +diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source.h b/third_party/blink/renderer/platform/media/multi_buffer_data_source.h +index cb5d1951af2ff71cc6c7905235d85d6cbc541ae7..292bcf55be733a5cc1e32e11bd00e9acebdbfcbf 100644 +--- a/third_party/blink/renderer/platform/media/multi_buffer_data_source.h ++++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source.h +@@ -33,6 +33,8 @@ namespace blink { + class BufferedDataSourceHost; + class MultiBufferReader; + ++void BLINK_PLATFORM_EXPORT AddStreamingScheme(const char* new_scheme); ++ + // A data source capable of loading URLs and buffering the data using an + // in-memory sliding window. + // diff --git a/patches/chromium/feat_add_support_for_overriding_the_base_spellchecker_download_url.patch b/patches/chromium/feat_add_support_for_overriding_the_base_spellchecker_download_url.patch index 9fc5bef9c5021..563ac340dc186 100644 --- a/patches/chromium/feat_add_support_for_overriding_the_base_spellchecker_download_url.patch +++ b/patches/chromium/feat_add_support_for_overriding_the_base_spellchecker_download_url.patch @@ -9,7 +9,7 @@ production use cases. This is unlikely to be upstreamed as the change is entirely in //chrome. diff --git a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc -index 22fade6370fe654e48373f35bbac079131b873ff..57d694eab66c1431789405656f600390e023b533 100644 +index ff5ee1d7a0f4e333498bf25acbbf49d1ce53b7a1..e98084036c04e9910779670497b1a431d4fee48a 100644 --- a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc +++ b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc @@ -51,6 +51,9 @@ namespace { diff --git a/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch b/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch index d3448ffcc3b40..f1d733bd953da 100644 --- a/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch +++ b/patches/chromium/feat_allow_embedders_to_add_observers_on_created_hunspell.patch @@ -7,10 +7,10 @@ Subject: feat: allow embedders to add observers on created hunspell This patch is used by Electron to implement spellchecker events. diff --git a/chrome/browser/spellchecker/spellcheck_service.cc b/chrome/browser/spellchecker/spellcheck_service.cc -index 80e5807fecbca3d3d3105522418c5f4b4d103f57..002204dbe0b9598b61141cab33b7befdfac077f8 100644 +index bbc3ea681bfe0db0e122635db5442c447a30d387..26bc4ccfcc7583fd76cd290132b0729c1f01bae3 100644 --- a/chrome/browser/spellchecker/spellcheck_service.cc +++ b/chrome/browser/spellchecker/spellcheck_service.cc -@@ -469,6 +469,9 @@ void SpellcheckService::LoadDictionaries() { +@@ -467,6 +467,9 @@ void SpellcheckService::LoadDictionaries() { std::make_unique( dictionary, platform_spellcheck_language, context_, this)); hunspell_dictionaries_.back()->AddObserver(this); @@ -20,7 +20,7 @@ index 80e5807fecbca3d3d3105522418c5f4b4d103f57..002204dbe0b9598b61141cab33b7befd hunspell_dictionaries_.back()->Load(); } -@@ -521,6 +524,20 @@ bool SpellcheckService::IsSpellcheckEnabled() const { +@@ -519,6 +522,20 @@ bool SpellcheckService::IsSpellcheckEnabled() const { (!hunspell_dictionaries_.empty() || enable_if_uninitialized); } diff --git a/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch b/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch index 54fb0814ebddd..bf7eab53b1692 100644 --- a/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch +++ b/patches/chromium/feat_enable_offscreen_rendering_with_viz_compositor.patch @@ -81,23 +81,23 @@ index 309422bcf85810db88a048bd0930c4072b41f234..759549f3046f4a897b597409b670bb1c private: const HWND hwnd_; diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn -index 03a9986ff94bc57e82a95e7a2a3fcc1415f28da0..79283e753512855360127471d40e145c325649ca 100644 +index e3056ad83f954787f50c2507cb63659605c3dd3b..358eceadb8a3c2a6782f5fcd4b57630f87689c8b 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn -@@ -139,6 +139,8 @@ viz_component("service") { - "display_embedder/output_surface_provider_impl.h", - "display_embedder/server_shared_bitmap_manager.cc", - "display_embedder/server_shared_bitmap_manager.h", +@@ -136,6 +136,8 @@ viz_component("service") { + "display_embedder/skia_output_surface_impl_on_gpu.h", + "display_embedder/skia_render_copy_results.cc", + "display_embedder/skia_render_copy_results.h", + "display_embedder/software_output_device_proxy.cc", + "display_embedder/software_output_device_proxy.h", "display_embedder/software_output_surface.cc", "display_embedder/software_output_surface.h", - "display_embedder/viz_process_context_provider.cc", + "display_embedder/vsync_parameter_listener.cc", diff --git a/components/viz/service/display_embedder/output_surface_provider.h b/components/viz/service/display_embedder/output_surface_provider.h -index 77d463e683d8b8d3a202681a6884eacaab79d70d..05d51cb2637d34c073cd0025e365803633459a86 100644 +index 18ea9142343e68dfa64c5e81269dbc80e55c1277..c76c4bcd3b30230753be51d87eabffa93a107b6e 100644 --- a/components/viz/service/display_embedder/output_surface_provider.h +++ b/components/viz/service/display_embedder/output_surface_provider.h -@@ -39,7 +39,8 @@ class OutputSurfaceProvider { +@@ -38,7 +38,8 @@ class OutputSurfaceProvider { mojom::DisplayClient* display_client, DisplayCompositorMemoryAndTaskController* gpu_dependency, const RendererSettings& renderer_settings, @@ -108,26 +108,25 @@ index 77d463e683d8b8d3a202681a6884eacaab79d70d..05d51cb2637d34c073cd0025e3658036 } // namespace viz diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc -index 8a277c6337d446890bb32814a68db2a9d3d3cd72..4c4e631d5a1476eaad6f54281e6d6899070d1a65 100644 +index d6ffe3a759fbde3fbb0f86fda9a07c63d50ff73a..4854bca8e1d3117534e4bf02ea8ebf5b2e6ea70c 100644 --- a/components/viz/service/display_embedder/output_surface_provider_impl.cc +++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc -@@ -26,6 +26,7 @@ +@@ -23,12 +23,14 @@ #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h" #include "components/viz/service/display_embedder/skia_output_surface_impl.h" +#include "components/viz/service/display_embedder/software_output_device_proxy.h" #include "components/viz/service/display_embedder/software_output_surface.h" - #include "components/viz/service/display_embedder/viz_process_context_provider.h" #include "components/viz/service/gl/gpu_service_impl.h" -@@ -39,6 +40,7 @@ - #include "gpu/ipc/scheduler_sequence.h" - #include "gpu/ipc/service/gpu_channel_manager_delegate.h" - #include "gpu/ipc/service/image_transport_surface.h" + #include "gpu/command_buffer/client/shared_memory_limits.h" + #include "gpu/command_buffer/service/scheduler_sequence.h" + #include "gpu/config/gpu_finch_features.h" + #include "gpu/ipc/common/surface_handle.h" +#include "services/viz/privileged/mojom/compositing/layered_window_updater.mojom.h" #include "ui/base/ui_base_switches.h" - #include "ui/gl/gl_context.h" - #include "ui/gl/init/gl_factory.h" -@@ -126,7 +128,8 @@ std::unique_ptr OutputSurfaceProviderImpl::CreateOutputSurface( + + #if BUILDFLAG(IS_WIN) +@@ -89,7 +91,8 @@ std::unique_ptr OutputSurfaceProviderImpl::CreateOutputSurface( mojom::DisplayClient* display_client, DisplayCompositorMemoryAndTaskController* gpu_dependency, const RendererSettings& renderer_settings, @@ -137,16 +136,16 @@ index 8a277c6337d446890bb32814a68db2a9d3d3cd72..4c4e631d5a1476eaad6f54281e6d6899 #if BUILDFLAG(IS_CHROMEOS_ASH) if (surface_handle == gpu::kNullSurfaceHandle) return std::make_unique(); -@@ -138,7 +141,7 @@ std::unique_ptr OutputSurfaceProviderImpl::CreateOutputSurface( +@@ -97,7 +100,7 @@ std::unique_ptr OutputSurfaceProviderImpl::CreateOutputSurface( if (!gpu_compositing) { - output_surface = std::make_unique( + return std::make_unique( - CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client)); + CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client, offscreen)); - } else if (renderer_settings.use_skia_renderer) { + } else { DCHECK(gpu_dependency); - { -@@ -243,10 +246,22 @@ std::unique_ptr OutputSurfaceProviderImpl::CreateOutputSurface( + +@@ -137,10 +140,22 @@ std::unique_ptr OutputSurfaceProviderImpl::CreateOutputSurface( std::unique_ptr OutputSurfaceProviderImpl::CreateSoftwareOutputDeviceForPlatform( gpu::SurfaceHandle surface_handle, @@ -159,9 +158,9 @@ index 8a277c6337d446890bb32814a68db2a9d3d3cd72..4c4e631d5a1476eaad6f54281e6d6899 +#if !BUILDFLAG(IS_APPLE) + if (offscreen) { + DCHECK(display_client); -+ mojom::LayeredWindowUpdaterPtr layered_window_updater; ++ mojo::PendingRemote layered_window_updater; + display_client->CreateLayeredWindowUpdater( -+ mojo::MakeRequest(&layered_window_updater)); ++ layered_window_updater.InitWithNewPipeAndPassReceiver()); + return std::make_unique( + std::move(layered_window_updater)); + } @@ -171,10 +170,10 @@ index 8a277c6337d446890bb32814a68db2a9d3d3cd72..4c4e631d5a1476eaad6f54281e6d6899 return CreateSoftwareOutputDeviceWin(surface_handle, &output_device_backing_, display_client); diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.h b/components/viz/service/display_embedder/output_surface_provider_impl.h -index fa9bc45b5c12821789270907f73c7e6f3c0c1424..6d2ad1d88631db82f41de2852c3e9a6ad1431b2e 100644 +index be10797e6f517ae069b8bc579155440d8a110362..fb6848b70a80c9c6cda42605a8b86ffbeb2a5ec8 100644 --- a/components/viz/service/display_embedder/output_surface_provider_impl.h +++ b/components/viz/service/display_embedder/output_surface_provider_impl.h -@@ -66,12 +66,14 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl +@@ -49,12 +49,14 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl mojom::DisplayClient* display_client, DisplayCompositorMemoryAndTaskController* gpu_dependency, const RendererSettings& renderer_settings, @@ -190,7 +189,7 @@ index fa9bc45b5c12821789270907f73c7e6f3c0c1424..6d2ad1d88631db82f41de2852c3e9a6a + bool offscreen); const raw_ptr gpu_service_impl_; - const raw_ptr task_executor_; + diff --git a/components/viz/service/display_embedder/software_output_device_mac.cc b/components/viz/service/display_embedder/software_output_device_mac.cc index 33e12349a951ef533b964d1158f8fa124623e946..fc04bcaffefc277dd1d0cdd766168de017fedca8 100644 --- a/components/viz/service/display_embedder/software_output_device_mac.cc @@ -213,10 +212,10 @@ index 33e12349a951ef533b964d1158f8fa124623e946..fc04bcaffefc277dd1d0cdd766168de0 IOSurfaceCreateMachPort(current_paint_buffer_->io_surface)); client_->SoftwareDeviceUpdatedCALayerParams(ca_layer_params); diff --git a/components/viz/service/display_embedder/software_output_device_mac.h b/components/viz/service/display_embedder/software_output_device_mac.h -index a480befb5d8db36e7e281d5033aeef0bea83d220..4e54acc897d08c87bccc3b44f68634e2873cb132 100644 +index 16a4e74e11775b694dfeeb82b475c628b86174b1..f8099e165da6c8253016abc92ea3021056e37c85 100644 --- a/components/viz/service/display_embedder/software_output_device_mac.h +++ b/components/viz/service/display_embedder/software_output_device_mac.h -@@ -59,6 +59,7 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice { +@@ -60,6 +60,7 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice { void UpdateAndCopyBufferDamage(Buffer* previous_paint_buffer, const SkRegion& new_damage_rect); @@ -226,7 +225,7 @@ index a480befb5d8db36e7e281d5033aeef0bea83d220..4e54acc897d08c87bccc3b44f68634e2 diff --git a/components/viz/service/display_embedder/software_output_device_proxy.cc b/components/viz/service/display_embedder/software_output_device_proxy.cc new file mode 100644 -index 0000000000000000000000000000000000000000..88aba74877a6490e08e357266b1ce8461b5b6dff +index 0000000000000000000000000000000000000000..d5e90022d129ce6a7a8effd6c85d3a5295ac79bf --- /dev/null +++ b/components/viz/service/display_embedder/software_output_device_proxy.cc @@ -0,0 +1,158 @@ @@ -302,7 +301,7 @@ index 0000000000000000000000000000000000000000..88aba74877a6490e08e357266b1ce846 +SoftwareOutputDeviceProxy::~SoftwareOutputDeviceProxy() = default; + +SoftwareOutputDeviceProxy::SoftwareOutputDeviceProxy( -+ mojom::LayeredWindowUpdaterPtr layered_window_updater) ++ mojo::PendingRemote layered_window_updater) + : layered_window_updater_(std::move(layered_window_updater)) { + DCHECK(layered_window_updater_.is_bound()); +} @@ -390,10 +389,10 @@ index 0000000000000000000000000000000000000000..88aba74877a6490e08e357266b1ce846 +} // namespace viz diff --git a/components/viz/service/display_embedder/software_output_device_proxy.h b/components/viz/service/display_embedder/software_output_device_proxy.h new file mode 100644 -index 0000000000000000000000000000000000000000..a80258d6165e45a3c3d2b551158ff7d2a5778a7c +index 0000000000000000000000000000000000000000..daeabe1906b177adfe56b8057a72afb33269f976 --- /dev/null +++ b/components/viz/service/display_embedder/software_output_device_proxy.h -@@ -0,0 +1,93 @@ +@@ -0,0 +1,95 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. @@ -409,6 +408,8 @@ index 0000000000000000000000000000000000000000..a80258d6165e45a3c3d2b551158ff7d2 +#include "components/viz/host/host_display_client.h" +#include "components/viz/service/display/software_output_device.h" +#include "components/viz/service/viz_service_export.h" ++#include "mojo/public/cpp/bindings/pending_remote.h" ++#include "mojo/public/cpp/bindings/remote.h" +#include "services/viz/privileged/mojom/compositing/display_private.mojom.h" +#include "services/viz/privileged/mojom/compositing/layered_window_updater.mojom.h" + @@ -455,7 +456,7 @@ index 0000000000000000000000000000000000000000..a80258d6165e45a3c3d2b551158ff7d2 +class SoftwareOutputDeviceProxy : public SoftwareOutputDeviceBase { + public: + explicit SoftwareOutputDeviceProxy( -+ mojom::LayeredWindowUpdaterPtr layered_window_updater); ++ mojo::PendingRemote layered_window_updater); + ~SoftwareOutputDeviceProxy() override; + + SoftwareOutputDeviceProxy(const SoftwareOutputDeviceProxy&) = delete; @@ -473,7 +474,7 @@ index 0000000000000000000000000000000000000000..a80258d6165e45a3c3d2b551158ff7d2 + // Runs |swap_ack_callback_| after draw has happened. + void DrawAck(); + -+ mojom::LayeredWindowUpdaterPtr layered_window_updater_; ++ mojo::Remote layered_window_updater_; + + std::unique_ptr canvas_; + bool waiting_on_draw_ack_ = false; @@ -501,11 +502,11 @@ index 583e3e2525c753a0962d481fc67a3582df75d0e9..9416ec929bebcff7f07088e635376ef2 waiting_on_draw_ack_ = true; diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc -index 7607a49cdc1a6028e272ce76b78806ec13415f42..e2f4350edeae766916716345327d0bbefb561e4c 100644 +index 4e150f1fc12884d92b11605b6f39ec4a1d720b99..569b4e2277c758f628e528b80917f0f1e65f76d8 100644 --- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc @@ -84,7 +84,8 @@ RootCompositorFrameSinkImpl::Create( - params->gpu_compositing, params->widget, params->renderer_settings); + params->gpu_compositing, params->widget); auto output_surface = output_surface_provider->CreateOutputSurface( params->widget, params->gpu_compositing, display_client.get(), - display_controller.get(), params->renderer_settings, debug_settings); @@ -515,7 +516,7 @@ index 7607a49cdc1a6028e272ce76b78806ec13415f42..e2f4350edeae766916716345327d0bbe // Creating output surface failed. The host can send a new request, possibly // with a different compositing mode. diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc -index 0e3af0f9280abe8560393325b400ad2543ed0556..7fe490e55a4bb8a183d0d241188ea15a44347245 100644 +index 4a9cf8ff4a94ecda70e3d0f8d1b9d18687e4aa87..27a7adcf524e33819b372213285bfccb1f3924ba 100644 --- a/content/browser/compositor/viz_process_transport_factory.cc +++ b/content/browser/compositor/viz_process_transport_factory.cc @@ -381,8 +381,14 @@ void VizProcessTransportFactory::OnEstablishedGpuChannel( @@ -548,13 +549,13 @@ index b2f873919d68633103d115d7d9550a098c1a254c..8e38831a6df15d37e5fb87d63613b7db // Notifies that a swap has occurred and provides information about the pixel diff --git a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom -index a9a0e5a1167b2018e6dc206ecb7d37aad94042aa..3997ecb0228914144d6b04595c47376679fca3ef 100644 +index 2534c06b9de7de9b6353c81016ae0fa8609effd3..e5edff80fcdd969c0854641a6e67af12b80138dc 100644 --- a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom +++ b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom -@@ -32,6 +32,7 @@ struct RootCompositorFrameSinkParams { +@@ -31,6 +31,7 @@ struct RootCompositorFrameSinkParams { + bool send_swap_size_notifications = false; // Disables begin frame rate limiting for the display compositor. bool disable_frame_rate_limit = false; - bool use_preferred_interval_for_video = false; + bool offscreen = false; [EnableIf=is_android] @@ -571,10 +572,10 @@ index 6b7fbb6cf13dc8ee6ade0878a9a2c1efc5d4d3f1..e2af75168cb914a7b3b4a6c9b6a28549 + Draw(gfx.mojom.Rect damage_rect) => (); }; diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h -index 8b74e1d2a463156f62e983f535ff68a53215f648..6ef04da46c8b097b01d5ee40dcadf222d7a7870c 100644 +index 5dee5932ce9cacc68af498ef2312fd58cd285e15..d8f977154e5f0c0456ee03ddf67f94b0e7ab475d 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h -@@ -81,6 +81,7 @@ class DisplayPrivate; +@@ -83,6 +83,7 @@ class DisplayPrivate; class ExternalBeginFrameController; } // namespace mojom class ContextProvider; @@ -582,7 +583,7 @@ index 8b74e1d2a463156f62e983f535ff68a53215f648..6ef04da46c8b097b01d5ee40dcadf222 class HostFrameSinkManager; class LocalSurfaceId; class RasterContextProvider; -@@ -137,6 +138,16 @@ class COMPOSITOR_EXPORT ContextFactory { +@@ -139,6 +140,16 @@ class COMPOSITOR_EXPORT ContextFactory { virtual viz::HostFrameSinkManager* GetHostFrameSinkManager() = 0; }; @@ -599,7 +600,7 @@ index 8b74e1d2a463156f62e983f535ff68a53215f648..6ef04da46c8b097b01d5ee40dcadf222 // Compositor object to take care of GPU painting. // A Browser compositor object is responsible for generating the final // displayable form of pixels comprising a single widget's contents. It draws an -@@ -177,6 +188,9 @@ class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver, +@@ -180,6 +191,9 @@ class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver, // Schedules a redraw of the layer tree associated with this compositor. void ScheduleDraw(); @@ -609,7 +610,7 @@ index 8b74e1d2a463156f62e983f535ff68a53215f648..6ef04da46c8b097b01d5ee40dcadf222 // Sets the root of the layer tree drawn by this Compositor. The root layer // must have no parent. The compositor's root layer is reset if the root layer // is destroyed. NULL can be passed to reset the root layer, in which case the -@@ -467,6 +481,8 @@ class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver, +@@ -482,6 +496,8 @@ class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver, std::unique_ptr pending_begin_frame_args_; @@ -619,7 +620,7 @@ index 8b74e1d2a463156f62e983f535ff68a53215f648..6ef04da46c8b097b01d5ee40dcadf222 raw_ptr root_layer_ = nullptr; diff --git a/ui/gfx/ca_layer_params.h b/ui/gfx/ca_layer_params.h -index c5fb29b30b9c5b7483998c567ed9a479d8743939..dc10d78315f76a3914ccd6e2e99af97fa909918b 100644 +index 12e115cd6a128d8d150abc786d4d38b1d5119d91..b6320de28750333bee7ee83393849f4eb0a956ac 100644 --- a/ui/gfx/ca_layer_params.h +++ b/ui/gfx/ca_layer_params.h @@ -6,6 +6,7 @@ @@ -630,7 +631,7 @@ index c5fb29b30b9c5b7483998c567ed9a479d8743939..dc10d78315f76a3914ccd6e2e99af97f #include "ui/gfx/geometry/size.h" #include "ui/gfx/gfx_export.h" -@@ -41,6 +42,8 @@ struct GFX_EXPORT CALayerParams { +@@ -51,6 +52,8 @@ struct GFX_EXPORT CALayerParams { gfx::ScopedRefCountedIOSurfaceMachPort io_surface_mach_port; #endif @@ -651,7 +652,7 @@ index de00e766ba17532e10dcf5d0fd31fa344920a9f7..7aaedf83ad22dcc1d2dd39a31cf7e08b float scale_factor; }; diff --git a/ui/gfx/mojom/ca_layer_params_mojom_traits.cc b/ui/gfx/mojom/ca_layer_params_mojom_traits.cc -index c7035798bd867f51b39f36f1be79293bf2b5cc12..131446361de812f9b915483bca2b6d2165b65e3d 100644 +index a80185658d82c67713e578d176955c442f0568ab..e29003b3b6def9a1f842139f4269893a2609a601 100644 --- a/ui/gfx/mojom/ca_layer_params_mojom_traits.cc +++ b/ui/gfx/mojom/ca_layer_params_mojom_traits.cc @@ -52,6 +52,9 @@ bool StructTraits::Read( diff --git a/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch b/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch index df31e9a3f8f82..3b31f510cf4c4 100644 --- a/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch +++ b/patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch @@ -17,43 +17,43 @@ headers, moving forward we should find a way in upstream to provide access to these headers for loader clients created on the browser process. diff --git a/services/network/public/cpp/resource_request.cc b/services/network/public/cpp/resource_request.cc -index 87868727a78223baef9ffd2591f49fced240ef4e..f6a6ff28f33e2d1c065f2abeb96733b2d28a6ea1 100644 +index 7e02d8c952d2228a39d1fd1fa5a36859e2ea9ab9..1cfa83a0d0d0fa3fec3f92faa94aece678f83552 100644 --- a/services/network/public/cpp/resource_request.cc +++ b/services/network/public/cpp/resource_request.cc -@@ -233,6 +233,7 @@ bool ResourceRequest::EqualsForTesting(const ResourceRequest& request) const { +@@ -234,6 +234,7 @@ bool ResourceRequest::EqualsForTesting(const ResourceRequest& request) const { do_not_prompt_for_login == request.do_not_prompt_for_login && - is_main_frame == request.is_main_frame && + is_outermost_main_frame == request.is_outermost_main_frame && transition_type == request.transition_type && + report_raw_headers == request.report_raw_headers && previews_state == request.previews_state && upgrade_if_insecure == request.upgrade_if_insecure && is_revalidating == request.is_revalidating && diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h -index 8b9a7b36f53a4cfcd159ac18c06d1724072013c8..ef0191bae8a07e531ae129cf32b22f4930c5e266 100644 +index 10d7912016a57e413e7f6056697028bbc5a4e0e6..f22a212ca8dc3f95373e23d22689c896720b7ee0 100644 --- a/services/network/public/cpp/resource_request.h +++ b/services/network/public/cpp/resource_request.h -@@ -156,6 +156,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest { +@@ -159,6 +159,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest { bool do_not_prompt_for_login = false; - bool is_main_frame = false; + bool is_outermost_main_frame = false; int transition_type = 0; + bool report_raw_headers = false; int previews_state = 0; bool upgrade_if_insecure = false; bool is_revalidating = false; diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc -index 1fcf54cac11c38352e14774cd08bcaa162443e9c..5356da11391d52a8f9aaa57a27616cee6dc0f2b6 100644 +index 10295a165e2131b7cd5bff996f36f2214db7a125..2d1bb21bf5813125397a93d368de031b11bb4bbb 100644 --- a/services/network/public/cpp/url_request_mojom_traits.cc +++ b/services/network/public/cpp/url_request_mojom_traits.cc @@ -209,6 +209,7 @@ bool StructTraits< out->do_not_prompt_for_login = data.do_not_prompt_for_login(); - out->is_main_frame = data.is_main_frame(); + out->is_outermost_main_frame = data.is_outermost_main_frame(); out->transition_type = data.transition_type(); + out->report_raw_headers = data.report_raw_headers(); out->previews_state = data.previews_state(); out->upgrade_if_insecure = data.upgrade_if_insecure(); out->is_revalidating = data.is_revalidating(); diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h -index 1b8dbc0538d0af843e40edc41505d08f9034f97b..270822eb756090f8a74f34823009942ed21e8616 100644 +index b4f785570ffab62087ef9be3d18cecb6c747fa38..f6ff5ebc9808e230ed358203c5d0024c676bcd85 100644 --- a/services/network/public/cpp/url_request_mojom_traits.h +++ b/services/network/public/cpp/url_request_mojom_traits.h @@ -269,6 +269,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) @@ -67,7 +67,7 @@ index 1b8dbc0538d0af843e40edc41505d08f9034f97b..270822eb756090f8a74f34823009942e return request.previews_state; } diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom -index 79b5d03ded03ced9e6ff4d17d10935004bfb0062..923883fd010f9621c790dd5381a7e1f0cb36e740 100644 +index 05cc03e830d2805d6d572a38e2606de0f346b6bd..75b8da2f1141dffa34d01e84e339b791fdd60664 100644 --- a/services/network/public/mojom/url_request.mojom +++ b/services/network/public/mojom/url_request.mojom @@ -312,6 +312,9 @@ struct URLRequest { @@ -81,7 +81,7 @@ index 79b5d03ded03ced9e6ff4d17d10935004bfb0062..923883fd010f9621c790dd5381a7e1f0 // browser decide. // Note: this is an enum of type PreviewsState. diff --git a/services/network/public/mojom/url_response_head.mojom b/services/network/public/mojom/url_response_head.mojom -index 4c4cc16db82d7434573f7740855fbe72d68815e6..f71290800b6bb51a39b1f86be36f02d602ac3397 100644 +index 3d2bcc3e81eb42f645fa4e8b1425cb5c54cfd3a1..4cdbe0e38609abfd0b0b5856deb8b2dd5c91ead8 100644 --- a/services/network/public/mojom/url_response_head.mojom +++ b/services/network/public/mojom/url_response_head.mojom @@ -8,6 +8,7 @@ import "mojo/public/mojom/base/time.mojom"; @@ -92,7 +92,7 @@ index 4c4cc16db82d7434573f7740855fbe72d68815e6..f71290800b6bb51a39b1f86be36f02d6 import "services/network/public/mojom/ip_endpoint.mojom"; import "services/network/public/mojom/load_timing_info.mojom"; import "services/network/public/mojom/network_param.mojom"; -@@ -29,6 +30,9 @@ struct URLResponseHead { +@@ -28,6 +29,9 @@ struct URLResponseHead { // The response headers or NULL if the URL type does not support headers. HttpResponseHeaders headers; @@ -103,10 +103,10 @@ index 4c4cc16db82d7434573f7740855fbe72d68815e6..f71290800b6bb51a39b1f86be36f02d6 string mime_type; diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc -index 73b90e9b575b94f009ae3b87bd0ad76d69803bc3..e08bb784a11209f1531e8d981bd238d67db31e22 100644 +index 2e8a874bf93e03e7c194dc13555eead6fe1fcafa..5b28db971f8feebd36965ccafe8b1b957b3f1ede 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc -@@ -462,6 +462,7 @@ URLLoader::URLLoader( +@@ -606,6 +606,7 @@ URLLoader::URLLoader( mojo::SimpleWatcher::ArmingPolicy::MANUAL, base::SequencedTaskRunnerHandle::Get()), per_factory_corb_state_(context.GetMutableCorbState()), @@ -114,7 +114,7 @@ index 73b90e9b575b94f009ae3b87bd0ad76d69803bc3..e08bb784a11209f1531e8d981bd238d6 devtools_request_id_(request.devtools_request_id), request_mode_(request.mode), request_credentials_mode_(request.credentials_mode), -@@ -629,7 +630,7 @@ URLLoader::URLLoader( +@@ -795,7 +796,7 @@ URLLoader::URLLoader( url_request_->SetRequestHeadersCallback(base::BindRepeating( &URLLoader::SetRawRequestHeadersAndNotify, base::Unretained(this))); @@ -123,7 +123,7 @@ index 73b90e9b575b94f009ae3b87bd0ad76d69803bc3..e08bb784a11209f1531e8d981bd238d6 url_request_->SetResponseHeadersCallback(base::BindRepeating( &URLLoader::SetRawResponseHeaders, base::Unretained(this))); } -@@ -1388,6 +1389,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) { +@@ -1555,6 +1556,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) { } response_ = BuildResponseHead(); @@ -144,10 +144,10 @@ index 73b90e9b575b94f009ae3b87bd0ad76d69803bc3..e08bb784a11209f1531e8d981bd238d6 // Parse and remove the Trust Tokens response headers, if any are expected, diff --git a/services/network/url_loader.h b/services/network/url_loader.h -index 98fe2512671e43a4e0da6e9b9ff714d7204fc3a8..bf8751c1b37a678f73ec8e11c86e1eb1287443e4 100644 +index 7a1d7fe570c3b3d94d1dbcfdda2b965323ce5e95..9bc4eb1a1f300529308a2f120b4bc676b11acfbe 100644 --- a/services/network/url_loader.h +++ b/services/network/url_loader.h -@@ -506,6 +506,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader +@@ -518,6 +518,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader std::unique_ptr resource_scheduler_request_handle_; diff --git a/patches/chromium/feat_filter_out_non-shareable_windows_in_the_current_application_in.patch b/patches/chromium/feat_filter_out_non-shareable_windows_in_the_current_application_in.patch new file mode 100644 index 0000000000000..c72abdbc38363 --- /dev/null +++ b/patches/chromium/feat_filter_out_non-shareable_windows_in_the_current_application_in.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Thu, 26 May 2022 15:38:32 -0700 +Subject: feat: filter out non-shareable windows in the current application in + ScreenCaptureKitDevice + +This patch ensures that windows protected via win.setContentProtection(true) do not appear in full display captures via desktopCapturer. This patch could be upstreamed but as the check is limited to in-process windows it doesn't make a lot of sense for Chromium itself. This patch currently has a limitation that it only function for windows created / protected BEFORE the stream is started. There is theoretical future work we can do via polling / observers to automatically update the SCContentFilter when new windows are made but for now this will solve 99+% of the problem and folks can re-order their logic a bit to get it working for their use cases. + +diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm +index 50a779be2e7d3a95496e2791187a6b56266786eb..5876babb99b5e98b151e13e4091305763a417a9e 100644 +--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm ++++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm +@@ -100,7 +100,15 @@ void OnShareableContentCreated( + case DesktopMediaID::TYPE_SCREEN: + for (SCDisplay* display : [content displays]) { + if (source_.id == [display displayID]) { +- NSArray* exclude_windows = nil; ++ NSArray* exclude_ns_windows = [[[NSApplication sharedApplication] windows] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSWindow* win, NSDictionary *bindings) { ++ return [win sharingType] == NSWindowSharingNone; ++ }]]; ++ NSArray* exclude_windows = [[content windows] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(SCWindow* win, NSDictionary *bindings) { ++ for (NSWindow* excluded : exclude_ns_windows) { ++ if ((CGWindowID)[excluded windowNumber] == [win windowID]) return true; ++ } ++ return false; ++ }]]; + filter.reset([[SCContentFilter alloc] + initWithDisplay:display + excludingWindows:exclude_windows]); diff --git a/patches/chromium/fix_adapt_exclusive_access_for_electron_needs.patch b/patches/chromium/fix_adapt_exclusive_access_for_electron_needs.patch new file mode 100644 index 0000000000000..6daf2cabfd185 --- /dev/null +++ b/patches/chromium/fix_adapt_exclusive_access_for_electron_needs.patch @@ -0,0 +1,143 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr +Date: Mon, 25 Oct 2021 21:45:57 +0200 +Subject: fix: adapt exclusive_access for electron needs + +This patch is necessary in order to properly enable +navigator.keyboard.{(un)?lock}() functionality. We don't have a concept +of PermissionManager nor of a Profile, so this would not affect usage of +the API. + +We also need to ensure that NotifyExclusiveTabAccessLost is called +on all platforms in FullscreenController::ExitFullscreenModeInternal() +and not just macOS, since Electron's native window impls report state +change fairly instantly as well, and so pressing escape won't work on +Linux or Windows to un-fullscreen in some circumstances without this +change. + +diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc +index 8106b5ceec5b6b3ca01d14308a351e63eac809c1..5758757980879a9c1810c4de44f228860688d442 100644 +--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc ++++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc +@@ -17,12 +17,16 @@ + #include "build/build_config.h" + #include "chrome/browser/app_mode/app_mode_utils.h" + #include "chrome/browser/profiles/profile.h" ++#if 0 + #include "chrome/browser/ui/blocked_content/popunder_preventer.h" ++#endif + #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" + #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" + #include "chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h" ++#if 0 + #include "chrome/browser/ui/status_bubble.h" + #include "chrome/browser/ui/tabs/tab_strip_model.h" ++#endif + #include "chrome/common/chrome_switches.h" + #include "content/public/browser/navigation_details.h" + #include "content/public/browser/navigation_entry.h" +@@ -181,6 +185,7 @@ void FullscreenController::EnterFullscreenModeForTab( + return; + } + ++#if 0 + if (base::FeatureList::IsEnabled( + blink::features::kWindowPlacementFullscreenCompanionWindow)) { + if (!popunder_preventer_) +@@ -188,6 +193,7 @@ void FullscreenController::EnterFullscreenModeForTab( + else + popunder_preventer_->WillActivateWebContents(web_contents); + } ++#endif + + // Keep the current state. |SetTabWithExclusiveAccess| may change the return + // value of |IsWindowFullscreenForTabOrPending|. +@@ -237,7 +243,9 @@ void FullscreenController::EnterFullscreenModeForTab( + } + + void FullscreenController::ExitFullscreenModeForTab(WebContents* web_contents) { ++#if 0 + popunder_preventer_.reset(); ++#endif + + if (MaybeToggleFullscreenWithinTab(web_contents, false)) { + // During tab capture of fullscreen-within-tab views, the browser window +@@ -292,11 +300,13 @@ void FullscreenController::ExitFullscreenModeForTab(WebContents* web_contents) { + void FullscreenController::FullscreenTabOpeningPopup( + content::WebContents* opener, + content::WebContents* popup) { ++#if 0 + DCHECK(base::FeatureList::IsEnabled( + blink::features::kWindowPlacementFullscreenCompanionWindow)); + DCHECK_EQ(exclusive_access_tab(), opener); + DCHECK(popunder_preventer_); + popunder_preventer_->AddPotentialPopunder(popup); ++#endif + } + + void FullscreenController::OnTabDeactivated( +@@ -465,18 +475,17 @@ void FullscreenController::EnterFullscreenModeInternal( + // Do not enter fullscreen mode if disallowed by pref. This prevents the user + // from manually entering fullscreen mode and also disables kiosk mode on + // desktop platforms. +- if (!exclusive_access_manager() +- ->context() +- ->GetProfile() +- ->GetPrefs() +- ->GetBoolean(prefs::kFullscreenAllowed)) { ++ auto* profile = exclusive_access_manager()->context()->GetProfile(); ++ if (!profile || !profile->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed)) + return; +- } + #endif + started_fullscreen_transition_ = true; + toggled_into_fullscreen_ = true; ++#if 0 + bool entering_tab_fullscreen = option == TAB && !tab_fullscreen_; ++#endif + GURL url; ++#if 0 + if (option == TAB) { + url = GetRequestingOrigin(); + tab_fullscreen_ = true; +@@ -509,6 +518,7 @@ void FullscreenController::EnterFullscreenModeInternal( + if (!extension_caused_fullscreen_.is_empty()) + url = extension_caused_fullscreen_; + } ++#endif + + if (option == BROWSER) + base::RecordAction(base::UserMetricsAction("ToggleFullscreen")); +@@ -536,12 +546,12 @@ void FullscreenController::ExitFullscreenModeInternal() { + RecordExitingUMA(); + toggled_into_fullscreen_ = false; + started_fullscreen_transition_ = true; +-#if BUILDFLAG(IS_MAC) +- // Mac windows report a state change instantly, and so we must also clear ++ ++ // Electron native windows report a state change instantly, and so we must also clear + // state_prior_to_tab_fullscreen_ to match them else other logic using + // state_prior_to_tab_fullscreen_ will be incorrect. + NotifyTabExclusiveAccessLost(); +-#endif ++ + exclusive_access_manager()->context()->ExitFullscreen(); + extension_caused_fullscreen_ = GURL(); + +diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h +index a31c0b1a17d4cda765a4511923686b7f44d10e81..0b0a015f0500432273bf0e7f7231987cdd11b440 100644 +--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h ++++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h +@@ -247,10 +247,12 @@ class FullscreenController : public ExclusiveAccessControllerBase { + // Used in testing to set the state to tab fullscreen. + bool is_tab_fullscreen_for_testing_ = false; + ++#if 0 + // Tracks related popups that lost activation or were shown without activation + // during content fullscreen sessions. This also activates the popups when + // fullscreen exits, to prevent sites from creating persisent popunders. + std::unique_ptr popunder_preventer_; ++#endif + + base::ObserverList observer_list_; + diff --git a/patches/chromium/fix_allow_guest_webcontents_to_enter_fullscreen.patch b/patches/chromium/fix_allow_guest_webcontents_to_enter_fullscreen.patch new file mode 100644 index 0000000000000..7786b2fb77fe4 --- /dev/null +++ b/patches/chromium/fix_allow_guest_webcontents_to_enter_fullscreen.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Mon, 6 Jun 2022 14:25:15 -0700 +Subject: fix: allow guest webcontents to enter fullscreen + +This can be upstreamed, a guest webcontents can't technically become the focused webContents. This DCHECK should allow all guest webContents to request fullscreen entrance. + +diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc +index 2aa24b773a974e7789c661a0ffa5e01715c6e229..74993d461cbd0885a709cf8b663b9c69650aa3cf 100644 +--- a/content/browser/web_contents/web_contents_impl.cc ++++ b/content/browser/web_contents/web_contents_impl.cc +@@ -3469,7 +3469,7 @@ void WebContentsImpl::EnterFullscreenMode( + OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::EnterFullscreenMode"); + DCHECK(CanEnterFullscreenMode(requesting_frame, options)); + DCHECK(requesting_frame->IsActive()); +- DCHECK(ContainsOrIsFocusedWebContents()); ++ DCHECK(ContainsOrIsFocusedWebContents() || IsGuest()); + + if (delegate_) { + delegate_->EnterFullscreenModeForTab(requesting_frame, options); diff --git a/patches/chromium/fix_aspect_ratio_with_max_size.patch b/patches/chromium/fix_aspect_ratio_with_max_size.patch index 195ea7ae74d67..1f2b4db050994 100644 --- a/patches/chromium/fix_aspect_ratio_with_max_size.patch +++ b/patches/chromium/fix_aspect_ratio_with_max_size.patch @@ -11,10 +11,10 @@ enlarge window above dimensions set during creation of the BrowserWindow. diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index 9ca11a19e66e34585b4b11e89cc3b789a4389b5e..264a9109e42c23e9be6bf7269b3cfee2634b61e4 100644 +index 91e45df23e659d705839fa3798ad3452bac012e5..2dbe61a4bdf6556f6db101e47d81d37417736bd1 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc -@@ -3581,6 +3581,21 @@ void HWNDMessageHandler::SizeWindowToAspectRatio(UINT param, +@@ -3703,6 +3703,21 @@ void HWNDMessageHandler::SizeWindowToAspectRatio(UINT param, delegate_->GetMinMaxSize(&min_window_size, &max_window_size); min_window_size = delegate_->DIPToScreenSize(min_window_size); max_window_size = delegate_->DIPToScreenSize(max_window_size); @@ -33,6 +33,6 @@ index 9ca11a19e66e34585b4b11e89cc3b789a4389b5e..264a9109e42c23e9be6bf7269b3cfee2 + if (max_window_size.height()) + max_window_size.Enlarge(0, rect.bottom - rect.top); + } - gfx::SizeRectToAspectRatio(GetWindowResizeEdge(param), aspect_ratio_.value(), - min_window_size, max_window_size, window_rect); - } + + absl::optional max_size_param; + if (!max_window_size.IsEmpty()) diff --git a/patches/chromium/fix_crash_loading_non-standard_schemes_in_iframes.patch b/patches/chromium/fix_crash_loading_non-standard_schemes_in_iframes.patch new file mode 100644 index 0000000000000..84d7eb40925bc --- /dev/null +++ b/patches/chromium/fix_crash_loading_non-standard_schemes_in_iframes.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr +Date: Mon, 29 Aug 2022 11:44:57 +0200 +Subject: fix: crash loading non-standard schemes in iframes + +This fixes a crash that occurs when loading non-standard schemes from +iframes or webviews. This was happening because +ChildProcessSecurityPolicyImpl::CanAccessDataForOrigin contains explicit +exceptions to allow built-in non-standard schemes, but does not check +for non-standard schemes registered by the embedder. + +Upstream, https://bugs.chromium.org/p/chromium/issues/detail?id=1081397 +contains several paths forward - here I chose to swap out the +CHECK in navigation_request.cc from policy->CanAccessDataForOrigin to +policy->CanCommitOriginAndUrl. + +Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3856266. + +diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc +index 37434a26db44ed035fcbebd9febbda10efa859da..060b310d38db85944e37b8a202493212106d8946 100644 +--- a/content/browser/renderer_host/navigation_request.cc ++++ b/content/browser/renderer_host/navigation_request.cc +@@ -6573,10 +6573,11 @@ std::pair NavigationRequest:: + if (IsForMhtmlSubframe()) + return origin_with_debug_info; + +- int process_id = GetRenderFrameHost()->GetProcess()->GetID(); +- auto* policy = ChildProcessSecurityPolicyImpl::GetInstance(); +- CHECK( +- policy->CanAccessDataForOrigin(process_id, origin_with_debug_info.first)); ++ CanCommitStatus can_commit = GetRenderFrameHost()->CanCommitOriginAndUrl( ++ origin_with_debug_info.first, GetURL(), IsSameDocument(), IsPdf(), ++ GetUrlInfo().is_sandboxed); ++ CHECK_EQ(CanCommitStatus::CAN_COMMIT_ORIGIN_AND_URL, can_commit); ++ + return origin_with_debug_info; + } + +diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h +index 6aff64db8cc09f95d658fe9e0bd54c0b4c6ff433..e1dda0c951f9ea6f28b6d43ab2b9d4481f5d7773 100644 +--- a/content/browser/renderer_host/render_frame_host_impl.h ++++ b/content/browser/renderer_host/render_frame_host_impl.h +@@ -2557,6 +2557,17 @@ class CONTENT_EXPORT RenderFrameHostImpl + HandleAXEvents(tree_id, std::move(updates_and_events), reset_token); + } + ++ // Returns whether the given origin and URL is allowed to commit in the ++ // current RenderFrameHost. The |url| is used to ensure it matches the origin ++ // in cases where it is applicable. This is a more conservative check than ++ // RenderProcessHost::FilterURL, since it will be used to kill processes that ++ // commit unauthorized origins. ++ CanCommitStatus CanCommitOriginAndUrl(const url::Origin& origin, ++ const GURL& url, ++ bool is_same_document_navigation, ++ bool is_pdf, ++ bool is_sandboxed); ++ + protected: + friend class RenderFrameHostFactory; + +@@ -2892,17 +2903,6 @@ class CONTENT_EXPORT RenderFrameHostImpl + // relevant. + void ResetWaitingState(); + +- // Returns whether the given origin and URL is allowed to commit in the +- // current RenderFrameHost. The |url| is used to ensure it matches the origin +- // in cases where it is applicable. This is a more conservative check than +- // RenderProcessHost::FilterURL, since it will be used to kill processes that +- // commit unauthorized origins. +- CanCommitStatus CanCommitOriginAndUrl(const url::Origin& origin, +- const GURL& url, +- bool is_same_document_navigation, +- bool is_pdf, +- bool is_sandboxed); +- + // Returns whether a subframe navigation request should be allowed to commit + // to the current RenderFrameHost. + bool CanSubframeCommitOriginAndUrl(NavigationRequest* navigation_request); diff --git a/patches/chromium/fix_crash_when_saving_edited_pdf_files.patch b/patches/chromium/fix_crash_when_saving_edited_pdf_files.patch index 7db4c0911e37d..28b418cf624a8 100644 --- a/patches/chromium/fix_crash_when_saving_edited_pdf_files.patch +++ b/patches/chromium/fix_crash_when_saving_edited_pdf_files.patch @@ -12,11 +12,11 @@ therefore causes unmapped page access crashes. This patch can be removed should we choose to support chrome.fileSystem or support it enough to fix the crash. -diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js -index f3d71309080248024983891acb17d4df69648056..3cd563ed13ab9bd8fa084f54eb8f112b66399eb9 100644 ---- a/chrome/browser/resources/pdf/pdf_viewer.js -+++ b/chrome/browser/resources/pdf/pdf_viewer.js -@@ -966,25 +966,12 @@ export class PDFViewerElement extends PDFViewerBaseElement { +diff --git a/chrome/browser/resources/pdf/pdf_viewer.ts b/chrome/browser/resources/pdf/pdf_viewer.ts +index 940a00b9b9f992d4254fc74922c3d8b31772fa4e..b3373265a65a6b50276a09bfb54065521ad6eac4 100644 +--- a/chrome/browser/resources/pdf/pdf_viewer.ts ++++ b/chrome/browser/resources/pdf/pdf_viewer.ts +@@ -860,26 +860,12 @@ export class PDFViewerElement extends PDFViewerBaseElement { dataArray = [result.dataToSave]; } @@ -25,7 +25,8 @@ index f3d71309080248024983891acb17d4df69648056..3cd563ed13ab9bd8fa084f54eb8f112b const blob = new Blob(dataArray); - const fileName = this.attachments_[index].name; - chrome.fileSystem.chooseEntry( -- {type: 'saveFile', suggestedName: fileName}, entry => { +- {type: 'saveFile', suggestedName: fileName}, +- (entry?: FileSystemFileEntry) => { - if (chrome.runtime.lastError) { - if (chrome.runtime.lastError.message !== 'User cancelled') { - console.error( @@ -34,7 +35,7 @@ index f3d71309080248024983891acb17d4df69648056..3cd563ed13ab9bd8fa084f54eb8f112b - } - return; - } -- entry.createWriter(writer => { +- entry!.createWriter((writer: FileWriter) => { - writer.write(blob); - // Unblock closing the window now that the user has saved - // successfully. @@ -47,12 +48,11 @@ index f3d71309080248024983891acb17d4df69648056..3cd563ed13ab9bd8fa084f54eb8f112b } /** -@@ -1111,30 +1098,13 @@ export class PDFViewerElement extends PDFViewerBaseElement { - if (!fileName.toLowerCase().endsWith('.pdf')) { +@@ -987,30 +973,12 @@ export class PDFViewerElement extends PDFViewerBaseElement { fileName = fileName + '.pdf'; } + - // Create blob before callback to avoid race condition. -+ + const a = document.createElement('a'); + a.download = fileName; const blob = new Blob([result.dataToSave], {type: 'application/pdf'}); @@ -60,9 +60,9 @@ index f3d71309080248024983891acb17d4df69648056..3cd563ed13ab9bd8fa084f54eb8f112b - { - type: 'saveFile', - accepts: [{description: '*.pdf', extensions: ['pdf']}], -- suggestedName: fileName +- suggestedName: fileName, - }, -- entry => { +- (entry?: FileSystemFileEntry) => { - if (chrome.runtime.lastError) { - if (chrome.runtime.lastError.message !== 'User cancelled') { - console.error( @@ -71,7 +71,7 @@ index f3d71309080248024983891acb17d4df69648056..3cd563ed13ab9bd8fa084f54eb8f112b - } - return; - } -- entry.createWriter(writer => { +- entry!.createWriter((writer: FileWriter) => { - writer.write(blob); - // Unblock closing the window now that the user has saved - // successfully. diff --git a/patches/chromium/fix_dont_delete_SerialPortManager_on_main_thread.patch b/patches/chromium/fix_dont_delete_SerialPortManager_on_main_thread.patch index cf2398b0c00ef..dc7c6ef34bdba 100644 --- a/patches/chromium/fix_dont_delete_SerialPortManager_on_main_thread.patch +++ b/patches/chromium/fix_dont_delete_SerialPortManager_on_main_thread.patch @@ -50,7 +50,7 @@ upstream would also hit this DCHECK, so give it a try with content_shell or chrome and that would help reporting upstream crbug. diff --git a/services/device/device_service.cc b/services/device/device_service.cc -index 11a7b2902490986ba2462f92c3b3e5ae1b1a127f..32d591621c7206affab50ef061aa565527d5952f 100644 +index e1066e90022485463adb69f5738107670d94ba3f..85cdc5d2df4b17d41305fa8ff4337de65056cdf7 100644 --- a/services/device/device_service.cc +++ b/services/device/device_service.cc @@ -159,7 +159,7 @@ DeviceService::~DeviceService() { diff --git a/patches/chromium/fix_export_zlib_symbols.patch b/patches/chromium/fix_export_zlib_symbols.patch index 079d44b8eafbd..0590f70607420 100644 --- a/patches/chromium/fix_export_zlib_symbols.patch +++ b/patches/chromium/fix_export_zlib_symbols.patch @@ -6,10 +6,10 @@ Subject: fix: export zlib symbols This patch sets ZLIB_DLL so that we properly export zlib symbols. diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn -index 49f52e1f8b1e505481a124a55ab91a7dd5ec571c..2cb7ee4f708808433e638bf62cb9a465c3651944 100644 +index ee7483e9ef6a4ff85f8e6ac966d6e6c1e669dcf6..54d42304d84e1a25bb8b690282ff8268626eb5ad 100644 --- a/third_party/zlib/BUILD.gn +++ b/third_party/zlib/BUILD.gn -@@ -312,6 +312,10 @@ component("zlib") { +@@ -316,6 +316,10 @@ component("zlib") { defines = [] deps = [] diff --git a/patches/chromium/fix_expose_decrementcapturercount_in_web_contents_impl.patch b/patches/chromium/fix_expose_decrementcapturercount_in_web_contents_impl.patch index e02059c0f4cde..4ad225cdb9e3c 100644 --- a/patches/chromium/fix_expose_decrementcapturercount_in_web_contents_impl.patch +++ b/patches/chromium/fix_expose_decrementcapturercount_in_web_contents_impl.patch @@ -8,10 +8,10 @@ we invoke it in order to expose contents.decrementCapturerCount([stayHidden, sta to users. We should try to upstream this. diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h -index e1ac23f3adf38591ae220ea84c5c0717a28e64bb..fad1663512cf30b270289ecfa9c336b08fe67836 100644 +index 892efd5009b0a0ef00081bd765d20c46d68b2324..f40238dc39a017a07972c8fec48a802da8a2cad0 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h -@@ -1831,7 +1831,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, +@@ -1858,7 +1858,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, // IncrementCapturerCount() is destructed. void DecrementCapturerCount(bool stay_hidden, bool stay_awake, @@ -21,10 +21,10 @@ index e1ac23f3adf38591ae220ea84c5c0717a28e64bb..fad1663512cf30b270289ecfa9c336b0 // Calculates the PageVisibilityState for |visibility|, taking the capturing // state into account. diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h -index cd1b44d4ff5ce8924749ba9e41b3f599108bb8fd..72bc509b0506fafd026aa858864623886142b5f0 100644 +index a389a9c41f96ec3231b62510cde140c52dcdbe9e..25f7919970139baf58531a257f7a8c7184fef85a 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h -@@ -673,6 +673,10 @@ class WebContents : public PageNavigator, +@@ -670,6 +670,10 @@ class WebContents : public PageNavigator, bool stay_awake, bool is_activity = true) = 0; diff --git a/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch b/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch index 7460a09ea3beb..8892da56d9f9c 100644 --- a/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch +++ b/patches/chromium/fix_media_key_usage_with_globalshortcuts.patch @@ -59,10 +59,10 @@ index ad366d0fd4c3a637d75a102ab56984f0d01bfc04..d63eb133fd4bab1ea309bb8c742acf88 // true if register successfully, or false if 1) the specificied |accelerator| // has been registered by another caller or other native applications, or diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc -index ac923f436cbdd6ded0629da4e4c659d94258e55b..43f9531075bcef87de8e60f24071f49fe4cd0891 100644 +index b954f8dde00d4f5257223c464e9145a6bef48900..ee9da826014d3aae9675daac6cdbc0f447a14efd 100644 --- a/content/browser/media/media_keys_listener_manager_impl.cc +++ b/content/browser/media/media_keys_listener_manager_impl.cc -@@ -55,7 +55,12 @@ bool MediaKeysListenerManagerImpl::StartWatchingMediaKey( +@@ -56,7 +56,11 @@ bool MediaKeysListenerManagerImpl::StartWatchingMediaKey( CanActiveMediaSessionControllerReceiveEvents(); // Tell the underlying MediaKeysListener to listen for the key. @@ -71,12 +71,11 @@ index ac923f436cbdd6ded0629da4e4c659d94258e55b..43f9531075bcef87de8e60f24071f49f +#if BUILDFLAG(IS_MAC) + !media_key_handling_enabled_ && +#endif // BUILDFLAG(IS_MAC) -+ should_start_watching && -+ media_keys_listener_ && ++ should_start_watching && media_keys_listener_ && !media_keys_listener_->StartWatchingMediaKey(key_code)) { return false; } -@@ -238,18 +243,18 @@ void MediaKeysListenerManagerImpl::StartListeningForMediaKeysIfNecessary() { +@@ -239,6 +243,7 @@ void MediaKeysListenerManagerImpl::StartListeningForMediaKeysIfNecessary() { #endif if (system_media_controls_) { @@ -84,19 +83,22 @@ index ac923f436cbdd6ded0629da4e4c659d94258e55b..43f9531075bcef87de8e60f24071f49f system_media_controls_->AddObserver(this); system_media_controls_notifier_ = std::make_unique( - system_media_controls_.get()); -- } else { -- // If we can't access system media controls, then directly listen for media -- // key keypresses instead. -- media_keys_listener_ = ui::MediaKeysListener::Create( -- this, ui::MediaKeysListener::Scope::kGlobal); -- DCHECK(media_keys_listener_); +@@ -251,6 +256,19 @@ void MediaKeysListenerManagerImpl::StartListeningForMediaKeysIfNecessary() { + DCHECK(media_keys_listener_); } -+ // Directly listen for media key keypresses when using GlobalShortcuts. -+ media_keys_listener_ = ui::MediaKeysListener::Create( -+ this, ui::MediaKeysListener::Scope::kGlobal); -+ DCHECK(media_keys_listener_); ++#if BUILDFLAG(IS_MAC) ++ // Chromium's implementation of SystemMediaControls falls ++ // down into MPRemoteCommandCenter, which makes it such that an app will not ++ // will not receive remote control events until it begins playing audio. ++ // If there's not already a MediaKeysListener instance, create one so ++ // that globalShortcuts work correctly. ++ if (!media_keys_listener_) { ++ media_keys_listener_ = ui::MediaKeysListener::Create( ++ this, ui::MediaKeysListener::Scope::kGlobal); ++ DCHECK(media_keys_listener_); ++ } ++#endif + EnsureAuxiliaryServices(); } diff --git a/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch b/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch index 5b43683bfa253..4f26f498c4d3a 100644 --- a/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch +++ b/patches/chromium/fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch @@ -44,10 +44,10 @@ index 4a894ef70eeb1d8489049aef552c9bae4f24ae62..df101c53861a83f107d459270c37b3b4 } } diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h -index 79dffd981f4d461f30bd3796cfba1457eda3a89d..ae378ce95f90989fd0e74c38b57f5f7dc0a1ee29 100644 +index 81e5cde38627914e6a19ed2c1ab62547fdd7fc19..111c59c91073578d8d176598b5e4d10b84918d4c 100644 --- a/content/browser/renderer_host/legacy_render_widget_host_win.h +++ b/content/browser/renderer_host/legacy_render_widget_host_win.h -@@ -105,6 +105,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND +@@ -106,6 +106,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest) MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange) diff --git a/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch b/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch new file mode 100644 index 0000000000000..f501a3b7786e3 --- /dev/null +++ b/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kyrylo Hrechykhin +Date: Thu, 6 Oct 2022 18:30:53 +0200 +Subject: fix: on-screen-keyboard hides on input blur in webview + +Changes introduced by this patch fix issue where OSK does not hide on +input rendered inside webview is blurred. This patch should be removed +when proper fix in chromium repo is available. + +Note: the issue still occurs if input rendered in webview blurred due +to touch outside of webview. It is caused by webview implementation +details. Specificaly due to webview has its own tree nodes and focused +node does not change in this case. + +chromium-bug: https://crbug.com/1369605 + +diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc +index 4e6d62be68d59c8a49159fda4d1e68f101a6f0a3..cfd5a01ea84a1f454a5172da3e96e66a50c82939 100644 +--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc ++++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc +@@ -992,6 +992,12 @@ RenderWidgetHostViewChildFrame::DidUpdateVisualProperties( + return viz::ScopedSurfaceIdAllocator(std::move(allocation_task)); + } + ++void RenderWidgetHostViewChildFrame::FocusedNodeChanged( ++ bool is_editable_node, ++ const gfx::Rect& node_bounds_in_screen) { ++ NOTREACHED(); ++} ++ + ui::TextInputType RenderWidgetHostViewChildFrame::GetTextInputType() const { + if (!text_input_manager_) + return ui::TEXT_INPUT_TYPE_NONE; +diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h +index 70b151bcb8e3b1964d316bf2e169dbe0f28f24c7..c3857298974a0c2761efcd3924587607997e3117 100644 +--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h ++++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h +@@ -181,6 +181,8 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame + void DisableAutoResize(const gfx::Size& new_size) override; + viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties( + const cc::RenderFrameMetadata& metadata) override; ++ void FocusedNodeChanged(bool is_editable_node, ++ const gfx::Rect& node_bounds_in_screen) override; + + // RenderFrameMetadataProvider::Observer implementation. + void OnRenderFrameMetadataChangedBeforeActivation( +diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc +index 74993d461cbd0885a709cf8b663b9c69650aa3cf..940045d9bbb62676811f55f5d30a93a352f43ede 100644 +--- a/content/browser/web_contents/web_contents_impl.cc ++++ b/content/browser/web_contents/web_contents_impl.cc +@@ -7928,7 +7928,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame( + "WebContentsImpl::OnFocusedElementChangedInFrame", + "render_frame_host", frame); + RenderWidgetHostViewBase* root_view = +- static_cast(GetRenderWidgetHostView()); ++ static_cast(GetTopLevelRenderWidgetHostView()); + if (!root_view || !frame->GetView()) + return; + // Convert to screen coordinates from window coordinates by adding the diff --git a/patches/chromium/fix_patch_out_permissions_checks_in_exclusive_access.patch b/patches/chromium/fix_patch_out_permissions_checks_in_exclusive_access.patch deleted file mode 100644 index f957509ddd87c..0000000000000 --- a/patches/chromium/fix_patch_out_permissions_checks_in_exclusive_access.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Mon, 25 Oct 2021 21:45:57 +0200 -Subject: fix: patch out permissions checks in exclusive_access - -This patch is necessary in order to properly enable -navigator.keyboard.{(un)?lock}() functionality. We don't have a concept -of PermissionManager nor of a Profile, so this would not affect usage of -the API. - -We might consider potentially using our own permissions handler, -but it's not strictly necessary for this API to work to spec. - -Profile check has been upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3247196 - -diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc -index 9b2c91d39324b61afa49ccea6be2eda8308473ff..1652b52c5c752809348b3ab44d3703ac343c829d 100644 ---- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc -+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc -@@ -382,13 +382,9 @@ void FullscreenController::EnterFullscreenModeInternal( - // Do not enter fullscreen mode if disallowed by pref. This prevents the user - // from manually entering fullscreen mode and also disables kiosk mode on - // desktop platforms. -- if (!exclusive_access_manager() -- ->context() -- ->GetProfile() -- ->GetPrefs() -- ->GetBoolean(prefs::kFullscreenAllowed)) { -+ auto* profile = exclusive_access_manager()->context()->GetProfile(); -+ if (!profile || !profile->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed)) - return; -- } - #endif - - toggled_into_fullscreen_ = true; -@@ -401,6 +397,7 @@ void FullscreenController::EnterFullscreenModeInternal( - url = extension_caused_fullscreen_; - } - -+#if 0 - if (display_id != display::kInvalidDisplayId) { - // Check, but do not prompt, for permission to request a specific screen. - // Sites generally need permission to get the display id in the first place. -@@ -413,6 +410,7 @@ void FullscreenController::EnterFullscreenModeInternal( - display_id = display::kInvalidDisplayId; - } - } -+#endif - - if (option == BROWSER) - base::RecordAction(base::UserMetricsAction("ToggleFullscreen")); diff --git a/patches/chromium/fix_patch_out_profile_refs_in_accessibility_ui.patch b/patches/chromium/fix_patch_out_profile_refs_in_accessibility_ui.patch index 0559a3d4c4528..079a862e35e77 100644 --- a/patches/chromium/fix_patch_out_profile_refs_in_accessibility_ui.patch +++ b/patches/chromium/fix_patch_out_profile_refs_in_accessibility_ui.patch @@ -7,11 +7,11 @@ This tweaks Chrome's Accessibility support at chrome://accessibility to make it usable from Electron by removing Profile references. diff --git a/chrome/browser/accessibility/accessibility_ui.cc b/chrome/browser/accessibility/accessibility_ui.cc -index 555dba06e99bd7294f88a21ddaf3b86a12fdd5ac..8064592eb285d1407ff8334149c27e3a65560d9e 100644 +index 28366584e6a3cc2655e5bc7417c4e52b9d0f4163..46894c02ca15f7091f280b2960f2ec628c500e53 100644 --- a/chrome/browser/accessibility/accessibility_ui.cc +++ b/chrome/browser/accessibility/accessibility_ui.cc -@@ -20,7 +20,10 @@ - #include "base/values.h" +@@ -21,7 +21,10 @@ + #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" +#if 0 @@ -33,49 +33,49 @@ index 555dba06e99bd7294f88a21ddaf3b86a12fdd5ac..8064592eb285d1407ff8334149c27e3a #include "ui/views/accessibility/widget_ax_tree_id_map.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" -@@ -163,7 +168,7 @@ std::unique_ptr BuildTargetDescriptor( +@@ -162,7 +167,7 @@ base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) { accessibility_mode); } -#if !BUILDFLAG(IS_ANDROID) +#if 0 - std::unique_ptr BuildTargetDescriptor(Browser* browser) { - std::unique_ptr target_data( - new base::DictionaryValue()); -@@ -202,7 +207,9 @@ void HandleAccessibilityRequestCallback( + base::Value::Dict BuildTargetDescriptor(Browser* browser) { + base::Value::Dict target_data; + target_data.Set(kSessionIdField, browser->session_id().id()); +@@ -196,7 +201,9 @@ void HandleAccessibilityRequestCallback( DCHECK(ShouldHandleAccessibilityRequestCallback(path)); - base::DictionaryValue data; + base::Value::Dict data; +#if 0 PrefService* pref = Profile::FromBrowserContext(current_context)->GetPrefs(); +#endif ui::AXMode mode = content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode(); bool is_native_enabled = content::BrowserAccessibilityState::GetInstance() -@@ -236,7 +243,7 @@ void HandleAccessibilityRequestCallback( - data.SetBoolKey(kViewsAccessibility, - features::IsAccessibilityTreeForViewsEnabled()); +@@ -228,7 +235,7 @@ void HandleAccessibilityRequestCallback( + // enabled. + data.Set(kViewsAccessibility, features::IsAccessibilityTreeForViewsEnabled()); - bool show_internal = pref->GetBoolean(prefs::kShowInternalAccessibilityTree); + bool show_internal = true; - data.SetStringKey(kInternal, show_internal ? kOn : kOff); + data.Set(kInternal, show_internal ? kOn : kOff); - std::unique_ptr rvh_list(new base::ListValue()); -@@ -271,11 +278,11 @@ void HandleAccessibilityRequestCallback( - data.Set(kPagesField, std::move(rvh_list)); + base::Value::List page_list; +@@ -264,11 +271,11 @@ void HandleAccessibilityRequestCallback( + data.Set(kPagesField, std::move(page_list)); - std::unique_ptr browser_list(new base::ListValue()); + base::Value::List browser_list; -#if !BUILDFLAG(IS_ANDROID) +#if 0 for (Browser* browser : *BrowserList::GetInstance()) { - browser_list->Append(BuildTargetDescriptor(browser)); + browser_list.Append(BuildTargetDescriptor(browser)); } -#endif // !BUILDFLAG(IS_ANDROID) +#endif // !BUILDFLAG(IS_ANDROID) data.Set(kBrowsersField, std::move(browser_list)); - std::unique_ptr widgets_list(new base::ListValue()); -@@ -491,8 +498,10 @@ void AccessibilityUIMessageHandler::SetGlobalFlag(const base::ListValue* args) { + base::Value::List widgets_list; +@@ -483,8 +490,10 @@ void AccessibilityUIMessageHandler::SetGlobalFlag( AllowJavascript(); if (flag_name_str == kInternal) { @@ -86,7 +86,7 @@ index 555dba06e99bd7294f88a21ddaf3b86a12fdd5ac..8064592eb285d1407ff8334149c27e3a return; } -@@ -599,10 +608,12 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree( +@@ -588,10 +597,12 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree( AXPropertyFilter::ALLOW_EMPTY); AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY); @@ -97,26 +97,26 @@ index 555dba06e99bd7294f88a21ddaf3b86a12fdd5ac..8064592eb285d1407ff8334149c27e3a std::string accessibility_contents = - web_contents->DumpAccessibilityTree(internal, property_filters); + web_contents->DumpAccessibilityTree(true, property_filters); - result->SetStringKey(kTreeField, accessibility_contents); - FireWebUIListener(request_type, *(result.get())); + result.Set(kTreeField, accessibility_contents); + FireWebUIListener(request_type, result); } -@@ -627,6 +638,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( +@@ -614,6 +625,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( AXPropertyFilter::ALLOW_EMPTY); AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY); +#if 0 for (Browser* browser : *BrowserList::GetInstance()) { if (browser->session_id().id() == session_id) { - std::unique_ptr result( -@@ -641,6 +653,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( + base::Value::Dict result = BuildTargetDescriptor(browser); +@@ -626,6 +638,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree( return; } } +#endif #endif // !BUILDFLAG(IS_ANDROID) // No browser with the specified |session_id| was found. - std::unique_ptr result(new base::DictionaryValue()); -@@ -757,5 +770,7 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents( + base::Value::Dict result; +@@ -738,5 +751,7 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents( // static void AccessibilityUIMessageHandler::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { @@ -125,10 +125,10 @@ index 555dba06e99bd7294f88a21ddaf3b86a12fdd5ac..8064592eb285d1407ff8334149c27e3a +#endif } diff --git a/chrome/browser/accessibility/accessibility_ui.h b/chrome/browser/accessibility/accessibility_ui.h -index 0f73d3883093f6e49427ac6fe6428e97282a1e03..9041c90d13b07b03cc96e8a03a3821ef54a69a7d 100644 +index 8ae101cdb4de8ea570e3af6e05e9124b51a9f14c..2706f8ad05a6bee71b68f59406eb0bd3391a3fcd 100644 --- a/chrome/browser/accessibility/accessibility_ui.h +++ b/chrome/browser/accessibility/accessibility_ui.h -@@ -26,6 +26,8 @@ struct AXEventNotificationDetails; +@@ -22,6 +22,8 @@ struct AXEventNotificationDetails; class WebContents; } // namespace content @@ -137,7 +137,7 @@ index 0f73d3883093f6e49427ac6fe6428e97282a1e03..9041c90d13b07b03cc96e8a03a3821ef namespace user_prefs { class PrefRegistrySyncable; } // namespace user_prefs -@@ -67,6 +69,8 @@ class AccessibilityUIMessageHandler : public content::WebUIMessageHandler { +@@ -63,6 +65,8 @@ class AccessibilityUIMessageHandler : public content::WebUIMessageHandler { static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); private: diff --git a/patches/chromium/fix_properly_honor_printing_page_ranges.patch b/patches/chromium/fix_properly_honor_printing_page_ranges.patch index 7addac9d25797..df7e887c60b17 100644 --- a/patches/chromium/fix_properly_honor_printing_page_ranges.patch +++ b/patches/chromium/fix_properly_honor_printing_page_ranges.patch @@ -62,10 +62,10 @@ index 9e351c7e80a135adf0ebe011763f5164e51981bb..b9fcb4d2a8c7a22ebc7cd8434636454e PMPrintSettings print_settings = static_cast([print_info_.get() PMPrintSettings]); diff --git a/printing/printing_context_system_dialog_win.cc b/printing/printing_context_system_dialog_win.cc -index a964910a3b7e3bd225a3b8dc35ef9dc57c77248d..9f791d9ba5f0b540f5e3a67f5e1abb318ddb7680 100644 +index b7ba6ba4446963b08bce9fe416379169bd880378..7c621ea7a60725d08ee9ade68b65fd5bc88b0c2d 100644 --- a/printing/printing_context_system_dialog_win.cc +++ b/printing/printing_context_system_dialog_win.cc -@@ -54,14 +54,28 @@ void PrintingContextSystemDialogWin::AskUserForSettings( +@@ -75,14 +75,28 @@ void PrintingContextSystemDialogWin::AskUserForSettings( PRINTPAGERANGE ranges[32]; dialog_options.nStartPage = START_PAGE_GENERAL; if (max_pages) { @@ -74,7 +74,7 @@ index a964910a3b7e3bd225a3b8dc35ef9dc57c77248d..9f791d9ba5f0b540f5e3a67f5e1abb31 - ranges[0].nFromPage = 1; - ranges[0].nToPage = max_pages; - dialog_options.nPageRanges = 1; -- dialog_options.nMaxPageRanges = base::size(ranges); +- dialog_options.nMaxPageRanges = std::size(ranges); + + auto page_ranges = settings_->ranges(); + if (!page_ranges.empty()) { @@ -95,15 +95,15 @@ index a964910a3b7e3bd225a3b8dc35ef9dc57c77248d..9f791d9ba5f0b540f5e3a67f5e1abb31 + dialog_options.nMinPage = 1; dialog_options.nMaxPage = max_pages; -+ dialog_options.nMaxPageRanges = base::size(ranges); ++ dialog_options.nMaxPageRanges = std::size(ranges); dialog_options.lpPageRanges = ranges; } else { // No need to bother, we don't know how many pages are available. diff --git a/ui/gtk/printing/print_dialog_gtk.cc b/ui/gtk/printing/print_dialog_gtk.cc -index aca31e17a90f95d6a4616fec5b33ce55cd136af0..e340cfae256797b7683fad8b32776a95889a8f46 100644 +index db23b214107c2b4a137e623e183ca08b409959fb..3f10aa71ad6fe698392228dd4b8a73eae7b1dbc6 100644 --- a/ui/gtk/printing/print_dialog_gtk.cc +++ b/ui/gtk/printing/print_dialog_gtk.cc -@@ -240,6 +240,24 @@ void PrintDialogGtk::UpdateSettings( +@@ -243,6 +243,24 @@ void PrintDialogGtk::UpdateSettings( gtk_print_settings_set_n_copies(gtk_settings_, settings->copies()); gtk_print_settings_set_collate(gtk_settings_, settings->collate()); diff --git a/patches/chromium/fix_return_v8_value_from_localframe_requestexecutescript.patch b/patches/chromium/fix_return_v8_value_from_localframe_requestexecutescript.patch new file mode 100644 index 0000000000000..db49bbdb07304 --- /dev/null +++ b/patches/chromium/fix_return_v8_value_from_localframe_requestexecutescript.patch @@ -0,0 +1,198 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 +Date: Mon, 5 Sep 2022 19:07:54 +0900 +Subject: fix: return v8::Value from LocalFrame::RequestExecuteScript + +Allows api::WebFrame::ExecuteJavaScript(InIsolateWorld) to work with +v8::Value instead of base::Value. +Refs https://bugs.chromium.org/p/chromium/issues/detail?id=1323953 + +diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc +index 032ef69a5b50cef88f341b8a7a3de0acef88898d..a425fe1fb6275afd8e25033932f6f444efd6f643 100644 +--- a/extensions/renderer/script_injection.cc ++++ b/extensions/renderer/script_injection.cc +@@ -332,6 +332,7 @@ void ScriptInjection::InjectJs(std::set* executing_scripts, + blink::mojom::LoadEventBlockingOption::kBlock, + base::BindOnce(&ScriptInjection::OnJsInjectionCompleted, + weak_ptr_factory_.GetWeakPtr()), ++ base::NullCallback(), + blink::BackForwardCacheAware::kPossiblyDisallow, + injector_->ShouldWaitForPromise()); + } +diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h +index ba043cf658f568e4390db1619b1042749e430b2b..285d53074a0fcfb00caaec8c3f8a0bbebcd68953 100644 +--- a/third_party/blink/public/web/web_local_frame.h ++++ b/third_party/blink/public/web/web_local_frame.h +@@ -424,6 +424,7 @@ class WebLocalFrame : public WebFrame { + mojom::EvaluationTiming, + mojom::LoadEventBlockingOption, + WebScriptExecutionCallback, ++ WebScriptExecutionCallbackUnmodified, + BackForwardCacheAware, + mojom::PromiseResultOption) = 0; + +diff --git a/third_party/blink/public/web/web_script_execution_callback.h b/third_party/blink/public/web/web_script_execution_callback.h +index c37e7ef609c91e9b9107d7a6194b213039184fb9..3f2e27b4f51dc1d673883cf2bf75f596a952ac44 100644 +--- a/third_party/blink/public/web/web_script_execution_callback.h ++++ b/third_party/blink/public/web/web_script_execution_callback.h +@@ -17,6 +17,12 @@ namespace base { + class TimeTicks; + } + ++namespace v8 { ++class Value; ++template ++class Local; ++} ++ + namespace blink { + + template +@@ -26,6 +32,9 @@ using WebScriptExecutionCallback = + base::OnceCallback>&, + base::TimeTicks)>; + ++using WebScriptExecutionCallbackUnmodified = ++ base::OnceCallback>&)>; ++ + } // namespace blink + + #endif // THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SCRIPT_EXECUTION_CALLBACK_H_ +diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc +index 3891afe36284d033e3ba88ffda63545b07f6c718..69eb59439932887b34099f7cd3ebd51ecd4aa676 100644 +--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc ++++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc +@@ -1133,6 +1133,7 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld( + auto* executor = MakeGarbageCollected( + DomWindow(), ToScriptState(frame_, *isolated_world), + execution_request->Callback(), ++ base::NullCallback(), + /*executor=*/execution_request); + executor->Run(); + +diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/third_party/blink/renderer/core/frame/pausable_script_executor.cc +index 4b2b8fc8e5b48948b36bfdc5b76ebeabe5c72606..90437b41b3e12309c194d9f3e94ac37603403227 100644 +--- a/third_party/blink/renderer/core/frame/pausable_script_executor.cc ++++ b/third_party/blink/renderer/core/frame/pausable_script_executor.cc +@@ -262,7 +262,7 @@ void PausableScriptExecutor::CreateAndRun(LocalDOMWindow* window, + } + PausableScriptExecutor* executor = + MakeGarbageCollected( +- window, script_state, std::move(callback), ++ window, script_state, std::move(callback), base::NullCallback(), + MakeGarbageCollected( + window->GetIsolate(), function, receiver, argc, argv)); + executor->Run(); +@@ -277,6 +277,14 @@ void PausableScriptExecutor::ContextDestroyed() { + ScriptState::Scope script_scope(script_state_); + std::move(callback_).Run(Vector>(), {}); + } ++ if (raw_callback_) { ++ // Though the context is (about to be) destroyed, the callback is invoked ++ // with a vector of v8::Local<>s, which implies that creating v8::Locals ++ // is permitted. Ensure a valid scope is present for the callback. ++ // See https://crbug.com/840719. ++ ScriptState::Scope script_scope(script_state_); ++ std::move(raw_callback_).Run(Vector>()); ++ } + Dispose(); + } + +@@ -285,11 +293,12 @@ PausableScriptExecutor::PausableScriptExecutor( + scoped_refptr world, + Vector sources, + mojom::blink::UserActivationOption user_gesture, +- WebScriptExecutionCallback callback) ++ WebScriptExecutionCallback callback, ++ WebScriptExecutionCallbackUnmodified raw_callback) + : PausableScriptExecutor( + window, + ToScriptState(window, *world), +- std::move(callback), ++ std::move(callback), std::move(raw_callback), + MakeGarbageCollected(std::move(sources), + world->GetWorldId(), + user_gesture)) {} +@@ -298,11 +307,12 @@ PausableScriptExecutor::PausableScriptExecutor( + LocalDOMWindow* window, + ScriptState* script_state, + WebScriptExecutionCallback callback, ++ WebScriptExecutionCallbackUnmodified raw_callback, + Executor* executor) + : ExecutionContextLifecycleObserver(window), + script_state_(script_state), + callback_(std::move(callback)), +- blocking_option_(mojom::blink::LoadEventBlockingOption::kDoNotBlock), ++ raw_callback_(std::move(raw_callback)), + executor_(executor) { + CHECK(script_state_); + CHECK(script_state_->ContextIsValid()); +@@ -388,6 +398,9 @@ void PausableScriptExecutor::HandleResults( + if (callback_) + std::move(callback_).Run(results, start_time_); + ++ if (raw_callback_) ++ std::move(raw_callback_).Run(results); ++ + Dispose(); + } + +diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.h b/third_party/blink/renderer/core/frame/pausable_script_executor.h +index 12a42ef52c2689a1c2d3029890fed8e12faa03aa..fe5bd4bee4f236f2958dcf03e1f644639afc4c75 100644 +--- a/third_party/blink/renderer/core/frame/pausable_script_executor.h ++++ b/third_party/blink/renderer/core/frame/pausable_script_executor.h +@@ -48,10 +48,12 @@ class CORE_EXPORT PausableScriptExecutor final + scoped_refptr, + Vector, + mojom::blink::UserActivationOption, +- WebScriptExecutionCallback); ++ WebScriptExecutionCallback, ++ WebScriptExecutionCallbackUnmodified); + PausableScriptExecutor(LocalDOMWindow*, + ScriptState*, + WebScriptExecutionCallback, ++ WebScriptExecutionCallbackUnmodified, + Executor*); + ~PausableScriptExecutor() override; + +@@ -75,6 +77,7 @@ class CORE_EXPORT PausableScriptExecutor final + + Member script_state_; + WebScriptExecutionCallback callback_; ++ WebScriptExecutionCallbackUnmodified raw_callback_; + base::TimeTicks start_time_; + mojom::blink::LoadEventBlockingOption blocking_option_; + TaskHandle task_handle_; +diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +index a31fe747be3c228c4eec512835de6368d29516aa..4197391cb15a55eaca55eca2d3886ebcb8360e95 100644 +--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc ++++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +@@ -1086,6 +1086,7 @@ void WebLocalFrameImpl::RequestExecuteScript( + mojom::blink::EvaluationTiming evaluation_timing, + mojom::blink::LoadEventBlockingOption blocking_option, + WebScriptExecutionCallback callback, ++ WebScriptExecutionCallbackUnmodified raw_callback, + BackForwardCacheAware back_forward_cache_aware, + mojom::blink::PromiseResultOption promise_behavior) { + DCHECK(GetFrame()); +@@ -1109,7 +1110,7 @@ void WebLocalFrameImpl::RequestExecuteScript( + base::checked_cast(sources.size())); + auto* executor = MakeGarbageCollected( + GetFrame()->DomWindow(), std::move(world), std::move(script_sources), +- user_gesture, std::move(callback)); ++ user_gesture, std::move(callback), std::move(raw_callback)); + executor->set_wait_for_promise(promise_behavior); + switch (evaluation_timing) { + case mojom::blink::EvaluationTiming::kAsynchronous: +diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h +index 76cbde766ba8ebc1b503eea9a5b6335f775dc00c..ebb1084be8069251d8f568e7b9f30d3dc83b0a64 100644 +--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h ++++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h +@@ -189,6 +189,7 @@ class CORE_EXPORT WebLocalFrameImpl final + mojom::blink::EvaluationTiming, + mojom::blink::LoadEventBlockingOption, + WebScriptExecutionCallback, ++ WebScriptExecutionCallbackUnmodified, + BackForwardCacheAware back_forward_cache_aware, + mojom::blink::PromiseResultOption) override; + void Alert(const WebString& message) override; diff --git a/patches/chromium/fix_revert_emulationhandler_update_functions_to_early_return.patch b/patches/chromium/fix_revert_emulationhandler_update_functions_to_early_return.patch new file mode 100644 index 0000000000000..0ff3414d49fa0 --- /dev/null +++ b/patches/chromium/fix_revert_emulationhandler_update_functions_to_early_return.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr +Date: Fri, 26 Aug 2022 11:24:27 +0200 +Subject: fix: revert EmulationHandler update functions to early return + +Our debugger class (a subclass of ontent::DevToolsAgentHostClient) isn't +aware of those changes unless we hook RenderFrameHostChanged. If we +don't do this, some navigation lifecycle events +{loadingFinished, dataReceived} emitted by the renderer are lost. We +disconnect and reconnect the webcontents to the DevToolsAgentHost to +prevent this from happening. + +As of https://chromium-review.googlesource.com/c/chromium/src/+/3758294 +this results in a DCHECK, since DevToolsAgentHost::DisconnectWebContents +results in a call to UpdateDeviceEmulationState and host_ is nullptr. To +fix this, we revert those state update calls to early returns. + +Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3856525 + +diff --git a/content/browser/devtools/protocol/emulation_handler.cc b/content/browser/devtools/protocol/emulation_handler.cc +index 90c7fbebfcedd744163f8294be6de99db7b54aef..5c507f3aa02d918fc9c87ed3842f282f4545f0ff 100644 +--- a/content/browser/devtools/protocol/emulation_handler.cc ++++ b/content/browser/devtools/protocol/emulation_handler.cc +@@ -588,7 +588,9 @@ WebContentsImpl* EmulationHandler::GetWebContents() { + } + + void EmulationHandler::UpdateTouchEventEmulationState() { +- DCHECK(host_); ++ if (!host_) ++ return; ++ + // We only have a single TouchEmulator for all frames, so let the main frame's + // EmulationHandler enable/disable it. + DCHECK(!host_->GetParentOrOuterDocument()); +@@ -608,7 +610,9 @@ void EmulationHandler::UpdateTouchEventEmulationState() { + } + + void EmulationHandler::UpdateDeviceEmulationState() { +- DCHECK(host_); ++ if (!host_) ++ return; ++ + // Device emulation only happens on the outermost main frame. + DCHECK(!host_->GetParentOrOuterDocument()); + diff --git a/patches/chromium/fix_the_gn_gen_for_components_segmentation_platform.patch b/patches/chromium/fix_the_gn_gen_for_components_segmentation_platform.patch new file mode 100644 index 0000000000000..be71fd0151a97 --- /dev/null +++ b/patches/chromium/fix_the_gn_gen_for_components_segmentation_platform.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Adam Kallai +Date: Mon, 22 Aug 2022 20:35:17 +0000 +Subject: Fix the gn gen for components/segmentation_platform + +'optimization_guide_segmentation_handler' dependency only available if +the 'build_with_tflite_lib' condition is set. + +Change-Id: I4d13e1f17caaaa744b3c95e425466cf851edf613 + +Bug: 1355185 +Change-Id: I4d13e1f17caaaa744b3c95e425466cf851edf613 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3845194 +Reviewed-by: Siddhartha S +Commit-Queue: Siddhartha S +Cr-Commit-Position: refs/heads/main@{#1037919} +(cherry picked from commit 9352250ae5e5589a7484873d7efe66d708ba6ad6) + +diff --git a/components/segmentation_platform/embedder/BUILD.gn b/components/segmentation_platform/embedder/BUILD.gn +index 385ab7e469f4e0c02500295edc7f24cedaf0ac6b..9bbac1528bcf0c7c1589c4962bee0ff9c5febaf7 100644 +--- a/components/segmentation_platform/embedder/BUILD.gn ++++ b/components/segmentation_platform/embedder/BUILD.gn +@@ -2,6 +2,8 @@ + # Use of this source code is governed by a BSD-style license that can be + # found in the LICENSE file. + ++import("//components/optimization_guide/features.gni") ++ + if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +@@ -21,11 +23,14 @@ source_set("embedder") { + "//components/optimization_guide/core", + "//components/optimization_guide/core:features", + "//components/segmentation_platform/internal", +- "//components/segmentation_platform/internal:optimization_guide_segmentation_handler", + "//components/segmentation_platform/internal/proto", + "//components/segmentation_platform/public", + "//url", + ] ++ ++ if (build_with_tflite_lib) { ++ deps += [ "//components/segmentation_platform/internal:optimization_guide_segmentation_handler" ] ++ } + } + + source_set("unit_tests") { diff --git a/patches/chromium/fix_use_electron_generated_resources.patch b/patches/chromium/fix_use_electron_generated_resources.patch deleted file mode 100644 index 60b0f49524594..0000000000000 --- a/patches/chromium/fix_use_electron_generated_resources.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Thu, 24 Sep 2020 11:10:41 -0700 -Subject: fix: use electron generated resources - -This patch fixes a few instances where we need to use Electron generated -resources for IDS strings, or the IDs will be wrong and cause DCHECKS -as they will loaded as empty strings. - -* IDS_UTILITY_PROCESS_UTILITY_WIN_NAME on Windows -* IDR_PDF_MANIFEST on Linux -* IDS_UTILITY_PROCESS_PRINTING_SERVICE_NAME on Windows - -diff --git a/chrome/browser/pdf/pdf_extension_util.cc b/chrome/browser/pdf/pdf_extension_util.cc -index f72431f5bc7ba82316cf318f7845e7523c366d92..5133f3cd28c0d630a039118eb91c6c37ee202f3e 100644 ---- a/chrome/browser/pdf/pdf_extension_util.cc -+++ b/chrome/browser/pdf/pdf_extension_util.cc -@@ -11,8 +11,7 @@ - #include "build/chromeos_buildflags.h" - #include "chrome/browser/browser_process.h" - #include "chrome/common/chrome_content_client.h" --#include "chrome/grit/browser_resources.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "components/strings/grit/components_strings.h" - #include "components/zoom/page_zoom_constants.h" - #include "pdf/pdf_features.h" -diff --git a/chrome/browser/printing/printing_service.cc b/chrome/browser/printing/printing_service.cc -index 6d18517898c11c6a628cec2eade57fe845827b3d..a21f52e8a3c6f80d69b27faae4b77700fdd09e35 100644 ---- a/chrome/browser/printing/printing_service.cc -+++ b/chrome/browser/printing/printing_service.cc -@@ -5,7 +5,7 @@ - #include "chrome/browser/printing/printing_service.h" - - #include "base/no_destructor.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "chrome/services/printing/public/mojom/printing_service.mojom.h" - #include "content/public/browser/service_process_host.h" - -diff --git a/chrome/browser/win/icon_reader_service.cc b/chrome/browser/win/icon_reader_service.cc -index d5497a7e26cdb66c7c074bc509e2bfec7d7875cd..62d2f555253eef903bd04ff1a0ad37d1470309e0 100644 ---- a/chrome/browser/win/icon_reader_service.cc -+++ b/chrome/browser/win/icon_reader_service.cc -@@ -4,7 +4,7 @@ - - #include "chrome/browser/win/icon_reader_service.h" - --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "chrome/services/util_win/public/mojom/util_read_icon.mojom.h" - #include "content/public/browser/service_process_host.h" - diff --git a/patches/chromium/frame_host_manager.patch b/patches/chromium/frame_host_manager.patch index 69ce8ecb1ad81..27a1fc982be1a 100644 --- a/patches/chromium/frame_host_manager.patch +++ b/patches/chromium/frame_host_manager.patch @@ -6,10 +6,10 @@ Subject: frame_host_manager.patch Allows embedder to intercept site instances created by chromium. diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc -index 988290f88894157458641d2d201a060820813358..e19b30fc7a88c981d0dad3ed739f3219980b5aeb 100644 +index 569297aab0b4187afde801643957949216404082..a1e332ae2bcf2027019261e38bb82c8446e014d1 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc -@@ -3089,6 +3089,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest( +@@ -3270,6 +3270,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest( request->ResetStateForSiteInstanceChange(); } @@ -20,10 +20,10 @@ index 988290f88894157458641d2d201a060820813358..e19b30fc7a88c981d0dad3ed739f3219 } diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h -index ceb2bb900e122840505aa8d3911923cffc9a907e..c135db6a148e1d1b4af8d5a1d6a80e11ad99d9fe 100644 +index 7eb47e0c73c7f0d8a0cadcf5b8163f8a5154faea..a699439c45bcfce66b697e2a97e6d1ae408cd343 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h -@@ -276,6 +276,11 @@ class CONTENT_EXPORT ContentBrowserClient { +@@ -271,6 +271,11 @@ class CONTENT_EXPORT ContentBrowserClient { virtual ~ContentBrowserClient() = default; diff --git a/patches/chromium/gin_enable_disable_v8_platform.patch b/patches/chromium/gin_enable_disable_v8_platform.patch index 5043b8a49a854..e2c389870ebf4 100644 --- a/patches/chromium/gin_enable_disable_v8_platform.patch +++ b/patches/chromium/gin_enable_disable_v8_platform.patch @@ -7,67 +7,70 @@ We don't use gin to create the V8 platform, because we need to inject Node things. diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc -index 00190da513499e6275d19bd99b6502db246cd33d..f273749bd026abb287ba33e03208a286e80a57a1 100644 +index 88f9e4dd05d8efdabbbdd044f5e09e844ced3d55..c254b045494936eca14ce947e1c2de3327820aa2 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc -@@ -121,9 +121,10 @@ IsolateHolder::~IsolateHolder() { - void IsolateHolder::Initialize(ScriptMode mode, - v8::ArrayBuffer::Allocator* allocator, +@@ -137,9 +137,10 @@ void IsolateHolder::Initialize(ScriptMode mode, const intptr_t* reference_table, -- const std::string js_command_line_flags) { -+ const std::string js_command_line_flags, + const std::string js_command_line_flags, + v8::FatalErrorCallback fatal_error_callback, +- v8::OOMErrorCallback oom_error_callback) { ++ v8::OOMErrorCallback oom_error_callback, + bool create_v8_platform) { CHECK(allocator); -- V8Initializer::Initialize(mode, js_command_line_flags); -+ V8Initializer::Initialize(mode, js_command_line_flags, create_v8_platform); +- V8Initializer::Initialize(mode, js_command_line_flags, oom_error_callback); ++ V8Initializer::Initialize(mode, js_command_line_flags, oom_error_callback, create_v8_platform); g_array_buffer_allocator = allocator; g_reference_table = reference_table; - } + g_fatal_error_callback = fatal_error_callback; diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h -index 1e36669dfb275b8a7c4913c8465bd299c548ed3a..178023d52c9e8ef716ee215e7a243b1800357818 100644 +index d7739924bc3c3daec848db52730bd60c72ff2d8a..78af701cb06f6cb1bdd9829b2fcc46c8d63f5c4f 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h -@@ -102,7 +102,8 @@ class GIN_EXPORT IsolateHolder { - static void Initialize(ScriptMode mode, - v8::ArrayBuffer::Allocator* allocator, +@@ -109,7 +109,8 @@ class GIN_EXPORT IsolateHolder { const intptr_t* reference_table = nullptr, -- const std::string js_command_line_flags = {}); -+ const std::string js_command_line_flags = {}, + const std::string js_command_line_flags = {}, + v8::FatalErrorCallback fatal_error_callback = nullptr, +- v8::OOMErrorCallback oom_error_callback = nullptr); ++ v8::OOMErrorCallback oom_error_callback = nullptr, + bool create_v8_platform = true); // Returns whether `Initialize` has already been invoked in the process. // Initialization is a one-way operation (i.e., this method cannot return diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc -index f411bbde031d18bd3e0322ce154ccfd8eace930d..5db96b7402de70d1b4eba8b12a51fbc89fcb7fb6 100644 +index cb3302bb2abb735609436bdf2a5d4d51cc4258ad..5530d975303cc96701e4b70ffbcaf6e7c02bb016 100644 --- a/gin/v8_initializer.cc +++ b/gin/v8_initializer.cc -@@ -342,12 +342,14 @@ void SetFlags(IsolateHolder::ScriptMode mode, - +@@ -368,7 +368,8 @@ void SetFlags(IsolateHolder::ScriptMode mode, // static void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, -- const std::string js_command_line_flags) { -+ const std::string js_command_line_flags, + const std::string js_command_line_flags, +- v8::OOMErrorCallback oom_error_callback) { ++ v8::OOMErrorCallback oom_error_callback, + bool create_v8_platform) { static bool v8_is_initialized = false; if (v8_is_initialized) return; +@@ -378,7 +379,8 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, + // See https://crbug.com/v8/11043 + SetFlags(mode, js_command_line_flags); - v8::V8::InitializePlatform(V8Platform::Get()); + if (create_v8_platform) + v8::V8::InitializePlatform(V8Platform::Get()); - // Set this early on as some initialization steps, such as the initialization - // of the virtual memory cage, already use V8's random number generator. + // Set this as early as possible in order to ensure OOM errors are reported + // correctly. diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h -index beeedc5737f6e60dde123200fbb6430a40366577..17ee4c894e89b7d2d12377475a5dd01910b61312 100644 +index da5b4017b4a8128bf620d4b43d4c2d183719265b..13a120c7fe8e69a44793473f3124c33d572a07a3 100644 --- a/gin/v8_initializer.h +++ b/gin/v8_initializer.h -@@ -29,7 +29,8 @@ class GIN_EXPORT V8Initializer { - public: +@@ -31,7 +31,8 @@ class GIN_EXPORT V8Initializer { // This should be called by IsolateHolder::Initialize(). static void Initialize(IsolateHolder::ScriptMode mode, -- const std::string js_command_line_flags = {}); -+ const std::string js_command_line_flags = {}, + const std::string js_command_line_flags = {}, +- v8::OOMErrorCallback oom_error_callback = nullptr); ++ v8::OOMErrorCallback oom_error_callback = nullptr, + bool create_v8_platform = true); // Get address and size information for currently loaded snapshot. diff --git a/patches/chromium/gpu_notify_when_dxdiag_request_fails.patch b/patches/chromium/gpu_notify_when_dxdiag_request_fails.patch index 385502d7e9df0..4f42b1699b1a1 100644 --- a/patches/chromium/gpu_notify_when_dxdiag_request_fails.patch +++ b/patches/chromium/gpu_notify_when_dxdiag_request_fails.patch @@ -12,7 +12,7 @@ rendering and there is no signal from browser process on this event to identify it. diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc -index b26a3c72aa63b81f8f4558b28b404faf138a897b..335dc385eb03bc9634387af44dfd1aa3bfa71cb6 100644 +index 54cc8dc51d400a5738c7e3d63e6f368bead2a021..182ef4fde23a6afe2e9d8a8f02d8ccf6161c633e 100644 --- a/content/browser/gpu/gpu_data_manager_impl.cc +++ b/content/browser/gpu/gpu_data_manager_impl.cc @@ -230,6 +230,11 @@ void GpuDataManagerImpl::TerminateInfoCollectionGpuProcess() { @@ -28,10 +28,10 @@ index b26a3c72aa63b81f8f4558b28b404faf138a897b..335dc385eb03bc9634387af44dfd1aa3 void GpuDataManagerImpl::UpdateDawnInfo( diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h -index 4364da656ac02f2f717e713f37d29ce44c14242b..ba044aee23db495e1da69c5bc0a807e96783faa9 100644 +index 1fc56c055d423ab074f8f4f90415e34593a04a18..c637247f003e1c6bfe073a43a09851682cd242cc 100644 --- a/content/browser/gpu/gpu_data_manager_impl.h +++ b/content/browser/gpu/gpu_data_manager_impl.h -@@ -124,6 +124,7 @@ class CONTENT_EXPORT GpuDataManagerImpl : public GpuDataManager, +@@ -125,6 +125,7 @@ class CONTENT_EXPORT GpuDataManagerImpl : public GpuDataManager, // BrowserMainParts override instead. void PostCreateThreads(); void TerminateInfoCollectionGpuProcess(); @@ -40,10 +40,10 @@ index 4364da656ac02f2f717e713f37d29ce44c14242b..ba044aee23db495e1da69c5bc0a807e9 void UpdateDawnInfo(const std::vector& dawn_info_list); diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc -index 972bb4e8ba2d1470ed5f24c125551e3e627d79e4..d3b15d35eb458c00e470569904924c28c7a3957d 100644 +index 526b9768da187b0f7d94b3500a63af8242d568af..01faafb23559dd13f5a770c1dd3864a2ea858321 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.cc +++ b/content/browser/gpu/gpu_data_manager_impl_private.cc -@@ -1211,6 +1211,12 @@ void GpuDataManagerImplPrivate::TerminateInfoCollectionGpuProcess() { +@@ -1199,6 +1199,12 @@ void GpuDataManagerImplPrivate::TerminateInfoCollectionGpuProcess() { if (host) host->ForceShutdown(); } @@ -57,10 +57,10 @@ index 972bb4e8ba2d1470ed5f24c125551e3e627d79e4..d3b15d35eb458c00e470569904924c28 void GpuDataManagerImplPrivate::UpdateDawnInfo( diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h -index 81f6abb91a3fdefc1b0128f3224c7b82bfcbd0d2..99980e3528f4660bf1205e44326645d97e762cb9 100644 +index af6dd8d8af99c5bd1e854c8cfbeb89e04476fefd..758adb66dff5aefad9f3c9f8c23de6fa9df33ef7 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.h +++ b/content/browser/gpu/gpu_data_manager_impl_private.h -@@ -89,6 +89,7 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate { +@@ -87,6 +87,7 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate { bool VulkanRequested() const; void PostCreateThreads(); void TerminateInfoCollectionGpuProcess(); diff --git a/patches/chromium/gritsettings_resource_ids.patch b/patches/chromium/gritsettings_resource_ids.patch index e595534ffa59e..5b11d2d911004 100644 --- a/patches/chromium/gritsettings_resource_ids.patch +++ b/patches/chromium/gritsettings_resource_ids.patch @@ -6,10 +6,10 @@ Subject: gritsettings_resource_ids.patch Add electron resources file to the list of resource ids generation. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec -index 77f77f2deb13fc1c02903fc436028cce2d051cf0..25223130a82b22ad46eddf7e133c6085c5c843d3 100644 +index d9ae17943b8fcfaa6026869328e60c8cc4057425..7d97829b1a0d2589607eb696bdde1fa72cc09424 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec -@@ -952,6 +952,11 @@ +@@ -984,6 +984,11 @@ "includes": [4960], }, diff --git a/patches/chromium/gtk_visibility.patch b/patches/chromium/gtk_visibility.patch index 52f3cc0d8a50e..20894a2cf14e9 100644 --- a/patches/chromium/gtk_visibility.patch +++ b/patches/chromium/gtk_visibility.patch @@ -18,7 +18,7 @@ index 349043f8a3cfc9f91cbae951e74258799a4fd126..0f7e3e544f524a7ad6660b54912cb119 # on GTK. "//examples:peerconnection_client", diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn -index dd65850ec1352b764a9661b37e7c7b5e7d256016..89094825f858dcd91298dbaf26b370ca57eb4836 100644 +index 34126e87bb62c312230e4a0c479f49736fa20e35..7320904ca819b6f6616192dd9f04f02ead2430a8 100644 --- a/ui/ozone/platform/x11/BUILD.gn +++ b/ui/ozone/platform/x11/BUILD.gn @@ -6,7 +6,7 @@ import("//build/config/chromeos/ui_mode.gni") diff --git a/patches/chromium/hack_plugin_response_interceptor_to_point_to_electron.patch b/patches/chromium/hack_plugin_response_interceptor_to_point_to_electron.patch index 2b0621f918e82..392a9b6b9be46 100644 --- a/patches/chromium/hack_plugin_response_interceptor_to_point_to_electron.patch +++ b/patches/chromium/hack_plugin_response_interceptor_to_point_to_electron.patch @@ -8,7 +8,7 @@ require a largeish patch to get working, so just redirect it to our implementation instead. diff --git a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc -index b5c0e1c131351a51e3c03918dfc10e92ca1bace1..c6fe2e473a9d8a5ed2854a69909eb360d052147a 100644 +index 570359f62ce2ae59f2fe24cd56edf7e222b3d0bd..1d1fa2e2222435c88448b2577bbbd9c697196394 100644 --- a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc +++ b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc @@ -10,8 +10,8 @@ diff --git a/patches/chromium/hack_to_allow_gclient_sync_with_host_os_mac_on_linux_in_ci.patch b/patches/chromium/hack_to_allow_gclient_sync_with_host_os_mac_on_linux_in_ci.patch index b3fda53f56fc1..89ec97f2f2949 100644 --- a/patches/chromium/hack_to_allow_gclient_sync_with_host_os_mac_on_linux_in_ci.patch +++ b/patches/chromium/hack_to_allow_gclient_sync_with_host_os_mac_on_linux_in_ci.patch @@ -11,10 +11,10 @@ If removing this patch causes no sync failures, it's safe to delete :+1: Ref https://chromium-review.googlesource.com/c/chromium/src/+/2953903 diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py -index 0fb53bbaf4174594b46ecba6d4d28f7436ef9a72..9951fc52f06be5199b93d29d18a1b5582299f334 100755 +index c8703580d32010666d81fc28ea7325ef0b292fec..a8c9e3af875586d041d58d6d70b5b81092139eed 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py -@@ -298,6 +298,8 @@ def GetDefaultHostOs(): +@@ -307,6 +307,8 @@ def GetDefaultHostOs(): 'win32': 'win', } default_host_os = _PLATFORM_HOST_OS_MAP.get(sys.platform, sys.platform) diff --git a/patches/chromium/introduce_ozoneplatform_electron_can_call_x11_property.patch b/patches/chromium/introduce_ozoneplatform_electron_can_call_x11_property.patch index f879002345cc1..963907108c66e 100644 --- a/patches/chromium/introduce_ozoneplatform_electron_can_call_x11_property.patch +++ b/patches/chromium/introduce_ozoneplatform_electron_can_call_x11_property.patch @@ -9,10 +9,10 @@ at rutime. It would be best if eventually all usages of this property were replaced with clean ozone native implementations. diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc -index 9008af973427d7dab8170449bc5767cebc9d2e9e..e312287e4aca61b51a69c8413088f56f9f704b5e 100644 +index f7fe443469c54e6cf76c2eb7f00c94d245515e59..d2dac184b3bfa69e142c106ec91f94d5c5e38d5a 100644 --- a/ui/ozone/platform/x11/ozone_platform_x11.cc +++ b/ui/ozone/platform/x11/ozone_platform_x11.cc -@@ -200,6 +200,7 @@ class OzonePlatformX11 : public OzonePlatform, +@@ -192,6 +192,7 @@ class OzonePlatformX11 : public OzonePlatform, properties->supports_vulkan_swap_chain = true; properties->uses_external_vulkan_image_factory = true; properties->skia_can_fall_back_to_x11 = true; @@ -21,10 +21,10 @@ index 9008af973427d7dab8170449bc5767cebc9d2e9e..e312287e4aca61b51a69c8413088f56f properties->supports_global_application_menus = true; properties->app_modal_dialogs_use_event_blocker = true; diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h -index 22ba32317a74df24249d1528dcaaa28ff18bd0f4..fa57f97520a0327be2c7f5179591ca61b801c8b0 100644 +index 193224d33283d4d3c45dc11b9620700a3a379cce..81abd63261952f0930a4659f270791d27d9d74a3 100644 --- a/ui/ozone/public/ozone_platform.h +++ b/ui/ozone/public/ozone_platform.h -@@ -132,6 +132,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform { +@@ -129,6 +129,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform { // Linux only: determines if Skia can fall back to the X11 output device. bool skia_can_fall_back_to_x11 = false; diff --git a/patches/chromium/isolate_holder.patch b/patches/chromium/isolate_holder.patch index bcf1ff58add19..4d79064e76138 100644 --- a/patches/chromium/isolate_holder.patch +++ b/patches/chromium/isolate_holder.patch @@ -15,38 +15,65 @@ for us to register the isolate in between Isolate::Allocate and Isolate::Initialize. diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc -index f273749bd026abb287ba33e03208a286e80a57a1..0159cd61a8e95d6cca51cdc855f1dea3ec965d6b 100644 +index c254b045494936eca14ce947e1c2de3327820aa2..63c9b9681fcc4e1e9a9590d59d74349bb8aee3b1 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc -@@ -59,7 +59,8 @@ IsolateHolder::IsolateHolder( +@@ -73,7 +73,8 @@ IsolateHolder::IsolateHolder( + IsolateType isolate_type, + IsolateCreationMode isolate_creation_mode, v8::CreateHistogramCallback create_histogram_callback, - v8::AddHistogramSampleCallback add_histogram_sample_callback, - v8::FatalErrorCallback fatal_error_callback, -- v8::OOMErrorCallback oom_error_callback) -+ v8::OOMErrorCallback oom_error_callback, +- v8::AddHistogramSampleCallback add_histogram_sample_callback) ++ v8::AddHistogramSampleCallback add_histogram_sample_callback, ++ v8::Isolate* isolate) + : IsolateHolder(task_runner, + access_mode, + isolate_type, +@@ -81,14 +82,16 @@ IsolateHolder::IsolateHolder( + atomics_wait_mode, + create_histogram_callback, + add_histogram_sample_callback), +- isolate_creation_mode) {} ++ isolate_creation_mode, ++ isolate) {} + + IsolateHolder::IsolateHolder( + scoped_refptr task_runner, + AccessMode access_mode, + IsolateType isolate_type, + std::unique_ptr params, +- IsolateCreationMode isolate_creation_mode) ++ IsolateCreationMode isolate_creation_mode, + v8::Isolate* isolate) : access_mode_(access_mode), isolate_type_(isolate_type) { CHECK(Initialized()) << "You need to invoke gin::IsolateHolder::Initialize first"; -@@ -70,7 +71,7 @@ IsolateHolder::IsolateHolder( - v8::ArrayBuffer::Allocator* allocator = g_array_buffer_allocator; +@@ -99,7 +102,7 @@ IsolateHolder::IsolateHolder( + v8::ArrayBuffer::Allocator* allocator = params->array_buffer_allocator; DCHECK(allocator); - isolate_ = v8::Isolate::Allocate(); + isolate_ = isolate ? isolate : v8::Isolate::Allocate(); isolate_data_ = std::make_unique(isolate_, allocator, access_mode_, task_runner); - if (isolate_creation_mode == IsolateCreationMode::kCreateSnapshot) { + // TODO(https://crbug.com/1347092): Refactor such that caller need not diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h -index 178023d52c9e8ef716ee215e7a243b1800357818..979fdc27efbe69c276894e0dc82e53ac2c4db7b4 100644 +index 78af701cb06f6cb1bdd9829b2fcc46c8d63f5c4f..4a36f4826f9df765c664a819eb4e3679fbecb104 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h -@@ -84,7 +84,8 @@ class GIN_EXPORT IsolateHolder { +@@ -83,13 +83,15 @@ class GIN_EXPORT IsolateHolder { + IsolateType isolate_type, + IsolateCreationMode isolate_creation_mode = IsolateCreationMode::kNormal, v8::CreateHistogramCallback create_histogram_callback = nullptr, - v8::AddHistogramSampleCallback add_histogram_sample_callback = nullptr, - v8::FatalErrorCallback fatal_error_callback = nullptr, -- v8::OOMErrorCallback oom_error_callback = nullptr); -+ v8::OOMErrorCallback oom_error_callback = nullptr, +- v8::AddHistogramSampleCallback add_histogram_sample_callback = nullptr); ++ v8::AddHistogramSampleCallback add_histogram_sample_callback = nullptr, ++ v8::Isolate* isolate = nullptr); + IsolateHolder( + scoped_refptr task_runner, + AccessMode access_mode, + IsolateType isolate_type, + std::unique_ptr params, +- IsolateCreationMode isolate_creation_mode = IsolateCreationMode::kNormal); ++ IsolateCreationMode isolate_creation_mode = IsolateCreationMode::kNormal, + v8::Isolate* isolate = nullptr); IsolateHolder(const IsolateHolder&) = delete; IsolateHolder& operator=(const IsolateHolder&) = delete; diff --git a/patches/chromium/load_v8_snapshot_in_browser_process.patch b/patches/chromium/load_v8_snapshot_in_browser_process.patch index b960942083b87..5fb0d549c8417 100644 --- a/patches/chromium/load_v8_snapshot_in_browser_process.patch +++ b/patches/chromium/load_v8_snapshot_in_browser_process.patch @@ -9,10 +9,10 @@ but due to the nature of electron, we need to load the v8 snapshot in the browser process. diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc -index 9d22238878e3204dd1d866d2bb085d5311dca36a..e3610815fd942e631a61089ca5eeba07edd7213c 100644 +index fb4af331fb38b9e431137fd2b3806be84175acbf..14ca983c91cfe495ebd2859866a7f434d0a9ab02 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc -@@ -249,11 +249,8 @@ void LoadV8SnapshotFile(const base::CommandLine& command_line) { +@@ -253,11 +253,8 @@ void LoadV8SnapshotFile(const base::CommandLine& command_line) { bool ShouldLoadV8Snapshot(const base::CommandLine& command_line, const std::string& process_type) { diff --git a/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch b/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch index 6cf5df78a02c3..81ba08c541044 100644 --- a/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch +++ b/patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch @@ -9,10 +9,10 @@ be created for each child process, despite logs being redirected to a file. diff --git a/content/app/content_main.cc b/content/app/content_main.cc -index 332b7d026e0365a66d5f4f275a90b48d0f2db5aa..3813fe1a3b2e95af5e213201ab3ea08a656e01c3 100644 +index 34cbeddf6cabd78806304e45e25074d5d2ccd51e..db66cfa6313e805e91d9dbb189ae10b02792a112 100644 --- a/content/app/content_main.cc +++ b/content/app/content_main.cc -@@ -381,8 +381,12 @@ RunContentProcess(ContentMainParams params, +@@ -413,8 +413,12 @@ RunContentProcess(ContentMainParams params, #if BUILDFLAG(IS_WIN) // Route stdio to parent console (if any) or create one. diff --git a/patches/chromium/make_gtk_getlibgtk_public.patch b/patches/chromium/make_gtk_getlibgtk_public.patch index bf195bbaba7d3..cb65b28e8d8c0 100644 --- a/patches/chromium/make_gtk_getlibgtk_public.patch +++ b/patches/chromium/make_gtk_getlibgtk_public.patch @@ -1,16 +1,28 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Thu, 7 Apr 2022 20:30:16 +0900 -Subject: Make gtk::GetLibGtk public +Subject: Make gtk::GetLibGtk and gtk::GetLibGdkPixbuf public -Allows embedders to get a handle to the gtk library -already loaded in the process. +Allows embedders to get a handle to the gtk and +gdk_pixbuf libraries already loaded in the process. diff --git a/ui/gtk/gtk_compat.cc b/ui/gtk/gtk_compat.cc -index 7104a0d5f4489c687f3cb9e63bc7cbef59d2fa62..f0b9ed834a3f7310da09377f0b2105cf635ffeb7 100644 +index 2ba5b4c4468fca1bf76011754e358c81f670a8d3..e831abb6d14be75b3f5e5b4b3455b8b136f921b1 100644 --- a/ui/gtk/gtk_compat.cc +++ b/ui/gtk/gtk_compat.cc -@@ -86,12 +86,6 @@ void* GetLibGtk4(bool check = true) { +@@ -66,11 +66,6 @@ void* GetLibGio() { + return libgio; + } + +-void* GetLibGdkPixbuf() { +- static void* libgdk_pixbuf = DlOpen("libgdk_pixbuf-2.0.so.0"); +- return libgdk_pixbuf; +-} +- + void* GetLibGdk3() { + static void* libgdk3 = DlOpen("libgdk-3.so.0"); + return libgdk3; +@@ -86,12 +81,6 @@ void* GetLibGtk4(bool check = true) { return libgtk4; } @@ -23,10 +35,15 @@ index 7104a0d5f4489c687f3cb9e63bc7cbef59d2fa62..f0b9ed834a3f7310da09377f0b2105cf bool LoadGtk3() { if (!GetLibGtk3(false)) return false; -@@ -133,6 +127,12 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) { +@@ -134,6 +123,17 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) { } // namespace ++void* GetLibGdkPixbuf() { ++ static void* libgdk_pixbuf = DlOpen("libgdk_pixbuf-2.0.so.0"); ++ return libgdk_pixbuf; ++} ++ +void* GetLibGtk() { + if (GtkCheckVersion(4)) + return GetLibGtk4(); @@ -37,13 +54,16 @@ index 7104a0d5f4489c687f3cb9e63bc7cbef59d2fa62..f0b9ed834a3f7310da09377f0b2105cf static bool loaded = LoadGtkImpl(); return loaded; diff --git a/ui/gtk/gtk_compat.h b/ui/gtk/gtk_compat.h -index 72981270fe26579211afcaf3c596a412f69f5fac..b5dbfde5b011d57d26960d245e0dc61cac9341e4 100644 +index 57e55b9e749b43d327deff449a530e1f435a8e8b..37720be9e393d192b3b7db13a007431a9ce77ddc 100644 --- a/ui/gtk/gtk_compat.h +++ b/ui/gtk/gtk_compat.h -@@ -37,6 +37,9 @@ using SkColor = uint32_t; +@@ -34,6 +34,12 @@ using SkColor = uint32_t; namespace gtk { ++// Get handle to the currently loaded gdk_pixbuf library in the process. ++void* GetLibGdkPixbuf(); ++ +// Get handle to the currently loaded gtk library in the process. +void* GetLibGtk(); + diff --git a/patches/chromium/mas-audiodeviceduck.patch b/patches/chromium/mas-audiodeviceduck.patch deleted file mode 100644 index 765e3e06f0711..0000000000000 --- a/patches/chromium/mas-audiodeviceduck.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeremy Apthorp -Date: Thu, 20 Sep 2018 17:49:31 -0700 -Subject: mas: avoid usage of AudioDeviceDuck - -Removes usage of the AudioDeviceDuck private API. - -diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc -index e28d37435da00153e34132f49ce8f6b240e70a65..77ce459d969022b7c5a4d1e57bb1f7e6fa7a9898 100644 ---- a/media/audio/mac/audio_low_latency_input_mac.cc -+++ b/media/audio/mac/audio_low_latency_input_mac.cc -@@ -34,19 +34,23 @@ - - namespace { - extern "C" { -+#ifndef MAS_BUILD - // See: - // https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/PAL/pal/spi/cf/CoreAudioSPI.h?rev=228264 - OSStatus AudioDeviceDuck(AudioDeviceID inDevice, - Float32 inDuckedLevel, - const AudioTimeStamp* __nullable inStartTime, - Float32 inRampDuration) __attribute__((weak_import)); -+#endif - } - - void UndoDucking(AudioDeviceID output_device_id) { -+#ifndef MAS_BUILD - if (AudioDeviceDuck != nullptr) { - // Ramp the volume back up over half a second. - AudioDeviceDuck(output_device_id, 1.0, nullptr, 0.5); - } -+#endif - } - - } // namespace diff --git a/patches/chromium/mas-cfisobjc.patch b/patches/chromium/mas-cfisobjc.patch deleted file mode 100644 index 88035201b5109..0000000000000 --- a/patches/chromium/mas-cfisobjc.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeremy Apthorp -Date: Thu, 20 Sep 2018 17:49:20 -0700 -Subject: mas: avoid usage of _CFIsObjC - -Removes usage of the _CFIsObjC private API. - -diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm -index bd26c088c2340f0c88227837fc797b1ed8157768..6e133c11acb7ea2570e6295b0788edc1606afbc2 100644 ---- a/base/mac/foundation_util.mm -+++ b/base/mac/foundation_util.mm -@@ -31,12 +31,6 @@ - #if !BUILDFLAG(IS_IOS) - CFTypeID SecACLGetTypeID(); - CFTypeID SecTrustedApplicationGetTypeID(); --// The NSFont/CTFont toll-free bridging is broken before 10.15. --// http://www.openradar.me/15341349 rdar://15341349 --// --// TODO(https://crbug.com/1076527): This is fixed in 10.15. When 10.15 is the --// minimum OS for Chromium, remove this SPI declaration. --Boolean _CFIsObjC(CFTypeID typeID, CFTypeRef obj); - #endif - } // extern "C" - -@@ -317,8 +311,7 @@ void SetBaseBundleID(const char* new_base_bundle_id) { - const_cast(reinterpret_cast(cf_val)); - DCHECK(!cf_val || - CTFontGetTypeID() == CFGetTypeID(cf_val) || -- (_CFIsObjC(CTFontGetTypeID(), cf_val) && -- [ns_val isKindOfClass:[NSFont class]])); -+ ([ns_val isKindOfClass:[NSFont class]])); - return ns_val; - } - -@@ -389,9 +382,6 @@ CTFontRef NSToCFCast(NSFont* ns_val) { - return (CTFontRef)(cf_val); - } - -- if (!_CFIsObjC(CTFontGetTypeID(), cf_val)) -- return NULL; -- - id ns_val = reinterpret_cast(const_cast(cf_val)); - if ([ns_val isKindOfClass:[NSFont class]]) { - return (CTFontRef)(cf_val); diff --git a/patches/chromium/mas-cgdisplayusesforcetogray.patch b/patches/chromium/mas-cgdisplayusesforcetogray.patch index c55b2981c5830..2408079f26546 100644 --- a/patches/chromium/mas-cgdisplayusesforcetogray.patch +++ b/patches/chromium/mas-cgdisplayusesforcetogray.patch @@ -6,10 +6,10 @@ Subject: mas: avoid usage of CGDisplayUsesForceToGray Removes usage of the CGDisplayUsesForceToGray private API. diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm -index 1fb42e658d219e46bbc157d929d3b2158c063204..cb6dec724dbe511cb0c66d507d0b68db7296b648 100644 +index fc2ac4583bafd1847fd8dfe3fccbdf4eb40bd929..50fb6b583f84623bd8a146d9476cdf7989627d8a 100644 --- a/ui/display/mac/screen_mac.mm +++ b/ui/display/mac/screen_mac.mm -@@ -155,7 +155,17 @@ DisplayMac BuildDisplayForScreen(NSScreen* screen) { +@@ -269,7 +269,17 @@ DisplayMac BuildDisplayForScreen(NSScreen* screen) { display.set_color_depth(Display::kDefaultBitsPerPixel); display.set_depth_per_component(Display::kDefaultBitsPerComponent); } diff --git a/patches/chromium/mas_avoid_usage_of_abort_report_np.patch b/patches/chromium/mas_avoid_usage_of_abort_report_np.patch deleted file mode 100644 index 5c3f9a8b72719..0000000000000 --- a/patches/chromium/mas_avoid_usage_of_abort_report_np.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Attard -Date: Mon, 4 Mar 2019 14:43:36 -0800 -Subject: mas: avoid usage of abort_report_np - -Disable usage of the private API abort_report_np in MAS builds. - -diff --git a/sandbox/mac/sandbox_logging.cc b/sandbox/mac/sandbox_logging.cc -index 702224dce1871c07b07f6882e46d14fe532d6ed2..797cb6646171486797a5e5fbbb1b187e3a9f81d4 100644 ---- a/sandbox/mac/sandbox_logging.cc -+++ b/sandbox/mac/sandbox_logging.cc -@@ -32,9 +32,11 @@ - } - #endif - -+#if !defined(MAS_BUILD) - extern "C" { - void abort_report_np(const char*, ...); - } -+#endif - - namespace sandbox { - -@@ -104,9 +106,11 @@ void SendAslLog(Level level, const char* message) { - asl_set(asl_message.get(), ASL_KEY_MSG, message); - asl_send(asl_client.get(), asl_message.get()); - -+#if !defined(MAS_BUILD) - if (level == Level::FATAL) { - abort_report_np(message); - } -+#endif - } - - // |error| is strerror(errno) when a P* logging function is called. Pass diff --git a/patches/chromium/mas_avoid_usage_of_private_macos_apis.patch b/patches/chromium/mas_avoid_usage_of_private_macos_apis.patch new file mode 100644 index 0000000000000..73fcfcd3ddf79 --- /dev/null +++ b/patches/chromium/mas_avoid_usage_of_private_macos_apis.patch @@ -0,0 +1,240 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Mon, 4 Mar 2019 14:43:36 -0800 +Subject: mas: avoid usage of private macOS APIs + +Disable usage of the following private APIs in MAS builds: +* abort_report_np +* pthread_fchdir_np +* pthread_chdir_np +* SetApplicationIsDaemon +* _LSSetApplicationLaunchServicesServerConnectionStatus +* AreDeviceAndUserJoinedToDomain +* _CFIsObjC +* AudioDeviceDuck + +diff --git a/base/enterprise_util_mac.mm b/base/enterprise_util_mac.mm +index dd14c8cfa32ab0bb2e92f192c54a494c4f5b4fb7..2c6f0b336c97bc23995e9fe8cdc7f72a69f54e64 100644 +--- a/base/enterprise_util_mac.mm ++++ b/base/enterprise_util_mac.mm +@@ -189,6 +189,13 @@ MacDeviceManagementStateNew IsDeviceRegisteredWithManagementNew() { + DeviceUserDomainJoinState AreDeviceAndUserJoinedToDomain() { + static DeviceUserDomainJoinState state = [] { + DeviceUserDomainJoinState state{false, false}; ++#if defined(MAS_BUILD) ++ return state; ++ }(); ++ ++ return state; ++} ++#else + + @autoreleasepool { + ODSession* session = [ODSession defaultSession]; +@@ -295,5 +302,6 @@ DeviceUserDomainJoinState AreDeviceAndUserJoinedToDomain() { + + return state; + } ++#endif + + } // namespace base +diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm +index 1cbc8d582610426c870ac14ee825345805a9639a..1889df911a449e0b2ed80b42d55d747b36f9cf8c 100644 +--- a/base/mac/foundation_util.mm ++++ b/base/mac/foundation_util.mm +@@ -28,12 +28,6 @@ + extern "C" { + CFTypeID SecKeyGetTypeID(); + #if !BUILDFLAG(IS_IOS) +-// The NSFont/CTFont toll-free bridging is broken before 10.15. +-// http://www.openradar.me/15341349 rdar://15341349 +-// +-// TODO(https://crbug.com/1076527): This is fixed in 10.15. When 10.15 is the +-// minimum OS for Chromium, remove this SPI declaration. +-Boolean _CFIsObjC(CFTypeID typeID, CFTypeRef obj); + #endif + } // extern "C" + +@@ -315,8 +309,7 @@ void SetBaseBundleID(const char* new_base_bundle_id) { + const_cast(reinterpret_cast(cf_val)); + DCHECK(!cf_val || + CTFontGetTypeID() == CFGetTypeID(cf_val) || +- (_CFIsObjC(CTFontGetTypeID(), cf_val) && +- [ns_val isKindOfClass:[NSFont class]])); ++ ([ns_val isKindOfClass:[NSFont class]])); + return ns_val; + } + +@@ -387,9 +380,6 @@ CTFontRef NSToCFCast(NSFont* ns_val) { + return (CTFontRef)(cf_val); + } + +- if (!_CFIsObjC(CTFontGetTypeID(), cf_val)) +- return NULL; +- + id ns_val = reinterpret_cast(const_cast(cf_val)); + if ([ns_val isKindOfClass:[NSFont class]]) { + return (CTFontRef)(cf_val); +diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc +index bf33d321197226a74d4f26731108ad8b0b8c72a0..349dc2cdde63e32daf06f1ccc0d29e7ce8b2ac46 100644 +--- a/base/process/launch_mac.cc ++++ b/base/process/launch_mac.cc +@@ -19,14 +19,19 @@ + #include "base/threading/scoped_blocking_call.h" + #include "base/threading/thread_restrictions.h" + #include "base/trace_event/base_tracing.h" ++#if defined(MAS_BUILD) ++#include ++#endif + + extern "C" { + // Changes the current thread's directory to a path or directory file + // descriptor. libpthread only exposes a syscall wrapper starting in + // macOS 10.12, but the system call dates back to macOS 10.5. On older OSes, + // the syscall is issued directly. ++#if !defined(MAS_BUILD) + int pthread_chdir_np(const char* dir) API_AVAILABLE(macosx(10.12)); + int pthread_fchdir_np(int fd) API_AVAILABLE(macosx(10.12)); ++#endif + + int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t attrs, int disclaim) + API_AVAILABLE(macosx(10.14)); +@@ -95,13 +100,27 @@ class PosixSpawnFileActions { + }; + + int ChangeCurrentThreadDirectory(const char* path) { ++#if defined(MAS_BUILD) ++ #pragma clang diagnostic push ++ #pragma clang diagnostic ignored "-Wdeprecated-declarations" ++ return syscall(SYS___pthread_chdir, path); ++ #pragma clang diagnostic pop ++#else + return pthread_chdir_np(path); ++#endif + } + + // The recommended way to unset a per-thread cwd is to set a new value to an + // invalid file descriptor, per libpthread-218.1.3/private/private.h. + int ResetCurrentThreadDirectory() { ++#if defined(MAS_BUILD) ++ #pragma clang diagnostic push ++ #pragma clang diagnostic ignored "-Wdeprecated-declarations" ++ return syscall(SYS___pthread_fchdir, -1); ++ #pragma clang diagnostic pop ++#else + return pthread_fchdir_np(-1); ++#endif + } + + struct GetAppOutputOptions { +@@ -221,11 +240,13 @@ Process LaunchProcess(const std::vector& argv, + file_actions.Inherit(STDERR_FILENO); + } + ++#if 0 + if (options.disclaim_responsibility) { + if (__builtin_available(macOS 10.14, *)) { + DPSXCHECK(responsibility_spawnattrs_setdisclaim(attr.get(), 1)); + } + } ++#endif + + std::vector argv_cstr; + argv_cstr.reserve(argv.size() + 1); +diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc +index de981fa288c19ca46a8172e99bc25df36ff29d50..45e5648826c60f6ba6332776e7579a62165b0e8d 100644 +--- a/media/audio/mac/audio_low_latency_input_mac.cc ++++ b/media/audio/mac/audio_low_latency_input_mac.cc +@@ -34,19 +34,23 @@ + + namespace { + extern "C" { ++#ifndef MAS_BUILD + // See: + // https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/PAL/pal/spi/cf/CoreAudioSPI.h?rev=228264 + OSStatus AudioDeviceDuck(AudioDeviceID inDevice, + Float32 inDuckedLevel, + const AudioTimeStamp* __nullable inStartTime, + Float32 inRampDuration) __attribute__((weak_import)); ++#endif + } + + void UndoDucking(AudioDeviceID output_device_id) { ++#ifndef MAS_BUILD + if (AudioDeviceDuck != nullptr) { + // Ramp the volume back up over half a second. + AudioDeviceDuck(output_device_id, 1.0, nullptr, 0.5); + } ++#endif + } + + } // namespace +diff --git a/sandbox/mac/sandbox_logging.cc b/sandbox/mac/sandbox_logging.cc +index f071b192208fdfb1b9da932fcbbf64f0712d8f8b..7481ec29aaaa7b9f40af4a1180dd779e60131ea5 100644 +--- a/sandbox/mac/sandbox_logging.cc ++++ b/sandbox/mac/sandbox_logging.cc +@@ -32,9 +32,11 @@ + } + #endif + ++#if !defined(MAS_BUILD) + extern "C" { + void abort_report_np(const char*, ...); + } ++#endif + + namespace sandbox::logging { + +@@ -71,9 +73,11 @@ void SendOsLog(Level level, const char* message) { + + os_log_with_type(log.get(), os_log_type, "%{public}s", message); + ++#if !defined(MAS_BUILD) + if (level == Level::FATAL) { + abort_report_np(message); + } ++#endif + } + + // |error| is strerror(errno) when a P* logging function is called. Pass +diff --git a/sandbox/mac/system_services.cc b/sandbox/mac/system_services.cc +index 9f5261425162791668c2d15b7ffba091f831d652..c37f3dc05cb8372c7a6c4caef7a280b6f2f48e98 100644 +--- a/sandbox/mac/system_services.cc ++++ b/sandbox/mac/system_services.cc +@@ -9,6 +9,7 @@ + + #include "base/mac/mac_logging.h" + ++#if !defined(MAS_BUILD) + extern "C" { + OSStatus SetApplicationIsDaemon(Boolean isDaemon); + void _LSSetApplicationLaunchServicesServerConnectionStatus( +@@ -19,10 +20,12 @@ void _LSSetApplicationLaunchServicesServerConnectionStatus( + // https://github.com/WebKit/webkit/commit/8da694b0b3febcc262653d01a45e946ce91845ed. + void _CSCheckFixDisable() API_AVAILABLE(macosx(10.15)); + } // extern "C" ++#endif + + namespace sandbox { + + void DisableLaunchServices() { ++ #if !defined(MAS_BUILD) + // Allow the process to continue without a LaunchServices ASN. The + // INIT_Process function in HIServices will abort if it cannot connect to + // launchservicesd to get an ASN. By setting this flag, HIServices skips +@@ -36,12 +39,15 @@ void DisableLaunchServices() { + 0, ^bool(CFDictionaryRef options) { + return false; + }); ++ #endif + } + + void DisableCoreServicesCheckFix() { ++#if !defined(MAS_BUILD) + if (__builtin_available(macOS 10.15, *)) { + _CSCheckFixDisable(); + } ++#endif + } + + } // namespace sandbox diff --git a/patches/chromium/mas_avoid_usage_of_pthread_fchdir_np.patch b/patches/chromium/mas_avoid_usage_of_pthread_fchdir_np.patch deleted file mode 100644 index 5ea6286df620b..0000000000000 --- a/patches/chromium/mas_avoid_usage_of_pthread_fchdir_np.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Attard -Date: Mon, 4 Mar 2019 14:46:48 -0800 -Subject: mas: avoid usage of pthread_fchdir_np - -Disable usage of pthread_fchdir_np and pthread_chdir_np in MAS builds. - -diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc -index 184cfa25dbc6cfa2a32be3f8d964ea359254f807..c9bfc4d8ca1408206244305d7634dcd51e99377c 100644 ---- a/base/process/launch_mac.cc -+++ b/base/process/launch_mac.cc -@@ -26,8 +26,10 @@ extern "C" { - // descriptor. libpthread only exposes a syscall wrapper starting in - // macOS 10.12, but the system call dates back to macOS 10.5. On older OSes, - // the syscall is issued directly. -+#if !defined(MAS_BUILD) - int pthread_chdir_np(const char* dir) API_AVAILABLE(macosx(10.12)); - int pthread_fchdir_np(int fd) API_AVAILABLE(macosx(10.12)); -+#endif - - int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t attrs, int disclaim) - API_AVAILABLE(macosx(10.14)); -@@ -96,21 +98,29 @@ class PosixSpawnFileActions { - }; - - int ChangeCurrentThreadDirectory(const char* path) { -+ #if defined(MAS_BUILD) -+ return syscall(SYS___pthread_chdir, path); -+ #else - if (__builtin_available(macOS 10.12, *)) { - return pthread_chdir_np(path); - } else { - return syscall(SYS___pthread_chdir, path); - } -+ #endif - } - - // The recommended way to unset a per-thread cwd is to set a new value to an - // invalid file descriptor, per libpthread-218.1.3/private/private.h. - int ResetCurrentThreadDirectory() { -+ #if defined(MAS_BUILD) -+ return syscall(SYS___pthread_fchdir, -1); -+ #else - if (__builtin_available(macOS 10.12, *)) { - return pthread_fchdir_np(-1); - } else { - return syscall(SYS___pthread_fchdir, -1); - } -+ #endif - } - - struct GetAppOutputOptions { -@@ -230,11 +240,13 @@ Process LaunchProcess(const std::vector& argv, - file_actions.Inherit(STDERR_FILENO); - } - -+#if 0 - if (options.disclaim_responsibility) { - if (__builtin_available(macOS 10.14, *)) { - DPSXCHECK(responsibility_spawnattrs_setdisclaim(attr.get(), 1)); - } - } -+#endif - - std::vector argv_cstr; - argv_cstr.reserve(argv.size() + 1); diff --git a/patches/chromium/mas_avoid_usage_of_setapplicationisdaemon_and.patch b/patches/chromium/mas_avoid_usage_of_setapplicationisdaemon_and.patch deleted file mode 100644 index a6d15502298b1..0000000000000 --- a/patches/chromium/mas_avoid_usage_of_setapplicationisdaemon_and.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Attard -Date: Mon, 4 Mar 2019 14:51:45 -0800 -Subject: mas: avoid usage of SetApplicationIsDaemon and - _LSSetApplicationLaunchServicesServerConnectionStatus - -Disable usage of SetApplicationIsDaemon and -_LSSetApplicationLaunchServicesServerConnectionStatus in MAS builds - -diff --git a/sandbox/mac/system_services.cc b/sandbox/mac/system_services.cc -index 9f5261425162791668c2d15b7ffba091f831d652..c37f3dc05cb8372c7a6c4caef7a280b6f2f48e98 100644 ---- a/sandbox/mac/system_services.cc -+++ b/sandbox/mac/system_services.cc -@@ -9,6 +9,7 @@ - - #include "base/mac/mac_logging.h" - -+#if !defined(MAS_BUILD) - extern "C" { - OSStatus SetApplicationIsDaemon(Boolean isDaemon); - void _LSSetApplicationLaunchServicesServerConnectionStatus( -@@ -19,10 +20,12 @@ void _LSSetApplicationLaunchServicesServerConnectionStatus( - // https://github.com/WebKit/webkit/commit/8da694b0b3febcc262653d01a45e946ce91845ed. - void _CSCheckFixDisable() API_AVAILABLE(macosx(10.15)); - } // extern "C" -+#endif - - namespace sandbox { - - void DisableLaunchServices() { -+ #if !defined(MAS_BUILD) - // Allow the process to continue without a LaunchServices ASN. The - // INIT_Process function in HIServices will abort if it cannot connect to - // launchservicesd to get an ASN. By setting this flag, HIServices skips -@@ -36,12 +39,15 @@ void DisableLaunchServices() { - 0, ^bool(CFDictionaryRef options) { - return false; - }); -+ #endif - } - - void DisableCoreServicesCheckFix() { -+#if !defined(MAS_BUILD) - if (__builtin_available(macOS 10.15, *)) { - _CSCheckFixDisable(); - } -+#endif - } - - } // namespace sandbox diff --git a/patches/chromium/mas_disable_custom_window_frame.patch b/patches/chromium/mas_disable_custom_window_frame.patch index e64c5fd2f5049..726031eb70315 100644 --- a/patches/chromium/mas_disable_custom_window_frame.patch +++ b/patches/chromium/mas_disable_custom_window_frame.patch @@ -7,7 +7,7 @@ Disable private window frame APIs (NSNextStepFrame and NSThemeFrame) for MAS build. diff --git a/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm b/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm -index cf88f696a46ff0ac84bcf466b44d1080438426c1..7672eee30a811001a0149edfa4eed9dc6a4b11f6 100644 +index 4d8f9f89f03653221fc0b509aa0e15ff20e73574..7bd5094db9b1a8e9af4ecc118fed7b78178e1e58 100644 --- a/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm +++ b/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm @@ -9,6 +9,7 @@ @@ -18,7 +18,7 @@ index cf88f696a46ff0ac84bcf466b44d1080438426c1..7672eee30a811001a0149edfa4eed9dc @interface NSWindow (PrivateBrowserNativeWidgetAPI) + (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle; @end -@@ -63,10 +64,13 @@ - (NSRect)_draggableFrame NS_DEPRECATED_MAC(10_10, 10_11) { +@@ -55,10 +56,13 @@ - (BOOL)_shouldCenterTrafficLights { @end @@ -32,7 +32,7 @@ index cf88f696a46ff0ac84bcf466b44d1080438426c1..7672eee30a811001a0149edfa4eed9dc + (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle { // - NSThemeFrame and its subclasses will be nil if it's missing at runtime. if ([BrowserWindowFrame class]) -@@ -81,6 +85,8 @@ - (BOOL)_usesCustomDrawing { +@@ -73,6 +77,8 @@ - (BOOL)_usesCustomDrawing { return NO; } @@ -75,7 +75,7 @@ index 8416c7c6e052dafb2aad61c0bd3224c36e945d23..cd356beda023ab2409b16d58ca38c70b + @end diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h -index 5a23ea7558814eec59eda349bc7194afcb70d01e..c9147bbe5a225291552082434e5db34239394139 100644 +index cfbb9f03214084c5181e48e1b0d497ab0b5cf1b3..21fdd6e2e9fae08443ca74c49c1b6984ea0c3429 100644 --- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h +++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h @@ -17,6 +17,7 @@ class NativeWidgetNSWindowBridge; @@ -95,11 +95,11 @@ index 5a23ea7558814eec59eda349bc7194afcb70d01e..c9147bbe5a225291552082434e5db342 // The NSWindow used by BridgedNativeWidget. Provides hooks into AppKit that // can only be accomplished by overriding methods. diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm -index 83e08e8e56f8fdfe5c321c33b451b9bde8ee819a..f48d8ac4816e2d775c16758e086eb56ad456bd01 100644 +index 8ffa07e273fc65d8d29e119bb7dd4114b5eba6f4..60de405c461ec05a7036025553b82dd18f2acd13 100644 --- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm +++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm -@@ -16,7 +16,9 @@ - #import "ui/base/cocoa/window_size_constants.h" +@@ -78,7 +78,9 @@ void OrderChildWindow(NSWindow* child_window, + } // namespace @interface NSWindow (Private) +#ifndef MAS_BUILD @@ -108,7 +108,7 @@ index 83e08e8e56f8fdfe5c321c33b451b9bde8ee819a..f48d8ac4816e2d775c16758e086eb56a - (BOOL)hasKeyAppearance; - (long long)_resizeDirectionForMouseLocation:(CGPoint)location; - (BOOL)_isConsideredOpenForPersistentState; -@@ -48,6 +50,8 @@ - (void)cr_mouseDownOnFrameView:(NSEvent*)event { +@@ -110,6 +112,8 @@ - (void)cr_mouseDownOnFrameView:(NSEvent*)event { } @end @@ -117,7 +117,7 @@ index 83e08e8e56f8fdfe5c321c33b451b9bde8ee819a..f48d8ac4816e2d775c16758e086eb56a @implementation NativeWidgetMacNSWindowTitledFrame - (void)mouseDown:(NSEvent*)event { if (self.window.isMovable) -@@ -74,6 +78,8 @@ - (BOOL)usesCustomDrawing { +@@ -136,6 +140,8 @@ - (BOOL)usesCustomDrawing { } @end @@ -126,7 +126,7 @@ index 83e08e8e56f8fdfe5c321c33b451b9bde8ee819a..f48d8ac4816e2d775c16758e086eb56a @implementation NativeWidgetMacNSWindow { @private base::scoped_nsobject _commandDispatcher; -@@ -186,6 +192,8 @@ - (BOOL)hasViewsMenuActive { +@@ -285,6 +291,8 @@ - (NSAccessibilityRole)accessibilityRole { // NSWindow overrides. @@ -135,7 +135,7 @@ index 83e08e8e56f8fdfe5c321c33b451b9bde8ee819a..f48d8ac4816e2d775c16758e086eb56a + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle { if (windowStyle & NSWindowStyleMaskTitled) { if (Class customFrame = [NativeWidgetMacNSWindowTitledFrame class]) -@@ -197,6 +205,8 @@ + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle { +@@ -296,6 +304,8 @@ + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle { return [super frameViewClassForStyleMask:windowStyle]; } diff --git a/patches/chromium/mas_disable_remote_accessibility.patch b/patches/chromium/mas_disable_remote_accessibility.patch index 5b8f416677503..f24ef46dfb0ed 100644 --- a/patches/chromium/mas_disable_remote_accessibility.patch +++ b/patches/chromium/mas_disable_remote_accessibility.patch @@ -11,7 +11,7 @@ needs to think it's coming from the PWA process). I think it can just be chopped out -- if there are any side-effects, we should be able to work around them. diff --git a/components/remote_cocoa/app_shim/application_bridge.mm b/components/remote_cocoa/app_shim/application_bridge.mm -index 9734fb620a9a4010083af41a9e5cea038556eef5..05c95fb9b15f5ccbfecaee29d360dd27bf42f086 100644 +index 306db835fe203f663b1d84dd3490b619eb3f60b2..7a41d7afe6197e0a78934206782b1063f77f707a 100644 --- a/components/remote_cocoa/app_shim/application_bridge.mm +++ b/components/remote_cocoa/app_shim/application_bridge.mm @@ -51,6 +51,7 @@ @@ -44,10 +44,10 @@ index 9734fb620a9a4010083af41a9e5cea038556eef5..05c95fb9b15f5ccbfecaee29d360dd27 } // namespace diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm -index cb82b91eb2e62453bcf2e3dd47f1b44d927e37d9..a35a14928d63a25284768de2ef67f2de2bedd133 100644 +index 378cb463ff2ad323fe413d5ef40d6bd48659a5df..686527e081f1dc9bfa3cd8313ef818a05a4e5bfb 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm -@@ -561,10 +561,12 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) { +@@ -583,10 +583,12 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) { // this should be treated as an error and caught early. CHECK(bridged_view_); @@ -61,10 +61,10 @@ index cb82b91eb2e62453bcf2e3dd47f1b44d927e37d9..a35a14928d63a25284768de2ef67f2de // Beware: This view was briefly removed (in favor of a bare CALayer) in // crrev/c/1236675. The ordering of unassociated layers relative to NSView diff --git a/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm b/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm -index 2cd40c288f42937688e4f846a002779158ada68f..f4c7bb0ab75835bfdbd100ce852646bf77817c9e 100644 +index be7b05ee4f779ccc44e6eea7ff7fb3e8bd504d6f..3b3336913cf91c3b7f22cefb4139f82b882c97c9 100644 --- a/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm +++ b/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm -@@ -73,8 +73,10 @@ id GetFocusedBrowserAccessibilityElement() override { +@@ -77,8 +77,10 @@ id GetFocusedBrowserAccessibilityElement() override { return nil; } void SetAccessibilityWindow(NSWindow* window) override { @@ -75,7 +75,7 @@ index 2cd40c288f42937688e4f846a002779158ada68f..f4c7bb0ab75835bfdbd100ce852646bf } void ForwardKeyboardEvent(const content::NativeWebKeyboardEvent& key_event, -@@ -136,8 +138,10 @@ void SmartMagnify(const blink::WebGestureEvent& web_event) override { +@@ -140,8 +142,10 @@ void SmartMagnify(const blink::WebGestureEvent& web_event) override { mojo::AssociatedRemote host_; std::unique_ptr bridge_; @@ -86,11 +86,41 @@ index 2cd40c288f42937688e4f846a002779158ada68f..f4c7bb0ab75835bfdbd100ce852646bf }; } +diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm +index 6c0700b182e9765afd60d8deec501d13432e1b0a..c85c024a5a5711471e24698f14dda21b49817424 100644 +--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm ++++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm +@@ -21,7 +21,9 @@ + #include "ui/accelerated_widget_mac/accelerated_widget_mac.h" + #include "ui/accessibility/ax_role_properties.h" + #include "ui/accessibility/platform/ax_private_webkit_constants_mac.h" ++#ifndef MAS_BUILD + #include "ui/base/cocoa/remote_accessibility_api.h" ++#endif + + namespace { + +@@ -613,6 +615,7 @@ void PostAnnouncementNotification(NSString* announcement) { + if ([NSApp isActive]) + return window == [NSApp accessibilityFocusedWindow]; + ++#ifndef MAS_BUILD + // TODO(accessibility): We need a solution to the problem described below. + // If the window is NSAccessibilityRemoteUIElement, there are some challenges: + // 1. NSApp is the browser which spawned the PWA, and what it considers the +@@ -640,6 +643,7 @@ void PostAnnouncementNotification(NSString* announcement) { + // from within the app shim content. + if ([window isKindOfClass:[NSAccessibilityRemoteUIElement class]]) + return true; ++#endif + + return false; + } diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h -index 80d639b4a9eb7fa9265da4977782d125b72db719..5f82a49f6336cf89c8d404f8aef7b103709c95e9 100644 +index 0549e3b400cb42e1a3491a2de9739c275ae006df..ab59ea7211b425e36d3d0fa673d8c09b99140716 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h -@@ -49,7 +49,9 @@ class ScopedPasswordInputEnabler; +@@ -52,7 +52,9 @@ class ScopedPasswordInputEnabler; @protocol RenderWidgetHostViewMacDelegate; @@ -100,7 +130,7 @@ index 80d639b4a9eb7fa9265da4977782d125b72db719..5f82a49f6336cf89c8d404f8aef7b103 @class RenderWidgetHostViewCocoa; namespace content { -@@ -665,10 +667,12 @@ class CONTENT_EXPORT RenderWidgetHostViewMac +@@ -668,10 +670,12 @@ class CONTENT_EXPORT RenderWidgetHostViewMac // EnsureSurfaceSynchronizedForWebTest(). uint32_t latest_capture_sequence_number_ = 0u; @@ -114,10 +144,10 @@ index 80d639b4a9eb7fa9265da4977782d125b72db719..5f82a49f6336cf89c8d404f8aef7b103 // Used to force the NSApplication's focused accessibility element to be the // content::BrowserAccessibilityCocoa accessibility tree when the NSView for diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm -index 09ada3b859e1862cbf365960422871a56af54983..58002d37ba340f84f47e2522c0d7bf7c1a64c5d2 100644 +index d460e055c8bc70845cdf89567e17a79da70fd9f1..f28dcfe0721239ca9341a0db80e8626a515c34d8 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm -@@ -253,8 +253,10 @@ +@@ -259,8 +259,10 @@ void RenderWidgetHostViewMac::MigrateNSViewBridge( remote_cocoa::mojom::Application* remote_cocoa_application, uint64_t parent_ns_view_id) { @@ -128,7 +158,7 @@ index 09ada3b859e1862cbf365960422871a56af54983..58002d37ba340f84f47e2522c0d7bf7c // Disconnect from the previous bridge (this will have the effect of // destroying the associated bridge), and close the receiver (to allow it -@@ -1498,8 +1500,10 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, +@@ -1561,8 +1563,10 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, gfx::NativeViewAccessible RenderWidgetHostViewMac::AccessibilityGetNativeViewAccessibleForWindow() { @@ -139,7 +169,7 @@ index 09ada3b859e1862cbf365960422871a56af54983..58002d37ba340f84f47e2522c0d7bf7c return [GetInProcessNSView() window]; } -@@ -1543,9 +1547,11 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, +@@ -1606,9 +1610,11 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, } void RenderWidgetHostViewMac::SetAccessibilityWindow(NSWindow* window) { @@ -151,7 +181,7 @@ index 09ada3b859e1862cbf365960422871a56af54983..58002d37ba340f84f47e2522c0d7bf7c } bool RenderWidgetHostViewMac::SyncIsWidgetForMainFrame( -@@ -2038,12 +2044,14 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, +@@ -2103,12 +2109,14 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback, void RenderWidgetHostViewMac::SetRemoteAccessibilityWindowToken( const std::vector& window_token) { @@ -167,11 +197,11 @@ index 09ada3b859e1862cbf365960422871a56af54983..58002d37ba340f84f47e2522c0d7bf7c /////////////////////////////////////////////////////////////////////////////// diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn -index 0d7d47d1260d47959b0fa9f116a039c8b8307c96..15cc28a9bbc7b33a727e7c172207262902835ccc 100644 +index 8efef6d9adbca21613be3c32fe9f43b2d50ff8c5..6e819be94a6a5e8a26598f4883697719fecef693 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn -@@ -317,6 +317,13 @@ component("base") { - ] +@@ -341,6 +341,13 @@ component("base") { + sources += [ "resource/resource_bundle_lacros.cc" ] } + if (is_mas_build) { @@ -205,10 +235,10 @@ index e7adfee3210ec723c687adfcc4bee8827ef643e7..25a924a47eeb30d783ef83dbb4896c4b + #endif // UI_BASE_COCOA_REMOTE_ACCESSIBILITY_API_H_ diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.h b/ui/views/cocoa/native_widget_mac_ns_window_host.h -index 1964f624abc96c54645d1697b598799cfd9a2a00..30580103974b99dcaed2adb0b460b1af17658927 100644 +index 5a09100094d0371a3e58db6c7626e06bdcdd17c3..1aa7bde93efdf198998ba4e6a97dcf2aadd9f4e9 100644 --- a/ui/views/cocoa/native_widget_mac_ns_window_host.h +++ b/ui/views/cocoa/native_widget_mac_ns_window_host.h -@@ -31,7 +31,9 @@ +@@ -32,7 +32,9 @@ #include "ui/views/window/dialog_observer.h" @class NativeWidgetMacNSWindow; @@ -218,7 +248,7 @@ index 1964f624abc96c54645d1697b598799cfd9a2a00..30580103974b99dcaed2adb0b460b1af @class NSView; namespace remote_cocoa { -@@ -445,11 +447,13 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost +@@ -449,11 +451,13 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost mojo::AssociatedRemote remote_ns_window_remote_; @@ -233,10 +263,10 @@ index 1964f624abc96c54645d1697b598799cfd9a2a00..30580103974b99dcaed2adb0b460b1af // Used to force the NSApplication's focused accessibility element to be the // views::Views accessibility tree when the NSView for this is focused. diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm -index b77478d96caba7e94c198e9cc8cdd7a6b78e6b25..79af41886c66b51219b69282db17497c5af702d5 100644 +index cdaf472a02038e1fbcb15747dd1992e2ea0e998b..a9cb80cf7f3631eab7d0fcbcf685ee88af6d8972 100644 --- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm +++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm -@@ -294,14 +294,22 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -325,14 +325,22 @@ void HandleAccelerator(const ui::Accelerator& accelerator, NativeWidgetMacNSWindowHost::GetNativeViewAccessibleForNSView() const { if (in_process_ns_window_bridge_) return in_process_ns_window_bridge_->ns_view(); @@ -259,7 +289,7 @@ index b77478d96caba7e94c198e9cc8cdd7a6b78e6b25..79af41886c66b51219b69282db17497c } remote_cocoa::mojom::NativeWidgetNSWindow* -@@ -1275,6 +1283,7 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -1304,6 +1312,7 @@ void HandleAccelerator(const ui::Accelerator& accelerator, void NativeWidgetMacNSWindowHost::SetRemoteAccessibilityTokens( const std::vector& window_token, const std::vector& view_token) { @@ -267,7 +297,7 @@ index b77478d96caba7e94c198e9cc8cdd7a6b78e6b25..79af41886c66b51219b69282db17497c remote_window_accessible_ = ui::RemoteAccessibility::GetRemoteElementFromToken(window_token); remote_view_accessible_ = -@@ -1282,14 +1291,17 @@ void HandleAccelerator(const ui::Accelerator& accelerator, +@@ -1311,14 +1320,17 @@ void HandleAccelerator(const ui::Accelerator& accelerator, [remote_view_accessible_ setWindowUIElement:remote_window_accessible_.get()]; [remote_view_accessible_ setTopLevelUIElement:remote_window_accessible_.get()]; diff --git a/patches/chromium/mas_disable_remote_layer.patch b/patches/chromium/mas_disable_remote_layer.patch index 541ac9b7e977d..b31cf0975df7c 100644 --- a/patches/chromium/mas_disable_remote_layer.patch +++ b/patches/chromium/mas_disable_remote_layer.patch @@ -16,7 +16,7 @@ cases where performance improves when disabling remote CoreAnimation (remote CoreAnimation is really only about battery usage). diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.h b/gpu/ipc/service/image_transport_surface_overlay_mac.h -index 1b84c9df5990d0905d068ca822d5173313a74edd..89a90a5c8e0c3ede1b0fe63d45c5768b42394474 100644 +index 506ff3c2b9a14a725d13e3933bc281d05c0b6b13..9726e2d34d6d123ad3e62d843d21b755788fc062 100644 --- a/gpu/ipc/service/image_transport_surface_overlay_mac.h +++ b/gpu/ipc/service/image_transport_surface_overlay_mac.h @@ -21,7 +21,9 @@ @@ -29,7 +29,17 @@ index 1b84c9df5990d0905d068ca822d5173313a74edd..89a90a5c8e0c3ede1b0fe63d45c5768b @class CALayer; namespace ui { -@@ -116,7 +118,9 @@ class ImageTransportSurfaceOverlayMacBase : public BaseClass, +@@ -113,7 +115,9 @@ class ImageTransportSurfaceOverlayMac : public gl::GLSurface, + base::WeakPtr delegate_; + + bool use_remote_layer_api_; ++#ifndef MAS_BUILD + base::scoped_nsobject ca_context_; ++#endif + std::unique_ptr ca_layer_tree_coordinator_; + + gfx::Size pixel_size_; +@@ -204,7 +208,9 @@ class ImageTransportSurfaceOverlayMacEGL : public gl::GLSurfaceEGL, base::WeakPtr delegate_; bool use_remote_layer_api_; @@ -40,32 +50,57 @@ index 1b84c9df5990d0905d068ca822d5173313a74edd..89a90a5c8e0c3ede1b0fe63d45c5768b gfx::Size pixel_size_; diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.mm b/gpu/ipc/service/image_transport_surface_overlay_mac.mm -index 224542e2a70e980684d5d882af7fe3988c5ee96b..7a726eea86f21fe31077aaa447cccc05007d5eaa 100644 +index 27b0c985b119095bd92ac021db10731a917dfa0c..83bd23a7ed0a5870f226442a6335b26de7676206 100644 --- a/gpu/ipc/service/image_transport_surface_overlay_mac.mm +++ b/gpu/ipc/service/image_transport_surface_overlay_mac.mm -@@ -59,7 +59,7 @@ +@@ -60,6 +60,7 @@ + ca_layer_tree_coordinator_ = std::make_unique( + use_remote_layer_api_, allow_av_sample_buffer_display_layer); + ++#ifndef MAS_BUILD + // Create the CAContext to send this to the GPU process, and the layer for + // the context. + if (use_remote_layer_api_) { +@@ -68,6 +69,7 @@ + options:@{}] retain]); + [ca_context_ setLayer:ca_layer_tree_coordinator_->GetCALayerForDisplay()]; + } ++#endif + } + ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { +@@ -145,7 +147,9 @@ + "GLImpl", static_cast(gl::GetGLImplementation()), + "width", pixel_size_.width()); + if (use_remote_layer_api_) { ++#ifndef MAS_BUILD + params.ca_context_id = [ca_context_ contextId]; ++#endif + } else { + IOSurfaceRef io_surface = + ca_layer_tree_coordinator_->GetIOSurfaceForDisplay(); +@@ -379,6 +383,7 @@ ca_layer_tree_coordinator_ = std::make_unique( use_remote_layer_api_, allow_av_sample_buffer_display_layer); -- + +#ifndef MAS_BUILD // Create the CAContext to send this to the GPU process, and the layer for // the context. if (use_remote_layer_api_) { -@@ -68,6 +68,7 @@ +@@ -387,6 +392,7 @@ options:@{}] retain]); [ca_context_ setLayer:ca_layer_tree_coordinator_->GetCALayerForDisplay()]; } +#endif } - template -@@ -148,7 +149,9 @@ + ImageTransportSurfaceOverlayMacEGL::~ImageTransportSurfaceOverlayMacEGL() { +@@ -465,7 +471,9 @@ "GLImpl", static_cast(gl::GetGLImplementation()), "width", pixel_size_.width()); if (use_remote_layer_api_) { +#ifndef MAS_BUILD - params.ca_layer_params.ca_context_id = [ca_context_ contextId]; + params.ca_context_id = [ca_context_ contextId]; +#endif } else { IOSurfaceRef io_surface = diff --git a/patches/chromium/mas_gate_private_enterprise_APIs.patch b/patches/chromium/mas_gate_private_enterprise_APIs.patch deleted file mode 100644 index 306a8c3792401..0000000000000 --- a/patches/chromium/mas_gate_private_enterprise_APIs.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: VerteDinde -Date: Tue, 19 Oct 2021 16:56:25 -0700 -Subject: fix: mas gate private enterprise APIs - -Beginning in Electron 15.2.0, Chromium moved several formerly public -APIs into the AreDeviceAndUserJoinedToDomain method. Using these APIs -in a MAS build will result in rejection from the Apple Store. This -patch gates those APIs to non-MAS builds to comply with Apple -Store requirements, and returns the default state for MAS builds. - -diff --git a/base/enterprise_util_mac.mm b/base/enterprise_util_mac.mm -index bbb851e1cafb37ebaa67e4577598fab25c90fde6..6ab12e5505b5ba545e7e0cc8c93d3ba9a6d0bacc 100644 ---- a/base/enterprise_util_mac.mm -+++ b/base/enterprise_util_mac.mm -@@ -168,6 +168,13 @@ MacDeviceManagementStateNew IsDeviceRegisteredWithManagementNew() { - DeviceUserDomainJoinState AreDeviceAndUserJoinedToDomain() { - static DeviceUserDomainJoinState state = [] { - DeviceUserDomainJoinState state{false, false}; -+#if defined(MAS_BUILD) -+ return state; -+ }(); -+ -+ return state; -+} -+#else - - @autoreleasepool { - ODSession* session = [ODSession defaultSession]; -@@ -274,5 +281,6 @@ DeviceUserDomainJoinState AreDeviceAndUserJoinedToDomain() { - - return state; - } -+#endif - - } // namespace base diff --git a/patches/chromium/mas_no_private_api.patch b/patches/chromium/mas_no_private_api.patch index df57e80ec71dc..34f1f6b50e6aa 100644 --- a/patches/chromium/mas_no_private_api.patch +++ b/patches/chromium/mas_no_private_api.patch @@ -122,7 +122,7 @@ index c15f3a631292b538698625328fb429ee3c9964f5..37e038753ecf1b82ec92c06b2c0729b5 } diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm -index 3f7dce0281f7b5a540d7b9377ef14a8a6aa9a2fa..11d8419791f3e45d5242081422d452d4fc703833 100644 +index 69e60d498941c34cfac9e79c7517765bf93849f5..b998ad7cf01c21e93c57e1283cfdcb1e02ac49cf 100644 --- a/device/bluetooth/bluetooth_adapter_mac.mm +++ b/device/bluetooth/bluetooth_adapter_mac.mm @@ -42,6 +42,7 @@ @@ -141,8 +141,8 @@ index 3f7dce0281f7b5a540d7b9377ef14a8a6aa9a2fa..11d8419791f3e45d5242081422d452d4 namespace { -@@ -123,8 +125,10 @@ CBCentralManagerState GetCBManagerState(CBCentralManager* manager) { - controller_state_function_( +@@ -114,8 +116,10 @@ bool IsDeviceSystemPaired(const std::string& device_address) { + : controller_state_function_( base::BindRepeating(&BluetoothAdapterMac::GetHostControllerState, base::Unretained(this))), +#ifndef MAS_BUILD @@ -152,7 +152,7 @@ index 3f7dce0281f7b5a540d7b9377ef14a8a6aa9a2fa..11d8419791f3e45d5242081422d452d4 classic_discovery_manager_( BluetoothDiscoveryManagerMac::CreateClassic(this)), low_energy_discovery_manager_( -@@ -365,8 +369,12 @@ CBCentralManagerState GetCBManagerState(CBCentralManager* manager) { +@@ -356,8 +360,12 @@ bool IsDeviceSystemPaired(const std::string& device_address) { } bool BluetoothAdapterMac::SetPoweredImpl(bool powered) { @@ -166,10 +166,10 @@ index 3f7dce0281f7b5a540d7b9377ef14a8a6aa9a2fa..11d8419791f3e45d5242081422d452d4 void BluetoothAdapterMac::RemovePairingDelegateInternal( diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn -index 6ffc09426b92b0623957f4a5f547865f49e29546..45cf4e11a77c175d61c2ffe69009802596c97e25 100644 +index d872796dee0dee4aa14c238f788b962b3f1c9311..4d5f74c18d773755d5d8f7223bc0d5c944467d69 100644 --- a/media/audio/BUILD.gn +++ b/media/audio/BUILD.gn -@@ -175,6 +175,12 @@ source_set("audio") { +@@ -176,6 +176,12 @@ source_set("audio") { "mac/scoped_audio_unit.cc", "mac/scoped_audio_unit.h", ] @@ -183,10 +183,10 @@ index 6ffc09426b92b0623957f4a5f547865f49e29546..45cf4e11a77c175d61c2ffe690098025 "AudioToolbox.framework", "AudioUnit.framework", diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc -index ebdc6364312ee710d416318836c03aeec9bfb65c..aa9b50de7efaf0e1b64effea93204984c91790b5 100644 +index eb0aff29b2f4fd2b035ef96186fd58d976876b05..8a68a8885ec42715c9b9dab0f04d1b90eb9baa6e 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc -@@ -886,7 +886,7 @@ AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( +@@ -885,7 +885,7 @@ AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( void AudioManagerMac::InitializeOnAudioThread() { DCHECK(GetTaskRunner()->BelongsToCurrentThread()); @@ -196,10 +196,10 @@ index ebdc6364312ee710d416318836c03aeec9bfb65c..aa9b50de7efaf0e1b64effea93204984 } diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc -index e59fec60e9d593d311b21c12daf2d611a36a2d6e..b812dee59b55edee6efe73ce4b1da0a89b45240e 100644 +index 025078e112683380b484b7c47f786862f4e48a74..11c81ec36a9793afab0da8578f85378f9ce3a446 100644 --- a/net/dns/dns_config_service_posix.cc +++ b/net/dns/dns_config_service_posix.cc -@@ -129,8 +129,8 @@ class DnsConfigServicePosix::Watcher : public DnsConfigService::Watcher { +@@ -130,8 +130,8 @@ class DnsConfigServicePosix::Watcher : public DnsConfigService::Watcher { bool Watch() override { CheckOnCorrectSequence(); @@ -209,7 +209,7 @@ index e59fec60e9d593d311b21c12daf2d611a36a2d6e..b812dee59b55edee6efe73ce4b1da0a8 if (!config_watcher_.Watch(base::BindRepeating(&Watcher::OnConfigChanged, base::Unretained(this)))) { LOG(ERROR) << "DNS config watch failed to start."; -@@ -147,6 +147,7 @@ class DnsConfigServicePosix::Watcher : public DnsConfigService::Watcher { +@@ -148,6 +148,7 @@ class DnsConfigServicePosix::Watcher : public DnsConfigService::Watcher { success = false; } #endif // !BUILDFLAG(IS_IOS) @@ -313,10 +313,10 @@ index d59a16112d27e2696437163483c44eca414c225c..1ccd20fe7efa3cbae48f99d0660b0252 NOTREACHED(); return nullptr; diff --git a/ui/accessibility/platform/inspect/ax_transform_mac.mm b/ui/accessibility/platform/inspect/ax_transform_mac.mm -index 7cb34e119cd30353fe56e7c71ed5e1d417896888..dbb6cc8e37eff9b30269687f29808ec3ca46b243 100644 +index 397f01d7249f491840e5953b65c2d54eb92dc638..a7279e44346cb5b0b26599bd62693ad40a59e84f 100644 --- a/ui/accessibility/platform/inspect/ax_transform_mac.mm +++ b/ui/accessibility/platform/inspect/ax_transform_mac.mm -@@ -86,6 +86,7 @@ +@@ -87,6 +87,7 @@ } } @@ -324,11 +324,11 @@ index 7cb34e119cd30353fe56e7c71ed5e1d417896888..dbb6cc8e37eff9b30269687f29808ec3 // AXTextMarker if (IsAXTextMarker(value)) { return AXTextMarkerToBaseValue(value, indexer); -@@ -94,6 +95,7 @@ +@@ -95,6 +96,7 @@ // AXTextMarkerRange if (IsAXTextMarkerRange(value)) return AXTextMarkerRangeToBaseValue(value, indexer); +#endif // Accessible object - if (IsNSAccessibilityElement(value) || IsAXUIElement(value)) { + if (AXElementWrapper::IsValidElement(value)) { diff --git a/patches/chromium/mas_use_public_apis_to_determine_if_a_font_is_a_system_font.patch b/patches/chromium/mas_use_public_apis_to_determine_if_a_font_is_a_system_font.patch index 4a2895266232f..6ba1e0d11fdad 100644 --- a/patches/chromium/mas_use_public_apis_to_determine_if_a_font_is_a_system_font.patch +++ b/patches/chromium/mas_use_public_apis_to_determine_if_a_font_is_a_system_font.patch @@ -9,7 +9,7 @@ system font by checking if it's kCTFontPriorityAttribute is set to system priority. diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm -index 99b4dffbd41dd5d53e4f8e7e0bfbbf3ecc6fcb43..db57e78efa22a26b71426d2960aeb7919ae6cf47 100644 +index 88262d4dd82b3a954ed09492c508ad83dece0256..81fad8ca63479737885f09be7cf05b8eada1f104 100644 --- a/ui/gfx/platform_font_mac.mm +++ b/ui/gfx/platform_font_mac.mm @@ -25,9 +25,11 @@ @@ -24,7 +24,7 @@ index 99b4dffbd41dd5d53e4f8e7e0bfbbf3ecc6fcb43..db57e78efa22a26b71426d2960aeb791 namespace { -@@ -232,7 +234,13 @@ NSInteger ToNSFontManagerWeight(Weight weight) { +@@ -220,7 +222,13 @@ NSInteger ToNSFontManagerWeight(Weight weight) { // TODO(avi, etienneb): Figure out this font stuff. base::ScopedCFTypeRef descriptor( CTFontCopyFontDescriptor(font)); diff --git a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch index 117a515b17993..1872cac3cff7d 100644 --- a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch +++ b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch @@ -7,10 +7,10 @@ This adds a callback from the network service that's used to implement session.setCertificateVerifyCallback. diff --git a/services/network/network_context.cc b/services/network/network_context.cc -index 2ee1a3da9ca1543d032c2e05c9b340a231f0f495..a4cd97599e2f131fe0d97ee49a44ed5b748739b7 100644 +index 3ee7e8145e8cd0a68680e2044f0fb44d314a4317..f25c1baa5142d53a882b864a67d94e9e0911f0bf 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc -@@ -126,6 +126,11 @@ +@@ -130,6 +130,11 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" @@ -22,7 +22,7 @@ index 2ee1a3da9ca1543d032c2e05c9b340a231f0f495..a4cd97599e2f131fe0d97ee49a44ed5b #if BUILDFLAG(IS_CT_SUPPORTED) #include "components/certificate_transparency/chrome_ct_policy_enforcer.h" #include "components/certificate_transparency/chrome_require_ct_delegate.h" -@@ -433,6 +438,91 @@ bool GetFullDataFilePath( +@@ -438,6 +443,91 @@ bool GetFullDataFilePath( } // namespace @@ -114,7 +114,7 @@ index 2ee1a3da9ca1543d032c2e05c9b340a231f0f495..a4cd97599e2f131fe0d97ee49a44ed5b constexpr uint32_t NetworkContext::kMaxOutstandingRequestsPerProcess; NetworkContext::PendingCertVerify::PendingCertVerify() = default; -@@ -671,6 +761,13 @@ void NetworkContext::SetClient( +@@ -743,6 +833,13 @@ void NetworkContext::SetClient( client_.Bind(std::move(client)); } @@ -128,9 +128,9 @@ index 2ee1a3da9ca1543d032c2e05c9b340a231f0f495..a4cd97599e2f131fe0d97ee49a44ed5b void NetworkContext::CreateURLLoaderFactory( mojo::PendingReceiver receiver, mojom::URLLoaderFactoryParamsPtr params) { -@@ -2235,6 +2332,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( +@@ -2324,6 +2421,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( std::move(cert_verifier)); - cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_); + cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_.get()); #endif // BUILDFLAG(IS_CHROMEOS) + auto remote_cert_verifier = std::make_unique(std::move(cert_verifier)); + remote_cert_verifier_ = remote_cert_verifier.get(); @@ -139,10 +139,10 @@ index 2ee1a3da9ca1543d032c2e05c9b340a231f0f495..a4cd97599e2f131fe0d97ee49a44ed5b builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier( diff --git a/services/network/network_context.h b/services/network/network_context.h -index 01befea8b354ed1dd143aa895d0d9efb0d26fd35..06a36a156501b252e91037ebac45c29c2995f624 100644 +index cc1c9079baed00f6327efe929ab9d004d2272cfb..a9a1beed6c8e59abb9065701f34f155905781a2a 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h -@@ -105,6 +105,7 @@ class URLMatcher; +@@ -104,6 +104,7 @@ class URLMatcher; namespace network { class CertVerifierWithTrustAnchors; @@ -150,7 +150,7 @@ index 01befea8b354ed1dd143aa895d0d9efb0d26fd35..06a36a156501b252e91037ebac45c29c class CookieManager; class ExpectCTReporter; class HostResolver; -@@ -220,6 +221,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext +@@ -240,6 +241,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext void CreateURLLoaderFactory( mojo::PendingReceiver receiver, mojom::URLLoaderFactoryParamsPtr params) override; @@ -159,9 +159,9 @@ index 01befea8b354ed1dd143aa895d0d9efb0d26fd35..06a36a156501b252e91037ebac45c29c void ResetURLLoaderFactories() override; void GetCookieManager( mojo::PendingReceiver receiver) override; -@@ -795,6 +798,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext - CertVerifierWithTrustAnchors* cert_verifier_with_trust_anchors_ = nullptr; - #endif +@@ -827,6 +830,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext + std::vector dismount_closures_; + #endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED) + RemoteCertVerifier* remote_cert_verifier_ = nullptr; + @@ -169,10 +169,10 @@ index 01befea8b354ed1dd143aa895d0d9efb0d26fd35..06a36a156501b252e91037ebac45c29c // CertNetFetcher is not used by the current platform, or if the actual // net::CertVerifier is instantiated outside of the network service. diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom -index 0b1afd416381c28e5bc96fa44562c061f44a7121..ae0a20a7a33e5a313f5545985a34e9cb93220996 100644 +index e4eec4dde27862507252d6853ec3186400181c95..e47bbfac56cd6c787ba3e7c0518a5326386a19b6 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom -@@ -277,6 +277,17 @@ struct NetworkContextFilePaths { +@@ -283,6 +283,17 @@ struct NetworkContextFilePaths { bool trigger_migration = false; }; @@ -190,7 +190,7 @@ index 0b1afd416381c28e5bc96fa44562c061f44a7121..ae0a20a7a33e5a313f5545985a34e9cb // Parameters for constructing a network context. struct NetworkContextParams { // The user agent string. -@@ -821,6 +832,9 @@ interface NetworkContext { +@@ -851,6 +862,9 @@ interface NetworkContext { // Sets a client for this network context. SetClient(pending_remote client); diff --git a/patches/chromium/notification_provenance.patch b/patches/chromium/notification_provenance.patch index 5d535e2d459c5..ef1fb762c08ec 100644 --- a/patches/chromium/notification_provenance.patch +++ b/patches/chromium/notification_provenance.patch @@ -7,10 +7,10 @@ Pass RenderFrameHost through to PlatformNotificationService so Electron can identify which renderer a notification came from. diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc -index 06a1db7fd9324de7d1fcf49c5b8a40b922a945be..c63b92a5a100785bf00b5e6da4c7f71bb9e769b7 100644 +index 17b9ed63bd839632a5eed5bcbaa3e990472761ef..09c266f1a99e42d6c417c294d7db1d6621ec0365 100644 --- a/chrome/browser/notifications/platform_notification_service_impl.cc +++ b/chrome/browser/notifications/platform_notification_service_impl.cc -@@ -196,6 +196,7 @@ bool PlatformNotificationServiceImpl::WasClosedProgrammatically( +@@ -197,6 +197,7 @@ bool PlatformNotificationServiceImpl::WasClosedProgrammatically( // TODO(awdf): Rename to DisplayNonPersistentNotification (Similar for Close) void PlatformNotificationServiceImpl::DisplayNotification( @@ -31,23 +31,24 @@ index b0e64049d411305d58802fd290bb0480e9b36fee..4afcf3b7a5b841409b0e1c4c2f32fd48 const GURL& origin, const GURL& document_url, diff --git a/content/browser/notifications/blink_notification_service_impl.cc b/content/browser/notifications/blink_notification_service_impl.cc -index 442b856f8bcfbcea7742188897f0ce0a25cd60f4..6165eb772901faa25514c9bbefd13ff6b45d6b33 100644 +index c969a5d35eac7b071b46d6a8106072e571f177a5..033618eda6e1e5b90a6e9b655e38f27bf051380a 100644 --- a/content/browser/notifications/blink_notification_service_impl.cc +++ b/content/browser/notifications/blink_notification_service_impl.cc -@@ -81,10 +81,12 @@ BlinkNotificationServiceImpl::BlinkNotificationServiceImpl( - PlatformNotificationContextImpl* notification_context, +@@ -83,11 +83,13 @@ BlinkNotificationServiceImpl::BlinkNotificationServiceImpl( BrowserContext* browser_context, scoped_refptr service_worker_context, + RenderProcessHost* render_process_host, + RenderFrameHost* render_frame_host, const url::Origin& origin, const GURL& document_url, + const WeakDocumentPtr& weak_document_ptr, mojo::PendingReceiver receiver) : notification_context_(notification_context), + render_frame_host_(render_frame_host), browser_context_(browser_context), service_worker_context_(std::move(service_worker_context)), - origin_(origin), -@@ -147,7 +149,7 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( + render_process_host_id_(render_process_host->GetID()), +@@ -152,7 +154,7 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( notification_id, std::move(event_listener_remote)); browser_context_->GetPlatformNotificationService()->DisplayNotification( @@ -57,18 +58,18 @@ index 442b856f8bcfbcea7742188897f0ce0a25cd60f4..6165eb772901faa25514c9bbefd13ff6 } diff --git a/content/browser/notifications/blink_notification_service_impl.h b/content/browser/notifications/blink_notification_service_impl.h -index cb2b09912dbe426611e944316841ee2a9c2e373f..4d2603c29b2d89fa296b1aad40c2132a9c7498aa 100644 +index 20db1f61b391f7b154071f24e91fd0925e3e0df2..4816ac66d1eebe0823844b07b146707db7727c21 100644 --- a/content/browser/notifications/blink_notification_service_impl.h +++ b/content/browser/notifications/blink_notification_service_impl.h -@@ -41,6 +41,7 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl - PlatformNotificationContextImpl* notification_context, +@@ -43,6 +43,7 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl BrowserContext* browser_context, scoped_refptr service_worker_context, + RenderProcessHost* render_process_host, + RenderFrameHost* render_frame_host, const url::Origin& origin, const GURL& document_url, - mojo::PendingReceiver receiver); -@@ -101,6 +102,7 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl + const WeakDocumentPtr& weak_document_ptr, +@@ -104,6 +105,7 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl // The notification context that owns this service instance. raw_ptr notification_context_; @@ -77,72 +78,85 @@ index cb2b09912dbe426611e944316841ee2a9c2e373f..4d2603c29b2d89fa296b1aad40c2132a scoped_refptr service_worker_context_; diff --git a/content/browser/notifications/blink_notification_service_impl_unittest.cc b/content/browser/notifications/blink_notification_service_impl_unittest.cc -index f0d5ea365cf09d2dc06de88fc03e4bf5ddfdf4a6..b68666813ab231a3d4233d3ed2f9655b18d8a280 100644 +index 41fb02d532190e82d50286e2733a6c3627bf25c8..f19bb5dcb69233733125029d8f997f7343d7e04b 100644 --- a/content/browser/notifications/blink_notification_service_impl_unittest.cc +++ b/content/browser/notifications/blink_notification_service_impl_unittest.cc -@@ -126,7 +126,7 @@ class BlinkNotificationServiceImplTest : public ::testing::Test { - +@@ -129,7 +129,7 @@ class BlinkNotificationServiceImplTest : public ::testing::Test { notification_service_ = std::make_unique( notification_context_.get(), &browser_context_, -- embedded_worker_helper_->context_wrapper(), -+ embedded_worker_helper_->context_wrapper(), nullptr, - url::Origin::Create(GURL(kTestOrigin)), + embedded_worker_helper_->context_wrapper(), &render_process_host_, +- url::Origin::Create(GURL(kTestOrigin)), ++ nullptr, url::Origin::Create(GURL(kTestOrigin)), /*document_url=*/GURL(), + /*weak_document_ptr=*/WeakDocumentPtr(), notification_service_remote_.BindNewPipeAndPassReceiver()); diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc -index 8e23ab272000a1244959bf9164d6880660d4a843..ff89f2bdf07e91029841bab7ce7c7a92526c0132 100644 +index fdd74853b9b277d9b47fb99311349b66f70dfa11..06d1f5a8cc7f0ff12e4a7d66b435a19369af126b 100644 --- a/content/browser/notifications/platform_notification_context_impl.cc +++ b/content/browser/notifications/platform_notification_context_impl.cc -@@ -281,13 +281,14 @@ void PlatformNotificationContextImpl::Shutdown() { - } +@@ -283,6 +283,7 @@ void PlatformNotificationContextImpl::Shutdown() { void PlatformNotificationContextImpl::CreateService( + RenderProcessHost* render_process_host, + RenderFrameHost* render_frame_host, const url::Origin& origin, const GURL& document_url, - mojo::PendingReceiver receiver) { + const WeakDocumentPtr& weak_document_ptr, +@@ -290,7 +291,8 @@ void PlatformNotificationContextImpl::CreateService( DCHECK_CURRENTLY_ON(BrowserThread::UI); services_.push_back(std::make_unique( -- this, browser_context_, service_worker_context_, origin, document_url, -- std::move(receiver))); -+ this, browser_context_, service_worker_context_, render_frame_host, -+ origin, document_url, std::move(receiver))); + this, browser_context_, service_worker_context_, render_process_host, +- origin, document_url, weak_document_ptr, std::move(receiver))); ++ render_frame_host, origin, document_url, weak_document_ptr, ++ std::move(receiver))); } void PlatformNotificationContextImpl::RemoveService( diff --git a/content/browser/notifications/platform_notification_context_impl.h b/content/browser/notifications/platform_notification_context_impl.h -index 951075749b24814606f494c5a89ee2adf527f512..7036323ff8ee38ae92790dfd2e216df61181bc55 100644 +index 424fae79eb1c93f1fac293ae8fdeb6d067f523cc..6a2f074ad981deb15b46bd91b6d7eb5de8612403 100644 --- a/content/browser/notifications/platform_notification_context_impl.h +++ b/content/browser/notifications/platform_notification_context_impl.h -@@ -47,6 +47,7 @@ class BrowserContext; - struct NotificationDatabaseData; +@@ -48,6 +48,7 @@ struct NotificationDatabaseData; class PlatformNotificationServiceProxy; + class RenderProcessHost; class ServiceWorkerContextWrapper; +class RenderFrameHost; // Implementation of the Web Notification storage context. The public methods // defined in this interface must only be called on the UI thread. -@@ -76,6 +77,7 @@ class CONTENT_EXPORT PlatformNotificationContextImpl - // Creates a BlinkNotificationServiceImpl that is owned by this context. +@@ -78,6 +79,7 @@ class CONTENT_EXPORT PlatformNotificationContextImpl // |document_url| is empty when originating from a worker. void CreateService( + RenderProcessHost* render_process_host, + RenderFrameHost* render_frame_host, const url::Origin& origin, const GURL& document_url, - mojo::PendingReceiver receiver); + const WeakDocumentPtr& weak_document_ptr, diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc -index a002e3972f1ed8ea8ff2a7febe1c6b7a8ffbe657..eebe90092c65dd9160a394b9b6eb2273b03de503 100644 +index 18ad9b07e8d6ce33e4f5497aed48269ea49e2b9e..161aefa1d91923be35046dfe735071c687710deb 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc -@@ -2135,7 +2135,7 @@ void RenderProcessHostImpl::CreateNotificationService( - document_url = rfh->GetLastCommittedURL(); - +@@ -2075,8 +2075,9 @@ void RenderProcessHostImpl::CreateNotificationService( + // For workers: + if (render_frame_id == MSG_ROUTING_NONE) { + storage_partition_impl_->GetPlatformNotificationContext()->CreateService( +- this, origin, /*document_url=*/GURL(), +- /*weak_document_ptr=*/WeakDocumentPtr(), std::move(receiver)); ++ this, RenderFrameHost::FromID(GetID(), render_frame_id), origin, ++ /*document_url=*/GURL(), /*weak_document_ptr=*/WeakDocumentPtr(), ++ std::move(receiver)); + return; + } + +@@ -2084,7 +2085,7 @@ void RenderProcessHostImpl::CreateNotificationService( + RenderFrameHost* rfh = RenderFrameHost::FromID(GetID(), render_frame_id); + CHECK(rfh); storage_partition_impl_->GetPlatformNotificationContext()->CreateService( -- origin, document_url, std::move(receiver)); -+ RenderFrameHost::FromID(GetID(), render_frame_id), origin, document_url, std::move(receiver)); +- this, origin, rfh->GetLastCommittedURL(), rfh->GetWeakDocumentPtr(), ++ this, rfh, origin, rfh->GetLastCommittedURL(), rfh->GetWeakDocumentPtr(), + std::move(receiver)); } - void RenderProcessHostImpl::CreateWebSocketConnector( diff --git a/content/public/browser/platform_notification_service.h b/content/public/browser/platform_notification_service.h index 9646cbeb31141e3518f51482801431f3a6010360..b13b6ab07b4931b892749c84879d9a6adb3bcb58 100644 --- a/content/public/browser/platform_notification_service.h diff --git a/patches/chromium/pepper_plugin_support.patch b/patches/chromium/pepper_plugin_support.patch index b9d73ff072c6d..bae8f486133f3 100644 --- a/patches/chromium/pepper_plugin_support.patch +++ b/patches/chromium/pepper_plugin_support.patch @@ -7,13 +7,13 @@ This tweaks Chrome's pepper flash and PDF plugin support to make it usable from Electron. diff --git a/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc -index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc244092d2 100644 +index 2425ccd480f4b0f3ac3b9dddb5dbf90639fe515b..6f20e2edd880e34149668ece6e80e79b3da8dc66 100644 --- a/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc +++ b/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc -@@ -7,17 +7,21 @@ +@@ -6,17 +6,21 @@ + #include - #include "base/cxx17_backports.h" +#if 0 #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" @@ -32,7 +32,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc #include "ppapi/c/pp_errors.h" #include "ppapi/host/dispatch_host_message.h" #include "ppapi/host/host_message_context.h" -@@ -26,12 +30,11 @@ +@@ -25,12 +29,11 @@ #include "ppapi/shared_impl/file_system_util.h" #include "storage/browser/file_system/isolated_context.h" @@ -46,7 +46,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc namespace { -@@ -41,6 +44,7 @@ const char* kPredefinedAllowedCrxFsOrigins[] = { +@@ -40,6 +43,7 @@ const char* kPredefinedAllowedCrxFsOrigins[] = { }; } // namespace @@ -54,7 +54,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc // static PepperIsolatedFileSystemMessageFilter* -@@ -64,11 +68,16 @@ PepperIsolatedFileSystemMessageFilter::PepperIsolatedFileSystemMessageFilter( +@@ -63,11 +67,16 @@ PepperIsolatedFileSystemMessageFilter::PepperIsolatedFileSystemMessageFilter( const base::FilePath& profile_directory, const GURL& document_url, ppapi::host::PpapiHost* ppapi_host) @@ -62,7 +62,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc : render_process_id_(render_process_id), profile_directory_(profile_directory), document_url_(document_url) { - for (size_t i = 0; i < base::size(kPredefinedAllowedCrxFsOrigins); ++i) + for (size_t i = 0; i < std::size(kPredefinedAllowedCrxFsOrigins); ++i) allowed_crxfs_origins_.insert(kPredefinedAllowedCrxFsOrigins[i]); +#else + : profile_directory_(profile_directory), @@ -71,7 +71,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc } PepperIsolatedFileSystemMessageFilter:: -@@ -93,6 +102,7 @@ int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived( +@@ -92,6 +101,7 @@ int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived( return PP_ERROR_FAILED; } @@ -79,7 +79,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc Profile* PepperIsolatedFileSystemMessageFilter::GetProfile() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); ProfileManager* profile_manager = g_browser_process->profile_manager(); -@@ -117,6 +127,7 @@ PepperIsolatedFileSystemMessageFilter::CreateCrxFileSystem(Profile* profile) { +@@ -116,6 +126,7 @@ PepperIsolatedFileSystemMessageFilter::CreateCrxFileSystem(Profile* profile) { return storage::IsolatedContext::ScopedFSHandle(); #endif } @@ -87,7 +87,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( ppapi::host::HostMessageContext* context, -@@ -125,7 +136,7 @@ int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( +@@ -124,7 +135,7 @@ int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_INVALID: break; case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_CRX: @@ -96,7 +96,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc } NOTREACHED(); context->reply_msg = -@@ -133,6 +144,7 @@ int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( +@@ -132,6 +143,7 @@ int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( return PP_ERROR_FAILED; } @@ -104,7 +104,7 @@ index 308e7bff4ea829f5e68a93e77e0205f3f6a509c4..88a1e057ed8873f05e0d11160e7994bc int32_t PepperIsolatedFileSystemMessageFilter::OpenCrxFileSystem( ppapi::host::HostMessageContext* context) { #if BUILDFLAG(ENABLE_EXTENSIONS) -@@ -173,3 +185,4 @@ int32_t PepperIsolatedFileSystemMessageFilter::OpenCrxFileSystem( +@@ -172,3 +184,4 @@ int32_t PepperIsolatedFileSystemMessageFilter::OpenCrxFileSystem( return PP_ERROR_NOTSUPPORTED; #endif } @@ -156,41 +156,28 @@ index 40fafdbed313800a3f420d9d5a3daf8bbbdb7d95..1367725e04455ba5f299b8341a28f222 #endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ diff --git a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc -index 4b84f4ef068a76fa2be244a7f7ca2c6a8734bd46..13ae0a57535dfb516eb70b272fdaa5a4720d0591 100644 +index e3ee403ec5d4d75f22f1853ec8637a0559ce3c43..76232286e02a20bcd578c5ba28af638dfc8f562c 100644 --- a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc +++ b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc -@@ -6,8 +6,13 @@ +@@ -5,7 +5,9 @@ + #include "chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h" #include "base/check_op.h" - #include "chrome/renderer/pepper/pepper_flash_font_file_host.h" +#if 0 #include "chrome/renderer/pepper/pepper_uma_host.h" -+#endif -+#include "electron/buildflags/buildflags.h" -+#if BUILDFLAG(ENABLE_PDF_VIEWER) - #include "components/pdf/renderer/pepper_pdf_host.h" +#endif #include "content/public/renderer/renderer_ppapi_host.h" - #include "pdf/buildflags.h" #include "ppapi/host/ppapi_host.h" -@@ -55,7 +60,7 @@ ChromeRendererPepperHostFactory::CreateResourceHost( - } - } - --#if BUILDFLAG(ENABLE_PDF) -+#if BUILDFLAG(ENABLE_PDF_VIEWER) - if (host_->GetPpapiHost()->permissions().HasPermission( - ppapi::PERMISSION_PDF)) { - switch (message.type()) { -@@ -66,6 +71,7 @@ ChromeRendererPepperHostFactory::CreateResourceHost( - } - #endif + #include "ppapi/host/resource_host.h" +@@ -33,6 +35,7 @@ ChromeRendererPepperHostFactory::CreateResourceHost( + if (!host_->IsValidInstance(instance)) + return nullptr; +#if 0 // Permissions for the following interfaces will be checked at the // time of the corresponding instance's method calls. Currently these // interfaces are available only for whitelisted apps which may not have -@@ -75,6 +81,7 @@ ChromeRendererPepperHostFactory::CreateResourceHost( +@@ -42,6 +45,7 @@ ChromeRendererPepperHostFactory::CreateResourceHost( return std::make_unique(host_, instance, resource); } } diff --git a/patches/chromium/picture-in-picture.patch b/patches/chromium/picture-in-picture.patch index 22bc937a11a4c..6db8209177164 100644 --- a/patches/chromium/picture-in-picture.patch +++ b/patches/chromium/picture-in-picture.patch @@ -8,50 +8,11 @@ chrome's generated resources for our own. This updates the #include so that we don't get errors for Chrome's generated resources, which are non-existent because we don't generate them in our build. -diff --git a/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc b/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc -index 063cbf00a7ae871d426cef5cec00aa379c3ace11..444d3cc2e1b00a62f382232d3d2eccdd481abf11 100644 ---- a/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc -+++ b/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc -@@ -5,7 +5,7 @@ - #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h" - - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" - #include "ui/gfx/color_palette.h" -diff --git a/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc b/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc -index 648e199cb015155ba84cf1c846cf6d2a16858007..294bfb625d1155e640eeeb37bea597dc2d980e58 100644 ---- a/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc -+++ b/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc -@@ -5,7 +5,7 @@ - #include "chrome/browser/ui/views/overlay/back_to_tab_label_button.h" - - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "third_party/skia/include/core/SkColor.h" - #include "ui/base/cursor/cursor.h" - #include "ui/base/l10n/l10n_util.h" -diff --git a/chrome/browser/ui/views/overlay/close_image_button.cc b/chrome/browser/ui/views/overlay/close_image_button.cc -index 0c1fa8676d00240e60ddd037664a409d1c9619dd..64d21f1878c3433324fc61353a10ee21d59c0b47 100644 ---- a/chrome/browser/ui/views/overlay/close_image_button.cc -+++ b/chrome/browser/ui/views/overlay/close_image_button.cc -@@ -6,7 +6,7 @@ - - #include "build/chromeos_buildflags.h" - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" - #include "ui/gfx/color_palette.h" diff --git a/chrome/browser/ui/views/overlay/document_overlay_window_views.cc b/chrome/browser/ui/views/overlay/document_overlay_window_views.cc -index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d42815d9f4 100644 +index be17e30aa831282c4be52e788d67993d47eba5df..d5c3988af5be1d9e89330eb5c5195f9b94d13ffc 100644 --- a/chrome/browser/ui/views/overlay/document_overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/document_overlay_window_views.cc -@@ -20,6 +20,7 @@ +@@ -15,15 +15,19 @@ #include "base/timer/timer.h" #include "build/build_config.h" #include "chrome/app/vector_icons/vector_icons.h" @@ -59,24 +20,19 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 #include "chrome/browser/command_updater_delegate.h" #include "chrome/browser/command_updater_impl.h" #include "chrome/browser/profiles/profile.h" -@@ -28,14 +29,15 @@ + #include "chrome/browser/themes/theme_service.h" + #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" ++#endif + #include "chrome/browser/ui/color/chrome_color_id.h" ++#if 0 #include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" +#endif #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h" #include "chrome/browser/ui/views/overlay/close_image_button.h" #include "chrome/browser/ui/views/overlay/resize_handle_button.h" --#include "chrome/grit/generated_resources.h" - #include "components/omnibox/browser/location_bar_model_impl.h" - #include "components/vector_icons/vector_icons.h" - #include "content/public/browser/document_picture_in_picture_window_controller.h" - #include "content/public/browser/web_contents.h" -+#include "electron/grit/electron_resources.h" - #include "content/public/common/content_constants.h" - #include "media/base/media_switches.h" - #include "media/base/video_util.h" -@@ -57,7 +59,7 @@ +@@ -57,7 +61,7 @@ #include "ui/aura/window.h" #endif @@ -85,7 +41,7 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 #include "chrome/browser/shell_integration_win.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" -@@ -91,7 +93,7 @@ T* AddChildView(std::vector>* views, +@@ -109,7 +113,7 @@ END_METADATA } // namespace OverlayLocationBarViewProxy::~OverlayLocationBarViewProxy() = default; @@ -94,7 +50,7 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 class OverlayLocationBarViewImpl : public OverlayLocationBarViewProxy, public ChromeLocationBarModelDelegate, public LocationBarView::Delegate, -@@ -149,7 +151,7 @@ class OverlayLocationBarViewImpl : public OverlayLocationBarViewProxy, +@@ -167,7 +171,7 @@ class OverlayLocationBarViewImpl : public OverlayLocationBarViewProxy, const std::unique_ptr location_bar_model_; CommandUpdaterImpl command_updater_; }; @@ -103,7 +59,7 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 // static std::unique_ptr DocumentOverlayWindowViews::Create( content::DocumentPictureInPictureWindowController* controller, -@@ -185,7 +187,7 @@ std::unique_ptr DocumentOverlayWindowViews::Create( +@@ -203,7 +207,7 @@ std::unique_ptr DocumentOverlayWindowViews::Create( overlay_window->Init(std::move(params)); overlay_window->OnRootViewReady(); @@ -112,7 +68,7 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 std::wstring app_user_model_id; Browser* browser = chrome::FindBrowserWithWebContents(controller->GetWebContents()); -@@ -260,12 +262,6 @@ views::View* DocumentOverlayWindowViews::GetControlsContainerView() const { +@@ -278,12 +282,6 @@ views::View* DocumentOverlayWindowViews::GetControlsContainerView() const { return controls_container_view_; } @@ -125,7 +81,7 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 void DocumentOverlayWindowViews::SetUpViews() { // The window content consists of the fixed-height controls_container_view at // the top which is a box layout, and the remainder of the view is filled with -@@ -281,6 +277,7 @@ void DocumentOverlayWindowViews::SetUpViews() { +@@ -299,6 +297,7 @@ void DocumentOverlayWindowViews::SetUpViews() { // +-------------------------------------+ content::WebContents* pip_contents = controller_->GetChildWebContents(); @@ -133,7 +89,7 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 auto* profile = Profile::FromBrowserContext(pip_contents->GetBrowserContext()); profile_for_theme_ = profile; -@@ -291,8 +288,8 @@ void DocumentOverlayWindowViews::SetUpViews() { +@@ -309,8 +308,8 @@ void DocumentOverlayWindowViews::SetUpViews() { location_bar_view_proxy_ = std::make_unique( profile, controller_->GetWebContents()); } @@ -145,10 +101,10 @@ index d12f196f2e7b1a4b3936af2cb16d872e91785fe4..4a015d21cf27b975c87d91d2149555d4 web_view->SetWebContents(pip_contents); diff --git a/chrome/browser/ui/views/overlay/document_overlay_window_views.h b/chrome/browser/ui/views/overlay/document_overlay_window_views.h -index 86d385842501d28b5eb42f841822294eb597e6ed..43c19dfa6ec6b48f8694636cc184dd616e5d6aca 100644 +index b2b178ccadce82f8d4ec8e5a6dafe1c67bcecd74..603d82a461c4c443ac26c85a46fbd866a42237e6 100644 --- a/chrome/browser/ui/views/overlay/document_overlay_window_views.h +++ b/chrome/browser/ui/views/overlay/document_overlay_window_views.h -@@ -55,7 +55,6 @@ class DocumentOverlayWindowViews : public OverlayWindowViews, +@@ -56,7 +56,6 @@ class DocumentOverlayWindowViews : public OverlayWindowViews, bool IsVisible() const override; void OnNativeWidgetMove() override; void OnNativeWidgetDestroyed() override; @@ -156,24 +112,11 @@ index 86d385842501d28b5eb42f841822294eb597e6ed..43c19dfa6ec6b48f8694636cc184dd61 // OverlayWindowViews bool ControlsHitTestContainsPoint(const gfx::Point& point) override; -diff --git a/chrome/browser/ui/views/overlay/hang_up_button.cc b/chrome/browser/ui/views/overlay/hang_up_button.cc -index 8e54570ea4c83483eedee4c781f0498ba07bc3dd..b1eb0b2f1a3dfb71e1f5d3917c67e66ac2b27d22 100644 ---- a/chrome/browser/ui/views/overlay/hang_up_button.cc -+++ b/chrome/browser/ui/views/overlay/hang_up_button.cc -@@ -4,7 +4,7 @@ - - #include "chrome/browser/ui/views/overlay/hang_up_button.h" - --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "components/vector_icons/vector_icons.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc -index d96a4937e6ff6bbf4311673b4c91e9f0e957832a..a06cae5f50eb671fc05bd3d41ae4d218a649e991 100644 +index 590d247e1136b9ac5f766a613e8d91916eb0dda4..453c358d210d48d21a237654143439f2065e98fe 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc -@@ -14,13 +14,15 @@ +@@ -14,9 +14,11 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "build/build_config.h" @@ -181,16 +124,11 @@ index d96a4937e6ff6bbf4311673b4c91e9f0e957832a..a06cae5f50eb671fc05bd3d41ae4d218 #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" --#include "chrome/grit/generated_resources.h" +#endif + #include "chrome/grit/generated_resources.h" + #include "chromeos/ui/base/chromeos_ui_constants.h" #include "components/vector_icons/vector_icons.h" - #include "content/public/browser/picture_in_picture_window_controller.h" - #include "content/public/browser/web_contents.h" -+#include "electron/grit/electron_resources.h" - #include "ui/base/hit_test.h" - #include "ui/display/display.h" - #include "ui/display/screen.h" -@@ -36,7 +38,7 @@ +@@ -37,7 +39,7 @@ #include "ui/aura/window.h" #endif @@ -199,86 +137,8 @@ index d96a4937e6ff6bbf4311673b4c91e9f0e957832a..a06cae5f50eb671fc05bd3d41ae4d218 #include "chrome/browser/shell_integration_win.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" -diff --git a/chrome/browser/ui/views/overlay/playback_image_button.cc b/chrome/browser/ui/views/overlay/playback_image_button.cc -index ad413df822af98f4f80a460c6e464cf5237d5ac4..821b75400a7a4921e59a414516739c6de5a66df7 100644 ---- a/chrome/browser/ui/views/overlay/playback_image_button.cc -+++ b/chrome/browser/ui/views/overlay/playback_image_button.cc -@@ -6,7 +6,7 @@ - - #include "chrome/app/vector_icons/vector_icons.h" - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "components/vector_icons/vector_icons.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" -diff --git a/chrome/browser/ui/views/overlay/resize_handle_button.cc b/chrome/browser/ui/views/overlay/resize_handle_button.cc -index 90c9dbbfa741da8cf72594738c1686b14e277663..34063436a7e8e36f624c1b86765fe886434df54a 100644 ---- a/chrome/browser/ui/views/overlay/resize_handle_button.cc -+++ b/chrome/browser/ui/views/overlay/resize_handle_button.cc -@@ -6,7 +6,7 @@ - - #include "chrome/app/vector_icons/vector_icons.h" - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "ui/base/hit_test.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" -diff --git a/chrome/browser/ui/views/overlay/skip_ad_label_button.cc b/chrome/browser/ui/views/overlay/skip_ad_label_button.cc -index ae3b37b13498d63b0bc8d7d66e228f974e1c4b4a..9a4e7de29921209a5a7807efeecb02e05f38692d 100644 ---- a/chrome/browser/ui/views/overlay/skip_ad_label_button.cc -+++ b/chrome/browser/ui/views/overlay/skip_ad_label_button.cc -@@ -5,7 +5,7 @@ - #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h" - - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" - #include "ui/gfx/color_palette.h" -diff --git a/chrome/browser/ui/views/overlay/toggle_camera_button.cc b/chrome/browser/ui/views/overlay/toggle_camera_button.cc -index c5254509559fd89a8831d69498e2f120416b08df..711490193ac7a9a122fe2b85661dd1a63d3a06ac 100644 ---- a/chrome/browser/ui/views/overlay/toggle_camera_button.cc -+++ b/chrome/browser/ui/views/overlay/toggle_camera_button.cc -@@ -5,7 +5,7 @@ - #include "chrome/browser/ui/views/overlay/toggle_camera_button.h" - - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "components/vector_icons/vector_icons.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" -diff --git a/chrome/browser/ui/views/overlay/toggle_microphone_button.cc b/chrome/browser/ui/views/overlay/toggle_microphone_button.cc -index 98d653475bf2aaa57bd11961df3697882a9a40d7..3870cad08c531a2a8b3f6ba84088065a0d31f033 100644 ---- a/chrome/browser/ui/views/overlay/toggle_microphone_button.cc -+++ b/chrome/browser/ui/views/overlay/toggle_microphone_button.cc -@@ -5,7 +5,7 @@ - #include "chrome/browser/ui/views/overlay/toggle_microphone_button.h" - - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "components/vector_icons/vector_icons.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" -diff --git a/chrome/browser/ui/views/overlay/track_image_button.cc b/chrome/browser/ui/views/overlay/track_image_button.cc -index d5690233eb85d9f2992ae90461c0d1fd83730d84..d32ee40d1dc7a0004d534540189179b240964888 100644 ---- a/chrome/browser/ui/views/overlay/track_image_button.cc -+++ b/chrome/browser/ui/views/overlay/track_image_button.cc -@@ -6,7 +6,7 @@ - - #include "chrome/app/vector_icons/vector_icons.h" - #include "chrome/browser/ui/views/overlay/constants.h" --#include "chrome/grit/generated_resources.h" -+#include "electron/grit/electron_resources.h" - #include "components/vector_icons/vector_icons.h" - #include "ui/base/l10n/l10n_util.h" - #include "ui/base/metadata/metadata_impl_macros.h" diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc -index d25bffe434d866760d1efc4dd972b6ba4946acd0..2819bcefb83b6b4cb10114b7ad1df881ccade58d 100644 +index 9ce062e48c356f2ac23feb97c31aabcac8610942..08c27dc6f54c9216098d29b6a5331483722517d2 100644 --- a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc @@ -15,9 +15,11 @@ @@ -290,22 +150,10 @@ index d25bffe434d866760d1efc4dd972b6ba4946acd0..2819bcefb83b6b4cb10114b7ad1df881 #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" +#endif + #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h" #include "chrome/browser/ui/views/overlay/back_to_tab_label_button.h" - #include "chrome/browser/ui/views/overlay/close_image_button.h" -@@ -28,10 +30,10 @@ - #include "chrome/browser/ui/views/overlay/toggle_camera_button.h" - #include "chrome/browser/ui/views/overlay/toggle_microphone_button.h" - #include "chrome/browser/ui/views/overlay/track_image_button.h" --#include "chrome/grit/generated_resources.h" - #include "components/vector_icons/vector_icons.h" - #include "content/public/browser/video_picture_in_picture_window_controller.h" - #include "content/public/browser/web_contents.h" -+#include "electron/grit/electron_resources.h" - #include "media/base/media_switches.h" - #include "media/base/video_util.h" - #include "third_party/skia/include/core/SkColor.h" -@@ -53,7 +55,7 @@ +@@ -56,7 +58,7 @@ #include "ui/aura/window.h" #endif @@ -314,7 +162,7 @@ index d25bffe434d866760d1efc4dd972b6ba4946acd0..2819bcefb83b6b4cb10114b7ad1df881 #include "chrome/browser/shell_integration_win.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" -@@ -127,7 +129,7 @@ std::unique_ptr VideoOverlayWindowViews::Create( +@@ -166,7 +168,7 @@ std::unique_ptr VideoOverlayWindowViews::Create( overlay_window->Init(std::move(params)); overlay_window->OnRootViewReady(); diff --git a/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch b/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch index a94e20661ddce..fdd22562281f6 100644 --- a/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch +++ b/patches/chromium/port_autofill_colors_to_the_color_pipeline.patch @@ -8,13 +8,19 @@ needed in chromium but our autofill implementation uses them. This patch can be our autofill implementation to work like Chromium's. diff --git a/ui/color/color_id.h b/ui/color/color_id.h -index 1b9518366ba6c44421a86565ea3eba80e14b6c43..203ac8902eda26262f4178985ee565874bf879b8 100644 +index 401c319799f6bc97845bd88a3f0211d2d6511274..db0d729b22b8ae22781b15de00507f14cc669b83 100644 --- a/ui/color/color_id.h +++ b/ui/color/color_id.h -@@ -121,6 +121,10 @@ - E_CPONLY(kColorPwaSecurityChipForegroundSecure) \ - E_CPONLY(kColorPwaToolbarBackground) \ - E_CPONLY(kColorPwaToolbarForeground) \ +@@ -129,6 +129,16 @@ + E_CPONLY(kColorOverlayScrollbarStrokeHoveredLight) \ + E_CPONLY(kColorProgressBar) \ + E_CPONLY(kColorProgressBarPaused) \ ++ E_CPONLY(kColorPwaSecurityChipForeground) \ ++ E_CPONLY(kColorPwaSecurityChipForegroundDangerous) \ ++ E_CPONLY(kColorPwaSecurityChipForegroundPolicyCert) \ ++ E_CPONLY(kColorPwaSecurityChipForegroundSecure) \ ++ E_CPONLY(kColorPwaToolbarBackground) \ ++ E_CPONLY(kColorPwaToolbarForeground) \ + E_CPONLY(kColorResultsTableNormalBackground) \ + E_CPONLY(kColorResultsTableHoveredBackground) \ + E_CPONLY(kColorResultsTableNormalText) \ @@ -22,7 +28,7 @@ index 1b9518366ba6c44421a86565ea3eba80e14b6c43..203ac8902eda26262f4178985ee56587 E_CPONLY(kColorSeparator) \ E_CPONLY(kColorShadowBase) \ E_CPONLY(kColorShadowValueAmbientShadowElevationSixteen) \ -@@ -173,6 +177,7 @@ +@@ -183,6 +193,7 @@ E_CPONLY(kColorTreeNodeForeground) \ E_CPONLY(kColorTreeNodeForegroundSelectedFocused) \ E_CPONLY(kColorTreeNodeForegroundSelectedUnfocused) \ @@ -31,13 +37,13 @@ index 1b9518366ba6c44421a86565ea3eba80e14b6c43..203ac8902eda26262f4178985ee56587 #if BUILDFLAG(IS_CHROMEOS) diff --git a/ui/color/ui_color_mixer.cc b/ui/color/ui_color_mixer.cc -index 1d8415814c6245e3f2dfd01de7a2de11f09cdc7a..6db48efe454820e242b862edbfaf4d40cf16eb9d 100644 +index ca33acaffdb3c3dbd8f5f1b7012b1013a983645e..ae5ca280a3965c5922f272fdbc45247fcc8a9750 100644 --- a/ui/color/ui_color_mixer.cc +++ b/ui/color/ui_color_mixer.cc -@@ -141,6 +141,17 @@ void AddUiColorMixer(ColorProvider* provider, - kColorPwaSecurityChipForeground}; - mixer[kColorPwaToolbarBackground] = {kColorEndpointBackground}; - mixer[kColorPwaToolbarForeground] = {kColorEndpointForeground}; +@@ -151,6 +151,17 @@ void AddUiColorMixer(ColorProvider* provider, + gfx::kGoogleGreyAlpha500); + mixer[kColorProgressBarPaused] = {kColorDisabledForeground}; + mixer[kColorProgressBar] = {kColorAccent}; + mixer[kColorResultsTableNormalBackground] = {SK_ColorWHITE}; + mixer[kColorResultsTableHoveredBackground] = + SetAlpha(kColorResultsTableNormalText, 0x0D); @@ -52,7 +58,7 @@ index 1d8415814c6245e3f2dfd01de7a2de11f09cdc7a..6db48efe454820e242b862edbfaf4d40 mixer[kColorSeparator] = {kColorMidground}; mixer[kColorShadowBase] = {dark_mode ? SK_ColorBLACK : gfx::kGoogleGrey800}; mixer[kColorShadowValueAmbientShadowElevationThree] = -@@ -216,6 +227,7 @@ void AddUiColorMixer(ColorProvider* provider, +@@ -232,6 +243,7 @@ void AddUiColorMixer(ColorProvider* provider, mixer[kColorTreeNodeForegroundSelectedFocused] = {kColorTreeNodeForeground}; mixer[kColorTreeNodeForegroundSelectedUnfocused] = { kColorTreeNodeForegroundSelectedFocused}; diff --git a/patches/chromium/printing.patch b/patches/chromium/printing.patch index 6593266db987f..07f0ca2501605 100644 --- a/patches/chromium/printing.patch +++ b/patches/chromium/printing.patch @@ -10,11 +10,34 @@ majority of changes originally come from these PRs: This patch also fixes callback for manual user cancellation and success. +diff --git a/BUILD.gn b/BUILD.gn +index 645819d78ca8526340714f05acc9f1819e72c4e3..86f6cfd19586f1d352d6a91c3d76b7323ccf26fe 100644 +--- a/BUILD.gn ++++ b/BUILD.gn +@@ -987,7 +987,6 @@ if (is_win) { + "//media:media_unittests", + "//media/midi:midi_unittests", + "//net:net_unittests", +- "//printing:printing_unittests", + "//sql:sql_unittests", + "//third_party/breakpad:symupload($host_toolchain)", + "//ui/base:ui_base_unittests", +@@ -996,6 +995,10 @@ if (is_win) { + "//ui/views:views_unittests", + "//url:url_unittests", + ] ++ ++ if (enable_basic_printing) { ++ deps += [ "//printing:printing_unittests" ] ++ } + } + } + diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc -index 8d40bbf98d4d58704f118cb42039b0956a9f6639..06196c0fa02012a5faa82471bd39fac087918f54 100644 +index 331a084371402b5a2440b5d60feac8f0189e84b9..6755d1f497cef4deea6b83df1d8720dcf54817e9 100644 --- a/chrome/browser/printing/print_job.cc +++ b/chrome/browser/printing/print_job.cc -@@ -89,6 +89,7 @@ bool PrintWithReducedRasterization(PrefService* prefs) { +@@ -90,6 +90,7 @@ bool PrintWithReducedRasterization(PrefService* prefs) { return base::FeatureList::IsEnabled(features::kPrintWithReducedRasterization); } @@ -22,7 +45,7 @@ index 8d40bbf98d4d58704f118cb42039b0956a9f6639..06196c0fa02012a5faa82471bd39fac0 PrefService* GetPrefsForWebContents(content::WebContents* web_contents) { // TODO(thestig): Figure out why crbug.com/1083911 occurred, which is likely // because `web_contents` was null. As a result, this section has many more -@@ -97,6 +98,7 @@ PrefService* GetPrefsForWebContents(content::WebContents* web_contents) { +@@ -98,6 +99,7 @@ PrefService* GetPrefsForWebContents(content::WebContents* web_contents) { web_contents ? web_contents->GetBrowserContext() : nullptr; return context ? Profile::FromBrowserContext(context)->GetPrefs() : nullptr; } @@ -30,7 +53,7 @@ index 8d40bbf98d4d58704f118cb42039b0956a9f6639..06196c0fa02012a5faa82471bd39fac0 #endif // BUILDFLAG(IS_WIN) -@@ -356,8 +358,10 @@ void PrintJob::StartPdfToEmfConversion( +@@ -351,8 +353,10 @@ void PrintJob::StartPdfToEmfConversion( const PrintSettings& settings = document()->settings(); @@ -42,7 +65,7 @@ index 8d40bbf98d4d58704f118cb42039b0956a9f6639..06196c0fa02012a5faa82471bd39fac0 using RenderMode = PdfRenderSettings::Mode; RenderMode mode = print_with_reduced_rasterization -@@ -447,8 +451,10 @@ void PrintJob::StartPdfToPostScriptConversion( +@@ -442,8 +446,10 @@ void PrintJob::StartPdfToPostScriptConversion( if (ps_level2) { mode = PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2; } else { @@ -54,25 +77,11 @@ index 8d40bbf98d4d58704f118cb42039b0956a9f6639..06196c0fa02012a5faa82471bd39fac0 ? PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3_WITH_TYPE42_FONTS : PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3; } -diff --git a/chrome/browser/printing/print_job.h b/chrome/browser/printing/print_job.h -index 650c78f16c812170aeda99d75300ff88f47347a0..c33ce445a23f97a744db3a4ac30ef471c359553b 100644 ---- a/chrome/browser/printing/print_job.h -+++ b/chrome/browser/printing/print_job.h -@@ -261,6 +261,9 @@ class JobEventDetails : public base::RefCountedThreadSafe { - public: - // Event type. - enum Type { -+ // Print... dialog box has been closed with CANCEL button. -+ USER_INIT_CANCELED, -+ - // A new document started printing. - NEW_DOC, - diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc -index 7dbb9aea759e4a80a4ef3133eeffcd952bbe6d50..62fbaa0e24dff2037f47ef4ccf09993aa79b3ef8 100644 +index f0d4596f0e95391e752c48dc6ac12f76397c27f1..b7313ce8037c88aa5b8826dc2edcb0dfa4ebee46 100644 --- a/chrome/browser/printing/print_job_worker.cc +++ b/chrome/browser/printing/print_job_worker.cc -@@ -20,13 +20,13 @@ +@@ -20,7 +20,6 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/printing/print_job.h" @@ -80,14 +89,15 @@ index 7dbb9aea759e4a80a4ef3133eeffcd952bbe6d50..62fbaa0e24dff2037f47ef4ccf09993a #include "components/crash/core/common/crash_keys.h" #include "components/device_event_log/device_event_log.h" #include "content/public/browser/browser_task_traits.h" - #include "content/public/browser/browser_thread.h" +@@ -28,6 +27,7 @@ + #include "content/public/browser/global_routing_id.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -+#include "electron/grit/electron_resources.h" ++#include "chrome/grit/generated_resources.h" #include "printing/backend/print_backend.h" #include "printing/buildflags/buildflags.h" #include "printing/mojom/print.mojom.h" -@@ -239,16 +239,21 @@ void PrintJobWorker::UpdatePrintSettings(base::Value new_settings, +@@ -208,16 +208,19 @@ void PrintJobWorker::SetSettings(base::Value::Dict new_settings, #endif // BUILDFLAG(IS_LINUX) && defined(USE_CUPS) } @@ -101,22 +111,20 @@ index 7dbb9aea759e4a80a4ef3133eeffcd952bbe6d50..62fbaa0e24dff2037f47ef4ccf09993a - result = printing_context_->UpdatePrintSettings(std::move(new_settings)); + // Reset settings from previous print job + printing_context_->ResetSettings(); -+ mojom::ResultCode get_default_result = printing_context_->UseDefaultSettings(); -+ if (get_default_result == mojom::ResultCode::kSuccess) { -+ mojom::ResultCode update_result = -+ printing_context_->UpdatePrintSettings(std::move(new_settings)); -+ GetSettingsDone(std::move(callback), update_result); -+ } ++ mojom::ResultCode result_code = printing_context_->UseDefaultSettings(); ++ if (result_code == mojom::ResultCode::kSuccess) ++ result_code = printing_context_->UpdatePrintSettings(std::move(new_settings)); ++ GetSettingsDone(std::move(callback), result_code); } - GetSettingsDone(std::move(callback), result); } #if BUILDFLAG(IS_CHROMEOS) diff --git a/chrome/browser/printing/print_job_worker_oop.cc b/chrome/browser/printing/print_job_worker_oop.cc -index 457749cf31578666304c30a5df1b8428629caafe..21c4a76411ee06775fb5bbb2d5a2ac17911d1c2a 100644 +index 398d59a0ebad165981e9e96b29ffc672e4b841eb..e420d87ef0e90cddb740ac4b24f92519a6eb3347 100644 --- a/chrome/browser/printing/print_job_worker_oop.cc +++ b/chrome/browser/printing/print_job_worker_oop.cc -@@ -225,7 +225,7 @@ void PrintJobWorkerOop::OnFailure() { +@@ -356,7 +356,7 @@ void PrintJobWorkerOop::OnFailure() { } void PrintJobWorkerOop::ShowErrorDialog() { @@ -126,31 +134,34 @@ index 457749cf31578666304c30a5df1b8428629caafe..21c4a76411ee06775fb5bbb2d5a2ac17 void PrintJobWorkerOop::UnregisterServiceManagerClient() { diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc -index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd0828b8a1 100644 +index 8f4cb7f50dd34c4ef49022242c4b93d703a508a2..d9183b6c1d84a4685f38e84071eb25f26cd28867 100644 --- a/chrome/browser/printing/print_view_manager_base.cc +++ b/chrome/browser/printing/print_view_manager_base.cc -@@ -29,10 +29,10 @@ +@@ -30,8 +30,6 @@ #include "chrome/browser/printing/print_view_manager_common.h" #include "chrome/browser/printing/printer_query.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/simple_message_box.h" -#include "chrome/browser/ui/webui/print_preview/printer_handler.h" #include "chrome/common/pref_names.h" -+#if 0 #include "chrome/grit/generated_resources.h" -+#endif #include "components/prefs/pref_service.h" - #include "components/printing/browser/print_composite_client.h" - #include "components/printing/browser/print_manager_utils.h" -@@ -47,6 +47,7 @@ - #include "content/public/browser/render_process_host.h" - #include "content/public/browser/render_view_host.h" - #include "content/public/browser/web_contents.h" -+#include "electron/grit/electron_resources.h" - #include "mojo/public/cpp/system/buffer.h" - #include "printing/buildflags/buildflags.h" - #include "printing/metafile_skia.h" -@@ -81,6 +82,8 @@ using PrintSettingsCallback = +@@ -82,10 +80,23 @@ namespace printing { + + namespace { + ++std::string PrintReasonFromPrintStatus(PrintViewManager::PrintStatus status) { ++ if (status == PrintViewManager::PrintStatus::kInvalid) { ++ return "Invalid printer settings"; ++ } else if (status == PrintViewManager::PrintStatus::kCanceled) { ++ return "Print job canceled"; ++ } else if (status == PrintViewManager::PrintStatus::kFailed) { ++ return "Print job failed"; ++ } ++ return ""; ++} ++ + using PrintSettingsCallback = base::OnceCallback)>; void ShowWarningMessageBox(const std::u16string& message) { @@ -159,16 +170,16 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd // Runs always on the UI thread. static bool is_dialog_shown = false; if (is_dialog_shown) -@@ -89,6 +92,7 @@ void ShowWarningMessageBox(const std::u16string& message) { +@@ -94,6 +105,7 @@ void ShowWarningMessageBox(const std::u16string& message) { base::AutoReset auto_reset(&is_dialog_shown, true); chrome::ShowWarningMessageBox(nullptr, std::u16string(), message); +#endif } - #if BUILDFLAG(ENABLE_PRINT_PREVIEW) -@@ -188,7 +192,9 @@ void UpdatePrintSettingsReplyOnIO( - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + void OnDidGetDefaultPrintSettings( +@@ -143,7 +155,9 @@ void OnDidUpdatePrintSettings( + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(printer_query); mojom::PrintPagesParamsPtr params = CreateEmptyPrintPagesParamsPtr(); - if (printer_query->last_status() == mojom::ResultCode::kSuccess) { @@ -178,26 +189,25 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd RenderParamsFromPrintSettings(printer_query->settings(), params->params.get()); params->params->document_cookie = printer_query->cookie(); -@@ -241,6 +247,7 @@ void ScriptedPrintReplyOnIO( +@@ -171,6 +185,7 @@ void OnDidScriptedPrint( mojom::PrintManagerHost::ScriptedPrintCallback callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); mojom::PrintPagesParamsPtr params = CreateEmptyPrintPagesParamsPtr(); + if (printer_query->last_status() == mojom::ResultCode::kSuccess && printer_query->settings().dpi()) { RenderParamsFromPrintSettings(printer_query->settings(), -@@ -250,8 +257,9 @@ void ScriptedPrintReplyOnIO( +@@ -180,7 +195,8 @@ void OnDidScriptedPrint( } bool has_valid_cookie = params->params->document_cookie; bool has_dpi = !params->params->dpi.IsEmpty(); +- std::move(callback).Run(std::move(params)); + bool canceled = printer_query->last_status() == mojom::ResultCode::kCanceled; - content::GetUIThreadTaskRunner({})->PostTask( -- FROM_HERE, base::BindOnce(std::move(callback), std::move(params))); -+ FROM_HERE, base::BindOnce(std::move(callback), std::move(params), canceled)); ++ std::move(callback).Run(std::move(params), canceled); if (has_dpi && has_valid_cookie) { queue->QueuePrinterQuery(std::move(printer_query)); -@@ -290,12 +298,14 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) +@@ -195,12 +211,14 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) : PrintManager(web_contents), queue_(g_browser_process->print_job_manager()->queue()) { DCHECK(queue_); @@ -212,30 +222,29 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd } PrintViewManagerBase::~PrintViewManagerBase() { -@@ -303,7 +313,10 @@ PrintViewManagerBase::~PrintViewManagerBase() { +@@ -208,7 +226,10 @@ PrintViewManagerBase::~PrintViewManagerBase() { DisconnectFromCurrentPrintJob(); } -bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) { +bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh, + bool silent, -+ base::Value settings, ++ base::Value::Dict settings, + CompletionCallback callback) { // Remember the ID for `rfh`, to enable checking that the `RenderFrameHost` // is still valid after a possible inner message loop runs in // `DisconnectFromCurrentPrintJob()`. -@@ -326,7 +339,9 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) { - // go in `ReleasePrintJob()`. +@@ -236,6 +257,9 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) { + #endif SetPrintingRFH(rfh); -- GetPrintRenderFrame(rfh)->PrintRequestedPages(); + callback_ = std::move(callback); + + GetPrintRenderFrame(rfh)->PrintRequestedPages(silent, std::move(settings)); - - for (auto& observer : GetObservers()) - observer.OnPrintNow(rfh); -@@ -470,7 +485,8 @@ void PrintViewManagerBase::GetDefaultPrintSettingsReply( + CompletePrintNow(rfh); + return true; + } +@@ -395,7 +419,8 @@ void PrintViewManagerBase::GetDefaultPrintSettingsReply( void PrintViewManagerBase::ScriptedPrintReply( ScriptedPrintCallback callback, int process_id, @@ -244,8 +253,8 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd + bool canceled) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!content::RenderProcessHost::FromID(process_id)) { -@@ -478,16 +494,19 @@ void PrintViewManagerBase::ScriptedPrintReply( + #if BUILDFLAG(ENABLE_OOP_PRINTING) +@@ -410,8 +435,11 @@ void PrintViewManagerBase::ScriptedPrintReply( return; } @@ -258,34 +267,33 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd } void PrintViewManagerBase::UpdatePrintingEnabled() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // The Unretained() is safe because ForEachFrame() is synchronous. -- web_contents()->ForEachFrame(base::BindRepeating( -- &PrintViewManagerBase::SendPrintingEnabled, base::Unretained(this), -- printing_enabled_.GetValue())); -+ web_contents()->ForEachFrame( -+ base::BindRepeating(&PrintViewManagerBase::SendPrintingEnabled, +@@ -419,8 +447,7 @@ void PrintViewManagerBase::UpdatePrintingEnabled() { + // The Unretained() is safe because ForEachRenderFrameHost() is synchronous. + web_contents()->GetPrimaryMainFrame()->ForEachRenderFrameHost( + base::BindRepeating(&PrintViewManagerBase::SendPrintingEnabled, +- base::Unretained(this), +- printing_enabled_.GetValue())); + base::Unretained(this), true)); } void PrintViewManagerBase::NavigationStopped() { -@@ -601,12 +620,13 @@ void PrintViewManagerBase::DidPrintDocument( +@@ -536,11 +563,14 @@ void PrintViewManagerBase::DidPrintDocument( void PrintViewManagerBase::GetDefaultPrintSettings( GetDefaultPrintSettingsCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +#if 0 // Printing is always enabled. ++ if (!printing_enabled_.GetValue()) { GetDefaultPrintSettingsReply(std::move(callback), mojom::PrintParams::New()); return; } -- +#endif - content::RenderFrameHost* render_frame_host = GetCurrentTargetFrame(); - auto callback_wrapper = - base::BindOnce(&PrintViewManagerBase::GetDefaultPrintSettingsReply, -@@ -624,18 +644,20 @@ void PrintViewManagerBase::UpdatePrintSettings( - base::Value job_settings, + #if BUILDFLAG(ENABLE_OOP_PRINTING) + if (printing::features::kEnableOopPrintDriversJobPrint.Get() && + !service_manager_client_id_.has_value()) { +@@ -578,18 +608,20 @@ void PrintViewManagerBase::UpdatePrintSettings( + base::Value::Dict job_settings, UpdatePrintSettingsCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +#if 0 // Printing is always enabled. @@ -296,7 +304,7 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd } - +#endif - if (!job_settings.FindIntKey(kSettingPrinterType)) { + if (!job_settings.FindInt(kSettingPrinterType)) { UpdatePrintSettingsReply(std::move(callback), CreateEmptyPrintPagesParamsPtr(), false); return; @@ -306,15 +314,15 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd content::BrowserContext* context = web_contents() ? web_contents()->GetBrowserContext() : nullptr; PrefService* prefs = -@@ -645,6 +667,7 @@ void PrintViewManagerBase::UpdatePrintSettings( +@@ -599,6 +631,7 @@ void PrintViewManagerBase::UpdatePrintSettings( if (value > 0) - job_settings.SetIntKey(kSettingRasterizePdfDpi, value); + job_settings.Set(kSettingRasterizePdfDpi, value); } +#endif auto callback_wrapper = base::BindOnce(&PrintViewManagerBase::UpdatePrintSettingsReply, -@@ -670,7 +693,7 @@ void PrintViewManagerBase::ScriptedPrint(mojom::ScriptedPrintParamsPtr params, +@@ -630,14 +663,14 @@ void PrintViewManagerBase::ScriptedPrint(mojom::ScriptedPrintParamsPtr params, // didn't happen for some reason. bad_message::ReceivedBadMessage( render_process_host, bad_message::PVMB_SCRIPTED_PRINT_FENCED_FRAME); @@ -322,53 +330,74 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd + std::move(callback).Run(CreateEmptyPrintPagesParamsPtr(), false); return; } - int process_id = render_process_host->GetID(); -@@ -693,7 +716,6 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie) { - PrintManager::PrintingFailed(cookie); + #if BUILDFLAG(ENABLE_OOP_PRINTING) + if (printing::features::kEnableOopPrintDriversJobPrint.Get() && + !service_manager_client_id_.has_value()) { + // Renderer process has requested settings outside of the expected setup. +- std::move(callback).Run(CreateEmptyPrintPagesParamsPtr()); ++ std::move(callback).Run(CreateEmptyPrintPagesParamsPtr(), false); + return; + } + #endif +@@ -675,7 +708,6 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie, + PrintManager::PrintingFailed(cookie, reason); - #if BUILDFLAG(ENABLE_PRINT_PREVIEW) + #if !BUILDFLAG(IS_ANDROID) // Android does not implement this function. - ShowPrintErrorDialog(); #endif ReleasePrinterQuery(); -@@ -708,6 +730,11 @@ void PrintViewManagerBase::RemoveObserver(Observer& observer) { +@@ -690,6 +722,11 @@ void PrintViewManagerBase::RemoveObserver(Observer& observer) { } void PrintViewManagerBase::ShowInvalidPrinterSettingsError() { + if (!callback_.is_null()) { -+ std::string cb_str = "Invalid printer settings"; -+ std::move(callback_).Run(printing_succeeded_, cb_str); ++ printing_status_ = PrintStatus::kInvalid; ++ TerminatePrintJob(true); + } + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&ShowWarningMessageBox, l10n_util::GetStringUTF16( -@@ -718,8 +745,10 @@ void PrintViewManagerBase::RenderFrameHostStateChanged( +@@ -700,10 +737,12 @@ void PrintViewManagerBase::RenderFrameHostStateChanged( content::RenderFrameHost* render_frame_host, content::RenderFrameHost::LifecycleState /*old_state*/, content::RenderFrameHost::LifecycleState new_state) { -+#if 0 // Printing is always enabled. - if (new_state == content::RenderFrameHost::LifecycleState::kActive) ++#if 0 + if (new_state == content::RenderFrameHost::LifecycleState::kActive && + render_frame_host->GetProcess()->IsPdf()) { SendPrintingEnabled(printing_enabled_.GetValue(), render_frame_host); + } +#endif } void PrintViewManagerBase::DidStartLoading() { -@@ -779,6 +808,11 @@ void PrintViewManagerBase::OnJobDone() { - ReleasePrintJob(); - } - -+void PrintViewManagerBase::UserInitCanceled() { -+ printing_canceled_ = true; +@@ -759,7 +798,12 @@ void PrintViewManagerBase::OnJobDone() { + // Printing is done, we don't need it anymore. + // print_job_->is_job_pending() may still be true, depending on the order + // of object registration. +- printing_succeeded_ = true; ++ printing_status_ = PrintStatus::kSucceeded; + ReleasePrintJob(); +} + - void PrintViewManagerBase::OnFailed() { - TerminatePrintJob(true); ++void PrintViewManagerBase::UserInitCanceled() { ++ printing_status_ = PrintStatus::kCanceled; + ReleasePrintJob(); } -@@ -840,7 +874,10 @@ bool PrintViewManagerBase::CreateNewPrintJob( - // Disconnect the current |print_job_|. +@@ -773,7 +817,7 @@ bool PrintViewManagerBase::RenderAllMissingPagesNow() { + + // Is the document already complete? + if (print_job_->document() && print_job_->document()->IsComplete()) { +- printing_succeeded_ = true; ++ printing_status_ = PrintStatus::kSucceeded; + return true; + } + +@@ -821,7 +865,10 @@ bool PrintViewManagerBase::CreateNewPrintJob( + + // Disconnect the current `print_job_`. auto weak_this = weak_ptr_factory_.GetWeakPtr(); - DisconnectFromCurrentPrintJob(); + if (callback_.is_null()) { @@ -378,21 +407,37 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd if (!weak_this) return false; -@@ -915,6 +952,13 @@ void PrintViewManagerBase::ReleasePrintJob() { - content::RenderFrameHost* rfh = printing_rfh_; - printing_rfh_ = nullptr; +@@ -842,7 +889,7 @@ bool PrintViewManagerBase::CreateNewPrintJob( + #endif + print_job_->AddObserver(*this); + +- printing_succeeded_ = false; ++ printing_status_ = PrintStatus::kFailed; + return true; + } + +@@ -902,6 +949,11 @@ void PrintViewManagerBase::ReleasePrintJob() { + } + #endif + if (!callback_.is_null()) { -+ std::string cb_str = ""; -+ if (!printing_succeeded_) -+ cb_str = printing_canceled_ ? "canceled" : "failed"; -+ std::move(callback_).Run(printing_succeeded_, cb_str); ++ bool success = printing_status_ == PrintStatus::kSucceeded; ++ std::move(callback_).Run(success, PrintReasonFromPrintStatus(printing_status_)); + } + if (!print_job_) return; -@@ -964,7 +1008,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() { +@@ -909,7 +961,7 @@ void PrintViewManagerBase::ReleasePrintJob() { + // printing_rfh_ should only ever point to a RenderFrameHost with a live + // RenderFrame. + DCHECK(rfh->IsRenderFrameLive()); +- GetPrintRenderFrame(rfh)->PrintingDone(printing_succeeded_); ++ GetPrintRenderFrame(rfh)->PrintingDone(printing_status_ == PrintStatus::kSucceeded); + } + + print_job_->RemoveObserver(*this); +@@ -951,7 +1003,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() { } bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) { @@ -401,11 +446,20 @@ index 9ed04fffa69c23834dec23836532dc3cc71299a6..2e332aab1d316569998f8d349af386bd return true; if (!cookie) { +@@ -1059,7 +1111,7 @@ void PrintViewManagerBase::SendPrintingEnabled(bool enabled, + } + + void PrintViewManagerBase::CompletePrintNow(content::RenderFrameHost* rfh) { +- GetPrintRenderFrame(rfh)->PrintRequestedPages(); ++ GetPrintRenderFrame(rfh)->PrintRequestedPages(/*silent=*/true, /*job_settings=*/base::Value::Dict()); + + for (auto& observer : GetObservers()) + observer.OnPrintNow(rfh); diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h -index 2661776307f773ac8f2c62529ec86349b045ee8f..4fa8f358ee59baed32ef4fd0684d010256206a54 100644 +index 871e00c49028ccf58d207f904c22e0107f3c2b65..c9b136ab165410eb533f84254454dac0b6674f14 100644 --- a/chrome/browser/printing/print_view_manager_base.h +++ b/chrome/browser/printing/print_view_manager_base.h -@@ -37,6 +37,8 @@ namespace printing { +@@ -42,6 +42,8 @@ namespace printing { class PrintQueriesQueue; class PrinterQuery; @@ -414,27 +468,42 @@ index 2661776307f773ac8f2c62529ec86349b045ee8f..4fa8f358ee59baed32ef4fd0684d0102 // Base class for managing the print commands for a WebContents. class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { public: -@@ -58,7 +60,10 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { +@@ -65,7 +67,10 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { // Prints the current document immediately. Since the rendering is // asynchronous, the actual printing will not be completed on the return of // this function. Returns false if printing is impossible at the moment. - virtual bool PrintNow(content::RenderFrameHost* rfh); + virtual bool PrintNow(content::RenderFrameHost* rfh, -+ bool silent, -+ base::Value settings, -+ CompletionCallback callback); ++ bool silent = true, ++ base::Value::Dict settings = {}, ++ CompletionCallback callback = {}); #if BUILDFLAG(ENABLE_PRINT_PREVIEW) // Prints the document in `print_data` with settings specified in -@@ -106,6 +111,7 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { - ScriptedPrintCallback callback) override; +@@ -123,6 +128,7 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { void ShowInvalidPrinterSettingsError() override; - void PrintingFailed(int32_t cookie) override; + void PrintingFailed(int32_t cookie, + mojom::PrintFailureReason reason) override; + void UserInitCanceled(); // Adds and removes observers for `PrintViewManagerBase` events. The order in // which notifications are sent to observers is undefined. Observers must be -@@ -193,7 +199,8 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { +@@ -130,6 +136,14 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { + void AddObserver(Observer& observer); + void RemoveObserver(Observer& observer); + ++ enum class PrintStatus { ++ kSucceeded, ++ kCanceled, ++ kFailed, ++ kInvalid, ++ kUnknown ++ }; ++ + protected: + explicit PrintViewManagerBase(content::WebContents* web_contents); + +@@ -251,7 +265,8 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { // Runs `callback` with `params` to reply to ScriptedPrint(). void ScriptedPrintReply(ScriptedPrintCallback callback, int process_id, @@ -444,7 +513,7 @@ index 2661776307f773ac8f2c62529ec86349b045ee8f..4fa8f358ee59baed32ef4fd0684d0102 // Requests the RenderView to render all the missing pages for the print job. // No-op if no print job is pending. Returns true if at least one page has -@@ -248,9 +255,15 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { +@@ -324,8 +339,11 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer { // The current RFH that is printing with a system printing dialog. raw_ptr printing_rfh_ = nullptr; @@ -452,28 +521,51 @@ index 2661776307f773ac8f2c62529ec86349b045ee8f..4fa8f358ee59baed32ef4fd0684d0102 + CompletionCallback callback_; + // Indication of success of the print job. - bool printing_succeeded_ = false; +- bool printing_succeeded_ = false; ++ PrintStatus printing_status_ = PrintStatus::kUnknown; -+ // Indication of whether the print job was manually canceled -+ bool printing_canceled_ = false; -+ // Set while running an inner message loop inside RenderAllMissingPagesNow(). // This means we are _blocking_ until all the necessary pages have been - // rendered or the print settings are being loaded. +diff --git a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc +index f3c3f85edb19489d079dc93411be64828ae581e2..ff303dcbc034cd8f1530fe1543729e98d3035826 100644 +--- a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc ++++ b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc +@@ -21,7 +21,7 @@ FakePrintRenderFrame::FakePrintRenderFrame( + + FakePrintRenderFrame::~FakePrintRenderFrame() = default; + +-void FakePrintRenderFrame::PrintRequestedPages() {} ++void FakePrintRenderFrame::PrintRequestedPages(bool /*silent*/, ::base::Value::Dict /*settings*/) {} + + void FakePrintRenderFrame::PrintWithParams(mojom::PrintPagesParamsPtr params, + PrintWithParamsCallback callback) { +diff --git a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h +index 0e788384809f9f7218c6483822ffea08f86b4f79..c6f08845cb292ff406db5560c9a744dc7ab1c712 100644 +--- a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h ++++ b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h +@@ -25,7 +25,7 @@ class FakePrintRenderFrame : public mojom::PrintRenderFrame { + + private: + // printing::mojom::PrintRenderFrame: +- void PrintRequestedPages() override; ++ void PrintRequestedPages(bool silent, ::base::Value::Dict settings) override; + void PrintWithParams(mojom::PrintPagesParamsPtr params, + PrintWithParamsCallback callback) override; + void PrintForSystemDialog() override; diff --git a/components/printing/common/print.mojom b/components/printing/common/print.mojom -index 51ebcb4ae399018d3fd8566656596a7ef1f148af..c0fbff95137e2e5bccb9702a8cc858df2d989964 100644 +index 95d9f19082978772297cff1bcd9c5f73db50bd62..96fe7fbb54fe0908e2153d901c130b6a5c621522 100644 --- a/components/printing/common/print.mojom +++ b/components/printing/common/print.mojom -@@ -274,7 +274,7 @@ interface PrintPreviewUI { +@@ -285,7 +285,7 @@ union PrintWithParamsResult { interface PrintRenderFrame { // Tells the RenderFrame to switch the CSS to print media type, render every // requested page, and then switch back the CSS to display media type. - PrintRequestedPages(); + PrintRequestedPages(bool silent, mojo_base.mojom.DictionaryValue settings); - // Tells the RenderFrame to switch the CSS to print media type, render every - // requested page using the print preview document's frame/node, and then -@@ -341,7 +341,7 @@ interface PrintManagerHost { + // Requests the frame to be printed with specified parameters. This is used + // to programmatically produce PDF by request from the browser (e.g. over +@@ -368,7 +368,7 @@ interface PrintManagerHost { // Request the print settings from the user. This step is about showing // UI to the user to select the final print settings. [Sync] @@ -483,37 +575,37 @@ index 51ebcb4ae399018d3fd8566656596a7ef1f148af..c0fbff95137e2e5bccb9702a8cc858df // Tells the browser that there are invalid printer settings. ShowInvalidPrinterSettingsError(); diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc -index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cbd1345f33 100644 +index 2331b4db94bb6397616dc230498960860554787f..ade741255b9e0274252121ecc2ec68697429c8ad 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc -@@ -40,6 +40,7 @@ - #include "printing/metafile_skia.h" +@@ -42,6 +42,7 @@ #include "printing/mojom/print.mojom.h" + #include "printing/page_number.h" #include "printing/print_job_constants.h" +#include "printing/print_settings.h" #include "printing/units.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" -@@ -1259,7 +1260,8 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) { +@@ -1283,7 +1284,8 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) { if (!weak_this) return; - Print(web_frame, blink::WebNode(), PrintRequestType::kScripted); + Print(web_frame, blink::WebNode(), PrintRequestType::kScripted, -+ false /* silent */, base::DictionaryValue() /* new_settings */); ++ false /* silent */, base::Value::Dict() /* new_settings */); if (!weak_this) return; -@@ -1290,7 +1292,7 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver( +@@ -1314,7 +1316,7 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver( receivers_.Add(this, std::move(receiver)); } -void PrintRenderFrameHelper::PrintRequestedPages() { -+void PrintRenderFrameHelper::PrintRequestedPages(bool silent, base::Value settings) { ++void PrintRenderFrameHelper::PrintRequestedPages(bool silent, base::Value::Dict settings) { ScopedIPC scoped_ipc(weak_ptr_factory_.GetWeakPtr()); if (ipc_nesting_level_ > kAllowedIpcDepthForPrint) return; -@@ -1305,7 +1307,7 @@ void PrintRenderFrameHelper::PrintRequestedPages() { +@@ -1329,7 +1331,7 @@ void PrintRenderFrameHelper::PrintRequestedPages() { // plugin node and print that instead. auto plugin = delegate_->GetPdfElement(frame); @@ -522,17 +614,17 @@ index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cb if (!render_frame_gone_) frame->DispatchAfterPrintEvent(); -@@ -1336,7 +1338,8 @@ void PrintRenderFrameHelper::PrintForSystemDialog() { +@@ -1406,7 +1408,8 @@ void PrintRenderFrameHelper::PrintForSystemDialog() { } Print(frame, print_preview_context_.source_node(), - PrintRequestType::kRegular); + PrintRequestType::kRegular, false, -+ base::DictionaryValue()); ++ base::Value::Dict()); if (!render_frame_gone_) print_preview_context_.DispatchAfterPrintEvent(); // WARNING: |this| may be gone at this point. Do not do any more work here and -@@ -1383,6 +1386,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value settings) { +@@ -1455,6 +1458,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) { if (ipc_nesting_level_ > kAllowedIpcDepthForPrint) return; @@ -540,38 +632,38 @@ index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cb + print_preview_context_.InitWithFrame(frame); print_preview_context_.OnPrintPreview(); - if (print_preview_context_.IsForArc()) { -@@ -1920,7 +1925,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) { + #if BUILDFLAG(IS_CHROMEOS_ASH) +@@ -2067,7 +2072,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) { return; Print(duplicate_node.GetDocument().GetFrame(), duplicate_node, - PrintRequestType::kRegular); + PrintRequestType::kRegular, false /* silent */, -+ base::DictionaryValue() /* new_settings */); ++ base::Value::Dict() /* new_settings */); // Check if |this| is still valid. if (!weak_this) return; -@@ -1935,7 +1941,9 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) { +@@ -2082,7 +2088,9 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) { void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, const blink::WebNode& node, - PrintRequestType print_request_type) { + PrintRequestType print_request_type, + bool silent, -+ base::Value settings) { ++ base::Value::Dict settings) { // If still not finished with earlier print request simply ignore. if (prep_frame_view_) return; -@@ -1943,7 +1951,7 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, +@@ -2090,7 +2098,7 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, FrameReference frame_ref(frame); uint32_t expected_page_count = 0; - if (!CalculateNumberOfPages(frame, node, &expected_page_count)) { -+ if (!CalculateNumberOfPages(frame, node, &expected_page_count, base::Value::AsDictionaryValue(settings))) { ++ if (!CalculateNumberOfPages(frame, node, &expected_page_count, std::move(settings))) { DidFinishPrinting(FAIL_PRINT_INIT); return; // Failed to init print page settings. } -@@ -1962,8 +1970,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, +@@ -2109,8 +2117,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame, print_pages_params_->params->print_scaling_option; auto self = weak_ptr_factory_.GetWeakPtr(); @@ -588,7 +680,7 @@ index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cb // Check if |this| is still valid. if (!self) return; -@@ -2211,36 +2226,51 @@ void PrintRenderFrameHelper::IPCProcessed() { +@@ -2375,36 +2390,52 @@ void PrintRenderFrameHelper::IPCProcessed() { } } @@ -598,10 +690,10 @@ index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cb - GetPrintManagerHost()->GetDefaultPrintSettings(&settings.params); +bool PrintRenderFrameHelper::InitPrintSettings( + bool fit_to_paper_size, -+ const base::DictionaryValue& new_settings) { ++ base::Value::Dict new_settings) { + mojom::PrintPagesParamsPtr settings; + -+ if (new_settings.DictEmpty()) { ++ if (new_settings.empty()) { + settings = mojom::PrintPagesParams::New(); + settings->params = mojom::PrintParams::New(); + GetPrintManagerHost()->GetDefaultPrintSettings(&settings->params); @@ -609,7 +701,8 @@ index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cb + bool canceled = false; + int cookie = + print_pages_params_ ? print_pages_params_->params->document_cookie : 0; -+ GetPrintManagerHost()->UpdatePrintSettings(cookie, new_settings.Clone(), &settings, &canceled); ++ GetPrintManagerHost()->UpdatePrintSettings( ++ cookie, std::move(new_settings), &settings, &canceled); + if (canceled) + return false; + } @@ -644,15 +737,15 @@ index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cb + blink::WebLocalFrame* frame, + const blink::WebNode& node, + uint32_t* number_of_pages, -+ const base::DictionaryValue& settings) { ++ base::Value::Dict settings) { DCHECK(frame); - bool fit_to_paper_size = !IsPrintingNodeOrPdfFrame(frame, node); + bool fit_to_paper_size = !IsPrintingPdfFrame(frame, node); - if (!InitPrintSettings(fit_to_paper_size)) { -+ if (!InitPrintSettings(fit_to_paper_size, settings)) { ++ if (!InitPrintSettings(fit_to_paper_size, std::move(settings))) { notify_browser_of_print_failure_ = false; GetPrintManagerHost()->ShowInvalidPrinterSettingsError(); return false; -@@ -2385,7 +2415,7 @@ mojom::PrintPagesParamsPtr PrintRenderFrameHelper::GetPrintSettingsFromUser( +@@ -2529,7 +2560,7 @@ mojom::PrintPagesParamsPtr PrintRenderFrameHelper::GetPrintSettingsFromUser( std::move(params), base::BindOnce( [](base::OnceClosure quit_closure, mojom::PrintPagesParamsPtr* output, @@ -661,84 +754,100 @@ index 0d5c467e59c85589872a41b3783110b9d84ffbdb..75a0c6c1ee04cb655261d9d385e486cb *output = std::move(input); std::move(quit_closure).Run(); }, -@@ -2630,18 +2660,7 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type, - } - - bool PrintRenderFrameHelper::CheckForCancel() { -- const mojom::PrintParams& print_params = *print_pages_params_->params; -- bool cancel = false; -- -- if (!GetPrintManagerHost()->CheckForCancel(print_params.preview_ui_id, -- print_params.preview_request_id, -- &cancel)) { -- cancel = true; -- } -- -- if (cancel) -- notify_browser_of_print_failure_ = false; -- return cancel; -+ return false; - } - - bool PrintRenderFrameHelper::PreviewPageRendered( diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h -index 2b703118bf94a82262adc293368dcfcdb67807ff..a07f307ff48f3ce5409354a5ba8d54b43325da73 100644 +index 66026548181a897c161d7202646f33fd8847ccb8..113a8165b5db6294087773e5a4b2f0035f4c8f5d 100644 --- a/components/printing/renderer/print_render_frame_helper.h +++ b/components/printing/renderer/print_render_frame_helper.h -@@ -254,7 +254,7 @@ class PrintRenderFrameHelper +@@ -255,7 +255,7 @@ class PrintRenderFrameHelper mojo::PendingAssociatedReceiver receiver); // printing::mojom::PrintRenderFrame: - void PrintRequestedPages() override; -+ void PrintRequestedPages(bool silent, base::Value settings) override; ++ void PrintRequestedPages(bool silent, base::Value::Dict settings) override; + void PrintWithParams(mojom::PrintPagesParamsPtr params, + PrintWithParamsCallback callback) override; #if BUILDFLAG(ENABLE_PRINT_PREVIEW) - void PrintForSystemDialog() override; - void SetPrintPreviewUI( -@@ -321,7 +321,9 @@ class PrintRenderFrameHelper +@@ -328,7 +328,9 @@ class PrintRenderFrameHelper // WARNING: |this| may be gone after this method returns. void Print(blink::WebLocalFrame* frame, const blink::WebNode& node, - PrintRequestType print_request_type); + PrintRequestType print_request_type, + bool silent, -+ base::Value settings); ++ base::Value::Dict settings); // Notification when printing is done - signal tear-down/free resources. void DidFinishPrinting(PrintingResult result); -@@ -330,12 +332,14 @@ class PrintRenderFrameHelper +@@ -337,12 +339,14 @@ class PrintRenderFrameHelper // Initialize print page settings with default settings. // Used only for native printing workflow. - bool InitPrintSettings(bool fit_to_paper_size); + bool InitPrintSettings(bool fit_to_paper_size, -+ const base::DictionaryValue& settings); ++ base::Value::Dict new_settings); // Calculate number of pages in source document. bool CalculateNumberOfPages(blink::WebLocalFrame* frame, const blink::WebNode& node, - uint32_t* number_of_pages); + uint32_t* number_of_pages, -+ const base::DictionaryValue& settings); ++ base::Value::Dict settings); #if BUILDFLAG(ENABLE_PRINT_PREVIEW) // Set options for print preset from source PDF document. +diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn +index 993ec8acd401d5ccb1e07652c28f6f0a1d89c6bc..638dbd46cb572274a17b0c06ed3db0cf7b614b7f 100644 +--- a/content/browser/BUILD.gn ++++ b/content/browser/BUILD.gn +@@ -2802,8 +2802,9 @@ source_set("browser") { + "//ppapi/shared_impl", + ] + +- assert(enable_basic_printing) +- deps += [ "//printing" ] ++ if (enable_basic_printing) { ++ deps += [ "//printing" ] ++ } + + if (is_chromeos) { + sources += [ +diff --git a/content/browser/utility_sandbox_delegate_win.cc b/content/browser/utility_sandbox_delegate_win.cc +index e7f5b062791f6b2b94943c88d487757f2d77c7c5..f69ed3d412caa7254cfbea85a5448770a42b537d 100644 +--- a/content/browser/utility_sandbox_delegate_win.cc ++++ b/content/browser/utility_sandbox_delegate_win.cc +@@ -95,6 +95,7 @@ bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy) { + return true; + } + ++#if BUILDFLAG(ENABLE_PRINTING) + // Sets the sandbox policy for the print backend service process. + bool PrintBackendPreSpawnTarget(sandbox::TargetPolicy* policy) { + // Print Backend policy lockdown level must be at least USER_LIMITED and +@@ -105,6 +106,7 @@ bool PrintBackendPreSpawnTarget(sandbox::TargetPolicy* policy) { + policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); + return true; + } ++#endif + + std::string UtilityAppContainerId(base::CommandLine& cmd_line) { + return base::WideToUTF8(cmd_line.GetProgram().value()); diff --git a/printing/printing_context.cc b/printing/printing_context.cc -index 3d8281c8af9a4339bdd492c67edafc4ec6efb09d..6f8b9d42e051579cf1d0774afa771a7e45d31ff2 100644 +index 6cca846b9831da669ca52aff776caf5a23f6f4d1..39d1032f276181a535de9fba89c2246c7a9814d7 100644 --- a/printing/printing_context.cc +++ b/printing/printing_context.cc -@@ -120,7 +120,6 @@ mojom::ResultCode PrintingContext::UsePdfSettings() { +@@ -143,7 +143,6 @@ void PrintingContext::UsePdfSettings() { mojom::ResultCode PrintingContext::UpdatePrintSettings( - base::Value job_settings) { + base::Value::Dict job_settings) { - ResetSettings(); { std::unique_ptr settings = PrintSettingsFromJobSettings(job_settings); diff --git a/printing/printing_context.h b/printing/printing_context.h -index 3f36303105b7979a1a771bf26b42596abe5b3cce..52f740bb832db4a8d76431d9bc77cab10bb7e0c7 100644 +index 0e6dd8092f6025790560ca2bab2d68daf47caff2..a4aa6e21b1d37e534b543ad8b112070eedd12d2e 100644 --- a/printing/printing_context.h +++ b/printing/printing_context.h -@@ -170,6 +170,9 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext { +@@ -171,6 +171,9 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext { bool PrintingAborted() const { return abort_printing_; } @@ -748,7 +857,7 @@ index 3f36303105b7979a1a771bf26b42596abe5b3cce..52f740bb832db4a8d76431d9bc77cab1 int job_id() const { return job_id_; } protected: -@@ -180,9 +183,6 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext { +@@ -181,9 +184,6 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext { static std::unique_ptr CreateImpl(Delegate* delegate, bool skip_system_calls); @@ -758,3 +867,26 @@ index 3f36303105b7979a1a771bf26b42596abe5b3cce..52f740bb832db4a8d76431d9bc77cab1 // Determine if system calls should be skipped by this instance. bool skip_system_calls() const { #if BUILDFLAG(ENABLE_OOP_PRINTING) +diff --git a/sandbox/policy/mac/sandbox_mac.mm b/sandbox/policy/mac/sandbox_mac.mm +index 2a1a5aaf18d43a68b13783d55279e481bd91c2e5..156c6ca844d97376268baa57dcf220561a63fa04 100644 +--- a/sandbox/policy/mac/sandbox_mac.mm ++++ b/sandbox/policy/mac/sandbox_mac.mm +@@ -22,7 +22,6 @@ + #include "sandbox/policy/mac/nacl_loader.sb.h" + #include "sandbox/policy/mac/network.sb.h" + #include "sandbox/policy/mac/ppapi.sb.h" +-#include "sandbox/policy/mac/print_backend.sb.h" + #include "sandbox/policy/mac/print_compositor.sb.h" + #include "sandbox/policy/mac/renderer.sb.h" + #include "sandbox/policy/mac/screen_ai.sb.h" +@@ -30,6 +29,10 @@ + #include "sandbox/policy/mac/utility.sb.h" + #include "sandbox/policy/mojom/sandbox.mojom.h" + ++#if BUILDFLAG(ENABLE_PRINTING) ++#include "sandbox/policy/mac/print_backend.sb.h" ++#endif ++ + namespace sandbox { + namespace policy { + diff --git a/patches/chromium/process_singleton.patch b/patches/chromium/process_singleton.patch index 565c00742ba81..958b5d49d399c 100644 --- a/patches/chromium/process_singleton.patch +++ b/patches/chromium/process_singleton.patch @@ -23,8 +23,35 @@ This patch adds a few changes to the Chromium code: `ProcessSingleton` instance that tries to connect to the socket before the browser thread is ready. +diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc +index c29925908862930061f63e9f02d614b8a8a7980d..5ce3a8dd6366093ac5d09bab8b1774b8771faea8 100644 +--- a/chrome/browser/chrome_browser_main.cc ++++ b/chrome/browser/chrome_browser_main.cc +@@ -1421,7 +1421,6 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { + switch (notify_result_) { + case ProcessSingleton::PROCESS_NONE: + // No process already running, fall through to starting a new one. +- process_singleton_->StartWatching(); + g_browser_process->platform_part()->PlatformSpecificCommandLineProcessing( + *base::CommandLine::ForCurrentProcess()); + break; +diff --git a/chrome/browser/chrome_process_singleton.cc b/chrome/browser/chrome_process_singleton.cc +index d97fa8a96c110acc25b0ef46d7a4ac1c708f7c76..0919af8e8b0a51ef8e8dd28f2f07139d197a7384 100644 +--- a/chrome/browser/chrome_process_singleton.cc ++++ b/chrome/browser/chrome_process_singleton.cc +@@ -31,10 +31,6 @@ ProcessSingleton::NotifyResult + return process_singleton_.NotifyOtherProcessOrCreate(); + } + +-void ChromeProcessSingleton::StartWatching() { +- process_singleton_.StartWatching(); +-} +- + void ChromeProcessSingleton::Cleanup() { + process_singleton_.Cleanup(); + } diff --git a/chrome/browser/process_singleton.h b/chrome/browser/process_singleton.h -index 16bb3aa15a5378e8319f75f4b6b72b39177828f4..5a64220aaf1309832dc0ad543e353de67fe0a779 100644 +index 7cd82d27a741f194da5d0b3fcfd9c15c8ea1fa5c..5a64220aaf1309832dc0ad543e353de67fe0a779 100644 --- a/chrome/browser/process_singleton.h +++ b/chrome/browser/process_singleton.h @@ -102,12 +102,19 @@ class ProcessSingleton { @@ -56,7 +83,17 @@ index 16bb3aa15a5378e8319f75f4b6b72b39177828f4..5a64220aaf1309832dc0ad543e353de6 // Sets ourself up as the singleton instance. Returns true on success. If // false is returned, we are not the singleton instance and the caller must -@@ -173,6 +182,8 @@ class ProcessSingleton { +@@ -127,9 +136,6 @@ class ProcessSingleton { + // another process should call this directly. + bool Create(); + +- // Start watching for notifications from other processes. +- void StartWatching(); +- + // Clear any lock state during shutdown. + void Cleanup(); + +@@ -176,6 +182,8 @@ class ProcessSingleton { #if BUILDFLAG(IS_WIN) bool EscapeVirtualization(const base::FilePath& user_data_dir); @@ -65,7 +102,13 @@ index 16bb3aa15a5378e8319f75f4b6b72b39177828f4..5a64220aaf1309832dc0ad543e353de6 HWND remote_window_; // The HWND_MESSAGE of another browser. base::win::MessageWindow window_; // The message-only window. bool is_virtualized_; // Stuck inside Microsoft Softricity VM environment. -@@ -222,6 +233,8 @@ class ProcessSingleton { +@@ -220,12 +228,13 @@ class ProcessSingleton { + + // Temporary directory to hold the socket. + base::ScopedTempDir socket_dir_; +- int sock_ = -1; + + // Helper class for linux specific messages. LinuxWatcher is ref counted // because it posts messages between threads. class LinuxWatcher; scoped_refptr watcher_; @@ -75,26 +118,18 @@ index 16bb3aa15a5378e8319f75f4b6b72b39177828f4..5a64220aaf1309832dc0ad543e353de6 #if BUILDFLAG(IS_MAC) diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc -index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35a2fd1b75 100644 +index 7e4cc9cdd350e814c20feccdcc8d70b1080e60a1..2de07460462632680f9b16a019744527dcee5125 100644 --- a/chrome/browser/process_singleton_posix.cc +++ b/chrome/browser/process_singleton_posix.cc -@@ -53,6 +53,7 @@ +@@ -54,6 +54,7 @@ #include #include #include +#include #include - #include -@@ -82,6 +83,7 @@ - #include "base/strings/utf_string_conversions.h" - #include "base/task/sequenced_task_runner_helpers.h" - #include "base/task/single_thread_task_runner.h" -+#include "base/task/post_task.h" - #include "base/threading/platform_thread.h" - #include "base/threading/thread_task_runner_handle.h" - #include "base/time/time.h" -@@ -98,9 +100,11 @@ + #include "base/base_paths.h" +@@ -97,9 +98,11 @@ #include "net/base/network_interfaces.h" #include "ui/base/l10n/l10n_util.h" @@ -104,9 +139,9 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35 #endif +#endif - #if defined(TOOLKIT_VIEWS) && \ - (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) -@@ -349,6 +353,9 @@ bool SymlinkPath(const base::FilePath& target, const base::FilePath& path) { + using content::BrowserThread; + +@@ -343,6 +346,9 @@ bool SymlinkPath(const base::FilePath& target, const base::FilePath& path) { bool DisplayProfileInUseError(const base::FilePath& lock_path, const std::string& hostname, int pid) { @@ -116,7 +151,7 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35 std::u16string error = l10n_util::GetStringFUTF16( IDS_PROFILE_IN_USE_POSIX, base::NumberToString16(pid), base::ASCIIToUTF16(hostname)); -@@ -368,6 +375,7 @@ bool DisplayProfileInUseError(const base::FilePath& lock_path, +@@ -362,6 +368,7 @@ bool DisplayProfileInUseError(const base::FilePath& lock_path, NOTREACHED(); return false; @@ -124,7 +159,7 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35 } bool IsChromeProcess(pid_t pid) { -@@ -408,6 +416,21 @@ bool CheckCookie(const base::FilePath& path, const base::FilePath& cookie) { +@@ -402,6 +409,21 @@ bool CheckCookie(const base::FilePath& path, const base::FilePath& cookie) { return (cookie == ReadLink(path)); } @@ -146,7 +181,17 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35 bool ConnectSocket(ScopedSocket* socket, const base::FilePath& socket_path, const base::FilePath& cookie_path) { -@@ -775,6 +798,10 @@ ProcessSingleton::ProcessSingleton( +@@ -757,7 +779,8 @@ ProcessSingleton::ProcessSingleton( + const base::FilePath& user_data_dir, + const NotificationCallback& notification_callback) + : notification_callback_(notification_callback), +- current_pid_(base::GetCurrentProcId()) { ++ current_pid_(base::GetCurrentProcId()), ++ watcher_(new LinuxWatcher(this)) { + socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename); + lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename); + cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename); +@@ -768,6 +791,10 @@ ProcessSingleton::ProcessSingleton( ProcessSingleton::~ProcessSingleton() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -157,13 +202,13 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35 } ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { -@@ -947,6 +974,20 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { +@@ -932,6 +959,20 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { base::Seconds(kTimeoutInSeconds)); } +void ProcessSingleton::StartListeningOnSocket() { + watcher_ = base::MakeRefCounted(this); -+ base::PostTask(FROM_HERE, {BrowserThread::IO}, ++ content::GetIOThreadTaskRunner({})->PostTask(FROM_HERE, + base::BindOnce(&ProcessSingleton::LinuxWatcher::StartListening, + watcher_, sock_)); +} @@ -178,7 +223,7 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( const base::CommandLine& command_line, -@@ -1046,14 +1087,32 @@ bool ProcessSingleton::Create() { +@@ -1031,14 +1072,32 @@ bool ProcessSingleton::Create() { #endif } @@ -216,29 +261,61 @@ index c9f26ea2d2ea16484d416fdce095ec1b8b885991..7d3a441bdb64268ed5fbfa7bf589fb35 // Check that the directory was created with the correct permissions. int dir_mode = 0; CHECK(base::GetPosixFilePermissions(socket_dir_.GetPath(), &dir_mode) && -@@ -1096,10 +1155,13 @@ bool ProcessSingleton::Create() { - if (listen(sock, 5) < 0) +@@ -1050,9 +1109,10 @@ bool ProcessSingleton::Create() { + // leaving a dangling symlink. + base::FilePath socket_target_path = + socket_dir_.GetPath().Append(chrome::kSingletonSocketFilename); ++ int sock; + SockaddrUn addr; + socklen_t socklen; +- SetupSocket(socket_target_path.value(), &sock_, &addr, &socklen); ++ SetupSocket(socket_target_path.value(), &sock, &addr, &socklen); + + // Setup the socket symlink and the two cookies. + base::FilePath cookie(GenerateCookie()); +@@ -1071,26 +1131,24 @@ bool ProcessSingleton::Create() { + return false; + } + +- if (bind(sock_, reinterpret_cast(&addr), socklen) < 0) { ++ if (bind(sock, reinterpret_cast(&addr), socklen) < 0) { + PLOG(ERROR) << "Failed to bind() " << socket_target_path.value(); +- CloseSocket(sock_); ++ CloseSocket(sock); + return false; + } + +- if (listen(sock_, 5) < 0) ++ if (listen(sock, 5) < 0) NOTREACHED() << "listen failed: " << base::safe_strerror(errno); +- return true; +-} ++ sock_ = sock; + +-void ProcessSingleton::StartWatching() { +- DCHECK_GE(sock_, 0); +- DCHECK(!watcher_); +- watcher_ = new LinuxWatcher(this); - DCHECK(BrowserThread::IsThreadInitialized(BrowserThread::IO)); - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&ProcessSingleton::LinuxWatcher::StartListening, -- watcher_, sock)); -+ sock_ = sock; -+ +- watcher_, sock_)); + if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) { + StartListeningOnSocket(); + } else { + listen_on_ready_ = true; + } - - return true; ++ ++ return true; } + + void ProcessSingleton::Cleanup() { diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc -index 8eb7de0cd4007a5fd5431bcc7fb7be4962bd608e..0ea5eb3e3cf055d981ab73486115bac53287f2d7 100644 +index 41bc176510f93ef667e4f1373eab61142f3e264f..0c87fc8ccb4511904f19b76ae5e03a5df6664391 100644 --- a/chrome/browser/process_singleton_win.cc +++ b/chrome/browser/process_singleton_win.cc -@@ -28,7 +28,9 @@ +@@ -29,7 +29,9 @@ #include "base/win/wmi.h" #include "chrome/browser/process_singleton_internal.h" #include "chrome/browser/shell_integration.h" @@ -265,7 +342,7 @@ index 8eb7de0cd4007a5fd5431bcc7fb7be4962bd608e..0ea5eb3e3cf055d981ab73486115bac5 } // Function was copied from Process::Terminate. -@@ -245,9 +252,13 @@ bool ProcessSingleton::EscapeVirtualization( +@@ -252,9 +259,13 @@ bool ProcessSingleton::EscapeVirtualization( } ProcessSingleton::ProcessSingleton( @@ -279,7 +356,7 @@ index 8eb7de0cd4007a5fd5431bcc7fb7be4962bd608e..0ea5eb3e3cf055d981ab73486115bac5 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE), user_data_dir_(user_data_dir), -@@ -361,13 +372,16 @@ ProcessSingleton::NotifyOtherProcessOrCreate() { +@@ -368,13 +379,16 @@ ProcessSingleton::NotifyOtherProcessOrCreate() { return PROFILE_IN_USE; } @@ -297,7 +374,7 @@ index 8eb7de0cd4007a5fd5431bcc7fb7be4962bd608e..0ea5eb3e3cf055d981ab73486115bac5 remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_); if (!remote_window_ && !EscapeVirtualization(user_data_dir_)) { -@@ -376,7 +390,7 @@ bool ProcessSingleton::Create() { +@@ -383,7 +397,7 @@ bool ProcessSingleton::Create() { // access. As documented, it's clearer to NOT request ownership on creation // since it isn't guaranteed we will get it. It is better to create it // without ownership and explicitly get the ownership afterward. @@ -306,7 +383,7 @@ index 8eb7de0cd4007a5fd5431bcc7fb7be4962bd608e..0ea5eb3e3cf055d981ab73486115bac5 if (!only_me.IsValid()) { DPLOG(FATAL) << "CreateMutex failed"; return false; -@@ -415,6 +429,17 @@ bool ProcessSingleton::Create() { +@@ -422,6 +436,17 @@ bool ProcessSingleton::Create() { window_.CreateNamed(base::BindRepeating(&ProcessLaunchNotification, notification_callback_), user_data_dir_.value()); @@ -324,3 +401,12 @@ index 8eb7de0cd4007a5fd5431bcc7fb7be4962bd608e..0ea5eb3e3cf055d981ab73486115bac5 CHECK(result && window_.hwnd()); } } +@@ -430,8 +455,6 @@ bool ProcessSingleton::Create() { + return window_.hwnd() != NULL; + } + +-void ProcessSingleton::StartWatching() {} +- + void ProcessSingleton::Cleanup() { + } + diff --git a/patches/chromium/proxy_config_monitor.patch b/patches/chromium/proxy_config_monitor.patch index 155415a59b428..6b489214e651e 100644 --- a/patches/chromium/proxy_config_monitor.patch +++ b/patches/chromium/proxy_config_monitor.patch @@ -6,7 +6,7 @@ Subject: proxy_config_monitor.patch Allow monitoring proxy config changes for a pref service. diff --git a/chrome/browser/net/proxy_config_monitor.cc b/chrome/browser/net/proxy_config_monitor.cc -index 88fad9811069e7851363c8068f9702a9019669cc..526d951589f2757835fded706f4e448a8bb9daae 100644 +index d05a82a9c369a42cddebb1af1546a5ba6ae59c9f..7a263e3e6cc2a6bd27ec61598d9aae81c12d16e0 100644 --- a/chrome/browser/net/proxy_config_monitor.cc +++ b/chrome/browser/net/proxy_config_monitor.cc @@ -11,7 +11,9 @@ @@ -34,7 +34,7 @@ index 88fad9811069e7851363c8068f9702a9019669cc..526d951589f2757835fded706f4e448a ProxyConfigMonitor::ProxyConfigMonitor(Profile* profile) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(profile); -@@ -56,6 +59,7 @@ ProxyConfigMonitor::ProxyConfigMonitor(Profile* profile) { +@@ -57,6 +60,7 @@ ProxyConfigMonitor::ProxyConfigMonitor(Profile* profile) { proxy_config_service_->AddObserver(this); } @@ -42,7 +42,7 @@ index 88fad9811069e7851363c8068f9702a9019669cc..526d951589f2757835fded706f4e448a ProxyConfigMonitor::ProxyConfigMonitor(PrefService* local_state) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || -@@ -133,9 +137,11 @@ void ProxyConfigMonitor::OnLazyProxyConfigPoll() { +@@ -134,9 +138,11 @@ void ProxyConfigMonitor::OnLazyProxyConfigPoll() { void ProxyConfigMonitor::OnPACScriptError(int32_t line_number, const std::string& details) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -54,7 +54,7 @@ index 88fad9811069e7851363c8068f9702a9019669cc..526d951589f2757835fded706f4e448a } void ProxyConfigMonitor::OnRequestMaybeFailedDueToProxySettings( -@@ -149,9 +155,10 @@ void ProxyConfigMonitor::OnRequestMaybeFailedDueToProxySettings( +@@ -150,9 +156,10 @@ void ProxyConfigMonitor::OnRequestMaybeFailedDueToProxySettings( // controlled. return; } diff --git a/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch b/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch index 3b5caea926f8b..afee0cfa345d2 100644 --- a/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch +++ b/patches/chromium/refactor_expose_cursor_changes_to_the_webcontentsobserver.patch @@ -8,7 +8,7 @@ Chrome moved the SetCursor IPC message to mojo, which we use to tell OSR about ` Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2172779 diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h -index 059ff2b47e7aa8b9707e71ae9a1793bfdd86d319..529637f8b6af6b8b45f9de61d27b5e9c379c9645 100644 +index bdad25cd2c823fa2125fc523c400479882735ae6..bf2ddb136274eb3e4e597ed3060aabcaa9c5f432 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h @@ -14,6 +14,7 @@ @@ -19,7 +19,7 @@ index 059ff2b47e7aa8b9707e71ae9a1793bfdd86d319..529637f8b6af6b8b45f9de61d27b5e9c #include "content/public/common/drop_data.h" #include "services/metrics/public/cpp/ukm_recorder.h" #include "third_party/abseil-cpp/absl/types/optional.h" -@@ -252,6 +253,9 @@ class CONTENT_EXPORT RenderWidgetHostDelegate { +@@ -257,6 +258,9 @@ class CONTENT_EXPORT RenderWidgetHostDelegate { // Returns the associated RenderViewHostDelegateView*, if possible. virtual RenderViewHostDelegateView* GetDelegateView(); @@ -30,10 +30,10 @@ index 059ff2b47e7aa8b9707e71ae9a1793bfdd86d319..529637f8b6af6b8b45f9de61d27b5e9c // RenderWidgetHost on the primary main frame, and false otherwise. virtual bool IsWidgetForPrimaryMainFrame(RenderWidgetHostImpl*); diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc -index 59dda38e5781132472991979d90317dfaa96028f..7d51b1d678b9b11c0dfc48a0a890a43d21830530 100644 +index 457ba67603442e8ae9ea75be1cb3b4bf32ed4c4f..50680346b1db4c687d9d956fd3a13adbbd27e65a 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc -@@ -2082,6 +2082,8 @@ void RenderWidgetHostImpl::FilterDropData(DropData* drop_data) { +@@ -2076,6 +2076,8 @@ void RenderWidgetHostImpl::FilterDropData(DropData* drop_data) { void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) { if (view_) view_->UpdateCursor(WebCursor(cursor)); @@ -43,10 +43,10 @@ index 59dda38e5781132472991979d90317dfaa96028f..7d51b1d678b9b11c0dfc48a0a890a43d void RenderWidgetHostImpl::ShowContextMenuAtPoint( diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index 5afb01c9de253053243a1add87269a9d848b5297..1734f93f7d06faf2c28d65d23bbc6c17f72e0b59 100644 +index 2b393e7e7089d17a0906610c3c8979c20928a5f6..47b85a2bd890485dec96e23fb2cb8f8553f5c4e2 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -4486,6 +4486,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() { +@@ -4609,6 +4609,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() { return text_input_manager_.get(); } @@ -57,21 +57,21 @@ index 5afb01c9de253053243a1add87269a9d848b5297..1734f93f7d06faf2c28d65d23bbc6c17 + bool WebContentsImpl::IsWidgetForPrimaryMainFrame( RenderWidgetHostImpl* render_widget_host) { - return render_widget_host == GetMainFrame()->GetRenderWidgetHost(); + return render_widget_host == GetPrimaryMainFrame()->GetRenderWidgetHost(); diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h -index 5020c6674ba692c15d75d5eec981ac7b60f61bbe..e1ac23f3adf38591ae220ea84c5c0717a28e64bb 100644 +index 91dd718d313ee66bfeea3c0a08e5d2ec3e38b133..892efd5009b0a0ef00081bd765d20c46d68b2324 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h -@@ -966,6 +966,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, - blink::mojom::FrameVisibility visibility) override; +@@ -974,6 +974,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, void SendScreenRects() override; + void SendActiveState(bool active) override; TextInputManager* GetTextInputManager() override; + void OnCursorChanged(const WebCursor& cursor) override; bool IsWidgetForPrimaryMainFrame( RenderWidgetHostImpl* render_widget_host) override; bool IsShowingContextMenuOnPage() const override; diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h -index b68d706fe204c3e8d65b2bf523950840c0398db2..8852a8da29bc9b7f9b832ad392741751f46e3fd7 100644 +index bea8d6a0d6ac44c56132bc7e3745c5c154a02e79..e3fc1e633a9803eee837acbf6434fc6471d5c067 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h @@ -13,6 +13,7 @@ @@ -82,7 +82,7 @@ index b68d706fe204c3e8d65b2bf523950840c0398db2..8852a8da29bc9b7f9b832ad392741751 #include "content/public/browser/allow_service_worker_result.h" #include "content/public/browser/reload_type.h" #include "content/public/browser/render_frame_host.h" -@@ -527,6 +528,9 @@ class CONTENT_EXPORT WebContentsObserver { +@@ -533,6 +534,9 @@ class CONTENT_EXPORT WebContentsObserver { // Invoked when the primary main frame changes size. virtual void PrimaryMainFrameWasResized(bool width_changed) {} diff --git a/patches/chromium/refactor_restore_base_adaptcallbackforrepeating.patch b/patches/chromium/refactor_restore_base_adaptcallbackforrepeating.patch index ddd75f00d4f9a..66ec1ac0489e0 100644 --- a/patches/chromium/refactor_restore_base_adaptcallbackforrepeating.patch +++ b/patches/chromium/refactor_restore_base_adaptcallbackforrepeating.patch @@ -12,10 +12,10 @@ should be removed as soon as those have been updated. Patching because every instance is a FTBFS that prevents testing any one instance's fix. diff --git a/base/callback_helpers.h b/base/callback_helpers.h -index 046130ff8cbc4945e94a4ee71ac6320b4f7c5369..c71c3e1720b3f4c7b7362d99957cd2479bf88a37 100644 +index 49ce51acb678886e0c679caa42e616400ab3bd48..760d97e8614195c8106b07b8477cf91a5dbebc15 100644 --- a/base/callback_helpers.h +++ b/base/callback_helpers.h -@@ -94,6 +94,22 @@ class OnceCallbackHolder final { +@@ -96,6 +96,22 @@ class OnceCallbackHolder final { } // namespace internal diff --git a/patches/chromium/remove_incorrect_width_height_adjustments.patch b/patches/chromium/remove_incorrect_width_height_adjustments.patch deleted file mode 100644 index 4fce52ba6e282..0000000000000 --- a/patches/chromium/remove_incorrect_width_height_adjustments.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bruce Dawson -Date: Mon, 28 Feb 2022 19:07:41 +0000 -Subject: Remove incorrect width/height adjustments - -In late 2016 a change which fixed some problems around window sizing -when attaching or detaching additional displays was landed, which fixed -some genuine bugs. Unfortunately it included a subtraction of 1 from the -width and height of the Chrome window. I couldn't find any discussion of -this size adjustment and I think that it was just a misunderstanding of -how window rectangles work (inclusive versus exclusive extents). - -This size adjustment causes non-maximized Chrome windows to shrink every -time a monitor is added or removed. The problematic commit was found -by the bug-filer through a bisect of more than four years of Chrome -history - I'm just landing the fix that they suggested. - -Bug: 1300415 -Change-Id: Ief124f584a91aa9cc3f10704b0cc1e83356dea5b -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3492658 -Reviewed-by: Allen Bauer -Commit-Queue: Bruce Dawson -Cr-Commit-Position: refs/heads/main@{#975872} - -diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc -index 264a9109e42c23e9be6bf7269b3cfee2634b61e4..86f06d2a2c9588a2210a9f78f47e73f1b7c5e329 100644 ---- a/ui/views/win/hwnd_message_handler.cc -+++ b/ui/views/win/hwnd_message_handler.cc -@@ -2834,8 +2834,8 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) { - // (Win+Shift+Arrows). See crbug.com/656001. - window_rect.left = window_pos->x; - window_rect.top = window_pos->y; -- window_rect.right = window_pos->x + window_pos->cx - 1; -- window_rect.bottom = window_pos->y + window_pos->cy - 1; -+ window_rect.right = window_pos->x + window_pos->cx; -+ window_rect.bottom = window_pos->y + window_pos->cy; - } - - HMONITOR monitor; diff --git a/patches/chromium/render_widget_host_view_base.patch b/patches/chromium/render_widget_host_view_base.patch index 6a2fb792cfb5c..0726ac0addf00 100644 --- a/patches/chromium/render_widget_host_view_base.patch +++ b/patches/chromium/render_widget_host_view_base.patch @@ -6,10 +6,10 @@ Subject: render_widget_host_view_base.patch ... something to do with OSR? and maybe as well? terrifying. diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc -index 14b5b4552f8077236486c6c182a1e231b8aa8408..a6c20b9803eb9a259460ec09826cc1cb037e5e3f 100644 +index 999eeb6fc817a3898b2227fd58aa1ecc660f21a3..8c51cd22fef29fe3e647b80e951af4cf7d9e4637 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc -@@ -661,6 +661,13 @@ bool RenderWidgetHostViewBase::ScreenRectIsUnstableFor( +@@ -705,6 +705,13 @@ bool RenderWidgetHostViewBase::ScreenRectIsUnstableFor( return false; } @@ -24,7 +24,7 @@ index 14b5b4552f8077236486c6c182a1e231b8aa8408..a6c20b9803eb9a259460ec09826cc1cb const blink::WebMouseEvent& event, const ui::LatencyInfo& latency) { diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h -index abdd3cf7d93ab9a1f80351d38ddcee52664414da..98da92a6d31103dfa0a48e278c3a15ee0533791e 100644 +index f3a4f3961b543be0787b9f6ace585ce614e3c23e..5f112610fa0815f58436c54c9631b59ddf8606db 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h @@ -26,8 +26,10 @@ @@ -38,7 +38,7 @@ index abdd3cf7d93ab9a1f80351d38ddcee52664414da..98da92a6d31103dfa0a48e278c3a15ee #include "content/public/browser/render_widget_host_view.h" #include "content/public/common/page_visibility_state.h" #include "content/public/common/widget_type.h" -@@ -67,9 +69,11 @@ class CursorManager; +@@ -68,9 +70,11 @@ class CursorManager; class MouseWheelPhaseHandler; class RenderWidgetHostImpl; class RenderWidgetHostViewBaseObserver; @@ -50,7 +50,7 @@ index abdd3cf7d93ab9a1f80351d38ddcee52664414da..98da92a6d31103dfa0a48e278c3a15ee class WebCursor; class WebContentsAccessibility; class DelegatedFrameHost; -@@ -139,6 +143,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView { +@@ -147,6 +151,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView { const gfx::Rect& keyboard_rect) override {} bool IsHTMLFormPopup() const override; @@ -60,7 +60,7 @@ index abdd3cf7d93ab9a1f80351d38ddcee52664414da..98da92a6d31103dfa0a48e278c3a15ee // This only needs to be overridden by RenderWidgetHostViewBase subclasses // that handle content embedded within other RenderWidgetHostViews. gfx::PointF TransformPointToRootCoordSpaceF( -@@ -290,6 +297,11 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView { +@@ -315,6 +322,11 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView { virtual void ProcessGestureEvent(const blink::WebGestureEvent& event, const ui::LatencyInfo& latency); diff --git a/patches/chromium/render_widget_host_view_mac.patch b/patches/chromium/render_widget_host_view_mac.patch index 9500c595ccfb4..fc700f5317d69 100644 --- a/patches/chromium/render_widget_host_view_mac.patch +++ b/patches/chromium/render_widget_host_view_mac.patch @@ -10,10 +10,10 @@ kinds of utility windows. Similarly for `disableAutoHideCursor`. Additionally, disables usage of some private APIs in MAS builds. diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm -index 57b797c2e730a76d4910f8bcd5b35cc515a61012..61575390665f00b96d593a2e1066be3b28d8de6f 100644 +index e26ed62d252e27792d3f2813b502ac93f723a5c2..87b977a5da2334c1494402f81588d0a3fcd8c7a0 100644 --- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm +++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm -@@ -154,6 +154,15 @@ void ExtractUnderlines(NSAttributedString* string, +@@ -157,6 +157,15 @@ void ExtractUnderlines(NSAttributedString* string, } // namespace @@ -26,10 +26,10 @@ index 57b797c2e730a76d4910f8bcd5b35cc515a61012..61575390665f00b96d593a2e1066be3b +- (BOOL)shouldIgnoreMouseEvent; +@end + - // These are not documented, so use only after checking -respondsToSelector:. - @interface NSApplication (UndocumentedSpeechMethods) - - (void)speakString:(NSString*)string; -@@ -610,6 +619,9 @@ - (BOOL)acceptsMouseEventsWhenInactive { + // RenderWidgetHostViewCocoa --------------------------------------------------- + + // Private methods: +@@ -598,6 +607,9 @@ - (BOOL)acceptsMouseEventsWhenInactive { } - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent { @@ -39,7 +39,7 @@ index 57b797c2e730a76d4910f8bcd5b35cc515a61012..61575390665f00b96d593a2e1066be3b return [self acceptsMouseEventsWhenInactive]; } -@@ -686,6 +698,10 @@ - (BOOL)shouldIgnoreMouseEvent:(NSEvent*)theEvent { +@@ -674,6 +686,10 @@ - (BOOL)shouldIgnoreMouseEvent:(NSEvent*)theEvent { // its parent view. BOOL hitSelf = NO; while (view) { @@ -50,18 +50,18 @@ index 57b797c2e730a76d4910f8bcd5b35cc515a61012..61575390665f00b96d593a2e1066be3b if (view == self) hitSelf = YES; if ([view isKindOfClass:[self class]] && ![view isEqual:self] && -@@ -1006,6 +1022,10 @@ - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv { - eventType == NSKeyDown && - !(modifierFlags & NSCommandKeyMask); +@@ -993,6 +1009,10 @@ - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv { + eventType == NSEventTypeKeyDown && + !(modifierFlags & NSEventModifierFlagCommand); + if ([theEvent.window respondsToSelector:@selector(disableAutoHideCursor)] && + [theEvent.window disableAutoHideCursor]) + shouldAutohideCursor = NO; + // We only handle key down events and just simply forward other events. - if (eventType != NSKeyDown) { + if (eventType != NSEventTypeKeyDown) { _hostHelper->ForwardKeyboardEvent(event, latency_info); -@@ -1752,9 +1772,11 @@ - (NSAccessibilityRole)accessibilityRole { +@@ -1813,9 +1833,11 @@ - (NSAccessibilityRole)accessibilityRole { // Since this implementation doesn't have to wait any IPC calls, this doesn't // make any key-typing jank. --hbono 7/23/09 // @@ -73,7 +73,7 @@ index 57b797c2e730a76d4910f8bcd5b35cc515a61012..61575390665f00b96d593a2e1066be3b - (NSArray*)validAttributesForMarkedText { // This code is just copied from WebKit except renaming variables. -@@ -1763,7 +1785,10 @@ - (NSArray*)validAttributesForMarkedText { +@@ -1824,7 +1846,10 @@ - (NSArray*)validAttributesForMarkedText { initWithObjects:NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName, NSMarkedClauseSegmentAttributeName, diff --git a/patches/chromium/resource_file_conflict.patch b/patches/chromium/resource_file_conflict.patch index 69210dc4e5925..3638b1d443987 100644 --- a/patches/chromium/resource_file_conflict.patch +++ b/patches/chromium/resource_file_conflict.patch @@ -52,10 +52,10 @@ Some alternatives to this patch: None of these options seems like a substantial maintainability win over this patch to me (@nornagon). diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn -index 51555df59f2bf9d0f396b9ffea0524a2533274ec..f2c4feac76e96575de3627b7e8f2373b4fb30411 100644 +index aee9abd99a03ad2266e2fcd15c680ae3b97e9dc3..0223183c4e869e835429a52ad7d9eb381a2d21f5 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn -@@ -1596,7 +1596,7 @@ if (is_chrome_branded && !is_android) { +@@ -1547,7 +1547,7 @@ if (is_chrome_branded && !is_android) { } } @@ -64,7 +64,7 @@ index 51555df59f2bf9d0f396b9ffea0524a2533274ec..f2c4feac76e96575de3627b7e8f2373b chrome_paks("packed_resources") { if (is_mac) { output_dir = "$root_gen_dir/repack" -@@ -1624,6 +1624,12 @@ if (!is_android) { +@@ -1576,6 +1576,12 @@ if (!is_android) { } } @@ -75,5 +75,5 @@ index 51555df59f2bf9d0f396b9ffea0524a2533274ec..f2c4feac76e96575de3627b7e8f2373b +} + repack("unit_tests_pak") { + testonly = true sources = [ "$root_gen_dir/chrome/chrome_test_resources.pak" ] - output = "$root_out_dir/unit_tests.pak" diff --git a/patches/chromium/revert_spellcheck_fully_launch_spell_check_delayed_initialization.patch b/patches/chromium/revert_spellcheck_fully_launch_spell_check_delayed_initialization.patch new file mode 100644 index 0000000000000..02dc352163d6c --- /dev/null +++ b/patches/chromium/revert_spellcheck_fully_launch_spell_check_delayed_initialization.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: VerteDinde +Date: Mon, 15 Aug 2022 21:51:18 -0700 +Subject: Revert "[SpellCheck] Fully launch spell check delayed initialization" + +This reverts commit bf1a502a147c3208d7bb9106fb3aa71b4eee3cf6. +Delaying spell check initialization is causing specs for +'custom dictionary word list API' to fail in Electron. This patch +can be reverted when those failures are addressed. It's unlikely +that this patch will be upstreamed. + +diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc +index 328574de32fb02f014433b1005d5aa625e498d9f..5cdc5a8c67688747ff3b5323c42e4605ab613347 100644 +--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc ++++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc +@@ -297,26 +297,7 @@ TEST_F(LanguageSettingsPrivateApiTest, GetNeverTranslateLanguagesListTest) { + } + } + +-class LanguageSettingsPrivateApiGetLanguageListTest +- : public LanguageSettingsPrivateApiTest { +- public: +- LanguageSettingsPrivateApiGetLanguageListTest() = default; +- ~LanguageSettingsPrivateApiGetLanguageListTest() override = default; +- +- protected: +- void InitFeatures() override { +-#if BUILDFLAG(IS_WIN) +- // Force Windows hybrid spellcheck to be enabled, and disable the delayed +- // init feature since that case is tested in +- // LanguageSettingsPrivateApiTestDelayInit below. +- feature_list_.InitWithFeatures( +- /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker}, +- /*disabled_features=*/{spellcheck::kWinDelaySpellcheckServiceInit}); +-#endif // BUILDFLAG(IS_WIN) +- } +-}; +- +-TEST_F(LanguageSettingsPrivateApiGetLanguageListTest, GetLanguageList) { ++TEST_F(LanguageSettingsPrivateApiTest, GetLanguageListTest) { + translate::TranslateDownloadManager::GetInstance()->ResetForTesting(); + RunGetLanguageListTest(); + } +diff --git a/chrome/browser/spellchecker/spellcheck_service_unittest.cc b/chrome/browser/spellchecker/spellcheck_service_unittest.cc +index b8fa14fa50d82521845b9f84d62d9de922df9168..1e9c21eca325845bbc8f09a5287a2451f9829e80 100644 +--- a/chrome/browser/spellchecker/spellcheck_service_unittest.cc ++++ b/chrome/browser/spellchecker/spellcheck_service_unittest.cc +@@ -341,18 +341,9 @@ const std::vector SpellcheckServiceHybridUnitTestBase:: + // dictionaries. + }; + +-class GetDictionariesHybridUnitTestNoDelayInit ++class SpellcheckServiceHybridUnitTest + : public SpellcheckServiceHybridUnitTestBase, +- public testing::WithParamInterface { +- protected: +- void InitFeatures() override { +- // Disable kWinDelaySpellcheckServiceInit, as the case where it's enabled +- // is tested in SpellcheckServiceWindowsDictionaryMappingUnitTestDelayInit. +- feature_list_.InitWithFeatures( +- /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker}, +- /*disabled_features=*/{spellcheck::kWinDelaySpellcheckServiceInit}); +- } +-}; ++ public testing::WithParamInterface {}; + + static const TestCase kHybridGetDictionariesParams[] = { + // Galician (gl) has only Windows support, no Hunspell dictionary. Croatian +@@ -407,10 +398,10 @@ static const TestCase kHybridGetDictionariesParams[] = { + }; + + INSTANTIATE_TEST_SUITE_P(TestCases, +- GetDictionariesHybridUnitTestNoDelayInit, ++ SpellcheckServiceHybridUnitTest, + testing::ValuesIn(kHybridGetDictionariesParams)); + +-TEST_P(GetDictionariesHybridUnitTestNoDelayInit, GetDictionaries) { ++TEST_P(SpellcheckServiceHybridUnitTest, GetDictionaries) { + RunGetDictionariesTest(GetParam().accept_languages, + GetParam().spellcheck_dictionaries, + GetParam().expected_dictionaries); +@@ -440,16 +431,7 @@ std::ostream& operator<<(std::ostream& out, + + class SpellcheckServiceWindowsDictionaryMappingUnitTest + : public SpellcheckServiceHybridUnitTestBase, +- public testing::WithParamInterface { +- protected: +- void InitFeatures() override { +- // Disable kWinDelaySpellcheckServiceInit, as the case where it's enabled +- // is tested in SpellcheckServiceWindowsDictionaryMappingUnitTestDelayInit. +- feature_list_.InitWithFeatures( +- /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker}, +- /*disabled_features=*/{spellcheck::kWinDelaySpellcheckServiceInit}); +- } +-}; ++ public testing::WithParamInterface {}; + + static const DictionaryMappingTestCase kHybridDictionaryMappingsParams[] = { + DictionaryMappingTestCase({"en-CA", "en-CA", "en-CA", "en", "en"}), +diff --git a/components/spellcheck/common/spellcheck_features.cc b/components/spellcheck/common/spellcheck_features.cc +index 37f2b0e837d8031bee488e9fd7bd4eb456c42204..dcd365a802e0feebbb2bc3839c7a0f47fb113c70 100644 +--- a/components/spellcheck/common/spellcheck_features.cc ++++ b/components/spellcheck/common/spellcheck_features.cc +@@ -32,7 +32,7 @@ const base::Feature kWinUseBrowserSpellChecker{ + "WinUseBrowserSpellChecker", base::FEATURE_ENABLED_BY_DEFAULT}; + + const base::Feature kWinDelaySpellcheckServiceInit{ +- "WinDelaySpellcheckServiceInit", base::FEATURE_ENABLED_BY_DEFAULT}; ++ "WinDelaySpellcheckServiceInit", base::FEATURE_DISABLED_BY_DEFAULT}; + + const base::Feature kWinRetrieveSuggestionsOnlyOnDemand{ + "WinRetrieveSuggestionsOnlyOnDemand", base::FEATURE_ENABLED_BY_DEFAULT}; diff --git a/patches/chromium/scroll_bounce_flag.patch b/patches/chromium/scroll_bounce_flag.patch index d88d68edf85bd..b674f5fe65211 100644 --- a/patches/chromium/scroll_bounce_flag.patch +++ b/patches/chromium/scroll_bounce_flag.patch @@ -6,10 +6,10 @@ Subject: scroll_bounce_flag.patch Patch to make scrollBounce option work. diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc -index 03b92fd7a6218d3469648b96f273377d84c2f13f..d7ca333c81fd5765da047acf54aaeb5e07ab4c26 100644 +index a15cfb291dea69d78bad2b4726b013d8a636a361..50c1d506d20be94d89f7c33fe3efb4bd30fb2305 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc -@@ -1344,7 +1344,7 @@ bool RenderThreadImpl::IsLcdTextEnabled() { +@@ -1285,7 +1285,7 @@ bool RenderThreadImpl::IsLcdTextEnabled() { } bool RenderThreadImpl::IsElasticOverscrollEnabled() { diff --git a/patches/chromium/short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch b/patches/chromium/short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch new file mode 100644 index 0000000000000..a47563743be14 --- /dev/null +++ b/patches/chromium/short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Rose +Date: Tue, 12 Jul 2022 16:51:43 -0700 +Subject: short-circuit permissions checks in MediaStreamDevicesController + +The //components/permissions architecture is complicated and not that +widely used in Chromium, and mostly oriented around showing permissions +UI and/or remembering per-site permissions, which we're not interested +in. + +Since we do a permissions check prior to invoking the +MediaStreamDevicesController, and don't (yet) provide the ability to set +granular permissions (e.g. allow video but not audio), just +short-circuit all the permissions checks in MSDC for now to allow us to +unduplicate this code. + +diff --git a/components/webrtc/media_stream_devices_controller.cc b/components/webrtc/media_stream_devices_controller.cc +index 71eb2eda28d4d0d5dd9a1ad37309dd27caa69ccf..88a1d29ded5630a484106e6638921c6d279778d7 100644 +--- a/components/webrtc/media_stream_devices_controller.cc ++++ b/components/webrtc/media_stream_devices_controller.cc +@@ -92,10 +92,12 @@ void MediaStreamDevicesController::RequestPermissions( + + std::vector permission_types; + ++#if 0 + content::PermissionController* permission_controller = + web_contents->GetBrowserContext()->GetPermissionController(); +- ++#endif + if (controller->ShouldRequestAudio()) { ++#if 0 + content::PermissionResult permission_status = + permission_controller->GetPermissionResultForCurrentDocument( + blink::PermissionType::AUDIO_CAPTURE, rfh); +@@ -106,10 +108,12 @@ void MediaStreamDevicesController::RequestPermissions( + content::PermissionStatusSource::FEATURE_POLICY); + return; + } ++#endif + + permission_types.push_back(blink::PermissionType::AUDIO_CAPTURE); + } + if (controller->ShouldRequestVideo()) { ++#if 0 + content::PermissionResult permission_status = + permission_controller->GetPermissionResultForCurrentDocument( + blink::PermissionType::VIDEO_CAPTURE, rfh); +@@ -120,6 +124,7 @@ void MediaStreamDevicesController::RequestPermissions( + content::PermissionStatusSource::FEATURE_POLICY); + return; + } ++#endif + + permission_types.push_back(blink::PermissionType::VIDEO_CAPTURE); + +@@ -131,6 +136,7 @@ void MediaStreamDevicesController::RequestPermissions( + // pan-tilt-zoom permission and there are suitable PTZ capable devices + // available. + if (request.request_pan_tilt_zoom_permission && has_pan_tilt_zoom_camera) { ++#if 0 + permission_status = + permission_controller->GetPermissionResultForCurrentDocument( + blink::PermissionType::CAMERA_PAN_TILT_ZOOM, rfh); +@@ -140,6 +146,7 @@ void MediaStreamDevicesController::RequestPermissions( + controller->RunCallback(/*blocked_by_permissions_policy=*/false); + return; + } ++#endif + + permission_types.push_back(blink::PermissionType::CAMERA_PAN_TILT_ZOOM); + } +@@ -428,6 +435,7 @@ bool MediaStreamDevicesController::PermissionIsBlockedForReason( + + // TODO(raymes): This function wouldn't be needed if + // PermissionManager::RequestPermissions returned a denial reason. ++#if 0 + content::PermissionResult result = + web_contents_->GetBrowserContext() + ->GetPermissionController() +@@ -436,6 +444,7 @@ bool MediaStreamDevicesController::PermissionIsBlockedForReason( + DCHECK_EQ(blink::mojom::PermissionStatus::DENIED, result.status); + return true; + } ++#endif + return false; + } + diff --git a/patches/chromium/support_mixed_sandbox_with_zygote.patch b/patches/chromium/support_mixed_sandbox_with_zygote.patch index e33766bf410c0..7ed514ab08de2 100644 --- a/patches/chromium/support_mixed_sandbox_with_zygote.patch +++ b/patches/chromium/support_mixed_sandbox_with_zygote.patch @@ -22,10 +22,10 @@ However, the patch would need to be reviewed by the security team, as it does touch a security-sensitive class. diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc -index eebe90092c65dd9160a394b9b6eb2273b03de503..5f2451eefad211c85460eb457ad3d6e184540d59 100644 +index 161aefa1d91923be35046dfe735071c687710deb..368d47247ced2320e0627e9cce3cf05e59ea9f39 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc -@@ -1838,9 +1838,15 @@ bool RenderProcessHostImpl::Init() { +@@ -1764,9 +1764,15 @@ bool RenderProcessHostImpl::Init() { std::unique_ptr sandbox_delegate = std::make_unique( cmd_line.get(), IsJitDisabled()); @@ -39,13 +39,13 @@ index eebe90092c65dd9160a394b9b6eb2273b03de503..5f2451eefad211c85460eb457ad3d6e1 std::make_unique(); +#endif #endif - // Spawn the child process asynchronously to avoid blocking the UI thread. - // As long as there's no renderer prefix, we can use the zygote process + + auto file_data = std::make_unique(); diff --git a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc -index e8d6ef94664bb37996871c0cc0db7c815783b786..0d56fa0aebee80883019a100900119972bf02edd 100644 +index 71bbf3608a2b112e51b6b178755f06657f657ff9..6f3f2f00f35f5c5b38654cb0388cba070e3cdab2 100644 --- a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc +++ b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.cc -@@ -25,6 +25,9 @@ namespace content { +@@ -31,6 +31,9 @@ namespace content { #if BUILDFLAG(USE_ZYGOTE_HANDLE) ZygoteHandle RendererSandboxedProcessLauncherDelegate::GetZygote() { @@ -55,10 +55,10 @@ index e8d6ef94664bb37996871c0cc0db7c815783b786..0d56fa0aebee80883019a10090011997 const base::CommandLine& browser_command_line = *base::CommandLine::ForCurrentProcess(); base::CommandLine::StringType renderer_prefix = -@@ -52,6 +55,9 @@ RendererSandboxedProcessLauncherDelegateWin:: - bool is_jit_disabled) - : renderer_code_integrity_enabled_( - GetContentClient()->browser()->IsRendererCodeIntegrityEnabled()) { +@@ -60,6 +63,9 @@ RendererSandboxedProcessLauncherDelegateWin:: + GetContentClient()->browser()->IsRendererCodeIntegrityEnabled()), + renderer_app_container_disabled_( + GetContentClient()->browser()->IsRendererAppContainerDisabled()) { +#if BUILDFLAG(USE_ZYGOTE_HANDLE) + use_zygote_ = !cmd_line->HasSwitch(switches::kNoZygote); +#endif @@ -66,7 +66,7 @@ index e8d6ef94664bb37996871c0cc0db7c815783b786..0d56fa0aebee80883019a10090011997 dynamic_code_can_be_disabled_ = true; return; diff --git a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h -index 463df70c55df932427c761a67dbc89d7657f9703..d6d8094e31129eb7ca1f0bf36523d48204281795 100644 +index d820cb4ff004194d9c18bfddaf90bf520e8446ff..0dcffcf367b5d08bb31b68e648c1f4ce3aa15600 100644 --- a/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h +++ b/content/browser/renderer_host/renderer_sandboxed_process_launcher_delegate.h @@ -18,6 +18,11 @@ class CONTENT_EXPORT RendererSandboxedProcessLauncherDelegate diff --git a/patches/chromium/sysroot.patch b/patches/chromium/sysroot.patch index 30b60348f9835..e4fac7f0441b5 100644 --- a/patches/chromium/sysroot.patch +++ b/patches/chromium/sysroot.patch @@ -7,7 +7,7 @@ Make chrome's install-sysroot scripts point to our custom sysroot builds, which include extra deps that Electron needs (e.g. libnotify) diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py -index ada6208644cb22c9f51c571f9509e335c0836163..8f7169a0837a80c05faebce85ab4feac9e02bde2 100755 +index abd7eb4a8d116075751bcf6e44f872bac83431ef..54c01f56ac3f17b4534b6e89d9f8c4ba3bd79bf9 100755 --- a/build/linux/sysroot_scripts/install-sysroot.py +++ b/build/linux/sysroot_scripts/install-sysroot.py @@ -41,9 +41,11 @@ except ImportError: @@ -24,7 +24,7 @@ index ada6208644cb22c9f51c571f9509e335c0836163..8f7169a0837a80c05faebce85ab4feac VALID_ARCHS = ('arm', 'arm64', 'i386', 'amd64', 'mips', 'mips64el') -@@ -105,7 +107,7 @@ def GetSysrootDict(target_platform, target_arch): +@@ -106,7 +108,7 @@ def GetSysrootDict(target_platform, target_arch): if target_arch not in VALID_ARCHS: raise Error('Unknown architecture: %s' % target_arch) diff --git a/patches/chromium/unsandboxed_ppapi_processes_skip_zygote.patch b/patches/chromium/unsandboxed_ppapi_processes_skip_zygote.patch index b3d8608dc3a5c..b89002c3b34f4 100644 --- a/patches/chromium/unsandboxed_ppapi_processes_skip_zygote.patch +++ b/patches/chromium/unsandboxed_ppapi_processes_skip_zygote.patch @@ -6,10 +6,10 @@ Subject: unsandboxed_ppapi_processes_skip_zygote.patch Unsandboxed ppapi processes should skip zygote. diff --git a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc -index a0d6f0353bb387e6eca9f2b13ab1d40996234110..8548abdfae14d630794abc1033f9b9eda59f771b 100644 +index f822120af8bf8849609a765d7478fbdba1e50a8b..f928b747d202179636761666ff084a81433a933b 100644 --- a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc +++ b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc -@@ -7,6 +7,7 @@ +@@ -8,6 +8,7 @@ #include "build/build_config.h" #include "content/public/common/content_switches.h" #include "sandbox/policy/mojom/sandbox.mojom.h" @@ -17,7 +17,7 @@ index a0d6f0353bb387e6eca9f2b13ab1d40996234110..8548abdfae14d630794abc1033f9b9ed #if BUILDFLAG(IS_WIN) #include "base/win/windows_version.h" -@@ -63,6 +64,9 @@ bool PpapiPluginSandboxedProcessLauncherDelegate::PreSpawnTarget( +@@ -62,6 +63,9 @@ bool PpapiPluginSandboxedProcessLauncherDelegate::PreSpawnTarget( ZygoteHandle PpapiPluginSandboxedProcessLauncherDelegate::GetZygote() { const base::CommandLine& browser_command_line = *base::CommandLine::ForCurrentProcess(); diff --git a/patches/chromium/v8_context_snapshot_generator.patch b/patches/chromium/v8_context_snapshot_generator.patch deleted file mode 100644 index 6e7f5ad9c9de6..0000000000000 --- a/patches/chromium/v8_context_snapshot_generator.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nitish Sakhawalkar -Date: Thu, 20 Sep 2018 17:47:58 -0700 -Subject: v8_context_snapshot_generator.patch - -v8_context_snapshot_generator is a build time executable. -The patch adds the config. - -diff --git a/tools/v8_context_snapshot/BUILD.gn b/tools/v8_context_snapshot/BUILD.gn -index a06eae4ab3217210f997126f7dcc318785cdb759..9484ccd615817459f17daf76ff9f82e88cfacbdd 100644 ---- a/tools/v8_context_snapshot/BUILD.gn -+++ b/tools/v8_context_snapshot/BUILD.gn -@@ -114,6 +114,7 @@ if (use_v8_context_snapshot) { - configs += [ - "//v8:external_startup_data", - ":disable_icf", -+ "//electron/build/config:build_time_executable", - ] - } - } diff --git a/patches/chromium/web_contents.patch b/patches/chromium/web_contents.patch index f9d20ffdd014d..1b5ecfb240dbc 100644 --- a/patches/chromium/web_contents.patch +++ b/patches/chromium/web_contents.patch @@ -9,12 +9,12 @@ is needed for OSR. Originally landed in https://github.com/electron/libchromiumcontent/pull/226. diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index b19517ceafabde2ad88e83af97b9768b8a03fb60..4a553eee8f5d06cb645f2b52fe3baee347b1fa94 100644 +index 7f04a05eec8780e735e0458c75103d9f2e9b858b..2aa24b773a974e7789c661a0ffa5e01715c6e229 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -3040,6 +3040,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, +@@ -3089,6 +3089,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, site_instance.get(), params.renderer_initiated_creation, - params.main_frame_name, GetOriginalOpener(), primary_main_frame_policy); + params.main_frame_name, GetOpener(), primary_main_frame_policy); + if (params.view && params.delegate_view) { + view_.reset(params.view); @@ -23,22 +23,22 @@ index b19517ceafabde2ad88e83af97b9768b8a03fb60..4a553eee8f5d06cb645f2b52fe3baee3 + + if (!view_) { + - WebContentsViewDelegate* delegate = + std::unique_ptr delegate = GetContentClient()->browser()->GetWebContentsViewDelegate(this); -@@ -3050,6 +3057,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, - view_.reset(CreateWebContentsView(this, delegate, - &render_view_host_delegate_view_)); +@@ -3099,6 +3106,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params, + view_ = CreateWebContentsView(this, std::move(delegate), + &render_view_host_delegate_view_); } + } // !view_ CHECK(render_view_host_delegate_view_); CHECK(view_.get()); diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h -index ad5c13965f1ccc078de5f25b08d51ed43e37f259..cd1b44d4ff5ce8924749ba9e41b3f599108bb8fd 100644 +index 024cd37e818e1c508cf2a8e324478235444f16ed..a389a9c41f96ec3231b62510cde140c52dcdbe9e 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h -@@ -93,10 +93,13 @@ class BrowserContext; +@@ -94,10 +94,13 @@ class BrowserContext; class BrowserPluginGuestDelegate; class RenderFrameHost; class RenderViewHost; @@ -52,7 +52,7 @@ index ad5c13965f1ccc078de5f25b08d51ed43e37f259..cd1b44d4ff5ce8924749ba9e41b3f599 class WebUI; struct DropData; struct MHTMLGenerationParams; -@@ -234,6 +237,10 @@ class WebContents : public PageNavigator, +@@ -237,6 +240,10 @@ class WebContents : public PageNavigator, network::mojom::WebSandboxFlags starting_sandbox_flags = network::mojom::WebSandboxFlags::kNone; diff --git a/patches/chromium/webview_cross_drag.patch b/patches/chromium/webview_cross_drag.patch index 67d32c0a23bbd..b44e2eccaa131 100644 --- a/patches/chromium/webview_cross_drag.patch +++ b/patches/chromium/webview_cross_drag.patch @@ -8,26 +8,26 @@ This allows dragging and dropping between s. Originally landed in https://github.com/electron/libchromiumcontent/pull/267 diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc -index eff6616ef019ea8b661b878cc5fccd1e4b9217aa..9aff1848395dc41311df575dd7cbf0771271ed03 100644 +index 3e2342d28760172bcfd765f7ac3733b4d89a1445..351bee9cfcc31dc6ca06f1fc502b70617105191a 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc -@@ -890,10 +890,7 @@ bool WebContentsViewAura::IsValidDragTarget( - // TODO(https://crbug.com/1266953): There are some known gaps caused by - // comparing `RenderViewHost` IDs, as `RenderViewHost` ID is not really a - // strong signal for page identity. -- return !drag_start_ || -- target_rwh->GetProcess()->GetID() == drag_start_->process_id || -- GetRenderViewHostID(web_contents_->GetRenderViewHost()) != -- drag_start_->view_id; +@@ -916,10 +916,7 @@ bool WebContentsViewAura::IsValidDragTarget( + // for the outermost view. Inner `WebContents` will have a + // `WebContentsViewChildFrame` so when dragging between an inner + // `WebContents` and its embedder the view IDs will be the same. +- bool cross_tab_drag = +- GetRenderViewHostID(web_contents_->GetRenderViewHost()) != +- drag_start_->view_id; +- return cross_tab_drag; + return true; } //////////////////////////////////////////////////////////////////////////////// diff --git a/content/browser/web_contents/web_drag_dest_mac.mm b/content/browser/web_contents/web_drag_dest_mac.mm -index 6455404fdccab1fffceef4b8d291c137d3a448c4..483b0b5b689da03f0d7e43576fa73275197f5a95 100644 +index dab3703cc4469802bae9e4d45c3e7d0f0857f577..ecd8af37c681ae5c97060af00bbeb8ebddb72b26 100644 --- a/content/browser/web_contents/web_drag_dest_mac.mm +++ b/content/browser/web_contents/web_drag_dest_mac.mm -@@ -385,9 +385,7 @@ - (void)setDragStartTrackersForProcess:(int)processID { +@@ -388,9 +388,7 @@ - (void)setDragStartTrackersForProcess:(int)processID { } - (bool)isValidDragTarget:(content::RenderWidgetHostImpl*)targetRWH { diff --git a/patches/chromium/webview_fullscreen.patch b/patches/chromium/webview_fullscreen.patch index 727671ac417c4..915b68b72b7c5 100644 --- a/patches/chromium/webview_fullscreen.patch +++ b/patches/chromium/webview_fullscreen.patch @@ -14,11 +14,11 @@ Note that we also need to manually update embedder's `api::WebContents::IsFullscreenForTabOrPending` value. diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc -index e36a19c847912b007a94464321bb83b15bdcdafd..afd175d35096b0a50ccee3f2b14c632adbfec58a 100644 +index 1f58d6a342b0c1e0c5fd4d525a684a166f11a69d..05d803e286343e1443863c6dd292102bae12fe83 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc -@@ -6105,6 +6105,15 @@ void RenderFrameHostImpl::EnterFullscreen( - notified_instances.insert(parent_site_instance); +@@ -6567,6 +6567,17 @@ void RenderFrameHostImpl::EnterFullscreen( + } } + // Entering fullscreen from webview should also notify its outer frame. @@ -26,10 +26,12 @@ index e36a19c847912b007a94464321bb83b15bdcdafd..afd175d35096b0a50ccee3f2b14c632a + RenderFrameProxyHost* outer_proxy = + frame_tree_node()->render_manager()->GetProxyToOuterDelegate(); + DCHECK(outer_proxy); -+ outer_proxy->GetAssociatedRemoteFrame()->WillEnterFullscreen( -+ options.Clone()); ++ if (outer_proxy->is_render_frame_proxy_live()) { ++ outer_proxy->GetAssociatedRemoteFrame()->WillEnterFullscreen( ++ options.Clone()); ++ } + } + - delegate_->EnterFullscreenMode(this, *options); - delegate_->FullscreenStateChanged(this, /*is_fullscreen=*/true, - std::move(options)); + // Focus the window if another frame may have delegated the capability. + if (had_fullscreen_token && !GetView()->HasFocus()) + GetView()->Focus(); diff --git a/patches/chromium/worker_context_will_destroy.patch b/patches/chromium/worker_context_will_destroy.patch index fb1f1fb62a707..4eca49c954db9 100644 --- a/patches/chromium/worker_context_will_destroy.patch +++ b/patches/chromium/worker_context_will_destroy.patch @@ -10,10 +10,10 @@ An attempt to upstream this was made, but rejected: https://chromium-review.googlesource.com/c/chromium/src/+/1954347 diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h -index 63ead7f8ab838693bade7163ddebd1787cc82344..8512a66eda07202b6c6faea049736fd8f16c93db 100644 +index a9146ec6c85b3dfa854d764e8010124f76cd3fc7..e0b308051be9b34ce26b65f6cd582beb7743662d 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h -@@ -361,6 +361,11 @@ class CONTENT_EXPORT ContentRendererClient { +@@ -365,6 +365,11 @@ class CONTENT_EXPORT ContentRendererClient { virtual void DidInitializeWorkerContextOnWorkerThread( v8::Local context) {} @@ -26,10 +26,10 @@ index 63ead7f8ab838693bade7163ddebd1787cc82344..8512a66eda07202b6c6faea049736fd8 // An empty URL is returned if the URL is not overriden. virtual GURL OverrideFlashEmbedWithHTML(const GURL& url); diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc -index bd420d1cf8b5c1de687be10979921381cb770de9..0ea0012253d8348f1ba204f3b1fca7c5e2d306ce 100644 +index b822b43d0a2398689120a87b6dbd5f1c5f0f4ee3..53b42b67823474fc5c688654da280cde82faea87 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc -@@ -954,6 +954,12 @@ void RendererBlinkPlatformImpl::WillStopWorkerThread() { +@@ -860,6 +860,12 @@ void RendererBlinkPlatformImpl::WillStopWorkerThread() { WorkerThreadRegistry::Instance()->WillStopCurrentWorkerThread(); } @@ -43,10 +43,10 @@ index bd420d1cf8b5c1de687be10979921381cb770de9..0ea0012253d8348f1ba204f3b1fca7c5 const v8::Local& worker) { GetContentClient()->renderer()->DidInitializeWorkerContextOnWorkerThread( diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h -index 7255ac218c8fd061c2125e33054d9a87c13d1eb4..ab771fe015c195f53ce8bb1411050635f02c69f3 100644 +index 9718602c31f866b668cd211ff4fd72f69de1cd42..8f80fb04990c3e2820dcbc9b89dc0255c9c49d30 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h -@@ -209,6 +209,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { +@@ -180,6 +180,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { void DidStartWorkerThread() override; void WillStopWorkerThread() override; void WorkerContextCreated(const v8::Local& worker) override; @@ -55,10 +55,10 @@ index 7255ac218c8fd061c2125e33054d9a87c13d1eb4..ab771fe015c195f53ce8bb1411050635 const blink::WebSecurityOrigin& script_origin) override; blink::ProtocolHandlerSecurityLevel GetProtocolHandlerSecurityLevel() diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h -index d188491afffbd259d4287b0668a9d1cec291934a..2fe5234832f8a3510326171e1ccf5dbfeca49fc9 100644 +index ad34b6230f57ad906bae515aa73ea2aaf1bfeede..b5cff1fee2d14c02f2d67cf012b7ba24fc3a7a06 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h -@@ -720,6 +720,7 @@ class BLINK_PLATFORM_EXPORT Platform { +@@ -625,6 +625,7 @@ class BLINK_PLATFORM_EXPORT Platform { virtual void DidStartWorkerThread() {} virtual void WillStopWorkerThread() {} virtual void WorkerContextCreated(const v8::Local& worker) {} @@ -67,10 +67,10 @@ index d188491afffbd259d4287b0668a9d1cec291934a..2fe5234832f8a3510326171e1ccf5dbf const WebSecurityOrigin& script_origin) { return false; diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc -index 3d29142e7e9d641d17ad16a8b24bf263f0bd4c73..9f5f07b2865df5ed8dd4a8c01082f4378b5f9ccf 100644 +index 20d674166c78e316751bfa3ec7aed74656eea9b4..d289cfca8d8a9b093d8d30427e594c46b2f56c79 100644 --- a/third_party/blink/renderer/core/workers/worker_thread.cc +++ b/third_party/blink/renderer/core/workers/worker_thread.cc -@@ -730,6 +730,12 @@ void WorkerThread::PrepareForShutdownOnWorkerThread() { +@@ -744,6 +744,12 @@ void WorkerThread::PrepareForShutdownOnWorkerThread() { nested_runner_->QuitNow(); } diff --git a/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch b/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch index 78c40be5909da..d33d2271d35af 100644 --- a/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch +++ b/patches/chromium/worker_feat_add_hook_to_notify_script_ready.patch @@ -19,10 +19,10 @@ that clearly establishes the worker script is ready for evaluation with the scop initialized. diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h -index 8512a66eda07202b6c6faea049736fd8f16c93db..afe767350c8878da38ab2b566fa89bcb831f8716 100644 +index e0b308051be9b34ce26b65f6cd582beb7743662d..857d5eb211890b10e143f54662636f2ba522b698 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h -@@ -361,6 +361,11 @@ class CONTENT_EXPORT ContentRendererClient { +@@ -365,6 +365,11 @@ class CONTENT_EXPORT ContentRendererClient { virtual void DidInitializeWorkerContextOnWorkerThread( v8::Local context) {} @@ -35,10 +35,10 @@ index 8512a66eda07202b6c6faea049736fd8f16c93db..afe767350c8878da38ab2b566fa89bcb // from the worker thread. virtual void WillDestroyWorkerContextOnWorkerThread( diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc -index 0ea0012253d8348f1ba204f3b1fca7c5e2d306ce..8851d8bd283e1d44a921034e969f160ff494d6f9 100644 +index 53b42b67823474fc5c688654da280cde82faea87..db175070bdcefc84f1d6001568941a9f4f14789c 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc -@@ -966,6 +966,12 @@ void RendererBlinkPlatformImpl::WorkerContextCreated( +@@ -872,6 +872,12 @@ void RendererBlinkPlatformImpl::WorkerContextCreated( worker); } @@ -52,10 +52,10 @@ index 0ea0012253d8348f1ba204f3b1fca7c5e2d306ce..8851d8bd283e1d44a921034e969f160f const blink::WebSecurityOrigin& script_origin) { return GetContentClient()->renderer()->AllowScriptExtensionForServiceWorker( diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h -index ab771fe015c195f53ce8bb1411050635f02c69f3..a78d38985b3761a63cc4efbd354820c6fd258d9c 100644 +index 8f80fb04990c3e2820dcbc9b89dc0255c9c49d30..f16af9a3e4027066cddbd5082998adc837e9b5dc 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h -@@ -209,6 +209,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { +@@ -180,6 +180,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { void DidStartWorkerThread() override; void WillStopWorkerThread() override; void WorkerContextCreated(const v8::Local& worker) override; @@ -65,10 +65,10 @@ index ab771fe015c195f53ce8bb1411050635f02c69f3..a78d38985b3761a63cc4efbd354820c6 bool AllowScriptExtensionForServiceWorker( const blink::WebSecurityOrigin& script_origin) override; diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h -index 2fe5234832f8a3510326171e1ccf5dbfeca49fc9..b36a118861b2efae6ae28ef0e7f14db5d284b929 100644 +index b5cff1fee2d14c02f2d67cf012b7ba24fc3a7a06..765c0882406fa0ab7ae3d0460ff9a9814f60db0a 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h -@@ -720,6 +720,8 @@ class BLINK_PLATFORM_EXPORT Platform { +@@ -625,6 +625,8 @@ class BLINK_PLATFORM_EXPORT Platform { virtual void DidStartWorkerThread() {} virtual void WillStopWorkerThread() {} virtual void WorkerContextCreated(const v8::Local& worker) {} @@ -78,10 +78,10 @@ index 2fe5234832f8a3510326171e1ccf5dbfeca49fc9..b36a118861b2efae6ae28ef0e7f14db5 virtual bool AllowScriptExtensionForServiceWorker( const WebSecurityOrigin& script_origin) { diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc -index 03288c7b1897ee2c18b80677ee5837246d36568a..fc10bbf3d92c7f88c734d8ecfb20dbc4b72ae200 100644 +index ae3d2a664a9bd758d495f90f237f4f0ae768aef9..b56470ef35862f1b1b2af69bc48d842d2aa4ba7c 100644 --- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc +++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc -@@ -257,6 +257,7 @@ void WorkerOrWorkletScriptController::PrepareForEvaluation() { +@@ -262,6 +262,7 @@ void WorkerOrWorkletScriptController::PrepareForEvaluation() { V8PerContextData* per_context_data = script_state_->PerContextData(); std::ignore = per_context_data->ConstructorForType(global_scope_->GetWrapperTypeInfo()); diff --git a/patches/config.json b/patches/config.json index 1f10e013b33b3..e142fc9deee0d 100644 --- a/patches/config.json +++ b/patches/config.json @@ -5,6 +5,8 @@ "src/electron/patches/devtools_frontend": "src/third_party/devtools-frontend/src", + "src/electron/patches/ffmpeg": "src/third_party/ffmpeg", + "src/electron/patches/webrtc": "src/third_party/webrtc", "src/electron/patches/v8": "src/v8", diff --git a/patches/devtools_frontend/fix_expose_globals_to_allow_patching_devtools_dock.patch b/patches/devtools_frontend/fix_expose_globals_to_allow_patching_devtools_dock.patch index 98510d24c4e2c..e94b4197ec86b 100644 --- a/patches/devtools_frontend/fix_expose_globals_to_allow_patching_devtools_dock.patch +++ b/patches/devtools_frontend/fix_expose_globals_to_allow_patching_devtools_dock.patch @@ -12,7 +12,7 @@ upstream a more durable approach to allowing us to do this, at which point this patch can be removed. diff --git a/front_end/entrypoints/shell/BUILD.gn b/front_end/entrypoints/shell/BUILD.gn -index bf96adcaa42a2406cf1dd7cd2468802886aa4fd7..cd84442cab4a0da772dd37cd4e921041b3b6173a 100644 +index 848d6edb722a88aa2d1b42290e65d677f5107acf..86e1c70d7693db0f1a6df32f0413c45f4854e586 100644 --- a/front_end/entrypoints/shell/BUILD.gn +++ b/front_end/entrypoints/shell/BUILD.gn @@ -31,6 +31,7 @@ devtools_entrypoint("shell") { diff --git a/patches/ffmpeg/.patches b/patches/ffmpeg/.patches new file mode 100644 index 0000000000000..31dc878c5b29c --- /dev/null +++ b/patches/ffmpeg/.patches @@ -0,0 +1 @@ +link_with_loader_path.patch diff --git a/patches/ffmpeg/link_with_loader_path.patch b/patches/ffmpeg/link_with_loader_path.patch new file mode 100644 index 0000000000000..6665cd91ff354 --- /dev/null +++ b/patches/ffmpeg/link_with_loader_path.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cheng Zhao +Date: Tue, 2 Aug 2022 11:53:00 +0900 +Subject: fix: link with @loader_path/libffmpeg.dylib + +Submitted to https://chromium-review.googlesource.com/c/chromium/third_party/ffmpeg/+/3803946. + +When building with `is_component_build=false is_component_ffmpeg=true`, +we must manually instruct executables to link with the ffmpeg.dylib, +which is generated at the @loader_path, where for most targets is the +out/{Release,Debug} dir. + +Using @rpath is wrong because the @rpath of most targets does not +include the out dir, and the linker won't be able to find ffmpeg.dylib +because of so. + +diff --git a/BUILD.gn b/BUILD.gn +index 5ea4e373360f1e09d8295be89beb063f482ec165..4fd65674d1a2a94868de6aa32bdde04a4b9c2662 100755 +--- a/BUILD.gn ++++ b/BUILD.gn +@@ -448,7 +448,7 @@ if (is_component_ffmpeg) { + + if (!is_component_build) { + if (is_mac) { +- ldflags += [ "-Wl,-install_name,@rpath/libffmpeg.dylib" ] ++ ldflags += [ "-Wl,-install_name,@loader_path/libffmpeg.dylib" ] + } else if (is_linux) { + all_dependent_configs = [ + "//build/config/gcc:rpath_for_built_shared_libraries", diff --git a/docs/fiddles/communication/two-processes/.keep b/patches/lss/.patches similarity index 100% rename from docs/fiddles/communication/two-processes/.keep rename to patches/lss/.patches diff --git a/patches/nan/.patches b/patches/nan/.patches index 5a0539df8d7b2..55f1dd90c6bb6 100644 --- a/patches/nan/.patches +++ b/patches/nan/.patches @@ -1 +1,2 @@ -use_new_constructor_for_scriptorigin.patch +use_new_constructor_for_scriptorigin_when_17_x.patch +chore_remove_deprecated_accessorsignatures.patch diff --git a/patches/nan/chore_remove_deprecated_accessorsignatures.patch b/patches/nan/chore_remove_deprecated_accessorsignatures.patch new file mode 100644 index 0000000000000..8cd9f2000153a --- /dev/null +++ b/patches/nan/chore_remove_deprecated_accessorsignatures.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr +Date: Thu, 2 Jun 2022 15:45:21 +0200 +Subject: chore: remove deprecated AccessorSignatures + +Removed in https://chromium-review.googlesource.com/c/v8/v8/+/3654096 +Upstreamed to nan: https://github.com/nodejs/nan/pull/941 + +diff --git a/nan.h b/nan.h +index df5496c1a001120d10cd7c4b87d5e7bce8169f38..c29a99b79970421a15c5520a94ab65b1c3c473ff 100644 +--- a/nan.h ++++ b/nan.h +@@ -2516,8 +2516,7 @@ inline void SetAccessor( + , SetterCallback setter = 0 + , v8::Local data = v8::Local() + , v8::AccessControl settings = v8::DEFAULT +- , v8::PropertyAttribute attribute = v8::None +- , imp::Sig signature = imp::Sig()) { ++ , v8::PropertyAttribute attribute = v8::None) { + HandleScope scope; + + imp::NativeGetter getter_ = +@@ -2550,9 +2549,6 @@ inline void SetAccessor( + , obj + , settings + , attribute +-#if (NODE_MODULE_VERSION < NODE_18_0_MODULE_VERSION) +- , signature +-#endif + ); + } + +diff --git a/nan_callbacks.h b/nan_callbacks.h +index 53ede846ac9a865a737218dabbbd48305d3d6b63..ea81e452d364e3d3c15a121dc69ae21134bfb586 100644 +--- a/nan_callbacks.h ++++ b/nan_callbacks.h +@@ -52,8 +52,6 @@ typedef void(*IndexQueryCallback)( + const PropertyCallbackInfo&); + + namespace imp { +-typedef v8::Local Sig; +- + static const int kDataIndex = 0; + + static const int kFunctionIndex = 1; diff --git a/patches/nan/use_new_constructor_for_scriptorigin.patch b/patches/nan/use_new_constructor_for_scriptorigin.patch deleted file mode 100644 index dfa36b750afc2..0000000000000 --- a/patches/nan/use_new_constructor_for_scriptorigin.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeremy Rose -Date: Fri, 28 Jan 2022 13:46:07 -0800 -Subject: use new constructor for ScriptOrigin - -https://chromium-review.googlesource.com/c/v8/v8/+/3395880 - -diff --git a/test/cpp/nannew.cpp b/test/cpp/nannew.cpp -index 64c857996c4626f3a447bdb796d4d581a37d9299..95a12f9521b8c9bed0e5eed85b6e56917069ea09 100644 ---- a/test/cpp/nannew.cpp -+++ b/test/cpp/nannew.cpp -@@ -248,7 +248,7 @@ NAN_METHOD(testScript) { - - #if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 8 || \ - (V8_MAJOR_VERSION == 8 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 9)) -- ScriptOrigin origin(New("foo").ToLocalChecked(), 5); -+ ScriptOrigin origin(v8::Isolate::GetCurrent(), New("foo").ToLocalChecked(), 5); - #else - ScriptOrigin origin(New("foo").ToLocalChecked(), New(5)); - #endif -diff --git a/test/cpp/news.cpp b/test/cpp/news.cpp -index 5b54c0cedaaa824be71b8c6fee948139a34d3310..f0aa65cc80741d57ba6675f7d5d5908b24f601c5 100644 ---- a/test/cpp/news.cpp -+++ b/test/cpp/news.cpp -@@ -114,7 +114,7 @@ NAN_METHOD(NewScript) { - } - - NAN_METHOD(NewScript2) { -- v8::ScriptOrigin origin(New("x").ToLocalChecked()); -+ v8::ScriptOrigin origin(v8::Isolate::GetCurrent(), New("x").ToLocalChecked()); - v8::Local script = - New( - New("2+4").ToLocalChecked() -@@ -131,7 +131,7 @@ NAN_METHOD(CompileScript) { - } - - NAN_METHOD(CompileScript2) { -- v8::ScriptOrigin origin(New("x").ToLocalChecked()); -+ v8::ScriptOrigin origin(v8::Isolate::GetCurrent(), New("x").ToLocalChecked()); - v8::Local script = - CompileScript(New("2+4").ToLocalChecked(), origin).ToLocalChecked(); - info.GetReturnValue().Set( diff --git a/patches/nan/use_new_constructor_for_scriptorigin_when_17_x.patch b/patches/nan/use_new_constructor_for_scriptorigin_when_17_x.patch new file mode 100644 index 0000000000000..e2c18d2e64dd3 --- /dev/null +++ b/patches/nan/use_new_constructor_for_scriptorigin_when_17_x.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Rose +Date: Thu, 5 May 2022 14:14:36 -0700 +Subject: use new constructor for ScriptOrigin when >= 17.x + +https://chromium-review.googlesource.com/c/v8/v8/+/3395880 + +diff --git a/test/cpp/news.cpp b/test/cpp/news.cpp +index a218167c7e3a5ec90c6668943cb395dba2bbe3a7..08557d5478d5400445603deffd721525ecbf746e 100644 +--- a/test/cpp/news.cpp ++++ b/test/cpp/news.cpp +@@ -115,7 +115,7 @@ NAN_METHOD(NewScript) { + + NAN_METHOD(NewScript2) { + v8::ScriptOrigin origin( +-#if NODE_MODULE_VERSION >= NODE_18_0_MODULE_VERSION ++#if NODE_MODULE_VERSION >= NODE_17_0_MODULE_VERSION + info.GetIsolate(), + #endif + New("x").ToLocalChecked()); +@@ -136,7 +136,7 @@ NAN_METHOD(CompileScript) { + + NAN_METHOD(CompileScript2) { + v8::ScriptOrigin origin( +-#if NODE_MODULE_VERSION >= NODE_18_0_MODULE_VERSION ++#if NODE_MODULE_VERSION >= NODE_17_0_MODULE_VERSION + info.GetIsolate(), + #endif + New("x").ToLocalChecked()); diff --git a/patches/node/.patches b/patches/node/.patches index a726f4c9972f8..298d3c8426171 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -1,10 +1,8 @@ refactor_alter_child_process_fork_to_use_execute_script_with.patch -feat_add_uv_loop_watcher_queue_code.patch feat_initialize_asar_support.patch expose_get_builtin_module_function.patch build_add_gn_build_files.patch fix_add_default_values_for_variables_in_common_gypi.patch -feat_add_flags_for_low-level_hooks_and_exceptions.patch fix_expose_tracing_agent_and_use_tracing_tracingcontroller_instead.patch pass_all_globals_through_require.patch build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch @@ -12,29 +10,23 @@ refactor_allow_embedder_overriding_of_internal_fs_calls.patch chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch chore_add_context_to_context_aware_module_prevention.patch chore_read_nobrowserglobals_from_global_not_process.patch -enable_31_bit_smis_on_64bit_arch_and_ptr_compression.patch fix_handle_boringssl_and_openssl_incompatibilities.patch -fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch -fix_allow_preventing_initializeinspector_in_env.patch src_allow_embedders_to_provide_a_custom_pageallocator_to.patch fix_crypto_tests_to_run_with_bssl.patch fix_account_for_debugger_agent_race_condition.patch -add_should_read_node_options_from_env_option_to_disable_node_options.patch repl_fix_crash_when_sharedarraybuffer_disabled.patch fix_readbarrier_undefined_symbol_error_on_woa_arm64.patch -chore_fix_-wimplicit-fallthrough.patch -test_add_fixture_trim_option.patch fix_crash_caused_by_gethostnamew_on_windows_7.patch fix_suppress_clang_-wdeprecated-declarations_in_libuv.patch -fix_don_t_create_console_window_when_creating_process.patch +fix_serdes_test.patch darwin_remove_eprototype_error_workaround_3405.patch darwin_translate_eprototype_to_econnreset_3413.patch darwin_bump_minimum_supported_version_to_10_15_3406.patch -fix_serdes_test.patch fix_failing_node_js_test_on_outdated.patch be_compatible_with_cppgc.patch +feat_add_knostartdebugsignalhandler_to_environment_to_prevent.patch +worker_thread_add_asar_support.patch process_monitor_for_exit_with_kqueue_on_bsds_3441.patch -unix_protect_fork_in_uv_spawn_from_signals.patch process_bsd_handle_kevent_note_exit_failure_3451.patch reland_macos_use_posix_spawn_instead_of_fork_3257.patch process_reset_the_signal_mask_if_the_fork_fails_3537.patch @@ -44,5 +36,17 @@ unix_remove_uv_cloexec_ioctl_3515.patch process_simplify_uv_write_int_calls_3519.patch macos_don_t_use_thread-unsafe_strtok_3524.patch process_fix_hang_after_note_exit_3521.patch -worker_thread_add_asar_support.patch +feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch +fix_preserve_proper_method_names_as-is_in_error_stack.patch macos_avoid_posix_spawnp_cwd_bug_3597.patch +src_update_importmoduledynamically.patch +fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch +json_parse_errors_made_user-friendly.patch +support_v8_sandboxed_pointers.patch +build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch +build_ensure_native_module_compilation_fails_if_not_using_a_new.patch +fix_override_createjob_in_node_platform.patch +buffer_fix_atob_input_validation.patch +v8_api_advance_api_deprecation.patch +enable_-wunqualified-std-cast-call.patch +fix_expose_the_built-in_electron_module_via_the_esm_loader.patch diff --git a/patches/node/add_should_read_node_options_from_env_option_to_disable_node_options.patch b/patches/node/add_should_read_node_options_from_env_option_to_disable_node_options.patch deleted file mode 100644 index 8f7b86fbef1fb..0000000000000 --- a/patches/node/add_should_read_node_options_from_env_option_to_disable_node_options.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Samuel Attard -Date: Wed, 21 Jul 2021 13:40:59 -0700 -Subject: add should_read_node_options_from_env option to disable NODE_OPTIONS - parsing at runtime - -We can remove the NODE_OPTIONS environment variable but it in theory could be injected / re-inserted at runtime and be used for workers. In order to ensure the fuse is respected we need a hard runtime toggle for NODE_OPTION support. - -diff --git a/src/env.cc b/src/env.cc -index 2cb2dccdf32ba4ad58972bb1d2b185996104b5ee..0abd61d6ddd1fb55afde40b38cf7c9400a8c3d41 100644 ---- a/src/env.cc -+++ b/src/env.cc -@@ -329,6 +329,9 @@ std::string GetExecPath(const std::vector& argv) { - return exec_path; - } - -+/* static */ -+bool Environment::should_read_node_options_from_env_ = true; -+ - Environment::Environment(IsolateData* isolate_data, - Isolate* isolate, - const std::vector& args, -diff --git a/src/env.h b/src/env.h -index e0deca497feb111622b257b952c9ed9161c7d001..ab8334bf0e3405fee4d21a4b541bd1164d92ca89 100644 ---- a/src/env.h -+++ b/src/env.h -@@ -1145,6 +1145,8 @@ class Environment : public MemoryRetainer { - inline double trigger_async_id(); - inline double get_default_trigger_async_id(); - -+ static bool should_read_node_options_from_env_; -+ - // List of id's that have been destroyed and need the destroy() cb called. - inline std::vector* destroy_async_id_list(); - -diff --git a/src/node.cc b/src/node.cc -index 207a95d202b4e422a39f837241f1655f7111b1e3..14b9002dbd918b59b05d8b12c5441080695ed9f0 100644 ---- a/src/node.cc -+++ b/src/node.cc -@@ -875,7 +875,7 @@ int InitializeNodeWithArgs(std::vector* argv, - #if !defined(NODE_WITHOUT_NODE_OPTIONS) - std::string node_options; - -- if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) { -+ if (Environment::should_read_node_options_from_env_ && credentials::SafeGetenv("NODE_OPTIONS", &node_options)) { - std::vector env_argv = - ParseNodeOptionsEnvVar(node_options, errors); - -diff --git a/src/node_worker.cc b/src/node_worker.cc -index 16b7be36f284311f38583fa1df28a2945560b524..62a7dae080fad7e18863968dee22dbe4b461ab82 100644 ---- a/src/node_worker.cc -+++ b/src/node_worker.cc -@@ -467,6 +467,7 @@ void Worker::New(const FunctionCallbackInfo& args) { - }); - - #ifndef NODE_WITHOUT_NODE_OPTIONS -+ if (Environment::should_read_node_options_from_env_) { - MaybeLocal maybe_node_opts = - env_vars->Get(isolate, OneByteString(isolate, "NODE_OPTIONS")); - Local node_opts; -@@ -497,6 +498,7 @@ void Worker::New(const FunctionCallbackInfo& args) { - return; - } - } -+ } - #endif - } - diff --git a/patches/node/be_compatible_with_cppgc.patch b/patches/node/be_compatible_with_cppgc.patch index 3bbc3ce0bde16..c907fff1e20a4 100644 --- a/patches/node/be_compatible_with_cppgc.patch +++ b/patches/node/be_compatible_with_cppgc.patch @@ -83,7 +83,7 @@ index bb1e8d4b46bce3bf08f730ac5d43f7113d17ae39..6da0669943fc6465ffc47a1c8c3dadfe } diff --git a/src/base_object.h b/src/base_object.h -index d46a0f216009c63f45c440fc352b54d1ac4a08d8..81913c0d7762bf499ee19aaa3b63b986ca370bb4 100644 +index 1c63da92fd80c042d5ea729bdd70049cae51a141..3b8127e884187b21cebeabb39b60bd3010b62217 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -40,7 +40,7 @@ class TransferData; diff --git a/patches/node/buffer_fix_atob_input_validation.patch b/patches/node/buffer_fix_atob_input_validation.patch new file mode 100644 index 0000000000000..a4285f7b7223e --- /dev/null +++ b/patches/node/buffer_fix_atob_input_validation.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr +Date: Tue, 23 Aug 2022 11:13:45 +0200 +Subject: buffer: fix `atob` input validation + +This patch combines: + +* https://github.com/nodejs/node/pull/42539 +* https://github.com/nodejs/node/pull/42662 + +To bring the Node.js implementation of atob into alignment with the +WHATWG spec. + +diff --git a/lib/buffer.js b/lib/buffer.js +index 57d6cddbaa2e6bdd846a667897588dea18daeb42..7602d4049e9bb1c09440bc3af09ad5ad9c768308 100644 +--- a/lib/buffer.js ++++ b/lib/buffer.js +@@ -23,8 +23,10 @@ + + const { + Array, ++ ArrayFrom, + ArrayIsArray, + ArrayPrototypeForEach, ++ ArrayPrototypeIndexOf, + MathFloor, + MathMin, + MathTrunc, +@@ -1231,8 +1233,25 @@ function btoa(input) { + return buf.toString('base64'); + } + +-const kBase64Digits = +- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; ++// Refs: https://infra.spec.whatwg.org/#forgiving-base64-decode ++const kForgivingBase64AllowedChars = [ ++ // ASCII whitespace ++ // Refs: https://infra.spec.whatwg.org/#ascii-whitespace ++ 0x09, 0x0A, 0x0C, 0x0D, 0x20, ++ ++ // Uppercase letters ++ ...ArrayFrom({ length: 26 }, (_, i) => StringPrototypeCharCodeAt('A') + i), ++ ++ // Lowercase letters ++ ...ArrayFrom({ length: 26 }, (_, i) => StringPrototypeCharCodeAt('a') + i), ++ ++ // Decimal digits ++ ...ArrayFrom({ length: 10 }, (_, i) => StringPrototypeCharCodeAt('0') + i), ++ ++ 0x2B, // + ++ 0x2F, // / ++ 0x3D, // = ++]; + + function atob(input) { + // The implementation here has not been performance optimized in any way and +@@ -1241,11 +1260,31 @@ function atob(input) { + if (arguments.length === 0) { + throw new ERR_MISSING_ARGS('input'); + } ++ + input = `${input}`; ++ let nonAsciiWhitespaceCharCount = 0; ++ + for (let n = 0; n < input.length; n++) { +- if (!kBase64Digits.includes(input[n])) ++ const index = ArrayPrototypeIndexOf( ++ kForgivingBase64AllowedChars, ++ StringPrototypeCharCodeAt(input, n)); ++ ++ if (index > 4) { ++ // The first 5 elements of `kForgivingBase64AllowedChars` are ++ // ASCII whitespace char codes. ++ nonAsciiWhitespaceCharCount++; ++ } else if (index === -1) { + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); ++ } + } ++ ++ // See #3 - https://infra.spec.whatwg.org/#forgiving-base64 ++ if (nonAsciiWhitespaceCharCount % 4 === 1) { ++ throw lazyDOMException( ++ 'The string to be decoded is not correctly encoded.', ++ 'InvalidCharacterError'); ++ } ++ + return Buffer.from(input, 'base64').toString('latin1'); + } + diff --git a/patches/node/build_add_gn_build_files.patch b/patches/node/build_add_gn_build_files.patch index 9fe9d6153f9d1..8b8ed6a9e3d63 100644 --- a/patches/node/build_add_gn_build_files.patch +++ b/patches/node/build_add_gn_build_files.patch @@ -7,12 +7,12 @@ This adds GN build files for Node, so we don't have to build with GYP. diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 -index 0000000000000000000000000000000000000000..bd5788caa61305fd9af8f9d7f8f1937a224fda83 +index 0000000000000000000000000000000000000000..9e34a074cfa7dec61c4e11821ba5f1969f393dfb --- /dev/null +++ b/BUILD.gn -@@ -0,0 +1,394 @@ -+import("//electron/build/asar.gni") +@@ -0,0 +1,403 @@ +import("//v8/gni/v8.gni") ++import("node.gni") + +declare_args() { + # Enable the V8 inspector protocol for use with node. @@ -192,6 +192,15 @@ index 0000000000000000000000000000000000000000..bd5788caa61305fd9af8f9d7f8f1937a + } +} + ++executable("overlapped-checker") { ++ sources = [] ++ if (is_win) { ++ sources += [ "test/overlapped-checker/main_win.c" ] ++ } else { ++ sources += [ "test/overlapped-checker/main_unix.c" ] ++ } ++} ++ +component("node_lib") { + deps = [ + ":node_js2c", @@ -663,10 +672,10 @@ index 0000000000000000000000000000000000000000..fb000f8ee7647c375bc190d1729d67bb +} diff --git a/deps/nghttp2/BUILD.gn b/deps/nghttp2/BUILD.gn new file mode 100644 -index 0000000000000000000000000000000000000000..8bfecba74d4d90e9fbf0e2cd301118e4adc6cba8 +index 0000000000000000000000000000000000000000..9abde472d88923db835b12982b7f2ccb1f260196 --- /dev/null +++ b/deps/nghttp2/BUILD.gn -@@ -0,0 +1,49 @@ +@@ -0,0 +1,47 @@ +config("nghttp2_config") { + defines = [ "NGHTTP2_STATICLIB" ] + include_dirs = [ "lib/includes" ] @@ -677,11 +686,9 @@ index 0000000000000000000000000000000000000000..8bfecba74d4d90e9fbf0e2cd301118e4 + "_U_", + "BUILDING_NGHTTP2", + "NGHTTP2_STATICLIB", ++ "HAVE_CONFIG_H", + ] + include_dirs = [ "lib/includes" ] -+ if (is_win) { -+ defines += [ "HAVE_CONFIG_H" ] -+ } + + cflags_c = [ + "-Wno-implicit-function-declaration", @@ -964,10 +971,10 @@ index 0000000000000000000000000000000000000000..2c9d2826c85bdd033f1df1d6188df636 +} diff --git a/filenames.json b/filenames.json new file mode 100644 -index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc41054754 +index 0000000000000000000000000000000000000000..a2cfdffcd7308b73c5c302ebc4b946c6de1bd518 --- /dev/null +++ b/filenames.json -@@ -0,0 +1,604 @@ +@@ -0,0 +1,616 @@ +// This file is automatically generated by generate_gn_filenames_json.py +// DO NOT EDIT +{ @@ -1191,6 +1198,7 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "lib/internal/blob.js", + "lib/internal/socket_list.js", + "lib/internal/socketaddress.js", ++ "lib/internal/promise_hooks.js", + "lib/internal/stream_base_commons.js", + "lib/internal/url.js", + "lib/internal/async_hooks.js", @@ -1223,12 +1231,14 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "lib/internal/cluster/primary.js", + "lib/internal/cluster/utils.js", + "lib/internal/cluster/child.js", ++ "lib/internal/webstreams/compression.js", + "lib/internal/webstreams/util.js", + "lib/internal/webstreams/writablestream.js", + "lib/internal/webstreams/readablestream.js", + "lib/internal/webstreams/queuingstrategies.js", + "lib/internal/webstreams/encoding.js", + "lib/internal/webstreams/transformstream.js", ++ "lib/internal/webstreams/adapters.js", + "lib/internal/webstreams/transfer.js", + "lib/internal/bootstrap/loaders.js", + "lib/internal/bootstrap/pre_execution.js", @@ -1252,6 +1262,7 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "lib/internal/streams/destroy.js", + "lib/internal/streams/legacy.js", + "lib/internal/streams/passthrough.js", ++ "lib/internal/streams/operators.js", + "lib/internal/streams/readable.js", + "lib/internal/streams/from.js", + "lib/internal/streams/writable.js", @@ -1263,6 +1274,7 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "lib/internal/streams/lazy_transform.js", + "lib/internal/streams/duplex.js", + "lib/internal/streams/pipeline.js", ++ "lib/internal/readline/interface.js", + "lib/internal/readline/utils.js", + "lib/internal/readline/emitKeypressEvents.js", + "lib/internal/readline/callbacks.js", @@ -1300,13 +1312,18 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "lib/internal/modules/run_main.js", + "lib/internal/modules/package_json_reader.js", + "lib/internal/modules/esm/module_job.js", ++ "lib/internal/modules/esm/assert.js", ++ "lib/internal/modules/esm/fetch_module.js", + "lib/internal/modules/esm/get_source.js", + "lib/internal/modules/esm/translators.js", + "lib/internal/modules/esm/resolve.js", + "lib/internal/modules/esm/create_dynamic_module.js", + "lib/internal/modules/esm/load.js", ++ "lib/internal/modules/esm/handle_process_exit.js", ++ "lib/internal/modules/esm/initialize_import_meta.js", + "lib/internal/modules/esm/module_map.js", + "lib/internal/modules/esm/get_format.js", ++ "lib/internal/modules/esm/formats.js", + "lib/internal/modules/esm/loader.js", + "lib/internal/modules/cjs/helpers.js", + "lib/internal/modules/cjs/loader.js", @@ -1365,7 +1382,8 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "deps/acorn/acorn/dist/acorn.js", + "deps/acorn/acorn-walk/dist/walk.js", + "deps/cjs-module-lexer/lexer.js", -+ "deps/cjs-module-lexer/dist/lexer.js" ++ "deps/cjs-module-lexer/dist/lexer.js", ++ "deps/undici/undici.js" + ], + "node_sources": [ + "src/api/async_resource.cc", @@ -1565,6 +1583,7 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "src/tracing/trace_event_common.h", + "src/tracing/traced_value.h", + "src/timer_wrap.h", ++ "src/timer_wrap-inl.h", + "src/tty_wrap.h", + "src/udp_wrap.h", + "src/util.h", @@ -1572,6 +1591,41 @@ index 0000000000000000000000000000000000000000..ac32bd83b683b048ffde3314f4caebbc + "//v8/include/v8.h" + ] +} +diff --git a/node.gni b/node.gni +new file mode 100644 +index 0000000000000000000000000000000000000000..9b1a4048a4a64c36d88de0bbe1a548c906aaa22c +--- /dev/null ++++ b/node.gni +@@ -0,0 +1,29 @@ ++# 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, ++ "*", ++ [ ++ "script", ++ "args", ++ ]) ++ 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 ] ++ } ++ args = [ ++ rebase_path(cwd), ++ rebase_path(invoker.script), ++ ] ++ args += invoker.args ++ } ++} diff --git a/src/inspector/BUILD.gn b/src/inspector/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d1d6b51e8c0c5bc6a5d09e217eb3048361d9d591 @@ -1778,7 +1832,7 @@ index 0000000000000000000000000000000000000000..d1d6b51e8c0c5bc6a5d09e217eb30483 + args = rebase_path(inputs + outputs, root_build_dir) +} diff --git a/src/node_version.h b/src/node_version.h -index 31e75367f8263f575f37243475acb58bb5c40d04..8f102792fe66847dad0ba7176299cf09686cd182 100644 +index 0f1a9b52cccba1e54150494a7ee5b28961a8d59d..bb68b2dfef4a693d8a1d0fe056fe696254d12d09 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -89,7 +89,10 @@ @@ -1905,10 +1959,10 @@ index 0000000000000000000000000000000000000000..2a92eccfa582df361f2a889c0d9b32c1 + + out_file.writelines(new_contents) diff --git a/tools/install.py b/tools/install.py -index 41cc1cbc60a9480cc08df3aa0ebe582c2becc3a2..dd13ad149f1b4cb807ca7aff62e1b15718116855 100755 +index 8a050dfa7c8b771ceb30fd2b74dc47f3de96834c..ad3bee1660de26d3502c6247f23b091171a6416c 100755 --- a/tools/install.py +++ b/tools/install.py -@@ -170,17 +170,72 @@ def files(action): +@@ -172,17 +172,72 @@ def files(action): def headers(action): def wanted_v8_headers(files_arg, dest): v8_headers = [ @@ -1991,7 +2045,7 @@ index 41cc1cbc60a9480cc08df3aa0ebe582c2becc3a2..dd13ad149f1b4cb807ca7aff62e1b157 files_arg = [name for name in files_arg if name in v8_headers] action(files_arg, dest) -@@ -201,7 +256,7 @@ def headers(action): +@@ -209,7 +264,7 @@ def headers(action): if sys.platform.startswith('aix'): action(['out/Release/node.exp'], 'include/node/') diff --git a/patches/node/build_ensure_native_module_compilation_fails_if_not_using_a_new.patch b/patches/node/build_ensure_native_module_compilation_fails_if_not_using_a_new.patch new file mode 100644 index 0000000000000..7b7150085658a --- /dev/null +++ b/patches/node/build_ensure_native_module_compilation_fails_if_not_using_a_new.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Wed, 13 Jul 2022 13:56:12 -0700 +Subject: build: ensure native module compilation fails if not using a new + enough builder + +This should not be upstreamed, it is a quality-of-life patch for downstream module builders. + +diff --git a/common.gypi b/common.gypi +index ca08deeb19f5fe9ee399ad809b24579fdaa10036..c68cf1eb0f9cdd2a8fe314237c1e790fe3690272 100644 +--- a/common.gypi ++++ b/common.gypi +@@ -85,6 +85,8 @@ + + 'v8_enable_reverse_jsargs%': 1, + ++ 'using_electron_config_gypi%': 0, ++ + ##### end V8 defaults ##### + + # When building native modules using 'npm install' with the system npm, +@@ -290,6 +292,7 @@ + 'V8_DEPRECATION_WARNINGS', + 'V8_IMMINENT_DEPRECATION_WARNINGS', + '_GLIBCXX_USE_CXX11_ABI=1', ++ 'ELECTRON_ENSURE_CONFIG_GYPI', + ], + + # Forcibly disable -Werror. We support a wide range of compilers, it's +@@ -393,6 +396,11 @@ + }], + ], + }], ++ ['using_electron_config_gypi == 1', { ++ 'defines': [ ++ 'USING_ELECTRON_CONFIG_GYPI', ++ ], ++ }], + ['v8_enable_pointer_compression == 1', { + 'defines': [ + 'V8_COMPRESS_POINTERS', +diff --git a/configure.py b/configure.py +index 426afed7cd0a3a403d4b753af0b25f55024d0f71..6ab1469c07298c9083a77d0211727a6fff37267e 100755 +--- a/configure.py ++++ b/configure.py +@@ -1427,6 +1427,7 @@ def configure_library(lib, output, pkgname=None): + + + def configure_v8(o): ++ o['variables']['using_electron_config_gypi'] = 1 + o['variables']['v8_enable_webassembly'] = 1 + o['variables']['v8_enable_lite_mode'] = 1 if options.v8_lite_mode else 0 + o['variables']['v8_enable_gdbjit'] = 1 if options.gdb else 0 +diff --git a/src/node.h b/src/node.h +index 0b807cb25f9eb52b2100f0e2a7c25344790967cf..a41b09047d2c499a90225651a8324ad83a7712e3 100644 +--- a/src/node.h ++++ b/src/node.h +@@ -22,6 +22,12 @@ + #ifndef SRC_NODE_H_ + #define SRC_NODE_H_ + ++#ifdef ELECTRON_ENSURE_CONFIG_GYPI ++#ifndef USING_ELECTRON_CONFIG_GYPI ++#error "It looks like you are building this native module without using the right config.gypi. This normally means that you need to update electron-rebuild (>=3.2.8) or node-gyp (>=8.4.0) if you're building modules directly." ++#endif ++#endif ++ + #ifdef _WIN32 + # ifndef BUILDING_NODE_EXTENSION + # define NODE_EXTERN __declspec(dllexport) diff --git a/patches/node/build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch b/patches/node/build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch new file mode 100644 index 0000000000000..b21f8958be5d3 --- /dev/null +++ b/patches/node/build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Thu, 7 Jul 2022 14:42:49 -0700 +Subject: build: ensure v8 pointer compression + sandbox is enabled on 64bit + +Aligns common.gypi with the current build flag state of //v8. + +Specifically enables `V8_ENABLE_SANDBOX`, `V8_SANDBOXED_POINTERS`, `V8_COMPRESS_POINTERS` and `V8_COMPRESS_POINTERS_IN_SHARED_CAGE`. + +diff --git a/common.gypi b/common.gypi +index bdfe81d11cc50f492c93fe48f6946765b6fb5238..ca08deeb19f5fe9ee399ad809b24579fdaa10036 100644 +--- a/common.gypi ++++ b/common.gypi +@@ -65,6 +65,7 @@ + # node-gyp to build addons. + 'v8_enable_pointer_compression%': 0, + 'v8_enable_31bit_smis_on_64bit_arch%': 0, ++ 'v8_enable_sandbox%': 0, + + # Disable V8 untrusted code mitigations. + # See https://github.com/v8/v8/wiki/Untrusted-code-mitigations +@@ -134,6 +135,7 @@ + ['target_arch in "arm ia32 mips mipsel ppc"', { + 'v8_enable_pointer_compression': 0, + 'v8_enable_31bit_smis_on_64bit_arch': 0, ++ 'v8_enable_sandbox': 0, + }], + ['target_arch in "ppc64 s390x"', { + 'v8_enable_backtrace': 1, +@@ -394,9 +396,15 @@ + ['v8_enable_pointer_compression == 1', { + 'defines': [ + 'V8_COMPRESS_POINTERS', +- 'V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE', ++ 'V8_COMPRESS_POINTERS_IN_SHARED_CAGE', + ], + }], ++ ['v8_enable_sandbox == 1', { ++ 'defines': [ ++ 'V8_ENABLE_SANDBOX', ++ 'V8_SANDBOXED_POINTERS' ++ ] ++ }], + ['v8_enable_pointer_compression == 1 or v8_enable_31bit_smis_on_64bit_arch == 1', { + 'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH'], + }], +diff --git a/configure.py b/configure.py +index fed2688c792486e5f86509eea0dd6d45f749a99d..426afed7cd0a3a403d4b753af0b25f55024d0f71 100755 +--- a/configure.py ++++ b/configure.py +@@ -1439,6 +1439,7 @@ def configure_v8(o): + o['variables']['v8_use_siphash'] = 0 if options.without_siphash else 1 + o['variables']['v8_enable_pointer_compression'] = 1 if options.enable_pointer_compression else 0 + o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0 ++ o['variables']['v8_enable_sandbox'] = 1 if options.enable_pointer_compression else 0 + o['variables']['v8_trace_maps'] = 1 if options.trace_maps else 0 + o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform) + o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8) diff --git a/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch b/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch index 711d8326bb029..519b9bf148983 100644 --- a/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch +++ b/patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch @@ -35,7 +35,7 @@ index b45af42d12ff7df8a9e125e87f51af3456811c23..c84ff7feb07aebf656ada7e37d812d9d async function* watch(filename, options = {}) { const path = toNamespacedPath(getValidatedPath(filename)); diff --git a/src/node_native_module.cc b/src/node_native_module.cc -index 006a30903184d76d6c11849784e6c6b38fd39807..edde37f281c10a1cb69db642149cc300744499cb 100644 +index 5d20e1d6a86416c0de9f01a22b992aad889078d3..c836540c7d9328ae4646097ecc18023c1d8add8f 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -20,6 +20,7 @@ NativeModuleLoader NativeModuleLoader::instance_; diff --git a/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch b/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch index a5087a9679b6c..63740ebc306f6 100644 --- a/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch +++ b/patches/node/chore_allow_the_node_entrypoint_to_be_a_builtin_module.patch @@ -8,31 +8,33 @@ they use themselves as the entry point. We should try to upstream some form of this. diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js -index 4d4996e9868c35ac3e0babbf08c38d90a6857abc..419ffd9d5deb84eb94381259d3084411f6c3341b 100644 +index b184a0d9ae3434af746be269495e9e4c80c58091..899d5a906683e8967746e10a6de452e99e236903 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js -@@ -104,10 +104,12 @@ function patchProcessObject(expandArgv1) { +@@ -103,11 +103,13 @@ function patchProcessObject(expandArgv1) { if (expandArgv1 && process.argv[1] && !StringPrototypeStartsWith(process.argv[1], '-')) { // Expand process.argv[1] into a full path. - const path = require('path'); - try { - process.argv[1] = path.resolve(process.argv[1]); -- } catch {} +- } catch { +- // Continue regardless of error. + if (!process.argv[1] || !process.argv[1].startsWith('electron/js2c')) { + const path = require('path'); + try { + process.argv[1] = path.resolve(process.argv[1]); -+ } catch {} -+ } ++ } catch { ++ // Continue regardless of error. ++ } + } } - // TODO(joyeecheung): most of these should be deprecated and removed, diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js -index 05a62bb3c3852536001912cb0b69fe5578ace125..37f395e9f2b7ab9ce99b0f8f4217253fcbd9175b 100644 +index 5195ff2da0496f2bfb9112d336c38040f662087b..5c62e367f2dd7d112096551f1c34ee67ce1a5c3a 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js -@@ -1075,6 +1075,13 @@ Module.prototype._compile = function(content, filename) { +@@ -1079,6 +1079,13 @@ Module.prototype._compile = function(content, filename) { if (getOptionValue('--inspect-brk') && process._eval == null) { if (!resolvedArgv) { // We enter the repl if we're not given a filename argument. diff --git a/patches/node/chore_fix_-wimplicit-fallthrough.patch b/patches/node/chore_fix_-wimplicit-fallthrough.patch deleted file mode 100644 index 5b3103652136e..0000000000000 --- a/patches/node/chore_fix_-wimplicit-fallthrough.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Mon, 11 Oct 2021 13:46:24 +0200 -Subject: chore: fix -Wimplicit-fallthrough - -Upstreamed at https://github.com/nghttp2/nghttp2/pull/1626. - -diff --git a/deps/nghttp2/BUILD.gn b/deps/nghttp2/BUILD.gn -index 8bfecba74d4d90e9fbf0e2cd301118e4adc6cba8..63e1149f0c4a39cb944114e5824d6074343301e8 100644 ---- a/deps/nghttp2/BUILD.gn -+++ b/deps/nghttp2/BUILD.gn -@@ -16,7 +16,6 @@ static_library("nghttp2") { - - cflags_c = [ - "-Wno-implicit-function-declaration", -- "-Wno-implicit-fallthrough", - "-Wno-string-plus-int", - "-Wno-unreachable-code-return", - "-Wno-unused-but-set-variable", -diff --git a/deps/nghttp2/lib/nghttp2_hd.c b/deps/nghttp2/lib/nghttp2_hd.c -index 5e8693152599215261e47b152d565bbd9a0083e7..6d54e91dea6d77ad8925ad0452fd2a0a36f35f73 100644 ---- a/deps/nghttp2/lib/nghttp2_hd.c -+++ b/deps/nghttp2/lib/nghttp2_hd.c -@@ -1891,7 +1891,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, - rv = NGHTTP2_ERR_HEADER_COMP; - goto fail; - } -- /* fall through */ -+ __attribute__((fallthrough)); - case NGHTTP2_HD_STATE_INFLATE_START: - case NGHTTP2_HD_STATE_OPCODE: - if ((*in & 0xe0u) == 0x20u) { -@@ -2001,7 +2001,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, - inflater->left = 0; - inflater->shift = 0; - DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0); -- /* Fall through */ -+ __attribute__((fallthrough)); - case NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN: - rfin = 0; - rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV); -@@ -2085,7 +2085,7 @@ ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, - inflater->left = 0; - inflater->shift = 0; - DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0); -- /* Fall through */ -+ __attribute__((fallthrough)); - case NGHTTP2_HD_STATE_READ_VALUELEN: - rfin = 0; - rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV); -diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c -index 36f1179f72a22595dda0b98927d87e2098cad4df..f007dbf410b1bdc5d1f603aa85c3a4f0704e9741 100644 ---- a/deps/nghttp2/lib/nghttp2_session.c -+++ b/deps/nghttp2/lib/nghttp2_session.c -@@ -2644,10 +2644,10 @@ static int session_after_frame_sent1(nghttp2_session *session) { - case NGHTTP2_HCAT_PUSH_RESPONSE: - stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); - ++session->num_outgoing_streams; -- /* Fall through */ -+ __attribute__((fallthrough)); - case NGHTTP2_HCAT_RESPONSE: - stream->state = NGHTTP2_STREAM_OPENED; -- /* Fall through */ -+ __attribute__((fallthrough)); - case NGHTTP2_HCAT_HEADERS: - if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); -@@ -5456,7 +5456,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, - - iframe->state = NGHTTP2_IB_READ_HEAD; - -- /* Fall through */ -+ __attribute__((fallthrough)); - case NGHTTP2_IB_READ_HEAD: { - int on_begin_frame_called = 0; - diff --git a/patches/node/chore_read_nobrowserglobals_from_global_not_process.patch b/patches/node/chore_read_nobrowserglobals_from_global_not_process.patch index 046a66f06ab2f..b47a91bbe02ed 100644 --- a/patches/node/chore_read_nobrowserglobals_from_global_not_process.patch +++ b/patches/node/chore_read_nobrowserglobals_from_global_not_process.patch @@ -7,10 +7,10 @@ This is used so that we can modify the flag at runtime where config can only be set at compile time. diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js -index ef06d0563fa7452348754418867a56c9b8c6f4e1..a313402f93937cf2f1f93eb74422d9609e291d76 100644 +index 8c31d0202b70ec9784b4289a175a62fd9fd85f8c..2b4c7a933d7f87050f7342e6c3ae2070e3dde030 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js -@@ -193,7 +193,7 @@ const { +@@ -209,7 +209,7 @@ const { queueMicrotask } = require('internal/process/task_queues'); diff --git a/patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch b/patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch index 43023e3d02254..555ee607137d1 100644 --- a/patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch +++ b/patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch @@ -11,7 +11,7 @@ Refs: https://github.com/libuv/libuv/pull/482 Refs: https://github.com/libuv/libuv/pull/3405 diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md -index 30e0ea617a6fcaa5b4b7c7c5b117652e61f367d3..dc57dfb12dc7ddf8d29308ac44f46084a933d5ca 100644 +index 87e23823ad6424526fdbc2457e535875124b31cb..79509db5b17bb9e7fe245d8a0fd7fa25f8665426 100644 --- a/deps/uv/SUPPORTED_PLATFORMS.md +++ b/deps/uv/SUPPORTED_PLATFORMS.md @@ -3,7 +3,7 @@ diff --git a/patches/node/darwin_remove_eprototype_error_workaround_3405.patch b/patches/node/darwin_remove_eprototype_error_workaround_3405.patch index 60dc8b799e4b7..45d8d4936d74e 100644 --- a/patches/node/darwin_remove_eprototype_error_workaround_3405.patch +++ b/patches/node/darwin_remove_eprototype_error_workaround_3405.patch @@ -18,7 +18,7 @@ I'm opting to simply remove the workaround and have the error bubble up. Refs: https://github.com/libuv/libuv/pull/482 diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c -index bc64fe8f44b26d9f4c0d4d0d282b65cdf11a531b..1af448e7691392c3f7794eed1905d9132394e207 100644 +index 5858258d2868c3352e0e9e3313045aa29ff4a873..c5cd6ddc0b627eeb047e0cb08677f65b4601b89b 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -58,20 +58,6 @@ struct uv__stream_select_s { diff --git a/patches/node/darwin_translate_eprototype_to_econnreset_3413.patch b/patches/node/darwin_translate_eprototype_to_econnreset_3413.patch index 903921bce934b..c6199bc4c1388 100644 --- a/patches/node/darwin_translate_eprototype_to_econnreset_3413.patch +++ b/patches/node/darwin_translate_eprototype_to_econnreset_3413.patch @@ -18,7 +18,7 @@ Refs: https://github.com/libuv/libuv/pull/482 Refs: https://github.com/libuv/libuv/pull/3405 diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c -index 1af448e7691392c3f7794eed1905d9132394e207..9d22debf2bf5bd5912ade152e55a85ad652e3819 100644 +index c5cd6ddc0b627eeb047e0cb08677f65b4601b89b..b5b05a6a4a737f50b780b7c15717b4f465496fa8 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -865,6 +865,20 @@ static int uv__try_write(uv_stream_t* stream, diff --git a/patches/node/enable_-wunqualified-std-cast-call.patch b/patches/node/enable_-wunqualified-std-cast-call.patch new file mode 100644 index 0000000000000..0a78954c84505 --- /dev/null +++ b/patches/node/enable_-wunqualified-std-cast-call.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 +Date: Fri, 26 Aug 2022 00:10:16 +0900 +Subject: Enable -Wunqualified-std-cast-call + +Refs https://chromium-review.googlesource.com/c/chromium/src/+/3825237 +Should be upstreamed. + +diff --git a/src/node_http2.cc b/src/node_http2.cc +index ca82da47b4b160af0b1c11f9d162919272666cdb..e60036bb9cc07c5a87c2a017507c3533e229f14f 100644 +--- a/src/node_http2.cc ++++ b/src/node_http2.cc +@@ -645,7 +645,7 @@ void Http2Stream::EmitStatistics() { + duration, + statistics_); + +- env()->SetImmediate([entry = move(entry)](Environment* env) { ++ env()->SetImmediate([entry = std::move(entry)](Environment* env) { + if (HasHttp2Observer(env)) + entry->Notify(env); + }); diff --git a/patches/node/enable_31_bit_smis_on_64bit_arch_and_ptr_compression.patch b/patches/node/enable_31_bit_smis_on_64bit_arch_and_ptr_compression.patch deleted file mode 100644 index 3beda4a974e9f..0000000000000 --- a/patches/node/enable_31_bit_smis_on_64bit_arch_and_ptr_compression.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeremy Apthorp -Date: Tue, 10 Dec 2019 15:02:21 -0800 -Subject: enable 31 bit smis on 64bit arch and ptr compression - -This aligns with the defaults set on the Chromium build. Without this, native -node modules will have different (wrong) ideas about how v8 structs are laid -out in memory on 64-bit machines, and will summarily fail to work. - -diff --git a/common.gypi b/common.gypi -index 4b6a965f65b9ad711507e4dd7ade4d54d52277cc..9e4064b263819756f17fb712a54bd6f828c5be35 100644 ---- a/common.gypi -+++ b/common.gypi -@@ -64,7 +64,7 @@ - # options but default values are required here as this file is also used by - # node-gyp to build addons. - 'v8_enable_pointer_compression%': 0, -- 'v8_enable_31bit_smis_on_64bit_arch%': 0, -+ 'v8_enable_31bit_smis_on_64bit_arch%': 1, - - # Disable V8 untrusted code mitigations. - # See https://github.com/v8/v8/wiki/Untrusted-code-mitigations -@@ -130,6 +130,9 @@ - 'v8_enable_pointer_compression': 0, - 'v8_enable_31bit_smis_on_64bit_arch': 0, - }], -+ ['target_arch == "arm64" or target_arch == "x64"', { -+ 'v8_enable_pointer_compression': 1, -+ }], - ['target_arch in "ppc64 s390x"', { - 'v8_enable_backtrace': 1, - }], diff --git a/patches/node/feat_add_flags_for_low-level_hooks_and_exceptions.patch b/patches/node/feat_add_flags_for_low-level_hooks_and_exceptions.patch deleted file mode 100644 index bfe9ef5ec6ade..0000000000000 --- a/patches/node/feat_add_flags_for_low-level_hooks_and_exceptions.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Thu, 13 Sep 2018 08:42:22 -0700 -Subject: feat: add flags for low-level hooks and exceptions - -This commit adds two new exposed methods to `node.cc`, `InitGeneric` and -`LoadEnvironmentGeneric` that allow for control of which mode Node -should run, which i have called `standalone_mode` and -`upstream_node_mode`. Default behavior of `Init` and `LoadEnvironment` -remain the same. - -We have 3 modes when running Node in Electron: -1. In the main process, we want to have a full Node environment, but -with signal handlers and other low level things disabled -2. In renderer process, we want Node to reuse the web page's context -3. In `ELECTRON_RUN_AS_NODE`, we want Node to run as it runs officially -by default - -For modes 1 and 3, we have Node create a new V8 context with a Node -Environment on it. However, for mode 2, since the V8 context is created -by blink for web frames and web workers we make Node create the Node -Environment on the V8 context of blink, so no new V8 context is created. - -As a result, a renderer process may have multiple Node Environments in it. - -diff --git a/src/node.cc b/src/node.cc -index e942c108a15a3c50d92c08b344f6691050c7859d..207a95d202b4e422a39f837241f1655f7111b1e3 100644 ---- a/src/node.cc -+++ b/src/node.cc -@@ -139,6 +139,8 @@ using v8::Undefined; - using v8::V8; - using v8::Value; - -+bool g_upstream_node_mode = true; -+ - namespace per_process { - - // node_revert.h -@@ -853,7 +855,9 @@ int InitializeNodeWithArgs(std::vector* argv, - binding::RegisterBuiltinModules(); - - // Make inherited handles noninheritable. -- uv_disable_stdio_inheritance(); -+ if (g_upstream_node_mode) { -+ uv_disable_stdio_inheritance(); -+ } - - // Cache the original command line to be - // used in diagnostic reports. -@@ -887,7 +891,8 @@ int InitializeNodeWithArgs(std::vector* argv, - if (exit_code != 0) return exit_code; - } - #endif -- -+ if (g_upstream_node_mode) { -+ // NOTE(jeremy): indentation is intentionally wrong here, to ease rebasing. - const int exit_code = ProcessGlobalArgs(argv, - exec_argv, - errors, -@@ -930,7 +935,7 @@ int InitializeNodeWithArgs(std::vector* argv, - return 9; - } - per_process::metadata.versions.InitializeIntlVersions(); -- -+ } // g_upstream_node_mode - # ifndef __POSIX__ - std::string tz; - if (credentials::SafeGetenv("TZ", &tz) && !tz.empty()) { -diff --git a/src/node.h b/src/node.h -index 1f9afa558d0c8b7950a0f5862017e09a08118ec1..45de72bd94cf669ac2badf89d23164cb7022a5b3 100644 ---- a/src/node.h -+++ b/src/node.h -@@ -213,6 +213,8 @@ namespace node { - - class IsolateData; - class Environment; -+// Whether node should open some low level hooks. -+NODE_EXTERN extern bool g_upstream_node_mode; - - // TODO(addaleax): Officially deprecate this and replace it with something - // better suited for a public embedder API. diff --git a/patches/node/feat_add_knostartdebugsignalhandler_to_environment_to_prevent.patch b/patches/node/feat_add_knostartdebugsignalhandler_to_environment_to_prevent.patch new file mode 100644 index 0000000000000..eff6170cab0b4 --- /dev/null +++ b/patches/node/feat_add_knostartdebugsignalhandler_to_environment_to_prevent.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Mon, 7 Mar 2022 16:36:28 -0800 +Subject: feat: add kNoStartDebugSignalHandler to Environment to prevent + SIGUSR1 handling + +This patch should be upstreamed, it allows embedders to prevent the call to StartDebugSignalHandler which handles SIGUSR1 and starts the inspector agent. Apps that have --inspect disabled also don't want SIGUSR1 to have this affect. + +diff --git a/src/env-inl.h b/src/env-inl.h +index 4a34393cad7e071bf27947418be6b3d9bdd42f98..b9834a797c89f707d1e4978587af66ebf11591d4 100644 +--- a/src/env-inl.h ++++ b/src/env-inl.h +@@ -886,6 +886,10 @@ inline bool Environment::no_global_search_paths() const { + !options_->global_search_paths; + } + ++inline bool Environment::should_start_debug_signal_handler() const { ++ return (flags_ & EnvironmentFlags::kNoStartDebugSignalHandler) == 0; ++} ++ + bool Environment::filehandle_close_warning() const { + return emit_filehandle_warning_; + } +diff --git a/src/env.h b/src/env.h +index cda7a52fa1ffc66d7ba42de3a275f49093f8557d..86f3c718ada13ee71e5af87e1b3772f39274cf43 100644 +--- a/src/env.h ++++ b/src/env.h +@@ -1216,6 +1216,7 @@ class Environment : public MemoryRetainer { + inline bool tracks_unmanaged_fds() const; + inline bool hide_console_windows() const; + inline bool no_global_search_paths() const; ++ inline bool should_start_debug_signal_handler() const; + inline uint64_t thread_id() const; + inline worker::Worker* worker_context() const; + Environment* worker_parent_env() const; +diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc +index 5fc533741d7c8d7a8471b3c3c6a334c0e9e43501..2c36a0b132cf1b21595ac39619b99d316ad81d9e 100644 +--- a/src/inspector_agent.cc ++++ b/src/inspector_agent.cc +@@ -690,8 +690,10 @@ bool Agent::Start(const std::string& path, + StartIoThreadAsyncCallback)); + uv_unref(reinterpret_cast(&start_io_thread_async)); + start_io_thread_async.data = this; +- // Ignore failure, SIGUSR1 won't work, but that should not block node start. +- StartDebugSignalHandler(); ++ if (parent_env_->should_start_debug_signal_handler()) { ++ // Ignore failure, SIGUSR1 won't work, but that should not block node start. ++ StartDebugSignalHandler(); ++ } + + parent_env_->AddCleanupHook([](void* data) { + Environment* env = static_cast(data); +diff --git a/src/node.h b/src/node.h +index 0a9f5139276eb2e102b41a586adf61fa563b47d6..0b807cb25f9eb52b2100f0e2a7c25344790967cf 100644 +--- a/src/node.h ++++ b/src/node.h +@@ -445,7 +445,11 @@ enum Flags : uint64_t { + // This control is needed by embedders who may not want to initialize the V8 + // inspector in situations where one has already been created, + // e.g. Blink's in Chromium. +- kNoCreateInspector = 1 << 9 ++ kNoCreateInspector = 1 << 9, ++ // Controls where or not the InspectorAgent for this Environment should ++ // call StartDebugSignalHandler. This control is needed by embedders who may ++ // not want to allow other processes to start the V8 inspector. ++ kNoStartDebugSignalHandler = 1 << 10 + }; + } // namespace EnvironmentFlags + diff --git a/patches/node/feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch b/patches/node/feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch new file mode 100644 index 0000000000000..a568f9f86ab4a --- /dev/null +++ b/patches/node/feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch @@ -0,0 +1,506 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cheng Zhao +Date: Mon, 31 Jan 2022 20:56:58 +0900 +Subject: feat: add UV_LOOP_INTERRUPT_ON_IO_CHANGE option to uv_loop_configure + +https://github.com/libuv/libuv/pull/3308 + +diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst +index 0f5ddfb3ca21b7e5b38d0a4ce4b9e77387597199..ba815202fb157aa82859ec0518523cf6f2ec6ba1 100644 +--- a/deps/uv/docs/src/loop.rst ++++ b/deps/uv/docs/src/loop.rst +@@ -73,7 +73,15 @@ API + + This option is necessary to use :c:func:`uv_metrics_idle_time`. + ++ - UV_LOOP_INTERRUPT_ON_IO_CHANGE: Interrupt the loop whenever a new IO ++ event has been added or changed. ++ ++ This option is usually when implementing event loop integration, to make ++ the polling of backend fd interrupt to recognize the changes of IO events. ++ + .. versionchanged:: 1.39.0 added the UV_METRICS_IDLE_TIME option. ++ .. versionchanged:: 1.43.0 added the UV_LOOP_INTERRUPT_ON_IO_CHANGE option. ++ + + .. c:function:: int uv_loop_close(uv_loop_t* loop) + +diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h +index 606083c87de5790d7e66fc34aeaae9a58acb8ef4..824b0b77cf5f0a46dcb3855c44ac73faaba2055f 100644 +--- a/deps/uv/include/uv.h ++++ b/deps/uv/include/uv.h +@@ -252,7 +252,8 @@ typedef struct uv_statfs_s uv_statfs_t; + + typedef enum { + UV_LOOP_BLOCK_SIGNAL = 0, +- UV_METRICS_IDLE_TIME ++ UV_METRICS_IDLE_TIME, ++ UV_LOOP_INTERRUPT_ON_IO_CHANGE + } uv_loop_option; + + typedef enum { +diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c +index e1805c323795e5b0c465d80100eebeb7bf838caa..dd4358c0cdaa97ba8fadf4d9755993803beddd18 100644 +--- a/deps/uv/src/unix/async.c ++++ b/deps/uv/src/unix/async.c +@@ -38,7 +38,6 @@ + #include + #endif + +-static void uv__async_send(uv_loop_t* loop); + static int uv__async_start(uv_loop_t* loop); + + +@@ -70,7 +69,7 @@ int uv_async_send(uv_async_t* handle) { + return 0; + + /* Wake up the other thread's event loop. */ +- uv__async_send(handle->loop); ++ uv__loop_interrupt(handle->loop); + + /* Tell the other thread we're done. */ + if (cmpxchgi(&handle->pending, 1, 2) != 1) +@@ -165,40 +164,6 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + } + + +-static void uv__async_send(uv_loop_t* loop) { +- const void* buf; +- ssize_t len; +- int fd; +- int r; +- +- buf = ""; +- len = 1; +- fd = loop->async_wfd; +- +-#if defined(__linux__) +- if (fd == -1) { +- static const uint64_t val = 1; +- buf = &val; +- len = sizeof(val); +- fd = loop->async_io_watcher.fd; /* eventfd */ +- } +-#endif +- +- do +- r = write(fd, buf, len); +- while (r == -1 && errno == EINTR); +- +- if (r == len) +- return; +- +- if (r == -1) +- if (errno == EAGAIN || errno == EWOULDBLOCK) +- return; +- +- abort(); +-} +- +- + static int uv__async_start(uv_loop_t* loop) { + int pipefd[2]; + int err; +diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c +index 7cd3a2a954ff7d70e6ba7a6f7538648841bc54b2..f89b7158218be60ac10e61484a2d5e5e28a3182f 100644 +--- a/deps/uv/src/unix/core.c ++++ b/deps/uv/src/unix/core.c +@@ -887,6 +887,9 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + loop->watchers[w->fd] = w; + loop->nfds++; + } ++ ++ if (uv__get_internal_fields(loop)->flags & UV_LOOP_INTERRUPT_ON_IO_CHANGE) ++ uv__loop_interrupt(loop); + } + + +@@ -918,6 +921,9 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + } + else if (QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); ++ ++ if (uv__get_internal_fields(loop)->flags & UV_LOOP_INTERRUPT_ON_IO_CHANGE) ++ uv__loop_interrupt(loop); + } + + +@@ -934,6 +940,9 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) { + void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { + if (QUEUE_EMPTY(&w->pending_queue)) + QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue); ++ ++ if (uv__get_internal_fields(loop)->flags & UV_LOOP_INTERRUPT_ON_IO_CHANGE) ++ uv__loop_interrupt(loop); + } + + +diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c +index a88e71c339351f2ebcdd6c3f933fc3b1122910ed..46fc03264b6cc1a3a4d8faf5ec5a754fc07c9b6d 100644 +--- a/deps/uv/src/unix/loop.c ++++ b/deps/uv/src/unix/loop.c +@@ -217,6 +217,11 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + return 0; + } + ++ if (option == UV_LOOP_INTERRUPT_ON_IO_CHANGE) { ++ lfields->flags |= UV_LOOP_INTERRUPT_ON_IO_CHANGE; ++ return 0; ++ } ++ + if (option != UV_LOOP_BLOCK_SIGNAL) + return UV_ENOSYS; + +@@ -226,3 +231,40 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + loop->flags |= UV_LOOP_BLOCK_SIGPROF; + return 0; + } ++ ++ ++void uv__loop_interrupt(uv_loop_t* loop) { ++ const void* buf; ++ ssize_t len; ++ int fd; ++ int r; ++ ++ buf = ""; ++ len = 1; ++ fd = loop->async_wfd; ++ ++#if defined(__linux__) ++ if (fd == -1) { ++ static const uint64_t val = 1; ++ buf = &val; ++ len = sizeof(val); ++ fd = loop->async_io_watcher.fd; /* eventfd */ ++ } ++#endif ++ ++ do ++ r = write(fd, buf, len); ++ while (r == -1 && errno == EINTR); ++ ++ if (r == len) ++ return; ++ ++ if (!uv_loop_alive(loop)) ++ return; ++ ++ if (r == -1) ++ if (errno == EAGAIN || errno == EWOULDBLOCK) ++ return; ++ ++ abort(); ++} +diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h +index 6001b0cf68d0b0268b578218b664a737f43c9521..5d2212571f4bcb648ab332f0c5650d0fdb37c03a 100644 +--- a/deps/uv/src/uv-common.h ++++ b/deps/uv/src/uv-common.h +@@ -140,6 +140,8 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); + + void uv__loop_close(uv_loop_t* loop); + ++void uv__loop_interrupt(uv_loop_t* loop); ++ + int uv__read_start(uv_stream_t* stream, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +@@ -268,6 +270,10 @@ void uv__threadpool_cleanup(void); + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \ + (h)->flags |= UV_HANDLE_ACTIVE; \ + if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \ ++ int loop_flags = uv__get_internal_fields((h)->loop)->flags; \ ++ if (loop_flags & UV_LOOP_INTERRUPT_ON_IO_CHANGE) { \ ++ uv__loop_interrupt((h)->loop); \ ++ } \ + } \ + while (0) + +diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c +index e53a0f8e28637a58ceec7852d1a79874fc1a9548..dd4065c1cc68763bfe258492e3119669311394dc 100644 +--- a/deps/uv/src/win/core.c ++++ b/deps/uv/src/win/core.c +@@ -381,10 +381,20 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { + return 0; + } + ++ if (option == UV_LOOP_INTERRUPT_ON_IO_CHANGE) { ++ lfields->flags |= UV_LOOP_INTERRUPT_ON_IO_CHANGE; ++ return 0; ++ } ++ + return UV_ENOSYS; + } + + ++void uv__loop_interrupt(uv_loop_t* loop) { ++ PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); ++} ++ ++ + int uv_backend_fd(const uv_loop_t* loop) { + return -1; + } +diff --git a/deps/uv/test/test-embed.c b/deps/uv/test/test-embed.c +index c6ddceb149d9c1d68b0dd17b6dac0d4c3c3e9dbc..f6572c5dc2b6ef39bd11889ad1f7873007a6437d 100644 +--- a/deps/uv/test/test-embed.c ++++ b/deps/uv/test/test-embed.c +@@ -25,115 +25,179 @@ + #include + #include + +-#ifndef HAVE_KQUEUE +-# if defined(__APPLE__) || \ +- defined(__DragonFly__) || \ +- defined(__FreeBSD__) || \ +- defined(__FreeBSD_kernel__) || \ +- defined(__OpenBSD__) || \ +- defined(__NetBSD__) +-# define HAVE_KQUEUE 1 +-# endif +-#endif +- + #ifndef HAVE_EPOLL + # if defined(__linux__) + # define HAVE_EPOLL 1 + # endif + #endif + +-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) ++#if defined(HAVE_EPOLL) ++# include ++#endif + +-#if defined(HAVE_KQUEUE) ++#if !defined(_WIN32) + # include +-# include + # include + #endif + +-#if defined(HAVE_EPOLL) +-# include +-#endif +- ++static uv_loop_t main_loop; ++static uv_loop_t external_loop; + static uv_thread_t embed_thread; + static uv_sem_t embed_sem; +-static uv_timer_t embed_timer; + static uv_async_t embed_async; ++static uv_async_t main_async; + static volatile int embed_closed; + +-static int embed_timer_called; ++static uv_timer_t main_timer; ++static int main_timer_called; + + +-static void embed_thread_runner(void* arg) { ++#if defined(_WIN32) ++static void embed_thread_poll_win(HANDLE iocp, int timeout) { ++ DWORD bytes; ++ ULONG_PTR key; ++ OVERLAPPED* overlapped; ++ ++ GetQueuedCompletionStatus(iocp, ++ &bytes, ++ &key, ++ &overlapped, ++ timeout >= 0 ? timeout : INFINITE); ++ ++ /* Give the event back so the loop can deal with it. */ ++ if (overlapped != NULL) ++ PostQueuedCompletionStatus(iocp, ++ bytes, ++ key, ++ overlapped); ++} ++#else ++static void embed_thread_poll_unix(int fd, int timeout) { + int r; +- int fd; ++ do { ++#if defined(HAVE_EPOLL) ++ struct epoll_event ev; ++ r = epoll_wait(fd, &ev, 1, timeout); ++#else ++ struct timeval tv; ++ if (timeout >= 0) { ++ tv.tv_sec = timeout / 1000; ++ tv.tv_usec = (timeout % 1000) * 1000; ++ } ++ fd_set readset; ++ FD_ZERO(&readset); ++ FD_SET(fd, &readset); ++ r = select(fd + 1, &readset, NULL, NULL, timeout >= 0 ? &tv : NULL); ++#endif ++ } while (r == -1 && errno == EINTR); ++} ++#endif /* !_WIN32 */ ++ ++ ++static void embed_thread_runner(void* arg) { + int timeout; + +- while (!embed_closed) { +- fd = uv_backend_fd(uv_default_loop()); +- timeout = uv_backend_timeout(uv_default_loop()); +- +- do { +-#if defined(HAVE_KQUEUE) +- struct timespec ts; +- ts.tv_sec = timeout / 1000; +- ts.tv_nsec = (timeout % 1000) * 1000000; +- r = kevent(fd, NULL, 0, NULL, 0, &ts); +-#elif defined(HAVE_EPOLL) +- { +- struct epoll_event ev; +- r = epoll_wait(fd, &ev, 1, timeout); +- } ++ do { ++ timeout = uv_backend_timeout(&main_loop); ++ ++#if defined(_WIN32) ++ embed_thread_poll_win(main_loop.iocp, timeout); ++#else ++ embed_thread_poll_unix(uv_backend_fd(&main_loop), timeout); + #endif +- } while (r == -1 && errno == EINTR); ++ + uv_async_send(&embed_async); ++ + uv_sem_wait(&embed_sem); +- } ++ } while (!embed_closed); + } + + + static void embed_cb(uv_async_t* async) { +- uv_run(uv_default_loop(), UV_RUN_ONCE); ++ /* Run tasks in main loop */ ++ uv_run(&main_loop, UV_RUN_NOWAIT); + ++ /* Tell embed thread to continue polling */ + uv_sem_post(&embed_sem); + } + + +-static void embed_timer_cb(uv_timer_t* timer) { +- embed_timer_called++; ++static void main_timer_cb(uv_timer_t* timer) { ++ main_timer_called++; + embed_closed = 1; + + uv_close((uv_handle_t*) &embed_async, NULL); ++ uv_close((uv_handle_t*) &main_async, NULL); + } +-#endif + + +-TEST_IMPL(embed) { +-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) +- uv_loop_t external; +- +- ASSERT(0 == uv_loop_init(&external)); ++static void init_loops(void) { ++ ASSERT_EQ(0, uv_loop_init(&main_loop)); ++ ASSERT_EQ(0, uv_loop_init(&external_loop)); + +- embed_timer_called = 0; ++ main_timer_called = 0; + embed_closed = 0; + +- uv_async_init(&external, &embed_async, embed_cb); ++ uv_async_init(&external_loop, &embed_async, embed_cb); + +- /* Start timer in default loop */ +- uv_timer_init(uv_default_loop(), &embed_timer); +- uv_timer_start(&embed_timer, embed_timer_cb, 250, 0); ++ /* Create a dummy async for main loop otherwise backend timeout will ++ always be 0 */ ++ uv_async_init(&main_loop, &main_async, embed_cb); + +- /* Start worker that will interrupt external loop */ ++ /* Start worker that will poll main loop and interrupt external loop */ + uv_sem_init(&embed_sem, 0); + uv_thread_create(&embed_thread, embed_thread_runner, NULL); ++} + +- /* But run external loop */ +- uv_run(&external, UV_RUN_DEFAULT); ++ ++static void run_loop(void) { ++ /* Run external loop */ ++ uv_run(&external_loop, UV_RUN_DEFAULT); + + uv_thread_join(&embed_thread); +- uv_loop_close(&external); ++ uv_sem_destroy(&embed_sem); ++ uv_loop_close(&external_loop); ++ uv_loop_close(&main_loop); ++} + +- ASSERT(embed_timer_called == 1); +-#endif ++ ++TEST_IMPL(embed) { ++ init_loops(); ++ ++ /* Start timer in main loop */ ++ uv_timer_init(&main_loop, &main_timer); ++ uv_timer_start(&main_timer, main_timer_cb, 250, 0); ++ ++ run_loop(); ++ ASSERT_EQ(main_timer_called, 1); ++ ++ return 0; ++} ++ ++ ++static uv_timer_t external_timer; ++ ++ ++static void external_timer_cb(uv_timer_t* timer) { ++ /* Start timer in main loop */ ++ uv_timer_init(&main_loop, &main_timer); ++ uv_timer_start(&main_timer, main_timer_cb, 250, 0); ++} ++ ++ ++TEST_IMPL(embed_with_external_timer) { ++ init_loops(); ++ ++ /* Interrupt embed polling when a handle is started */ ++ ASSERT_EQ(0, uv_loop_configure(&main_loop, UV_LOOP_INTERRUPT_ON_IO_CHANGE)); ++ ++ /* Start timer in external loop, whose callback will not interrupt the ++ polling in embed thread */ ++ uv_timer_init(&external_loop, &external_timer); ++ uv_timer_start(&external_timer, external_timer_cb, 100, 0); ++ ++ run_loop(); ++ ASSERT_EQ(main_timer_called, 1); + + return 0; + } +diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h +index a43edf1a4a9b0932ec73b8edaca0f676ecf3ccfa..199402e31406cf8ba360d54769461bb5285011ee 100644 +--- a/deps/uv/test/test-list.h ++++ b/deps/uv/test/test-list.h +@@ -263,6 +263,7 @@ TEST_DECLARE (process_priority) + TEST_DECLARE (has_ref) + TEST_DECLARE (active) + TEST_DECLARE (embed) ++TEST_DECLARE (embed_with_external_timer) + TEST_DECLARE (async) + TEST_DECLARE (async_null_cb) + TEST_DECLARE (eintr_handling) +@@ -860,6 +861,7 @@ TASK_LIST_START + TEST_ENTRY (active) + + TEST_ENTRY (embed) ++ TEST_ENTRY (embed_with_external_timer) + + TEST_ENTRY (async) + TEST_ENTRY (async_null_cb) diff --git a/patches/node/feat_add_uv_loop_watcher_queue_code.patch b/patches/node/feat_add_uv_loop_watcher_queue_code.patch deleted file mode 100644 index 610da58034be2..0000000000000 --- a/patches/node/feat_add_uv_loop_watcher_queue_code.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Mon, 30 Jul 2018 10:34:54 -0700 -Subject: feat: add uv_loop watcher_queue code - -Electron's Node Integration works by listening to Node's backend file descriptor in a separate thread; when an event is ready the backend file descriptor will trigger a new event for it, and the main thread will then iterate the libuv loop. For certain operations (ex. adding a timeout task) the backend file descriptor isn't informed, & as a result the main thread doesn't know it needs to iterate the libuv loop so the timeout task will never execute until something else trigger a new event. This commit should be removed when https://github.com/libuv/libuv/pull/1921 is merged - -diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h -index 77503bde9f28e4769ae3832fb2117e632e9c9268..49930027bdad013d8fcbc375c534d67cc5201bc7 100644 ---- a/deps/uv/include/uv.h -+++ b/deps/uv/include/uv.h -@@ -1802,6 +1802,8 @@ union uv_any_req { - struct uv_loop_s { - /* User data - use this for whatever. */ - void* data; -+ /* Callback when loop's watcher queue updates. */ -+ void (*on_watcher_queue_updated)(uv_loop_t*); - /* Loop reference counting. */ - unsigned int active_handles; - void* handle_queue[2]; -diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c -index 71e9c525c4a77b8b5322e8516c58329100a8d951..a6425294086ff2f1435fdd6866380d3aaaf68200 100644 ---- a/deps/uv/src/unix/core.c -+++ b/deps/uv/src/unix/core.c -@@ -906,8 +906,11 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - return; - #endif - -- if (QUEUE_EMPTY(&w->watcher_queue)) -+ if (QUEUE_EMPTY(&w->watcher_queue)) { - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); -+ if (loop->on_watcher_queue_updated) -+ loop->on_watcher_queue_updated(loop); -+ } - - if (loop->watchers[w->fd] == NULL) { - loop->watchers[w->fd] = w; -@@ -942,8 +945,11 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - loop->nfds--; - } - } -- else if (QUEUE_EMPTY(&w->watcher_queue)) -+ else if (QUEUE_EMPTY(&w->watcher_queue)) { - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); -+ if (loop->on_watcher_queue_updated) -+ loop->on_watcher_queue_updated(loop); -+ } - } - - -@@ -960,6 +966,8 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) { - void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { - if (QUEUE_EMPTY(&w->pending_queue)) - QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue); -+ if (loop->on_watcher_queue_updated) -+ loop->on_watcher_queue_updated(loop); - } - - diff --git a/patches/node/feat_initialize_asar_support.patch b/patches/node/feat_initialize_asar_support.patch index b32de0a339035..a7901aba7994f 100644 --- a/patches/node/feat_initialize_asar_support.patch +++ b/patches/node/feat_initialize_asar_support.patch @@ -6,10 +6,10 @@ Subject: feat: initialize asar support This patch initializes asar support in Node.js. diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js -index f2a10641906e317270e7f27f4ee3ee1956802113..4d4996e9868c35ac3e0babbf08c38d90a6857abc 100644 +index 8de57a5666131ff0c9f7ad844498e1bd3c357a70..b184a0d9ae3434af746be269495e9e4c80c58091 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js -@@ -76,6 +76,7 @@ function prepareMainThreadExecution(expandArgv1 = false) { +@@ -84,6 +84,7 @@ function prepareMainThreadExecution(expandArgv1 = false) { assert(!CJSLoader.hasLoadedAnyUserCJSModule); loadPreloadModules(); initializeFrozenIntrinsics(); @@ -17,7 +17,7 @@ index f2a10641906e317270e7f27f4ee3ee1956802113..4d4996e9868c35ac3e0babbf08c38d90 } function patchProcessObject(expandArgv1) { -@@ -484,6 +485,10 @@ function loadPreloadModules() { +@@ -540,6 +541,10 @@ function loadPreloadModules() { } } diff --git a/patches/node/fix_account_for_debugger_agent_race_condition.patch b/patches/node/fix_account_for_debugger_agent_race_condition.patch index e2c4b5401c958..f4f70161ba85a 100644 --- a/patches/node/fix_account_for_debugger_agent_race_condition.patch +++ b/patches/node/fix_account_for_debugger_agent_race_condition.patch @@ -10,7 +10,7 @@ errors. This is remedied by adding a small timeout to the test. We'll either upstream this or figure out a better solution. diff --git a/test/parallel/test-debugger-address.js b/test/parallel/test-debugger-address.js -index 95dd1c6e3f82835d5ccaf65544d654b71efaa392..ed8dccf91247068455dd593bb3e8c02bddc89ae5 100644 +index bffc28ac916e8d241465f1e2649ab8aa4a15a0c7..079e668a3d1c505fa0a540fb1df87b32e603db48 100644 --- a/test/parallel/test-debugger-address.js +++ b/test/parallel/test-debugger-address.js @@ -59,6 +59,7 @@ function launchTarget(...args) { @@ -22,7 +22,7 @@ index 95dd1c6e3f82835d5ccaf65544d654b71efaa392..ed8dccf91247068455dd593bb3e8c02b .then(() => cli.waitFor(/break/)) .then(() => cli.waitForPrompt()) diff --git a/test/sequential/test-debugger-pid.js b/test/sequential/test-debugger-pid.js -index 402c1f86dd4ed99b413eca5fce8a2db47797b11a..74ef0a1618ccf1f6671bbe2a03548eee6cd0b88c 100644 +index 0056113ecaecd3a176ee9539b7fda0132ef59963..3228d0ecc220b5c8c8034fea0dce20f8c38ac68c 100644 --- a/test/sequential/test-debugger-pid.js +++ b/test/sequential/test-debugger-pid.js @@ -41,6 +41,7 @@ function launchTarget(...args) { diff --git a/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch b/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch index fc9a9c0e2182d..93e000bb61628 100644 --- a/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch +++ b/patches/node/fix_add_default_values_for_variables_in_common_gypi.patch @@ -7,10 +7,10 @@ common.gypi is a file that's included in the node header bundle, despite the fact that we do not build node with gyp. diff --git a/common.gypi b/common.gypi -index b8d61f0d32709f3476dd2fd870d3959ab8f16a60..4b6a965f65b9ad711507e4dd7ade4d54d52277cc 100644 +index 3cfed562577978c41a256fc779f6a3a172e65b3d..96d512630e9727467aa523c2dfc1a4cf9275465b 100644 --- a/common.gypi +++ b/common.gypi -@@ -81,6 +81,23 @@ +@@ -84,6 +84,23 @@ ##### end V8 defaults ##### diff --git a/patches/node/fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch b/patches/node/fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch index 7b1e9bff157a1..1943720ef81c6 100644 --- a/patches/node/fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch +++ b/patches/node/fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch @@ -6,26 +6,19 @@ Subject: fix: add v8_enable_reverse_jsargs defines in common.gypi This can be removed once node upgrades V8 and inevitably has to do this exact same thing. Also hi node people if you are looking at this. diff --git a/common.gypi b/common.gypi -index 9e4064b263819756f17fb712a54bd6f828c5be35..2e59efb38d95231fcbcbb5a7859a6cfad3cf232c 100644 +index 96d512630e9727467aa523c2dfc1a4cf9275465b..bdfe81d11cc50f492c93fe48f6946765b6fb5238 100644 --- a/common.gypi +++ b/common.gypi -@@ -65,6 +65,7 @@ - # node-gyp to build addons. - 'v8_enable_pointer_compression%': 0, - 'v8_enable_31bit_smis_on_64bit_arch%': 1, -+ 'v8_enable_reverse_jsargs%': 1, - - # Disable V8 untrusted code mitigations. - # See https://github.com/v8/v8/wiki/Untrusted-code-mitigations -@@ -79,6 +80,7 @@ +@@ -82,6 +82,8 @@ # TODO(refack): make v8-perfetto happen 'v8_use_perfetto': 0, ++ 'v8_enable_reverse_jsargs%': 1, + ##### end V8 defaults ##### # When building native modules using 'npm install' with the system npm, -@@ -390,6 +392,9 @@ +@@ -398,6 +400,9 @@ ['v8_enable_pointer_compression == 1 or v8_enable_31bit_smis_on_64bit_arch == 1', { 'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH'], }], diff --git a/patches/node/fix_allow_preventing_initializeinspector_in_env.patch b/patches/node/fix_allow_preventing_initializeinspector_in_env.patch deleted file mode 100644 index e018f2af59442..0000000000000 --- a/patches/node/fix_allow_preventing_initializeinspector_in_env.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Tue, 22 Sep 2020 19:44:30 -0700 -Subject: fix: allow preventing InitializeInspector in env - -https://github.com/nodejs/node/commit/8c5ad1392f30cfe6b107e9bd85f4cb918ba04aab -made it such that env->InitializeInspector was called in CreateEnvironment -no matter what, which creates an issue for Electron, as the V8 inspector -already exists in the renderer process and therefore we only want to -initialize it in the browser process. This adds a new -EnvironmentFlags option which allows preventing that invocation. - -diff --git a/src/api/environment.cc b/src/api/environment.cc -index 523d252e08974a10f9a53fb46d3345669cec3380..5bf19a0dda42849159d954181058897c45d280fd 100644 ---- a/src/api/environment.cc -+++ b/src/api/environment.cc -@@ -344,12 +344,14 @@ Environment* CreateEnvironment( - Environment* env = new Environment( - isolate_data, context, args, exec_args, nullptr, flags, thread_id); - #if HAVE_INSPECTOR -- if (inspector_parent_handle) { -- env->InitializeInspector( -- std::move(static_cast( -- inspector_parent_handle.get())->impl)); -- } else { -- env->InitializeInspector({}); -+ if (env->should_initialize_inspector()) { -+ if (inspector_parent_handle) { -+ env->InitializeInspector( -+ std::move(static_cast( -+ inspector_parent_handle.get())->impl)); -+ } else { -+ env->InitializeInspector({}); -+ } - } - #endif - -diff --git a/src/env-inl.h b/src/env-inl.h -index 1e85bc07a4cc29f3b380da3c0e217a85309eb3a5..845e00208af4b12960ed8b3f3926323af7685185 100644 ---- a/src/env-inl.h -+++ b/src/env-inl.h -@@ -892,6 +892,10 @@ inline bool Environment::no_global_search_paths() const { - !options_->global_search_paths; - } - -+inline bool Environment::should_initialize_inspector() const { -+ return (flags_ & EnvironmentFlags::kNoInitializeInspector) == 0; -+} -+ - bool Environment::filehandle_close_warning() const { - return emit_filehandle_warning_; - } -diff --git a/src/env.h b/src/env.h -index 0c3715151488f425a723618252e1277b78fafe5f..e0deca497feb111622b257b952c9ed9161c7d001 100644 ---- a/src/env.h -+++ b/src/env.h -@@ -1204,6 +1204,7 @@ class Environment : public MemoryRetainer { - inline bool tracks_unmanaged_fds() const; - inline bool hide_console_windows() const; - inline bool no_global_search_paths() const; -+ inline bool should_initialize_inspector() const; - inline uint64_t thread_id() const; - inline worker::Worker* worker_context() const; - Environment* worker_parent_env() const; -diff --git a/src/node.h b/src/node.h -index 364f789fbcbec8e3234961294698d8e69b04a310..85b5ac6a5a5cb5e4388a92a1d07c9afe17140a8c 100644 ---- a/src/node.h -+++ b/src/node.h -@@ -420,7 +420,11 @@ enum Flags : uint64_t { - // $HOME/.node_modules and $NODE_PATH. This is used by standalone apps that - // do not expect to have their behaviors changed because of globally - // installed modules. -- kNoGlobalSearchPaths = 1 << 7 -+ kNoGlobalSearchPaths = 1 << 7, -+ // Controls whether or not the Environment should call InitializeInspector. -+ // This control is needed by embedders who may not want to initialize the V8 -+ // inspector in situations where it already exists. -+ kNoInitializeInspector = 1 << 8 - }; - } // namespace EnvironmentFlags - diff --git a/patches/node/fix_crash_caused_by_gethostnamew_on_windows_7.patch b/patches/node/fix_crash_caused_by_gethostnamew_on_windows_7.patch index eb24c26a805cb..8d1899062c761 100644 --- a/patches/node/fix_crash_caused_by_gethostnamew_on_windows_7.patch +++ b/patches/node/fix_crash_caused_by_gethostnamew_on_windows_7.patch @@ -6,7 +6,7 @@ Subject: fix: crash caused by GetHostNameW on Windows 7 Backported from https://github.com/libuv/libuv/pull/3285. diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c -index 88602c7ee8623f16f87398cf3ffd1f71555fc1a0..5ffde08e1aed041c4da679156ed10f7e54bfc386 100644 +index 33e874ac442f88b58d2b68c8ec9764f6f664552e..37ece5e2867ab836492a8b7faa0aa5e1b8e562f0 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -37,6 +37,7 @@ @@ -166,69 +166,17 @@ index 88602c7ee8623f16f87398cf3ffd1f71555fc1a0..5ffde08e1aed041c4da679156ed10f7e int uv_os_gethostname(char* buffer, size_t* size) { WCHAR buf[UV_MAXHOSTNAMESIZE]; size_t len; -@@ -1674,7 +1803,9 @@ int uv_os_gethostname(char* buffer, size_t* size) { +@@ -1674,10 +1803,10 @@ int uv_os_gethostname(char* buffer, size_t* size) { uv__once_init(); /* Initialize winsock */ -- if (GetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) -+ sGetHostNameW gethostnamew = +- if (pGetHostNameW == NULL) +- return UV_ENOSYS; ++ uv_sGetHostNameW gethostnamew = + pGetHostNameW == NULL ? uv__gethostnamew_nt60 : pGetHostNameW; + +- if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) + if (gethostnamew(buf, UV_MAXHOSTNAMESIZE) != 0) return uv_translate_sys_error(WSAGetLastError()); convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str); -diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c -index bb86ec8ceac8ba3fccd02b292aca7ddfab38e187..9d6effb10ddd1801f7411ee71a70575b7072ab7d 100644 ---- a/deps/uv/src/win/winapi.c -+++ b/deps/uv/src/win/winapi.c -@@ -45,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; - /* User32.dll function pointer */ - sSetWinEventHook pSetWinEventHook; - -+/* ws2_32.dll function pointer */ -+sGetHostNameW pGetHostNameW; - - void uv_winapi_init(void) { - HMODULE ntdll_module; - HMODULE powrprof_module; - HMODULE user32_module; - HMODULE kernel32_module; -+ HMODULE ws2_32_module;; - - ntdll_module = GetModuleHandleA("ntdll.dll"); - if (ntdll_module == NULL) { -@@ -134,4 +137,10 @@ void uv_winapi_init(void) { - pSetWinEventHook = (sSetWinEventHook) - GetProcAddress(user32_module, "SetWinEventHook"); - } -+ -+ ws2_32_module = LoadLibraryA("ws2_32.dll"); -+ if (ws2_32_module != NULL) { -+ pGetHostNameW = (sGetHostNameW) -+ GetProcAddress(ws2_32_module, "GetHostNameW"); -+ } - } -diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h -index 0b66b5634bca88cec65b1bf0c0193986f5ddd542..5951717ab9e21db274f956c44410cc03c1617eaf 100644 ---- a/deps/uv/src/win/winapi.h -+++ b/deps/uv/src/win/winapi.h -@@ -4739,6 +4739,11 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS { - # define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17) - #endif - -+/* From winsock2.h */ -+typedef int (WSAAPI *sGetHostNameW) -+ (PWSTR name, -+ int namelen); -+ - /* Ntdll function pointers */ - extern sRtlGetVersion pRtlGetVersion; - extern sRtlNtStatusToDosError pRtlNtStatusToDosError; -@@ -4759,4 +4764,7 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi - /* User32.dll function pointer */ - extern sSetWinEventHook pSetWinEventHook; - -+/* ws2_32.dll function pointer */ -+extern sGetHostNameW pGetHostNameW; -+ - #endif /* UV_WIN_WINAPI_H_ */ diff --git a/patches/node/fix_crypto_tests_to_run_with_bssl.patch b/patches/node/fix_crypto_tests_to_run_with_bssl.patch index 7774100703837..052e1e10ffaec 100644 --- a/patches/node/fix_crypto_tests_to_run_with_bssl.patch +++ b/patches/node/fix_crypto_tests_to_run_with_bssl.patch @@ -31,7 +31,7 @@ index 4e3c32fdcd23fbe3e74bd5e624b739d224689f33..19d65aae7fa8ec9f9b907733ead17a20 // Test Parallel Execution w/ KeyObject is threadsafe in openssl3 { diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js -index 21c5af6cfe3e5eef64fc2d4dcc63c55b1d79ad51..b21eb4b97ad778304b3a4e8d549e109614350dfb 100644 +index 3749895769ffc9947143aee9aeb126628262bc84..f769fc37dbd81d5a0219236921e0bcb0de416463 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -50,7 +50,9 @@ const errMessages = { @@ -251,6 +251,35 @@ index 3bbca5b0da395b94c04da7bb7c55b107e41367d8..af62558c4f23aa82804e0077da7b7f3a // +diff --git a/test/parallel/test-crypto-certificate.js b/test/parallel/test-crypto-certificate.js +index 4a5f1f149fe6c739f7f1d2ee17df6e61a942d621..b3287f428ce6b3fde11d449c601a57ff5e3843f9 100644 +--- a/test/parallel/test-crypto-certificate.js ++++ b/test/parallel/test-crypto-certificate.js +@@ -40,8 +40,10 @@ function copyArrayBuffer(buf) { + } + + function checkMethods(certificate) { +- ++ /* spkacValid has a md5 based signature which is not allowed in boringssl ++ https://boringssl.googlesource.com/boringssl/+/33d7e32ce40c04e8f1b99c05964956fda187819f + assert.strictEqual(certificate.verifySpkac(spkacValid), true); ++ */ + assert.strictEqual(certificate.verifySpkac(spkacFail), false); + + assert.strictEqual( +@@ -56,10 +58,12 @@ function checkMethods(certificate) { + ); + assert.strictEqual(certificate.exportChallenge(spkacFail), ''); + ++ /* spkacValid has a md5 based signature which is not allowed in boringssl + const ab = copyArrayBuffer(spkacValid); + assert.strictEqual(certificate.verifySpkac(ab), true); + assert.strictEqual(certificate.verifySpkac(new Uint8Array(ab)), true); + assert.strictEqual(certificate.verifySpkac(new DataView(ab)), true); ++ */ + } + + { diff --git a/test/parallel/test-crypto-cipher-decipher.js b/test/parallel/test-crypto-cipher-decipher.js index 35514afbea92562a81c163b1e4d918b4ab609f71..13098e1acf12c309f2ed6f6143a2c2eeb8a2763d 100644 --- a/test/parallel/test-crypto-cipher-decipher.js @@ -508,6 +537,19 @@ index af2146982c7a3bf7bd7527f44e4b17a3b605026e..f6b91f675cfea367c608892dee078b56 // Non-XOF hash functions should accept valid outputLength options as well. assert.strictEqual(crypto.createHash('sha224', { outputLength: 28 }) +diff --git a/test/parallel/test-crypto-hkdf.js b/test/parallel/test-crypto-hkdf.js +index 16744201a935dcd25af4e0f446701b08fe08dd64..e7ef0b78a19fb755456d038fc676eedb2f71ff07 100644 +--- a/test/parallel/test-crypto-hkdf.js ++++ b/test/parallel/test-crypto-hkdf.js +@@ -117,8 +117,6 @@ const algorithms = [ + ['sha256', 'secret', 'salt', 'info', 10], + ['sha512', 'secret', 'salt', '', 15], + ]; +-if (!common.hasOpenSSL3) +- algorithms.push(['whirlpool', 'secret', '', 'info', 20]); + + algorithms.forEach(([ hash, secret, salt, info, length ]) => { + { diff --git a/test/parallel/test-crypto-padding.js b/test/parallel/test-crypto-padding.js index f1f14b472997e76bb4100edb1c6cf4fc24d1074d..5057e3f9bc5bb78aceffa5e79530f8ceed84e6f7 100644 --- a/test/parallel/test-crypto-padding.js @@ -590,7 +632,7 @@ index 9afcb38616dafd6da1ab7b5843d68f4f796ca9a6..00d3381056a5a40c549f06d74c130149 } +*/ diff --git a/test/parallel/test-crypto-sign-verify.js b/test/parallel/test-crypto-sign-verify.js -index 6893f0c0e6d49a8e171ec9f156f74656dab9fd06..4c8ccd10e0dcd64669cccca1e8c2e5279d683595 100644 +index b2c14b1efcd68bd20e9c946106f1ab5fb58627c5..eef0bfe638b641c68fdadd95226a74df044921cb 100644 --- a/test/parallel/test-crypto-sign-verify.js +++ b/test/parallel/test-crypto-sign-verify.js @@ -29,6 +29,7 @@ const keySize = 2048; @@ -673,20 +715,19 @@ index 008ab129f0e019c659eecf5a76b7eb412c947fe3..6688f5d916f50e1e4fcfff1619c8634a cipher.end('Papaya!'); // Should not cause an unhandled exception. diff --git a/test/parallel/test-crypto-x509.js b/test/parallel/test-crypto-x509.js -index c85a79b4854369e35fbe89833e9df9a12065671e..8f13ac60362854d12264f26b74533bd55efd6605 100644 +index d1782359277dc52d7a60830a6dd958544d610e6b..4c781f062bc505b860b821773070551f4cd80067 100644 --- a/test/parallel/test-crypto-x509.js +++ b/test/parallel/test-crypto-x509.js -@@ -104,7 +104,8 @@ const der = Buffer.from( - '84:AC:5B:08:9A:20:89:B6:8F:D6' +@@ -110,7 +110,7 @@ const der = Buffer.from( + 'A3:06:C5:CE:43:C1:7F:2D:7E:5F:44:A5:EE:A3:CB:97:05:A3:E3:68' ); assert.strictEqual(x509.keyUsage, undefined); - assert.strictEqual(x509.serialNumber, 'ECC9B856270DA9A8'); -+ + assert.match(x509.serialNumber, /ECC9B856270DA9A8/i); assert.deepStrictEqual(x509.raw, der); -@@ -190,6 +191,12 @@ const der = Buffer.from( +@@ -196,6 +196,12 @@ const der = Buffer.from( }); mc.port2.postMessage(x509); @@ -699,7 +740,7 @@ index c85a79b4854369e35fbe89833e9df9a12065671e..8f13ac60362854d12264f26b74533bd5 // Verify that legacy encoding works const legacyObjectCheck = { subject: 'C=US\n' + -@@ -213,11 +220,7 @@ const der = Buffer.from( +@@ -219,11 +225,7 @@ const der = Buffer.from( 'CA Issuers - URI:http://ca.nodejs.org/ca.cert' : 'OCSP - URI:http://ocsp.nodejs.org/\n' + 'CA Issuers - URI:http://ca.nodejs.org/ca.cert\n', @@ -712,16 +753,16 @@ index c85a79b4854369e35fbe89833e9df9a12065671e..8f13ac60362854d12264f26b74533bd5 bits: 1024, exponent: '0x10001', valid_from: 'Nov 16 18:42:21 2018 GMT', -@@ -226,7 +229,7 @@ const der = Buffer.from( - fingerprint256: - 'B0:BE:46:49:B8:29:63:E0:6F:63:C8:8A:57:9C:3F:9B:72:' + - 'C6:F5:89:E3:0D:84:AC:5B:08:9A:20:89:B6:8F:D6', +@@ -237,7 +239,7 @@ const der = Buffer.from( + 'D0:39:97:54:B6:D0:B4:46:5B:DE:13:5B:68:86:B6:F2:A8:' + + '95:22:D5:6E:8B:35:DA:89:29:CA:A3:06:C5:CE:43:C1:7F:' + + '2D:7E:5F:44:A5:EE:A3:CB:97:05:A3:E3:68', - serialNumber: 'ECC9B856270DA9A8' + serialNumberPattern: /ECC9B856270DA9A8/i }; const legacyObject = x509.toLegacyObject(); -@@ -235,7 +238,7 @@ const der = Buffer.from( +@@ -246,7 +248,7 @@ const der = Buffer.from( assert.strictEqual(legacyObject.subject, legacyObjectCheck.subject); assert.strictEqual(legacyObject.issuer, legacyObjectCheck.issuer); assert.strictEqual(legacyObject.infoAccess, legacyObjectCheck.infoAccess); @@ -730,7 +771,7 @@ index c85a79b4854369e35fbe89833e9df9a12065671e..8f13ac60362854d12264f26b74533bd5 assert.strictEqual(legacyObject.bits, legacyObjectCheck.bits); assert.strictEqual(legacyObject.exponent, legacyObjectCheck.exponent); assert.strictEqual(legacyObject.valid_from, legacyObjectCheck.valid_from); -@@ -244,7 +247,5 @@ const der = Buffer.from( +@@ -255,7 +257,5 @@ const der = Buffer.from( assert.strictEqual( legacyObject.fingerprint256, legacyObjectCheck.fingerprint256); @@ -740,7 +781,7 @@ index c85a79b4854369e35fbe89833e9df9a12065671e..8f13ac60362854d12264f26b74533bd5 + assert.match(legacyObject.serialNumber, legacyObjectCheck.serialNumberPattern); } diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js -index 58441be4d093f06cac3d47e2fa752f2354a49f8a..36a91946c8ad23250a47c433c1216ec9cb14f0e1 100644 +index a8ceb169de2b3de73f062083c42292babc673e73..a3bb574d0e5dc85b4ba3fb0b3bd8782fbb8c8700 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -67,7 +67,7 @@ assert.throws(() => { @@ -770,16 +811,16 @@ index 58441be4d093f06cac3d47e2fa752f2354a49f8a..36a91946c8ad23250a47c433c1216ec9 !('opensslErrorStack' in err); }); -@@ -137,8 +137,6 @@ assert(crypto.getHashes().includes('sha1')); +@@ -150,8 +150,6 @@ assert(crypto.getHashes().includes('sha1')); assert(crypto.getHashes().includes('sha256')); assert(!crypto.getHashes().includes('SHA1')); assert(!crypto.getHashes().includes('SHA256')); -assert(crypto.getHashes().includes('RSA-SHA1')); -assert(!crypto.getHashes().includes('rsa-sha1')); validateList(crypto.getHashes()); - - // Assume that we have at least secp384r1. -@@ -172,7 +170,7 @@ const encodingError = { + // Make sure all of the hashes are supported by OpenSSL + for (const algo of crypto.getHashes()) +@@ -188,7 +186,7 @@ const encodingError = { // hex input that's not a power of two should throw, not assert in C++ land. ['createCipher', 'createDecipher'].forEach((funcName) => { assert.throws( @@ -788,7 +829,7 @@ index 58441be4d093f06cac3d47e2fa752f2354a49f8a..36a91946c8ad23250a47c433c1216ec9 (error) => { assert.ok(!('opensslErrorStack' in error)); if (common.hasFipsCrypto) { -@@ -224,15 +222,15 @@ assert.throws(() => { +@@ -240,15 +238,15 @@ assert.throws(() => { library: 'rsa routines', } : { name: 'Error', @@ -809,7 +850,7 @@ index 58441be4d093f06cac3d47e2fa752f2354a49f8a..36a91946c8ad23250a47c433c1216ec9 if (!common.hasOpenSSL3) { assert.throws(() => { // The correct header inside `rsa_private_pkcs8_bad.pem` should have been -@@ -260,7 +258,7 @@ if (!common.hasOpenSSL3) { +@@ -276,7 +274,7 @@ if (!common.hasOpenSSL3) { return true; }); } @@ -1011,3 +1052,36 @@ index 1094845c73e14313860ad476fb7baba2a11b5af4..51972b4b34b191ac59145889dbf2da5c }; function generateWrappingKeys() { +diff --git a/test/parallel/test-x509-escaping.js b/test/parallel/test-x509-escaping.js +index 99418e4c0bf21c26d5ba0ad9d617419abc625593..fc129b26ea13895353d6ede26bb2d91695c94ba4 100644 +--- a/test/parallel/test-x509-escaping.js ++++ b/test/parallel/test-x509-escaping.js +@@ -425,11 +425,11 @@ const { hasOpenSSL3 } = common; + assert.strictEqual(certX509.subjectAltName, 'DNS:evil.example.com'); + + // The newer X509Certificate API allows customizing this behavior: +- assert.strictEqual(certX509.checkHost(servername), servername); ++ assert.strictEqual(certX509.checkHost(servername), undefined); + assert.strictEqual(certX509.checkHost(servername, { subject: 'default' }), + undefined); + assert.strictEqual(certX509.checkHost(servername, { subject: 'always' }), +- servername); ++ undefined); + assert.strictEqual(certX509.checkHost(servername, { subject: 'never' }), + undefined); + +@@ -464,11 +464,11 @@ const { hasOpenSSL3 } = common; + assert.strictEqual(certX509.subjectAltName, 'IP Address:1.2.3.4'); + + // The newer X509Certificate API allows customizing this behavior: +- assert.strictEqual(certX509.checkHost(servername), servername); ++ assert.strictEqual(certX509.checkHost(servername), undefined); + assert.strictEqual(certX509.checkHost(servername, { subject: 'default' }), +- servername); ++ undefined); + assert.strictEqual(certX509.checkHost(servername, { subject: 'always' }), +- servername); ++ undefined); + assert.strictEqual(certX509.checkHost(servername, { subject: 'never' }), + undefined); + diff --git a/patches/node/fix_don_t_create_console_window_when_creating_process.patch b/patches/node/fix_don_t_create_console_window_when_creating_process.patch deleted file mode 100644 index 2ae896f558c86..0000000000000 --- a/patches/node/fix_don_t_create_console_window_when_creating_process.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Raymond Zhao -Date: Tue, 4 Jan 2022 16:11:41 -0800 -Subject: fix: Don't create console window when creating process - -This patch prevents console windows from being created during -execSync calls, or spawnSync calls where shell is true. Otherwise, -Windows users will see command prompts pop up for those calls. - -The patch has been upstreamed at https://github.com/nodejs/node/pull/41412. - -diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc -index 1141aceae984fba6ed07cd272a79d4007b9b03fe..afd08519d7f8974adff4060513f6160519a0b6b3 100644 ---- a/src/spawn_sync.cc -+++ b/src/spawn_sync.cc -@@ -810,6 +810,9 @@ Maybe SyncProcessRunner::ParseOptions(Local js_value) { - if (js_win_hide->BooleanValue(isolate)) - uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE; - -+ if (env()->hide_console_windows()) -+ uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE; -+ - Local js_wva = - js_options->Get(context, env()->windows_verbatim_arguments_string()) - .ToLocalChecked(); diff --git a/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch new file mode 100644 index 0000000000000..ca41bd3391169 --- /dev/null +++ b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Thu, 6 Oct 2022 04:09:16 -0700 +Subject: fix: expose the built-in electron module via the ESM loader + +This allows usage of `import { app } from 'electron'` and `import('electron')` natively in the browser + non-sandboxed renderer + +diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js +index 5ae0e17dcfb5e24a1a117c33c4d42891686e693f..619fe6cef3b02eb575410225f41d3e7d51f37b93 100644 +--- a/lib/internal/modules/esm/get_format.js ++++ b/lib/internal/modules/esm/get_format.js +@@ -31,6 +31,7 @@ const protocolHandlers = ObjectAssign(ObjectCreate(null), { + 'http:': getHttpProtocolModuleFormat, + 'https:': getHttpProtocolModuleFormat, + 'node:'() { return 'builtin'; }, ++ 'electron:'() { return 'commonjs'; }, + }); + + function getDataProtocolModuleFormat(parsed) { +diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js +index 3576f75f0a40a64dceb7e2649b344b83ebc04b39..314fbb78931eef154a1e47c655e2d4bafe11bac3 100644 +--- a/lib/internal/modules/esm/resolve.js ++++ b/lib/internal/modules/esm/resolve.js +@@ -888,6 +888,8 @@ function parsePackageName(specifier, base) { + return { packageName, packageSubpath, isScoped }; + } + ++const electronSpecifiers = new SafeSet(['electron', 'electron/main', 'electron/common', 'electron/renderer']); ++ + /** + * @param {string} specifier + * @param {string | URL | undefined} base +@@ -898,6 +900,10 @@ function packageResolve(specifier, base, conditions) { + if (NativeModule.canBeRequiredByUsers(specifier)) + return new URL('node:' + specifier); + ++ if (electronSpecifiers.has(specifier)) { ++ return new URL('electron:electron'); ++ } ++ + const { packageName, packageSubpath, isScoped } = + parsePackageName(specifier, base); + +@@ -1099,7 +1105,7 @@ function checkIfDisallowedImport(specifier, parsed, parsedParentURL) { + + function throwIfUnsupportedURLProtocol(url) { + if (url.protocol !== 'file:' && url.protocol !== 'data:' && +- url.protocol !== 'node:') { ++ url.protocol !== 'node:' && url.protocol !== 'electron:') { + throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(url); + } + } +diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js +index d7f4c7edec63d3ce500955a37c6eac00e3e524fd..b97cac53365b121f8e232f0085ff166511c3dda3 100644 +--- a/lib/internal/modules/esm/translators.js ++++ b/lib/internal/modules/esm/translators.js +@@ -155,7 +155,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source, + + if (!cjsParse) await initCJSParse(); + const { module, exportNames } = cjsPreparseModuleExports(filename); +- const namesWithDefault = exportNames.has('default') ? ++ const namesWithDefault = filename === 'electron' ? ['default', ...Object.keys(module.exports)] : exportNames.has('default') ? + [...exportNames] : ['default', ...exportNames]; + + return new ModuleWrap(url, undefined, namesWithDefault, function() { +@@ -174,7 +174,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source, + } + } + +- for (const exportName of exportNames) { ++ for (const exportName of namesWithDefault) { + if (!ObjectPrototypeHasOwnProperty(exports, exportName) || + exportName === 'default') + continue; +diff --git a/lib/internal/url.js b/lib/internal/url.js +index 939374a495856cf2b9c573fa98dc1895eee5e143..c37258ac29e8b7558c1f9a2af7ba6bdd0eab1355 100644 +--- a/lib/internal/url.js ++++ b/lib/internal/url.js +@@ -1418,6 +1418,8 @@ function fileURLToPath(path) { + path = new URL(path); + else if (!isURLInstance(path)) + throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path); ++ if (path.protocol === 'electron:') ++ return 'electron'; + if (path.protocol !== 'file:') + throw new ERR_INVALID_URL_SCHEME('file'); + return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path); diff --git a/patches/node/fix_expose_tracing_agent_and_use_tracing_tracingcontroller_instead.patch b/patches/node/fix_expose_tracing_agent_and_use_tracing_tracingcontroller_instead.patch index 8c641431ad5cc..b374abb78a810 100644 --- a/patches/node/fix_expose_tracing_agent_and_use_tracing_tracingcontroller_instead.patch +++ b/patches/node/fix_expose_tracing_agent_and_use_tracing_tracingcontroller_instead.patch @@ -7,10 +7,10 @@ Subject: fix: expose tracing::Agent and use tracing::TracingController instead This API is used by Electron to create Node's tracing controller. diff --git a/src/api/environment.cc b/src/api/environment.cc -index 0fb750c5abbe00740f2095ec397c823e26666199..523d252e08974a10f9a53fb46d3345669cec3380 100644 +index 55b895c235f51eb7bcbd8cd4065b42a05208026a..1add2976e7c48e6704400b9ea0795b934ab0bfc2 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc -@@ -459,6 +459,10 @@ MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) { +@@ -461,6 +461,10 @@ MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) { return env->platform(); } @@ -22,7 +22,7 @@ index 0fb750c5abbe00740f2095ec397c823e26666199..523d252e08974a10f9a53fb46d334566 int thread_pool_size, node::tracing::TracingController* tracing_controller) { diff --git a/src/node.h b/src/node.h -index 45de72bd94cf669ac2badf89d23164cb7022a5b3..364f789fbcbec8e3234961294698d8e69b04a310 100644 +index 966edcd041be1bded2c3a86e5734d2849019c372..9b9ff1c86ceeaeca828328065e2ad5573ea17fc5 100644 --- a/src/node.h +++ b/src/node.h @@ -118,6 +118,7 @@ namespace node { @@ -33,7 +33,7 @@ index 45de72bd94cf669ac2badf89d23164cb7022a5b3..364f789fbcbec8e3234961294698d8e6 class TracingController; } -@@ -499,6 +500,8 @@ NODE_EXTERN v8::MaybeLocal PrepareStackTraceCallback( +@@ -523,6 +524,8 @@ NODE_EXTERN v8::MaybeLocal PrepareStackTraceCallback( NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env); NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env); diff --git a/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch b/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch index a91c0a3cdd949..1e6d8e14b488b 100644 --- a/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch +++ b/patches/node/fix_handle_boringssl_and_openssl_incompatibilities.patch @@ -17,10 +17,10 @@ Upstreams: - https://github.com/nodejs/node/pull/39136 diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc -index fe828bafa6422cc1f1717afddbd4b199055e9c43..74c56954e5e2d8efc3d8495860addc0138f39f3a 100644 +index a5aa39c23c1708ac27564a1a77a9f05fc07791e2..630a3400e74f20b1dbee17027c7dbe8688fed4b2 100644 --- a/src/crypto/crypto_common.cc +++ b/src/crypto/crypto_common.cc -@@ -176,7 +176,7 @@ const char* GetClientHelloALPN(const SSLPointer& ssl) { +@@ -162,7 +162,7 @@ const char* GetClientHelloALPN(const SSLPointer& ssl) { const unsigned char* buf; size_t len; size_t rem; @@ -29,7 +29,7 @@ index fe828bafa6422cc1f1717afddbd4b199055e9c43..74c56954e5e2d8efc3d8495860addc01 if (!SSL_client_hello_get0_ext( ssl.get(), TLSEXT_TYPE_application_layer_protocol_negotiation, -@@ -189,13 +189,15 @@ const char* GetClientHelloALPN(const SSLPointer& ssl) { +@@ -175,13 +175,15 @@ const char* GetClientHelloALPN(const SSLPointer& ssl) { len = (buf[0] << 8) | buf[1]; if (len + 2 != rem) return nullptr; return reinterpret_cast(buf + 3); @@ -46,7 +46,7 @@ index fe828bafa6422cc1f1717afddbd4b199055e9c43..74c56954e5e2d8efc3d8495860addc01 if (!SSL_client_hello_get0_ext( ssl.get(), TLSEXT_TYPE_server_name, -@@ -217,6 +219,8 @@ const char* GetClientHelloServerName(const SSLPointer& ssl) { +@@ -203,6 +205,8 @@ const char* GetClientHelloServerName(const SSLPointer& ssl) { if (len + 2 > rem) return nullptr; return reinterpret_cast(buf + 5); @@ -55,7 +55,7 @@ index fe828bafa6422cc1f1717afddbd4b199055e9c43..74c56954e5e2d8efc3d8495860addc01 } const char* GetServerName(SSL* ssl) { -@@ -224,7 +228,10 @@ const char* GetServerName(SSL* ssl) { +@@ -210,7 +214,10 @@ const char* GetServerName(SSL* ssl) { } bool SetGroups(SecureContext* sc, const char* groups) { @@ -66,7 +66,7 @@ index fe828bafa6422cc1f1717afddbd4b199055e9c43..74c56954e5e2d8efc3d8495860addc01 } const char* X509ErrorCode(long err) { // NOLINT(runtime/int) -@@ -1117,14 +1124,14 @@ MaybeLocal GetClientHelloCiphers( +@@ -1101,14 +1108,14 @@ MaybeLocal GetClientHelloCiphers( Environment* env, const SSLPointer& ssl) { EscapableHandleScope scope(env->isolate()); @@ -86,10 +86,10 @@ index fe828bafa6422cc1f1717afddbd4b199055e9c43..74c56954e5e2d8efc3d8495860addc01 if (!Set(env->context(), obj, diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc -index 7e99759654e8b9272c48e0e6c0637f4327dc1615..612ed87ce396e285719a9efc8c346adb6d29b366 100644 +index b6ef5e5b1e004e663fbfd2578b82644cb53051e0..1d48ea6d022304b1e6a4f703fea790437edcc876 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc -@@ -144,13 +144,11 @@ void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const { +@@ -143,13 +143,11 @@ void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const { bool DiffieHellman::Init(const char* p, int p_len, int g) { dh_.reset(DH_new()); if (p_len <= 0) { @@ -105,7 +105,7 @@ index 7e99759654e8b9272c48e0e6c0637f4327dc1615..612ed87ce396e285719a9efc8c346adb return false; } BIGNUM* bn_p = -@@ -168,21 +166,18 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) { +@@ -167,21 +165,18 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) { bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) { dh_.reset(DH_new()); if (p_len <= 0) { @@ -130,7 +130,7 @@ index 7e99759654e8b9272c48e0e6c0637f4327dc1615..612ed87ce396e285719a9efc8c346adb return false; } BIGNUM* bn_p = -@@ -502,16 +497,20 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { +@@ -501,16 +496,20 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { if (!BN_set_word(bn_g.get(), params->params.generator) || !DH_set0_pqg(dh.get(), prime, nullptr, bn_g.get())) return EVPKeyCtxPointer(); @@ -152,7 +152,7 @@ index 7e99759654e8b9272c48e0e6c0637f4327dc1615..612ed87ce396e285719a9efc8c346adb if (!param_ctx || EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 || EVP_PKEY_CTX_set_dh_paramgen_prime_len( -@@ -523,8 +522,10 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { +@@ -522,8 +521,10 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) { return EVPKeyCtxPointer(); } @@ -188,28 +188,6 @@ index c7894baf00ee9ce4684f4c752f1c7c9b98163741..655895dbff8b88daa53c7b40a5feca42 if (EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) return EVPKeyCtxPointer(); -diff --git a/src/crypto/crypto_hkdf.cc b/src/crypto/crypto_hkdf.cc -index 0aa96ada47abe4b66fb616c665101278bbe0afb6..1e9a4863c5faea5f6b275483ca16f3a6e8dac25b 100644 ---- a/src/crypto/crypto_hkdf.cc -+++ b/src/crypto/crypto_hkdf.cc -@@ -101,6 +101,7 @@ bool HKDFTraits::DeriveBits( - Environment* env, - const HKDFConfig& params, - ByteSource* out) { -+#ifndef OPENSSL_IS_BORINGSSL - EVPKeyCtxPointer ctx = - EVPKeyCtxPointer(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr)); - if (!ctx || -@@ -132,6 +133,9 @@ bool HKDFTraits::DeriveBits( - - *out = std::move(buf); - return true; -+#else -+ return false; -+#endif - } - - void HKDFConfig::MemoryInfo(MemoryTracker* tracker) const { diff --git a/src/crypto/crypto_random.cc b/src/crypto/crypto_random.cc index fc88deb460314c2620d842ec30141bcd13109d60..c097ccfcffb1158317ba09e7c4beb725ccbab74f 100644 --- a/src/crypto/crypto_random.cc @@ -244,10 +222,10 @@ index ae4550e9fde8120c35409e495d5b763a95546509..188a7efe76df2a1aa2eb2746f4d74836 if (target diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc -index fec0a493c985f1fb716dd6222e438b430947f2a1..1a7d26ad134b094d02023c99934b8ac7a4bb18d7 100644 +index e1ef170a9f17634d218492a2ce888c3a4365e097..f55e292fbbc75448b15dc9be0327ad2dedef49e0 100644 --- a/src/crypto/crypto_util.cc +++ b/src/crypto/crypto_util.cc -@@ -503,24 +503,14 @@ Maybe Decorate(Environment* env, Local obj, +@@ -508,24 +508,15 @@ Maybe Decorate(Environment* env, Local obj, V(BIO) \ V(PKCS7) \ V(X509V3) \ @@ -269,10 +247,11 @@ index fec0a493c985f1fb716dd6222e438b430947f2a1..1a7d26ad134b094d02023c99934b8ac7 - V(ASYNC) \ - V(KDF) \ - V(SM2) \ ++ V(HKDF) \ V(USER) \ #define V(name) case ERR_LIB_##name: lib = #name "_"; break; -@@ -680,7 +670,7 @@ void SecureBuffer(const FunctionCallbackInfo& args) { +@@ -684,7 +675,7 @@ void SecureBuffer(const FunctionCallbackInfo& args) { CHECK(args[0]->IsUint32()); Environment* env = Environment::GetCurrent(args); uint32_t len = args[0].As()->Value(); @@ -281,7 +260,7 @@ index fec0a493c985f1fb716dd6222e438b430947f2a1..1a7d26ad134b094d02023c99934b8ac7 if (data == nullptr) { // There's no memory available for the allocation. // Return nothing. -@@ -692,7 +682,7 @@ void SecureBuffer(const FunctionCallbackInfo& args) { +@@ -696,7 +687,7 @@ void SecureBuffer(const FunctionCallbackInfo& args) { data, len, [](void* data, size_t len, void* deleter_data) { @@ -290,7 +269,7 @@ index fec0a493c985f1fb716dd6222e438b430947f2a1..1a7d26ad134b094d02023c99934b8ac7 }, data); Local buffer = ArrayBuffer::New(env->isolate(), store); -@@ -700,10 +690,12 @@ void SecureBuffer(const FunctionCallbackInfo& args) { +@@ -704,10 +695,12 @@ void SecureBuffer(const FunctionCallbackInfo& args) { } void SecureHeapUsed(const FunctionCallbackInfo& args) { @@ -303,20 +282,6 @@ index fec0a493c985f1fb716dd6222e438b430947f2a1..1a7d26ad134b094d02023c99934b8ac7 } } // namespace -diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h -index 463a19f516d23fdb56eb83025f4a3f2b3f4a426b..86e66e29ee644f86cb8ac20f37061fc03dc3099b 100644 ---- a/src/crypto/crypto_util.h -+++ b/src/crypto/crypto_util.h -@@ -16,7 +16,9 @@ - #include - #include - #include -+#ifndef OPENSSL_IS_BORINGSSL - #include -+#endif - #include - #include - #include diff --git a/src/node_metadata.h b/src/node_metadata.h index 4486d5af2c1622c7c8f44401dc3ebb986d8e3c2e..db1769f1b3f1617ed8dbbea57b5e324183b42be2 100644 --- a/src/node_metadata.h diff --git a/patches/node/fix_override_createjob_in_node_platform.patch b/patches/node/fix_override_createjob_in_node_platform.patch new file mode 100644 index 0000000000000..252cf947f4bc4 --- /dev/null +++ b/patches/node/fix_override_createjob_in_node_platform.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Keeley Hammond +Date: Tue, 2 Aug 2022 12:52:02 -0700 +Subject: fix: override createjob in node_platform + +This CL changed Platform::CreateJob to an abstract method: +https://chromium-review.googlesource.com/c/v8/v8/+/3779694 +This patch adds an override for NodePlatform::CreateJob, using +the same parameters as PostJob. + +diff --git a/src/node_platform.cc b/src/node_platform.cc +index 5be79694fef65c9290f1b46d2657581dea16f543..e10caa9f6e39ec5b255acd9bc6b7f8efc77221d9 100644 +--- a/src/node_platform.cc ++++ b/src/node_platform.cc +@@ -523,6 +523,12 @@ std::unique_ptr NodePlatform::PostJob(v8::TaskPriority priority, + this, priority, std::move(job_task), NumberOfWorkerThreads()); + } + ++std::unique_ptr NodePlatform::CreateJob(v8::TaskPriority priority, ++ std::unique_ptr job_task) { ++ return v8::platform::NewDefaultJobHandle( ++ this, priority, std::move(job_task), NumberOfWorkerThreads()); ++} ++ + bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { + return ForIsolate(isolate)->IdleTasksEnabled(); + } +diff --git a/src/node_platform.h b/src/node_platform.h +index 4a05f3bba58c8e875d0ab67f292589edbb3b812b..b8a956c286a5ea88b8b520322e04b4e4e16a2591 100644 +--- a/src/node_platform.h ++++ b/src/node_platform.h +@@ -158,6 +158,9 @@ class NodePlatform : public MultiIsolatePlatform { + std::unique_ptr PostJob( + v8::TaskPriority priority, + std::unique_ptr job_task) override; ++ std::unique_ptr CreateJob( ++ v8::TaskPriority priority, ++ std::unique_ptr job_task) override; + + void RegisterIsolate(v8::Isolate* isolate, uv_loop_t* loop) override; + void RegisterIsolate(v8::Isolate* isolate, diff --git a/patches/node/fix_preserve_proper_method_names_as-is_in_error_stack.patch b/patches/node/fix_preserve_proper_method_names_as-is_in_error_stack.patch new file mode 100644 index 0000000000000..e14acc34fa100 --- /dev/null +++ b/patches/node/fix_preserve_proper_method_names_as-is_in_error_stack.patch @@ -0,0 +1,432 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr +Date: Thu, 7 Apr 2022 11:07:10 +0200 +Subject: fix: preserve "proper method names" as-is in error.stack + +Refs https://chromium-review.googlesource.com/c/v8/v8/+/3565724. + +This patch can be removed when Node.js updates to V8 10.2.60 or higher, +which includes the above CL. + +The above CL removes prepended Function. and Object. from +stack traces, and so we need to remove them from the comparison output. + +diff --git a/test/message/async_error_nexttick_main.out b/test/message/async_error_nexttick_main.out +index 8d11dea63d4191d4e492d42cad499e9e6f277bd4..9669e9b5102ff9ce8dfffbc45dadc60dab578458 100644 +--- a/test/message/async_error_nexttick_main.out ++++ b/test/message/async_error_nexttick_main.out +@@ -1,7 +1,7 @@ + Error: test + at one (*fixtures*async-error.js:4:9) + at two (*fixtures*async-error.js:17:9) +- at processTicksAndRejections (node:internal/process/task_queues:*:*) ++ at process.processTicksAndRejections (node:internal/process/task_queues:*:*) + at async three (*fixtures*async-error.js:20:3) + at async four (*fixtures*async-error.js:24:3) + at async main (*message*async_error_nexttick_main.js:7:5) +diff --git a/test/message/core_line_numbers.out b/test/message/core_line_numbers.out +index 97b017f66e2395ca90fc7562b9043579911ddc62..1d21462c8cf63ddbbf9e3b785b553a3104710132 100644 +--- a/test/message/core_line_numbers.out ++++ b/test/message/core_line_numbers.out +@@ -7,8 +7,8 @@ RangeError: Invalid input + at Object.decode (node:punycode:*:*) + at Object. (*test*message*core_line_numbers.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* +diff --git a/test/message/error_aggregateTwoErrors.out b/test/message/error_aggregateTwoErrors.out +index d1dc13eacc303cc52003bd5820e7eeec8d48822b..eb85c92e63c850bbf8fbbe2c1600e783e0cd6066 100644 +--- a/test/message/error_aggregateTwoErrors.out ++++ b/test/message/error_aggregateTwoErrors.out +@@ -4,9 +4,9 @@ throw aggregateTwoErrors(err, originalError); + AggregateError: original + at Object. (*test*message*error_aggregateTwoErrors.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* { + code: 'ERR0' +diff --git a/test/message/error_exit.out b/test/message/error_exit.out +index 2ef95b535dafe7b0a918b8d6a844e4c4a617818d..dc5e6e7d28cef3a23ca7ba2cfb1435cad55e2aeb 100644 +--- a/test/message/error_exit.out ++++ b/test/message/error_exit.out +@@ -9,9 +9,9 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + at Object. (*test*message*error_exit.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* { + generatedMessage: true, +diff --git a/test/message/error_with_nul.out b/test/message/error_with_nul.out +index 7fbb33f08e8dc342b9efc899e66f5e3350e9489b..a359999420fa76bd09b401a732acb7dcdfaa2198 100644 +GIT binary patch +delta 13 +VcmdnUvXEuMi;3^+Czmts0st)*2A2Q; + +delta 31 +ncmZ3;vXN!N3wHmctkmQZy@@aCIo(S0l1no4^YkXCGwuQa$o~w9 + +diff --git a/test/message/events_unhandled_error_common_trace.out b/test/message/events_unhandled_error_common_trace.out +index 19e89869ba74fae3f447e299904939da5a683280..2bdbe3df1b4c7e13ba33f099ae89f88365e6b690 100644 +--- a/test/message/events_unhandled_error_common_trace.out ++++ b/test/message/events_unhandled_error_common_trace.out +@@ -7,9 +7,9 @@ Error: foo:bar + at foo (*events_unhandled_error_common_trace.js:*:*) + at Object. (*events_unhandled_error_common_trace.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* + Emitted 'error' event at: +diff --git a/test/message/events_unhandled_error_nexttick.out b/test/message/events_unhandled_error_nexttick.out +index 3e0d4697504e49eaae5ce1807a3794cccbcd6eec..87bb2fbb91a66e6dde9dfc61427682cba90f529c 100644 +--- a/test/message/events_unhandled_error_nexttick.out ++++ b/test/message/events_unhandled_error_nexttick.out +@@ -5,11 +5,11 @@ node:events:* + Error + at Object. (*events_unhandled_error_nexttick.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* + Emitted 'error' event at: + at *events_unhandled_error_nexttick.js:*:* +- at processTicksAndRejections (node:internal/process/task_queues:*:*) ++ at process.processTicksAndRejections (node:internal/process/task_queues:*:*) +diff --git a/test/message/events_unhandled_error_sameline.out b/test/message/events_unhandled_error_sameline.out +index c027275033941df96d6ab24c1647f110a0436d9a..872556a3b393e737adb4ed3b613f2c0cf20b1d2c 100644 +--- a/test/message/events_unhandled_error_sameline.out ++++ b/test/message/events_unhandled_error_sameline.out +@@ -5,9 +5,9 @@ node:events:* + Error + at Object. (*events_unhandled_error_sameline.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* + Emitted 'error' event at: +diff --git a/test/message/events_unhandled_error_subclass.out b/test/message/events_unhandled_error_subclass.out +index 5b8131970d50d50971184ccad0e2159c52fb0afd..073ab348a96f2e24efc2a661009287e4b7acda77 100644 +--- a/test/message/events_unhandled_error_subclass.out ++++ b/test/message/events_unhandled_error_subclass.out +@@ -5,9 +5,9 @@ node:events:* + Error + at Object. (*events_unhandled_error_subclass.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* + Emitted 'error' event on Foo instance at: +diff --git a/test/message/if-error-has-good-stack.out b/test/message/if-error-has-good-stack.out +index d87581cd7675346d51261efa4e0e28c57f9652eb..c5188137124d38f48989d6774a177795617b4974 100644 +--- a/test/message/if-error-has-good-stack.out ++++ b/test/message/if-error-has-good-stack.out +@@ -12,9 +12,9 @@ AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error + at a (*if-error-has-good-stack.js:*:*) + at Object. (*if-error-has-good-stack.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* { + generatedMessage: false, +@@ -25,9 +25,9 @@ AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error + at a (*if-error-has-good-stack.js:*:*) + at Object. (*if-error-has-good-stack.js:*:*) + at Module._compile (node:internal/modules/cjs/loader:*:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*:*) + at Module.load (node:internal/modules/cjs/loader:*:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) + at node:internal/main/run_main_module:*:* + expected: null, +diff --git a/test/message/nexttick_throw.out b/test/message/nexttick_throw.out +index 955bcda6a26da019c9954c80ef9db24ea3094bef..3180f9a7de5df66f30c9dcee697ddfbb97df3725 100644 +--- a/test/message/nexttick_throw.out ++++ b/test/message/nexttick_throw.out +@@ -4,4 +4,4 @@ + ^ + ReferenceError: undefined_reference_error_maker is not defined + at *test*message*nexttick_throw.js:*:* +- at processTicksAndRejections (node:internal/process/task_queues:*:*) ++ at process.processTicksAndRejections (node:internal/process/task_queues:*:*) +diff --git a/test/message/source_map_disabled_by_api.out b/test/message/source_map_disabled_by_api.out +index d2cca7da5297e3772ae1acf7b8901eada6c21112..bbe017b05a20edd736ea13e2b501f8d9fdc7d0e6 100644 +--- a/test/message/source_map_disabled_by_api.out ++++ b/test/message/source_map_disabled_by_api.out +@@ -5,9 +5,9 @@ Error: an error! + at functionA (*enclosing-call-site-min.js:1:26) + at Object. (*enclosing-call-site-min.js:1:199) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) + *enclosing-call-site.js:16 + throw new Error('an error!') +@@ -20,7 +20,7 @@ Error: an error! + at functionA (*enclosing-call-site.js:2:3) + at Object. (*enclosing-call-site.js:24:3) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) +diff --git a/test/message/source_map_enabled_by_api.out b/test/message/source_map_enabled_by_api.out +index 525ceccec12e4bdb8a08964ade461692ee99beca..e85ecee7f14a8ba1a599aeaf1d9f5f4855c42c5d 100644 +--- a/test/message/source_map_enabled_by_api.out ++++ b/test/message/source_map_enabled_by_api.out +@@ -9,9 +9,9 @@ Error: an error! + at functionA (*enclosing-call-site.js:2:3) + at Object. (*enclosing-call-site.js:24:3) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) + *enclosing-call-site-min.js:1 + var functionA=function(){functionB()};function functionB(){functionC()}var functionC=function(){functionD()},functionD=function(){if(0 (*enclosing-call-site-min.js:1:199) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) +diff --git a/test/message/source_map_enclosing_function.out b/test/message/source_map_enclosing_function.out +index 3eb76ecbbef31cd224e27001b825bce210f4e170..1babe95e398c61cdd3a4e1fd82fe418e4fbcd238 100644 +--- a/test/message/source_map_enclosing_function.out ++++ b/test/message/source_map_enclosing_function.out +@@ -9,7 +9,7 @@ Error: an error! + at functionA (*enclosing-call-site.js:2:3) + at Object. (*enclosing-call-site.js:24:3) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) +diff --git a/test/message/source_map_reference_error_tabs.out b/test/message/source_map_reference_error_tabs.out +index bce1b5f8911d4b34d3165d7a4bc5195cbe29211d..d56ef13b20bf9ca333e8806e3905059583c1f991 100644 +--- a/test/message/source_map_reference_error_tabs.out ++++ b/test/message/source_map_reference_error_tabs.out +@@ -6,9 +6,9 @@ ReferenceError: alert is not defined + at *tabs.coffee:26:2* + at *tabs.coffee:1:14* + at Module._compile (node:internal/modules/cjs/loader:* +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:* ++ at Module._extensions..js (node:internal/modules/cjs/loader:* + at Module.load (node:internal/modules/cjs/loader:* +- at Function.Module._load (node:internal/modules/cjs/loader:* ++ at Module._load (node:internal/modules/cjs/loader:* + at Module.require (node:internal/modules/cjs/loader:* + at require (node:internal/modules/cjs/helpers:* + at Object. (*source_map_reference_error_tabs.js:* +diff --git a/test/message/source_map_throw_catch.out b/test/message/source_map_throw_catch.out +index 95bba5eee3e9dc6415ab44b7c842fc05b5d5dec2..9a98aa59e767592c04153c2a6d349710d7f28a2e 100644 +--- a/test/message/source_map_throw_catch.out ++++ b/test/message/source_map_throw_catch.out +@@ -6,9 +6,9 @@ Error: an exception + at *typescript-throw.ts:18:11* + at *typescript-throw.ts:24:1* + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) + at require (node:internal/modules/cjs/helpers:*) + at Object. (*source_map_throw_catch.js:6:3) +diff --git a/test/message/source_map_throw_first_tick.out b/test/message/source_map_throw_first_tick.out +index efa97a1d9f56ddbaf87422fa14d1f14f07a33061..1d76129d0c3506824d22be17711b1351285af937 100644 +--- a/test/message/source_map_throw_first_tick.out ++++ b/test/message/source_map_throw_first_tick.out +@@ -6,9 +6,9 @@ Error: an exception + at *typescript-throw.ts:18:11* + at *typescript-throw.ts:24:1* + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) + at require (node:internal/modules/cjs/helpers:*) + at Object. (*source_map_throw_first_tick.js:5:1) +diff --git a/test/message/source_map_throw_icu.out b/test/message/source_map_throw_icu.out +index 78482d73ddf0376de2443321c426fc6c84a1c29a..c5f699f80a9be862772ae5af8884d85bec72ebe3 100644 +--- a/test/message/source_map_throw_icu.out ++++ b/test/message/source_map_throw_icu.out +@@ -6,9 +6,9 @@ Error: an error + at *icu.jsx:3:23* + at *icu.jsx:9:5* + at Module._compile (node:internal/modules/cjs/loader:* +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:* ++ at Module._extensions..js (node:internal/modules/cjs/loader:* + at Module.load (node:internal/modules/cjs/loader:* +- at Function.Module._load (node:internal/modules/cjs/loader:* ++ at Module._load (node:internal/modules/cjs/loader:* + at Module.require (node:internal/modules/cjs/loader:* + at require (node:internal/modules/cjs/helpers:* + at Object. (*source_map_throw_icu.js:* +diff --git a/test/message/source_map_throw_set_immediate.out b/test/message/source_map_throw_set_immediate.out +index c735e23cb955c5cb733ae766bd019848764b7ff1..21349d4c4598c0abac50b2b90e3bbf9b439257f5 100644 +--- a/test/message/source_map_throw_set_immediate.out ++++ b/test/message/source_map_throw_set_immediate.out +@@ -5,4 +5,4 @@ + Error: goodbye + at Hello *uglify-throw-original.js:5:9* + at *uglify-throw-original.js:9:3* +- at processImmediate (node:internal/timers:*) ++ at process.processImmediate (node:internal/timers:*) +diff --git a/test/message/timeout_throw.out b/test/message/timeout_throw.out +index 66e495eb84d0bda0c3f6b5f085aa2061f0e1b59a..968a5e4e4117713e4bf347e56ff84001ec86bb31 100644 +--- a/test/message/timeout_throw.out ++++ b/test/message/timeout_throw.out +@@ -4,4 +4,4 @@ + ReferenceError: undefined_reference_error_maker is not defined + at Timeout._onTimeout (*test*message*timeout_throw.js:*:*) + at listOnTimeout (node:internal/timers:*:*) +- at processTimers (node:internal/timers:*:*) ++ at process.processTimers (node:internal/timers:*:*) +diff --git a/test/message/undefined_reference_in_new_context.out b/test/message/undefined_reference_in_new_context.out +index 61dee9f6d4fba3696b91333c5fbdc20cf8e819fe..b06dc02a4861bd0eae89c682db0dce426b7409f3 100644 +--- a/test/message/undefined_reference_in_new_context.out ++++ b/test/message/undefined_reference_in_new_context.out +@@ -12,5 +12,5 @@ ReferenceError: foo is not defined + at Module._compile (node:internal/modules/cjs/loader:*) + at *..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*:*) ++ at Module._load (node:internal/modules/cjs/loader:*:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*:*) +diff --git a/test/message/vm_display_runtime_error.out b/test/message/vm_display_runtime_error.out +index 8f1e9c37967f253071ad20c5a4f2b81f7b65b8cc..d7a39915f999101d4f2bfcc5f7bc9ba77eab8f0d 100644 +--- a/test/message/vm_display_runtime_error.out ++++ b/test/message/vm_display_runtime_error.out +@@ -9,9 +9,9 @@ Error: boo! + at Object.runInThisContext (node:vm:*) + at Object. (*test*message*vm_display_runtime_error.js:*) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*) + at node:internal/main/run_main_module:*:* + test.vm:1 +@@ -24,8 +24,8 @@ Error: spooky! + at Object.runInThisContext (node:vm:*) + at Object. (*test*message*vm_display_runtime_error.js:*) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*) + at node:internal/main/run_main_module:*:* +diff --git a/test/message/vm_display_syntax_error.out b/test/message/vm_display_syntax_error.out +index b0b70fcd75966825e0ff1893ff984a3e20edc926..ce82fb366e0375eeea8ced2320a3662584411160 100644 +--- a/test/message/vm_display_syntax_error.out ++++ b/test/message/vm_display_syntax_error.out +@@ -8,9 +8,9 @@ SyntaxError: Unexpected number + at Object.runInThisContext (node:vm:*) + at Object. (*test*message*vm_display_syntax_error.js:*) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*) + at node:internal/main/run_main_module:*:* + test.vm:1 +@@ -22,8 +22,8 @@ SyntaxError: Unexpected number + at Object.runInThisContext (node:vm:*) + at Object. (*test*message*vm_display_syntax_error.js:*) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*) + at node:internal/main/run_main_module:*:* +diff --git a/test/message/vm_dont_display_runtime_error.out b/test/message/vm_dont_display_runtime_error.out +index 2ff2e8355ab90c8d9d00aaa6bf743c4f3b7d0de0..72ef73d628e10f600e5e3e90691587f2f63b1a69 100644 +--- a/test/message/vm_dont_display_runtime_error.out ++++ b/test/message/vm_dont_display_runtime_error.out +@@ -10,8 +10,8 @@ Error: boo! + at Object.runInThisContext (node:vm:*) + at Object. (*test*message*vm_dont_display_runtime_error.js:*) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*) + at node:internal/main/run_main_module:*:* +diff --git a/test/message/vm_dont_display_syntax_error.out b/test/message/vm_dont_display_syntax_error.out +index d46dce2993f863622d2764d816adda548e568121..2ce14fe4013df2aa37c0339880294ba804c4f0c3 100644 +--- a/test/message/vm_dont_display_syntax_error.out ++++ b/test/message/vm_dont_display_syntax_error.out +@@ -10,8 +10,8 @@ SyntaxError: Unexpected number + at Object.runInThisContext (node:vm:*) + at Object. (*test*message*vm_dont_display_syntax_error.js:*) + at Module._compile (node:internal/modules/cjs/loader:*) +- at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) ++ at Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) +- at Function.Module._load (node:internal/modules/cjs/loader:*) ++ at Module._load (node:internal/modules/cjs/loader:*) + at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:*) + at node:internal/main/run_main_module:*:* diff --git a/patches/node/fix_suppress_clang_-wdeprecated-declarations_in_libuv.patch b/patches/node/fix_suppress_clang_-wdeprecated-declarations_in_libuv.patch index 1613f28863fd0..a6ae0650793b4 100644 --- a/patches/node/fix_suppress_clang_-wdeprecated-declarations_in_libuv.patch +++ b/patches/node/fix_suppress_clang_-wdeprecated-declarations_in_libuv.patch @@ -6,10 +6,10 @@ Subject: fix: suppress clang -Wdeprecated-declarations in libuv Should be upstreamed. diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c -index 5ffde08e1aed041c4da679156ed10f7e54bfc386..69aff95f68519acc8fc399c4358702b146f802ca 100644 +index 37ece5e2867ab836492a8b7faa0aa5e1b8e562f0..d50296728f7e0810064647125a469f3ed714f8ea 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c -@@ -1949,10 +1949,17 @@ int uv_os_uname(uv_utsname_t* buffer) { +@@ -1950,10 +1950,17 @@ int uv_os_uname(uv_utsname_t* buffer) { #ifdef _MSC_VER #pragma warning(suppress : 4996) #endif diff --git a/patches/node/json_parse_errors_made_user-friendly.patch b/patches/node/json_parse_errors_made_user-friendly.patch new file mode 100644 index 0000000000000..5fe3fdf8ff49b --- /dev/null +++ b/patches/node/json_parse_errors_made_user-friendly.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: John Kleinschmidt +Date: Thu, 26 May 2022 17:08:33 -0400 +Subject: JSON.parse errors made user-friendly + +Update tests for https://chromium-review.googlesource.com/c/v8/v8/+/3513684 + +diff --git a/test/es-module/test-esm-data-urls.js b/test/es-module/test-esm-data-urls.js +index 9d0deb70a1568c93ccdecbef59327ecb2a17ae5e..2ab8f2bdcf7cca1437df33668c4177a76b4dc3ca 100644 +--- a/test/es-module/test-esm-data-urls.js ++++ b/test/es-module/test-esm-data-urls.js +@@ -75,7 +75,7 @@ function createBase64URL(mime, body) { + import('data:application/json;foo="test,",0', + { assert: { type: 'json' } }), { + name: 'SyntaxError', +- message: /Unexpected end of JSON input/ ++ message: 'data:application/json;foo="test,",0: Unterminated string in JSON at position 3' + }); + } + { +diff --git a/test/es-module/test-esm-invalid-pjson.js b/test/es-module/test-esm-invalid-pjson.js +index cdbebb17b4bb34421a2f98c384650d495908885c..12247f15dbaddc0e06f1e6aff09faf7a035cf43a 100644 +--- a/test/es-module/test-esm-invalid-pjson.js ++++ b/test/es-module/test-esm-invalid-pjson.js +@@ -17,11 +17,13 @@ child.stderr.on('data', (data) => { + child.on('close', mustCall((code, signal) => { + strictEqual(code, 1); + strictEqual(signal, null); ++ console.log('STDERR is: ', stderr); ++ console.log('DONE STDERR'); + ok( + stderr.includes( + `[ERR_INVALID_PACKAGE_CONFIG]: Invalid package config ${invalidJson} ` + + `while importing "invalid-pjson" from ${entry}. ` + +- `Unexpected token } in JSON at position ${12 + checkoutEOL.length * 2}` ++ `Expected ':' after property name in JSON at position ${12 + checkoutEOL.length * 2}` + ), + stderr); + })); diff --git a/patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch b/patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch index 0666f61533a6b..f05f9ee5186e0 100644 --- a/patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch +++ b/patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch @@ -48,10 +48,10 @@ index c8816b85b7e531648064e739fb89257565ad64bb..de51bac3d0e8daf519d35c6a3994f147 if (path == NULL) path = _PATH_DEFPATH; diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h -index 58489c4be7b3a7b36d5b01a1f07d411ef3d99ae3..b4c039706417ab679c4f24a863118e736635371c 100644 +index 199402e31406cf8ba360d54769461bb5285011ee..f8c08a4a7eb164ffff495c81e1f5df712084648b 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h -@@ -319,6 +319,7 @@ TEST_DECLARE (spawn_inherit_streams) +@@ -322,6 +322,7 @@ TEST_DECLARE (spawn_inherit_streams) TEST_DECLARE (spawn_quoted_path) TEST_DECLARE (spawn_tcp_server) TEST_DECLARE (spawn_exercise_sigchld_issue) @@ -59,7 +59,7 @@ index 58489c4be7b3a7b36d5b01a1f07d411ef3d99ae3..b4c039706417ab679c4f24a863118e73 TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (fs_poll_close_request) -@@ -946,6 +947,7 @@ TASK_LIST_START +@@ -954,6 +955,7 @@ TASK_LIST_START TEST_ENTRY (spawn_quoted_path) TEST_ENTRY (spawn_tcp_server) TEST_ENTRY (spawn_exercise_sigchld_issue) diff --git a/patches/node/pass_all_globals_through_require.patch b/patches/node/pass_all_globals_through_require.patch index e0ef037d54b9e..63e91ad95678d 100644 --- a/patches/node/pass_all_globals_through_require.patch +++ b/patches/node/pass_all_globals_through_require.patch @@ -6,7 +6,7 @@ Subject: Pass all globals through "require" (cherry picked from commit 7d015419cb7a0ecfe6728431a4ed2056cd411d62) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js -index b8eff0440624a41d89a39c46303fa51d581bf4bf..67eb7717f13379312721fc4da2e760bc08d8ed3a 100644 +index b4902850c7fec5bb67c9566f40ca1cdd2ba17b55..200c352cfd7321c47f37776589cfca397cad5d25 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -127,6 +127,13 @@ const { @@ -23,7 +23,7 @@ index b8eff0440624a41d89a39c46303fa51d581bf4bf..67eb7717f13379312721fc4da2e760bc const { isProxy } = require('internal/util/types'); -@@ -1096,10 +1103,12 @@ Module.prototype._compile = function(content, filename) { +@@ -1100,10 +1107,12 @@ Module.prototype._compile = function(content, filename) { if (requireDepth === 0) statCache = new SafeMap(); if (inspectorWrapper) { result = inspectorWrapper(compiledWrapper, thisValue, exports, diff --git a/patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch b/patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch index c0ab59bbeab92..b8b4e9ef2541c 100644 --- a/patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch +++ b/patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch @@ -25,7 +25,7 @@ index 16be13b99f5db77741aa276e90a437ef4eb5ba32..2dcc8b32f5165dd75061a1b55cc1abd2 /* flags of excluding ifaddr */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c -index 35200f17495d80ed2d19ef9f6f76bbc92ee042f6..071fe0ce0938657d0fb840af62a432352e938a8a 100644 +index efbc561dee2574f06ebd9408d1e89e435c93cc5a..857eb1d54bfde99754ce2c6e92a287c288bd9f52 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -285,7 +285,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { @@ -37,7 +37,7 @@ index 35200f17495d80ed2d19ef9f6f76bbc92ee042f6..071fe0ce0938657d0fb840af62a43235 nevents++; continue; } -@@ -383,6 +383,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { +@@ -382,6 +382,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nevents++; } diff --git a/patches/node/process_fix_hang_after_note_exit_3521.patch b/patches/node/process_fix_hang_after_note_exit_3521.patch index 68702cf332b81..768eda13452b3 100644 --- a/patches/node/process_fix_hang_after_note_exit_3521.patch +++ b/patches/node/process_fix_hang_after_note_exit_3521.patch @@ -10,7 +10,7 @@ track exactly which processes have exited. Should also be a slight speed improvement for excessively large numbers of live children. diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c -index 071fe0ce0938657d0fb840af62a432352e938a8a..4c4d990ff5fa6c8ab937be2e4f79ccdaf90670c2 100644 +index 857eb1d54bfde99754ce2c6e92a287c288bd9f52..036055149fcabcb9ff8f43522120c82b3474ab99 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -117,6 +117,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { diff --git a/patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch b/patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch index 917b589dbd37b..38609025d0f79 100644 --- a/patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch +++ b/patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch @@ -23,7 +23,7 @@ index 12d4da93686e993830a7d09e74d08191fc808f4f..16be13b99f5db77741aa276e90a437ef /* random */ int uv__random_devurandom(void* buf, size_t buflen); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c -index bf183d5fdc0ba89913469a294322eef84bc4cee8..35200f17495d80ed2d19ef9f6f76bbc92ee042f6 100644 +index 75e9110709da8d30628449311cb916a26c775ecf..efbc561dee2574f06ebd9408d1e89e435c93cc5a 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -284,6 +284,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { @@ -39,10 +39,10 @@ index bf183d5fdc0ba89913469a294322eef84bc4cee8..35200f17495d80ed2d19ef9f6f76bbc9 /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index f4aebb0490e198cd9adcadfeb6b006de479cc993..cfcba341e0e380ecd595e4b59e39c08a7b374a48 100644 +index 91bf3c507022b2eddc0d36f40d73a977bf731fbc..c1f6bd4b0076f0835caf83c45a6a896e7ae5def9 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c -@@ -48,10 +48,20 @@ extern char **environ; +@@ -49,10 +49,20 @@ extern char **environ; # include "zos-base.h" #endif @@ -64,7 +64,7 @@ index f4aebb0490e198cd9adcadfeb6b006de479cc993..cfcba341e0e380ecd595e4b59e39c08a int exit_status; int term_signal; int status; -@@ -60,10 +70,7 @@ static void uv__chld(uv_signal_t* handle, int signum) { +@@ -61,10 +71,7 @@ static void uv__chld(uv_signal_t* handle, int signum) { QUEUE* q; QUEUE* h; @@ -75,7 +75,7 @@ index f4aebb0490e198cd9adcadfeb6b006de479cc993..cfcba341e0e380ecd595e4b59e39c08a h = &loop->process_handles; q = QUEUE_HEAD(h); -@@ -419,7 +426,9 @@ int uv_spawn(uv_loop_t* loop, +@@ -420,7 +427,9 @@ int uv_spawn(uv_loop_t* loop, if (err) goto error; @@ -85,7 +85,7 @@ index f4aebb0490e198cd9adcadfeb6b006de479cc993..cfcba341e0e380ecd595e4b59e39c08a /* Acquire write lock to prevent opening new fds in worker threads */ uv_rwlock_wrlock(&loop->cloexec_lock); -@@ -478,6 +487,13 @@ int uv_spawn(uv_loop_t* loop, +@@ -495,6 +504,13 @@ int uv_spawn(uv_loop_t* loop, /* Only activate this handle if exec() happened successfully */ if (exec_errorno == 0) { @@ -100,10 +100,10 @@ index f4aebb0490e198cd9adcadfeb6b006de479cc993..cfcba341e0e380ecd595e4b59e39c08a uv__handle_start(process); } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h -index 59b95da9ebe3464bd1f9ce1c534122b1f9e06636..58489c4be7b3a7b36d5b01a1f07d411ef3d99ae3 100644 +index 1f566861a0e2e9e29c925972155f49667bb7ce85..a43edf1a4a9b0932ec73b8edaca0f676ecf3ccfa 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h -@@ -318,6 +318,7 @@ TEST_DECLARE (spawn_reads_child_path) +@@ -320,6 +320,7 @@ TEST_DECLARE (spawn_reads_child_path) TEST_DECLARE (spawn_inherit_streams) TEST_DECLARE (spawn_quoted_path) TEST_DECLARE (spawn_tcp_server) @@ -111,7 +111,7 @@ index 59b95da9ebe3464bd1f9ce1c534122b1f9e06636..58489c4be7b3a7b36d5b01a1f07d411e TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (fs_poll_close_request) -@@ -944,6 +945,7 @@ TASK_LIST_START +@@ -950,6 +951,7 @@ TASK_LIST_START TEST_ENTRY (spawn_inherit_streams) TEST_ENTRY (spawn_quoted_path) TEST_ENTRY (spawn_tcp_server) diff --git a/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch b/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch index 1eccad9b31b62..c6ffa555f14c1 100644 --- a/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch +++ b/patches/node/refactor_allow_embedder_overriding_of_internal_fs_calls.patch @@ -7,10 +7,10 @@ We use this to allow node's 'fs' module to read from ASAR files as if they were a real filesystem. diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js -index 58f7396990dddb7dd4cf3d23fcdcc1d48f52623e..ef06d0563fa7452348754418867a56c9b8c6f4e1 100644 +index dfae7675e16a6a81e40c69d85004fc841cadf738..8c31d0202b70ec9784b4289a175a62fd9fd85f8c 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js -@@ -62,6 +62,10 @@ setupBuffer(); +@@ -66,6 +66,10 @@ setupBuffer(); process.domain = null; process._exiting = false; @@ -22,7 +22,7 @@ index 58f7396990dddb7dd4cf3d23fcdcc1d48f52623e..ef06d0563fa7452348754418867a56c9 const nativeModule = internalBinding('native_module'); diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js -index 67eb7717f13379312721fc4da2e760bc08d8ed3a..05a62bb3c3852536001912cb0b69fe5578ace125 100644 +index 200c352cfd7321c47f37776589cfca397cad5d25..5195ff2da0496f2bfb9112d336c38040f662087b 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -86,7 +86,7 @@ const fs = require('fs'); diff --git a/patches/node/refactor_alter_child_process_fork_to_use_execute_script_with.patch b/patches/node/refactor_alter_child_process_fork_to_use_execute_script_with.patch index 686eb257df509..5157829f69aa6 100644 --- a/patches/node/refactor_alter_child_process_fork_to_use_execute_script_with.patch +++ b/patches/node/refactor_alter_child_process_fork_to_use_execute_script_with.patch @@ -7,10 +7,10 @@ Subject: refactor: alter child_process.fork to use execute script with When forking a child script, we setup a special environment to make the Electron binary run like the upstream node. On Mac, we use the helper app as node binary. diff --git a/lib/child_process.js b/lib/child_process.js -index 62c552d567eaad07ffe65ea5cb24be101b57ebdd..73c11500d7e4a540f26cc7ee3b692a2f4b158b19 100644 +index 415010241cdabac42ea79601c464bae4a2081c78..5c202237ecdf32afe89b5a5b4dfc2cf648fb9d23 100644 --- a/lib/child_process.js +++ b/lib/child_process.js -@@ -161,6 +161,15 @@ function fork(modulePath /* , args, options */) { +@@ -160,6 +160,15 @@ function fork(modulePath, args = [], options) { throw new ERR_CHILD_PROCESS_IPC_REQUIRED('options.stdio'); } diff --git a/patches/node/repl_fix_crash_when_sharedarraybuffer_disabled.patch b/patches/node/repl_fix_crash_when_sharedarraybuffer_disabled.patch index fe3a805081ff7..dae469157d32e 100644 --- a/patches/node/repl_fix_crash_when_sharedarraybuffer_disabled.patch +++ b/patches/node/repl_fix_crash_when_sharedarraybuffer_disabled.patch @@ -25,7 +25,7 @@ index a771b1813731edf4f0dd60f3505799e389f1d876..b9461677e2d7d1df192e752496e62cca bench.start(); for (let i = 0; i < n; i++) diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js -index 71a07a63a3636ab211746004ebab24a0058b08fc..e3ce67987ee3185a93750ebad72beab304c71e3a 100644 +index a8167b86ca2e5a11b2628e20063849e85a200a8c..110a3ed1637b642b1d83fb36549cced151b9c5cd 100644 --- a/lib/internal/main/worker_thread.js +++ b/lib/internal/main/worker_thread.js @@ -9,7 +9,7 @@ const { @@ -37,7 +37,7 @@ index 71a07a63a3636ab211746004ebab24a0058b08fc..e3ce67987ee3185a93750ebad72beab3 } = primordials; const { -@@ -142,6 +142,9 @@ port.on('message', (message) => { +@@ -146,6 +146,9 @@ port.on('message', (message) => { const originalCwd = process.cwd; process.cwd = function() { diff --git a/patches/node/src_allow_embedders_to_provide_a_custom_pageallocator_to.patch b/patches/node/src_allow_embedders_to_provide_a_custom_pageallocator_to.patch index 455cc74afe3e6..81619a8926da2 100644 --- a/patches/node/src_allow_embedders_to_provide_a_custom_pageallocator_to.patch +++ b/patches/node/src_allow_embedders_to_provide_a_custom_pageallocator_to.patch @@ -12,7 +12,7 @@ allocator that does handle these cases. Upstreamed in https://github.com/nodejs/node/pull/38362. diff --git a/src/api/environment.cc b/src/api/environment.cc -index 5bf19a0dda42849159d954181058897c45d280fd..03078ff3869fcd17101f1cdaf77f725dbbfa43e8 100644 +index 1add2976e7c48e6704400b9ea0795b934ab0bfc2..2abf5994405e8da2a04d1b23b75ccd3658398474 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -475,8 +475,9 @@ MultiIsolatePlatform* CreatePlatform( @@ -40,10 +40,10 @@ index 5bf19a0dda42849159d954181058897c45d280fd..03078ff3869fcd17101f1cdaf77f725d MaybeLocal GetPerContextExports(Local context) { diff --git a/src/node.h b/src/node.h -index 85b5ac6a5a5cb5e4388a92a1d07c9afe17140a8c..4201c0d0460b032721ef42a26d79c38a9ee20c24 100644 +index 9b9ff1c86ceeaeca828328065e2ad5573ea17fc5..0a9f5139276eb2e102b41a586adf61fa563b47d6 100644 --- a/src/node.h +++ b/src/node.h -@@ -313,7 +313,8 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform { +@@ -332,7 +332,8 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform { static std::unique_ptr Create( int thread_pool_size, @@ -53,7 +53,7 @@ index 85b5ac6a5a5cb5e4388a92a1d07c9afe17140a8c..4201c0d0460b032721ef42a26d79c38a }; enum IsolateSettingsFlags { -@@ -509,7 +510,8 @@ NODE_EXTERN node::tracing::Agent* CreateAgent(); +@@ -529,7 +530,8 @@ NODE_EXTERN node::tracing::Agent* CreateAgent(); NODE_DEPRECATED("Use MultiIsolatePlatform::Create() instead", NODE_EXTERN MultiIsolatePlatform* CreatePlatform( int thread_pool_size, diff --git a/patches/node/src_update_importmoduledynamically.patch b/patches/node/src_update_importmoduledynamically.patch new file mode 100644 index 0000000000000..9f657d234096e --- /dev/null +++ b/patches/node/src_update_importmoduledynamically.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Camillo Bruni +Date: Mon, 15 Nov 2021 15:34:38 +0100 +Subject: src: update ImportModuleDynamically + +PR-URL: https://github.com/nodejs/node/pull/41610 +Reviewed-By: Jiawen Geng +Reviewed-By: Antoine du Hamel +Reviewed-By: Darshan Sen +Reviewed-By: Colin Ihrig + +diff --git a/src/module_wrap.cc b/src/module_wrap.cc +index aeb0d2cb37313bdbb00abe065c91362cac5dcb9a..1e049d7258d21c7d7049f393ecfa1b4f53325910 100644 +--- a/src/module_wrap.cc ++++ b/src/module_wrap.cc +@@ -46,7 +46,6 @@ using v8::PrimitiveArray; + using v8::Promise; + using v8::ScriptCompiler; + using v8::ScriptOrigin; +-using v8::ScriptOrModule; + using v8::String; + using v8::UnboundModuleScript; + using v8::Undefined; +@@ -559,7 +558,8 @@ MaybeLocal ModuleWrap::ResolveModuleCallback( + + static MaybeLocal ImportModuleDynamically( + Local context, +- Local referrer, ++ Local host_defined_options, ++ Local resource_name, + Local specifier, + Local import_assertions) { + Isolate* isolate = context->GetIsolate(); +@@ -574,7 +574,7 @@ static MaybeLocal ImportModuleDynamically( + Local import_callback = + env->host_import_module_dynamically_callback(); + +- Local options = referrer->GetHostDefinedOptions(); ++ Local options = host_defined_options.As(); + if (options->Length() != HostDefinedOptions::kLength) { + Local resolver; + if (!Promise::Resolver::New(context).ToLocal(&resolver)) return {}; +@@ -588,11 +588,11 @@ static MaybeLocal ImportModuleDynamically( + + Local object; + +- int type = options->Get(isolate, HostDefinedOptions::kType) ++ int type = options->Get(context, HostDefinedOptions::kType) + .As() + ->Int32Value(context) + .ToChecked(); +- uint32_t id = options->Get(isolate, HostDefinedOptions::kID) ++ uint32_t id = options->Get(context, HostDefinedOptions::kID) + .As() + ->Uint32Value(context) + .ToChecked(); diff --git a/patches/node/support_v8_sandboxed_pointers.patch b/patches/node/support_v8_sandboxed_pointers.patch new file mode 100644 index 0000000000000..76c60ed36b339 --- /dev/null +++ b/patches/node/support_v8_sandboxed_pointers.patch @@ -0,0 +1,273 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Rose +Date: Tue, 21 Jun 2022 10:04:21 -0700 +Subject: support V8 sandboxed pointers + +This refactors several allocators to allocate within the V8 memory cage, +allowing them to be compatible with the V8_SANDBOXED_POINTERS feature. + +diff --git a/src/api/environment.cc b/src/api/environment.cc +index 2abf5994405e8da2a04d1b23b75ccd3658398474..b06e8529bb8ca2fa6d7f0735531bbbf39da6af12 100644 +--- a/src/api/environment.cc ++++ b/src/api/environment.cc +@@ -80,19 +80,27 @@ MaybeLocal PrepareStackTraceCallback(Local context, + return result; + } + ++NodeArrayBufferAllocator::NodeArrayBufferAllocator() { ++ zero_fill_field_ = static_cast(allocator_->Allocate(sizeof(*zero_fill_field_))); ++} ++ ++NodeArrayBufferAllocator::~NodeArrayBufferAllocator() { ++ allocator_->Free(zero_fill_field_, sizeof(*zero_fill_field_)); ++} ++ + void* NodeArrayBufferAllocator::Allocate(size_t size) { + void* ret; +- if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers) +- ret = UncheckedCalloc(size); ++ if (*zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers) ++ ret = allocator_->Allocate(size); + else +- ret = UncheckedMalloc(size); ++ ret = allocator_->AllocateUninitialized(size); + if (LIKELY(ret != nullptr)) + total_mem_usage_.fetch_add(size, std::memory_order_relaxed); + return ret; + } + + void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) { +- void* ret = node::UncheckedMalloc(size); ++ void* ret = allocator_->AllocateUninitialized(size); + if (LIKELY(ret != nullptr)) + total_mem_usage_.fetch_add(size, std::memory_order_relaxed); + return ret; +@@ -100,7 +108,7 @@ void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) { + + void* NodeArrayBufferAllocator::Reallocate( + void* data, size_t old_size, size_t size) { +- void* ret = UncheckedRealloc(static_cast(data), size); ++ void* ret = allocator_->Reallocate(data, old_size, size); + if (LIKELY(ret != nullptr) || UNLIKELY(size == 0)) + total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed); + return ret; +@@ -108,7 +116,7 @@ void* NodeArrayBufferAllocator::Reallocate( + + void NodeArrayBufferAllocator::Free(void* data, size_t size) { + total_mem_usage_.fetch_sub(size, std::memory_order_relaxed); +- free(data); ++ allocator_->Free(data, size); + } + + DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() { +diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc +index f55e292fbbc75448b15dc9be0327ad2dedef49e0..7719574859637aecc98f8a4b00ba6ebca8280631 100644 +--- a/src/crypto/crypto_util.cc ++++ b/src/crypto/crypto_util.cc +@@ -318,10 +318,35 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept { + return *this; + } + +-std::unique_ptr ByteSource::ReleaseToBackingStore() { ++std::unique_ptr ByteSource::ReleaseToBackingStore(Environment* env) { + // It's ok for allocated_data_ to be nullptr but + // only if size_ is zero. + CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr); ++#if defined(V8_SANDBOXED_POINTERS) ++ // When V8 sandboxed pointers are enabled, we have to copy into the memory ++ // cage. We still want to ensure we erase the data on free though, so ++ // provide a custom deleter that calls OPENSSL_cleanse. ++ if (!size()) ++ return ArrayBuffer::NewBackingStore(env->isolate(), 0); ++ std::unique_ptr allocator(ArrayBuffer::Allocator::NewDefaultAllocator()); ++ void* v8_data = allocator->Allocate(size()); ++ CHECK(v8_data); ++ memcpy(v8_data, allocated_data_, size()); ++ OPENSSL_clear_free(allocated_data_, size()); ++ std::unique_ptr ptr = ArrayBuffer::NewBackingStore( ++ v8_data, ++ size(), ++ [](void* data, size_t length, void*) { ++ OPENSSL_cleanse(data, length); ++ std::unique_ptr allocator(ArrayBuffer::Allocator::NewDefaultAllocator()); ++ allocator->Free(data, length); ++ }, nullptr); ++ CHECK(ptr); ++ allocated_data_ = nullptr; ++ data_ = nullptr; ++ size_ = 0; ++ return ptr; ++#else + std::unique_ptr ptr = ArrayBuffer::NewBackingStore( + allocated_data_, + size(), +@@ -333,10 +358,11 @@ std::unique_ptr ByteSource::ReleaseToBackingStore() { + data_ = nullptr; + size_ = 0; + return ptr; ++#endif // defined(V8_SANDBOXED_POINTERS) + } + + Local ByteSource::ToArrayBuffer(Environment* env) { +- std::unique_ptr store = ReleaseToBackingStore(); ++ std::unique_ptr store = ReleaseToBackingStore(env); + return ArrayBuffer::New(env->isolate(), std::move(store)); + } + +@@ -666,6 +692,16 @@ CryptoJobMode GetCryptoJobMode(v8::Local args) { + } + + namespace { ++#if defined(V8_SANDBOXED_POINTERS) ++// When V8 sandboxed pointers are enabled, the secure heap cannot be used as ++// all ArrayBuffers must be allocated inside the V8 memory cage. ++void SecureBuffer(const FunctionCallbackInfo& args) { ++ CHECK(args[0]->IsUint32()); ++ uint32_t len = args[0].As()->Value(); ++ Local buffer = ArrayBuffer::New(args.GetIsolate(), len); ++ args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); ++} ++#else + // SecureBuffer uses openssl to allocate a Uint8Array using + // OPENSSL_secure_malloc. Because we do not yet actually + // make use of secure heap, this has the same semantics as +@@ -693,6 +729,7 @@ void SecureBuffer(const FunctionCallbackInfo& args) { + Local buffer = ArrayBuffer::New(env->isolate(), store); + args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); + } ++#endif // defined(V8_SANDBOXED_POINTERS) + + void SecureHeapUsed(const FunctionCallbackInfo& args) { + #ifndef OPENSSL_IS_BORINGSSL +diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h +index c431159e6f77f8c86844bcadb86012b056d03372..9f57ac58d826cb0aae422ddca54e2136618c4bfe 100644 +--- a/src/crypto/crypto_util.h ++++ b/src/crypto/crypto_util.h +@@ -255,7 +255,7 @@ class ByteSource { + // Creates a v8::BackingStore that takes over responsibility for + // any allocated data. The ByteSource will be reset with size = 0 + // after being called. +- std::unique_ptr ReleaseToBackingStore(); ++ std::unique_ptr ReleaseToBackingStore(Environment* env); + + v8::Local ToArrayBuffer(Environment* env); + +diff --git a/src/node_i18n.cc b/src/node_i18n.cc +index c537a247f55ff070da1988fc8b7309b5692b5c18..59bfb597849cd5a94800d6c83b238ef77245243e 100644 +--- a/src/node_i18n.cc ++++ b/src/node_i18n.cc +@@ -104,7 +104,7 @@ namespace { + + template + MaybeLocal ToBufferEndian(Environment* env, MaybeStackBuffer* buf) { +- MaybeLocal ret = Buffer::New(env, buf); ++ MaybeLocal ret = Buffer::Copy(env, reinterpret_cast(buf->out()), buf->length() * sizeof(T)); + if (ret.IsEmpty()) + return ret; + +diff --git a/src/node_internals.h b/src/node_internals.h +index d37be23cd63e82d4040777bd0e17ed449ec0b15b..eb84760593ff5fb5aa6a8104e8714099f24a67a0 100644 +--- a/src/node_internals.h ++++ b/src/node_internals.h +@@ -97,7 +97,9 @@ bool InitializePrimordials(v8::Local context); + + class NodeArrayBufferAllocator : public ArrayBufferAllocator { + public: +- inline uint32_t* zero_fill_field() { return &zero_fill_field_; } ++ NodeArrayBufferAllocator(); ++ ~NodeArrayBufferAllocator() override; ++ inline uint32_t* zero_fill_field() { return zero_fill_field_; } + + void* Allocate(size_t size) override; // Defined in src/node.cc + void* AllocateUninitialized(size_t size) override; +@@ -116,8 +118,10 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator { + } + + private: +- uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land. ++ uint32_t* zero_fill_field_ = nullptr; // Boolean but exposed as uint32 to JS land. + std::atomic total_mem_usage_ {0}; ++ ++ std::unique_ptr allocator_{v8::ArrayBuffer::Allocator::NewDefaultAllocator()}; + }; + + class DebuggingArrayBufferAllocator final : public NodeArrayBufferAllocator { +diff --git a/src/node_serdes.cc b/src/node_serdes.cc +index f6f0034bc24d09e3ad65491c7d6be0b9c9db1581..92d5020f293c98c81d3891a82f7320629bf9f926 100644 +--- a/src/node_serdes.cc ++++ b/src/node_serdes.cc +@@ -29,6 +29,11 @@ using v8::ValueSerializer; + + namespace serdes { + ++v8::ArrayBuffer::Allocator* GetAllocator() { ++ static v8::ArrayBuffer::Allocator* allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); ++ return allocator; ++}; ++ + class SerializerContext : public BaseObject, + public ValueSerializer::Delegate { + public: +@@ -37,10 +42,15 @@ class SerializerContext : public BaseObject, + + ~SerializerContext() override = default; + ++ // v8::ValueSerializer::Delegate + void ThrowDataCloneError(Local message) override; + Maybe WriteHostObject(Isolate* isolate, Local object) override; + Maybe GetSharedArrayBufferId( + Isolate* isolate, Local shared_array_buffer) override; ++ void* ReallocateBufferMemory(void* old_buffer, ++ size_t old_length, ++ size_t* new_length) override; ++ void FreeBufferMemory(void* buffer) override; + + static void SetTreatArrayBufferViewsAsHostObjects( + const FunctionCallbackInfo& args); +@@ -61,6 +71,7 @@ class SerializerContext : public BaseObject, + + private: + ValueSerializer serializer_; ++ size_t last_length_ = 0; + }; + + class DeserializerContext : public BaseObject, +@@ -144,6 +155,24 @@ Maybe SerializerContext::GetSharedArrayBufferId( + return id.ToLocalChecked()->Uint32Value(env()->context()); + } + ++void* SerializerContext::ReallocateBufferMemory(void* old_buffer, ++ size_t requested_size, ++ size_t* new_length) { ++ *new_length = std::max(static_cast(4096), requested_size); ++ if (old_buffer) { ++ void* ret = GetAllocator()->Reallocate(old_buffer, last_length_, *new_length); ++ last_length_ = *new_length; ++ return ret; ++ } else { ++ last_length_ = *new_length; ++ return GetAllocator()->Allocate(*new_length); ++ } ++} ++ ++void SerializerContext::FreeBufferMemory(void* buffer) { ++ GetAllocator()->Free(buffer, last_length_); ++} ++ + Maybe SerializerContext::WriteHostObject(Isolate* isolate, + Local input) { + MaybeLocal ret; +@@ -211,7 +240,12 @@ void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo& args) { + std::pair ret = ctx->serializer_.Release(); + auto buf = Buffer::New(ctx->env(), + reinterpret_cast(ret.first), +- ret.second); ++ ret.second, ++ [](char* data, void* hint){ ++ if (data) ++ GetAllocator()->Free(data, reinterpret_cast(hint)); ++ }, ++ reinterpret_cast(ctx->last_length_)); + + if (!buf.IsEmpty()) { + args.GetReturnValue().Set(buf.ToLocalChecked()); diff --git a/patches/node/test_add_fixture_trim_option.patch b/patches/node/test_add_fixture_trim_option.patch deleted file mode 100644 index 8a20a9354c089..0000000000000 --- a/patches/node/test_add_fixture_trim_option.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shelley Vohr -Date: Mon, 8 Nov 2021 15:52:17 +0100 -Subject: test: add fixture trim option - -Fixes a spec failure originating with a strict requirement in BoringSSL -that base64 strings be evenly divisible by 4 in their implementation of -`NETSCAPE_SPKI_b64_decode`. - -Fixes that issue by trimming the newlines out of the file. - -Upstreamed at https://github.com/nodejs/node/pull/40757. - -diff --git a/test/common/fixtures.js b/test/common/fixtures.js -index e5e1d887df525e493989a4aa8df6952a0e5b6c47..2da8aeb6a694e4b45d76bc3908284783d83f6755 100644 ---- a/test/common/fixtures.js -+++ b/test/common/fixtures.js -@@ -15,8 +15,13 @@ function readFixtureSync(args, enc) { - return fs.readFileSync(fixturesPath(args), enc); - } - --function readFixtureKey(name, enc) { -- return fs.readFileSync(fixturesPath('keys', name), enc); -+function readFixtureKey(name, enc, trim) { -+ let result = fs.readFileSync(fixturesPath('keys', name), enc); -+ if (trim) { -+ result = Buffer.from(result.toString().trim(), 'utf8'); -+ } -+ -+ return result; - } - - function readFixtureKeys(enc, ...names) { -diff --git a/test/parallel/test-crypto-certificate.js b/test/parallel/test-crypto-certificate.js -index 4a5f1f149fe6c739f7f1d2ee17df6e61a942d621..a21fbff81c840da29034cb07ae2bd711cfe78b0a 100644 ---- a/test/parallel/test-crypto-certificate.js -+++ b/test/parallel/test-crypto-certificate.js -@@ -30,9 +30,9 @@ const { Certificate } = crypto; - const fixtures = require('../common/fixtures'); - - // Test Certificates --const spkacValid = fixtures.readKey('rsa_spkac.spkac'); -+const spkacValid = fixtures.readKey('rsa_spkac.spkac', null, true); - const spkacChallenge = 'this-is-a-challenge'; --const spkacFail = fixtures.readKey('rsa_spkac_invalid.spkac'); -+const spkacFail = fixtures.readKey('rsa_spkac_invalid.spkac', null, true); - const spkacPublicPem = fixtures.readKey('rsa_public.pem'); - - function copyArrayBuffer(buf) { diff --git a/patches/node/unix_protect_fork_in_uv_spawn_from_signals.patch b/patches/node/unix_protect_fork_in_uv_spawn_from_signals.patch deleted file mode 100644 index e8f06d17973e6..0000000000000 --- a/patches/node/unix_protect_fork_in_uv_spawn_from_signals.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Thu, 29 Jul 2021 12:09:51 -0400 -Subject: unix: protect fork in uv_spawn from signals - -Years ago, we found that various kernels (linux, macOS) were known to -fail if they try to deliver a signal during this syscall, so we prevent -that from happening. They may have fixed those issues, but it is -generally just a bad time for signals to arrive (glibc blocks them here, -for example, including some more internal ones that it won't let us -touch here). - -We try to be a bit conservative, and leave many signals unblocked which -could happen during normal execution and should terminate the process if -they do. There is a small race window after the child starts before we -clear the old handlers, if the user was to send an fake signal from -elsewhere, but that should be quite unlikely. - -PR-URL: https://github.com/libuv/libuv/pull/3251 -Reviewed-By: Ben Noordhuis - -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index cfcba341e0e380ecd595e4b59e39c08a7b374a48..c1f6bd4b0076f0835caf83c45a6a896e7ae5def9 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -223,13 +224,32 @@ static void uv__process_child_init(const uv_process_options_t* options, - int stdio_count, - int (*pipes)[2], - int error_fd) { -- sigset_t set; -+ sigset_t signewset; - int close_fd; - int use_fd; -- int err; - int fd; - int n; - -+ /* Reset signal disposition first. Use a hard-coded limit because NSIG is not -+ * fixed on Linux: it's either 32, 34 or 64, depending on whether RT signals -+ * are enabled. We are not allowed to touch RT signal handlers, glibc uses -+ * them internally. -+ */ -+ for (n = 1; n < 32; n += 1) { -+ if (n == SIGKILL || n == SIGSTOP) -+ continue; /* Can't be changed. */ -+ -+#if defined(__HAIKU__) -+ if (n == SIGKILLTHR) -+ continue; /* Can't be changed. */ -+#endif -+ -+ if (SIG_ERR != signal(n, SIG_DFL)) -+ continue; -+ -+ uv__write_errno(error_fd); -+ } -+ - if (options->flags & UV_PROCESS_DETACHED) - setsid(); - -@@ -311,32 +331,10 @@ static void uv__process_child_init(const uv_process_options_t* options, - environ = options->env; - } - -- /* Reset signal disposition. Use a hard-coded limit because NSIG -- * is not fixed on Linux: it's either 32, 34 or 64, depending on -- * whether RT signals are enabled. We are not allowed to touch -- * RT signal handlers, glibc uses them internally. -- */ -- for (n = 1; n < 32; n += 1) { -- if (n == SIGKILL || n == SIGSTOP) -- continue; /* Can't be changed. */ -- --#if defined(__HAIKU__) -- if (n == SIGKILLTHR) -- continue; /* Can't be changed. */ --#endif -- -- if (SIG_ERR != signal(n, SIG_DFL)) -- continue; -- -- uv__write_errno(error_fd); -- } -- -- /* Reset signal mask. */ -- sigemptyset(&set); -- err = pthread_sigmask(SIG_SETMASK, &set, NULL); -- -- if (err != 0) -- uv__write_errno(error_fd); -+ /* Reset signal mask just before exec. */ -+ sigemptyset(&signewset); -+ if (sigprocmask(SIG_SETMASK, &signewset, NULL) != 0) -+ abort(); - - #ifdef __MVS__ - execvpe(options->file, options->args, environ); -@@ -345,6 +343,7 @@ static void uv__process_child_init(const uv_process_options_t* options, - #endif - - uv__write_errno(error_fd); -+ abort(); - } - #endif - -@@ -356,6 +355,8 @@ int uv_spawn(uv_loop_t* loop, - /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ - return UV_ENOSYS; - #else -+ sigset_t signewset; -+ sigset_t sigoldset; - int signal_pipe[2] = { -1, -1 }; - int pipes_storage[8][2]; - int (*pipes)[2]; -@@ -432,25 +433,41 @@ int uv_spawn(uv_loop_t* loop, - - /* Acquire write lock to prevent opening new fds in worker threads */ - uv_rwlock_wrlock(&loop->cloexec_lock); -- pid = fork(); - -- if (pid == -1) { -+ /* Start the child with most signals blocked, to avoid any issues before we -+ * can reset them, but allow program failures to exit (and not hang). */ -+ sigfillset(&signewset); -+ sigdelset(&signewset, SIGKILL); -+ sigdelset(&signewset, SIGSTOP); -+ sigdelset(&signewset, SIGTRAP); -+ sigdelset(&signewset, SIGSEGV); -+ sigdelset(&signewset, SIGBUS); -+ sigdelset(&signewset, SIGILL); -+ sigdelset(&signewset, SIGSYS); -+ sigdelset(&signewset, SIGABRT); -+ if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) -+ abort(); -+ -+ pid = fork(); -+ if (pid == -1) - err = UV__ERR(errno); -- uv_rwlock_wrunlock(&loop->cloexec_lock); -- uv__close(signal_pipe[0]); -- uv__close(signal_pipe[1]); -- goto error; -- } - -- if (pid == 0) { -+ if (pid == 0) - uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); -+ -+ if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) - abort(); -- } - - /* Release lock in parent process */ - uv_rwlock_wrunlock(&loop->cloexec_lock); -+ - uv__close(signal_pipe[1]); - -+ if (pid == -1) { -+ uv__close(signal_pipe[0]); -+ goto error; -+ } -+ - process->status = 0; - exec_errorno = 0; - do diff --git a/patches/node/unix_remove_uv_cloexec_ioctl_3515.patch b/patches/node/unix_remove_uv_cloexec_ioctl_3515.patch index f49d25998bba2..937abe6108d84 100644 --- a/patches/node/unix_remove_uv_cloexec_ioctl_3515.patch +++ b/patches/node/unix_remove_uv_cloexec_ioctl_3515.patch @@ -8,7 +8,7 @@ Now that uv__cloexec_fcntl() is simplified maintaining duplicate code paths for the same thing. diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c -index 6cd519ad5b3e7af8f5c71b18a59b88458a233f15..8c30802ad15316a8ec20ecedfb5123174d74276b 100644 +index a87b96cfc1dfdc88fa712a4fa991320ff28f2dcd..7cd3a2a954ff7d70e6ba7a6f7538648841bc54b2 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -597,20 +597,6 @@ int uv__nonblock_ioctl(int fd, int set) { diff --git a/patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch b/patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch index 219ae54daa15b..13229f0466cd1 100644 --- a/patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch +++ b/patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch @@ -7,7 +7,7 @@ FD_CLOEXEC is the only defined flag for fcntl(F_SETFD) so don't bother getting the status of that flag first with fcntl(F_GETFD), just set it. diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c -index a6425294086ff2f1435fdd6866380d3aaaf68200..6cd519ad5b3e7af8f5c71b18a59b88458a233f15 100644 +index 71e9c525c4a77b8b5322e8516c58329100a8d951..a87b96cfc1dfdc88fa712a4fa991320ff28f2dcd 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -649,21 +649,9 @@ int uv__cloexec_fcntl(int fd, int set) { diff --git a/patches/node/v8_api_advance_api_deprecation.patch b/patches/node/v8_api_advance_api_deprecation.patch new file mode 100644 index 0000000000000..bb431064a381a --- /dev/null +++ b/patches/node/v8_api_advance_api_deprecation.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 +Date: Fri, 26 Aug 2022 00:03:44 +0900 +Subject: v8: [api] Advance API deprecation + +Refs https://chromium-review.googlesource.com/c/v8/v8/+/3702449 +Should be upstreamed. + +diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc +index 2c36a0b132cf1b21595ac39619b99d316ad81d9e..3dfea77eab2ff880508eda95a5dff80a6564251f 100644 +--- a/src/inspector_agent.cc ++++ b/src/inspector_agent.cc +@@ -217,7 +217,8 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel, + bool prevent_shutdown) + : delegate_(std::move(delegate)), prevent_shutdown_(prevent_shutdown), + retaining_context_(false) { +- session_ = inspector->connect(CONTEXT_GROUP_ID, this, StringView()); ++ session_ = inspector->connect( ++ CONTEXT_GROUP_ID, this, StringView(),V8Inspector::kFullyTrusted); + node_dispatcher_ = std::make_unique(this); + tracing_agent_ = + std::make_unique(env, main_thread_); diff --git a/patches/node/worker_thread_add_asar_support.patch b/patches/node/worker_thread_add_asar_support.patch index 7300f87fd4fc3..0fd22dff59e46 100644 --- a/patches/node/worker_thread_add_asar_support.patch +++ b/patches/node/worker_thread_add_asar_support.patch @@ -7,10 +7,10 @@ This patch initializes asar support in workers threads in Node.js. diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js -index 419ffd9d5deb84eb94381259d3084411f6c3341b..17a1860d158976f11035553601560d171c7fc25a 100644 +index 899d5a906683e8967746e10a6de452e99e236903..4c459b58b5a048d9d8a4f15f4011e7cce68089f4 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js -@@ -505,6 +505,7 @@ module.exports = { +@@ -563,6 +563,7 @@ module.exports = { loadPreloadModules, setupTraceCategoryState, setupInspectorHooks, @@ -19,10 +19,10 @@ index 419ffd9d5deb84eb94381259d3084411f6c3341b..17a1860d158976f11035553601560d17 initializeCJSLoader, initializeWASI diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js -index e3ce67987ee3185a93750ebad72beab304c71e3a..ef5082d73b6153b49875c61d9b365b873b16145d 100644 +index 110a3ed1637b642b1d83fb36549cced151b9c5cd..50da62d11bf87c333322264f26e5b427efc7d46b 100644 --- a/lib/internal/main/worker_thread.js +++ b/lib/internal/main/worker_thread.js -@@ -27,6 +27,7 @@ const { +@@ -29,6 +29,7 @@ const { initializeReport, initializeSourceMapsHandlers, loadPreloadModules, @@ -30,7 +30,7 @@ index e3ce67987ee3185a93750ebad72beab304c71e3a..ef5082d73b6153b49875c61d9b365b87 setupTraceCategoryState } = require('internal/bootstrap/pre_execution'); -@@ -154,6 +155,8 @@ port.on('message', (message) => { +@@ -158,6 +159,8 @@ port.on('message', (message) => { }; workerIo.sharedCwdCounter = cwdCounter; diff --git a/patches/squirrel.mac/.patches b/patches/squirrel.mac/.patches index 83de4c94d2a6f..53f27f11a9e25 100644 --- a/patches/squirrel.mac/.patches +++ b/patches/squirrel.mac/.patches @@ -1,4 +1,5 @@ build_add_gn_config.patch fix_ensure_that_self_is_retained_until_the_racsignal_is_complete.patch fix_use_kseccschecknestedcode_kseccsstrictvalidate_in_the_sec.patch +feat_add_new_squirrel_mac_bundle_installation_method_behind_flag.patch refactor_use_posix_spawn_instead_of_nstask_so_we_can_disclaim_the.patch diff --git a/patches/squirrel.mac/build_add_gn_config.patch b/patches/squirrel.mac/build_add_gn_config.patch index 4f6e3a0db339a..d2c9ef6b4d975 100644 --- a/patches/squirrel.mac/build_add_gn_config.patch +++ b/patches/squirrel.mac/build_add_gn_config.patch @@ -23,10 +23,10 @@ index 89c499e451ecb48655cfd42b01ffa1da56998c2e..98f80aad43a87ed75ca1660ad6a178db +vendor diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 -index 0000000000000000000000000000000000000000..d43e6d6be5c8e2b3a5f715721e61589be493718d +index 0000000000000000000000000000000000000000..68beb3d10580cdb747a78407c7f5bbb205825c4b --- /dev/null +++ b/BUILD.gn -@@ -0,0 +1,239 @@ +@@ -0,0 +1,242 @@ +assert(is_mac) + +import("//build/config/mac/rules.gni") @@ -148,7 +148,10 @@ index 0000000000000000000000000000000000000000..d43e6d6be5c8e2b3a5f715721e61589b + "$dtrace_header_dir", + ] + -+ cflags_objc = [ "-fobjc-arc" ] ++ cflags_objc = [ ++ "-fobjc-arc", ++ "-Wno-deprecated-declarations", ++ ] + + ldflags = [ "-Wl,-install_name,@rpath/$output_name.framework/$output_name" ] +} diff --git a/patches/squirrel.mac/feat_add_new_squirrel_mac_bundle_installation_method_behind_flag.patch b/patches/squirrel.mac/feat_add_new_squirrel_mac_bundle_installation_method_behind_flag.patch new file mode 100644 index 0000000000000..ed8006fe96309 --- /dev/null +++ b/patches/squirrel.mac/feat_add_new_squirrel_mac_bundle_installation_method_behind_flag.patch @@ -0,0 +1,128 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Mon, 28 Mar 2022 02:43:18 -0700 +Subject: feat: add new Squirrel.Mac bundle installation method behind flag + +The 'SquirrelMacEnableDirectContentsWrite' user default in your apps defaults suite +can be used to control this new installation method. It is designed to remove the +requirement that the updating process have write access to its parent directory. + +With this feature enabled the updating process only needs write access to it's own +.app bundle folder, not the owning /Applications folder. This should allow more +non-admin users to update applications when appropriately granted group based permissions. + +E.g. 775 and chown :staff + +diff --git a/Squirrel/SQRLInstaller.m b/Squirrel/SQRLInstaller.m +index 7dd98ddee4ae0f4e01fd7aaa3486083bff7d0da1..c1f328fa8c3689218ef260347cb8f9d30b789efe 100644 +--- a/Squirrel/SQRLInstaller.m ++++ b/Squirrel/SQRLInstaller.m +@@ -249,6 +249,7 @@ - (RACSignal *)acquireTargetBundleURLForRequest:(SQRLShipItRequest *)request { + ] reduce:^(NSURL *directoryURL, SQRLCodeSignature *codeSignature) { + NSURL *targetBundleURL = request.targetBundleURL; + NSURL *newBundleURL = [directoryURL URLByAppendingPathComponent:targetBundleURL.lastPathComponent]; ++ [NSFileManager.defaultManager createDirectoryAtURL:newBundleURL withIntermediateDirectories:FALSE attributes:nil error:nil]; + + return [[SQRLInstallerOwnedBundle alloc] initWithOriginalURL:request.targetBundleURL temporaryURL:newBundleURL codeSignature:codeSignature]; + }] +@@ -481,10 +482,50 @@ - (RACSignal *)installItemToURL:(NSURL *)targetURL fromURL:(NSURL *)sourceURL { + NSParameterAssert(targetURL != nil); + NSParameterAssert(sourceURL != nil); + ++ NSLog(@"Moving bundle from %@ to %@", sourceURL, targetURL); ++ ++ // If both the sourceURL and the targetURL exist we can try to skip a permissions check ++ // by moving Thing.app/Contents directly. This allows us to update applications without ++ // permission to write files into the parent directory of Thing.app ++ // ++ // There is no known case where these directories don't exist but in order to handle ++ // edge cases / race conditions we'll handle it anyway. ++ // ++ // This exists check is non-atomic with the rename call below but that's OK ++ BOOL canRenameContentsDirectly = FALSE; ++ // For now while this is tested at scale this new option is behind a user default, this ++ // can be set by applications wishing to test this feature at runtime. If it causes issues ++ // it can be opted out by individual users by setting this key to false explicitly. ++ // Once this has bene tested at scale it will become the default for all Squirrel.Mac ++ // users. ++ NSUserDefaults *defaults = [[NSUserDefaults alloc] init]; ++ [defaults addSuiteNamed:_applicationIdentifier]; ++ // In cases where this code is being executed under the ShipIt executable it's running ++ // under an application identifier equal to {parent_identifier}.ShipIt ++ // In this case we need to use the true parent identifier too as that is 99% of the time ++ // where the key will be set. ++ if ([_applicationIdentifier hasSuffix:@".ShipIt"]) { ++ [defaults addSuiteNamed:[_applicationIdentifier substringToIndex:[_applicationIdentifier length] - 7]]; ++ } ++ ++ if ([defaults boolForKey:@"SquirrelMacEnableDirectContentsWrite"]) { ++ canRenameContentsDirectly = [NSFileManager.defaultManager fileExistsAtPath:targetURL.path] && [NSFileManager.defaultManager fileExistsAtPath:sourceURL.path]; ++ ++ if (canRenameContentsDirectly) { ++ NSLog(@"Moving bundles via 'Contents' folder rename"); ++ } else { ++ NSLog(@"Moving bundles directly as one of source / target does not exist. This is unexpected."); ++ } ++ } else { ++ NSLog(@"Moving bundles directly as SquirrelMacEnableDirectContentsWrite is disabled for app: %@", _applicationIdentifier); ++ } ++ NSURL *targetContentsURL = canRenameContentsDirectly ? [targetURL URLByAppendingPathComponent:@"Contents"] : targetURL; ++ NSURL *sourceContentsURL = canRenameContentsDirectly ? [sourceURL URLByAppendingPathComponent:@"Contents"] : sourceURL; ++ + return [[[[RACSignal + defer:^{ + // rename() is atomic, NSFileManager sucks. +- if (rename(sourceURL.path.fileSystemRepresentation, targetURL.path.fileSystemRepresentation) == 0) { ++ if (rename(sourceContentsURL.path.fileSystemRepresentation, targetContentsURL.path.fileSystemRepresentation) == 0) { + return [RACSignal empty]; + } else { + int code = errno; +@@ -497,24 +538,24 @@ - (RACSignal *)installItemToURL:(NSURL *)targetURL fromURL:(NSURL *)sourceURL { + } + }] + doCompleted:^{ +- NSLog(@"Moved bundle from %@ to %@", sourceURL, targetURL); ++ NSLog(@"Moved bundle contents from %@ to %@", sourceContentsURL, targetContentsURL); + }] + catch:^(NSError *error) { + if (![error.domain isEqual:NSPOSIXErrorDomain] || error.code != EXDEV) return [RACSignal error:error]; + + // If the locations lie on two different volumes, remove the + // destination by hand, then perform a move. +- [NSFileManager.defaultManager removeItemAtURL:targetURL error:NULL]; ++ [NSFileManager.defaultManager removeItemAtURL:targetContentsURL error:NULL]; + +- if ([NSFileManager.defaultManager moveItemAtURL:sourceURL toURL:targetURL error:&error]) { +- NSLog(@"Moved bundle across volumes from %@ to %@", sourceURL, targetURL); ++ if ([NSFileManager.defaultManager moveItemAtURL:sourceContentsURL toURL:targetContentsURL error:&error]) { ++ NSLog(@"Moved bundle contents across volumes from %@ to %@", sourceContentsURL, targetContentsURL); + return [RACSignal empty]; + } else { +- NSString *description = [NSString stringWithFormat:NSLocalizedString(@"Couldn't move bundle %@ across volumes to %@", nil), sourceURL, targetURL]; ++ NSString *description = [NSString stringWithFormat:NSLocalizedString(@"Couldn't move bundle contents %@ across volumes to %@", nil), sourceContentsURL, targetContentsURL]; + return [RACSignal error:[self errorByAddingDescription:description code:SQRLInstallerErrorMovingAcrossVolumes toError:error]]; + } + }] +- setNameWithFormat:@"%@ -installItemAtURL: %@ fromURL: %@", self, targetURL, sourceURL]; ++ setNameWithFormat:@"%@ -installItemAtURL: %@ fromURL: %@", self, targetContentsURL, sourceContentsURL]; + } + + #pragma mark Quarantine Bit Removal +diff --git a/Squirrel/SQRLUpdater.m b/Squirrel/SQRLUpdater.m +index c81c820d61da3c7d1cfd2c516147c954a5773a0c..4c703159a2bb0239b7d4e1793a985b5ec2edcfa9 100644 +--- a/Squirrel/SQRLUpdater.m ++++ b/Squirrel/SQRLUpdater.m +@@ -329,7 +329,12 @@ - (id)initWithUpdateRequest:(NSURLRequest *)updateRequest requestForDownload:(SQ + + BOOL targetWritable = [self canWriteToURL:targetURL]; + BOOL parentWritable = [self canWriteToURL:targetURL.URLByDeletingLastPathComponent]; +- return [SQRLShipItLauncher launchPrivileged:!targetWritable || !parentWritable]; ++ BOOL launchPrivileged = !targetWritable || !parentWritable; ++ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"SquirrelMacEnableDirectContentsWrite"]) { ++ // If SquirrelMacEnableDirectContentsWrite is enabled we don't care if the parent directory is writeable or not ++ BOOL launchPrivileged = !targetWritable; ++ } ++ return [SQRLShipItLauncher launchPrivileged:launchPrivileged]; + }] + replayLazily] + setNameWithFormat:@"shipItLauncher"]; diff --git a/patches/v8/.patches b/patches/v8/.patches index 1e5615f3ce254..890f2f25a5475 100644 --- a/patches/v8/.patches +++ b/patches/v8/.patches @@ -4,6 +4,8 @@ dcheck.patch export_symbols_needed_for_windows_build.patch workaround_an_undefined_symbol_error.patch do_not_export_private_v8_symbols_on_windows.patch -fix_build_deprecated_attirbute_for_older_msvc_versions.patch +fix_build_deprecated_attribute_for_older_msvc_versions.patch fix_disable_implies_dcheck_for_node_stream_array_buffers.patch revert_fix_cppgc_removed_deleted_cstors_in_cppheapcreateparams.patch +revert_runtime_dhceck_terminating_exception_in_microtasks.patch +chore_disable_is_execution_terminating_dcheck.patch diff --git a/patches/v8/build_gn.patch b/patches/v8/build_gn.patch index 13649f1c4acc8..4a5ba08bbfe6a 100644 --- a/patches/v8/build_gn.patch +++ b/patches/v8/build_gn.patch @@ -9,10 +9,10 @@ necessary for native modules to load. Also, some fixes relating to mksnapshot on ARM. diff --git a/BUILD.gn b/BUILD.gn -index fb68d0ec4d121aaac31fd6e4c317a59976ef034c..dbbe9ae10bebdd71f441fda00c7dbfa187603a84 100644 +index 83082271b8b76179b41e943190303e31fa639a95..0a23171a391606bb3408dcf8a488d075a148443a 100644 --- a/BUILD.gn +++ b/BUILD.gn -@@ -598,7 +598,7 @@ config("internal_config") { +@@ -663,7 +663,7 @@ config("internal_config") { ":cppgc_header_features", ] @@ -21,7 +21,7 @@ index fb68d0ec4d121aaac31fd6e4c317a59976ef034c..dbbe9ae10bebdd71f441fda00c7dbfa1 defines += [ "BUILDING_V8_SHARED" ] } -@@ -5733,7 +5733,7 @@ if (current_toolchain == v8_generator_toolchain) { +@@ -6166,7 +6166,7 @@ if (current_toolchain == v8_generator_toolchain) { "src/interpreter/bytecodes.h", ] @@ -30,12 +30,3 @@ index fb68d0ec4d121aaac31fd6e4c317a59976ef034c..dbbe9ae10bebdd71f441fda00c7dbfa1 deps = [ ":v8_libbase", -@@ -5771,6 +5771,8 @@ if (current_toolchain == v8_snapshot_toolchain) { - - configs = [ ":internal_config" ] - -+ configs += [ "//electron/build/config:build_time_executable" ] -+ - deps = [ - ":v8_base_without_compiler", - ":v8_compiler_for_mksnapshot", diff --git a/patches/v8/chore_disable_is_execution_terminating_dcheck.patch b/patches/v8/chore_disable_is_execution_terminating_dcheck.patch new file mode 100644 index 0000000000000..01fff8491a630 --- /dev/null +++ b/patches/v8/chore_disable_is_execution_terminating_dcheck.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shelley Vohr +Date: Tue, 31 May 2022 19:58:01 +0200 +Subject: chore: disable is_execution_terminating DCHECK + +This causes a slew of crashes in Node.js. + +Upstream issue opened at https://github.com/nodejs/node-v8/issues/227. + +diff --git a/src/api/api-macros.h b/src/api/api-macros.h +index 149dd0555a69be576fd1eb97aa79b8aedafcac04..233e6d2ac511c4a7fa45d47bb7448beead52faf1 100644 +--- a/src/api/api-macros.h ++++ b/src/api/api-macros.h +@@ -97,8 +97,6 @@ + + // Lightweight version for APIs that don't require an active context. + #define DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate) \ +- /* Embedders should never enter V8 after terminating it */ \ +- DCHECK(!i_isolate->is_execution_terminating()); \ + DCHECK_NO_SCRIPT_NO_EXCEPTION_MAYBE_TEARDOWN(i_isolate) + + #define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate) \ +diff --git a/src/execution/microtask-queue.cc b/src/execution/microtask-queue.cc +index f47228f80b6a2b9e89afd50e6f67eba1185c0dd6..8adf3a9159b947f4fa567317d05cf0b9f204c862 100644 +--- a/src/execution/microtask-queue.cc ++++ b/src/execution/microtask-queue.cc +@@ -179,7 +179,7 @@ int MicrotaskQueue::RunMicrotasks(Isolate* isolate) { + + if (isolate->is_execution_terminating()) { + DCHECK(isolate->has_scheduled_exception()); +- DCHECK(maybe_result.is_null()); ++ // DCHECK(maybe_result.is_null()); + delete[] ring_buffer_; + ring_buffer_ = nullptr; + capacity_ = 0; diff --git a/patches/v8/dcheck.patch b/patches/v8/dcheck.patch index b4231609ce27d..937d33fb705c8 100644 --- a/patches/v8/dcheck.patch +++ b/patches/v8/dcheck.patch @@ -6,32 +6,15 @@ Subject: dcheck.patch https://github.com/auchenberg/volkswagen diff --git a/src/api/api.cc b/src/api/api.cc -index e6797c92a52ab7805261ace2156a39fe368bd747..1aed7cad8b7dfff9fc7b1f93040c3eda33693af3 100644 +index 353fa739d89bf85d6dbb202d62b3ddab9b0a899e..ae6d7c8548c1cb336e07dcfe7507f7919eb85845 100644 --- a/src/api/api.cc +++ b/src/api/api.cc -@@ -9097,7 +9097,7 @@ void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) { +@@ -9171,7 +9171,7 @@ void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) { } void Isolate::PerformMicrotaskCheckpoint() { - DCHECK_NE(MicrotasksPolicy::kScoped, GetMicrotasksPolicy()); -+ //DCHECK_NE(MicrotasksPolicy::kScoped, GetMicrotasksPolicy()); - i::Isolate* isolate = reinterpret_cast(this); - isolate->default_microtask_queue()->PerformCheckpoint(this); ++ // DCHECK_NE(MicrotasksPolicy::kScoped, GetMicrotasksPolicy()); + i::Isolate* i_isolate = reinterpret_cast(this); + i_isolate->default_microtask_queue()->PerformCheckpoint(this); } -diff --git a/src/heap/heap.cc b/src/heap/heap.cc -index 8e4ad43c1957f4ed555327588c41d049824c1dc5..54cf3b263ac5654b370897b951aa0be8f8d566e5 100644 ---- a/src/heap/heap.cc -+++ b/src/heap/heap.cc -@@ -6235,9 +6235,9 @@ void Heap::TearDown() { - void Heap::AddGCPrologueCallback(v8::Isolate::GCCallbackWithData callback, - GCType gc_type, void* data) { - DCHECK_NOT_NULL(callback); -- DCHECK(gc_prologue_callbacks_.end() == -- std::find(gc_prologue_callbacks_.begin(), gc_prologue_callbacks_.end(), -- GCCallbackTuple(callback, gc_type, data))); -+// DCHECK(gc_prologue_callbacks_.end() == -+// std::find(gc_prologue_callbacks_.begin(), gc_prologue_callbacks_.end(), -+// GCCallbackTuple(callback, gc_type, data))); - gc_prologue_callbacks_.emplace_back(callback, gc_type, data); - } - diff --git a/patches/v8/do_not_export_private_v8_symbols_on_windows.patch b/patches/v8/do_not_export_private_v8_symbols_on_windows.patch index 59cf1289c5fab..8b0f56b8fe03a 100644 --- a/patches/v8/do_not_export_private_v8_symbols_on_windows.patch +++ b/patches/v8/do_not_export_private_v8_symbols_on_windows.patch @@ -12,10 +12,10 @@ This patch can be safely removed if, when it is removed, `node.lib` does not contain any standard C++ library exports (e.g. `std::ostringstream`). diff --git a/BUILD.gn b/BUILD.gn -index c784f859ba874b9a79be3dd9c69d306b8a590660..93158da71e2e7dd1aecc421664d4d21687cb38a6 100644 +index b0c6d08bf50a3443e2589f09b6f1f5b7734c000c..7728123805054064d5acecacf6cbf8d1fe4a56c1 100644 --- a/BUILD.gn +++ b/BUILD.gn -@@ -598,6 +598,10 @@ config("internal_config") { +@@ -663,6 +663,10 @@ config("internal_config") { ":cppgc_header_features", ] @@ -27,10 +27,10 @@ index c784f859ba874b9a79be3dd9c69d306b8a590660..93158da71e2e7dd1aecc421664d4d216 defines += [ "BUILDING_V8_SHARED" ] } diff --git a/src/base/macros.h b/src/base/macros.h -index 3a73afc1ce7712a0683992608ff399734eea1f9d..f90f4ebffd6295bfa3e047cfb9c5ff0f2c30f26a 100644 +index 3a94093a14b0b3eabfff7063dd87049da56d62bc..641fb6a8d3dd80a23143e7f25bebe03e50681112 100644 --- a/src/base/macros.h +++ b/src/base/macros.h -@@ -393,13 +393,17 @@ bool is_inbounds(float_t v) { +@@ -389,13 +389,17 @@ bool is_inbounds(float_t v) { #ifdef V8_OS_WIN // Setup for Windows shared library export. diff --git a/patches/v8/export_symbols_needed_for_windows_build.patch b/patches/v8/export_symbols_needed_for_windows_build.patch index 4068e9b55533e..f4551bf39ef14 100644 --- a/patches/v8/export_symbols_needed_for_windows_build.patch +++ b/patches/v8/export_symbols_needed_for_windows_build.patch @@ -6,10 +6,10 @@ Subject: Export symbols needed for Windows build These symbols are required to build v8 with BUILD_V8_SHARED on Windows. diff --git a/src/objects/objects.h b/src/objects/objects.h -index 48f595a24ec7ead3076e1d44afb4f18b7bb810c3..df7cb44387a42fa173ce68ee8464d6abc050986f 100644 +index ced30839aa8627b9b21eabea1a4a3b2574a906d8..f038aea4e2e105b711f4530a1c40d63ee340724f 100644 --- a/src/objects/objects.h +++ b/src/objects/objects.h -@@ -886,7 +886,7 @@ enum AccessorComponent { ACCESSOR_GETTER, ACCESSOR_SETTER }; +@@ -928,7 +928,7 @@ enum AccessorComponent { ACCESSOR_GETTER, ACCESSOR_SETTER }; // Utility superclass for stack-allocated objects that must be updated // on gc. It provides two ways for the gc to update instances, either // iterating or updating after gc. @@ -19,7 +19,7 @@ index 48f595a24ec7ead3076e1d44afb4f18b7bb810c3..df7cb44387a42fa173ce68ee8464d6ab explicit inline Relocatable(Isolate* isolate); inline virtual ~Relocatable(); diff --git a/src/objects/ordered-hash-table.h b/src/objects/ordered-hash-table.h -index ec304170542f8a6053c60cbebb22c536cb56ac6c..be8f33d5e8bc2ff388f199dacebd408ccd32dda5 100644 +index 60a6343bb0698902074741c860f3af0f398a85a5..5699fd042e8e3fa19d155de5162a18e24b87f90c 100644 --- a/src/objects/ordered-hash-table.h +++ b/src/objects/ordered-hash-table.h @@ -64,7 +64,7 @@ namespace internal { diff --git a/patches/v8/expose_mksnapshot.patch b/patches/v8/expose_mksnapshot.patch index ae318986f9b8a..b9959281d59e2 100644 --- a/patches/v8/expose_mksnapshot.patch +++ b/patches/v8/expose_mksnapshot.patch @@ -6,10 +6,10 @@ Subject: expose_mksnapshot.patch Needed in order to target mksnapshot for mksnapshot zip. diff --git a/BUILD.gn b/BUILD.gn -index dbbe9ae10bebdd71f441fda00c7dbfa187603a84..c784f859ba874b9a79be3dd9c69d306b8a590660 100644 +index 0a23171a391606bb3408dcf8a488d075a148443a..b0c6d08bf50a3443e2589f09b6f1f5b7734c000c 100644 --- a/BUILD.gn +++ b/BUILD.gn -@@ -5745,7 +5745,6 @@ if (current_toolchain == v8_generator_toolchain) { +@@ -6178,7 +6178,6 @@ if (current_toolchain == v8_generator_toolchain) { if (current_toolchain == v8_snapshot_toolchain) { v8_executable("mksnapshot") { diff --git a/patches/v8/fix_build_deprecated_attirbute_for_older_msvc_versions.patch b/patches/v8/fix_build_deprecated_attribute_for_older_msvc_versions.patch similarity index 56% rename from patches/v8/fix_build_deprecated_attirbute_for_older_msvc_versions.patch rename to patches/v8/fix_build_deprecated_attribute_for_older_msvc_versions.patch index ad3c1b6198b4c..3bc3ef7c64f34 100644 --- a/patches/v8/fix_build_deprecated_attirbute_for_older_msvc_versions.patch +++ b/patches/v8/fix_build_deprecated_attribute_for_older_msvc_versions.patch @@ -1,18 +1,15 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Deepak Mohan Date: Tue, 28 Jan 2020 15:48:03 -0800 -Subject: fix: usage of c++ [[deprecated]] attirbute for older msvc versions +Subject: fix: usage of c++ [[deprecated]] attribute for older msvc versions -VS 2015 update 3 has a bug where [[deprecated]] attribute cannot -be applied to constructor declarations, this is fixed in 2017 and -higher versions, but native module compiling with this version -will have an issue. +This attribute can only be used in all contexts in Visual Studio 2019 diff --git a/include/v8config.h b/include/v8config.h -index b16ab3ff88d1054d12af4de3ad0018c97c0b7fcc..c9963b43c121964c0c37c858adb228cd090d5c2a 100644 +index 85bbfce01dff2b0b499e5c02b80e23b682443582..9cedeff64478d900bc6730537caff16f09dcfd46 100644 --- a/include/v8config.h +++ b/include/v8config.h -@@ -452,10 +452,13 @@ path. Add it with -I to the command line +@@ -469,10 +469,13 @@ path. Add it with -I to the command line # define V8_NOINLINE /* NOT SUPPORTED */ #endif @@ -20,7 +17,7 @@ index b16ab3ff88d1054d12af4de3ad0018c97c0b7fcc..c9963b43c121964c0c37c858adb228cd // A macro (V8_DEPRECATED) to mark classes or functions as deprecated. #if defined(V8_DEPRECATION_WARNINGS) -# define V8_DEPRECATED(message) [[deprecated(message)]] -+# if defined(_MSC_VER) && _MSC_VER <= 1900 ++# if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1920 +# define V8_DEPRECATED(message) __declspec(deprecated(message)) +# else +# define V8_DEPRECATED(message) [[deprecated(message)]] @@ -28,12 +25,12 @@ index b16ab3ff88d1054d12af4de3ad0018c97c0b7fcc..c9963b43c121964c0c37c858adb228cd #else # define V8_DEPRECATED(message) #endif -@@ -463,7 +466,11 @@ path. Add it with -I to the command line +@@ -480,7 +483,11 @@ path. Add it with -I to the command line // A macro (V8_DEPRECATE_SOON) to make it easier to see what will be deprecated. #if defined(V8_IMMINENT_DEPRECATION_WARNINGS) -# define V8_DEPRECATE_SOON(message) [[deprecated(message)]] -+# if defined(_MSC_VER) && _MSC_VER <= 1900 ++# if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1920 +# define V8_DEPRECATE_SOON(message) __declspec(deprecated(message)) +# else +# define V8_DEPRECATE_SOON(message) [[deprecated(message)]] @@ -41,3 +38,12 @@ index b16ab3ff88d1054d12af4de3ad0018c97c0b7fcc..c9963b43c121964c0c37c858adb228cd #else # define V8_DEPRECATE_SOON(message) #endif +@@ -514,7 +521,7 @@ path. Add it with -I to the command line + END_ALLOW_USE_DEPRECATED() + + +-#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 6) ++#if !defined(__clang__) && (defined(__GNUC__) && __GNUC__ < 6) || (defined(_MSC_VER) && _MSC_VER < 1920) + # define V8_ENUM_DEPRECATED(message) + # define V8_ENUM_DEPRECATE_SOON(message) + #else diff --git a/patches/v8/fix_disable_implies_dcheck_for_node_stream_array_buffers.patch b/patches/v8/fix_disable_implies_dcheck_for_node_stream_array_buffers.patch index ce960703ace71..9bffebef93014 100644 --- a/patches/v8/fix_disable_implies_dcheck_for_node_stream_array_buffers.patch +++ b/patches/v8/fix_disable_implies_dcheck_for_node_stream_array_buffers.patch @@ -18,7 +18,7 @@ This patch can be removed when streams support rab/gsab, or when support is synchronized across both v8 and node. diff --git a/src/objects/js-array-buffer.cc b/src/objects/js-array-buffer.cc -index cd760b9e67820c6ab69164992bccf19411cf1db6..f28258bf1b797c2a2d904e25802a17b14ad0c19a 100644 +index dd59d5d6afc7c8e0b309d4e8928cd2bb7e682884..f3445a71aa02683dc40221b2eee1a80071629fef 100644 --- a/src/objects/js-array-buffer.cc +++ b/src/objects/js-array-buffer.cc @@ -72,9 +72,9 @@ void JSArrayBuffer::Attach(std::shared_ptr backing_store) { diff --git a/patches/v8/revert_fix_cppgc_removed_deleted_cstors_in_cppheapcreateparams.patch b/patches/v8/revert_fix_cppgc_removed_deleted_cstors_in_cppheapcreateparams.patch index bf4935b108d45..1eabe26bfd11c 100644 --- a/patches/v8/revert_fix_cppgc_removed_deleted_cstors_in_cppheapcreateparams.patch +++ b/patches/v8/revert_fix_cppgc_removed_deleted_cstors_in_cppheapcreateparams.patch @@ -6,7 +6,7 @@ Subject: Revert "fix(cppgc): removed deleted cstors in CppHeapCreateParams" This reverts commit a66b09e5510d62ff469e72b1a8ff7f0ead1bf0f6. diff --git a/include/v8-cppgc.h b/include/v8-cppgc.h -index 201773f59ddd3ce2ed61fe08cb58786aeed605cc..7761d87fd0a325a53d398bafcdeadd6a87f4f1c2 100644 +index 412154930f7d92b5e3932bf7a1cace16eee940e8..401e492210609f9c1b16a082ff9d97b8acd4fc61 100644 --- a/include/v8-cppgc.h +++ b/include/v8-cppgc.h @@ -77,6 +77,9 @@ struct WrapperDescriptor final { diff --git a/patches/v8/revert_runtime_dhceck_terminating_exception_in_microtasks.patch b/patches/v8/revert_runtime_dhceck_terminating_exception_in_microtasks.patch new file mode 100644 index 0000000000000..3d3a888d896e7 --- /dev/null +++ b/patches/v8/revert_runtime_dhceck_terminating_exception_in_microtasks.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Rose +Date: Mon, 9 May 2022 17:09:21 -0700 +Subject: Revert "[runtime] DHCECK terminating exception in Microtasks" + +This reverts commit bccb536c98181e8a6e9cf0b6342311adbbf61aca. + +diff --git a/src/builtins/builtins-microtask-queue-gen.cc b/src/builtins/builtins-microtask-queue-gen.cc +index ca4b1dc557f573bfcde200201cbd2f05e3c6b530..9edc8ce00c524a63cb23911a474f1904af5d71f7 100644 +--- a/src/builtins/builtins-microtask-queue-gen.cc ++++ b/src/builtins/builtins-microtask-queue-gen.cc +@@ -118,7 +118,6 @@ void MicrotaskQueueBuiltinsAssembler::PrepareForContext( + void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask( + TNode current_context, TNode microtask) { + CSA_DCHECK(this, TaggedIsNotSmi(microtask)); +- CSA_DCHECK(this, Word32BinaryNot(IsExecutionTerminating())); + + StoreRoot(RootIndex::kCurrentMicrotask, microtask); + TNode saved_entered_context_count = GetEnteredContextCount(); +diff --git a/src/codegen/code-stub-assembler.cc b/src/codegen/code-stub-assembler.cc +index 9a12cfdd9d02624a6fbbf5b10da958a6024b0857..01acdbcd633e9f11e6bd0673ed33eed5ce4f61fa 100644 +--- a/src/codegen/code-stub-assembler.cc ++++ b/src/codegen/code-stub-assembler.cc +@@ -6139,12 +6139,6 @@ void CodeStubAssembler::SetPendingMessage(TNode message) { + StoreFullTaggedNoWriteBarrier(pending_message, message); + } + +-TNode CodeStubAssembler::IsExecutionTerminating() { +- TNode pending_message = GetPendingMessage(); +- return TaggedEqual(pending_message, +- LoadRoot(RootIndex::kTerminationException)); +-} +- + TNode CodeStubAssembler::InstanceTypeEqual(TNode instance_type, + int type) { + return Word32Equal(instance_type, Int32Constant(type)); +diff --git a/src/codegen/code-stub-assembler.h b/src/codegen/code-stub-assembler.h +index 5c89a2ac9de2db35c4b5c326a02269203bb0ce46..ecc20c69e8f72179d32ce53e68bc463105907d11 100644 +--- a/src/codegen/code-stub-assembler.h ++++ b/src/codegen/code-stub-assembler.h +@@ -2538,7 +2538,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler + + TNode GetPendingMessage(); + void SetPendingMessage(TNode message); +- TNode IsExecutionTerminating(); + + // Type checks. + // Check whether the map is for an object with special properties, such as a diff --git a/patches/v8/workaround_an_undefined_symbol_error.patch b/patches/v8/workaround_an_undefined_symbol_error.patch index 4226bc8f1acae..45230556a6913 100644 --- a/patches/v8/workaround_an_undefined_symbol_error.patch +++ b/patches/v8/workaround_an_undefined_symbol_error.patch @@ -12,10 +12,10 @@ By moving some functions out of the the arm64-assembler header file, this error no longer seems to happen. diff --git a/src/codegen/arm64/assembler-arm64.cc b/src/codegen/arm64/assembler-arm64.cc -index ac7a46a895dd914f48038f36738c40ccfbd5c63f..e9f7bc7d022d05b6b62caf171d4e457119256831 100644 +index 0110e903fd9c3681dca9921d4ad26fa47c38886a..18be54526bc11a4b285d9e0ab1873d587f11899d 100644 --- a/src/codegen/arm64/assembler-arm64.cc +++ b/src/codegen/arm64/assembler-arm64.cc -@@ -3629,6 +3629,22 @@ void Assembler::MoveWide(const Register& rd, uint64_t imm, int shift, +@@ -3627,6 +3627,22 @@ void Assembler::MoveWide(const Register& rd, uint64_t imm, int shift, ImmMoveWide(static_cast(imm)) | ShiftMoveWide(shift)); } @@ -39,10 +39,10 @@ index ac7a46a895dd914f48038f36738c40ccfbd5c63f..e9f7bc7d022d05b6b62caf171d4e4571 const Operand& operand, FlagsUpdate S, AddSubOp op) { DCHECK_EQ(rd.SizeInBits(), rn.SizeInBits()); diff --git a/src/codegen/arm64/assembler-arm64.h b/src/codegen/arm64/assembler-arm64.h -index f9e991a57b3294b0ed786b8a0b3f540d9ab5cd49..3352d8d5f3f1e4971498aafd45b9dbac447a1b4b 100644 +index f26054a12ee493fc82cc5285de96da3b5aa149b2..23d8ead77dc4cde1da093510353cc93c14ce4fe0 100644 --- a/src/codegen/arm64/assembler-arm64.h +++ b/src/codegen/arm64/assembler-arm64.h -@@ -2119,11 +2119,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { +@@ -2120,11 +2120,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { return rm.code() << Rm_offset; } @@ -55,7 +55,7 @@ index f9e991a57b3294b0ed786b8a0b3f540d9ab5cd49..3352d8d5f3f1e4971498aafd45b9dbac static Instr Ra(CPURegister ra) { DCHECK_NE(ra.code(), kSPRegInternalCode); -@@ -2147,15 +2143,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { +@@ -2148,15 +2144,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { // These encoding functions allow the stack pointer to be encoded, and // disallow the zero register. diff --git a/patches/webrtc/.patches b/patches/webrtc/.patches index b74a59b97d6fa..9cde1db8895b3 100644 --- a/patches/webrtc/.patches +++ b/patches/webrtc/.patches @@ -1,2 +1 @@ add_thread_local_to_x_error_trap_cc.patch -cherry-pick-a18fddcb53e6.patch diff --git a/patches/webrtc/cherry-pick-a18fddcb53e6.patch b/patches/webrtc/cherry-pick-a18fddcb53e6.patch deleted file mode 100644 index da5f2e41f9114..0000000000000 --- a/patches/webrtc/cherry-pick-a18fddcb53e6.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tony Herre -Date: Fri, 25 Mar 2022 09:33:14 +0100 -Subject: Filter out Mac StatusIndicator window from desktop capture list - -Since 12.2, the orange/red indicator at the top right of the screen shows up as a window in the Chrome getDisplayMedia() picker, as it's not filtered out by the existing filters. Screenshots in the bug. - -Bug: chromium:1297731, b/218211225 -Change-Id: I0f87e8d2af42a5a2e3d84f69fe73596e9cf35622 -Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/251841 -Reviewed-by: Alexander Cooper -Commit-Queue: Tony Herre -Cr-Commit-Position: refs/heads/main@{#36350} - -diff --git a/modules/desktop_capture/mac/window_list_utils.cc b/modules/desktop_capture/mac/window_list_utils.cc -index d2fb20ed4ca0689fd6f51ee994308e876680ab1e..5d881662ea2f2d86d2c33bf20f79d31ef4e7a481 100644 ---- a/modules/desktop_capture/mac/window_list_utils.cc -+++ b/modules/desktop_capture/mac/window_list_utils.cc -@@ -31,6 +31,11 @@ namespace webrtc { - - namespace { - -+// WindowName of the status indicator dot shown since Monterey in the taskbar. -+// Testing on 12.2.1 shows this is independent of system language setting. -+const CFStringRef kStatusIndicator = CFSTR("StatusIndicator"); -+const CFStringRef kStatusIndicatorOwnerName = CFSTR("Window Server"); -+ - bool ToUtf8(const CFStringRef str16, std::string* str8) { - size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16), - kCFStringEncodingUTF8) + -@@ -145,6 +150,17 @@ bool GetWindowList(rtc::FunctionView on_window, - continue; - } - -+ CFStringRef window_owner_name = reinterpret_cast( -+ CFDictionaryGetValue(window, kCGWindowOwnerName)); -+ // Ignore the red dot status indicator shown in the stats bar. Unlike the -+ // rest of the system UI it has a window_layer of 0, so was otherwise -+ // included. See crbug.com/1297731. -+ if (window_title && CFEqual(window_title, kStatusIndicator) && -+ window_owner_name && -+ CFEqual(window_owner_name, kStatusIndicatorOwnerName)) { -+ continue; -+ } -+ - if (!on_window(window)) { - break; - } diff --git a/script/add-debug-link.py b/script/add-debug-link.py index 405f55b110cca..167c9e2d93545 100755 --- a/script/add-debug-link.py +++ b/script/add-debug-link.py @@ -14,8 +14,7 @@ def add_debug_link_into_binaries(directory, target_cpu, debug_dir): add_debug_link_into_binary(binary_path, target_cpu, debug_dir) def add_debug_link_into_binary(binary_path, target_cpu, debug_dir): - if PLATFORM == 'linux' and (target_cpu == 'x86' or target_cpu == 'arm' or - target_cpu == 'arm64'): + if PLATFORM == 'linux' and target_cpu in ('x86', 'arm', 'arm64'): # Skip because no objcopy binary on the given target. return diff --git a/script/apply_all_patches.py b/script/apply_all_patches.py index c2e83bea7798a..5e35fc686ec7b 100755 --- a/script/apply_all_patches.py +++ b/script/apply_all_patches.py @@ -11,9 +11,10 @@ def apply_patches(dirs): threeway = os.environ.get("ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES") for patch_dir, repo in dirs.items(): - git.import_patches(repo=repo, patch_data=patch_from_dir(patch_dir), - threeway=threeway is not None, - committer_name="Electron Scripts", committer_email="scripts@electron") + if os.path.exists(repo): + git.import_patches(repo=repo, patch_data=patch_from_dir(patch_dir), + threeway=threeway is not None, + committer_name="Electron Scripts", committer_email="scripts@electron") def parse_args(): diff --git a/script/check-relative-doc-links.py b/script/check-relative-doc-links.py index 1b61e320ffbd3..f297253b6dd0e 100755 --- a/script/check-relative-doc-links.py +++ b/script/check-relative-doc-links.py @@ -23,7 +23,7 @@ def main(): filepaths.append(os.path.join(root, f)) except KeyboardInterrupt: print('Keyboard interruption. Please try again.') - return + return 0 totalBrokenLinks = 0 for path in filepaths: diff --git a/script/check-symlinks.js b/script/check-symlinks.js index db422bb6dc7e6..c68e2ac27eb82 100644 --- a/script/check-symlinks.js +++ b/script/check-symlinks.js @@ -2,13 +2,14 @@ const fs = require('fs'); const path = require('path'); const utils = require('./lib/utils'); +const branding = require('../shell/app/BRANDING.json'); if (process.platform !== 'darwin') { console.log('Not checking symlinks on non-darwin platform'); process.exit(0); } -const appPath = path.resolve(__dirname, '..', '..', 'out', utils.getOutDir(), 'Electron.app'); +const appPath = path.resolve(__dirname, '..', '..', 'out', utils.getOutDir(), `${branding.product_name}.app`); const visited = new Set(); const traverse = (p) => { if (visited.has(p)) return; diff --git a/script/copy-debug-symbols.py b/script/copy-debug-symbols.py index 3d321812b248e..0ceff1a0e2e3f 100755 --- a/script/copy-debug-symbols.py +++ b/script/copy-debug-symbols.py @@ -15,8 +15,7 @@ def copy_debug_from_binaries(directory, out_dir, target_cpu, compress): copy_debug_from_binary(binary_path, out_dir, target_cpu, compress) def copy_debug_from_binary(binary_path, out_dir, target_cpu, compress): - if PLATFORM == 'linux' and (target_cpu == 'x86' or target_cpu == 'arm' or - target_cpu == 'arm64'): + if PLATFORM == 'linux' and target_cpu in ('x86', 'arm', 'arm64'): # Skip because no objcopy binary on the given target. return debug_name = get_debug_name(binary_path) @@ -25,7 +24,6 @@ def copy_debug_from_binary(binary_path, out_dir, target_cpu, compress): cmd.extend(['--compress-debug-sections']) cmd.extend([binary_path, os.path.join(out_dir, debug_name)]) execute(cmd) - return debug_name def get_debug_name(binary_path): return os.path.basename(binary_path) + '.debug' diff --git a/script/generate-config-gypi.py b/script/generate-config-gypi.py index cf4be2af1d8a1..7a3ea6808b42a 100755 --- a/script/generate-config-gypi.py +++ b/script/generate-config-gypi.py @@ -14,9 +14,9 @@ def run_node_configure(target_cpu): configure = os.path.join(NODE_DIR, 'configure.py') args = ['--dest-cpu', target_cpu] - # Enabled in Chromium's V8. - if target_cpu == 'arm64' or target_cpu == 'x64': - args += ['--experimental-enable-pointer-compression'] + # Enabled in Chromium's V8, will be disabled on 32bit via + # common.gypi rules + args += ['--experimental-enable-pointer-compression'] # Work around "No acceptable ASM compiler found" error on some System, # it breaks nothing since Electron does not use OpenSSL. @@ -62,4 +62,4 @@ def main(target_file, target_cpu): f.write(pprint.pformat(config, indent=2)) if __name__ == '__main__': - sys.exit(main(*sys.argv[1:])) + sys.exit(main(sys.argv[1], sys.argv[2])) diff --git a/script/generate-zip-manifest.py b/script/generate-zip-manifest.py index 8fb232ea1a0d5..c7b6558f012f9 100755 --- a/script/generate-zip-manifest.py +++ b/script/generate-zip-manifest.py @@ -11,4 +11,4 @@ def main(zip_path, manifest_out): return 0 if __name__ == '__main__': - sys.exit(main(*sys.argv[1:])) + sys.exit(main(sys.argv[1], sys.argv[2])) diff --git a/script/gn-check.js b/script/gn-check.js index 497e6ec5f3cd8..12dca3651e723 100644 --- a/script/gn-check.js +++ b/script/gn-check.js @@ -18,10 +18,11 @@ if (!OUT_DIR) { throw new Error('No viable out dir: one of Debug, Testing, or Release must exist.'); } -const env = Object.assign({ +const env = { CHROMIUM_BUILDTOOLS_PATH: path.resolve(SOURCE_ROOT, '..', 'buildtools'), - DEPOT_TOOLS_WIN_TOOLCHAIN: '0' -}, process.env); + DEPOT_TOOLS_WIN_TOOLCHAIN: '0', + ...process.env +}; // Users may not have depot_tools in PATH. env.PATH = `${env.PATH}${path.delimiter}${DEPOT_TOOLS}`; diff --git a/script/lib/azput.js b/script/lib/azput.js index 0e6a75cd2ad8f..6abd0220db768 100644 --- a/script/lib/azput.js +++ b/script/lib/azput.js @@ -20,12 +20,7 @@ let anErrorOccurred = false; function next (done) { const file = files.shift(); if (!file) return done(); - let key = filenameToKey(file); - // TODO: When we drop s3put, migrate the key to not include atom-shell in the callsites - key = key.replace('atom-shell/dist/', 'headers/dist/'); - key = key.replace('atom-shell/symbols/', 'symbols/'); - key = key.replace('atom-shell/tmp/', 'checksums-scratchpad/'); - key = key.replace('electron-artifacts/', 'release-builds/'); + const key = filenameToKey(file); const [containerName, ...keyPath] = key.split('/'); const blobKey = keyPath.join('/'); diff --git a/script/lib/config.py b/script/lib/config.py index f50f56837ffcc..883a0374bc251 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -21,8 +21,6 @@ 'libGLESv2.so', 'libffmpeg.so', 'libvk_swiftshader.so', - 'swiftshader/libEGL.so', - 'swiftshader/libGLESv2.so', ] verbose_mode = False @@ -31,8 +29,8 @@ def get_platform_key(): if 'MAS_BUILD' in os.environ: return 'mas' - else: - return PLATFORM + + return PLATFORM def get_target_arch(): @@ -53,17 +51,6 @@ def get_env_var(name): return value -def s3_config(): - config = (get_env_var('S3_BUCKET'), - get_env_var('S3_ACCESS_KEY'), - get_env_var('S3_SECRET_KEY')) - message = ('Error: Please set the $ELECTRON_S3_BUCKET, ' - '$ELECTRON_S3_ACCESS_KEY, and ' - '$ELECTRON_S3_SECRET_KEY environment variables') - assert all(len(c) for c in config), message - return config - - def enable_verbose_mode(): print('Running in verbose mode') global verbose_mode diff --git a/script/lib/git.py b/script/lib/git.py index 811adfc6a1070..93e61e6757ad4 100644 --- a/script/lib/git.py +++ b/script/lib/git.py @@ -233,11 +233,16 @@ def to_utf8(patch): """Python 2/3 compatibility: unicode has been renamed to str in Python3""" if sys.version_info[0] >= 3: return str(patch, "utf-8") - else: - return unicode(patch, "utf-8") + + return unicode(patch, "utf-8") def export_patches(repo, out_dir, patch_range=None, dry_run=False): + if not os.path.exists(repo): + sys.stderr.write( + "Skipping patches in {} because it does not exist.\n".format(repo) + ) + return if patch_range is None: patch_range, num_patches = guess_base_commit(repo) sys.stderr.write("Exporting {} patches in {} since {}\n".format( @@ -268,7 +273,7 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False): out_dir, len(bad_patches), "\n-- ".join(bad_patches) ) ) - exit(1) + sys.exit(1) else: # Remove old patches so that deleted commits are correctly reflected in the # patch files (as a removed file) @@ -291,4 +296,3 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False): ) as f: f.write(formatted_patch.encode('utf-8')) pl.write(filename + '\n') - diff --git a/script/lib/native_tests.py b/script/lib/native_tests.py index e84f393848793..04858bf7ed132 100644 --- a/script/lib/native_tests.py +++ b/script/lib/native_tests.py @@ -69,7 +69,8 @@ def get_current(): if platform in ('cygwin', 'win32'): return Platform.WINDOWS - assert False, "unexpected current platform '{}'".format(platform) + raise AssertionError( + "unexpected current platform '{}'".format(platform)) @staticmethod def get_all(): @@ -155,7 +156,7 @@ def __expand_shorthand(value): if isinstance(value, basestring): return {value: None} - assert False, "unexpected shorthand type: {}".format(type(value)) + raise AssertionError("unexpected shorthand type: {}".format(type(value))) @staticmethod def __make_a_list(value): @@ -174,7 +175,8 @@ def __merge_nested_lists(value): # It looks ugly as hell, but it does the job. return [list_item for key in value for list_item in value[key]] - assert False, "unexpected type for list merging: {}".format(type(value)) + raise AssertionError( + "unexpected type for list merging: {}".format(type(value))) def __platform_supports(self, binary_name): return Platform.get_current() in self.tests[binary_name]['platforms'] diff --git a/script/lib/s3put.js b/script/lib/s3put.js deleted file mode 100644 index 8f92b6d95decf..0000000000000 --- a/script/lib/s3put.js +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable camelcase */ -const AWS = require('aws-sdk'); -const fs = require('fs'); -const path = require('path'); -AWS.config.update({ region: 'us-west-2' }); -const s3 = new AWS.S3({ apiVersion: '2006-03-01' }); - -const args = require('minimist')(process.argv.slice(2)); - -let { bucket, prefix = '/', key_prefix = '', grant, _: files } = args; -if (prefix && !prefix.endsWith(path.sep)) prefix = path.resolve(prefix) + path.sep; - -function filenameToKey (file) { - file = path.resolve(file); - if (file.startsWith(prefix)) file = file.substr(prefix.length - 1); - return key_prefix + (path.sep === '\\' ? file.replace(/\\/g, '/') : file); -} - -let anErrorOccurred = false; -function next (done) { - const file = files.shift(); - if (!file) return done(); - const key = filenameToKey(file); - console.log(`Uploading '${file}' to bucket '${bucket}' with key '${key}'...`); - s3.upload({ - Bucket: bucket, - Key: key, - Body: fs.createReadStream(file), - ACL: grant - }, (err, data) => { - if (err) { - console.error(err); - anErrorOccurred = true; - } - next(done); - }); -} -next(() => { - process.exit(anErrorOccurred ? 1 : 0); -}); diff --git a/script/lib/util.py b/script/lib/util.py index 93774128706b8..05d476e93ab26 100644 --- a/script/lib/util.py +++ b/script/lib/util.py @@ -1,18 +1,13 @@ #!/usr/bin/env python3 from __future__ import print_function -import atexit import contextlib import errno import json import os import shutil -import ssl -import stat import subprocess import sys -import tarfile -import tempfile # Python 3 / 2 compat import try: from urllib.request import urlopen @@ -20,7 +15,7 @@ from urllib2 import urlopen import zipfile -from lib.config import is_verbose_mode, s3_config +from lib.config import is_verbose_mode ELECTRON_DIR = os.path.abspath( os.path.dirname(os.path.dirname(os.path.dirname(__file__))) @@ -161,26 +156,9 @@ def get_electron_version(): return 'v' + f.read().strip() def store_artifact(prefix, key_prefix, files): - # Legacy S3 Bucket - s3put(prefix, key_prefix, files) - # New AZ Storage + # Azure Storage azput(prefix, key_prefix, files) -def s3put(prefix, key_prefix, files): - bucket, access_key, secret_key = s3_config() - env = os.environ.copy() - env['AWS_ACCESS_KEY_ID'] = access_key - env['AWS_SECRET_ACCESS_KEY'] = secret_key - output = execute([ - 'node', - os.path.join(os.path.dirname(__file__), 's3put.js'), - '--bucket', bucket, - '--prefix', prefix, - '--key_prefix', key_prefix, - '--grant', 'public-read', - ] + files, env) - print(output) - def azput(prefix, key_prefix, files): env = os.environ.copy() output = execute([ @@ -208,9 +186,9 @@ def get_electron_exec(): if sys.platform == 'darwin': return '{0}/Electron.app/Contents/MacOS/Electron'.format(out_dir) - elif sys.platform == 'win32': + if sys.platform == 'win32': return '{0}/electron.exe'.format(out_dir) - elif sys.platform == 'linux': + if sys.platform == 'linux': return '{0}/electron'.format(out_dir) raise Exception( @@ -223,6 +201,7 @@ def get_buildtools_executable(name): 'linux': 'linux64', 'linux2': 'linux64', 'win32': 'win', + 'cygwin': 'win', }[sys.platform] path = os.path.join(buildtools, chromium_platform, name) if sys.platform == 'win32': diff --git a/script/lib/utils.js b/script/lib/utils.js index 55f678b43ed1c..44c81dc86aca0 100644 --- a/script/lib/utils.js +++ b/script/lib/utils.js @@ -1,5 +1,6 @@ const { GitProcess } = require('dugite'); const fs = require('fs'); +const os = require('os'); const path = require('path'); const ELECTRON_DIR = path.resolve(__dirname, '..', '..'); @@ -95,7 +96,35 @@ async function getCurrentBranch (gitDir) { return branch.trim(); } +function chunkFilenames (filenames, offset = 0) { + // Windows has a max command line length of 2047 characters, so we can't + // provide too many filenames without going over that. To work around that, + // chunk up a list of filenames such that it won't go over that limit when + // used as args. Other platforms may have higher limits, but 4095 might be + // the limit on Linux systems according to `termios(3)`, so cap it there. + const MAX_FILENAME_ARGS_LENGTH = + (os.platform() === 'win32' ? 2047 : 4095) - offset; + + return filenames.reduce( + (chunkedFilenames, filename) => { + const currChunk = chunkedFilenames[chunkedFilenames.length - 1]; + const currChunkLength = currChunk.reduce( + (totalLength, _filename) => totalLength + _filename.length + 1, + 0 + ); + if (currChunkLength + filename.length + 1 > MAX_FILENAME_ARGS_LENGTH) { + chunkedFilenames.push([filename]); + } else { + currChunk.push(filename); + } + return chunkedFilenames; + }, + [[]] + ); +} + module.exports = { + chunkFilenames, getCurrentBranch, getElectronExec, getOutDir, diff --git a/script/lint.js b/script/lint.js index 5e7489ee8ddd6..dba460730776e 100755 --- a/script/lint.js +++ b/script/lint.js @@ -9,10 +9,17 @@ const klaw = require('klaw'); const minimist = require('minimist'); const path = require('path'); +const { chunkFilenames } = require('./lib/utils'); + const ELECTRON_ROOT = path.normalize(path.dirname(__dirname)); const SOURCE_ROOT = path.resolve(ELECTRON_ROOT, '..'); const DEPOT_TOOLS = path.resolve(SOURCE_ROOT, 'third_party', 'depot_tools'); +// Augment the PATH for this script so that we can find executables +// in the depot_tools folder even if folks do not have an instance of +// DEPOT_TOOLS in their path already +process.env.PATH = `${process.env.PATH}${path.delimiter}${DEPOT_TOOLS}`; + const IGNORELIST = new Set([ ['shell', 'browser', 'resources', 'win', 'resource.h'], ['shell', 'common', 'node_includes.h'], @@ -25,10 +32,10 @@ const IGNORELIST = new Set([ const IS_WINDOWS = process.platform === 'win32'; function spawnAndCheckExitCode (cmd, args, opts) { - opts = Object.assign({ stdio: 'inherit' }, opts); + opts = { stdio: 'inherit', ...opts }; const { error, status, signal } = childProcess.spawnSync(cmd, args, opts); if (error) { - // the subsprocess failed or timed out + // the subprocess failed or timed out console.error(error); process.exit(1); } @@ -44,7 +51,7 @@ function spawnAndCheckExitCode (cmd, args, opts) { } function cpplint (args) { - args.unshift(`--project_root=${SOURCE_ROOT}`); + args.unshift(`--root=${SOURCE_ROOT}`); const result = childProcess.spawnSync(IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py', args, { encoding: 'utf8', shell: true }); // cpplint.py writes EVERYTHING to stderr, including status messages if (result.stderr) { @@ -69,12 +76,11 @@ const LINTERS = [{ roots: ['shell'], test: filename => filename.endsWith('.cc') || (filename.endsWith('.h') && !isObjCHeader(filename)), run: (opts, filenames) => { - if (opts.fix) { - spawnAndCheckExitCode('python', ['script/run-clang-format.py', '--fix', ...filenames]); - } else { - spawnAndCheckExitCode('python', ['script/run-clang-format.py', ...filenames]); + const clangFormatFlags = opts.fix ? ['--fix'] : []; + for (const chunk of chunkFilenames(filenames)) { + spawnAndCheckExitCode('python3', ['script/run-clang-format.py', ...clangFormatFlags, ...chunk]); + cpplint(chunk); } - cpplint(filenames); } }, { key: 'objc', @@ -82,9 +88,9 @@ const LINTERS = [{ test: filename => filename.endsWith('.mm') || (filename.endsWith('.h') && isObjCHeader(filename)), run: (opts, filenames) => { if (opts.fix) { - spawnAndCheckExitCode('python', ['script/run-clang-format.py', '--fix', ...filenames]); + spawnAndCheckExitCode('python3', ['script/run-clang-format.py', '-r', '--fix', ...filenames]); } else { - spawnAndCheckExitCode('python', ['script/run-clang-format.py', ...filenames]); + spawnAndCheckExitCode('python3', ['script/run-clang-format.py', '-r', ...filenames]); } const filter = [ '-readability/braces', @@ -102,8 +108,8 @@ const LINTERS = [{ run: (opts, filenames) => { const rcfile = path.join(DEPOT_TOOLS, 'pylintrc'); const args = ['--rcfile=' + rcfile, ...filenames]; - const env = Object.assign({ PYTHONPATH: path.join(ELECTRON_ROOT, 'script') }, process.env); - spawnAndCheckExitCode('pylint', args, { env }); + const env = { PYTHONPATH: path.join(ELECTRON_ROOT, 'script'), ...process.env }; + spawnAndCheckExitCode('pylint-2.7', args, { env }); } }, { key: 'javascript', @@ -142,10 +148,11 @@ const LINTERS = [{ test: filename => filename.endsWith('.gn') || filename.endsWith('.gni'), run: (opts, filenames) => { const allOk = filenames.map(filename => { - const env = Object.assign({ + const env = { CHROMIUM_BUILDTOOLS_PATH: path.resolve(ELECTRON_ROOT, '..', 'buildtools'), - DEPOT_TOOLS_WIN_TOOLCHAIN: '0' - }, process.env); + DEPOT_TOOLS_WIN_TOOLCHAIN: '0', + ...process.env + }; // Users may not have depot_tools in PATH. env.PATH = `${env.PATH}${path.delimiter}${DEPOT_TOOLS}`; const args = ['format', filename]; @@ -172,7 +179,7 @@ const LINTERS = [{ run: (opts, filenames) => { const patchesDir = path.resolve(__dirname, '../patches'); const patchesConfig = path.resolve(patchesDir, 'config.json'); - // If the config does not exist, that's a proiblem + // If the config does not exist, that's a problem if (!fs.existsSync(patchesConfig)) { process.exit(1); } diff --git a/script/nan-spec-runner.js b/script/nan-spec-runner.js index 5bd0faa6da5e6..04c8459a085f3 100644 --- a/script/nan-spec-runner.js +++ b/script/nan-spec-runner.js @@ -18,38 +18,62 @@ const args = require('minimist')(process.argv.slice(2), { }); async function main () { - const nodeDir = path.resolve(BASE, `out/${utils.getOutDir({ shouldLog: true })}/gen/node_headers`); - const env = Object.assign({}, process.env, { + const outDir = utils.getOutDir({ shouldLog: true }); + const nodeDir = path.resolve(BASE, 'out', outDir, 'gen', 'node_headers'); + const env = { + ...process.env, npm_config_nodedir: nodeDir, npm_config_msvs_version: '2019', npm_config_arch: process.env.NPM_CONFIG_ARCH, npm_config_yes: 'true' - }); + }; const clangDir = path.resolve(BASE, 'third_party', 'llvm-build', 'Release+Asserts', 'bin'); const cc = path.resolve(clangDir, 'clang'); const cxx = path.resolve(clangDir, 'clang++'); const ld = path.resolve(clangDir, 'lld'); + const platformFlags = []; + if (process.platform === 'darwin') { + const sdkPath = path.resolve(BASE, 'out', outDir, 'sdk', 'xcode_links'); + const sdks = (await fs.promises.readdir(sdkPath)).filter(fileName => fileName.endsWith('.sdk')); + const sdkToUse = sdks[0]; + if (!sdkToUse) { + console.error('Could not find an SDK to use for the NAN tests'); + process.exit(1); + } + + if (sdks.length) { + console.warn(`Multiple SDKs found in the xcode_links directory - using ${sdkToUse}`); + } + + platformFlags.push( + `-isysroot ${path.resolve(sdkPath, sdkToUse)}` + ); + } + // TODO(ckerr) this is cribbed from read obj/electron/electron_app.ninja. // Maybe it would be better to have this script literally open up that // file and pull cflags_cc from it instead of using bespoke code here? // I think it's unlikely to work; but if it does, it would be more futureproof const cxxflags = [ - '-std=c++14', + '-std=c++17', '-nostdinc++', - `-isystem"${path.resolve(BASE, 'buildtools', 'third_party', 'libc++')}"`, + `-I"${path.resolve(BASE, 'buildtools', 'third_party', 'libc++')}"`, `-isystem"${path.resolve(BASE, 'buildtools', 'third_party', 'libc++', 'trunk', 'include')}"`, `-isystem"${path.resolve(BASE, 'buildtools', 'third_party', 'libc++abi', 'trunk', 'include')}"`, - '-fPIC' + '-fPIC', + '-D_LIBCPP_ABI_NAMESPACE=Cr', + ...platformFlags ].join(' '); const ldflags = [ '-stdlib=libc++', '-fuse-ld=lld', - `-L"${path.resolve(BASE, 'out', `${utils.getOutDir({ shouldLog: true })}`, 'obj', 'buildtools', 'third_party', 'libc++abi')}"`, - `-L"${path.resolve(BASE, 'out', `${utils.getOutDir({ shouldLog: true })}`, 'obj', 'buildtools', 'third_party', 'libc++')}"`, - '-lc++abi' + `-L"${path.resolve(BASE, 'out', outDir, 'obj', 'buildtools', 'third_party', 'libc++abi')}"`, + `-L"${path.resolve(BASE, 'out', outDir, 'obj', 'buildtools', 'third_party', 'libc++')}"`, + '-lc++abi', + ...platformFlags ].join(' '); if (process.platform !== 'win32') { @@ -66,6 +90,7 @@ async function main () { cwd: NAN_DIR, stdio: 'inherit' }); + if (buildStatus !== 0) { console.error('Failed to build nan test modules'); return process.exit(buildStatus); @@ -84,7 +109,8 @@ async function main () { const onlyTests = args.only && args.only.split(','); const DISABLED_TESTS = [ - 'nannew-test.js' + 'nannew-test.js', + 'buffer-test.js' ]; const testsToRun = fs.readdirSync(path.resolve(NAN_DIR, 'test', 'js')) .filter(test => !DISABLED_TESTS.includes(test)) diff --git a/script/native-tests.py b/script/native-tests.py index 9c2bdc00859ee..7a577bc75f434 100755 --- a/script/native-tests.py +++ b/script/native-tests.py @@ -97,11 +97,11 @@ def main(): if args.binary is not None: return tests_list.run(args.binary, args.output_dir, args.verbosity, args.disabled_tests_policy) - else: - return tests_list.run_all(args.output_dir, args.verbosity, - args.disabled_tests_policy) - assert False, "unexpected command '{}'".format(args.command) + return tests_list.run_all(args.output_dir, args.verbosity, + args.disabled_tests_policy) + + raise AssertionError("unexpected command '{}'".format(args.command)) if __name__ == '__main__': diff --git a/script/node-disabled-tests.json b/script/node-disabled-tests.json index 41cb1a8794c01..1cec1b9e230f1 100644 --- a/script/node-disabled-tests.json +++ b/script/node-disabled-tests.json @@ -4,7 +4,6 @@ "async-hooks/test-crypto-randomBytes", "parallel/test-bootstrap-modules", "parallel/test-child-process-fork-exec-path", - "parallel/test-child-process-stdio-overlapped", "parallel/test-cli-node-print-help", "parallel/test-cluster-bind-privileged-port", "parallel/test-cluster-shared-handle-bind-privileged-port", @@ -14,16 +13,14 @@ "parallel/test-crypto-des3-wrap", "parallel/test-crypto-dh-stateless", "parallel/test-crypto-ecb", - "parallel/test-crypto-engine", "parallel/test-crypto-fips", - "parallel/test-crypto-hkdf.js", "parallel/test-crypto-keygen", "parallel/test-crypto-keygen-deprecation", "parallel/test-crypto-key-objects", "parallel/test-crypto-padding-aes256", "parallel/test-crypto-secure-heap", "parallel/test-fs-utimes-y2K38", - "parallel/test-heapsnapshot-near-heap-limit-worker.js", + "parallel/test-heapsnapshot-near-heap-limit-worker", "parallel/test-http2-clean-output", "parallel/test-https-agent-session-reuse", "parallel/test-https-options-boolean-check", @@ -98,14 +95,12 @@ "parallel/test-trace-events-fs-sync", "parallel/test-trace-events-metadata", "parallel/test-trace-events-none", - "parallel/test-trace-events-perf", "parallel/test-trace-events-process-exit", "parallel/test-trace-events-promises", "parallel/test-trace-events-v8", "parallel/test-trace-events-vm", "parallel/test-trace-events-worker-metadata", "parallel/test-v8-untrusted-code-mitigations", - "parallel/test-webcrypto-derivebits-hkdf", "parallel/test-webcrypto-derivebits-node-dh", "parallel/test-webcrypto-ed25519-ed448", "parallel/test-webcrypto-encrypt-decrypt", @@ -126,6 +121,9 @@ "report/test-report-uv-handles", "report/test-report-worker", "report/test-report-writereport", + "sequential/test-cpu-prof-kill", + "sequential/test-diagnostic-dir-cpu-prof", + "sequential/test-cpu-prof-drained", "sequential/test-tls-connect", "wpt/test-webcrypto" ] diff --git a/script/node-spec-runner.js b/script/node-spec-runner.js index 340ff1d9f63b7..570a4d00dfe3e 100644 --- a/script/node-spec-runner.js +++ b/script/node-spec-runner.js @@ -3,7 +3,7 @@ const fs = require('fs'); const path = require('path'); const args = require('minimist')(process.argv.slice(2), { - boolean: ['default'], + boolean: ['default', 'validateDisabled'], string: ['jUnitDir'] }); @@ -28,6 +28,7 @@ const defaultOptions = [ '--mode=debug', 'default', `--skip-tests=${DISABLED_TESTS.join(',')}`, + '--flaky-tests=dontcare', '--shell', utils.getAbsoluteElectronExec(), '-J' @@ -42,8 +43,7 @@ const getCustomOptions = () => { customOptions = customOptions.concat(extra); } - // We need this unilaterally or Node.js will try - // to run from out/Release/node. + // Necessary or Node.js will try to run from out/Release/node. customOptions = customOptions.concat([ '--shell', utils.getAbsoluteElectronExec() @@ -53,9 +53,25 @@ const getCustomOptions = () => { }; async function main () { + // Optionally validate that all disabled specs still exist. + if (args.validateDisabled) { + const missing = []; + for (const test of DISABLED_TESTS) { + const testName = test.endsWith('.js') ? test : `${test}.js`; + if (!fs.existsSync(path.join(NODE_DIR, 'test', testName))) { + missing.push(test); + } + } + + if (missing.length > 0) { + console.error(`Found ${missing.length} missing disabled specs: \n${missing.join('\n')}`); + process.exit(1); + } + } + const options = args.default ? defaultOptions : getCustomOptions(); - const testChild = cp.spawn('python', options, { + const testChild = cp.spawn('python3', options, { env: { ...process.env, ELECTRON_RUN_AS_NODE: 'true', diff --git a/script/release/ci-release-build.js b/script/release/ci-release-build.js index 57f1e0b5d98c6..ef3616374b4c8 100644 --- a/script/release/ci-release-build.js +++ b/script/release/ci-release-build.js @@ -2,11 +2,10 @@ if (!process.env.CI) require('dotenv-safe').load(); const assert = require('assert'); const got = require('got'); +const { Octokit } = require('@octokit/rest'); const BUILD_APPVEYOR_URL = 'https://ci.appveyor.com/api/builds'; const CIRCLECI_PIPELINE_URL = 'https://circleci.com/api/v2/project/gh/electron/electron/pipeline'; -const VSTS_URL = 'https://github.visualstudio.com/electron/_apis/build'; -const DEVOPS_URL = 'https://dev.azure.com/electron-ci/electron/_apis/build'; const CIRCLECI_WAIT_TIME = process.env.CIRCLECI_WAIT_TIME || 30000; const appVeyorJobs = { @@ -22,32 +21,34 @@ const circleCIPublishWorkflows = [ const circleCIPublishIndividualArches = { 'macos-publish': ['osx-x64', 'mas-x64', 'osx-arm64', 'mas-arm64'], - 'linux-publish': ['arm', 'arm64', 'ia32', 'x64'] + 'linux-publish': ['arm', 'arm64', 'x64'] }; -const vstsArmJobs = [ - 'electron-arm-testing', - 'electron-osx-arm64-testing', - 'electron-mas-arm64-testing', - 'electron-arm64-testing', - 'electron-woa-testing' -]; +const GHAJobs = ['electron-woa-testing']; let jobRequestedCount = 0; -async function makeRequest ({ auth, url, headers, body, method }) { +async function makeRequest ({ auth, username, password, url, headers, body, method }) { const clonedHeaders = { ...(headers || {}) }; - if (auth && auth.bearer) { + if (auth?.bearer) { clonedHeaders.Authorization = `Bearer ${auth.bearer}`; } - const response = await got(url, { + + const options = { headers: clonedHeaders, body, - method, - auth: auth && (auth.username || auth.password) ? `${auth.username}:${auth.password}` : undefined - }); + method + }; + + if (username || password) { + options.username = username; + options.password = password; + } + + const response = await got(url, options); + if (response.statusCode < 200 || response.statusCode >= 300) { console.error('Error: ', `(status ${response.statusCode})`, response.body); throw new Error(`Unexpected status code ${response.statusCode} from ${url}`); @@ -62,9 +63,9 @@ async function circleCIcall (targetBranch, workflowName, options) { parameters: {} }; if (options.ghRelease) { - buildRequest.parameters['upload-to-s3'] = '0'; + buildRequest.parameters['upload-to-storage'] = '0'; } else { - buildRequest.parameters['upload-to-s3'] = '1'; + buildRequest.parameters['upload-to-storage'] = '1'; } buildRequest.parameters[`run-${workflowName}`] = true; if (options.arch) { @@ -115,7 +116,7 @@ async function getCircleCIWorkflowId (pipelineId) { workflowId = workflows.items.find(item => item.name.includes('publish')).id; break; } - console.log('Unxpected number of workflows, response was:', workflows); + console.log('Unexpected number of workflows, response was:', workflows); workflowId = -1; break; } @@ -139,7 +140,7 @@ async function getCircleCIJobNumber (workflowId) { continue; } if (jobInfo.items.length !== 1) { - console.log('Unxpected number of jobs, response was:', jobInfo); + console.log('Unexpected number of jobs, response was:', jobInfo); jobNumber = -1; break; } @@ -170,19 +171,21 @@ async function getCircleCIJobNumber (workflowId) { } async function circleCIRequest (url, method, requestBody) { - return makeRequest({ - auth: { - username: process.env.CIRCLE_TOKEN, - password: '' - }, + const requestOpts = { + username: process.env.CIRCLE_TOKEN, + password: '', method, url, headers: { 'Content-Type': 'application/json', Accept: 'application/json' - }, - body: requestBody ? JSON.stringify(requestBody) : null - }, true).catch(err => { + } + }; + if (requestBody) { + requestOpts.body = JSON.stringify(requestBody); + } + + return makeRequest(requestOpts, true).catch(err => { console.log('Error calling CircleCI:', err); }); } @@ -205,7 +208,7 @@ async function callAppVeyor (targetBranch, job, options) { }; if (!options.ghRelease) { - environmentVariables.UPLOAD_TO_S3 = 1; + environmentVariables.UPLOAD_TO_STORAGE = 1; } const requestOpts = { @@ -247,75 +250,28 @@ function buildCircleCI (targetBranch, options) { } } -async function buildVSTS (targetBranch, options) { - assert(options.armTest, `${options.ci} only works with the --armTest option.`); - assert(vstsArmJobs.includes(options.job), `Unknown VSTS CI arm test job name: ${options.job}. Valid values are: ${vstsArmJobs}.`); +async function buildGHA (targetBranch, options) { + const { GHA_TOKEN } = process.env; + assert(GHA_TOKEN, `${options.ci} requires the $GHA_TOKEN environment variable to be provided`); - console.log(`Triggering VSTS to run build on branch: ${targetBranch}.`); - const environmentVariables = {}; + const octokit = new Octokit({ auth: GHA_TOKEN }); - if (options.circleBuildNum) { - environmentVariables.CIRCLE_BUILD_NUM = options.circleBuildNum; - } else if (options.appveyorJobId) { - environmentVariables.APPVEYOR_JOB_ID = options.appveyorJobId; - } + assert(GHAJobs.includes(options.job), `Unknown GitHub Actions arm test job name: ${options.job}. Valid values are: ${GHAJobs}.`); + assert(options.commit !== null, 'commit is a required option for GitHub Actions'); - let vstsURL = VSTS_URL; - let vstsToken = process.env.VSTS_TOKEN; - assert(vstsToken, `${options.ci} requires the $VSTS_TOKEN environment variable to be provided`); - if (options.ci === 'DevOps') { - vstsURL = DEVOPS_URL; - vstsToken = process.env.DEVOPS_TOKEN; - } - const requestOpts = { - url: `${vstsURL}/definitions?api-version=4.1`, - auth: { - user: '', - password: vstsToken - }, - headers: { - 'Content-Type': 'application/json' - } - }; + console.log(`Triggering GitHub Actions to run build on branch: ${targetBranch}.`); jobRequestedCount++; try { - const vstsResponse = await makeRequest(requestOpts, true); - const buildToRun = vstsResponse.value.find(build => build.name === options.job); - callVSTSBuild(buildToRun, targetBranch, environmentVariables, vstsURL, vstsToken); - } catch (err) { - console.log('Problem calling VSTS to get build definitions: ', err); - } -} - -async function callVSTSBuild (build, targetBranch, environmentVariables, vstsURL, vstsToken) { - const buildBody = { - definition: build, - sourceBranch: targetBranch, - priority: 'high' - }; - if (Object.keys(environmentVariables).length !== 0) { - buildBody.parameters = JSON.stringify(environmentVariables); - } - const requestOpts = { - url: `${vstsURL}/builds?api-version=4.1`, - auth: { - user: '', - password: vstsToken - }, - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(buildBody), - method: 'POST' - }; - - try { - const { _links } = await makeRequest(requestOpts, true); - console.log(`VSTS release build request for ${build.name} successful. Check ${_links.web.href} for status.`); + const response = await octokit.request('POST /repos/electron/electron/actions/workflows/electron_woa_testing.yml/dispatches', { + ref: targetBranch, + inputs: { + appveyor_job_id: `${options.appveyorJobId}` + } + }); } catch (err) { - console.log(`Could not call VSTS for job ${build.name}: `, err); + console.log('Problem calling GitHub Actions to get build definitions: ', err); } } @@ -330,9 +286,8 @@ function runRelease (targetBranch, options) { buildAppVeyor(targetBranch, options); break; } - case 'DevOps': - case 'VSTS': { - buildVSTS(targetBranch, options); + case 'GHA': { + buildGHA(targetBranch, options); break; } default: { @@ -351,13 +306,13 @@ module.exports = runRelease; if (require.main === module) { const args = require('minimist')(process.argv.slice(2), { - boolean: ['ghRelease', 'armTest'] + boolean: ['ghRelease'] }); const targetBranch = args._[0]; if (args._.length < 1) { console.log(`Trigger CI to build release builds of electron. - Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=CircleCI|AppVeyor|VSTS|DevOps] - [--ghRelease] [--armTest] [--circleBuildNum=xxx] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH + Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=CircleCI|AppVeyor|GHA] + [--ghRelease] [--circleBuildNum=xxx] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH `); process.exit(0); } diff --git a/script/release/get-url-hash.js b/script/release/get-url-hash.js index 0633567a7dd90..ae91fac30e526 100644 --- a/script/release/get-url-hash.js +++ b/script/release/get-url-hash.js @@ -1,34 +1,25 @@ -const AWS = require('aws-sdk'); - -const lambda = new AWS.Lambda({ - credentials: { - accessKeyId: process.env.AWS_LAMBDA_EXECUTE_KEY, - secretAccessKey: process.env.AWS_LAMBDA_EXECUTE_SECRET - }, - region: 'us-east-1' -}); +const got = require('got'); +const url = require('url'); module.exports = async function getUrlHash (targetUrl, algorithm = 'sha256', attempts = 3) { + const options = { + code: process.env.ELECTRON_ARTIFACT_HASHER_FUNCTION_KEY, + targetUrl, + algorithm + }; + const search = new url.URLSearchParams(options); + const functionUrl = url.format({ + protocol: 'https:', + hostname: 'electron-artifact-hasher.azurewebsites.net', + pathname: '/api/HashArtifact', + search: search.toString() + }); try { - return new Promise((resolve, reject) => { - lambda.invoke({ - FunctionName: 'hasher', - Payload: JSON.stringify({ - targetUrl, - algorithm - }) - }, (err, data) => { - if (err) return reject(err); - try { - const response = JSON.parse(data.Payload); - if (response.statusCode !== 200) return reject(new Error('non-200 status code received from hasher function')); - if (!response.hash) return reject(new Error('Successful lambda call but failed to get valid hash')); - resolve(response.hash); - } catch (err) { - return reject(err); - } - }); - }); + const resp = await got(functionUrl); + if (resp.statusCode !== 200) throw new Error('non-200 status code received from hasher function'); + if (!resp.body) throw new Error('Successful lambda call but failed to get valid hash'); + + return resp.body.trim(); } catch (err) { if (attempts > 1) { console.error('Failed to get URL hash for', targetUrl, 'we will retry', err); diff --git a/script/release/notes/index.js b/script/release/notes/index.js index 79d512218343f..a3ff8d267b0c7 100755 --- a/script/release/notes/index.js +++ b/script/release/notes/index.js @@ -133,7 +133,7 @@ const getPreviousPoint = async (point) => { console.log('error', error); } - // Otherwise, use the newest stable release that preceeds this branch. + // Otherwise, use the newest stable release that precedes this branch. // To reach that you may have to walk past >1 branch, e.g. to get past // 2-1-x which never had a stable release. let branch = currentBranch; @@ -147,7 +147,7 @@ const getPreviousPoint = async (point) => { } }; -async function getReleaseNotes (range, newVersion) { +async function getReleaseNotes (range, newVersion, unique) { const rangeList = range.split('..') || ['HEAD']; const to = rangeList.pop(); const from = rangeList.pop() || (await getPreviousPoint(to)); @@ -158,7 +158,7 @@ async function getReleaseNotes (range, newVersion) { const notes = await notesGenerator.get(from, to, newVersion); const ret = { - text: notesGenerator.render(notes) + text: notesGenerator.render(notes, unique) }; if (notes.unknown.length) { @@ -170,7 +170,7 @@ async function getReleaseNotes (range, newVersion) { async function main () { const opts = minimist(process.argv.slice(2), { - boolean: ['help'], + boolean: ['help', 'unique'], string: ['version'] }); opts.range = opts._.shift(); @@ -179,13 +179,14 @@ async function main () { console.log(` easy usage: ${name} version -full usage: ${name} [begin..]end [--version version] +full usage: ${name} [begin..]end [--version version] [--unique] * 'begin' and 'end' are two git references -- tags, branches, etc -- from which the release notes are generated. * if omitted, 'begin' defaults to the previous tag in end's branch. * if omitted, 'version' defaults to 'end'. Specifying a version is useful if you're making notes on a new version that isn't tagged yet. + * '--unique' omits changes that also landed in other branches. For example, these invocations are equivalent: ${process.argv[1]} v4.0.1 @@ -194,7 +195,7 @@ For example, these invocations are equivalent: return 0; } - const notes = await getReleaseNotes(opts.range, opts.version); + const notes = await getReleaseNotes(opts.range, opts.version, opts.unique); console.log(notes.text); if (notes.warning) { throw new Error(notes.warning); diff --git a/script/release/notes/notes.js b/script/release/notes/notes.js index 08579c100991c..7bc3d525d7eb1 100644 --- a/script/release/notes/notes.js +++ b/script/release/notes/notes.js @@ -410,7 +410,7 @@ const getNotes = async (fromRef, toRef, newVersion) => { // remove any old commits pool.commits = pool.commits.filter(commit => !pool.processedHashes.has(commit.hash)); - // if a commmit _and_ revert occurred in the unprocessed set, skip them both + // if a commit _and_ revert occurred in the unprocessed set, skip them both for (const commit of pool.commits) { const revertHash = commit.revertHash; if (!revertHash) { @@ -596,10 +596,14 @@ function renderDescription (commit) { const renderNote = (commit, excludeBranch) => `* ${renderDescription(commit)} ${renderLink(commit)} ${renderTrops(commit, excludeBranch)}\n`; -const renderNotes = (notes) => { +const renderNotes = (notes, unique = false) => { const rendered = [`# Release Notes for ${notes.name}\n\n`]; - const renderSection = (title, commits) => { + const renderSection = (title, commits, unique) => { + if (unique) { + // omit changes that also landed in other branches + commits = commits.filter((commit) => renderTrops(commit, notes.toBranch).length === 0); + } if (commits.length > 0) { rendered.push( `## ${title}\n\n`, @@ -608,17 +612,17 @@ const renderNotes = (notes) => { } }; - renderSection('Breaking Changes', notes.breaking); - renderSection('Features', notes.feat); - renderSection('Fixes', notes.fix); - renderSection('Other Changes', notes.other); + renderSection('Breaking Changes', notes.breaking, unique); + renderSection('Features', notes.feat, unique); + renderSection('Fixes', notes.fix, unique); + renderSection('Other Changes', notes.other, unique); if (notes.docs.length) { const docs = notes.docs.map(commit => renderLink(commit)).sort(); rendered.push('## Documentation\n\n', ` * Documentation changes: ${docs.join(', ')}\n`, '\n'); } - renderSection('Unknown', notes.unknown); + renderSection('Unknown', notes.unknown, unique); return rendered.join(''); }; diff --git a/script/release/publish-to-npm.js b/script/release/publish-to-npm.js index 55799665a57ad..081274d83edac 100644 --- a/script/release/publish-to-npm.js +++ b/script/release/publish-to-npm.js @@ -167,7 +167,7 @@ new Promise((resolve, reject) => { const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${rootPackageJson.version}.tgz`); return new Promise((resolve, reject) => { const result = childProcess.spawnSync('npm', ['install', tarballPath, '--force', '--silent'], { - env: Object.assign({}, process.env, { electron_config_cache: tempDir }), + env: { ...process.env, electron_config_cache: tempDir }, cwd: tempDir, stdio: 'inherit' }); diff --git a/script/release/release.js b/script/release/release.js index ceba04b340dd8..c3c8d6363b120 100755 --- a/script/release/release.js +++ b/script/release/release.js @@ -38,10 +38,7 @@ async function getDraftRelease (version, skipValidation) { const releaseInfo = await octokit.repos.listReleases({ owner: 'electron', repo: targetRepo - }).catch(err => { - console.error(`Failed to fetch releases: ${err}`); }); - console.log('releaseInfo: ', releaseInfo); const versionToCheck = version || pkgVersion; const drafts = releaseInfo.data.filter(release => { @@ -49,7 +46,6 @@ async function getDraftRelease (version, skipValidation) { }); const draft = drafts[0]; - console.log('drafts: ', drafts); if (!skipValidation) { failureCount = 0; check(drafts.length === 1, 'one draft exists', true); @@ -82,8 +78,6 @@ async function validateReleaseAssets (release, validatingRelease) { console.log(`${fail} error verifyingShasums`, err); }); } - const s3RemoteFiles = s3RemoteFilesForVersion(release.tag_name); - await verifyShasumsForRemoteFiles(s3RemoteFiles, true); const azRemoteFiles = azRemoteFilesForVersion(release.tag_name); await verifyShasumsForRemoteFiles(azRemoteFiles, true); } @@ -105,7 +99,6 @@ function assetsForVersion (version, validatingRelease) { `chromedriver-${version}-darwin-arm64.zip`, `chromedriver-${version}-linux-arm64.zip`, `chromedriver-${version}-linux-armv7l.zip`, - `chromedriver-${version}-linux-ia32.zip`, `chromedriver-${version}-linux-x64.zip`, `chromedriver-${version}-mas-x64.zip`, `chromedriver-${version}-mas-arm64.zip`, @@ -124,8 +117,6 @@ function assetsForVersion (version, validatingRelease) { `electron-${version}-linux-arm64.zip`, `electron-${version}-linux-armv7l-symbols.zip`, `electron-${version}-linux-armv7l.zip`, - `electron-${version}-linux-ia32-symbols.zip`, - `electron-${version}-linux-ia32.zip`, `electron-${version}-linux-x64-debug.zip`, `electron-${version}-linux-x64-symbols.zip`, `electron-${version}-linux-x64.zip`, @@ -153,13 +144,11 @@ function assetsForVersion (version, validatingRelease) { 'libcxxabi_headers.zip', `libcxx-objects-${version}-linux-arm64.zip`, `libcxx-objects-${version}-linux-armv7l.zip`, - `libcxx-objects-${version}-linux-ia32.zip`, `libcxx-objects-${version}-linux-x64.zip`, `ffmpeg-${version}-darwin-x64.zip`, `ffmpeg-${version}-darwin-arm64.zip`, `ffmpeg-${version}-linux-arm64.zip`, `ffmpeg-${version}-linux-armv7l.zip`, - `ffmpeg-${version}-linux-ia32.zip`, `ffmpeg-${version}-linux-x64.zip`, `ffmpeg-${version}-mas-x64.zip`, `ffmpeg-${version}-mas-arm64.zip`, @@ -170,7 +159,6 @@ function assetsForVersion (version, validatingRelease) { `mksnapshot-${version}-darwin-arm64.zip`, `mksnapshot-${version}-linux-arm64-x64.zip`, `mksnapshot-${version}-linux-armv7l-x64.zip`, - `mksnapshot-${version}-linux-ia32.zip`, `mksnapshot-${version}-linux-x64.zip`, `mksnapshot-${version}-mas-x64.zip`, `mksnapshot-${version}-mas-arm64.zip`, @@ -204,15 +192,6 @@ const cloudStoreFilePaths = (version) => [ 'SHASUMS256.txt' ]; -function s3RemoteFilesForVersion (version) { - const bucket = 'https://gh-contractor-zcbenz.s3.amazonaws.com/'; - const versionPrefix = `${bucket}atom-shell/dist/${version}/`; - return cloudStoreFilePaths(version).map((filePath) => ({ - file: filePath, - url: `${versionPrefix}${filePath}` - })); -} - function azRemoteFilesForVersion (version) { const azCDN = 'https://artifacts.electronjs.org/headers/'; const versionPrefix = `${azCDN}dist/${version}/`; diff --git a/script/release/uploaders/upload-index-json.py b/script/release/uploaders/upload-index-json.py index e90eed678c028..348023cf2cbd3 100755 --- a/script/release/uploaders/upload-index-json.py +++ b/script/release/uploaders/upload-index-json.py @@ -59,7 +59,7 @@ def main(): with open(index_json, "wb") as f: f.write(new_content) - store_artifact(OUT_DIR, 'atom-shell/dist', [index_json]) + store_artifact(OUT_DIR, 'headers/dist', [index_json]) if __name__ == '__main__': diff --git a/script/release/uploaders/upload-node-checksums.py b/script/release/uploaders/upload-node-checksums.py index 7df8bc1468c8f..6e36ca30d2a07 100755 --- a/script/release/uploaders/upload-node-checksums.py +++ b/script/release/uploaders/upload-node-checksums.py @@ -29,7 +29,7 @@ def main(): ] if args.target_dir is None: - store_artifact(directory, 'atom-shell/dist/{0}'.format(args.version), + store_artifact(directory, 'headers/dist/{0}'.format(args.version), checksums) else: copy_files(checksums, args.target_dir) diff --git a/script/release/uploaders/upload-node-headers.py b/script/release/uploaders/upload-node-headers.py index 77b72ae1d61a2..d70a5b704ac2a 100755 --- a/script/release/uploaders/upload-node-headers.py +++ b/script/release/uploaders/upload-node-headers.py @@ -45,9 +45,9 @@ def upload_node(version): versioned_header_tar = header_tar.format(version) shutil.copy2(generated_tar, os.path.join(GEN_DIR, versioned_header_tar)) - store_artifact(GEN_DIR, 'atom-shell/dist/{0}'.format(version), + store_artifact(GEN_DIR, 'headers/dist/{0}'.format(version), glob.glob('node-*.tar.gz')) - store_artifact(GEN_DIR, 'atom-shell/dist/{0}'.format(version), + store_artifact(GEN_DIR, 'headers/dist/{0}'.format(version), glob.glob('iojs-*.tar.gz')) if PLATFORM == 'win32': @@ -73,13 +73,13 @@ def upload_node(version): shutil.copy2(electron_lib, v4_node_lib) # Upload the node.lib. - store_artifact(DIST_DIR, 'atom-shell/dist/{0}'.format(version), [node_lib]) + store_artifact(DIST_DIR, 'headers/dist/{0}'.format(version), [node_lib]) # Upload the iojs.lib. - store_artifact(DIST_DIR, 'atom-shell/dist/{0}'.format(version), [iojs_lib]) + store_artifact(DIST_DIR, 'headers/dist/{0}'.format(version), [iojs_lib]) # Upload the v4 node.lib. - store_artifact(DIST_DIR, 'atom-shell/dist/{0}'.format(version), + store_artifact(DIST_DIR, 'headers/dist/{0}'.format(version), [v4_node_lib]) diff --git a/script/release/uploaders/upload-symbols.py b/script/release/uploaders/upload-symbols.py index 402cb4b2d31c1..bb0286777e0ec 100755 --- a/script/release/uploaders/upload-symbols.py +++ b/script/release/uploaders/upload-symbols.py @@ -56,7 +56,7 @@ def main(): files += glob.glob(SYMBOLS_DIR + '/*/*/*.src.zip') - # The file upload needs to be atom-shell/symbols/:symbol_name/:hash/:symbol + # The file upload needs to be symbols/:symbol_name/:hash/:symbol os.chdir(SYMBOLS_DIR) files = [os.path.relpath(f, os.getcwd()) for f in files] @@ -84,7 +84,7 @@ def run_symstore(pdb, dest, product): def upload_symbols(files): - store_artifact(SYMBOLS_DIR, 'atom-shell/symbols', + store_artifact(SYMBOLS_DIR, 'symbols', files) diff --git a/script/release/uploaders/upload.py b/script/release/uploaders/upload.py index 863a76790a4fe..5845b88ede1b4 100755 --- a/script/release/uploaders/upload.py +++ b/script/release/uploaders/upload.py @@ -47,7 +47,7 @@ def main(): args = parse_args() if args.verbose: enable_verbose_mode() - if args.upload_to_s3: + if args.upload_to_storage: utcnow = datetime.datetime.utcnow() args.upload_timestamp = utcnow.strftime('%Y%m%d') @@ -64,7 +64,7 @@ def main(): if not release['draft']: tag_exists = True - if not args.upload_to_s3: + if not args.upload_to_storage: assert release['exists'], \ 'Release does not exist; cannot upload to GitHub!' assert tag_exists == args.overwrite, \ @@ -91,9 +91,9 @@ def main(): shutil.copy2(os.path.join(OUT_DIR, 'dsym.zip'), dsym_zip) upload_electron(release, dsym_zip, args) - dsym_snaphot_zip = os.path.join(OUT_DIR, DSYM_SNAPSHOT_NAME) - shutil.copy2(os.path.join(OUT_DIR, 'dsym-snapshot.zip'), dsym_snaphot_zip) - upload_electron(release, dsym_snaphot_zip, args) + dsym_snapshot_zip = os.path.join(OUT_DIR, DSYM_SNAPSHOT_NAME) + shutil.copy2(os.path.join(OUT_DIR, 'dsym-snapshot.zip'), dsym_snapshot_zip) + upload_electron(release, dsym_snapshot_zip, args) elif PLATFORM == 'win32': pdb_zip = os.path.join(OUT_DIR, PDB_NAME) shutil.copy2(os.path.join(OUT_DIR, 'pdb.zip'), pdb_zip) @@ -146,7 +146,7 @@ def main(): OUT_DIR, 'hunspell_dictionaries.zip') upload_electron(release, hunspell_dictionaries_zip, args) - if not tag_exists and not args.upload_to_s3: + if not tag_exists and not args.upload_to_storage: # Upload symbols to symbol server. run_python_upload_script('upload-symbols.py') if PLATFORM == 'win32': @@ -160,6 +160,8 @@ def main(): 'toolchain_profile.json') upload_electron(release, toolchain_profile_zip, args) + return 0 + def parse_args(): parser = argparse.ArgumentParser(description='upload distribution file') parser.add_argument('-v', '--version', help='Specify the version', @@ -170,9 +172,9 @@ def parse_args(): parser.add_argument('-p', '--publish-release', help='Publish the release', action='store_true') - parser.add_argument('-s', '--upload_to_s3', - help='Upload assets to s3 bucket', - dest='upload_to_s3', + parser.add_argument('-s', '--upload_to_storage', + help='Upload assets to azure bucket', + dest='upload_to_storage', action='store_true', default=False, required=False) @@ -205,7 +207,8 @@ def zero_zip_date_time(fname): try: with open(fname, 'r+b') as f: _zero_zip_date_time(f) - except: + except Exception: + # pylint: disable=W0707 raise NonZipFileError(fname) @@ -225,7 +228,7 @@ def purify_extra_data(mm, offset, length, compressed_size=0): ZIP64_EXTRA_HEADER = 0x0001 zip64_extra_struct = Struct(" { - const currChunk = chunkedFilenames[chunkedFilenames.length - 1]; - const currChunkLength = currChunk.reduce( - (totalLength, _filename) => totalLength + _filename.length + 1, - 0 - ); - if (currChunkLength + filename.length + 1 > MAX_FILENAME_ARGS_LENGTH) { - chunkedFilenames.push([filename]); - } else { - currChunk.push(filename); - } - return chunkedFilenames; - }, - [[]] - ); -} - async function runClangTidy ( outDir: string, filenames: string[], @@ -143,7 +117,7 @@ async function runClangTidy ( jobs: number = 1 ): Promise { const cmd = path.resolve(LLVM_BIN, 'clang-tidy'); - const args = [`-p=${outDir}`]; + const args = [`-p=${outDir}`, '--use-color']; if (checks) args.push(`--checks=${checks}`); @@ -199,41 +173,10 @@ async function runClangTidy ( const worker = async () => { let filenames = chunkedFilenames.shift(); - while (filenames) { + while (filenames?.length) { results.push( await spawnAsync(cmd, [...args, ...filenames], {}).then((result) => { - // We lost color, so recolorize because it's much more legible - // There's a --use-color flag for clang-tidy but it has no effect - // on Windows at the moment, so just recolor for everyone - let state = null; - - for (const line of result.stdout.split('\n')) { - if (line.includes(' warning: ')) { - console.log( - line - .split(' warning: ') - .map((part) => chalk.whiteBright(part)) - .join(chalk.magentaBright(' warning: ')) - ); - state = 'code-line'; - } else if (line.includes(' note: ')) { - const lineParts = line.split(' note: '); - lineParts[0] = chalk.whiteBright(lineParts[0]); - console.log(lineParts.join(chalk.grey(' note: '))); - state = 'code-line'; - } else if (line.startsWith('error:')) { - console.log( - chalk.redBright('error: ') + line.split(' ').slice(1).join(' ') - ); - } else if (state === 'code-line') { - console.log(line); - state = 'post-code-line'; - } else if (state === 'post-code-line') { - console.log(chalk.greenBright(line)); - } else { - console.log(line); - } - } + console.log(result.stdout); if (result.status !== 0) { console.error(result.stderr); @@ -304,7 +247,7 @@ function parseCommandLine () { if (opts.help) showUsage(); if (!opts['out-dir']) { - console.log('--out-dir is a required argunment'); + console.log('--out-dir is a required argument'); process.exit(0); } diff --git a/script/spec-runner.js b/script/spec-runner.js index 11502c2da0c23..590966f064b8b 100755 --- a/script/spec-runner.js +++ b/script/spec-runner.js @@ -13,7 +13,7 @@ const fail = 'βœ—'.red; const args = require('minimist')(process.argv, { string: ['runners', 'target'], - boolean: ['buildNativeTests', 'runTestFilesSeperately'], + boolean: ['buildNativeTests', 'runTestFilesSeparately'], unknown: arg => unknownFlags.push(arg) }); @@ -155,7 +155,7 @@ const specFilter = (file) => { }; async function runTests (specDir, testName) { - if (args.runTestFilesSeperately) { + if (args.runTestFilesSeparately) { const getFiles = require('../spec/static/get-files'); const testFiles = await getFiles(path.resolve(__dirname, `../${specDir}`), { filter: specFilter }); const baseElectronDir = path.resolve(__dirname, '..'); @@ -230,12 +230,18 @@ async function runMainProcessElectronTests () { } async function installSpecModules (dir) { + // v8 headers use c++17 so override the gyp default of -std=c++14, + // but don't clobber any other CXXFLAGS that were passed into spec-runner.js + const CXXFLAGS = ['-std=c++17', process.env.CXXFLAGS].filter(x => !!x).join(' '); + const nodeDir = path.resolve(BASE, `out/${utils.getOutDir({ shouldLog: true })}/gen/node_headers`); - const env = Object.assign({}, process.env, { + const env = { + ...process.env, + CXXFLAGS, npm_config_nodedir: nodeDir, npm_config_msvs_version: '2019', npm_config_yes: 'true' - }); + }; if (fs.existsSync(path.resolve(dir, 'node_modules'))) { await fs.remove(path.resolve(dir, 'node_modules')); } diff --git a/script/start.js b/script/start.js index 0ba6e56a1fcb1..94ecfeac87952 100644 --- a/script/start.js +++ b/script/start.js @@ -14,3 +14,4 @@ const handleTerminationSignal = (signal) => handleTerminationSignal('SIGINT'); handleTerminationSignal('SIGTERM'); +handleTerminationSignal('SIGUSR2'); diff --git a/script/sysroots.json b/script/sysroots.json index aef0ad6713c80..b1b851fd518a8 100644 --- a/script/sysroots.json +++ b/script/sysroots.json @@ -1,38 +1,37 @@ - { - "sid_amd64": { - "Sha1Sum": "7e008cea9eae822d80d55c67fbb5ef4204678e74", - "SysrootDir": "debian_sid_amd64-sysroot", - "Tarball": "debian_sid_amd64_sysroot.tar.xz" + "bullseye_amd64": { + "Sha1Sum": "202e5738f4fad834a43ad9978efc53ff710ee979", + "SysrootDir": "debian_bullseye_amd64-sysroot", + "Tarball": "debian_bullseye_amd64_sysroot.tar.xz" }, - "sid_arm": { - "Sha1Sum": "b6f4bb07817bea91b06514a9c1e3832df5a90dbf", - "SysrootDir": "debian_sid_arm-sysroot", - "Tarball": "debian_sid_arm_sysroot.tar.xz" + "bullseye_arm": { + "Sha1Sum": "683d994e5643dff423643eac59c1f62606d14f43", + "SysrootDir": "debian_bullseye_arm-sysroot", + "Tarball": "debian_bullseye_arm_sysroot.tar.xz" }, - "sid_arm64": { + "bullseye_arm64": { "Sha1Sum": "5a56c1ef714154ea5003bcafb16f21b0f8dde023", - "SysrootDir": "debian_sid_arm64-sysroot", + "SysrootDir": "debian_bullseye_arm64-sysroot", "Tarball": "debian_sid_arm64_sysroot.tar.xz" }, - "sid_armel": { - "Sha1Sum": "84dfbda5b70e4056b5ec37d8dc95b9b890b2a2b5", - "SysrootDir": "debian_sid_armel-sysroot", - "Tarball": "debian_sid_armel_sysroot.tar.xz" + "bullseye_armel": { + "Sha1Sum": "db15aab39af3cfbc55a8ff0386943db1b78a1eab", + "SysrootDir": "debian_bullseye_armel-sysroot", + "Tarball": "debian_bullseye_armel_sysroot.tar.xz" }, - "sid_i386": { - "Sha1Sum": "b0f1f65ab3bd0232e7080bd3d89a9399f5ba07bc", - "SysrootDir": "debian_sid_i386-sysroot", - "Tarball": "debian_sid_i386_sysroot.tar.xz" + "bullseye_i386": { + "Sha1Sum": "41a75c881636adb765d4e40b06058f64df501ffe", + "SysrootDir": "debian_bullseye_i386-sysroot", + "Tarball": "debian_bullseye_i386_sysroot.tar.xz" }, - "sid_mips": { - "Sha1Sum": "72d808dad16f6bc605f0380649608b04435b0727", - "SysrootDir": "debian_sid_mips-sysroot", - "Tarball": "debian_sid_mips_sysroot.tar.xz" + "bullseye_mips": { + "Sha1Sum": "6d85967e8d6771e50180c289dae57ad06fd873cd", + "SysrootDir": "debian_bullseye_mips-sysroot", + "Tarball": "debian_bullseye_mips_sysroot.tar.xz" }, - "sid_mips64el": { - "Sha1Sum": "0ae3b93990a22fed1fa6974c0cf1fa0f9ad976b9", - "SysrootDir": "debian_sid_mips64el-sysroot", - "Tarball": "debian_sid_mips64el_sysroot.tar.xz" + "bullseye_mips64el": { + "Sha1Sum": "0774922d1269947f462bda38c82c4e5e819326ab", + "SysrootDir": "debian_bullseye_mips64el-sysroot", + "Tarball": "debian_bullseye_mips64el_sysroot.tar.xz" } -} \ No newline at end of file +} diff --git a/script/verify-mksnapshot.py b/script/verify-mksnapshot.py index 47d0a4fa32842..7efbc59dbe5f7 100755 --- a/script/verify-mksnapshot.py +++ b/script/verify-mksnapshot.py @@ -28,6 +28,7 @@ def main(): if args.snapshot_files_dir is None: with open(os.path.join(app_path, 'mksnapshot_args')) as f: mkargs = f.read().splitlines() + print('running: ' + ' '.join(mkargs + [ SNAPSHOT_SOURCE ])) subprocess.check_call(mkargs + [ SNAPSHOT_SOURCE ], cwd=app_path) print('ok mksnapshot successfully created snapshot_blob.bin.') context_snapshot = 'v8_context_snapshot.bin' @@ -41,6 +42,7 @@ def main(): app_path) genargs = [ gen_binary, \ '--output_file={0}'.format(context_snapshot_path) ] + print('running: ' + ' '.join(genargs)) subprocess.check_call(genargs) print('ok v8_context_snapshot_generator successfully created ' \ + context_snapshot) @@ -69,6 +71,7 @@ def main(): else: electron = os.path.join(app_path, PROJECT_NAME) + print('running: ' + ' '.join([electron, test_path])) subprocess.check_call([electron, test_path]) print('ok successfully used custom snapshot.') except subprocess.CalledProcessError as e: diff --git a/script/zip_manifests/check-zip-manifest.py b/script/zip_manifests/check-zip-manifest.py index a57475811a19f..4f5594b2c98f3 100755 --- a/script/zip_manifests/check-zip-manifest.py +++ b/script/zip_manifests/check-zip-manifest.py @@ -7,7 +7,7 @@ def main(zip_path, manifest_in): with open(manifest_in, 'r') as manifest, \ zipfile.ZipFile(zip_path, 'r', allowZip64=True) as z: files_in_zip = set(z.namelist()) - files_in_manifest = set([l.strip() for l in manifest.readlines()]) + files_in_manifest = {l.strip() for l in manifest.readlines()} added_files = files_in_zip - files_in_manifest removed_files = files_in_manifest - files_in_zip if added_files: @@ -18,10 +18,8 @@ def main(zip_path, manifest_in): print("Files removed from bundle:") for f in sorted(list(removed_files)): print('-' + f) - if added_files or removed_files: - return 1 - else: - return 0 + + return 1 if added_files or removed_files else 0 if __name__ == '__main__': - sys.exit(main(*sys.argv[1:])) + sys.exit(main(sys.argv[1], sys.argv[2])) diff --git a/script/zip_manifests/dist_zip.linux.arm.manifest b/script/zip_manifests/dist_zip.linux.arm.manifest index 7e08e3f695f0c..224d2f036d572 100644 --- a/script/zip_manifests/dist_zip.linux.arm.manifest +++ b/script/zip_manifests/dist_zip.linux.arm.manifest @@ -11,6 +11,7 @@ libGLESv2.so libffmpeg.so libvk_swiftshader.so libvulkan.so.1 +locales/af.pak locales/am.pak locales/ar.pak locales/bg.pak @@ -61,14 +62,13 @@ locales/te.pak locales/th.pak locales/tr.pak locales/uk.pak +locales/ur.pak locales/vi.pak locales/zh-CN.pak locales/zh-TW.pak resources.pak resources/default_app.asar snapshot_blob.bin -swiftshader/libEGL.so -swiftshader/libGLESv2.so vk_swiftshader_icd.json v8_context_snapshot.bin version diff --git a/script/zip_manifests/dist_zip.linux.arm64.manifest b/script/zip_manifests/dist_zip.linux.arm64.manifest index 7e08e3f695f0c..224d2f036d572 100644 --- a/script/zip_manifests/dist_zip.linux.arm64.manifest +++ b/script/zip_manifests/dist_zip.linux.arm64.manifest @@ -11,6 +11,7 @@ libGLESv2.so libffmpeg.so libvk_swiftshader.so libvulkan.so.1 +locales/af.pak locales/am.pak locales/ar.pak locales/bg.pak @@ -61,14 +62,13 @@ locales/te.pak locales/th.pak locales/tr.pak locales/uk.pak +locales/ur.pak locales/vi.pak locales/zh-CN.pak locales/zh-TW.pak resources.pak resources/default_app.asar snapshot_blob.bin -swiftshader/libEGL.so -swiftshader/libGLESv2.so vk_swiftshader_icd.json v8_context_snapshot.bin version diff --git a/script/zip_manifests/dist_zip.linux.x64.manifest b/script/zip_manifests/dist_zip.linux.x64.manifest index 7e08e3f695f0c..224d2f036d572 100644 --- a/script/zip_manifests/dist_zip.linux.x64.manifest +++ b/script/zip_manifests/dist_zip.linux.x64.manifest @@ -11,6 +11,7 @@ libGLESv2.so libffmpeg.so libvk_swiftshader.so libvulkan.so.1 +locales/af.pak locales/am.pak locales/ar.pak locales/bg.pak @@ -61,14 +62,13 @@ locales/te.pak locales/th.pak locales/tr.pak locales/uk.pak +locales/ur.pak locales/vi.pak locales/zh-CN.pak locales/zh-TW.pak resources.pak resources/default_app.asar snapshot_blob.bin -swiftshader/libEGL.so -swiftshader/libGLESv2.so vk_swiftshader_icd.json v8_context_snapshot.bin version diff --git a/script/zip_manifests/dist_zip.linux.x86.manifest b/script/zip_manifests/dist_zip.linux.x86.manifest index 7e08e3f695f0c..224d2f036d572 100644 --- a/script/zip_manifests/dist_zip.linux.x86.manifest +++ b/script/zip_manifests/dist_zip.linux.x86.manifest @@ -11,6 +11,7 @@ libGLESv2.so libffmpeg.so libvk_swiftshader.so libvulkan.so.1 +locales/af.pak locales/am.pak locales/ar.pak locales/bg.pak @@ -61,14 +62,13 @@ locales/te.pak locales/th.pak locales/tr.pak locales/uk.pak +locales/ur.pak locales/vi.pak locales/zh-CN.pak locales/zh-TW.pak resources.pak resources/default_app.asar snapshot_blob.bin -swiftshader/libEGL.so -swiftshader/libGLESv2.so vk_swiftshader_icd.json v8_context_snapshot.bin version diff --git a/script/zip_manifests/dist_zip.mac.arm64.manifest b/script/zip_manifests/dist_zip.mac.arm64.manifest index 91ed477f54512..26e7b9b957c3c 100644 --- a/script/zip_manifests/dist_zip.mac.arm64.manifest +++ b/script/zip_manifests/dist_zip.mac.arm64.manifest @@ -15,15 +15,13 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Librari Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libEGL.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libvk_swiftshader.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/vk_swiftshader_icd.json Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Info.plist -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/ -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects-101300.nib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ar.lproj/ @@ -128,6 +126,8 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resourc Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/tr.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/locale.pak +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/v8_context_snapshot.arm64.bin Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/locale.pak @@ -193,6 +193,7 @@ Electron.app/Contents/MacOS/ Electron.app/Contents/MacOS/Electron Electron.app/Contents/PkgInfo Electron.app/Contents/Resources/ +Electron.app/Contents/Resources/af.lproj/ Electron.app/Contents/Resources/am.lproj/ Electron.app/Contents/Resources/ar.lproj/ Electron.app/Contents/Resources/bg.lproj/ @@ -245,6 +246,7 @@ Electron.app/Contents/Resources/te.lproj/ Electron.app/Contents/Resources/th.lproj/ Electron.app/Contents/Resources/tr.lproj/ Electron.app/Contents/Resources/uk.lproj/ +Electron.app/Contents/Resources/ur.lproj/ Electron.app/Contents/Resources/vi.lproj/ Electron.app/Contents/Resources/zh_CN.lproj/ Electron.app/Contents/Resources/zh_TW.lproj/ diff --git a/script/zip_manifests/dist_zip.mac.x64.manifest b/script/zip_manifests/dist_zip.mac.x64.manifest index e411bc46d62d3..3e42bf0f614ec 100644 --- a/script/zip_manifests/dist_zip.mac.x64.manifest +++ b/script/zip_manifests/dist_zip.mac.x64.manifest @@ -15,15 +15,13 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Librari Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libEGL.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libvk_swiftshader.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/vk_swiftshader_icd.json Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Info.plist -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/ -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects-101300.nib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ar.lproj/ @@ -128,6 +126,8 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resourc Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/tr.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/locale.pak +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/v8_context_snapshot.x86_64.bin Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/locale.pak @@ -193,6 +193,7 @@ Electron.app/Contents/MacOS/ Electron.app/Contents/MacOS/Electron Electron.app/Contents/PkgInfo Electron.app/Contents/Resources/ +Electron.app/Contents/Resources/af.lproj/ Electron.app/Contents/Resources/am.lproj/ Electron.app/Contents/Resources/ar.lproj/ Electron.app/Contents/Resources/bg.lproj/ @@ -245,6 +246,7 @@ Electron.app/Contents/Resources/te.lproj/ Electron.app/Contents/Resources/th.lproj/ Electron.app/Contents/Resources/tr.lproj/ Electron.app/Contents/Resources/uk.lproj/ +Electron.app/Contents/Resources/ur.lproj/ Electron.app/Contents/Resources/vi.lproj/ Electron.app/Contents/Resources/zh_CN.lproj/ Electron.app/Contents/Resources/zh_TW.lproj/ diff --git a/script/zip_manifests/dist_zip.mac_mas.arm64.manifest b/script/zip_manifests/dist_zip.mac_mas.arm64.manifest index 20ca9e4428da2..eb63a730528bb 100644 --- a/script/zip_manifests/dist_zip.mac_mas.arm64.manifest +++ b/script/zip_manifests/dist_zip.mac_mas.arm64.manifest @@ -12,15 +12,13 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Librari Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libEGL.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libvk_swiftshader.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/vk_swiftshader_icd.json Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Info.plist -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/ -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects-101300.nib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ar.lproj/ @@ -125,6 +123,8 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resourc Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/tr.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/locale.pak +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/v8_context_snapshot.arm64.bin Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/locale.pak @@ -170,6 +170,7 @@ Electron.app/Contents/MacOS/ Electron.app/Contents/MacOS/Electron Electron.app/Contents/PkgInfo Electron.app/Contents/Resources/ +Electron.app/Contents/Resources/af.lproj/ Electron.app/Contents/Resources/am.lproj/ Electron.app/Contents/Resources/ar.lproj/ Electron.app/Contents/Resources/bg.lproj/ @@ -222,6 +223,7 @@ Electron.app/Contents/Resources/te.lproj/ Electron.app/Contents/Resources/th.lproj/ Electron.app/Contents/Resources/tr.lproj/ Electron.app/Contents/Resources/uk.lproj/ +Electron.app/Contents/Resources/ur.lproj/ Electron.app/Contents/Resources/vi.lproj/ Electron.app/Contents/Resources/zh_CN.lproj/ Electron.app/Contents/Resources/zh_TW.lproj/ diff --git a/script/zip_manifests/dist_zip.mac_mas.x64.manifest b/script/zip_manifests/dist_zip.mac_mas.x64.manifest index c3a864ce25578..29c698600badb 100644 --- a/script/zip_manifests/dist_zip.mac_mas.x64.manifest +++ b/script/zip_manifests/dist_zip.mac_mas.x64.manifest @@ -12,15 +12,13 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Librari Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libEGL.dylib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libvk_swiftshader.dylib Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/vk_swiftshader_icd.json Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/Info.plist -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/ -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects-101300.nib -Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib/keyedobjects.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/MainMenu.nib +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/af.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/am.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ar.lproj/ @@ -125,6 +123,8 @@ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resourc Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/tr.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/uk.lproj/locale.pak +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/ +Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/ur.lproj/locale.pak Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/v8_context_snapshot.x86_64.bin Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/ Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/vi.lproj/locale.pak @@ -170,6 +170,7 @@ Electron.app/Contents/MacOS/ Electron.app/Contents/MacOS/Electron Electron.app/Contents/PkgInfo Electron.app/Contents/Resources/ +Electron.app/Contents/Resources/af.lproj/ Electron.app/Contents/Resources/am.lproj/ Electron.app/Contents/Resources/ar.lproj/ Electron.app/Contents/Resources/bg.lproj/ @@ -222,6 +223,7 @@ Electron.app/Contents/Resources/te.lproj/ Electron.app/Contents/Resources/th.lproj/ Electron.app/Contents/Resources/tr.lproj/ Electron.app/Contents/Resources/uk.lproj/ +Electron.app/Contents/Resources/ur.lproj/ Electron.app/Contents/Resources/vi.lproj/ Electron.app/Contents/Resources/zh_CN.lproj/ Electron.app/Contents/Resources/zh_TW.lproj/ diff --git a/script/zip_manifests/dist_zip.win.arm64.manifest b/script/zip_manifests/dist_zip.win.arm64.manifest index 6f4e96ded7738..20a089bcd67c6 100755 --- a/script/zip_manifests/dist_zip.win.arm64.manifest +++ b/script/zip_manifests/dist_zip.win.arm64.manifest @@ -7,6 +7,7 @@ ffmpeg.dll icudtl.dat libEGL.dll libGLESv2.dll +locales/af.pak locales/am.pak locales/ar.pak locales/bg.pak @@ -57,14 +58,13 @@ locales/te.pak locales/th.pak locales/tr.pak locales/uk.pak +locales/ur.pak locales/vi.pak locales/zh-CN.pak locales/zh-TW.pak resources.pak resources/default_app.asar snapshot_blob.bin -swiftshader/libEGL.dll -swiftshader/libGLESv2.dll vk_swiftshader_icd.json vk_swiftshader.dll vulkan-1.dll diff --git a/script/zip_manifests/dist_zip.win.ia32.manifest b/script/zip_manifests/dist_zip.win.ia32.manifest index 61abecd09b4d0..5d8deb41a53b8 100644 --- a/script/zip_manifests/dist_zip.win.ia32.manifest +++ b/script/zip_manifests/dist_zip.win.ia32.manifest @@ -8,6 +8,7 @@ ffmpeg.dll icudtl.dat libEGL.dll libGLESv2.dll +locales/af.pak locales/am.pak locales/ar.pak locales/bg.pak @@ -58,14 +59,13 @@ locales/te.pak locales/th.pak locales/tr.pak locales/uk.pak +locales/ur.pak locales/vi.pak locales/zh-CN.pak locales/zh-TW.pak resources.pak resources/default_app.asar snapshot_blob.bin -swiftshader/libEGL.dll -swiftshader/libGLESv2.dll vk_swiftshader_icd.json vk_swiftshader.dll vulkan-1.dll diff --git a/script/zip_manifests/dist_zip.win.x64.manifest b/script/zip_manifests/dist_zip.win.x64.manifest index 61abecd09b4d0..5d8deb41a53b8 100644 --- a/script/zip_manifests/dist_zip.win.x64.manifest +++ b/script/zip_manifests/dist_zip.win.x64.manifest @@ -8,6 +8,7 @@ ffmpeg.dll icudtl.dat libEGL.dll libGLESv2.dll +locales/af.pak locales/am.pak locales/ar.pak locales/bg.pak @@ -58,14 +59,13 @@ locales/te.pak locales/th.pak locales/tr.pak locales/uk.pak +locales/ur.pak locales/vi.pak locales/zh-CN.pak locales/zh-TW.pak resources.pak resources/default_app.asar snapshot_blob.bin -swiftshader/libEGL.dll -swiftshader/libGLESv2.dll vk_swiftshader_icd.json vk_swiftshader.dll vulkan-1.dll diff --git a/shell/app/electron_content_client.cc b/shell/app/electron_content_client.cc index 767c4ea2a0ba1..a63aebdddad5e 100644 --- a/shell/app/electron_content_client.cc +++ b/shell/app/electron_content_client.cc @@ -18,26 +18,27 @@ #include "content/public/common/content_switches.h" #include "electron/buildflags/buildflags.h" #include "extensions/common/constants.h" +#include "pdf/buildflags.h" #include "ppapi/buildflags/buildflags.h" #include "shell/common/electron_paths.h" #include "shell/common/options_switches.h" +#include "third_party/widevine/cdm/buildflags.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "url/url_constants.h" // In SHARED_INTERMEDIATE_DIR. #include "widevine_cdm_version.h" // NOLINT(build/include_directory) -#if defined(WIDEVINE_CDM_AVAILABLE) +#if BUILDFLAG(ENABLE_WIDEVINE) #include "base/native_library.h" #include "content/public/common/cdm_info.h" #include "media/base/video_codecs.h" -#endif // defined(WIDEVINE_CDM_AVAILABLE) +#endif // BUILDFLAG(ENABLE_WIDEVINE) #if BUILDFLAG(ENABLE_PDF_VIEWER) #include "chrome/common/pdf_util.h" #include "components/pdf/common/internal_plugin_helpers.h" -#include "pdf/pdf.h" // nogncheck -#include "pdf/pdf_ppapi.h" // nogncheck +#include "pdf/pdf.h" // nogncheck #include "shell/common/electron_constants.h" #endif // BUILDFLAG(ENABLE_PDF_VIEWER) @@ -45,7 +46,8 @@ #include "content/public/browser/plugin_service.h" #include "content/public/common/pepper_plugin_info.h" #include "ppapi/shared_impl/ppapi_permissions.h" -#endif // BUILDFLAG(ENABLE_PLUGINS) +#include "ppapi/shared_impl/ppapi_switches.h" // nogncheck crbug.com/1125897 +#endif // BUILDFLAG(ENABLE_PLUGINS) namespace electron { @@ -57,7 +59,7 @@ enum class WidevineCdmFileCheck { kNotFound, }; -#if defined(WIDEVINE_CDM_AVAILABLE) +#if BUILDFLAG(ENABLE_WIDEVINE) bool IsWidevineAvailable( base::FilePath* cdm_path, std::vector* codecs_supported, @@ -101,11 +103,13 @@ bool IsWidevineAvailable( return false; } -#endif // defined(WIDEVINE_CDM_AVAILABLE) +#endif // BUILDFLAG(ENABLE_WIDEVINE) #if BUILDFLAG(ENABLE_PLUGINS) void ComputeBuiltInPlugins(std::vector* plugins) { #if BUILDFLAG(ENABLE_PDF_VIEWER) + // TODO(upstream/thestig): Figure out how to make the PDF Viewer work without + // this PPAPI plugin registration. content::PepperPluginInfo pdf_info; pdf_info.is_internal = true; pdf_info.is_out_of_process = true; @@ -116,12 +120,6 @@ void ComputeBuiltInPlugins(std::vector* plugins) { content::WebPluginMimeType pdf_mime_type(pdf::kInternalPluginMimeType, "pdf", "Portable Document Format"); pdf_info.mime_types.push_back(pdf_mime_type); - pdf_info.internal_entry_points.get_interface = chrome_pdf::PPP_GetInterface; - pdf_info.internal_entry_points.initialize_module = - chrome_pdf::PPP_InitializeModule; - pdf_info.internal_entry_points.shutdown_module = - chrome_pdf::PPP_ShutdownModule; - pdf_info.permissions = ppapi::PERMISSION_PDF | ppapi::PERMISSION_DEV; plugins->push_back(pdf_info); // NB. in Chrome, this plugin isn't registered until the PDF extension is @@ -230,7 +228,7 @@ void ElectronContentClient::AddContentDecryptionModules( std::vector* cdms, std::vector* cdm_host_file_paths) { if (cdms) { -#if defined(WIDEVINE_CDM_AVAILABLE) +#if BUILDFLAG(ENABLE_WIDEVINE) base::FilePath cdm_path; std::vector video_codecs_supported; base::flat_set session_types_supported; @@ -255,7 +253,7 @@ void ElectronContentClient::AddContentDecryptionModules( kWidevineCdmDisplayName, kWidevineCdmGuid, version, cdm_path, kWidevineCdmFileSystemId, capability, kWidevineKeySystem, false)); } -#endif // defined(WIDEVINE_CDM_AVAILABLE) +#endif // BUILDFLAG(ENABLE_WIDEVINE) } } diff --git a/shell/app/electron_crash_reporter_client.cc b/shell/app/electron_crash_reporter_client.cc index 245c55c90a13a..237c90c16f33a 100644 --- a/shell/app/electron_crash_reporter_client.cc +++ b/shell/app/electron_crash_reporter_client.cc @@ -190,7 +190,9 @@ bool ElectronCrashReporterClient::GetShouldCompressUploads() { void ElectronCrashReporterClient::GetProcessSimpleAnnotations( std::map* annotations) { - *annotations = global_annotations_; + for (auto&& pair : global_annotations_) { + (*annotations)[pair.first] = pair.second; + } (*annotations)["prod"] = ELECTRON_PRODUCT_NAME; (*annotations)["ver"] = ELECTRON_VERSION_STRING; } diff --git a/shell/app/electron_main_delegate.cc b/shell/app/electron_main_delegate.cc index caa13d764c7ba..6111b30a11951 100644 --- a/shell/app/electron_main_delegate.cc +++ b/shell/app/electron_main_delegate.cc @@ -23,6 +23,7 @@ #include "components/content_settings/core/common/content_settings_pattern.h" #include "content/public/common/content_switches.h" #include "electron/buildflags/buildflags.h" +#include "electron/fuses.h" #include "extensions/common/constants.h" #include "ipc/ipc_buildflags.h" #include "sandbox/policy/switches.h" @@ -41,6 +42,7 @@ #include "shell/renderer/electron_renderer_client.h" #include "shell/renderer/electron_sandboxed_renderer_client.h" #include "shell/utility/electron_content_utility_client.h" +#include "third_party/abseil-cpp/absl/types/variant.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches.h" @@ -134,11 +136,14 @@ bool ElectronPathProvider(int key, base::FilePath* result) { break; case chrome::DIR_APP_DICTIONARIES: // TODO(nornagon): can we just default to using Chrome's logic here? - if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur)) + if (!base::PathService::Get(DIR_SESSION_DATA, &cur)) return false; cur = cur.Append(base::FilePath::FromUTF8Unsafe("Dictionaries")); create_dir = true; break; + case DIR_SESSION_DATA: + // By default and for backward, equivalent to DIR_USER_DATA. + return base::PathService::Get(chrome::DIR_USER_DATA, result); case DIR_USER_CACHE: { #if BUILDFLAG(IS_POSIX) int parent_key = base::DIR_CACHE; @@ -234,9 +239,9 @@ ElectronMainDelegate::~ElectronMainDelegate() = default; const char* const ElectronMainDelegate::kNonWildcardDomainNonPortSchemes[] = { extensions::kExtensionScheme}; const size_t ElectronMainDelegate::kNonWildcardDomainNonPortSchemesSize = - base::size(kNonWildcardDomainNonPortSchemes); + std::size(kNonWildcardDomainNonPortSchemes); -bool ElectronMainDelegate::BasicStartupComplete(int* exit_code) { +absl::optional ElectronMainDelegate::BasicStartupComplete() { auto* command_line = base::CommandLine::ForCurrentProcess(); #if BUILDFLAG(IS_WIN) @@ -250,6 +255,8 @@ bool ElectronMainDelegate::BasicStartupComplete(int* exit_code) { auto env = base::Environment::Create(); + gin_helper::Locker::SetIsBrowserProcess(IsBrowserProcess(command_line)); + // Enable convenient stack printing. This is enabled by default in // non-official builds. if (env->HasVar(kElectronEnableStackDumping)) @@ -309,10 +316,7 @@ bool ElectronMainDelegate::BasicStartupComplete(int* exit_code) { ::switches::kDisableGpuMemoryBufferCompositorResources); #endif - content_client_ = std::make_unique(); - SetContentClient(content_client_.get()); - - return false; + return absl::nullopt; } void ElectronMainDelegate::PreSandboxStartup() { @@ -405,7 +409,7 @@ void ElectronMainDelegate::SandboxInitialized(const std::string& process_type) { #endif } -void ElectronMainDelegate::PreBrowserMain() { +absl::optional ElectronMainDelegate::PreBrowserMain() { // This is initialized early because the service manager reads some feature // flags and we need to make sure the feature list is initialized before the // service manager reads the features. @@ -413,6 +417,26 @@ void ElectronMainDelegate::PreBrowserMain() { #if BUILDFLAG(IS_MAC) RegisterAtomCrApp(); #endif + return absl::nullopt; +} + +base::StringPiece ElectronMainDelegate::GetBrowserV8SnapshotFilename() { + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + std::string process_type = + command_line->GetSwitchValueASCII(::switches::kProcessType); + bool load_browser_process_specific_v8_snapshot = + process_type.empty() && + electron::fuses::IsLoadBrowserProcessSpecificV8SnapshotEnabled(); + if (load_browser_process_specific_v8_snapshot) { + return "browser_v8_context_snapshot.bin"; + } + return ContentMainDelegate::GetBrowserV8SnapshotFilename(); +} + +content::ContentClient* ElectronMainDelegate::CreateContentClient() { + content_client_ = std::make_unique(); + return content_client_.get(); } content::ContentBrowserClient* @@ -455,8 +479,8 @@ ElectronMainDelegate::RunProcess( return std::move(main_function_params); } -bool ElectronMainDelegate::ShouldCreateFeatureList() { - return false; +bool ElectronMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) { + return absl::holds_alternative(invoked_in); } bool ElectronMainDelegate::ShouldLockSchemeRegistry() { diff --git a/shell/app/electron_main_delegate.h b/shell/app/electron_main_delegate.h index 255df5c235d8f..ca48a02a3b820 100644 --- a/shell/app/electron_main_delegate.h +++ b/shell/app/electron_main_delegate.h @@ -30,12 +30,15 @@ class ElectronMainDelegate : public content::ContentMainDelegate { ElectronMainDelegate(const ElectronMainDelegate&) = delete; ElectronMainDelegate& operator=(const ElectronMainDelegate&) = delete; + base::StringPiece GetBrowserV8SnapshotFilename() override; + protected: // content::ContentMainDelegate: - bool BasicStartupComplete(int* exit_code) override; + absl::optional BasicStartupComplete() override; void PreSandboxStartup() override; void SandboxInitialized(const std::string& process_type) override; - void PreBrowserMain() override; + absl::optional PreBrowserMain() override; + content::ContentClient* CreateContentClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentGpuClient* CreateContentGpuClient() override; content::ContentRendererClient* CreateContentRendererClient() override; @@ -43,7 +46,7 @@ class ElectronMainDelegate : public content::ContentMainDelegate { absl::variant RunProcess( const std::string& process_type, content::MainFunctionParams main_function_params) override; - bool ShouldCreateFeatureList() override; + bool ShouldCreateFeatureList(InvokedIn invoked_in) override; bool ShouldLockSchemeRegistry() override; #if BUILDFLAG(IS_LINUX) void ZygoteForked() override; diff --git a/shell/app/electron_main_mac.cc b/shell/app/electron_main_mac.cc index 496fb30ed60b2..c817df186e205 100644 --- a/shell/app/electron_main_mac.cc +++ b/shell/app/electron_main_mac.cc @@ -5,6 +5,7 @@ #include #include +#include "base/allocator/early_zone_registration_mac.h" #include "electron/buildflags/buildflags.h" #include "electron/fuses.h" #include "shell/app/electron_library_main.h" @@ -27,6 +28,7 @@ namespace { } // namespace int main(int argc, char* argv[]) { + partition_alloc::EarlyMallocZoneRegistration(); FixStdioStreams(); #if BUILDFLAG(ENABLE_RUN_AS_NODE) diff --git a/shell/browser/api/electron_api_app.cc b/shell/browser/api/electron_api_app.cc index d6d75c6a0230f..65b8fe7dbe85b 100644 --- a/shell/browser/api/electron_api_app.cc +++ b/shell/browser/api/electron_api_app.cc @@ -35,6 +35,7 @@ #include "crypto/crypto_buildflags.h" #include "media/audio/audio_manager.h" #include "net/dns/public/dns_over_https_config.h" +#include "net/dns/public/dns_over_https_server_config.h" #include "net/dns/public/util.h" #include "net/ssl/client_cert_identity.h" #include "net/ssl/ssl_cert_request_info.h" @@ -46,6 +47,7 @@ #include "shell/browser/api/electron_api_session.h" #include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/api/gpuinfo_manager.h" +#include "shell/browser/browser_process_impl.h" #include "shell/browser/electron_browser_context.h" #include "shell/browser/electron_browser_main_parts.h" #include "shell/browser/javascript_environment.h" @@ -452,9 +454,7 @@ struct Converter { }; } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo App::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -473,6 +473,8 @@ IconLoader::IconSize GetIconSizeByString(const std::string& size) { int GetPathConstant(const std::string& name) { if (name == "appData") return DIR_APP_DATA; + else if (name == "sessionData") + return DIR_SESSION_DATA; else if (name == "userData") return chrome::DIR_USER_DATA; else if (name == "cache") @@ -519,24 +521,21 @@ bool NotificationCallbackWrapper( const base::RepeatingCallback< void(const base::CommandLine& command_line, const base::FilePath& current_directory, - const std::vector additional_data, - const ProcessSingleton::NotificationAckCallback& ack_callback)>& - callback, + const std::vector additional_data)>& callback, const base::CommandLine& cmd, const base::FilePath& cwd, - const std::vector additional_data, - const ProcessSingleton::NotificationAckCallback& ack_callback) { + const std::vector additional_data) { // Make sure the callback is called after app gets ready. if (Browser::Get()->is_ready()) { - callback.Run(cmd, cwd, std::move(additional_data), ack_callback); + callback.Run(cmd, cwd, std::move(additional_data)); } else { scoped_refptr task_runner( base::ThreadTaskRunnerHandle::Get()); // Make a copy of the span so that the data isn't lost. - task_runner->PostTask( - FROM_HERE, base::BindOnce(base::IgnoreResult(callback), cmd, cwd, - std::move(additional_data), ack_callback)); + task_runner->PostTask(FROM_HERE, + base::BindOnce(base::IgnoreResult(callback), cmd, cwd, + std::move(additional_data))); } // ProcessSingleton needs to know whether current process is quiting. return !Browser::Get()->is_shutting_down(); @@ -706,13 +705,13 @@ void App::OnWillFinishLaunching() { Emit("will-finish-launching"); } -void App::OnFinishLaunching(const base::DictionaryValue& launch_info) { +void App::OnFinishLaunching(base::Value::Dict launch_info) { #if BUILDFLAG(IS_LINUX) // Set the application name for audio streams shown in external // applications. Only affects pulseaudio currently. media::AudioManager::SetGlobalAppName(Browser::Get()->GetName()); #endif - Emit("ready", launch_info); + Emit("ready", base::Value(std::move(launch_info))); } void App::OnPreMainMessageLoopRun() { @@ -756,22 +755,23 @@ void App::OnDidFailToContinueUserActivity(const std::string& type, void App::OnContinueUserActivity(bool* prevent_default, const std::string& type, - const base::DictionaryValue& user_info, - const base::DictionaryValue& details) { - if (Emit("continue-activity", type, user_info, details)) { + base::Value::Dict user_info, + base::Value::Dict details) { + if (Emit("continue-activity", type, base::Value(std::move(user_info)), + base::Value(std::move(details)))) { *prevent_default = true; } } void App::OnUserActivityWasContinued(const std::string& type, - const base::DictionaryValue& user_info) { - Emit("activity-was-continued", type, user_info); + base::Value::Dict user_info) { + Emit("activity-was-continued", type, base::Value(std::move(user_info))); } void App::OnUpdateUserActivityState(bool* prevent_default, const std::string& type, - const base::DictionaryValue& user_info) { - if (Emit("update-activity-state", type, user_info)) { + base::Value::Dict user_info) { + if (Emit("update-activity-state", type, base::Value(std::move(user_info)))) { *prevent_default = true; } } @@ -802,7 +802,6 @@ bool App::CanCreateWindow( bool opener_suppressed, bool* no_javascript_access) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(opener); @@ -828,7 +827,6 @@ void App::AllowCertificateError( base::OnceCallback callback) { auto adapted_callback = base::AdaptCallbackForRepeating(std::move(callback)); v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); bool prevent_default = Emit( "certificate-error", WebContents::FromOrCreate(isolate, web_contents), @@ -881,9 +879,8 @@ void App::OnGpuInfoUpdate() { Emit("gpu-info-update"); } -void App::OnGpuProcessCrashed(base::TerminationStatus status) { - Emit("gpu-process-crashed", - status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); +void App::OnGpuProcessCrashed() { + Emit("gpu-process-crashed", true); } void App::BrowserChildProcessLaunchedAndConnected( @@ -1042,6 +1039,16 @@ std::string App::GetLocale() { return g_browser_process->GetApplicationLocale(); } +std::string App::GetSystemLocale(gin_helper::ErrorThrower thrower) const { + if (!Browser::Get()->is_ready()) { + thrower.ThrowError( + "app.getSystemLocale() can only be called " + "after app is ready"); + return std::string(); + } + return static_cast(g_browser_process)->GetSystemLocale(); +} + std::string App::GetLocaleCountryCode() { std::string region; #if BUILDFLAG(IS_WIN) @@ -1084,54 +1091,14 @@ std::string App::GetLocaleCountryCode() { return region.size() == 2 ? region : std::string(); } -void App::OnFirstInstanceAck( - const base::span* first_instance_data) { - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - base::Value data_to_send; - if (first_instance_data) { - // Don't send back the local directly, because it might be empty. - v8::Local data_local; - data_local = DeserializeV8Value(isolate, *first_instance_data); - if (!data_local.IsEmpty()) { - gin::ConvertFromV8(isolate, data_local, &data_to_send); - } - } - Emit("first-instance-ack", data_to_send); -} - -// This function handles the user calling -// the callback parameter sent out by the second-instance event. -static void AckCallbackWrapper( - const ProcessSingleton::NotificationAckCallback& ack_callback, - gin::Arguments* args) { - blink::CloneableMessage ack_message; - args->GetNext(&ack_message); - if (!ack_message.encoded_message.empty()) { - ack_callback.Run(&ack_message.encoded_message); - } else { - ack_callback.Run(nullptr); - } -} - -void App::OnSecondInstance( - const base::CommandLine& cmd, - const base::FilePath& cwd, - const std::vector additional_data, - const ProcessSingleton::NotificationAckCallback& ack_callback) { +void App::OnSecondInstance(const base::CommandLine& cmd, + const base::FilePath& cwd, + const std::vector additional_data) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); v8::Local data_value = DeserializeV8Value(isolate, std::move(additional_data)); - auto cb = base::BindRepeating(&AckCallbackWrapper, ack_callback); - bool prevent_default = - Emit("second-instance", cmd.argv(), cwd, data_value, cb); - if (!prevent_default) { - // Call the callback ourselves, and send back nothing. - ack_callback.Run(nullptr); - } + Emit("second-instance", cmd.argv(), cwd, data_value); } bool App::HasSingleInstanceLock() const { @@ -1152,9 +1119,6 @@ bool App::RequestSingleInstanceLock(gin::Arguments* args) { base::CreateDirectoryAndGetError(user_dir, nullptr); auto cb = base::BindRepeating(&App::OnSecondInstance, base::Unretained(this)); - auto wrapped_cb = base::BindRepeating(NotificationCallbackWrapper, cb); - auto ack_cb = - base::BindRepeating(&App::OnFirstInstanceAck, base::Unretained(this)); blink::CloneableMessage additional_data_message; args->GetNext(&additional_data_message); @@ -1163,10 +1127,11 @@ bool App::RequestSingleInstanceLock(gin::Arguments* args) { IsSandboxEnabled(base::CommandLine::ForCurrentProcess()); process_singleton_ = std::make_unique( program_name, user_dir, additional_data_message.encoded_message, - app_is_sandboxed, wrapped_cb, ack_cb); + app_is_sandboxed, base::BindRepeating(NotificationCallbackWrapper, cb)); #else process_singleton_ = std::make_unique( - user_dir, additional_data_message.encoded_message, wrapped_cb, ack_cb); + user_dir, additional_data_message.encoded_message, + base::BindRepeating(NotificationCallbackWrapper, cb)); #endif switch (process_singleton_->NotifyOtherProcessOrCreate()) { @@ -1197,7 +1162,9 @@ bool App::Relaunch(gin::Arguments* js_args) { gin_helper::Dictionary options; if (js_args->GetNext(&options)) { - if (options.Get("execPath", &exec_path) || options.Get("args", &args)) + bool has_exec_path = options.Get("execPath", &exec_path); + bool has_args = options.Get("args", &args); + if (has_exec_path || has_args) override_argv = true; } @@ -1487,7 +1454,7 @@ v8::Local App::GetGPUFeatureStatus(v8::Isolate* isolate) { v8::Local App::GetGPUInfo(v8::Isolate* isolate, const std::string& info_type) { auto* const gpu_data_manager = content::GpuDataManagerImpl::GetInstance(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); if (info_type != "basic" && info_type != "complete") { promise.RejectWithErrorMessage( @@ -1632,6 +1599,11 @@ v8::Local App::GetDockAPI(v8::Isolate* isolate) { void ConfigureHostResolver(v8::Isolate* isolate, const gin_helper::Dictionary& opts) { gin_helper::ErrorThrower thrower(isolate); + if (!Browser::Get()->is_ready()) { + thrower.ThrowError( + "configureHostResolver cannot be called before the app is ready"); + return; + } net::SecureDnsMode secure_dns_mode = net::SecureDnsMode::kOff; std::string default_doh_templates; if (base::FeatureList::IsEnabled(features::kDnsOverHttps)) { @@ -1678,17 +1650,18 @@ void ConfigureHostResolver(v8::Isolate* isolate, // Validate individual server templates prior to batch-assigning to // doh_config. + std::vector servers; for (const std::string& server_template : secure_dns_server_strings) { - absl::optional server_config = - net::DnsOverHttpsConfig::FromString(server_template); + absl::optional server_config = + net::DnsOverHttpsServerConfig::FromString(server_template); if (!server_config.has_value()) { thrower.ThrowTypeError(std::string("not a valid DoH template: ") + server_template); return; } + servers.push_back(*server_config); } - doh_config = *net::DnsOverHttpsConfig::FromStrings( - std::move(secure_dns_server_strings)); + doh_config = net::DnsOverHttpsConfig(std::move(servers)); } if (opts.Has("enableAdditionalDnsQueryTypes") && @@ -1766,6 +1739,7 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) { base::BindRepeating(&Browser::IsEmojiPanelSupported, browser)) #if BUILDFLAG(IS_MAC) .SetMethod("hide", base::BindRepeating(&Browser::Hide, browser)) + .SetMethod("isHidden", base::BindRepeating(&Browser::IsHidden, browser)) .SetMethod("show", base::BindRepeating(&Browser::Show, browser)) .SetMethod("setUserActivity", base::BindRepeating(&Browser::SetUserActivity, browser)) @@ -1816,6 +1790,7 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) { .SetMethod("setAppLogsPath", &App::SetAppLogsPath) .SetMethod("setDesktopName", &App::SetDesktopName) .SetMethod("getLocale", &App::GetLocale) + .SetMethod("getSystemLocale", &App::GetSystemLocale) .SetMethod("getLocaleCountryCode", &App::GetLocaleCountryCode) #if BUILDFLAG(USE_NSS_CERTS) .SetMethod("importCertificate", &App::ImportCertificate) @@ -1859,9 +1834,7 @@ const char* App::GetTypeName() { return "App"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_app.h b/shell/browser/api/electron_api_app.h index d6bd52ada971f..079c5ca1fd6ab 100644 --- a/shell/browser/api/electron_api_app.h +++ b/shell/browser/api/electron_api_app.h @@ -96,7 +96,7 @@ class App : public ElectronBrowserClient::Delegate, void OnOpenURL(const std::string& url) override; void OnActivate(bool has_visible_windows) override; void OnWillFinishLaunching() override; - void OnFinishLaunching(const base::DictionaryValue& launch_info) override; + void OnFinishLaunching(base::Value::Dict launch_info) override; void OnAccessibilitySupportChanged() override; void OnPreMainMessageLoopRun() override; void OnPreCreateThreads() override; @@ -107,15 +107,13 @@ class App : public ElectronBrowserClient::Delegate, const std::string& error) override; void OnContinueUserActivity(bool* prevent_default, const std::string& type, - const base::DictionaryValue& user_info, - const base::DictionaryValue& details) override; - void OnUserActivityWasContinued( - const std::string& type, - const base::DictionaryValue& user_info) override; - void OnUpdateUserActivityState( - bool* prevent_default, - const std::string& type, - const base::DictionaryValue& user_info) override; + base::Value::Dict user_info, + base::Value::Dict details) override; + void OnUserActivityWasContinued(const std::string& type, + base::Value::Dict user_info) override; + void OnUpdateUserActivityState(bool* prevent_default, + const std::string& type, + base::Value::Dict user_info) override; void OnNewWindowForTab() override; void OnDidBecomeActive() override; #endif @@ -153,7 +151,7 @@ class App : public ElectronBrowserClient::Delegate, // content::GpuDataManagerObserver: void OnGpuInfoUpdate() override; - void OnGpuProcessCrashed(base::TerminationStatus status) override; + void OnGpuProcessCrashed() override; // content::BrowserChildProcessObserver: void BrowserChildProcessLaunchedAndConnected( @@ -193,12 +191,10 @@ class App : public ElectronBrowserClient::Delegate, void SetDesktopName(const std::string& desktop_name); std::string GetLocale(); std::string GetLocaleCountryCode(); - void OnFirstInstanceAck(const base::span* first_instance_data); - void OnSecondInstance( - const base::CommandLine& cmd, - const base::FilePath& cwd, - const std::vector additional_data, - const ProcessSingleton::NotificationAckCallback& ack_callback); + std::string GetSystemLocale(gin_helper::ErrorThrower thrower) const; + void OnSecondInstance(const base::CommandLine& cmd, + const base::FilePath& cwd, + const std::vector additional_data); bool HasSingleInstanceLock() const; bool RequestSingleInstanceLock(gin::Arguments* args); void ReleaseSingleInstanceLock(); diff --git a/shell/browser/api/electron_api_app_mac.mm b/shell/browser/api/electron_api_app_mac.mm index e9756836fb83f..3a42f85f6259e 100644 --- a/shell/browser/api/electron_api_app_mac.mm +++ b/shell/browser/api/electron_api_app_mac.mm @@ -13,9 +13,7 @@ #import #import -namespace electron { - -namespace api { +namespace electron::api { void App::SetAppLogsPath(gin_helper::ErrorThrower thrower, absl::optional custom_path) { @@ -82,6 +80,4 @@ return proc_translated == 1; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_app_mas.mm b/shell/browser/api/electron_api_app_mas.mm index 56f023d441021..9c924939f1bec 100644 --- a/shell/browser/api/electron_api_app_mas.mm +++ b/shell/browser/api/electron_api_app_mas.mm @@ -10,9 +10,7 @@ #include "base/strings/sys_string_conversions.h" -namespace electron { - -namespace api { +namespace electron::api { // Callback passed to js which will stop accessing the given bookmark. void OnStopAccessingSecurityScopedResource(NSURL* bookmarkUrl) { @@ -64,6 +62,4 @@ void OnStopAccessingSecurityScopedResource(NSURL* bookmarkUrl) { bookmarkUrl); } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_auto_updater.cc b/shell/browser/api/electron_api_auto_updater.cc index e49dcea4c5ea6..c214b5c4c2c7d 100644 --- a/shell/browser/api/electron_api_auto_updater.cc +++ b/shell/browser/api/electron_api_auto_updater.cc @@ -16,9 +16,7 @@ #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo AutoUpdater::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -32,7 +30,6 @@ AutoUpdater::~AutoUpdater() { void AutoUpdater::OnError(const std::string& message) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); v8::Local wrapper; if (GetWrapper(isolate).ToLocal(&wrapper)) { @@ -49,7 +46,6 @@ void AutoUpdater::OnError(const std::string& message, const int code, const std::string& domain) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); v8::Local wrapper; if (GetWrapper(isolate).ToLocal(&wrapper)) { @@ -136,9 +132,7 @@ const char* AutoUpdater::GetTypeName() { return "AutoUpdater"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_auto_updater.h b/shell/browser/api/electron_api_auto_updater.h index 6cbb7440cff5a..e31310a5d9473 100644 --- a/shell/browser/api/electron_api_auto_updater.h +++ b/shell/browser/api/electron_api_auto_updater.h @@ -13,9 +13,7 @@ #include "shell/browser/event_emitter_mixin.h" #include "shell/browser/window_list_observer.h" -namespace electron { - -namespace api { +namespace electron::api { class AutoUpdater : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -60,8 +58,6 @@ class AutoUpdater : public gin::Wrappable, void QuitAndInstall(); }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_AUTO_UPDATER_H_ diff --git a/shell/browser/api/electron_api_base_window.cc b/shell/browser/api/electron_api_base_window.cc index 3024eba2098ec..3a87a11d22f06 100644 --- a/shell/browser/api/electron_api_base_window.cc +++ b/shell/browser/api/electron_api_base_window.cc @@ -58,9 +58,7 @@ struct Converter { } // namespace gin #endif -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -209,7 +207,6 @@ void BaseWindow::OnWindowWillResize(const gfx::Rect& new_bounds, const gfx::ResizeEdge& edge, bool* prevent_default) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); gin_helper::Dictionary info = gin::Dictionary::CreateEmpty(isolate); info.Set("edge", edge); @@ -291,7 +288,7 @@ void BaseWindow::OnExecuteAppCommand(const std::string& command_name) { } void BaseWindow::OnTouchBarItemResult(const std::string& item_id, - const base::DictionaryValue& details) { + const base::Value::Dict& details) { Emit("-touch-bar-interaction", item_id, details); } @@ -309,7 +306,6 @@ void BaseWindow::OnSystemContextMenu(int x, int y, bool* prevent_default) { void BaseWindow::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) { if (IsWindowMessageHooked(message)) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope scope(isolate); messages_callback_map_[message].Run( ToBuffer(isolate, static_cast(&w_param), sizeof(WPARAM)), @@ -1325,9 +1321,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate, .SetProperty("id", &BaseWindow::GetID); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_base_window.h b/shell/browser/api/electron_api_base_window.h index 7651ddd0e653c..482f510f4ed40 100644 --- a/shell/browser/api/electron_api_base_window.h +++ b/shell/browser/api/electron_api_base_window.h @@ -10,7 +10,6 @@ #include #include -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "gin/handle.h" @@ -20,9 +19,7 @@ #include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/trackable_object.h" -namespace electron { - -namespace api { +namespace electron::api { class View; @@ -83,7 +80,7 @@ class BaseWindow : public gin_helper::TrackableObject, void OnWindowAlwaysOnTopChanged() override; void OnExecuteAppCommand(const std::string& command_name) override; void OnTouchBarItemResult(const std::string& item_id, - const base::DictionaryValue& details) override; + const base::Value::Dict& details) override; void OnNewWindowForTab() override; void OnSystemContextMenu(int x, int y, bool* prevent_default) override; #if BUILDFLAG(IS_WIN) @@ -258,8 +255,8 @@ class BaseWindow : public gin_helper::TrackableObject, template void EmitEventSoon(base::StringPiece eventName) { - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(base::IgnoreResult(&BaseWindow::Emit), weak_factory_.GetWeakPtr(), eventName)); } @@ -283,8 +280,6 @@ class BaseWindow : public gin_helper::TrackableObject, base::WeakPtrFactory weak_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_BASE_WINDOW_H_ diff --git a/shell/browser/api/electron_api_browser_view.cc b/shell/browser/api/electron_api_browser_view.cc index 1a9735cef11e3..eb0ac8e908959 100644 --- a/shell/browser/api/electron_api_browser_view.cc +++ b/shell/browser/api/electron_api_browser_view.cc @@ -6,10 +6,13 @@ #include +#include "content/browser/renderer_host/render_widget_host_view_base.h" // nogncheck +#include "content/public/browser/render_widget_host_view.h" #include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/browser.h" #include "shell/browser/native_browser_view.h" #include "shell/browser/ui/drag_util.h" +#include "shell/browser/web_contents_preferences.h" #include "shell/common/color_util.h" #include "shell/common/gin_converters/gfx_converter.h" #include "shell/common/gin_helper/dictionary.h" @@ -64,9 +67,7 @@ int32_t GetNextId() { } // namespace -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo BrowserView::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -154,11 +155,25 @@ gfx::Rect BrowserView::GetBounds() { } void BrowserView::SetBackgroundColor(const std::string& color_name) { - view_->SetBackgroundColor(ParseCSSColor(color_name)); + SkColor color = ParseCSSColor(color_name); + view_->SetBackgroundColor(color); if (web_contents()) { auto* wc = web_contents()->web_contents(); wc->SetPageBaseBackgroundColor(ParseCSSColor(color_name)); + + auto* const rwhv = wc->GetRenderWidgetHostView(); + if (rwhv) { + rwhv->SetBackgroundColor(color); + static_cast(rwhv) + ->SetContentBackgroundColor(color); + } + + // Ensure new color is stored in webPreferences, otherwise + // the color will be reset on the next load via HandleNewRenderFrame. + auto* web_preferences = WebContentsPreferences::From(wc); + if (web_preferences) + web_preferences->SetBackgroundColor(color); } } @@ -183,9 +198,7 @@ v8::Local BrowserView::FillObjectTemplate( .Build(); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_browser_view.h b/shell/browser/api/electron_api_browser_view.h index f635b0d8de817..6caacf41c5c79 100644 --- a/shell/browser/api/electron_api_browser_view.h +++ b/shell/browser/api/electron_api_browser_view.h @@ -28,9 +28,7 @@ namespace gin_helper { class Dictionary; } -namespace electron { - -namespace api { +namespace electron::api { class WebContents; @@ -90,8 +88,6 @@ class BrowserView : public gin::Wrappable, int32_t id_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_BROWSER_VIEW_H_ diff --git a/shell/browser/api/electron_api_browser_window.cc b/shell/browser/api/electron_api_browser_window.cc index e71b15fc0d575..3d1ec969123c8 100644 --- a/shell/browser/api/electron_api_browser_window.cc +++ b/shell/browser/api/electron_api_browser_window.cc @@ -33,9 +33,7 @@ #include "shell/browser/ui/views/win_frame_view.h" #endif -namespace electron { - -namespace api { +namespace electron::api { BrowserWindow::BrowserWindow(gin::Arguments* args, const gin_helper::Dictionary& options) @@ -290,7 +288,7 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) { } else { web_contents()->Close(); } -} // namespace api +} void BrowserWindow::OnWindowBlur() { if (api_web_contents_) @@ -349,7 +347,6 @@ void BrowserWindow::UpdateWindowControlsOverlay( void BrowserWindow::CloseImmediately() { // Close all child windows before closing current window. - v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); for (v8::Local value : child_windows_.Values(isolate())) { gin::Handle child; @@ -608,9 +605,7 @@ v8::Local BrowserWindow::From(v8::Isolate* isolate, return v8::Null(isolate); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_browser_window.h b/shell/browser/api/electron_api_browser_window.h index 00bdf694e8ff3..91195053495ba 100644 --- a/shell/browser/api/electron_api_browser_window.h +++ b/shell/browser/api/electron_api_browser_window.h @@ -14,9 +14,7 @@ #include "shell/browser/ui/drag_util.h" #include "shell/common/gin_helper/error_thrower.h" -namespace electron { - -namespace api { +namespace electron::api { class BrowserWindow : public BaseWindow, public content::RenderWidgetHost::InputEventObserver, @@ -133,8 +131,6 @@ class BrowserWindow : public BaseWindow, base::WeakPtrFactory weak_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_BROWSER_WINDOW_H_ diff --git a/shell/browser/api/electron_api_browser_window_mac.mm b/shell/browser/api/electron_api_browser_window_mac.mm index 759f85096f4fa..23d1fa35405a8 100644 --- a/shell/browser/api/electron_api_browser_window_mac.mm +++ b/shell/browser/api/electron_api_browser_window_mac.mm @@ -15,9 +15,7 @@ #include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h" #include "shell/browser/ui/inspectable_web_contents_view.h" -namespace electron { - -namespace api { +namespace electron::api { void BrowserWindow::OverrideNSWindowContentView( InspectableWebContentsView* view) { @@ -102,6 +100,4 @@ [[webView window] setMovableByWindowBackground:YES]; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_browser_window_views.cc b/shell/browser/api/electron_api_browser_window_views.cc index 9fdbf039f3e0d..e5b37aaf5fd5b 100644 --- a/shell/browser/api/electron_api_browser_window_views.cc +++ b/shell/browser/api/electron_api_browser_window_views.cc @@ -8,9 +8,7 @@ #include "shell/browser/native_window_views.h" #include "ui/aura/window.h" -namespace electron { - -namespace api { +namespace electron::api { void BrowserWindow::UpdateDraggableRegions( const std::vector& regions) { @@ -36,6 +34,4 @@ void BrowserWindow::UpdateDraggableRegions( ->UpdateDraggableRegions(draggable_regions_); } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_content_tracing.cc b/shell/browser/api/electron_api_content_tracing.cc index aa1047c403021..a1628bb7f37fa 100644 --- a/shell/browser/api/electron_api_content_tracing.cc +++ b/shell/browser/api/electron_api_content_tracing.cc @@ -42,9 +42,10 @@ struct Converter { } } - base::DictionaryValue memory_dump_config; + base::Value::Dict memory_dump_config; if (ConvertFromV8(isolate, val, &memory_dump_config)) { - *out = base::trace_event::TraceConfig(memory_dump_config); + *out = base::trace_event::TraceConfig( + base::Value(std::move(memory_dump_config))); return true; } diff --git a/shell/browser/api/electron_api_cookies.cc b/shell/browser/api/electron_api_cookies.cc index 5afc6c711f223..e4cebe4fb572c 100644 --- a/shell/browser/api/electron_api_cookies.cc +++ b/shell/browser/api/electron_api_cookies.cc @@ -91,9 +91,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -119,27 +117,27 @@ bool MatchesDomain(std::string filter, const std::string& domain) { } // Returns whether |cookie| matches |filter|. -bool MatchesCookie(const base::Value& filter, +bool MatchesCookie(const base::Value::Dict& filter, const net::CanonicalCookie& cookie) { const std::string* str; - if ((str = filter.FindStringKey("name")) && *str != cookie.Name()) + if ((str = filter.FindString("name")) && *str != cookie.Name()) return false; - if ((str = filter.FindStringKey("path")) && *str != cookie.Path()) + if ((str = filter.FindString("path")) && *str != cookie.Path()) return false; - if ((str = filter.FindStringKey("domain")) && + if ((str = filter.FindString("domain")) && !MatchesDomain(*str, cookie.Domain())) return false; - absl::optional secure_filter = filter.FindBoolKey("secure"); + absl::optional secure_filter = filter.FindBool("secure"); if (secure_filter && *secure_filter == cookie.IsSecure()) return false; - absl::optional session_filter = filter.FindBoolKey("session"); + absl::optional session_filter = filter.FindBool("session"); if (session_filter && *session_filter != !cookie.IsPersistent()) return false; return true; } // Remove cookies from |list| not matching |filter|, and pass it to |callback|. -void FilterCookies(const base::Value& filter, +void FilterCookies(base::Value::Dict filter, gin_helper::Promise promise, const net::CookieList& cookies) { net::CookieList result; @@ -151,11 +149,11 @@ void FilterCookies(const base::Value& filter, } void FilterCookieWithStatuses( - const base::Value& filter, + base::Value::Dict filter, gin_helper::Promise promise, const net::CookieAccessResultList& list, const net::CookieAccessResultList& excluded_list) { - FilterCookies(filter, std::move(promise), + FilterCookies(std::move(filter), std::move(promise), net::cookie_util::StripAccessResults(list)); } @@ -233,7 +231,7 @@ v8::Local Cookies::Get(v8::Isolate* isolate, auto* storage_partition = browser_context_->GetDefaultStoragePartition(); auto* manager = storage_partition->GetCookieManagerForBrowserProcess(); - base::DictionaryValue dict; + base::Value::Dict dict; gin::ConvertFromV8(isolate, filter.GetHandle(), &dict); std::string url; @@ -282,31 +280,31 @@ v8::Local Cookies::Remove(v8::Isolate* isolate, } v8::Local Cookies::Set(v8::Isolate* isolate, - const base::DictionaryValue& details) { + base::Value::Dict details) { gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); - const std::string* url_string = details.FindStringKey("url"); + const std::string* url_string = details.FindString("url"); if (!url_string) { promise.RejectWithErrorMessage("Missing required option 'url'"); return handle; } - const std::string* name = details.FindStringKey("name"); - const std::string* value = details.FindStringKey("value"); - const std::string* domain = details.FindStringKey("domain"); - const std::string* path = details.FindStringKey("path"); - bool http_only = details.FindBoolKey("httpOnly").value_or(false); - const std::string* same_site_string = details.FindStringKey("sameSite"); + const std::string* name = details.FindString("name"); + const std::string* value = details.FindString("value"); + const std::string* domain = details.FindString("domain"); + const std::string* path = details.FindString("path"); + bool http_only = details.FindBool("httpOnly").value_or(false); + const std::string* same_site_string = details.FindString("sameSite"); net::CookieSameSite same_site; std::string error = StringToCookieSameSite(same_site_string, &same_site); if (!error.empty()) { promise.RejectWithErrorMessage(error); return handle; } - bool secure = details.FindBoolKey("secure").value_or( + bool secure = details.FindBool("secure").value_or( same_site == net::CookieSameSite::NO_RESTRICTION); bool same_party = - details.FindBoolKey("sameParty") + details.FindBool("sameParty") .value_or(secure && same_site != net::CookieSameSite::STRICT_MODE); GURL url(url_string ? *url_string : ""); @@ -319,10 +317,9 @@ v8::Local Cookies::Set(v8::Isolate* isolate, auto canonical_cookie = net::CanonicalCookie::CreateSanitizedCookie( url, name ? *name : "", value ? *value : "", domain ? *domain : "", - path ? *path : "", - ParseTimeProperty(details.FindDoubleKey("creationDate")), - ParseTimeProperty(details.FindDoubleKey("expirationDate")), - ParseTimeProperty(details.FindDoubleKey("lastAccessDate")), secure, + path ? *path : "", ParseTimeProperty(details.FindDouble("creationDate")), + ParseTimeProperty(details.FindDouble("expirationDate")), + ParseTimeProperty(details.FindDouble("lastAccessDate")), secure, http_only, same_site, net::COOKIE_PRIORITY_DEFAULT, same_party, absl::nullopt); if (!canonical_cookie || !canonical_cookie->IsCanonical()) { @@ -397,6 +394,4 @@ const char* Cookies::GetTypeName() { return "Cookies"; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_cookies.h b/shell/browser/api/electron_api_cookies.h index fbfa335ce9f8a..3b98c033afe6d 100644 --- a/shell/browser/api/electron_api_cookies.h +++ b/shell/browser/api/electron_api_cookies.h @@ -8,6 +8,7 @@ #include #include "base/callback_list.h" +#include "base/values.h" #include "gin/handle.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_change_dispatcher.h" @@ -15,10 +16,6 @@ #include "shell/common/gin_helper/promise.h" #include "shell/common/gin_helper/trackable_object.h" -namespace base { -class DictionaryValue; -} - namespace gin_helper { class Dictionary; } @@ -51,8 +48,7 @@ class Cookies : public gin::Wrappable, v8::Local Get(v8::Isolate*, const gin_helper::Dictionary& filter); - v8::Local Set(v8::Isolate*, - const base::DictionaryValue& details); + v8::Local Set(v8::Isolate*, base::Value::Dict details); v8::Local Remove(v8::Isolate*, const GURL& url, const std::string& name); diff --git a/shell/browser/api/electron_api_crash_reporter.cc b/shell/browser/api/electron_api_crash_reporter.cc index 7740441b3a0bc..76fd7ef64d4a4 100644 --- a/shell/browser/api/electron_api_crash_reporter.cc +++ b/shell/browser/api/electron_api_crash_reporter.cc @@ -16,6 +16,7 @@ #include "base/path_service.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" +#include "base/trace_event/trace_event.h" #include "chrome/common/chrome_paths.h" #include "components/upload_list/crash_upload_list.h" #include "components/upload_list/text_log_upload_list.h" @@ -63,11 +64,7 @@ bool g_crash_reporter_initialized = false; } // namespace -namespace electron { - -namespace api { - -namespace crash_reporter { +namespace electron::api::crash_reporter { #if defined(MAS_BUILD) namespace { @@ -135,6 +132,7 @@ void Start(const std::string& submit_url, const std::map& global_extra, const std::map& extra, bool is_node_process) { + TRACE_EVENT0("electron", "crash_reporter::Start"); #if !defined(MAS_BUILD) if (g_crash_reporter_initialized) return; @@ -194,11 +192,7 @@ void Start(const std::string& submit_url, #endif } -} // namespace crash_reporter - -} // namespace api - -} // namespace electron +} // namespace electron::api::crash_reporter namespace { diff --git a/shell/browser/api/electron_api_crash_reporter.h b/shell/browser/api/electron_api_crash_reporter.h index 598c343c03c69..8b96b8e929496 100644 --- a/shell/browser/api/electron_api_crash_reporter.h +++ b/shell/browser/api/electron_api_crash_reporter.h @@ -9,11 +9,7 @@ #include #include "base/files/file_path.h" -namespace electron { - -namespace api { - -namespace crash_reporter { +namespace electron::api::crash_reporter { bool IsCrashReporterEnabled(); @@ -32,10 +28,6 @@ void Start(const std::string& submit_url, const std::map& extra, bool is_node_process); -} // namespace crash_reporter - -} // namespace api - -} // namespace electron +} // namespace electron::api::crash_reporter #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_CRASH_REPORTER_H_ diff --git a/shell/browser/api/electron_api_data_pipe_holder.cc b/shell/browser/api/electron_api_data_pipe_holder.cc index 85ee9204f4ec4..67fe81959a12f 100644 --- a/shell/browser/api/electron_api_data_pipe_holder.cc +++ b/shell/browser/api/electron_api_data_pipe_holder.cc @@ -18,9 +18,7 @@ #include "shell/common/node_includes.h" -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -88,8 +86,11 @@ class DataPipeReader { if (result == MOJO_RESULT_OK) { // success remaining_size_ -= length; head_ += length; - if (remaining_size_ == 0) + if (remaining_size_ == 0) { OnSuccess(); + } else { + handle_watcher_.ArmOrNotify(); + } } else if (result == MOJO_RESULT_SHOULD_WAIT) { // IO pending handle_watcher_.ArmOrNotify(); } else { // error @@ -103,26 +104,18 @@ class DataPipeReader { } void OnSuccess() { - // Pass the buffer to JS. - // - // Note that the lifetime of the native buffer belongs to us, and we will - // free memory when JS buffer gets garbage collected. - v8::Locker locker(promise_.isolate()); + // Copy the buffer to JS. + // TODO(nornagon): make this zero-copy by allocating the array buffer + // inside the sandbox v8::HandleScope handle_scope(promise_.isolate()); v8::Local buffer = - node::Buffer::New(promise_.isolate(), &buffer_.front(), buffer_.size(), - &DataPipeReader::FreeBuffer, this) + node::Buffer::Copy(promise_.isolate(), &buffer_.front(), buffer_.size()) .ToLocalChecked(); promise_.Resolve(buffer); // Destroy data pipe. handle_watcher_.Cancel(); - data_pipe_.reset(); - data_pipe_getter_.reset(); - } - - static void FreeBuffer(char* data, void* self) { - delete static_cast(self); + delete this; } gin_helper::Promise> promise_; @@ -189,6 +182,4 @@ gin::Handle DataPipeHolder::From(v8::Isolate* isolate, return gin::Handle(); } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_data_pipe_holder.h b/shell/browser/api/electron_api_data_pipe_holder.h index 535440d26838a..17b9dd244abcb 100644 --- a/shell/browser/api/electron_api_data_pipe_holder.h +++ b/shell/browser/api/electron_api_data_pipe_holder.h @@ -13,9 +13,7 @@ #include "services/network/public/cpp/data_element.h" #include "services/network/public/mojom/data_pipe_getter.mojom.h" -namespace electron { - -namespace api { +namespace electron::api { // Retains reference to the data pipe. class DataPipeHolder : public gin::Wrappable { @@ -49,8 +47,6 @@ class DataPipeHolder : public gin::Wrappable { mojo::Remote data_pipe_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_DATA_PIPE_HOLDER_H_ diff --git a/shell/browser/api/electron_api_debugger.cc b/shell/browser/api/electron_api_debugger.cc index 2569e24b3d390..e24c0dca3d658 100644 --- a/shell/browser/api/electron_api_debugger.cc +++ b/shell/browser/api/electron_api_debugger.cc @@ -20,9 +20,7 @@ using content::DevToolsAgentHost; -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo Debugger::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -43,50 +41,39 @@ void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host, DCHECK(agent_host == agent_host_); v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); base::StringPiece message_str(reinterpret_cast(message.data()), message.size()); - std::unique_ptr parsed_message = - base::JSONReader::ReadDeprecated(message_str, - base::JSON_REPLACE_INVALID_CHARACTERS); + absl::optional parsed_message = base::JSONReader::Read( + message_str, base::JSON_REPLACE_INVALID_CHARACTERS); if (!parsed_message || !parsed_message->is_dict()) return; - auto* dict = static_cast(parsed_message.get()); - int id; - if (!dict->GetInteger("id", &id)) { - std::string method; - if (!dict->GetString("method", &method)) + base::Value::Dict& dict = parsed_message->GetDict(); + absl::optional id = dict.FindInt("id"); + if (!id) { + std::string* method = dict.FindString("method"); + if (!method) return; - std::string session_id; - dict->GetString("sessionId", &session_id); - base::DictionaryValue* params_value = nullptr; - base::DictionaryValue params; - if (dict->GetDictionary("params", ¶ms_value)) - params.Swap(params_value); - Emit("message", method, params, session_id); + std::string* session_id = dict.FindString("sessionId"); + base::Value::Dict* params = dict.FindDict("params"); + Emit("message", *method, params ? std::move(*params) : base::Value::Dict(), + session_id ? *session_id : ""); } else { - auto it = pending_requests_.find(id); + auto it = pending_requests_.find(*id); if (it == pending_requests_.end()) return; - gin_helper::Promise promise = std::move(it->second); + gin_helper::Promise promise = std::move(it->second); pending_requests_.erase(it); - base::DictionaryValue* error = nullptr; - if (dict->GetDictionary("error", &error)) { - std::string message; - error->GetString("message", &message); - promise.RejectWithErrorMessage(message); + base::Value::Dict* error = dict.FindDict("error"); + if (error) { + std::string* message = error->FindString("message"); + promise.RejectWithErrorMessage(message ? *message : ""); } else { - base::DictionaryValue* result_body = nullptr; - base::DictionaryValue result; - if (dict->GetDictionary("result", &result_body)) { - result.Swap(result_body); - } - promise.Resolve(result); + base::Value::Dict* result = dict.FindDict("result"); + promise.Resolve(result ? std::move(*result) : base::Value::Dict()); } } } @@ -137,7 +124,7 @@ void Debugger::Detach() { v8::Local Debugger::SendCommand(gin::Arguments* args) { v8::Isolate* isolate = args->isolate(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); if (!agent_host_) { @@ -151,7 +138,7 @@ v8::Local Debugger::SendCommand(gin::Arguments* args) { return handle; } - base::DictionaryValue command_params; + base::Value::Dict command_params; args->GetNext(&command_params); std::string session_id; @@ -160,22 +147,21 @@ v8::Local Debugger::SendCommand(gin::Arguments* args) { return handle; } - base::DictionaryValue request; + base::Value::Dict request; int request_id = ++previous_request_id_; pending_requests_.emplace(request_id, std::move(promise)); - request.SetInteger("id", request_id); - request.SetString("method", method); - if (!command_params.DictEmpty()) { - request.Set("params", - base::Value::ToUniquePtrValue(command_params.Clone())); + request.Set("id", request_id); + request.Set("method", method); + if (!command_params.empty()) { + request.Set("params", base::Value(std::move(command_params))); } if (!session_id.empty()) { - request.SetString("sessionId", session_id); + request.Set("sessionId", session_id); } std::string json_args; - base::JSONWriter::Write(request, &json_args); + base::JSONWriter::Write(base::Value(std::move(request)), &json_args); agent_host_->DispatchProtocolMessage( this, base::as_bytes(base::make_span(json_args))); @@ -208,6 +194,4 @@ const char* Debugger::GetTypeName() { return "Debugger"; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_debugger.h b/shell/browser/api/electron_api_debugger.h index 204cd42365ebf..e9388df8b25a2 100644 --- a/shell/browser/api/electron_api_debugger.h +++ b/shell/browser/api/electron_api_debugger.h @@ -22,9 +22,7 @@ class DevToolsAgentHost; class WebContents; } // namespace content -namespace electron { - -namespace api { +namespace electron::api { class Debugger : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -59,7 +57,7 @@ class Debugger : public gin::Wrappable, private: using PendingRequestMap = - std::map>; + std::map>; void Attach(gin::Arguments* args); bool IsAttached(); @@ -74,8 +72,6 @@ class Debugger : public gin::Wrappable, int previous_request_id_ = 0; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_DEBUGGER_H_ diff --git a/shell/browser/api/electron_api_desktop_capturer.cc b/shell/browser/api/electron_api_desktop_capturer.cc index 00721e52bfcf8..63fa340e273bf 100644 --- a/shell/browser/api/electron_api_desktop_capturer.cc +++ b/shell/browser/api/electron_api_desktop_capturer.cc @@ -4,6 +4,7 @@ #include "shell/browser/api/electron_api_desktop_capturer.h" +#include #include #include #include @@ -24,12 +25,125 @@ #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" +#if defined(USE_OZONE) +#include "ui/ozone/buildflags.h" +#if BUILDFLAG(OZONE_PLATFORM_X11) +#define USE_OZONE_PLATFORM_X11 +#endif +#endif + #if BUILDFLAG(IS_WIN) #include "third_party/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h" #include "third_party/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h" #include "ui/display/win/display_info.h" +#elif BUILDFLAG(IS_LINUX) +#if defined(USE_OZONE_PLATFORM_X11) +#include "base/logging.h" +#include "ui/base/x/x11_display_util.h" +#include "ui/base/x/x11_util.h" +#include "ui/display/util/edid_parser.h" // nogncheck +#include "ui/gfx/x/randr.h" +#include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/xproto_util.h" +#endif // defined(USE_OZONE_PLATFORM_X11) #endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_LINUX) +// Private function in ui/base/x/x11_display_util.cc +std::map GetMonitors(int version, + x11::RandR* randr, + x11::Window window) { + std::map output_to_monitor; + if (version >= 105) { + if (auto reply = randr->GetMonitors({window}).Sync()) { + for (size_t monitor = 0; monitor < reply->monitors.size(); monitor++) { + for (x11::RandR::Output output : reply->monitors[monitor].outputs) + output_to_monitor[output] = monitor; + } + } + } + return output_to_monitor; +} +// Get the EDID data from the |output| and stores to |edid|. +// Private function in ui/base/x/x11_display_util.cc +std::vector GetEDIDProperty(x11::RandR* randr, + x11::RandR::Output output) { + constexpr const char kRandrEdidProperty[] = "EDID"; + auto future = randr->GetOutputProperty(x11::RandR::GetOutputPropertyRequest{ + .output = output, + .property = x11::GetAtom(kRandrEdidProperty), + .long_length = 128}); + auto response = future.Sync(); + std::vector edid; + if (response && response->format == 8 && response->type != x11::Atom::None) + edid = std::move(response->data); + return edid; +} + +// Find the mapping from monitor name atom to the display identifier +// that the screen API uses. Based on the logic in BuildDisplaysFromXRandRInfo +// in ui/base/x/x11_display_util.cc +std::map MonitorAtomIdToDisplayId() { + auto* connection = x11::Connection::Get(); + auto& randr = connection->randr(); + auto x_root_window = ui::GetX11RootWindow(); + int version = ui::GetXrandrVersion(); + + std::map monitor_atom_to_display; + + auto resources = randr.GetScreenResourcesCurrent({x_root_window}).Sync(); + if (!resources) { + LOG(ERROR) << "XRandR returned no displays; don't know how to map ids"; + return monitor_atom_to_display; + } + + std::map output_to_monitor = + GetMonitors(version, &randr, x_root_window); + auto monitors_reply = randr.GetMonitors({x_root_window}).Sync(); + + for (size_t i = 0; i < resources->outputs.size(); i++) { + x11::RandR::Output output_id = resources->outputs[i]; + auto output_info = + randr.GetOutputInfo({output_id, resources->config_timestamp}).Sync(); + if (!output_info) + continue; + + if (output_info->connection != x11::RandR::RandRConnection::Connected) + continue; + + if (output_info->crtc == static_cast(0)) + continue; + + auto crtc = + randr.GetCrtcInfo({output_info->crtc, resources->config_timestamp}) + .Sync(); + if (!crtc) + continue; + display::EdidParser edid_parser( + GetEDIDProperty(&randr, static_cast(output_id))); + auto output_32 = static_cast(output_id); + int64_t display_id = + output_32 > 0xff ? 0 : edid_parser.GetIndexBasedDisplayId(output_32); + // It isn't ideal, but if we can't parse the EDID data, fall back on the + // display number. + if (!display_id) + display_id = i; + + // Find the mapping between output identifier and the monitor name atom + // Note this isn't the atom string, but the numeric atom identifier, + // since this is what the WebRTC system uses as the display identifier + auto output_monitor_iter = output_to_monitor.find(output_id); + if (output_monitor_iter != output_to_monitor.end()) { + x11::Atom atom = + monitors_reply->monitors[output_monitor_iter->second].name; + monitor_atom_to_display[static_cast(atom)] = display_id; + } + } + + return monitor_atom_to_display; +} +#endif + namespace gin { template <> @@ -59,9 +173,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo DesktopCapturer::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -155,7 +267,6 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) { if (!webrtc::DxgiDuplicatorController::Instance()->GetDeviceNames( &device_names)) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope scope(isolate); gin_helper::CallMethod(this, "_onerror", "Failed to get sources."); @@ -181,17 +292,28 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) { for (auto& source : screen_sources) { source.display_id = base::NumberToString(source.media_list_source.id.id); } +#elif BUILDFLAG(IS_LINUX) +#if defined(USE_OZONE_PLATFORM_X11) + // On Linux, with X11, the source id is the numeric value of the + // display name atom and the display id is either the EDID or the + // loop index when that display was found (see + // BuildDisplaysFromXRandRInfo in ui/base/x/x11_display_util.cc) + std::map monitor_atom_to_display_id = + MonitorAtomIdToDisplayId(); + for (auto& source : screen_sources) { + auto display_id_iter = + monitor_atom_to_display_id.find(source.media_list_source.id.id); + if (display_id_iter != monitor_atom_to_display_id.end()) + source.display_id = base::NumberToString(display_id_iter->second); + } +#endif // defined(USE_OZONE_PLATFORM_X11) #endif // BUILDFLAG(IS_WIN) - // TODO(ajmacd): Add Linux support. The IDs across APIs differ but Chrome - // only supports capturing the entire desktop on Linux. Revisit this if - // individual screen support is added. std::move(screen_sources.begin(), screen_sources.end(), std::back_inserter(captured_sources_)); } if (!capture_window_ && !capture_screen_) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope scope(isolate); gin_helper::CallMethod(this, "_onfinished", captured_sources_); @@ -219,9 +341,7 @@ const char* DesktopCapturer::GetTypeName() { return "DesktopCapturer"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_desktop_capturer.h b/shell/browser/api/electron_api_desktop_capturer.h index 85b0eaa191195..0d16711d28bdc 100644 --- a/shell/browser/api/electron_api_desktop_capturer.h +++ b/shell/browser/api/electron_api_desktop_capturer.h @@ -15,9 +15,7 @@ #include "gin/wrappable.h" #include "shell/common/gin_helper/pinnable.h" -namespace electron { - -namespace api { +namespace electron::api { class DesktopCapturer : public gin::Wrappable, public gin_helper::Pinnable, @@ -77,8 +75,6 @@ class DesktopCapturer : public gin::Wrappable, base::WeakPtrFactory weak_ptr_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_DESKTOP_CAPTURER_H_ diff --git a/shell/browser/api/electron_api_download_item.cc b/shell/browser/api/electron_api_download_item.cc index 6943d8effcced..68a502a028844 100644 --- a/shell/browser/api/electron_api_download_item.cc +++ b/shell/browser/api/electron_api_download_item.cc @@ -48,9 +48,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -301,6 +299,4 @@ gin::Handle DownloadItem::FromOrCreate( return handle; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_download_item.h b/shell/browser/api/electron_api_download_item.h index 4ca867baf52f7..85e314d9c6ad0 100644 --- a/shell/browser/api/electron_api_download_item.h +++ b/shell/browser/api/electron_api_download_item.h @@ -18,9 +18,7 @@ class GURL; -namespace electron { - -namespace api { +namespace electron::api { class DownloadItem : public gin::Wrappable, public gin_helper::Pinnable, @@ -87,8 +85,6 @@ class DownloadItem : public gin::Wrappable, base::WeakPtrFactory weak_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_DOWNLOAD_ITEM_H_ diff --git a/shell/browser/api/electron_api_global_shortcut.cc b/shell/browser/api/electron_api_global_shortcut.cc index e3daf615a6172..b78f67e06657a 100644 --- a/shell/browser/api/electron_api_global_shortcut.cc +++ b/shell/browser/api/electron_api_global_shortcut.cc @@ -9,7 +9,7 @@ #include "base/containers/contains.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/common/extensions/command.h" +#include "extensions/common/command.h" #include "gin/dictionary.h" #include "gin/object_template_builder.h" #include "shell/browser/api/electron_api_system_preferences.h" @@ -51,9 +51,7 @@ bool MapHasMediaKeys( } // namespace -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo GlobalShortcut::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -182,9 +180,7 @@ const char* GlobalShortcut::GetTypeName() { return "GlobalShortcut"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_global_shortcut.h b/shell/browser/api/electron_api_global_shortcut.h index 19a86fe2963d1..4f843a487c510 100644 --- a/shell/browser/api/electron_api_global_shortcut.h +++ b/shell/browser/api/electron_api_global_shortcut.h @@ -14,9 +14,7 @@ #include "gin/wrappable.h" #include "ui/base/accelerators/accelerator.h" -namespace electron { - -namespace api { +namespace electron::api { class GlobalShortcut : public extensions::GlobalShortcutListener::Observer, public gin::Wrappable { @@ -56,8 +54,6 @@ class GlobalShortcut : public extensions::GlobalShortcutListener::Observer, AcceleratorCallbackMap accelerator_callback_map_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_GLOBAL_SHORTCUT_H_ diff --git a/shell/browser/api/electron_api_in_app_purchase.cc b/shell/browser/api/electron_api_in_app_purchase.cc index ef80526286c67..8162688bc8b30 100644 --- a/shell/browser/api/electron_api_in_app_purchase.cc +++ b/shell/browser/api/electron_api_in_app_purchase.cc @@ -135,9 +135,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo InAppPurchase::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -211,9 +209,7 @@ void InAppPurchase::OnTransactionsUpdated( } #endif -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_in_app_purchase.h b/shell/browser/api/electron_api_in_app_purchase.h index bd765bb178789..4b646410545d3 100644 --- a/shell/browser/api/electron_api_in_app_purchase.h +++ b/shell/browser/api/electron_api_in_app_purchase.h @@ -16,9 +16,7 @@ #include "shell/browser/mac/in_app_purchase_product.h" #include "v8/include/v8.h" -namespace electron { - -namespace api { +namespace electron::api { class InAppPurchase : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -51,8 +49,6 @@ class InAppPurchase : public gin::Wrappable, const std::vector& transactions) override; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_IN_APP_PURCHASE_H_ diff --git a/shell/browser/api/electron_api_menu.cc b/shell/browser/api/electron_api_menu.cc index b77b46d3541e5..1208144c96798 100644 --- a/shell/browser/api/electron_api_menu.cc +++ b/shell/browser/api/electron_api_menu.cc @@ -44,9 +44,7 @@ struct Converter { #endif -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo Menu::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -146,7 +144,6 @@ void Menu::OnMenuWillShow(ui::SimpleMenuModel* source) { base::OnceClosure Menu::BindSelfToClosure(base::OnceClosure callback) { // return ((callback, ref) => { callback() }).bind(null, callback, this) v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope scope(isolate); v8::Local self; if (GetWrapper(isolate).ToLocal(&self)) { @@ -213,7 +210,7 @@ void Menu::Clear() { } int Menu::GetIndexOfCommandId(int command_id) const { - return model_->GetIndexOfCommandId(command_id); + return model_->GetIndexOfCommandId(command_id).value_or(-1); } int Menu::GetItemCount() const { @@ -302,9 +299,7 @@ v8::Local Menu::FillObjectTemplate( .Build(); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_menu.h b/shell/browser/api/electron_api_menu.h index 09756a1a773a0..eb2275b2656ea 100644 --- a/shell/browser/api/electron_api_menu.h +++ b/shell/browser/api/electron_api_menu.h @@ -16,9 +16,7 @@ #include "shell/common/gin_helper/constructible.h" #include "shell/common/gin_helper/pinnable.h" -namespace electron { - -namespace api { +namespace electron::api { class Menu : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -123,9 +121,7 @@ class Menu : public gin::Wrappable, bool WorksWhenHiddenAt(int index) const; }; -} // namespace api - -} // namespace electron +} // namespace electron::api namespace gin { diff --git a/shell/browser/api/electron_api_menu_mac.h b/shell/browser/api/electron_api_menu_mac.h index f47276ea8d848..074f850604d69 100644 --- a/shell/browser/api/electron_api_menu_mac.h +++ b/shell/browser/api/electron_api_menu_mac.h @@ -13,9 +13,7 @@ using base::scoped_nsobject; -namespace electron { - -namespace api { +namespace electron::api { class MenuMac : public Menu { protected: @@ -50,8 +48,6 @@ class MenuMac : public Menu { base::WeakPtrFactory weak_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_MENU_MAC_H_ diff --git a/shell/browser/api/electron_api_menu_mac.mm b/shell/browser/api/electron_api_menu_mac.mm index c57391b19487f..eff18b2efd24c 100644 --- a/shell/browser/api/electron_api_menu_mac.mm +++ b/shell/browser/api/electron_api_menu_mac.mm @@ -10,7 +10,6 @@ #include "base/mac/scoped_sending_event.h" #include "base/strings/sys_string_conversions.h" #include "base/task/current_thread.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" @@ -43,9 +42,7 @@ } // namespace -namespace electron { - -namespace api { +namespace electron::api { MenuMac::MenuMac(gin::Arguments* args) : Menu(args) {} @@ -134,7 +131,7 @@ if (!item) { CGFloat windowBottom = CGRectGetMinY([view window].frame); CGFloat lowestMenuPoint = windowBottom + position.y - [menu size].height; - CGFloat screenBottom = CGRectGetMinY([view window].screen.frame); + CGFloat screenBottom = CGRectGetMinY([view window].screen.visibleFrame); CGFloat distanceFromBottom = lowestMenuPoint - screenBottom; if (distanceFromBottom < 0) position.y = position.y - distanceFromBottom + 4; @@ -143,7 +140,7 @@ // Place the menu left of cursor if it is overflowing off right of screen. CGFloat windowLeft = CGRectGetMinX([view window].frame); CGFloat rightmostMenuPoint = windowLeft + position.x + [menu size].width; - CGFloat screenRight = CGRectGetMaxX([view window].screen.frame); + CGFloat screenRight = CGRectGetMaxX([view window].screen.visibleFrame); if (rightmostMenuPoint > screenRight) position.x = position.x - [menu size].width; @@ -263,6 +260,4 @@ return handle; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_menu_views.cc b/shell/browser/api/electron_api_menu_views.cc index 447a6fbb96a58..908ae1bc925c1 100644 --- a/shell/browser/api/electron_api_menu_views.cc +++ b/shell/browser/api/electron_api_menu_views.cc @@ -13,9 +13,7 @@ using views::MenuRunner; -namespace electron { - -namespace api { +namespace electron::api { MenuViews::MenuViews(gin::Arguments* args) : Menu(args) {} @@ -91,6 +89,4 @@ gin::Handle Menu::New(gin::Arguments* args) { return handle; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_menu_views.h b/shell/browser/api/electron_api_menu_views.h index a0d40f9354a06..a89f9420e7c5d 100644 --- a/shell/browser/api/electron_api_menu_views.h +++ b/shell/browser/api/electron_api_menu_views.h @@ -13,9 +13,7 @@ #include "ui/display/screen.h" #include "ui/views/controls/menu/menu_runner.h" -namespace electron { - -namespace api { +namespace electron::api { class MenuViews : public Menu { public: @@ -39,8 +37,6 @@ class MenuViews : public Menu { base::WeakPtrFactory weak_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_MENU_VIEWS_H_ diff --git a/shell/browser/api/electron_api_native_theme.cc b/shell/browser/api/electron_api_native_theme.cc index 7c511685d1afa..b56e7a1277e74 100644 --- a/shell/browser/api/electron_api_native_theme.cc +++ b/shell/browser/api/electron_api_native_theme.cc @@ -6,7 +6,6 @@ #include -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "gin/handle.h" @@ -17,9 +16,7 @@ #include "ui/gfx/color_utils.h" #include "ui/native_theme/native_theme.h" -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo NativeTheme::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -39,8 +36,8 @@ void NativeTheme::OnNativeThemeUpdatedOnUI() { } void NativeTheme::OnNativeThemeUpdated(ui::NativeTheme* theme) { - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&NativeTheme::OnNativeThemeUpdatedOnUI, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&NativeTheme::OnNativeThemeUpdatedOnUI, base::Unretained(this))); } @@ -118,9 +115,7 @@ const char* NativeTheme::GetTypeName() { return "NativeTheme"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { @@ -175,4 +170,4 @@ bool Converter::FromV8( } // namespace gin -NODE_LINKED_MODULE_CONTEXT_AWARE(electron_common_native_theme, Initialize) +NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_native_theme, Initialize) diff --git a/shell/browser/api/electron_api_native_theme.h b/shell/browser/api/electron_api_native_theme.h index 5f26ab74d6ba9..3983360c98b4e 100644 --- a/shell/browser/api/electron_api_native_theme.h +++ b/shell/browser/api/electron_api_native_theme.h @@ -11,9 +11,7 @@ #include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme_observer.h" -namespace electron { - -namespace api { +namespace electron::api { class NativeTheme : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -57,9 +55,7 @@ class NativeTheme : public gin::Wrappable, ui::NativeTheme* web_theme_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api namespace gin { diff --git a/shell/browser/api/electron_api_native_theme_mac.mm b/shell/browser/api/electron_api_native_theme_mac.mm index 2dab1ea61ae0b..fefdf341e2910 100644 --- a/shell/browser/api/electron_api_native_theme_mac.mm +++ b/shell/browser/api/electron_api_native_theme_mac.mm @@ -7,9 +7,7 @@ #include "base/mac/sdk_forward_declarations.h" #include "shell/browser/mac/electron_application.h" -namespace electron { - -namespace api { +namespace electron::api { void NativeTheme::UpdateMacOSAppearanceForOverrideValue( ui::NativeTheme::ThemeSource override) { @@ -32,6 +30,4 @@ } } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_net.cc b/shell/browser/api/electron_api_net.cc index 564fe440d604a..cf84a4b8a7137 100644 --- a/shell/browser/api/electron_api_net.cc +++ b/shell/browser/api/electron_api_net.cc @@ -5,11 +5,15 @@ #include #include "gin/handle.h" +#include "net/base/filename_util.h" #include "net/base/network_change_notifier.h" #include "net/http/http_util.h" #include "services/network/public/cpp/features.h" #include "shell/browser/api/electron_api_url_loader.h" +#include "shell/common/gin_converters/file_path_converter.h" +#include "shell/common/gin_converters/gurl_converter.h" #include "shell/common/gin_helper/dictionary.h" +#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" @@ -28,6 +32,14 @@ bool IsValidHeaderValue(std::string header_value) { return net::HttpUtil::IsValidHeaderValue(header_value); } +base::FilePath FileURLToFilePath(v8::Isolate* isolate, const GURL& url) { + base::FilePath path; + if (!net::FileURLToFilePath(url, &path)) + gin_helper::ErrorThrower(isolate).ThrowError( + "Failed to convert URL to file path"); + return path; +} + using electron::api::SimpleURLLoaderWrapper; void Initialize(v8::Local exports, @@ -41,6 +53,7 @@ void Initialize(v8::Local exports, dict.SetMethod("isValidHeaderName", &IsValidHeaderName); dict.SetMethod("isValidHeaderValue", &IsValidHeaderValue); dict.SetMethod("createURLLoader", &SimpleURLLoaderWrapper::Create); + dict.SetMethod("fileURLToFilePath", &FileURLToFilePath); } } // namespace diff --git a/shell/browser/api/electron_api_net_log.cc b/shell/browser/api/electron_api_net_log.cc index f30aa2aebf8fe..8cf645acbdc31 100644 --- a/shell/browser/api/electron_api_net_log.cc +++ b/shell/browser/api/electron_api_net_log.cc @@ -132,9 +132,8 @@ v8::Local NetLog::StartLogging(base::FilePath log_path, auto command_line_string = base::CommandLine::ForCurrentProcess()->GetCommandLineString(); auto channel_string = std::string("Electron " ELECTRON_VERSION); - base::Value custom_constants = - base::Value::FromUniquePtrValue(net_log::GetPlatformConstantsForNetLog( - command_line_string, channel_string)); + base::Value::Dict custom_constants = net_log::GetPlatformConstantsForNetLog( + command_line_string, channel_string); auto* network_context = browser_context_->GetDefaultStoragePartition()->GetNetworkContext(); @@ -156,7 +155,7 @@ v8::Local NetLog::StartLogging(base::FilePath log_path, void NetLog::StartNetLogAfterCreateFile(net::NetLogCaptureMode capture_mode, uint64_t max_file_size, - base::Value custom_constants, + base::Value::Dict custom_constants, base::File output_file) { if (!net_log_exporter_) { // Theoretically the mojo pipe could have been closed by the time we get @@ -204,7 +203,7 @@ v8::Local NetLog::StopLogging(gin::Arguments* args) { // pointer lives long enough to resolve the promise. Moving it into the // callback will cause the instance variable to become empty. net_log_exporter_->Stop( - base::Value(base::Value::Type::DICTIONARY), + base::Value::Dict(), base::BindOnce( [](mojo::Remote, gin_helper::Promise promise, int32_t error) { diff --git a/shell/browser/api/electron_api_net_log.h b/shell/browser/api/electron_api_net_log.h index 30a6ad6981a1d..26450517c687e 100644 --- a/shell/browser/api/electron_api_net_log.h +++ b/shell/browser/api/electron_api_net_log.h @@ -57,7 +57,7 @@ class NetLog : public gin::Wrappable { void StartNetLogAfterCreateFile(net::NetLogCaptureMode capture_mode, uint64_t max_file_size, - base::Value custom_constants, + base::Value::Dict custom_constants, base::File output_file); void NetLogStarted(int32_t error); diff --git a/shell/browser/api/electron_api_notification.cc b/shell/browser/api/electron_api_notification.cc index 5216b7407df30..6f77147c4659e 100644 --- a/shell/browser/api/electron_api_notification.cc +++ b/shell/browser/api/electron_api_notification.cc @@ -45,9 +45,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo Notification::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -284,9 +282,7 @@ v8::Local Notification::FillObjectTemplate( .Build(); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { @@ -304,4 +300,4 @@ void Initialize(v8::Local exports, } // namespace -NODE_LINKED_MODULE_CONTEXT_AWARE(electron_common_notification, Initialize) +NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_notification, Initialize) diff --git a/shell/browser/api/electron_api_notification.h b/shell/browser/api/electron_api_notification.h index 8213c424ee64d..bbc35a9a52d9d 100644 --- a/shell/browser/api/electron_api_notification.h +++ b/shell/browser/api/electron_api_notification.h @@ -25,9 +25,7 @@ template class Handle; } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { class Notification : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -117,8 +115,6 @@ class Notification : public gin::Wrappable, base::WeakPtr notification_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_NOTIFICATION_H_ diff --git a/shell/browser/api/electron_api_power_monitor.cc b/shell/browser/api/electron_api_power_monitor.cc index 258fc1464f999..2f7ee06584ece 100644 --- a/shell/browser/api/electron_api_power_monitor.cc +++ b/shell/browser/api/electron_api_power_monitor.cc @@ -35,9 +35,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo PowerMonitor::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -116,9 +114,7 @@ const char* PowerMonitor::GetTypeName() { return "PowerMonitor"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_power_monitor.h b/shell/browser/api/electron_api_power_monitor.h index 26ee40cc3ccd0..7aab65e7f78e9 100644 --- a/shell/browser/api/electron_api_power_monitor.h +++ b/shell/browser/api/electron_api_power_monitor.h @@ -15,9 +15,7 @@ #include "shell/browser/lib/power_observer_linux.h" #endif -namespace electron { - -namespace api { +namespace electron::api { class PowerMonitor : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -86,8 +84,6 @@ class PowerMonitor : public gin::Wrappable, #endif }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_POWER_MONITOR_H_ diff --git a/shell/browser/api/electron_api_power_monitor_mac.mm b/shell/browser/api/electron_api_power_monitor_mac.mm index 90ec3118d17c2..f7ba52967b0ac 100644 --- a/shell/browser/api/electron_api_power_monitor_mac.mm +++ b/shell/browser/api/electron_api_power_monitor_mac.mm @@ -108,9 +108,7 @@ - (void)onUserDidResignActive:(NSNotification*)notification { @end -namespace electron { - -namespace api { +namespace electron::api { static MacLockMonitor* g_lock_monitor = nil; @@ -120,6 +118,4 @@ - (void)onUserDidResignActive:(NSNotification*)notification { [g_lock_monitor addEmitter:this]; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_power_monitor_win.cc b/shell/browser/api/electron_api_power_monitor_win.cc index bf1468cd97038..90f2cf97dfe26 100644 --- a/shell/browser/api/electron_api_power_monitor_win.cc +++ b/shell/browser/api/electron_api_power_monitor_win.cc @@ -42,7 +42,7 @@ void PowerMonitor::InitPlatformSpecificMonitors() { // Tel windows we want to be notified with session events WTSRegisterSessionNotification(window_, NOTIFY_FOR_THIS_SESSION); - // For Windows 8 and later, a new "connected standy" mode has been added and + // For Windows 8 and later, a new "connected standby" mode has been added and // we must explicitly register for its notifications. auto RegisterSuspendResumeNotification = reinterpret_cast( diff --git a/shell/browser/api/electron_api_power_save_blocker.cc b/shell/browser/api/electron_api_power_save_blocker.cc index 34a11086d50d7..0994cba7b6ea9 100644 --- a/shell/browser/api/electron_api_power_save_blocker.cc +++ b/shell/browser/api/electron_api_power_save_blocker.cc @@ -7,7 +7,6 @@ #include #include "base/callback_helpers.h" -#include "base/task/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "content/public/browser/device_service.h" #include "gin/dictionary.h" @@ -38,9 +37,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo PowerSaveBlocker::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -127,9 +124,7 @@ gin::ObjectTemplateBuilder PowerSaveBlocker::GetObjectTemplateBuilder( .SetMethod("isStarted", &PowerSaveBlocker::IsStarted); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_power_save_blocker.h b/shell/browser/api/electron_api_power_save_blocker.h index 74a08f55e4413..1e55e5299ec7a 100644 --- a/shell/browser/api/electron_api_power_save_blocker.h +++ b/shell/browser/api/electron_api_power_save_blocker.h @@ -13,9 +13,7 @@ #include "mojo/public/cpp/bindings/remote.h" #include "services/device/public/mojom/wake_lock.mojom.h" -namespace electron { - -namespace api { +namespace electron::api { class PowerSaveBlocker : public gin::Wrappable { public: @@ -56,8 +54,6 @@ class PowerSaveBlocker : public gin::Wrappable { mojo::Remote wake_lock_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_POWER_SAVE_BLOCKER_H_ diff --git a/shell/browser/api/electron_api_printing.cc b/shell/browser/api/electron_api_printing.cc index 75067584b1465..fcb8f907fea47 100644 --- a/shell/browser/api/electron_api_printing.cc +++ b/shell/browser/api/electron_api_printing.cc @@ -38,9 +38,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { #if BUILDFLAG(ENABLE_PRINTING) printing::PrinterList GetPrinterList(v8::Isolate* isolate) { @@ -55,7 +53,7 @@ printing::PrinterList GetPrinterList(v8::Isolate* isolate) { { base::ThreadRestrictions::ScopedAllowIO allow_io; printing::mojom::ResultCode code = - print_backend->EnumeratePrinters(&printers); + print_backend->EnumeratePrinters(printers); if (code != printing::mojom::ResultCode::kSuccess) LOG(INFO) << "Failed to enumerate printers"; } @@ -73,7 +71,7 @@ v8::Local GetPrinterListAsync(v8::Isolate* isolate) { auto print_backend = printing::PrintBackend::CreateInstance( g_browser_process->GetApplicationLocale()); printing::mojom::ResultCode code = - print_backend->EnumeratePrinters(&printers); + print_backend->EnumeratePrinters(printers); if (code != printing::mojom::ResultCode::kSuccess) LOG(INFO) << "Failed to enumerate printers"; return printers; @@ -89,9 +87,7 @@ v8::Local GetPrinterListAsync(v8::Isolate* isolate) { } #endif -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_protocol.cc b/shell/browser/api/electron_api_protocol.cc index cd396e9662749..fabb5ec7859b3 100644 --- a/shell/browser/api/electron_api_protocol.cc +++ b/shell/browser/api/electron_api_protocol.cc @@ -78,8 +78,7 @@ struct Converter { } // namespace gin -namespace electron { -namespace api { +namespace electron::api { gin::WrapperInfo Protocol::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -312,8 +311,7 @@ const char* Protocol::GetTypeName() { return "Protocol"; } -} // namespace api -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_push_notifications.cc b/shell/browser/api/electron_api_push_notifications.cc new file mode 100644 index 0000000000000..bb0cb13d0f1d7 --- /dev/null +++ b/shell/browser/api/electron_api_push_notifications.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2022 Asana, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/api/electron_api_push_notifications.h" + +#include + +#include "shell/common/gin_converters/value_converter.h" +#include "shell/common/gin_helper/dictionary.h" +#include "shell/common/node_includes.h" + +namespace electron { + +namespace api { + +PushNotifications* g_push_notifications = nullptr; + +gin::WrapperInfo PushNotifications::kWrapperInfo = {gin::kEmbedderNativeGin}; + +PushNotifications::PushNotifications() = default; + +PushNotifications::~PushNotifications() { + g_push_notifications = nullptr; +} + +// static +PushNotifications* PushNotifications::Get() { + if (!g_push_notifications) + g_push_notifications = new PushNotifications(); + return g_push_notifications; +} + +// static +gin::Handle PushNotifications::Create(v8::Isolate* isolate) { + return gin::CreateHandle(isolate, PushNotifications::Get()); +} + +// static +gin::ObjectTemplateBuilder PushNotifications::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + auto builder = gin_helper::EventEmitterMixin< + PushNotifications>::GetObjectTemplateBuilder(isolate); +#if BUILDFLAG(IS_MAC) + builder + .SetMethod("registerForAPNSNotifications", + &PushNotifications::RegisterForAPNSNotifications) + .SetMethod("unregisterForAPNSNotifications", + &PushNotifications::UnregisterForAPNSNotifications); +#endif + return builder; +} + +const char* PushNotifications::GetTypeName() { + return "PushNotifications"; +} + +} // namespace api + +} // namespace electron + +namespace { + +void Initialize(v8::Local exports, + v8::Local unused, + v8::Local context, + void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + gin::Dictionary dict(isolate, exports); + dict.Set("pushNotifications", + electron::api::PushNotifications::Create(isolate)); +} + +} // namespace + +NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_push_notifications, + Initialize) diff --git a/shell/browser/api/electron_api_push_notifications.h b/shell/browser/api/electron_api_push_notifications.h new file mode 100644 index 0000000000000..f0f46b5e574ee --- /dev/null +++ b/shell/browser/api/electron_api_push_notifications.h @@ -0,0 +1,64 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_PUSH_NOTIFICATIONS_H_ +#define ELECTRON_SHELL_BROWSER_API_ELECTRON_API_PUSH_NOTIFICATIONS_H_ + +#include + +#include +#include "gin/handle.h" +#include "gin/wrappable.h" +#include "shell/browser/browser_observer.h" +#include "shell/browser/electron_browser_client.h" +#include "shell/browser/event_emitter_mixin.h" +#include "shell/common/gin_helper/promise.h" + +namespace electron { + +namespace api { + +class PushNotifications + : public ElectronBrowserClient::Delegate, + public gin::Wrappable, + public gin_helper::EventEmitterMixin, + public BrowserObserver { + public: + static PushNotifications* Get(); + static gin::Handle Create(v8::Isolate* isolate); + + // gin::Wrappable + static gin::WrapperInfo kWrapperInfo; + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override; + const char* GetTypeName() override; + + // disable copy + PushNotifications(const PushNotifications&) = delete; + PushNotifications& operator=(const PushNotifications&) = delete; + +#if BUILDFLAG(IS_MAC) + void OnDidReceiveAPNSNotification(const base::Value::Dict& user_info); + void ResolveAPNSPromiseSetWithToken(const std::string& token_string); + void RejectAPNSPromiseSetWithError(const std::string& error_message); +#endif + + private: + PushNotifications(); + ~PushNotifications() override; + // This set maintains all the promises that should be fulfilled + // once macOS registers, or fails to register, for APNS + std::vector> apns_promise_set_; + +#if BUILDFLAG(IS_MAC) + v8::Local RegisterForAPNSNotifications(v8::Isolate* isolate); + void UnregisterForAPNSNotifications(); +#endif +}; + +} // namespace api + +} // namespace electron + +#endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_PUSH_NOTIFICATIONS_H_ diff --git a/shell/browser/api/electron_api_push_notifications_mac.mm b/shell/browser/api/electron_api_push_notifications_mac.mm new file mode 100644 index 0000000000000..6838293937a8f --- /dev/null +++ b/shell/browser/api/electron_api_push_notifications_mac.mm @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Asana, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/api/electron_api_push_notifications.h" + +#include + +#include +#include +#import "shell/browser/mac/electron_application.h" +#include "shell/common/gin_converters/value_converter.h" +#include "shell/common/gin_helper/promise.h" + +namespace electron { + +namespace api { + +v8::Local PushNotifications::RegisterForAPNSNotifications( + v8::Isolate* isolate) { + gin_helper::Promise promise(isolate); + v8::Local handle = promise.GetHandle(); + + [[AtomApplication sharedApplication] + registerForRemoteNotificationTypes:NSRemoteNotificationTypeBadge | + NSRemoteNotificationTypeAlert | + NSRemoteNotificationTypeSound]; + + PushNotifications::apns_promise_set_.emplace_back(std::move(promise)); + return handle; +} + +void PushNotifications::ResolveAPNSPromiseSetWithToken( + const std::string& token_string) { + std::vector> promises = + std::move(PushNotifications::apns_promise_set_); + for (auto& promise : promises) { + promise.Resolve(token_string); + } +} + +void PushNotifications::RejectAPNSPromiseSetWithError( + const std::string& error_message) { + std::vector> promises = + std::move(PushNotifications::apns_promise_set_); + for (auto& promise : promises) { + promise.RejectWithErrorMessage(error_message); + } +} + +void PushNotifications::UnregisterForAPNSNotifications() { + [[AtomApplication sharedApplication] unregisterForRemoteNotifications]; +} + +void PushNotifications::OnDidReceiveAPNSNotification( + const base::Value::Dict& user_info) { + Emit("received-apns-notification", user_info); +} + +} // namespace api + +} // namespace electron diff --git a/shell/browser/api/electron_api_safe_storage.cc b/shell/browser/api/electron_api_safe_storage.cc index ba1396cf28332..d667590132ee0 100644 --- a/shell/browser/api/electron_api_safe_storage.cc +++ b/shell/browser/api/electron_api_safe_storage.cc @@ -15,9 +15,7 @@ #include "shell/common/node_includes.h" #include "shell/common/platform_util.h" -namespace electron { - -namespace safestorage { +namespace electron::safestorage { static const char* kEncryptionVersionPrefixV10 = "v10"; static const char* kEncryptionVersionPrefixV11 = "v11"; @@ -31,12 +29,24 @@ void SetElectronCryptoReady(bool ready) { #endif bool IsEncryptionAvailable() { +#if BUILDFLAG(IS_LINUX) + // Calling IsEncryptionAvailable() before the app is ready results in a crash + // on Linux. + // Refs: https://github.com/electron/electron/issues/32206. + if (!Browser::Get()->is_ready()) + return false; +#endif return OSCrypt::IsEncryptionAvailable(); } v8::Local EncryptString(v8::Isolate* isolate, const std::string& plaintext) { - if (!OSCrypt::IsEncryptionAvailable()) { + if (!IsEncryptionAvailable()) { + if (!Browser::Get()->is_ready()) { + gin_helper::ErrorThrower(isolate).ThrowError( + "safeStorage cannot be used before app is ready"); + return v8::Local(); + } gin_helper::ErrorThrower(isolate).ThrowError( "Error while decrypting the ciphertext provided to " "safeStorage.decryptString. " @@ -59,7 +69,12 @@ v8::Local EncryptString(v8::Isolate* isolate, } std::string DecryptString(v8::Isolate* isolate, v8::Local buffer) { - if (!OSCrypt::IsEncryptionAvailable()) { + if (!IsEncryptionAvailable()) { + if (!Browser::Get()->is_ready()) { + gin_helper::ErrorThrower(isolate).ThrowError( + "safeStorage cannot be used before app is ready"); + return ""; + } gin_helper::ErrorThrower(isolate).ThrowError( "Error while decrypting the ciphertext provided to " "safeStorage.decryptString. " @@ -102,9 +117,7 @@ std::string DecryptString(v8::Isolate* isolate, v8::Local buffer) { return plaintext; } -} // namespace safestorage - -} // namespace electron +} // namespace electron::safestorage void Initialize(v8::Local exports, v8::Local unused, diff --git a/shell/browser/api/electron_api_safe_storage.h b/shell/browser/api/electron_api_safe_storage.h index d312769a3f53d..1ecde80f8cee4 100644 --- a/shell/browser/api/electron_api_safe_storage.h +++ b/shell/browser/api/electron_api_safe_storage.h @@ -7,9 +7,7 @@ #include "base/dcheck_is_on.h" -namespace electron { - -namespace safestorage { +namespace electron::safestorage { // Used in a DCHECK to validate that our assumption that the network context // manager has initialized before app ready holds true. Only used in the @@ -18,8 +16,6 @@ namespace safestorage { void SetElectronCryptoReady(bool ready); #endif -} // namespace safestorage - -} // namespace electron +} // namespace electron::safestorage #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SAFE_STORAGE_H_ diff --git a/shell/browser/api/electron_api_screen.cc b/shell/browser/api/electron_api_screen.cc index 35a4951687286..592d0017aeac6 100644 --- a/shell/browser/api/electron_api_screen.cc +++ b/shell/browser/api/electron_api_screen.cc @@ -24,9 +24,11 @@ #include "ui/display/win/screen_win.h" #endif -namespace electron { +#if defined(USE_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif -namespace api { +namespace electron::api { gin::WrapperInfo Screen::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -70,7 +72,18 @@ Screen::~Screen() { screen_->RemoveObserver(this); } -gfx::Point Screen::GetCursorScreenPoint() { +gfx::Point Screen::GetCursorScreenPoint(v8::Isolate* isolate) { +#if defined(USE_OZONE) + // Wayland will crash unless a window is created prior to calling + // GetCursorScreenPoint. + if (!ui::OzonePlatform::IsInitialized()) { + gin_helper::ErrorThrower thrower(isolate); + thrower.ThrowError( + "screen.getCursorScreenPoint() cannot be called before a window has " + "been created."); + return gfx::Point(); + } +#endif return screen_->GetCursorScreenPoint(); } @@ -166,9 +179,7 @@ const char* Screen::GetTypeName() { return "Screen"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { @@ -185,4 +196,4 @@ void Initialize(v8::Local exports, } // namespace -NODE_LINKED_MODULE_CONTEXT_AWARE(electron_common_screen, Initialize) +NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_screen, Initialize) diff --git a/shell/browser/api/electron_api_screen.h b/shell/browser/api/electron_api_screen.h index a8121b9ce54cc..ef203cd7b1076 100644 --- a/shell/browser/api/electron_api_screen.h +++ b/shell/browser/api/electron_api_screen.h @@ -19,9 +19,7 @@ class Rect; class Screen; } // namespace gfx -namespace electron { - -namespace api { +namespace electron::api { class Screen : public gin::Wrappable, public gin_helper::EventEmitterMixin, @@ -42,7 +40,7 @@ class Screen : public gin::Wrappable, Screen(v8::Isolate* isolate, display::Screen* screen); ~Screen() override; - gfx::Point GetCursorScreenPoint(); + gfx::Point GetCursorScreenPoint(v8::Isolate* isolate); display::Display GetPrimaryDisplay(); std::vector GetAllDisplays(); display::Display GetDisplayNearestPoint(const gfx::Point& point); @@ -58,8 +56,6 @@ class Screen : public gin::Wrappable, display::Screen* screen_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SCREEN_H_ diff --git a/shell/browser/api/electron_api_service_worker_context.cc b/shell/browser/api/electron_api_service_worker_context.cc index f148dc7a59de8..402f900d384e5 100644 --- a/shell/browser/api/electron_api_service_worker_context.cc +++ b/shell/browser/api/electron_api_service_worker_context.cc @@ -21,9 +21,7 @@ #include "shell/common/gin_helper/function_template_extensions.h" #include "shell/common/node_includes.h" -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -162,6 +160,4 @@ const char* ServiceWorkerContext::GetTypeName() { return "ServiceWorkerContext"; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_session.cc b/shell/browser/api/electron_api_session.cc index ac6b38cdb58f4..340adbd1a65a3 100644 --- a/shell/browser/api/electron_api_session.cc +++ b/shell/browser/api/electron_api_session.cc @@ -17,7 +17,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" -#include "base/task/post_task.h" #include "chrome/browser/browser_process.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" @@ -73,6 +72,7 @@ #include "shell/common/node_includes.h" #include "shell/common/options_switches.h" #include "shell/common/process_util.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "ui/base/l10n/l10n_util.h" #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) @@ -116,7 +116,7 @@ PreconnectRequest::PreconnectRequest( namespace { struct ClearStorageDataOptions { - GURL origin; + blink::StorageKey storage_key; uint32_t storage_types = StoragePartition::REMOVE_DATA_MASK_ALL; uint32_t quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL; }; @@ -171,7 +171,8 @@ struct Converter { gin_helper::Dictionary options; if (!ConvertFromV8(isolate, val, &options)) return false; - options.Get("origin", &out->origin); + if (GURL storage_origin; options.Get("origin", &storage_origin)) + out->storage_key = blink::StorageKey(url::Origin::Create(storage_origin)); std::vector types; if (options.Get("storages", &types)) out->storage_types = GetStorageMask(types); @@ -243,9 +244,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -372,7 +371,6 @@ void Session::OnDownloadCreated(content::DownloadManager* manager, if (item->IsSavePackageDownload()) return; - v8::Locker locker(isolate_); v8::HandleScope handle_scope(isolate_); auto handle = DownloadItem::FromOrCreate(isolate_, item); if (item->GetState() == download::DownloadItem::INTERRUPTED) @@ -468,8 +466,8 @@ v8::Local Session::ClearStorageData(gin::Arguments* args) { } storage_partition->ClearData( - options.storage_types, options.quota_types, options.origin, base::Time(), - base::Time::Max(), + options.storage_types, options.quota_types, options.storage_key, + base::Time(), base::Time::Max(), base::BindOnce(gin_helper::Promise::ResolvePromise, std::move(promise))); return handle; @@ -623,7 +621,7 @@ void Session::SetPermissionRequestHandler(v8::Local val, permission_manager->SetPermissionRequestHandler(base::BindRepeating( [](ElectronPermissionManager::RequestHandler* handler, content::WebContents* web_contents, - content::PermissionType permission_type, + blink::PermissionType permission_type, ElectronPermissionManager::StatusCallback callback, const base::Value& details) { handler->Run(web_contents, permission_type, @@ -657,6 +655,18 @@ void Session::SetDevicePermissionHandler(v8::Local val, permission_manager->SetDevicePermissionHandler(handler); } +void Session::SetBluetoothPairingHandler(v8::Local val, + gin::Arguments* args) { + ElectronPermissionManager::BluetoothPairingHandler handler; + if (!(val->IsNull() || gin::ConvertFromV8(args->isolate(), val, &handler))) { + args->ThrowTypeError("Must pass null or function"); + return; + } + auto* permission_manager = static_cast( + browser_context()->GetPermissionControllerDelegate()); + permission_manager->SetBluetoothPairingHandler(handler); +} + v8::Local Session::ClearHostResolverCache(gin::Arguments* args) { v8::Isolate* isolate = args->isolate(); gin_helper::Promise promise(isolate); @@ -952,8 +962,8 @@ void Session::Preconnect(const gin_helper::Dictionary& options, } DCHECK_GT(num_sockets_to_preconnect, 0); - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&StartPreconnectOnUI, base::Unretained(browser_context_), url, num_sockets_to_preconnect)); } @@ -1026,7 +1036,8 @@ base::Value Session::GetSpellCheckerLanguages() { void Session::SetSpellCheckerLanguages( gin_helper::ErrorThrower thrower, const std::vector& languages) { - base::ListValue language_codes; +#if !BUILDFLAG(IS_MAC) + base::Value::List language_codes; for (const std::string& lang : languages) { std::string code = spellcheck::GetCorrespondingSpellCheckLanguage(lang); if (code.empty()) { @@ -1037,14 +1048,16 @@ void Session::SetSpellCheckerLanguages( language_codes.Append(code); } browser_context_->prefs()->Set(spellcheck::prefs::kSpellCheckDictionaries, - language_codes); + base::Value(std::move(language_codes))); // Enable spellcheck if > 0 languages, disable if no languages set browser_context_->prefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, !languages.empty()); +#endif } void SetSpellCheckerDictionaryDownloadURL(gin_helper::ErrorThrower thrower, const GURL& url) { +#if !BUILDFLAG(IS_MAC) if (!url.is_valid()) { thrower.ThrowError( "The URL you provided to setSpellCheckerDictionaryDownloadURL is not a " @@ -1052,6 +1065,7 @@ void SetSpellCheckerDictionaryDownloadURL(gin_helper::ErrorThrower thrower, return; } SpellcheckHunspellDictionary::SetBaseDownloadURL(url); +#endif } v8::Local Session::ListWordsInSpellCheckerDictionary() { @@ -1164,7 +1178,7 @@ gin::Handle Session::CreateFrom( // static gin::Handle Session::FromPartition(v8::Isolate* isolate, const std::string& partition, - base::DictionaryValue options) { + base::Value::Dict options) { ElectronBrowserContext* browser_context; if (partition.empty()) { browser_context = @@ -1202,6 +1216,8 @@ gin::ObjectTemplateBuilder Session::GetObjectTemplateBuilder( &Session::SetPermissionCheckHandler) .SetMethod("setDevicePermissionHandler", &Session::SetDevicePermissionHandler) + .SetMethod("setBluetoothPairingHandler", + &Session::SetBluetoothPairingHandler) .SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache) .SetMethod("clearAuthCache", &Session::ClearAuthCache) .SetMethod("allowNTLMCredentialsForDomains", @@ -1257,9 +1273,7 @@ const char* Session::GetTypeName() { return "Session"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { @@ -1271,7 +1285,7 @@ v8::Local FromPartition(const std::string& partition, args->ThrowTypeError("Session can only be received when app is ready"); return v8::Null(args->isolate()); } - base::DictionaryValue options; + base::Value::Dict options; args->GetNext(&options); return Session::FromPartition(args->isolate(), partition, std::move(options)) .ToV8(); diff --git a/shell/browser/api/electron_api_session.h b/shell/browser/api/electron_api_session.h index e9b69380dfaf9..9507d706a4f20 100644 --- a/shell/browser/api/electron_api_session.h +++ b/shell/browser/api/electron_api_session.h @@ -75,10 +75,9 @@ class Session : public gin::Wrappable, static Session* FromBrowserContext(content::BrowserContext* context); // Gets the Session of |partition|. - static gin::Handle FromPartition( - v8::Isolate* isolate, - const std::string& partition, - base::DictionaryValue options = base::DictionaryValue()); + static gin::Handle FromPartition(v8::Isolate* isolate, + const std::string& partition, + base::Value::Dict options = {}); ElectronBrowserContext* browser_context() const { return browser_context_; } @@ -106,6 +105,8 @@ class Session : public gin::Wrappable, gin::Arguments* args); void SetDevicePermissionHandler(v8::Local val, gin::Arguments* args); + void SetBluetoothPairingHandler(v8::Local val, + gin::Arguments* args); v8::Local ClearHostResolverCache(gin::Arguments* args); v8::Local ClearAuthCache(); void AllowNTLMCredentialsForDomains(const std::string& domains); diff --git a/shell/browser/api/electron_api_system_preferences.cc b/shell/browser/api/electron_api_system_preferences.cc index 58df58f502e9a..e09503e344389 100644 --- a/shell/browser/api/electron_api_system_preferences.cc +++ b/shell/browser/api/electron_api_system_preferences.cc @@ -13,9 +13,7 @@ #include "ui/gfx/color_utils.h" #include "ui/native_theme/native_theme.h" -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo SystemPreferences::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -117,9 +115,7 @@ const char* SystemPreferences::GetTypeName() { return "SystemPreferences"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_system_preferences.h b/shell/browser/api/electron_api_system_preferences.h index d35dd5b947bea..b311e97fc6831 100644 --- a/shell/browser/api/electron_api_system_preferences.h +++ b/shell/browser/api/electron_api_system_preferences.h @@ -21,9 +21,7 @@ #include "ui/gfx/sys_color_change_listener.h" #endif -namespace electron { - -namespace api { +namespace electron::api { #if BUILDFLAG(IS_MAC) enum class NotificationCenterKind { @@ -67,25 +65,25 @@ class SystemPreferences void OnSysColorChange() override; // BrowserObserver: - void OnFinishLaunching(const base::DictionaryValue& launch_info) override; + void OnFinishLaunching(base::Value::Dict launch_info) override; #elif BUILDFLAG(IS_MAC) using NotificationCallback = base::RepeatingCallback< - void(const std::string&, base::DictionaryValue, const std::string&)>; + void(const std::string&, base::Value, const std::string&)>; void PostNotification(const std::string& name, - base::DictionaryValue user_info, + base::Value::Dict user_info, gin::Arguments* args); int SubscribeNotification(v8::Local maybe_name, const NotificationCallback& callback); void UnsubscribeNotification(int id); void PostLocalNotification(const std::string& name, - base::DictionaryValue user_info); + base::Value::Dict user_info); int SubscribeLocalNotification(v8::Local maybe_name, const NotificationCallback& callback); void UnsubscribeLocalNotification(int request_id); void PostWorkspaceNotification(const std::string& name, - base::DictionaryValue user_info); + base::Value::Dict user_info); int SubscribeWorkspaceNotification(v8::Local maybe_name, const NotificationCallback& callback); void UnsubscribeWorkspaceNotification(int request_id); @@ -160,7 +158,7 @@ class SystemPreferences std::string current_color_; - bool invertered_color_scheme_ = false; + bool inverted_color_scheme_ = false; bool high_contrast_color_scheme_ = false; @@ -168,8 +166,6 @@ class SystemPreferences #endif }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SYSTEM_PREFERENCES_H_ diff --git a/shell/browser/api/electron_api_system_preferences_mac.mm b/shell/browser/api/electron_api_system_preferences_mac.mm index 70006a88dd157..bbd37e3c38e63 100644 --- a/shell/browser/api/electron_api_system_preferences_mac.mm +++ b/shell/browser/api/electron_api_system_preferences_mac.mm @@ -86,9 +86,7 @@ static bool FromV8(v8::Isolate* isolate, } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -140,17 +138,18 @@ AVMediaType ParseMediaType(const std::string& media_type) { } // namespace void SystemPreferences::PostNotification(const std::string& name, - base::DictionaryValue user_info, + base::Value::Dict user_info, gin::Arguments* args) { bool immediate = false; args->GetNext(&immediate); NSDistributedNotificationCenter* center = [NSDistributedNotificationCenter defaultCenter]; - [center postNotificationName:base::SysUTF8ToNSString(name) - object:nil - userInfo:DictionaryValueToNSDictionary(user_info) - deliverImmediately:immediate]; + [center + postNotificationName:base::SysUTF8ToNSString(name) + object:nil + userInfo:DictionaryValueToNSDictionary(std::move(user_info)) + deliverImmediately:immediate]; } int SystemPreferences::SubscribeNotification( @@ -167,11 +166,12 @@ AVMediaType ParseMediaType(const std::string& media_type) { } void SystemPreferences::PostLocalNotification(const std::string& name, - base::DictionaryValue user_info) { + base::Value::Dict user_info) { NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - [center postNotificationName:base::SysUTF8ToNSString(name) - object:nil - userInfo:DictionaryValueToNSDictionary(user_info)]; + [center + postNotificationName:base::SysUTF8ToNSString(name) + object:nil + userInfo:DictionaryValueToNSDictionary(std::move(user_info))]; } int SystemPreferences::SubscribeLocalNotification( @@ -186,14 +186,14 @@ AVMediaType ParseMediaType(const std::string& media_type) { NotificationCenterKind::kNSNotificationCenter); } -void SystemPreferences::PostWorkspaceNotification( - const std::string& name, - base::DictionaryValue user_info) { +void SystemPreferences::PostWorkspaceNotification(const std::string& name, + base::Value::Dict user_info) { NSNotificationCenter* center = [[NSWorkspace sharedWorkspace] notificationCenter]; - [center postNotificationName:base::SysUTF8ToNSString(name) - object:nil - userInfo:DictionaryValueToNSDictionary(user_info)]; + [center + postNotificationName:base::SysUTF8ToNSString(name) + object:nil + userInfo:DictionaryValueToNSDictionary(std::move(user_info))]; } int SystemPreferences::SubscribeWorkspaceNotification( @@ -240,12 +240,12 @@ AVMediaType ParseMediaType(const std::string& media_type) { if (notification.userInfo) { copied_callback.Run( base::SysNSStringToUTF8(notification.name), - NSDictionaryToDictionaryValue(notification.userInfo), + base::Value(NSDictionaryToValue(notification.userInfo)), object); } else { copied_callback.Run( base::SysNSStringToUTF8(notification.name), - base::DictionaryValue(), object); + base::Value(base::Value::Dict()), object); } }]; return request_id; @@ -282,35 +282,36 @@ AVMediaType ParseMediaType(const std::string& media_type) { return gin::ConvertToV8(isolate, net::GURLWithNSURL([defaults URLForKey:key])); } else if (type == "array") { - return gin::ConvertToV8(isolate, - NSArrayToListValue([defaults arrayForKey:key])); + return gin::ConvertToV8( + isolate, base::Value(NSArrayToValue([defaults arrayForKey:key]))); } else if (type == "dictionary") { - return gin::ConvertToV8(isolate, NSDictionaryToDictionaryValue( - [defaults dictionaryForKey:key])); + return gin::ConvertToV8( + isolate, + base::Value(NSDictionaryToValue([defaults dictionaryForKey:key]))); } else { return v8::Undefined(isolate); } } void SystemPreferences::RegisterDefaults(gin::Arguments* args) { - base::DictionaryValue value; + base::Value::Dict value; if (!args->GetNext(&value)) { args->ThrowError(); - } else { - @try { - NSDictionary* dict = DictionaryValueToNSDictionary(value); - for (id key in dict) { - id value = [dict objectForKey:key]; - if ([value isKindOfClass:[NSNull class]] || value == nil) { - args->ThrowError(); - return; - } + return; + } + @try { + NSDictionary* dict = DictionaryValueToNSDictionary(std::move(value)); + for (id key in dict) { + id value = [dict objectForKey:key]; + if ([value isKindOfClass:[NSNull class]] || value == nil) { + args->ThrowError(); + return; } - [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; - } @catch (NSException* exception) { - args->ThrowError(); } + [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; + } @catch (NSException* exception) { + args->ThrowError(); } } @@ -359,17 +360,17 @@ AVMediaType ParseMediaType(const std::string& media_type) { } } } else if (type == "array") { - base::ListValue value; - if (args->GetNext(&value)) { - if (NSArray* array = ListValueToNSArray(value)) { + base::Value value; + if (args->GetNext(&value) && value.is_list()) { + if (NSArray* array = ListValueToNSArray(value.GetList())) { [defaults setObject:array forKey:key]; return; } } } else if (type == "dictionary") { - base::DictionaryValue value; - if (args->GetNext(&value)) { - if (NSDictionary* dict = DictionaryValueToNSDictionary(value)) { + base::Value value; + if (args->GetNext(&value) && value.is_dict()) { + if (NSDictionary* dict = DictionaryValueToNSDictionary(value.GetDict())) { [defaults setObject:dict forKey:key]; return; } @@ -423,17 +424,14 @@ AVMediaType ParseMediaType(const std::string& media_type) { } bool SystemPreferences::CanPromptTouchID() { - if (@available(macOS 10.12.2, *)) { - base::scoped_nsobject context([[LAContext alloc] init]); - if (![context - canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics - error:nil]) - return false; - if (@available(macOS 10.13.2, *)) - return [context biometryType] == LABiometryTypeTouchID; - return true; - } - return false; + base::scoped_nsobject context([[LAContext alloc] init]); + if (![context + canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics + error:nil]) + return false; + if (@available(macOS 10.13.2, *)) + return [context biometryType] == LABiometryTypeTouchID; + return true; } v8::Local SystemPreferences::PromptTouchID( @@ -442,46 +440,40 @@ AVMediaType ParseMediaType(const std::string& media_type) { gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); - if (@available(macOS 10.12.2, *)) { - base::scoped_nsobject context([[LAContext alloc] init]); - base::ScopedCFTypeRef access_control = - base::ScopedCFTypeRef( - SecAccessControlCreateWithFlags( - kCFAllocatorDefault, - kSecAttrAccessibleWhenUnlockedThisDeviceOnly, - kSecAccessControlPrivateKeyUsage | - kSecAccessControlUserPresence, - nullptr)); - - scoped_refptr runner = - base::SequencedTaskRunnerHandle::Get(); - - __block gin_helper::Promise p = std::move(promise); - [context - evaluateAccessControl:access_control - operation:LAAccessControlOperationUseKeySign - localizedReason:[NSString stringWithUTF8String:reason.c_str()] - reply:^(BOOL success, NSError* error) { - if (!success) { - std::string err_msg = std::string( - [error.localizedDescription UTF8String]); - runner->PostTask( - FROM_HERE, - base::BindOnce( - gin_helper::Promise::RejectPromise, - std::move(p), std::move(err_msg))); - } else { - runner->PostTask( - FROM_HERE, - base::BindOnce( - gin_helper::Promise::ResolvePromise, - std::move(p))); - } - }]; - } else { - promise.RejectWithErrorMessage( - "This API is not available on macOS versions older than 10.12.2"); - } + base::scoped_nsobject context([[LAContext alloc] init]); + base::ScopedCFTypeRef access_control = + base::ScopedCFTypeRef( + SecAccessControlCreateWithFlags( + kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, + kSecAccessControlPrivateKeyUsage | kSecAccessControlUserPresence, + nullptr)); + + scoped_refptr runner = + base::SequencedTaskRunnerHandle::Get(); + + __block gin_helper::Promise p = std::move(promise); + [context + evaluateAccessControl:access_control + operation:LAAccessControlOperationUseKeySign + localizedReason:[NSString stringWithUTF8String:reason.c_str()] + reply:^(BOOL success, NSError* error) { + if (!success) { + std::string err_msg = std::string( + [error.localizedDescription UTF8String]); + runner->PostTask( + FROM_HERE, + base::BindOnce( + gin_helper::Promise::RejectPromise, + std::move(p), std::move(err_msg))); + } else { + runner->PostTask( + FROM_HERE, + base::BindOnce( + gin_helper::Promise::ResolvePromise, + std::move(p))); + } + }]; + return handle; } @@ -529,8 +521,7 @@ AVMediaType ParseMediaType(const std::string& media_type) { } else if (color == "quaternary-label") { sysColor = [NSColor quaternaryLabelColor]; } else if (color == "scrubber-textured-background") { - if (@available(macOS 10.12.2, *)) - sysColor = [NSColor scrubberTexturedBackgroundColor]; + sysColor = [NSColor scrubberTexturedBackgroundColor]; } else if (color == "secondary-label") { sysColor = [NSColor secondaryLabelColor]; } else if (color == "selected-content-background") { @@ -663,6 +654,4 @@ AVMediaType ParseMediaType(const std::string& media_type) { } } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_system_preferences_win.cc b/shell/browser/api/electron_api_system_preferences_win.cc index 00e9a2728bd48..c2d77e941e4fd 100644 --- a/shell/browser/api/electron_api_system_preferences_win.cc +++ b/shell/browser/api/electron_api_system_preferences_win.cc @@ -185,7 +185,7 @@ std::string SystemPreferences::GetMediaAccessStatus( } void SystemPreferences::InitializeWindow() { - invertered_color_scheme_ = IsInvertedColorScheme(); + inverted_color_scheme_ = IsInvertedColorScheme(); high_contrast_color_scheme_ = IsHighContrastColorScheme(); // Wait until app is ready before creating sys color listener @@ -243,10 +243,10 @@ LRESULT CALLBACK SystemPreferences::WndProc(HWND hwnd, } void SystemPreferences::OnSysColorChange() { - bool new_invertered_color_scheme = IsInvertedColorScheme(); - if (new_invertered_color_scheme != invertered_color_scheme_) { - invertered_color_scheme_ = new_invertered_color_scheme; - Emit("inverted-color-scheme-changed", new_invertered_color_scheme); + bool new_inverted_color_scheme = IsInvertedColorScheme(); + if (new_inverted_color_scheme != inverted_color_scheme_) { + inverted_color_scheme_ = new_inverted_color_scheme; + Emit("inverted-color-scheme-changed", new_inverted_color_scheme); } bool new_high_contrast_color_scheme = IsHighContrastColorScheme(); @@ -258,8 +258,7 @@ void SystemPreferences::OnSysColorChange() { Emit("color-changed"); } -void SystemPreferences::OnFinishLaunching( - const base::DictionaryValue& launch_info) { +void SystemPreferences::OnFinishLaunching(base::Value::Dict launch_info) { color_change_listener_ = std::make_unique(this); } diff --git a/shell/browser/api/electron_api_tray.cc b/shell/browser/api/electron_api_tray.cc index 312fec8b09ddf..18d7a055e7de7 100644 --- a/shell/browser/api/electron_api_tray.cc +++ b/shell/browser/api/electron_api_tray.cc @@ -56,9 +56,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { gin::WrapperInfo Tray::kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -389,7 +387,6 @@ gfx::Rect Tray::GetBounds() { bool Tray::CheckAlive() { if (!tray_icon_) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope scope(isolate); gin_helper::ErrorThrower(isolate).ThrowError("Tray is destroyed"); return false; @@ -423,9 +420,7 @@ v8::Local Tray::FillObjectTemplate( .Build(); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_tray.h b/shell/browser/api/electron_api_tray.h index 8c4870b11ad89..64cc856df74bf 100644 --- a/shell/browser/api/electron_api_tray.h +++ b/shell/browser/api/electron_api_tray.h @@ -29,9 +29,7 @@ namespace gin_helper { class Dictionary; } -namespace electron { - -namespace api { +namespace electron::api { class Menu; @@ -113,8 +111,6 @@ class Tray : public gin::Wrappable, std::unique_ptr tray_icon_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_TRAY_H_ diff --git a/shell/browser/api/electron_api_url_loader.cc b/shell/browser/api/electron_api_url_loader.cc index 327a80379a8d4..3a2d329738966 100644 --- a/shell/browser/api/electron_api_url_loader.cc +++ b/shell/browser/api/electron_api_url_loader.cc @@ -66,13 +66,11 @@ struct Converter { return false; return true; } -}; // namespace gin +}; } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -491,7 +489,7 @@ gin::Handle SimpleURLLoaderWrapper::Create( int options = 0; if (!credentials_specified && !use_session_cookies) { // This is the default case, as well as the case when credentials is not - // specified and useSessionCoookies is false. credentials_mode will be + // specified and useSessionCookies is false. credentials_mode will be // kInclude, but cookies will be blocked. request->credentials_mode = network::mojom::CredentialsMode::kInclude; options |= network::mojom::kURLLoadOptionBlockAllCookies; @@ -614,6 +612,4 @@ const char* SimpleURLLoaderWrapper::GetTypeName() { return "SimpleURLLoaderWrapper"; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_url_loader.h b/shell/browser/api/electron_api_url_loader.h index 9ab4d389418fc..adf8de0be458d 100644 --- a/shell/browser/api/electron_api_url_loader.h +++ b/shell/browser/api/electron_api_url_loader.h @@ -33,9 +33,7 @@ class SimpleURLLoader; struct ResourceRequest; } // namespace network -namespace electron { - -namespace api { +namespace electron::api { /** Wraps a SimpleURLLoader to make it usable from JavaScript */ class SimpleURLLoaderWrapper @@ -123,8 +121,6 @@ class SimpleURLLoaderWrapper base::WeakPtrFactory weak_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_URL_LOADER_H_ diff --git a/shell/browser/api/electron_api_view.cc b/shell/browser/api/electron_api_view.cc index e8e172b508094..861871fda68a2 100644 --- a/shell/browser/api/electron_api_view.cc +++ b/shell/browser/api/electron_api_view.cc @@ -8,9 +8,7 @@ #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" -namespace electron { - -namespace api { +namespace electron::api { View::View(views::View* view) : view_(view) { view_->set_owned_by_client(); @@ -55,9 +53,7 @@ void View::BuildPrototype(v8::Isolate* isolate, #endif } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_view.h b/shell/browser/api/electron_api_view.h index ed2e483de0e25..4c9b6df348290 100644 --- a/shell/browser/api/electron_api_view.h +++ b/shell/browser/api/electron_api_view.h @@ -12,9 +12,7 @@ #include "shell/common/gin_helper/wrappable.h" #include "ui/views/view.h" -namespace electron { - -namespace api { +namespace electron::api { class View : public gin_helper::Wrappable { public: @@ -49,8 +47,6 @@ class View : public gin_helper::Wrappable { views::View* view_ = nullptr; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_VIEW_H_ diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index 62e184f512f7b..e12bc087c693f 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -18,7 +18,6 @@ #include "base/no_destructor.h" #include "base/strings/utf_string_conversions.h" #include "base/task/current_thread.h" -#include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -29,6 +28,7 @@ #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/views/eye_dropper/eye_dropper.h" #include "chrome/common/pref_names.h" +#include "components/embedder_support/user_agent_utils.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/security_state/content/content_utils.h" @@ -143,6 +143,10 @@ #include "shell/browser/osr/osr_web_contents_view.h" #endif +#if BUILDFLAG(IS_WIN) +#include "shell/browser/native_window_views.h" +#endif + #if !BUILDFLAG(IS_MAC) #include "ui/aura/window.h" #else @@ -150,7 +154,7 @@ #endif #if BUILDFLAG(IS_LINUX) -#include "ui/views/linux_ui/linux_ui.h" +#include "ui/linux/linux_ui.h" #endif #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) @@ -165,16 +169,18 @@ #endif #if BUILDFLAG(ENABLE_PRINTING) +#include "chrome/browser/printing/print_view_manager_base.h" #include "components/printing/browser/print_manager_utils.h" +#include "components/printing/browser/print_to_pdf/pdf_print_utils.h" #include "printing/backend/print_backend.h" // nogncheck #include "printing/mojom/print.mojom.h" // nogncheck -#include "shell/browser/printing/print_preview_message_handler.h" +#include "printing/page_range.h" #include "shell/browser/printing/print_view_manager_electron.h" #if BUILDFLAG(IS_WIN) #include "printing/backend/win_helper.h" #endif -#endif +#endif // BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PICTURE_IN_PICTURE) #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" @@ -370,9 +376,7 @@ struct Converter> { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -395,7 +399,7 @@ absl::optional GetCursorBlinkInterval() { if (system_value) return *system_value; #elif BUILDFLAG(IS_LINUX) - if (auto* linux_ui = views::LinuxUI::instance()) + if (auto* linux_ui = ui::LinuxUi::instance()) return linux_ui->GetCursorBlinkInterval(); #elif BUILDFLAG(IS_WIN) const auto system_msec = ::GetCaretBlinkTime(); @@ -419,21 +423,34 @@ bool IsDeviceNameValid(const std::u16string& device_name) { bool printer_exists = new_printer != nullptr; PMRelease(new_printer); return printer_exists; -#elif BUILDFLAG(IS_WIN) - printing::ScopedPrinterHandle printer; - return printer.OpenPrinterWithName(base::as_wcstr(device_name)); #else - return true; + scoped_refptr print_backend = + printing::PrintBackend::CreateInstance( + g_browser_process->GetApplicationLocale()); + return print_backend->IsValidPrinter(base::UTF16ToUTF8(device_name)); #endif } -std::pair GetDefaultPrinterAsync() { +// This function returns a validated device name. +// If the user passed one to webContents.print(), we check that it's valid and +// return it or fail if the network doesn't recognize it. If the user didn't +// pass a device name, we first try to return the system default printer. If one +// isn't set, then pull all the printers and use the first one or fail if none +// exist. +std::pair GetDeviceNameToUse( + const std::u16string& device_name) { #if BUILDFLAG(IS_WIN) // Blocking is needed here because Windows printer drivers are oftentimes // not thread-safe and have to be accessed on the UI thread. base::ThreadRestrictions::ScopedAllowIO allow_io; #endif + if (!device_name.empty()) { + if (!IsDeviceNameValid(device_name)) + return std::make_pair("Invalid deviceName provided", std::u16string()); + return std::make_pair(std::string(), device_name); + } + scoped_refptr print_backend = printing::PrintBackend::CreateInstance( g_browser_process->GetApplicationLocale()); @@ -446,14 +463,16 @@ std::pair GetDefaultPrinterAsync() { if (code != printing::mojom::ResultCode::kSuccess) LOG(ERROR) << "Failed to get default printer name"; - // Check for existing printers and pick the first one should it exist. if (printer_name.empty()) { printing::PrinterList printers; - if (print_backend->EnumeratePrinters(&printers) != + if (print_backend->EnumeratePrinters(printers) != printing::mojom::ResultCode::kSuccess) return std::make_pair("Failed to enumerate printers", std::u16string()); - if (!printers.empty()) - printer_name = printers.front().printer_name; + if (printers.empty()) + return std::make_pair("No printers available on the network", + std::u16string()); + + printer_name = printers.front().printer_name; } return std::make_pair(std::string(), base::UTF8ToUTF16(printer_name)); @@ -545,14 +564,13 @@ FileSystem CreateFileSystemStruct(content::WebContents* web_contents, return FileSystem(type, file_system_name, root_url, file_system_path); } -std::unique_ptr CreateFileSystemValue( - const FileSystem& file_system) { - auto file_system_value = std::make_unique(); - file_system_value->SetString("type", file_system.type); - file_system_value->SetString("fileSystemName", file_system.file_system_name); - file_system_value->SetString("rootURL", file_system.root_url); - file_system_value->SetString("fileSystemPath", file_system.file_system_path); - return file_system_value; +base::Value::Dict CreateFileSystemValue(const FileSystem& file_system) { + base::Value::Dict value; + value.Set("type", file_system.type); + value.Set("fileSystemName", file_system.file_system_name); + value.Set("rootURL", file_system.root_url); + value.Set("fileSystemPath", file_system.file_system_path); + return value; } void WriteToFile(const base::FilePath& path, const std::string& content) { @@ -623,6 +641,7 @@ WebContents::Type GetTypeFromViewType(extensions::mojom::ViewType view_type) { case extensions::mojom::ViewType::kBackgroundContents: case extensions::mojom::ViewType::kExtensionGuest: case extensions::mojom::ViewType::kTabContents: + case extensions::mojom::ViewType::kOffscreenDocument: case extensions::mojom::ViewType::kInvalid: return WebContents::Type::kRemote; } @@ -660,9 +679,8 @@ WebContents::WebContents(v8::Isolate* isolate, auto session = Session::CreateFrom(isolate, GetBrowserContext()); session_.Reset(isolate, session.ToV8()); - web_contents->SetUserAgentOverride(blink::UserAgentOverride::UserAgentOnly( - GetBrowserContext()->GetUserAgent()), - false); + SetUserAgent(GetBrowserContext()->GetUserAgent()); + web_contents->SetUserData(kElectronApiWebContentsKey, std::make_unique(GetWeakPtr())); InitZoomController(web_contents, gin::Dictionary::CreateEmpty(isolate)); @@ -868,9 +886,7 @@ void WebContents::InitWithSessionAndOptions( AutofillDriverFactory::CreateForWebContents(web_contents()); - web_contents()->SetUserAgentOverride(blink::UserAgentOverride::UserAgentOnly( - GetBrowserContext()->GetUserAgent()), - false); + SetUserAgent(GetBrowserContext()->GetUserAgent()); if (IsGuest()) { NativeWindow* owner_window = nullptr; @@ -920,10 +936,7 @@ void WebContents::InitWithWebContents( web_contents->SetDelegate(this); #if BUILDFLAG(ENABLE_PRINTING) - PrintPreviewMessageHandler::CreateForWebContents(web_contents.get()); PrintViewManagerElectron::CreateForWebContents(web_contents.get()); - printing::CreateCompositeClientIfNeeded(web_contents.get(), - browser_context->GetUserAgent()); #endif #if BUILDFLAG(ENABLE_PDF_VIEWER) @@ -943,12 +956,6 @@ void WebContents::InitWithWebContents( } WebContents::~WebContents() { - // clear out objects that have been granted permissions so that when - // WebContents::RenderFrameDeleted is called as a result of WebContents - // destruction it doesn't try to clear out a granted_devices_ - // on a destructed object. - granted_devices_.clear(); - if (!inspectable_web_contents_) { WebContentsDestroyed(); return; @@ -990,13 +997,13 @@ void WebContents::DeleteThisIfAlive() { } void WebContents::Destroy() { - // The content::WebContents should be destroyed asyncronously when possible + // The content::WebContents should be destroyed asynchronously when possible // as user may choose to destroy WebContents during an event of it. if (Browser::Get()->is_shutting_down() || IsGuest()) { DeleteThisIfAlive(); } else { - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce( + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( [](base::WeakPtr contents) { if (contents) contents->DeleteThisIfAlive(); @@ -1041,7 +1048,6 @@ void WebContents::WebContentsCreatedWithFullParams( tracker->body = params.body; v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); gin_helper::Dictionary dict; @@ -1073,7 +1079,6 @@ bool WebContents::IsWebContentsCreationOverridden( void WebContents::SetNextChildWebPreferences( const gin_helper::Dictionary preferences) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); // Store these prefs for when Chrome calls WebContentsCreatedWithFullParams // with the new child contents. @@ -1105,7 +1110,6 @@ void WebContents::AddNewContents( v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); auto api_web_contents = CreateAndTake(isolate, std::move(new_contents), Type::kBrowserWindow); @@ -1286,6 +1290,7 @@ void WebContents::UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type, ExclusiveAccessBubbleHideCallback bubble_first_hide_callback, + bool notify_download, bool force_update) {} void WebContents::OnExclusiveAccessUserInput() {} @@ -1311,9 +1316,7 @@ void WebContents::EnterFullscreenModeForTab( auto callback = base::BindRepeating(&WebContents::OnEnterFullscreenModeForTab, base::Unretained(this), requesting_frame, options); - permission_helper->RequestFullscreenPermission(callback); - exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab( - requesting_frame, options.display_id); + permission_helper->RequestFullscreenPermission(requesting_frame, callback); } void WebContents::OnEnterFullscreenModeForTab( @@ -1329,6 +1332,11 @@ void WebContents::OnEnterFullscreenModeForTab( return; } + owner_window()->set_fullscreen_transition_type( + NativeWindow::FullScreenTransitionType::HTML); + exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab( + requesting_frame, options.display_id); + SetHtmlApiFullscreen(true); if (native_fullscreen_) { @@ -1377,11 +1385,6 @@ bool WebContents::HandleContextMenu(content::RenderFrameHost& render_frame_host, return true; } -bool WebContents::OnGoToEntryOffset(int offset) { - GoToOffset(offset); - return false; -} - void WebContents::FindReply(content::WebContents* web_contents, int request_id, int number_of_matches, @@ -1392,7 +1395,6 @@ void WebContents::FindReply(content::WebContents* web_contents, return; v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); gin_helper::Dictionary result = gin::Dictionary::CreateEmpty(isolate); result.Set("requestId", request_id); @@ -1491,11 +1493,13 @@ void WebContents::HandleNewRenderFrame( // Set the background color of RenderWidgetHostView. auto* web_preferences = WebContentsPreferences::From(web_contents()); if (web_preferences) { + absl::optional maybe_color = web_preferences->GetBackgroundColor(); + web_contents()->SetPageBaseBackgroundColor(maybe_color); + bool guest = IsGuest() || type_ == Type::kBrowserView; - absl::optional color = - guest ? SK_ColorTRANSPARENT : web_preferences->GetBackgroundColor(); - web_contents()->SetPageBaseBackgroundColor(color); - SetBackgroundColor(rwhv, color.value_or(SK_ColorWHITE)); + SkColor color = + maybe_color.value_or(guest ? SK_ColorTRANSPARENT : SK_ColorWHITE); + SetBackgroundColor(rwhv, color); } if (!background_throttling_) @@ -1508,7 +1512,7 @@ void WebContents::HandleNewRenderFrame( auto* web_frame = WebFrameMain::FromRenderFrameHost(render_frame_host); if (web_frame) - web_frame->Connect(); + web_frame->MaybeSetupMojoConnection(); } void WebContents::OnBackgroundColorChanged() { @@ -1557,11 +1561,6 @@ void WebContents::RenderFrameDeleted( // is swapped by content::RenderFrameHostManager. // - // clear out objects that have been granted permissions - if (!granted_devices_.empty()) { - granted_devices_.erase(render_frame_host->GetFrameTreeNodeId()); - } - // WebFrameMain::FromRenderFrameHost(rfh) will use the RFH's FrameTreeNode ID // to find an existing instance of WebFrameMain. During a cross-origin // navigation, the deleted RFH will be the old host which was swapped out. In @@ -1771,7 +1770,7 @@ void WebContents::Invoke( void WebContents::OnFirstNonEmptyLayout( content::RenderFrameHost* render_frame_host) { - if (render_frame_host == web_contents()->GetMainFrame()) { + if (render_frame_host == web_contents()->GetPrimaryMainFrame()) { Emit("ready-to-show"); } } @@ -1989,7 +1988,6 @@ void WebContents::DevToolsFocused() { void WebContents::DevToolsOpened() { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); DCHECK(inspectable_web_contents_); DCHECK(inspectable_web_contents_->GetDevToolsWebContents()); @@ -1998,9 +1996,8 @@ void WebContents::DevToolsOpened() { devtools_web_contents_.Reset(isolate, handle.ToV8()); // Set inspected tabID. - base::Value tab_id(ID()); - inspectable_web_contents_->CallClientFunction("DevToolsAPI.setInspectedTabId", - &tab_id, nullptr, nullptr); + inspectable_web_contents_->CallClientFunction( + "DevToolsAPI", "setInspectedTabId", base::Value(ID())); // Inherit owner window in devtools when it doesn't have one. auto* devtools = inspectable_web_contents_->GetDevToolsWebContents(); @@ -2013,7 +2010,6 @@ void WebContents::DevToolsOpened() { void WebContents::DevToolsClosed() { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); devtools_web_contents_.Reset(); @@ -2090,7 +2086,7 @@ bool WebContents::GetBackgroundThrottling() const { void WebContents::SetBackgroundThrottling(bool allowed) { background_throttling_ = allowed; - auto* rfh = web_contents()->GetMainFrame(); + auto* rfh = web_contents()->GetPrimaryMainFrame(); if (!rfh) return; @@ -2112,12 +2108,15 @@ void WebContents::SetBackgroundThrottling(bool allowed) { } int WebContents::GetProcessID() const { - return web_contents()->GetMainFrame()->GetProcess()->GetID(); + return web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID(); } base::ProcessId WebContents::GetOSProcessID() const { - base::ProcessHandle process_handle = - web_contents()->GetMainFrame()->GetProcess()->GetProcess().Handle(); + base::ProcessHandle process_handle = web_contents() + ->GetPrimaryMainFrame() + ->GetProcess() + ->GetProcess() + .Handle(); return base::GetProcId(process_handle); } @@ -2154,8 +2153,7 @@ void WebContents::LoadURL(const GURL& url, std::string user_agent; if (options.Get("userAgent", &user_agent)) - web_contents()->SetUserAgentOverride( - blink::UserAgentOverride::UserAgentOnly(user_agent), false); + SetUserAgent(user_agent); std::string extra_headers; if (options.Get("extraHeaders", &extra_headers)) @@ -2185,7 +2183,7 @@ void WebContents::LoadURL(const GURL& url, params.transition_type = ui::PageTransitionFromInt( ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; - // Discord non-committed entries to ensure that we don't re-use a pending + // Discard non-committed entries to ensure that we don't re-use a pending // entry web_contents()->GetController().DiscardNonCommittedEntries(); web_contents()->GetController().LoadURLWithParams(params); @@ -2314,7 +2312,7 @@ void WebContents::SetWebRTCIPHandlingPolicy( std::string WebContents::GetMediaSourceID( content::WebContents* request_web_contents) { - auto* frame_host = web_contents()->GetMainFrame(); + auto* frame_host = web_contents()->GetPrimaryMainFrame(); if (!frame_host) return std::string(); @@ -2324,7 +2322,7 @@ std::string WebContents::GetMediaSourceID( content::WebContentsMediaCaptureId(frame_host->GetProcess()->GetID(), frame_host->GetRoutingID())); - auto* request_frame_host = request_web_contents->GetMainFrame(); + auto* request_frame_host = request_web_contents->GetPrimaryMainFrame(); if (!request_frame_host) return std::string(); @@ -2370,8 +2368,12 @@ void WebContents::ForcefullyCrashRenderer() { } void WebContents::SetUserAgent(const std::string& user_agent) { - web_contents()->SetUserAgentOverride( - blink::UserAgentOverride::UserAgentOnly(user_agent), false); + blink::UserAgentOverride ua_override; + ua_override.ua_string_override = user_agent; + if (!user_agent.empty()) + ua_override.ua_metadata_override = embedder_support::GetUserAgentMetadata(); + + web_contents()->SetUserAgentOverride(ua_override, false); } std::string WebContents::GetUserAgent() { @@ -2408,6 +2410,15 @@ void WebContents::OpenDevTools(gin::Arguments* args) { !owner_window()) { state = "detach"; } + +#if BUILDFLAG(IS_WIN) + auto* win = static_cast(owner_window()); + // Force a detached state when WCO is enabled to match Chrome + // behavior and prevent occlusion of DevTools. + if (win && win->IsWindowControlsOverlayEnabled()) + state = "detach"; +#endif + bool activate = true; if (args && args->Length() == 1) { gin_helper::Dictionary options; @@ -2452,7 +2463,7 @@ void WebContents::EnableDeviceEmulation( return; DCHECK(web_contents()); - auto* frame_host = web_contents()->GetMainFrame(); + auto* frame_host = web_contents()->GetPrimaryMainFrame(); if (frame_host) { auto* widget_host_impl = static_cast( frame_host->GetView()->GetRenderWidgetHost()); @@ -2468,7 +2479,7 @@ void WebContents::DisableDeviceEmulation() { return; DCHECK(web_contents()); - auto* frame_host = web_contents()->GetMainFrame(); + auto* frame_host = web_contents()->GetPrimaryMainFrame(); if (frame_host) { auto* widget_host_impl = static_cast( frame_host->GetView()->GetRenderWidgetHost()); @@ -2590,12 +2601,11 @@ bool WebContents::IsCurrentlyAudible() { } #if BUILDFLAG(ENABLE_PRINTING) -void WebContents::OnGetDefaultPrinter( - base::Value print_settings, +void WebContents::OnGetDeviceNameToUse( + base::Value::Dict print_settings, printing::CompletionCallback print_callback, - std::u16string device_name, bool silent, - // + // std::pair info) { // The content::WebContents might be already deleted at this point, and the // PrintViewManagerElectron class does not do null check. @@ -2612,16 +2622,7 @@ void WebContents::OnGetDefaultPrinter( } // If the user has passed a deviceName use it, otherwise use default printer. - std::u16string printer_name = device_name.empty() ? info.second : device_name; - - // If there are no valid printers available on the network, we bail. - if (printer_name.empty() || !IsDeviceNameValid(printer_name)) { - if (print_callback) - std::move(print_callback).Run(false, "no valid printers available"); - return; - } - - print_settings.SetStringKey(printing::kSettingDeviceName, printer_name); + print_settings.Set(printing::kSettingDeviceName, info.second); auto* print_view_manager = PrintViewManagerElectron::FromWebContents(web_contents()); @@ -2631,7 +2632,7 @@ void WebContents::OnGetDefaultPrinter( auto* focused_frame = web_contents()->GetFocusedFrame(); auto* rfh = focused_frame && focused_frame->HasSelection() ? focused_frame - : web_contents()->GetMainFrame(); + : web_contents()->GetPrimaryMainFrame(); print_view_manager->PrintNow(rfh, silent, std::move(print_settings), std::move(print_callback)); @@ -2640,7 +2641,7 @@ void WebContents::OnGetDefaultPrinter( void WebContents::Print(gin::Arguments* args) { gin_helper::Dictionary options = gin::Dictionary::CreateEmpty(args->isolate()); - base::Value settings(base::Value::Type::DICTIONARY); + base::Value::Dict settings; if (args->Length() >= 1 && !args->GetNext(&options)) { gin_helper::ErrorThrower(args->isolate()) @@ -2661,8 +2662,7 @@ void WebContents::Print(gin::Arguments* args) { bool print_background = false; options.Get("printBackground", &print_background); - settings.SetBoolKey(printing::kSettingShouldPrintBackgrounds, - print_background); + settings.Set(printing::kSettingShouldPrintBackgrounds, print_background); // Set custom margin settings gin_helper::Dictionary margins = @@ -2671,28 +2671,26 @@ void WebContents::Print(gin::Arguments* args) { printing::mojom::MarginType margin_type = printing::mojom::MarginType::kDefaultMargins; margins.Get("marginType", &margin_type); - settings.SetIntKey(printing::kSettingMarginsType, - static_cast(margin_type)); + settings.Set(printing::kSettingMarginsType, static_cast(margin_type)); if (margin_type == printing::mojom::MarginType::kCustomMargins) { - base::Value custom_margins(base::Value::Type::DICTIONARY); + base::Value::Dict custom_margins; int top = 0; margins.Get("top", &top); - custom_margins.SetIntKey(printing::kSettingMarginTop, top); + custom_margins.Set(printing::kSettingMarginTop, top); int bottom = 0; margins.Get("bottom", &bottom); - custom_margins.SetIntKey(printing::kSettingMarginBottom, bottom); + custom_margins.Set(printing::kSettingMarginBottom, bottom); int left = 0; margins.Get("left", &left); - custom_margins.SetIntKey(printing::kSettingMarginLeft, left); + custom_margins.Set(printing::kSettingMarginLeft, left); int right = 0; margins.Get("right", &right); - custom_margins.SetIntKey(printing::kSettingMarginRight, right); - settings.SetPath(printing::kSettingMarginsCustom, - std::move(custom_margins)); + custom_margins.Set(printing::kSettingMarginRight, right); + settings.Set(printing::kSettingMarginsCustom, std::move(custom_margins)); } } else { - settings.SetIntKey( + settings.Set( printing::kSettingMarginsType, static_cast(printing::mojom::MarginType::kDefaultMargins)); } @@ -2702,41 +2700,36 @@ void WebContents::Print(gin::Arguments* args) { options.Get("color", &print_color); auto const color_model = print_color ? printing::mojom::ColorModel::kColor : printing::mojom::ColorModel::kGray; - settings.SetIntKey(printing::kSettingColor, static_cast(color_model)); + settings.Set(printing::kSettingColor, static_cast(color_model)); // Is the orientation landscape or portrait. bool landscape = false; options.Get("landscape", &landscape); - settings.SetBoolKey(printing::kSettingLandscape, landscape); + settings.Set(printing::kSettingLandscape, landscape); // We set the default to the system's default printer and only update // if at the Chromium level if the user overrides. // Printer device name as opened by the OS. std::u16string device_name; options.Get("deviceName", &device_name); - if (!device_name.empty() && !IsDeviceNameValid(device_name)) { - gin_helper::ErrorThrower(args->isolate()) - .ThrowError("webContents.print(): Invalid deviceName provided."); - return; - } int scale_factor = 100; options.Get("scaleFactor", &scale_factor); - settings.SetIntKey(printing::kSettingScaleFactor, scale_factor); + settings.Set(printing::kSettingScaleFactor, scale_factor); int pages_per_sheet = 1; options.Get("pagesPerSheet", &pages_per_sheet); - settings.SetIntKey(printing::kSettingPagesPerSheet, pages_per_sheet); + settings.Set(printing::kSettingPagesPerSheet, pages_per_sheet); // True if the user wants to print with collate. bool collate = true; options.Get("collate", &collate); - settings.SetBoolKey(printing::kSettingCollate, collate); + settings.Set(printing::kSettingCollate, collate); // The number of individual copies to print int copies = 1; options.Get("copies", &copies); - settings.SetIntKey(printing::kSettingCopies, copies); + settings.Set(printing::kSettingCopies, copies); // Strings to be printed as headers and footers if requested by the user. std::string header; @@ -2745,53 +2738,52 @@ void WebContents::Print(gin::Arguments* args) { options.Get("footer", &footer); if (!(header.empty() && footer.empty())) { - settings.SetBoolKey(printing::kSettingHeaderFooterEnabled, true); + settings.Set(printing::kSettingHeaderFooterEnabled, true); - settings.SetStringKey(printing::kSettingHeaderFooterTitle, header); - settings.SetStringKey(printing::kSettingHeaderFooterURL, footer); + settings.Set(printing::kSettingHeaderFooterTitle, header); + settings.Set(printing::kSettingHeaderFooterURL, footer); } else { - settings.SetBoolKey(printing::kSettingHeaderFooterEnabled, false); + settings.Set(printing::kSettingHeaderFooterEnabled, false); } // We don't want to allow the user to enable these settings // but we need to set them or a CHECK is hit. - settings.SetIntKey(printing::kSettingPrinterType, - static_cast(printing::mojom::PrinterType::kLocal)); - settings.SetBoolKey(printing::kSettingShouldPrintSelectionOnly, false); - settings.SetBoolKey(printing::kSettingRasterizePdf, false); + settings.Set(printing::kSettingPrinterType, + static_cast(printing::mojom::PrinterType::kLocal)); + settings.Set(printing::kSettingShouldPrintSelectionOnly, false); + settings.Set(printing::kSettingRasterizePdf, false); // Set custom page ranges to print std::vector page_ranges; if (options.Get("pageRanges", &page_ranges)) { - base::Value page_range_list(base::Value::Type::LIST); + base::Value::List page_range_list; for (auto& range : page_ranges) { int from, to; if (range.Get("from", &from) && range.Get("to", &to)) { - base::Value range(base::Value::Type::DICTIONARY); + base::Value::Dict range; // Chromium uses 1-based page ranges, so increment each by 1. - range.SetIntKey(printing::kSettingPageRangeFrom, from + 1); - range.SetIntKey(printing::kSettingPageRangeTo, to + 1); + range.Set(printing::kSettingPageRangeFrom, from + 1); + range.Set(printing::kSettingPageRangeTo, to + 1); page_range_list.Append(std::move(range)); } else { continue; } } - if (!page_range_list.GetListDeprecated().empty()) - settings.SetPath(printing::kSettingPageRange, std::move(page_range_list)); + if (!page_range_list.empty()) + settings.Set(printing::kSettingPageRange, std::move(page_range_list)); } // Duplex type user wants to use. printing::mojom::DuplexMode duplex_mode = printing::mojom::DuplexMode::kSimplex; options.Get("duplexMode", &duplex_mode); - settings.SetIntKey(printing::kSettingDuplexMode, - static_cast(duplex_mode)); + settings.Set(printing::kSettingDuplexMode, static_cast(duplex_mode)); // We've already done necessary parameter sanitization at the // JS level, so we can simply pass this through. base::Value media_size(base::Value::Type::DICTIONARY); if (options.Get("mediaSize", &media_size)) - settings.SetKey(printing::kSettingMediaSize, std::move(media_size)); + settings.Set(printing::kSettingMediaSize, std::move(media_size)); // Set custom dots per inch (dpi) gin_helper::Dictionary dpi_settings; @@ -2799,30 +2791,103 @@ void WebContents::Print(gin::Arguments* args) { if (options.Get("dpi", &dpi_settings)) { int horizontal = 72; dpi_settings.Get("horizontal", &horizontal); - settings.SetIntKey(printing::kSettingDpiHorizontal, horizontal); + settings.Set(printing::kSettingDpiHorizontal, horizontal); int vertical = 72; dpi_settings.Get("vertical", &vertical); - settings.SetIntKey(printing::kSettingDpiVertical, vertical); + settings.Set(printing::kSettingDpiVertical, vertical); } else { - settings.SetIntKey(printing::kSettingDpiHorizontal, dpi); - settings.SetIntKey(printing::kSettingDpiVertical, dpi); + settings.Set(printing::kSettingDpiHorizontal, dpi); + settings.Set(printing::kSettingDpiVertical, dpi); } print_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, base::BindOnce(&GetDefaultPrinterAsync), - base::BindOnce(&WebContents::OnGetDefaultPrinter, + FROM_HERE, base::BindOnce(&GetDeviceNameToUse, device_name), + base::BindOnce(&WebContents::OnGetDeviceNameToUse, weak_factory_.GetWeakPtr(), std::move(settings), - std::move(callback), device_name, silent)); + std::move(callback), silent)); } -v8::Local WebContents::PrintToPDF(base::DictionaryValue settings) { +// Partially duplicated and modified from +// headless/lib/browser/protocol/page_handler.cc;l=41 +v8::Local WebContents::PrintToPDF(const base::Value& settings) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); gin_helper::Promise> promise(isolate); v8::Local handle = promise.GetHandle(); - PrintPreviewMessageHandler::FromWebContents(web_contents()) - ->PrintToPDF(std::move(settings), std::move(promise)); + + // This allows us to track headless printing calls. + auto unique_id = settings.GetDict().FindInt(printing::kPreviewRequestID); + auto landscape = settings.GetDict().FindBool("landscape"); + auto display_header_footer = + settings.GetDict().FindBool("displayHeaderFooter"); + auto print_background = settings.GetDict().FindBool("shouldPrintBackgrounds"); + auto scale = settings.GetDict().FindDouble("scale"); + auto paper_width = settings.GetDict().FindDouble("paperWidth"); + auto paper_height = settings.GetDict().FindDouble("paperHeight"); + auto margin_top = settings.GetDict().FindDouble("marginTop"); + auto margin_bottom = settings.GetDict().FindDouble("marginBottom"); + auto margin_left = settings.GetDict().FindDouble("marginLeft"); + auto margin_right = settings.GetDict().FindDouble("marginRight"); + auto page_ranges = *settings.GetDict().FindString("pageRanges"); + auto header_template = *settings.GetDict().FindString("headerTemplate"); + auto footer_template = *settings.GetDict().FindString("footerTemplate"); + auto prefer_css_page_size = settings.GetDict().FindBool("preferCSSPageSize"); + + absl::variant + print_pages_params = print_to_pdf::GetPrintPagesParams( + web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL(), + landscape, display_header_footer, print_background, scale, + paper_width, paper_height, margin_top, margin_bottom, margin_left, + margin_right, absl::make_optional(header_template), + absl::make_optional(footer_template), prefer_css_page_size); + + if (absl::holds_alternative(print_pages_params)) { + auto error = absl::get(print_pages_params); + promise.RejectWithErrorMessage("Invalid print parameters: " + error); + return handle; + } + + auto* manager = PrintViewManagerElectron::FromWebContents(web_contents()); + if (!manager) { + promise.RejectWithErrorMessage("Failed to find print manager"); + return handle; + } + + auto params = std::move( + absl::get(print_pages_params)); + params->params->document_cookie = unique_id.value_or(0); + + manager->PrintToPdf(web_contents()->GetPrimaryMainFrame(), page_ranges, + std::move(params), + base::BindOnce(&WebContents::OnPDFCreated, GetWeakPtr(), + std::move(promise))); + return handle; } + +void WebContents::OnPDFCreated( + gin_helper::Promise> promise, + PrintViewManagerElectron::PrintResult print_result, + scoped_refptr data) { + if (print_result != PrintViewManagerElectron::PrintResult::kPrintSuccess) { + promise.RejectWithErrorMessage( + "Failed to generate PDF: " + + PrintViewManagerElectron::PrintResultToString(print_result)); + return; + } + + v8::Isolate* isolate = promise.isolate(); + gin_helper::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope( + v8::Local::New(isolate, promise.GetContext())); + + v8::Local buffer = + node::Buffer::Copy(isolate, reinterpret_cast(data->front()), + data->size()) + .ToLocalChecked(); + + promise.Resolve(buffer); +} #endif void WebContents::AddWorkSpace(gin::Arguments* args, @@ -2923,7 +2988,7 @@ void WebContents::ShowDefinitionForSelection() { } void WebContents::CopyImageAt(int x, int y) { - auto* const host = web_contents()->GetMainFrame(); + auto* const host = web_contents()->GetPrimaryMainFrame(); if (host) host->CopyImageAt(x, y); } @@ -3089,7 +3154,7 @@ v8::Local WebContents::CapturePage(gin::Arguments* args) { // If the view's renderer is suspended this may fail on Windows/Linux - // bail if so. See CopyFromSurface in // content/public/browser/render_widget_host_view.h. - auto* rfh = web_contents()->GetMainFrame(); + auto* rfh = web_contents()->GetPrimaryMainFrame(); if (rfh && rfh->GetVisibilityState() == blink::mojom::PageVisibilityState::kHidden) { promise.Resolve(gfx::Image()); @@ -3367,11 +3432,15 @@ v8::Local WebContents::Debugger(v8::Isolate* isolate) { } content::RenderFrameHost* WebContents::MainFrame() { - return web_contents()->GetMainFrame(); + return web_contents()->GetPrimaryMainFrame(); +} + +content::RenderFrameHost* WebContents::Opener() { + return web_contents()->GetOpener(); } void WebContents::NotifyUserActivation() { - content::RenderFrameHost* frame = web_contents()->GetMainFrame(); + content::RenderFrameHost* frame = web_contents()->GetPrimaryMainFrame(); if (frame) frame->NotifyUserActivation( blink::mojom::UserActivationNotificationType::kInteraction); @@ -3387,7 +3456,7 @@ v8::Local WebContents::GetProcessMemoryInfo(v8::Isolate* isolate) { gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); - auto* frame_host = web_contents()->GetMainFrame(); + auto* frame_host = web_contents()->GetPrimaryMainFrame(); if (!frame_host) { promise.RejectWithErrorMessage("Failed to create memory dump"); return handle; @@ -3417,13 +3486,13 @@ v8::Local WebContents::TakeHeapSnapshot( return handle; } - auto* frame_host = web_contents()->GetMainFrame(); + auto* frame_host = web_contents()->GetPrimaryMainFrame(); if (!frame_host) { promise.RejectWithErrorMessage("takeHeapSnapshot failed"); return handle; } - if (!frame_host->IsRenderFrameCreated()) { + if (!frame_host->IsRenderFrameLive()) { promise.RejectWithErrorMessage("takeHeapSnapshot failed"); return handle; } @@ -3451,42 +3520,6 @@ v8::Local WebContents::TakeHeapSnapshot( return handle; } -void WebContents::GrantDevicePermission( - const url::Origin& origin, - const base::Value* device, - content::PermissionType permissionType, - content::RenderFrameHost* render_frame_host) { - granted_devices_[render_frame_host->GetFrameTreeNodeId()][permissionType] - [origin] - .push_back( - std::make_unique(device->Clone())); -} - -std::vector WebContents::GetGrantedDevices( - const url::Origin& origin, - content::PermissionType permissionType, - content::RenderFrameHost* render_frame_host) { - const auto& devices_for_frame_host_it = - granted_devices_.find(render_frame_host->GetFrameTreeNodeId()); - if (devices_for_frame_host_it == granted_devices_.end()) - return {}; - - const auto& current_devices_it = - devices_for_frame_host_it->second.find(permissionType); - if (current_devices_it == devices_for_frame_host_it->second.end()) - return {}; - - const auto& origin_devices_it = current_devices_it->second.find(origin); - if (origin_devices_it == current_devices_it->second.end()) - return {}; - - std::vector results; - for (const auto& object : origin_devices_it->second) - results.push_back(object->Clone()); - - return results; -} - void WebContents::UpdatePreferredSize(content::WebContents* web_contents, const gfx::Size& pref_size) { Emit("preferred-size-changed", pref_size); @@ -3519,7 +3552,15 @@ void WebContents::EnumerateDirectory( bool WebContents::IsFullscreenForTabOrPending( const content::WebContents* source) { - return html_fullscreen_; + if (!owner_window()) + return html_fullscreen_; + + bool in_transition = owner_window()->fullscreen_transition_state() != + NativeWindow::FullScreenTransitionState::NONE; + bool is_html_transition = owner_window()->fullscreen_transition_type() == + NativeWindow::FullScreenTransitionType::HTML; + + return html_fullscreen_ || (in_transition && is_html_transition); } bool WebContents::TakeFocus(content::WebContents* source, bool reverse) { @@ -3564,19 +3605,17 @@ void WebContents::DevToolsSaveToFile(const std::string& url, settings.title = url; settings.default_path = base::FilePath::FromUTF8Unsafe(url); if (!file_dialog::ShowSaveDialogSync(settings, &path)) { - base::Value url_value(url); inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr); + "DevToolsAPI", "canceledSaveURL", base::Value(url)); return; } } saved_files_[url] = path; // Notify DevTools. - base::Value url_value(url); - base::Value file_system_path_value(path.AsUTF8Unsafe()); inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.savedURL", &url_value, &file_system_path_value, nullptr); + "DevToolsAPI", "savedURL", base::Value(url), + base::Value(path.AsUTF8Unsafe())); file_task_runner_->PostTask(FROM_HERE, base::BindOnce(&WriteToFile, path, content)); } @@ -3588,9 +3627,8 @@ void WebContents::DevToolsAppendToFile(const std::string& url, return; // Notify DevTools. - base::Value url_value(url); - inspectable_web_contents_->CallClientFunction("DevToolsAPI.appendedToURL", - &url_value, nullptr, nullptr); + inspectable_web_contents_->CallClientFunction("DevToolsAPI", "appendedToURL", + base::Value(url)); file_task_runner_->PostTask( FROM_HERE, base::BindOnce(&AppendToFile, it->second, content)); } @@ -3598,10 +3636,8 @@ void WebContents::DevToolsAppendToFile(const std::string& url, void WebContents::DevToolsRequestFileSystems() { auto file_system_paths = GetAddedFileSystemPaths(GetDevToolsWebContents()); if (file_system_paths.empty()) { - base::ListValue empty_file_system_value; inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.fileSystemsLoaded", &empty_file_system_value, nullptr, - nullptr); + "DevToolsAPI", "fileSystemsLoaded", base::Value(base::Value::List())); return; } @@ -3617,11 +3653,12 @@ void WebContents::DevToolsRequestFileSystems() { file_systems.push_back(file_system); } - base::ListValue file_system_value; + base::Value::List file_system_value; for (const auto& file_system : file_systems) file_system_value.Append(CreateFileSystemValue(file_system)); inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.fileSystemsLoaded", &file_system_value, nullptr, nullptr); + "DevToolsAPI", "fileSystemsLoaded", + base::Value(std::move(file_system_value))); } void WebContents::DevToolsAddFileSystem( @@ -3647,14 +3684,15 @@ void WebContents::DevToolsAddFileSystem( FileSystem file_system = CreateFileSystemStruct( GetDevToolsWebContents(), file_system_id, path.AsUTF8Unsafe(), type); - std::unique_ptr file_system_value( - CreateFileSystemValue(file_system)); + base::Value::Dict file_system_value = CreateFileSystemValue(file_system); auto* pref_service = GetPrefService(GetDevToolsWebContents()); DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths); update.Get()->SetKey(path.AsUTF8Unsafe(), base::Value(type)); + std::string error = ""; // No error inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.fileSystemAdded", nullptr, file_system_value.get(), nullptr); + "DevToolsAPI", "fileSystemAdded", base::Value(error), + base::Value(std::move(file_system_value))); } void WebContents::DevToolsRemoveFileSystem( @@ -3670,10 +3708,8 @@ void WebContents::DevToolsRemoveFileSystem( DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths); update.Get()->RemoveKey(path); - base::Value file_system_path_value(path); - inspectable_web_contents_->CallClientFunction("DevToolsAPI.fileSystemRemoved", - &file_system_path_value, - nullptr, nullptr); + inspectable_web_contents_->CallClientFunction( + "DevToolsAPI", "fileSystemRemoved", base::Value(path)); } void WebContents::DevToolsIndexPath( @@ -3749,13 +3785,13 @@ void WebContents::DevToolsSetEyeDropperActive(bool active) { } void WebContents::ColorPickedInEyeDropper(int r, int g, int b, int a) { - base::DictionaryValue color; - color.SetInteger("r", r); - color.SetInteger("g", g); - color.SetInteger("b", b); - color.SetInteger("a", a); + base::Value::Dict color; + color.Set("r", r); + color.Set("g", g); + color.Set("b", b); + color.Set("a", a); inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.eyeDropperPickedColor", &color, nullptr, nullptr); + "DevToolsAPI", "eyeDropperPickedColor", base::Value(std::move(color))); } #if defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_MAC) @@ -3776,48 +3812,37 @@ void WebContents::OnDevToolsIndexingWorkCalculated( int request_id, const std::string& file_system_path, int total_work) { - base::Value request_id_value(request_id); - base::Value file_system_path_value(file_system_path); - base::Value total_work_value(total_work); inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.indexingTotalWorkCalculated", &request_id_value, - &file_system_path_value, &total_work_value); + "DevToolsAPI", "indexingTotalWorkCalculated", base::Value(request_id), + base::Value(file_system_path), base::Value(total_work)); } void WebContents::OnDevToolsIndexingWorked(int request_id, const std::string& file_system_path, int worked) { - base::Value request_id_value(request_id); - base::Value file_system_path_value(file_system_path); - base::Value worked_value(worked); inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.indexingWorked", &request_id_value, &file_system_path_value, - &worked_value); + "DevToolsAPI", "indexingWorked", base::Value(request_id), + base::Value(file_system_path), base::Value(worked)); } void WebContents::OnDevToolsIndexingDone(int request_id, const std::string& file_system_path) { devtools_indexing_jobs_.erase(request_id); - base::Value request_id_value(request_id); - base::Value file_system_path_value(file_system_path); - inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.indexingDone", &request_id_value, &file_system_path_value, - nullptr); + inspectable_web_contents_->CallClientFunction("DevToolsAPI", "indexingDone", + base::Value(request_id), + base::Value(file_system_path)); } void WebContents::OnDevToolsSearchCompleted( int request_id, const std::string& file_system_path, const std::vector& file_paths) { - base::ListValue file_paths_value; - for (const auto& file_path : file_paths) { + base::Value::List file_paths_value; + for (const auto& file_path : file_paths) file_paths_value.Append(file_path); - } - base::Value request_id_value(request_id); - base::Value file_system_path_value(file_system_path); inspectable_web_contents_->CallClientFunction( - "DevToolsAPI.searchCompleted", &request_id_value, &file_system_path_value, - &file_paths_value); + "DevToolsAPI", "searchCompleted", base::Value(request_id), + base::Value(file_system_path), base::Value(std::move(file_paths_value))); } void WebContents::SetHtmlApiFullscreen(bool enter_fullscreen) { @@ -3841,9 +3866,8 @@ void WebContents::SetHtmlApiFullscreen(bool enter_fullscreen) { ? !web_preferences->ShouldDisableHtmlFullscreenWindowResize() : true; - if (html_fullscreenable) { + if (html_fullscreenable) owner_window_->SetFullScreen(enter_fullscreen); - } UpdateHtmlApiFullscreen(enter_fullscreen); native_fullscreen_ = false; @@ -4025,6 +4049,7 @@ v8::Local WebContents::FillObjectTemplate( .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents) .SetProperty("debugger", &WebContents::Debugger) .SetProperty("mainFrame", &WebContents::MainFrame) + .SetProperty("opener", &WebContents::Opener) .Build(); } @@ -4133,14 +4158,13 @@ WebContents* WebContents::FromID(int32_t id) { // static gin::WrapperInfo WebContents::kWrapperInfo = {gin::kEmbedderNativeGin}; -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { using electron::api::GetAllWebContents; using electron::api::WebContents; +using electron::api::WebFrameMain; gin::Handle WebContentsFromID(v8::Isolate* isolate, int32_t id) { WebContents* contents = WebContents::FromID(id); @@ -4148,6 +4172,15 @@ gin::Handle WebContentsFromID(v8::Isolate* isolate, int32_t id) { : gin::Handle(); } +gin::Handle WebContentsFromFrame(v8::Isolate* isolate, + WebFrameMain* web_frame) { + content::RenderFrameHost* rfh = web_frame->render_frame_host(); + content::WebContents* source = content::WebContents::FromRenderFrameHost(rfh); + WebContents* contents = WebContents::From(source); + return contents ? gin::CreateHandle(isolate, contents) + : gin::Handle(); +} + gin::Handle WebContentsFromDevToolsTargetID( v8::Isolate* isolate, std::string target_id) { @@ -4176,6 +4209,7 @@ void Initialize(v8::Local exports, gin_helper::Dictionary dict(isolate, exports); dict.Set("WebContents", WebContents::GetConstructor(context)); dict.SetMethod("fromId", &WebContentsFromID); + dict.SetMethod("fromFrame", &WebContentsFromFrame); dict.SetMethod("fromDevToolsTargetId", &WebContentsFromDevToolsTargetID); dict.SetMethod("getAllWebContents", &GetAllWebContentsAsV8); } diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index 996c90cbbbc39..1d7bc0ccb7e34 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -21,7 +21,6 @@ #include "content/common/frame.mojom.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/keyboard_event_processing_result.h" -#include "content/public/browser/permission_type.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" @@ -47,7 +46,6 @@ #include "ui/gfx/image/image.h" #if BUILDFLAG(ENABLE_PRINTING) -#include "shell/browser/printing/print_preview_message_handler.h" #include "shell/browser/printing/print_view_manager_electron.h" #endif @@ -61,7 +59,8 @@ class ScriptExecutor; namespace blink { struct DeviceEmulationParams; -} +// enum class PermissionType; +} // namespace blink namespace gin_helper { class Dictionary; @@ -95,11 +94,6 @@ class OffScreenWebContentsView; namespace api { -using DevicePermissionMap = std::map< - int, - std::map>>>>; - // Wrapper around the content::WebContents. class WebContents : public ExclusiveAccessContext, public gin::Wrappable, @@ -222,15 +216,17 @@ class WebContents : public ExclusiveAccessContext, void HandleNewRenderFrame(content::RenderFrameHost* render_frame_host); #if BUILDFLAG(ENABLE_PRINTING) - void OnGetDefaultPrinter(base::Value print_settings, - printing::CompletionCallback print_callback, - std::u16string device_name, - bool silent, - // - std::pair info); + void OnGetDeviceNameToUse(base::Value::Dict print_settings, + printing::CompletionCallback print_callback, + bool silent, + // + std::pair info); void Print(gin::Arguments* args); // Print current page as PDF. - v8::Local PrintToPDF(base::DictionaryValue settings); + v8::Local PrintToPDF(const base::Value& settings); + void OnPDFCreated(gin_helper::Promise> promise, + PrintViewManagerElectron::PrintResult print_result, + scoped_refptr data); #endif void SetNextChildWebPreferences(const gin_helper::Dictionary); @@ -336,6 +332,7 @@ class WebContents : public ExclusiveAccessContext, v8::Local DevToolsWebContents(v8::Isolate* isolate); v8::Local Debugger(v8::Isolate* isolate); content::RenderFrameHost* MainFrame(); + content::RenderFrameHost* Opener(); WebContentsZoomController* GetZoomController() { return zoom_controller_; } @@ -435,21 +432,6 @@ class WebContents : public ExclusiveAccessContext, void SetImageAnimationPolicy(const std::string& new_policy); - // Grants |origin| access to |device|. - // To be used in place of ObjectPermissionContextBase::GrantObjectPermission. - void GrantDevicePermission(const url::Origin& origin, - const base::Value* device, - content::PermissionType permissionType, - content::RenderFrameHost* render_frame_host); - - // Returns the list of devices that |origin| has been granted permission to - // access. To be used in place of - // ObjectPermissionContextBase::GetGrantedObjects. - std::vector GetGrantedDevices( - const url::Origin& origin, - content::PermissionType permissionType, - content::RenderFrameHost* render_frame_host); - // disable copy WebContents(const WebContents&) = delete; WebContents& operator=(const WebContents&) = delete; @@ -553,7 +535,6 @@ class WebContents : public ExclusiveAccessContext, content::RenderWidgetHost* render_widget_host) override; bool HandleContextMenu(content::RenderFrameHost& render_frame_host, const content::ContextMenuParams& params) override; - bool OnGoToEntryOffset(int offset) override; void FindReply(content::WebContents* web_contents, int request_id, int number_of_matches, @@ -684,6 +665,7 @@ class WebContents : public ExclusiveAccessContext, const GURL& url, ExclusiveAccessBubbleType bubble_type, ExclusiveAccessBubbleHideCallback bubble_first_hide_callback, + bool notify_download, bool force_update) override; void OnExclusiveAccessUserInput() override; content::WebContents* GetActiveWebContents() override; @@ -829,9 +811,6 @@ class WebContents : public ExclusiveAccessContext, // Stores the frame thats currently in fullscreen, nullptr if there is none. content::RenderFrameHost* fullscreen_frame_ = nullptr; - // In-memory cache that holds objects that have been granted permissions. - DevicePermissionMap granted_devices_; - base::WeakPtrFactory weak_factory_{this}; }; diff --git a/shell/browser/api/electron_api_web_contents_impl.cc b/shell/browser/api/electron_api_web_contents_impl.cc index b7433097df435..0460480976b59 100644 --- a/shell/browser/api/electron_api_web_contents_impl.cc +++ b/shell/browser/api/electron_api_web_contents_impl.cc @@ -17,9 +17,7 @@ // have to isolate the usage of WebContentsImpl into a clean file to fix it: // error C2371: 'ssize_t': redefinition; different basic types -namespace electron { - -namespace api { +namespace electron::api { void WebContents::DetachFromOuterFrame() { // See detach_webview_frame.patch on how to detach. @@ -55,6 +53,4 @@ OffScreenRenderWidgetHostView* WebContents::GetOffScreenRenderWidgetHostView() } #endif -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_web_contents_mac.mm b/shell/browser/api/electron_api_web_contents_mac.mm index b31c1f79b130f..f6aa567482b45 100644 --- a/shell/browser/api/electron_api_web_contents_mac.mm +++ b/shell/browser/api/electron_api_web_contents_mac.mm @@ -15,9 +15,7 @@ @interface NSWindow (EventDispatchingWindow) - (void)redispatchKeyEvent:(NSEvent*)event; @end -namespace electron { - -namespace api { +namespace electron::api { bool WebContents::IsFocused() const { auto* view = web_contents()->GetRenderWidgetHostView(); @@ -54,7 +52,7 @@ - (void)redispatchKeyEvent:(NSEvent*)event; return false; // Send the event to the menu before sending it to the window - if (event.os_event.type == NSKeyDown && + if (event.os_event.type == NSEventTypeKeyDown && [[NSApp mainMenu] performKeyEquivalent:event.os_event]) return true; @@ -64,7 +62,7 @@ - (void)redispatchKeyEvent:(NSEvent*)event; [event.os_event.window redispatchKeyEvent:event.os_event]; // FIXME(nornagon): this isn't the right return value; we should implement // devtools windows as Widgets in order to take advantage of the - // pre-existing redispatch code in bridged_native_widget. + // preexisting redispatch code in bridged_native_widget. return false; } else if (event.os_event.window && [event.os_event.window @@ -81,6 +79,4 @@ - (void)redispatchKeyEvent:(NSEvent*)event; return false; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_web_contents_view.cc b/shell/browser/api/electron_api_web_contents_view.cc index 8e9e281cc8bb9..7b74cb238cd08 100644 --- a/shell/browser/api/electron_api_web_contents_view.cc +++ b/shell/browser/api/electron_api_web_contents_view.cc @@ -19,9 +19,7 @@ #include "shell/browser/ui/cocoa/delayed_native_view_host.h" #endif -namespace electron { - -namespace api { +namespace electron::api { WebContentsView::WebContentsView(v8::Isolate* isolate, gin::Handle web_contents) @@ -105,9 +103,7 @@ void WebContentsView::BuildPrototype( .SetProperty("webContents", &WebContentsView::GetWebContents); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/electron_api_web_contents_view.h b/shell/browser/api/electron_api_web_contents_view.h index d1f39ff26ef5d..057e31ec18b8d 100644 --- a/shell/browser/api/electron_api_web_contents_view.h +++ b/shell/browser/api/electron_api_web_contents_view.h @@ -12,9 +12,7 @@ namespace gin_helper { class Dictionary; } -namespace electron { - -namespace api { +namespace electron::api { class WebContents; @@ -53,8 +51,6 @@ class WebContentsView : public View, public content::WebContentsObserver { api::WebContents* api_web_contents_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_WEB_CONTENTS_VIEW_H_ diff --git a/shell/browser/api/electron_api_web_frame_main.cc b/shell/browser/api/electron_api_web_frame_main.cc index e7ba32a33f782..0c92c632f3909 100644 --- a/shell/browser/api/electron_api_web_frame_main.cc +++ b/shell/browser/api/electron_api_web_frame_main.cc @@ -11,8 +11,9 @@ #include "base/logging.h" #include "base/no_destructor.h" -#include "content/browser/renderer_host/frame_tree_node.h" // nogncheck +#include "content/browser/renderer_host/render_frame_host_impl.h" // nogncheck #include "content/public/browser/render_frame_host.h" +#include "content/public/common/isolated_world_ids.h" #include "electron/shell/common/api/api.mojom.h" #include "gin/object_template_builder.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -52,9 +53,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { typedef std::unordered_map WebFrameMainIdMap; @@ -96,19 +95,20 @@ void WebFrameMain::Destroyed() { void WebFrameMain::MarkRenderFrameDisposed() { render_frame_ = nullptr; render_frame_disposed_ = true; + TeardownMojoConnection(); } void WebFrameMain::UpdateRenderFrameHost(content::RenderFrameHost* rfh) { // Should only be called when swapping frames. render_frame_disposed_ = false; render_frame_ = rfh; - renderer_api_.reset(); + TeardownMojoConnection(); + MaybeSetupMojoConnection(); } bool WebFrameMain::CheckRenderFrame() const { if (render_frame_disposed_) { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope scope(isolate); gin_helper::ErrorThrower(isolate).ThrowError( "Render frame was disposed before WebFrameMain could be accessed"); @@ -142,17 +142,24 @@ v8::Local WebFrameMain::ExecuteJavaScript( return handle; } - if (user_gesture) { - auto* ftn = content::FrameTreeNode::From(render_frame_); - ftn->UpdateUserActivationState( - blink::mojom::UserActivationUpdateType::kNotifyActivation, - blink::mojom::UserActivationNotificationType::kTest); - } - - render_frame_->ExecuteJavaScriptForTests( - code, base::BindOnce([](gin_helper::Promise promise, - base::Value value) { promise.Resolve(value); }, - std::move(promise))); + static_cast(render_frame_) + ->ExecuteJavaScriptForTests( + code, user_gesture, true /* resolve_promises */, + content::ISOLATED_WORLD_ID_GLOBAL, + base::BindOnce( + [](gin_helper::Promise promise, + blink::mojom::JavaScriptExecutionResultType type, + base::Value value) { + if (type == + blink::mojom::JavaScriptExecutionResultType::kSuccess) { + promise.Resolve(value); + } else { + v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); + v8::HandleScope scope(isolate); + promise.Reject(gin::ConvertToV8(isolate, value)); + } + }, + std::move(promise))); return handle; } @@ -182,20 +189,42 @@ void WebFrameMain::Send(v8::Isolate* isolate, } const mojo::Remote& WebFrameMain::GetRendererApi() { + MaybeSetupMojoConnection(); + return renderer_api_; +} + +void WebFrameMain::MaybeSetupMojoConnection() { + if (render_frame_disposed_) { + // RFH may not be set yet if called between when a new RFH is created and + // before it's been swapped with an old RFH. + LOG(INFO) << "Attempt to setup WebFrameMain connection while render frame " + "is disposed"; + return; + } + if (!renderer_api_) { pending_receiver_ = renderer_api_.BindNewPipeAndPassReceiver(); - if (render_frame_->IsRenderFrameCreated()) { - render_frame_->GetRemoteInterfaces()->GetInterface( - std::move(pending_receiver_)); - } renderer_api_.set_disconnect_handler(base::BindOnce( &WebFrameMain::OnRendererConnectionError, weak_factory_.GetWeakPtr())); } - return renderer_api_; + + DCHECK(render_frame_); + + // Wait for RenderFrame to be created in renderer before accessing remote. + if (pending_receiver_ && render_frame_ && + render_frame_->IsRenderFrameLive()) { + render_frame_->GetRemoteInterfaces()->GetInterface( + std::move(pending_receiver_)); + } } -void WebFrameMain::OnRendererConnectionError() { +void WebFrameMain::TeardownMojoConnection() { renderer_api_.reset(); + pending_receiver_.reset(); +} + +void WebFrameMain::OnRendererConnectionError() { + TeardownMojoConnection(); } void WebFrameMain::PostMessage(v8::Isolate* isolate, @@ -267,6 +296,12 @@ GURL WebFrameMain::URL() const { return render_frame_->GetLastCommittedURL(); } +std::string WebFrameMain::Origin() const { + if (!CheckRenderFrame()) + return std::string(); + return render_frame_->GetLastCommittedOrigin().Serialize(); +} + blink::mojom::PageVisibilityState WebFrameMain::VisibilityState() const { if (!CheckRenderFrame()) return blink::mojom::PageVisibilityState::kHidden; @@ -315,13 +350,6 @@ std::vector WebFrameMain::FramesInSubtree() const { return frame_hosts; } -void WebFrameMain::Connect() { - if (pending_receiver_) { - render_frame_->GetRemoteInterfaces()->GetInterface( - std::move(pending_receiver_)); - } -} - void WebFrameMain::DOMContentLoaded() { Emit("dom-ready"); } @@ -348,6 +376,18 @@ gin::Handle WebFrameMain::From(v8::Isolate* isolate, return handle; } +// static +gin::Handle WebFrameMain::FromOrNull( + v8::Isolate* isolate, + content::RenderFrameHost* rfh) { + if (rfh == nullptr) + return gin::Handle(); + auto* web_frame = FromRenderFrameHost(rfh); + if (web_frame) + return gin::CreateHandle(isolate, web_frame); + return gin::Handle(); +} + // static v8::Local WebFrameMain::FillObjectTemplate( v8::Isolate* isolate, @@ -363,6 +403,7 @@ v8::Local WebFrameMain::FillObjectTemplate( .SetProperty("processId", &WebFrameMain::ProcessID) .SetProperty("routingId", &WebFrameMain::RoutingID) .SetProperty("url", &WebFrameMain::URL) + .SetProperty("origin", &WebFrameMain::Origin) .SetProperty("visibilityState", &WebFrameMain::VisibilityState) .SetProperty("top", &WebFrameMain::Top) .SetProperty("parent", &WebFrameMain::Parent) @@ -375,9 +416,7 @@ const char* WebFrameMain::GetTypeName() { return "WebFrameMain"; } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { @@ -397,6 +436,20 @@ v8::Local FromID(gin_helper::ErrorThrower thrower, return WebFrameMain::From(thrower.isolate(), rfh).ToV8(); } +v8::Local FromIDOrNull(gin_helper::ErrorThrower thrower, + int render_process_id, + int render_frame_id) { + if (!electron::Browser::Get()->is_ready()) { + thrower.ThrowError("WebFrameMain is available only after app ready"); + return v8::Null(thrower.isolate()); + } + + auto* rfh = + content::RenderFrameHost::FromID(render_process_id, render_frame_id); + + return WebFrameMain::FromOrNull(thrower.isolate(), rfh).ToV8(); +} + void Initialize(v8::Local exports, v8::Local unused, v8::Local context, @@ -405,6 +458,7 @@ void Initialize(v8::Local exports, gin_helper::Dictionary dict(isolate, exports); dict.Set("WebFrameMain", WebFrameMain::GetConstructor(context)); dict.SetMethod("fromId", &FromID); + dict.SetMethod("fromIdOrNull", &FromIDOrNull); } } // namespace diff --git a/shell/browser/api/electron_api_web_frame_main.h b/shell/browser/api/electron_api_web_frame_main.h index 23a3b657fd45c..32e5e351d505d 100644 --- a/shell/browser/api/electron_api_web_frame_main.h +++ b/shell/browser/api/electron_api_web_frame_main.h @@ -28,9 +28,7 @@ namespace gin { class Arguments; } -namespace electron { - -namespace api { +namespace electron::api { class WebContents; @@ -46,6 +44,9 @@ class WebFrameMain : public gin::Wrappable, static gin::Handle From( v8::Isolate* isolate, content::RenderFrameHost* render_frame_host); + static gin::Handle FromOrNull( + v8::Isolate* isolate, + content::RenderFrameHost* render_frame_host); static WebFrameMain* FromFrameTreeNodeId(int frame_tree_node_id); static WebFrameMain* FromRenderFrameHost( content::RenderFrameHost* render_frame_host); @@ -82,6 +83,9 @@ class WebFrameMain : public gin::Wrappable, void UpdateRenderFrameHost(content::RenderFrameHost* rfh); const mojo::Remote& GetRendererApi(); + void MaybeSetupMojoConnection(); + void TeardownMojoConnection(); + void OnRendererConnectionError(); // WebFrameMain can outlive its RenderFrameHost pointer so we need to check // whether its been disposed of prior to accessing it. @@ -105,6 +109,7 @@ class WebFrameMain : public gin::Wrappable, int ProcessID() const; int RoutingID() const; GURL URL() const; + std::string Origin() const; blink::mojom::PageVisibilityState VisibilityState() const; content::RenderFrameHost* Top() const; @@ -112,8 +117,6 @@ class WebFrameMain : public gin::Wrappable, std::vector Frames() const; std::vector FramesInSubtree() const; - void OnRendererConnectionError(); - void Connect(); void DOMContentLoaded(); mojo::Remote renderer_api_; @@ -130,8 +133,6 @@ class WebFrameMain : public gin::Wrappable, base::WeakPtrFactory weak_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_WEB_FRAME_MAIN_H_ diff --git a/shell/browser/api/electron_api_web_request.cc b/shell/browser/api/electron_api_web_request.cc index b8b5e05a96a6c..7189168db0268 100644 --- a/shell/browser/api/electron_api_web_request.cc +++ b/shell/browser/api/electron_api_web_request.cc @@ -81,9 +81,7 @@ struct Converter { } // namespace gin -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -115,13 +113,12 @@ bool MatchesFilterCondition(extensions::WebRequestInfo* info, // to pass the original keys. v8::Local HttpResponseHeadersToV8( net::HttpResponseHeaders* headers) { - base::DictionaryValue response_headers; + base::Value::Dict response_headers; if (headers) { size_t iter = 0; std::string key; std::string value; while (headers->EnumerateHeaderLines(&iter, &key, &value)) { - base::Value* values = response_headers.FindListKey(key); // Note that Web servers not developed with nodejs allow non-utf8 // characters in content-disposition's filename field. Use Chromium's // HttpContentDisposition class to decode the correct encoding instead of @@ -138,12 +135,14 @@ v8::Local HttpResponseHeadersToV8( std::string filename = "\"" + header.filename() + "\""; value = decodedFilename + "; filename=" + filename; } + base::Value::List* values = response_headers.FindList(key); if (!values) - values = response_headers.SetKey(key, base::ListValue()); - values->Append(value); + values = &response_headers.Set(key, base::Value::List())->GetList(); + values->Append(base::Value(value)); } } - return gin::ConvertToV8(v8::Isolate::GetCurrent(), response_headers); + return gin::ConvertToV8(v8::Isolate::GetCurrent(), + base::Value(std::move(response_headers))); } // Overloaded by multiple types to fill the |details| object. @@ -164,8 +163,8 @@ void ToDictionary(gin_helper::Dictionary* details, HttpResponseHeadersToV8(info->response_headers.get())); } - auto* render_frame_host = - content::RenderFrameHost::FromID(info->render_process_id, info->frame_id); + auto* render_frame_host = content::RenderFrameHost::FromID( + info->render_process_id, info->frame_routing_id); if (render_frame_host) { details->SetGetter("frame", render_frame_host); auto* web_contents = @@ -550,6 +549,4 @@ gin::Handle WebRequest::From( return gin::CreateHandle(isolate, user_data->data); } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/electron_api_web_request.h b/shell/browser/api/electron_api_web_request.h index fb8bee6a3c6ed..10575efafc2c3 100644 --- a/shell/browser/api/electron_api_web_request.h +++ b/shell/browser/api/electron_api_web_request.h @@ -19,9 +19,7 @@ namespace content { class BrowserContext; } -namespace electron { - -namespace api { +namespace electron::api { class WebRequest : public gin::Wrappable, public WebRequestAPI { public: @@ -151,8 +149,6 @@ class WebRequest : public gin::Wrappable, public WebRequestAPI { content::BrowserContext* browser_context_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_WEB_REQUEST_H_ diff --git a/shell/browser/api/electron_api_web_view_manager.cc b/shell/browser/api/electron_api_web_view_manager.cc index 7758c59cd5fd6..2bf03616b711c 100644 --- a/shell/browser/api/electron_api_web_view_manager.cc +++ b/shell/browser/api/electron_api_web_view_manager.cc @@ -28,10 +28,6 @@ void AddGuest(int guest_instance_id, electron::WebContentsZoomController::FromWebContents(guest_web_contents) ->SetDefaultZoomFactor(zoom_factor); } - - WebContentsPreferences::From(guest_web_contents)->Merge(options); - // Trigger re-calculation of webkit prefs. - guest_web_contents->NotifyPreferencesChanged(); } void RemoveGuest(content::WebContents* embedder, int guest_instance_id) { diff --git a/shell/browser/api/event.h b/shell/browser/api/event.h index a9e4dec39e9d8..763d684c72158 100644 --- a/shell/browser/api/event.h +++ b/shell/browser/api/event.h @@ -43,7 +43,7 @@ class Event : public gin::Wrappable { const char* GetTypeName() override; private: - // Replyer for the synchronous messages. + // Replier for the synchronous messages. InvokeCallback callback_; }; diff --git a/shell/browser/api/frame_subscriber.cc b/shell/browser/api/frame_subscriber.cc index 1718525f27abe..a3a42a72e58da 100644 --- a/shell/browser/api/frame_subscriber.cc +++ b/shell/browser/api/frame_subscriber.cc @@ -17,9 +17,7 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/skbitmap_operations.h" -namespace electron { - -namespace api { +namespace electron::api { constexpr static int kMaxFrameRate = 30; @@ -145,6 +143,8 @@ void FrameSubscriber::OnFrameCaptured( Done(content_rect, bitmap); } +void FrameSubscriber::OnNewCropVersion(uint32_t crop_version) {} + void FrameSubscriber::OnFrameWithEmptyRegionCapture() {} void FrameSubscriber::OnStopped() {} @@ -180,6 +180,4 @@ gfx::Size FrameSubscriber::GetRenderViewSize() const { gfx::ScaleSize(gfx::SizeF(size), view->GetDeviceScaleFactor())); } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/frame_subscriber.h b/shell/browser/api/frame_subscriber.h index 0a6a003927622..a8d86cb0a3794 100644 --- a/shell/browser/api/frame_subscriber.h +++ b/shell/browser/api/frame_subscriber.h @@ -22,9 +22,7 @@ class Image; class Rect; } // namespace gfx -namespace electron { - -namespace api { +namespace electron::api { class WebContents; @@ -59,6 +57,7 @@ class FrameSubscriber : public content::WebContentsObserver, const gfx::Rect& content_rect, mojo::PendingRemote callbacks) override; + void OnNewCropVersion(uint32_t crop_version) override; void OnFrameWithEmptyRegionCapture() override; void OnStopped() override; void OnLog(const std::string& message) override; @@ -77,8 +76,6 @@ class FrameSubscriber : public content::WebContentsObserver, base::WeakPtrFactory weak_ptr_factory_{this}; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_FRAME_SUBSCRIBER_H_ diff --git a/shell/browser/api/gpu_info_enumerator.cc b/shell/browser/api/gpu_info_enumerator.cc index 75b330a3264fc..57c3448068aa4 100644 --- a/shell/browser/api/gpu_info_enumerator.cc +++ b/shell/browser/api/gpu_info_enumerator.cc @@ -8,127 +8,125 @@ namespace electron { -GPUInfoEnumerator::GPUInfoEnumerator() - : value_stack(), current(std::make_unique()) {} +GPUInfoEnumerator::GPUInfoEnumerator() : value_stack_(), current_{} {} GPUInfoEnumerator::~GPUInfoEnumerator() = default; void GPUInfoEnumerator::AddInt64(const char* name, int64_t value) { - current->SetInteger(name, value); + // NOTE(nornagon): this loses precision. base::Value can't store int64_t. + current_.Set(name, static_cast(value)); } void GPUInfoEnumerator::AddInt(const char* name, int value) { - current->SetInteger(name, value); + current_.Set(name, value); } void GPUInfoEnumerator::AddString(const char* name, const std::string& value) { if (!value.empty()) - current->SetString(name, value); + current_.Set(name, value); } void GPUInfoEnumerator::AddBool(const char* name, bool value) { - current->SetBoolean(name, value); + current_.Set(name, value); } void GPUInfoEnumerator::AddTimeDeltaInSecondsF(const char* name, const base::TimeDelta& value) { - current->SetInteger(name, value.InMilliseconds()); + current_.Set(name, value.InMillisecondsF()); } void GPUInfoEnumerator::AddBinary(const char* name, const base::span& value) { - current->Set(name, std::make_unique(value)); + current_.Set(name, base::Value(value)); } void GPUInfoEnumerator::BeginGPUDevice() { - value_stack.push(std::move(current)); - current = std::make_unique(); + value_stack_.push(std::move(current_)); + current_ = {}; } void GPUInfoEnumerator::EndGPUDevice() { - auto& top_value = value_stack.top(); + auto& top_value = value_stack_.top(); // GPUDevice can be more than one. So create a list of all. // The first one is the active GPU device. - if (top_value->HasKey(kGPUDeviceKey)) { - base::ListValue* list; - top_value->GetList(kGPUDeviceKey, &list); - list->Append(std::move(current)); + if (base::Value* list_value = top_value.Find(kGPUDeviceKey)) { + DCHECK(list_value->is_list()); + base::Value::List& list = list_value->GetList(); + list.Append(std::move(current_)); } else { - auto gpus = std::make_unique(); - gpus->Append(std::move(current)); - top_value->SetList(kGPUDeviceKey, std::move(gpus)); + base::Value::List gpus; + gpus.Append(std::move(current_)); + top_value.Set(kGPUDeviceKey, std::move(gpus)); } - current = std::move(top_value); - value_stack.pop(); + current_ = std::move(top_value); + value_stack_.pop(); } void GPUInfoEnumerator::BeginVideoDecodeAcceleratorSupportedProfile() { - value_stack.push(std::move(current)); - current = std::make_unique(); + value_stack_.push(std::move(current_)); + current_ = {}; } void GPUInfoEnumerator::EndVideoDecodeAcceleratorSupportedProfile() { - auto& top_value = value_stack.top(); - top_value->SetKey(kVideoDecodeAcceleratorSupportedProfileKey, - base::Value::FromUniquePtrValue(std::move(current))); - current = std::move(top_value); - value_stack.pop(); + auto& top_value = value_stack_.top(); + top_value.Set(kVideoDecodeAcceleratorSupportedProfileKey, + std::move(current_)); + current_ = std::move(top_value); + value_stack_.pop(); } void GPUInfoEnumerator::BeginVideoEncodeAcceleratorSupportedProfile() { - value_stack.push(std::move(current)); - current = std::make_unique(); + value_stack_.push(std::move(current_)); + current_ = {}; } void GPUInfoEnumerator::EndVideoEncodeAcceleratorSupportedProfile() { - auto& top_value = value_stack.top(); - top_value->SetKey(kVideoEncodeAcceleratorSupportedProfileKey, - base::Value::FromUniquePtrValue(std::move(current))); - current = std::move(top_value); - value_stack.pop(); + auto& top_value = value_stack_.top(); + top_value.Set(kVideoEncodeAcceleratorSupportedProfileKey, + std::move(current_)); + current_ = std::move(top_value); + value_stack_.pop(); } void GPUInfoEnumerator::BeginImageDecodeAcceleratorSupportedProfile() { - value_stack.push(std::move(current)); - current = std::make_unique(); + value_stack_.push(std::move(current_)); + current_ = {}; } void GPUInfoEnumerator::EndImageDecodeAcceleratorSupportedProfile() { - auto& top_value = value_stack.top(); - top_value->SetKey(kImageDecodeAcceleratorSupportedProfileKey, - base::Value::FromUniquePtrValue(std::move(current))); - current = std::move(top_value); - value_stack.pop(); + auto& top_value = value_stack_.top(); + top_value.Set(kImageDecodeAcceleratorSupportedProfileKey, + std::move(current_)); + current_ = std::move(top_value); + value_stack_.pop(); } void GPUInfoEnumerator::BeginAuxAttributes() { - value_stack.push(std::move(current)); - current = std::make_unique(); + value_stack_.push(std::move(current_)); + current_ = {}; } void GPUInfoEnumerator::EndAuxAttributes() { - auto& top_value = value_stack.top(); - top_value->SetKey(kAuxAttributesKey, - base::Value::FromUniquePtrValue(std::move(current))); - current = std::move(top_value); - value_stack.pop(); + auto& top_value = value_stack_.top(); + top_value.Set(kAuxAttributesKey, std::move(current_)); + current_ = std::move(top_value); + value_stack_.pop(); } void GPUInfoEnumerator::BeginOverlayInfo() { - value_stack.push(std::move(current)); - current = std::make_unique(); + value_stack_.push(std::move(current_)); + current_ = {}; } void GPUInfoEnumerator::EndOverlayInfo() { - auto& top_value = value_stack.top(); - top_value->SetKey(kOverlayInfo, - base::Value::FromUniquePtrValue(std::move(current))); - current = std::move(top_value); - value_stack.pop(); + auto& top_value = value_stack_.top(); + top_value.Set(kOverlayInfo, std::move(current_)); + current_ = std::move(top_value); + value_stack_.pop(); } -std::unique_ptr GPUInfoEnumerator::GetDictionary() { - return std::move(current); +base::Value::Dict GPUInfoEnumerator::GetDictionary() { + return std::move(current_); } } // namespace electron diff --git a/shell/browser/api/gpu_info_enumerator.h b/shell/browser/api/gpu_info_enumerator.h index 389aa9d604d48..bd1af0799cec4 100644 --- a/shell/browser/api/gpu_info_enumerator.h +++ b/shell/browser/api/gpu_info_enumerator.h @@ -50,12 +50,12 @@ class GPUInfoEnumerator final : public gpu::GPUInfo::Enumerator { void EndAuxAttributes() override; void BeginOverlayInfo() override; void EndOverlayInfo() override; - std::unique_ptr GetDictionary(); + base::Value::Dict GetDictionary(); private: // The stack is used to manage nested values - std::stack> value_stack; - std::unique_ptr current; + std::stack value_stack_; + base::Value::Dict current_; }; } // namespace electron diff --git a/shell/browser/api/gpuinfo_manager.cc b/shell/browser/api/gpuinfo_manager.cc index d797d0ec4a6da..e4bcf0dcad0ce 100644 --- a/shell/browser/api/gpuinfo_manager.cc +++ b/shell/browser/api/gpuinfo_manager.cc @@ -41,11 +41,11 @@ bool GPUInfoManager::NeedsCompleteGpuInfoCollection() const { // Should be posted to the task runner void GPUInfoManager::ProcessCompleteInfo() { - const auto result = EnumerateGPUInfo(gpu_data_manager_->GetGPUInfo()); + base::Value::Dict result = EnumerateGPUInfo(gpu_data_manager_->GetGPUInfo()); // We have received the complete information, resolve all promises that // were waiting for this info. for (auto& promise : complete_info_promise_set_) { - promise.Resolve(*result); + promise.Resolve(base::Value(result.Clone())); } complete_info_promise_set_.clear(); } @@ -61,7 +61,7 @@ void GPUInfoManager::OnGpuInfoUpdate() { // Should be posted to the task runner void GPUInfoManager::CompleteInfoFetcher( - gin_helper::Promise promise) { + gin_helper::Promise promise) { complete_info_promise_set_.emplace_back(std::move(promise)); if (NeedsCompleteGpuInfoCollection()) { @@ -73,7 +73,7 @@ void GPUInfoManager::CompleteInfoFetcher( } void GPUInfoManager::FetchCompleteInfo( - gin_helper::Promise promise) { + gin_helper::Promise promise) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&GPUInfoManager::CompleteInfoFetcher, base::Unretained(this), std::move(promise))); @@ -81,14 +81,13 @@ void GPUInfoManager::FetchCompleteInfo( // This fetches the info synchronously, so no need to post to the task queue. // There cannot be multiple promises as they are resolved synchronously. -void GPUInfoManager::FetchBasicInfo( - gin_helper::Promise promise) { +void GPUInfoManager::FetchBasicInfo(gin_helper::Promise promise) { gpu::GPUInfo gpu_info; CollectBasicGraphicsInfo(&gpu_info); - promise.Resolve(*EnumerateGPUInfo(gpu_info)); + promise.Resolve(base::Value(EnumerateGPUInfo(gpu_info))); } -std::unique_ptr GPUInfoManager::EnumerateGPUInfo( +base::Value::Dict GPUInfoManager::EnumerateGPUInfo( gpu::GPUInfo gpu_info) const { GPUInfoEnumerator enumerator; gpu_info.EnumerateFields(&enumerator); diff --git a/shell/browser/api/gpuinfo_manager.h b/shell/browser/api/gpuinfo_manager.h index 43357ececc22b..8b134e50bf97c 100644 --- a/shell/browser/api/gpuinfo_manager.h +++ b/shell/browser/api/gpuinfo_manager.h @@ -28,22 +28,20 @@ class GPUInfoManager : public content::GpuDataManagerObserver { GPUInfoManager& operator=(const GPUInfoManager&) = delete; bool NeedsCompleteGpuInfoCollection() const; - void FetchCompleteInfo(gin_helper::Promise promise); - void FetchBasicInfo(gin_helper::Promise promise); + void FetchCompleteInfo(gin_helper::Promise promise); + void FetchBasicInfo(gin_helper::Promise promise); void OnGpuInfoUpdate() override; private: - std::unique_ptr EnumerateGPUInfo( - gpu::GPUInfo gpu_info) const; + base::Value::Dict EnumerateGPUInfo(gpu::GPUInfo gpu_info) const; // These should be posted to the task queue - void CompleteInfoFetcher(gin_helper::Promise promise); + void CompleteInfoFetcher(gin_helper::Promise promise); void ProcessCompleteInfo(); // This set maintains all the promises that should be fulfilled // once we have the complete information data - std::vector> - complete_info_promise_set_; + std::vector> complete_info_promise_set_; content::GpuDataManagerImpl* gpu_data_manager_; }; diff --git a/shell/browser/api/save_page_handler.cc b/shell/browser/api/save_page_handler.cc index 5d45341192773..e6c451e3288b7 100644 --- a/shell/browser/api/save_page_handler.cc +++ b/shell/browser/api/save_page_handler.cc @@ -11,9 +11,7 @@ #include "content/public/browser/web_contents.h" #include "shell/browser/electron_browser_context.h" -namespace electron { - -namespace api { +namespace electron::api { SavePageHandler::SavePageHandler(content::WebContents* web_contents, gin_helper::Promise promise) @@ -65,6 +63,4 @@ void SavePageHandler::Destroy(download::DownloadItem* item) { delete this; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/save_page_handler.h b/shell/browser/api/save_page_handler.h index 00202a0d5a3f8..d7468ed1a6ded 100644 --- a/shell/browser/api/save_page_handler.h +++ b/shell/browser/api/save_page_handler.h @@ -19,9 +19,7 @@ namespace content { class WebContents; } -namespace electron { - -namespace api { +namespace electron::api { // A self-destroyed class for handling save page request. class SavePageHandler : public content::DownloadManager::Observer, @@ -48,8 +46,6 @@ class SavePageHandler : public content::DownloadManager::Observer, gin_helper::Promise promise_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_SAVE_PAGE_HANDLER_H_ diff --git a/shell/browser/api/ui_event.cc b/shell/browser/api/ui_event.cc index 5721db147010e..bb39b32657faf 100644 --- a/shell/browser/api/ui_event.cc +++ b/shell/browser/api/ui_event.cc @@ -9,8 +9,7 @@ #include "ui/events/event_constants.h" #include "v8/include/v8.h" -namespace electron { -namespace api { +namespace electron::api { constexpr int mouse_button_flags = (ui::EF_RIGHT_MOUSE_BUTTON | ui::EF_LEFT_MOUSE_BUTTON | @@ -29,5 +28,4 @@ v8::Local CreateEventFromFlags(int flags) { .Build(); } -} // namespace api -} // namespace electron +} // namespace electron::api diff --git a/shell/browser/api/ui_event.h b/shell/browser/api/ui_event.h index 0f0ca1eb8397c..11c8fb1a6b210 100644 --- a/shell/browser/api/ui_event.h +++ b/shell/browser/api/ui_event.h @@ -11,12 +11,10 @@ template class Local; } // namespace v8 -namespace electron { -namespace api { +namespace electron::api { v8::Local CreateEventFromFlags(int flags); -} // namespace api -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_UI_EVENT_H_ diff --git a/shell/browser/api/views/electron_api_image_view.cc b/shell/browser/api/views/electron_api_image_view.cc index 3e26fa70d17cf..1841f2007cbd4 100644 --- a/shell/browser/api/views/electron_api_image_view.cc +++ b/shell/browser/api/views/electron_api_image_view.cc @@ -10,9 +10,7 @@ #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" -namespace electron { - -namespace api { +namespace electron::api { ImageView::ImageView() : View(new views::ImageView()) { view()->set_owned_by_client(); @@ -40,9 +38,7 @@ void ImageView::BuildPrototype(v8::Isolate* isolate, .SetMethod("setImage", &ImageView::SetImage); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/browser/api/views/electron_api_image_view.h b/shell/browser/api/views/electron_api_image_view.h index 332caa21b23b5..58c3c2f28e55e 100644 --- a/shell/browser/api/views/electron_api_image_view.h +++ b/shell/browser/api/views/electron_api_image_view.h @@ -10,9 +10,7 @@ #include "ui/gfx/image/image.h" #include "ui/views/controls/image_view.h" -namespace electron { - -namespace api { +namespace electron::api { class ImageView : public View { public: @@ -32,8 +30,6 @@ class ImageView : public View { } }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_BROWSER_API_VIEWS_ELECTRON_API_IMAGE_VIEW_H_ diff --git a/shell/browser/auto_updater_mac.mm b/shell/browser/auto_updater_mac.mm index 3dbf49e2da8a9..c9e4542ffdfba 100644 --- a/shell/browser/auto_updater_mac.mm +++ b/shell/browser/auto_updater_mac.mm @@ -24,7 +24,7 @@ namespace { -// The gloal SQRLUpdater object. +// The global SQRLUpdater object. SQRLUpdater* g_updater = nil; } // namespace diff --git a/shell/browser/bluetooth/electron_bluetooth_delegate.cc b/shell/browser/bluetooth/electron_bluetooth_delegate.cc index d25b4bd535d67..6cfc775041553 100644 --- a/shell/browser/bluetooth/electron_bluetooth_delegate.cc +++ b/shell/browser/bluetooth/electron_bluetooth_delegate.cc @@ -7,6 +7,7 @@ #include #include +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "content/public/browser/render_frame_host.h" @@ -14,7 +15,10 @@ #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/public/cpp/bluetooth_uuid.h" #include "shell/browser/api/electron_api_web_contents.h" +#include "shell/browser/electron_permission_manager.h" #include "shell/browser/lib/bluetooth_chooser.h" +#include "shell/common/gin_converters/frame_converter.h" +#include "shell/common/gin_helper/dictionary.h" #include "third_party/blink/public/common/bluetooth/web_bluetooth_device_id.h" #include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h" @@ -23,6 +27,28 @@ using content::RenderFrameHost; using content::WebContents; using device::BluetoothUUID; +namespace gin { + +template <> +struct Converter { + static v8::Local ToV8( + v8::Isolate* isolate, + content::BluetoothDelegate::PairingKind pairing_kind) { + switch (pairing_kind) { + case content::BluetoothDelegate::PairingKind::kConfirmOnly: + return StringToV8(isolate, "confirm"); + case content::BluetoothDelegate::PairingKind::kConfirmPinMatch: + return StringToV8(isolate, "confirmPin"); + case content::BluetoothDelegate::PairingKind::kProvidePin: + return StringToV8(isolate, "providePin"); + default: + return StringToV8(isolate, "unknown"); + } + } +}; + +} // namespace gin + namespace electron { ElectronBluetoothDelegate::ElectronBluetoothDelegate() = default; @@ -47,14 +73,6 @@ ElectronBluetoothDelegate::ShowBluetoothScanningPrompt( return nullptr; } -void ElectronBluetoothDelegate::ShowDeviceCredentialsPrompt( - content::RenderFrameHost* frame, - const std::u16string& device_identifier, - CredentialsCallback callback) { - // TODO(jkleinsc) implement this - std::move(callback).Run(DeviceCredentialsPromptResult::kCancelled, u""); -} - WebBluetoothDeviceId ElectronBluetoothDelegate::GetWebBluetoothDeviceId( RenderFrameHost* frame, const std::string& device_address) { @@ -91,6 +109,12 @@ bool ElectronBluetoothDelegate::HasDevicePermission( return true; } +void ElectronBluetoothDelegate::RevokeDevicePermissionWebInitiated( + RenderFrameHost* frame, + const WebBluetoothDeviceId& device_id) { + NOTIMPLEMENTED(); +} + bool ElectronBluetoothDelegate::IsAllowedToAccessService( RenderFrameHost* frame, const WebBluetoothDeviceId& device_id, @@ -132,4 +156,52 @@ ElectronBluetoothDelegate::GetPermittedDevices( return permitted_devices; } +void ElectronBluetoothDelegate::ShowDevicePairPrompt( + content::RenderFrameHost* frame, + const std::u16string& device_identifier, + PairPromptCallback callback, + PairingKind pairing_kind, + const absl::optional& pin) { + auto* web_contents = content::WebContents::FromRenderFrameHost(frame); + if (web_contents) { + auto* permission_manager = static_cast( + web_contents->GetBrowserContext()->GetPermissionControllerDelegate()); + + v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); + v8::HandleScope scope(isolate); + gin_helper::Dictionary details = + gin_helper::Dictionary::CreateEmpty(isolate); + details.Set("deviceId", device_identifier); + details.Set("pairingKind", pairing_kind); + details.SetGetter("frame", frame); + if (pin.has_value()) { + details.Set("pin", pin.value()); + } + + permission_manager->CheckBluetoothDevicePair( + details, base::AdaptCallbackForRepeating(base::BindOnce( + &ElectronBluetoothDelegate::OnDevicePairPromptResponse, + weak_factory_.GetWeakPtr(), std::move(callback)))); + } +} + +void ElectronBluetoothDelegate::OnDevicePairPromptResponse( + PairPromptCallback callback, + base::Value::Dict response) { + BluetoothDelegate::PairPromptResult result; + if (response.FindBool("confirmed").value_or(false)) { + result.result_code = BluetoothDelegate::PairPromptStatus::kSuccess; + } else { + result.result_code = BluetoothDelegate::PairPromptStatus::kCancelled; + } + + const std::string* pin = response.FindString("pin"); + if (pin) { + std::u16string trimmed_input = base::UTF8ToUTF16(*pin); + base::TrimWhitespace(trimmed_input, base::TRIM_ALL, &trimmed_input); + result.pin = base::UTF16ToUTF8(trimmed_input); + } + std::move(callback).Run(result); +} + } // namespace electron diff --git a/shell/browser/bluetooth/electron_bluetooth_delegate.h b/shell/browser/bluetooth/electron_bluetooth_delegate.h index 897ce2f2d31fa..8328f45636ad3 100644 --- a/shell/browser/bluetooth/electron_bluetooth_delegate.h +++ b/shell/browser/bluetooth/electron_bluetooth_delegate.h @@ -9,6 +9,7 @@ #include #include +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/scoped_observation.h" #include "content/public/browser/bluetooth_delegate.h" @@ -52,9 +53,11 @@ class ElectronBluetoothDelegate : public content::BluetoothDelegate { content::RenderFrameHost* frame, const content::BluetoothScanningPrompt::EventHandler& event_handler) override; - void ShowDeviceCredentialsPrompt(content::RenderFrameHost* frame, - const std::u16string& device_identifier, - CredentialsCallback callback) override; + void ShowDevicePairPrompt(content::RenderFrameHost* frame, + const std::u16string& device_identifier, + PairPromptCallback callback, + PairingKind pairing_kind, + const absl::optional& pin) override; blink::WebBluetoothDeviceId GetWebBluetoothDeviceId( content::RenderFrameHost* frame, const std::string& device_address) override; @@ -71,6 +74,9 @@ class ElectronBluetoothDelegate : public content::BluetoothDelegate { bool HasDevicePermission( content::RenderFrameHost* frame, const blink::WebBluetoothDeviceId& device_id) override; + void RevokeDevicePermissionWebInitiated( + content::RenderFrameHost* frame, + const blink::WebBluetoothDeviceId& device_id) override; bool IsAllowedToAccessService(content::RenderFrameHost* frame, const blink::WebBluetoothDeviceId& device_id, const device::BluetoothUUID& service) override; @@ -86,6 +92,12 @@ class ElectronBluetoothDelegate : public content::BluetoothDelegate { void AddFramePermissionObserver(FramePermissionObserver* observer) override; void RemoveFramePermissionObserver( FramePermissionObserver* observer) override; + + private: + void OnDevicePairPromptResponse(PairPromptCallback callback, + base::Value::Dict response); + + base::WeakPtrFactory weak_factory_{this}; }; } // namespace electron diff --git a/shell/browser/browser.cc b/shell/browser/browser.cc index e94b1d65c229c..959b2cc3ec447 100644 --- a/shell/browser/browser.cc +++ b/shell/browser/browser.cc @@ -184,7 +184,7 @@ void Browser::WillFinishLaunching() { observer.OnWillFinishLaunching(); } -void Browser::DidFinishLaunching(base::DictionaryValue launch_info) { +void Browser::DidFinishLaunching(base::Value::Dict launch_info) { // Make sure the userData directory is created. base::ThreadRestrictions::ScopedAllowIO allow_io; base::FilePath user_data; @@ -196,7 +196,7 @@ void Browser::DidFinishLaunching(base::DictionaryValue launch_info) { ready_promise_->Resolve(); } for (BrowserObserver& observer : observers_) - observer.OnFinishLaunching(launch_info); + observer.OnFinishLaunching(launch_info.Clone()); } v8::Local Browser::WhenReady(v8::Isolate* isolate) { diff --git a/shell/browser/browser.h b/shell/browser/browser.h old mode 100755 new mode 100644 index 4a69bbd75dcb6..7fc47ef826dad --- a/shell/browser/browser.h +++ b/shell/browser/browser.h @@ -158,13 +158,14 @@ class Browser : public WindowListObserver { // Hide the application. void Hide(); + bool IsHidden(); // Show the application. void Show(); // Creates an activity and sets it as the one currently in use. void SetUserActivity(const std::string& type, - base::DictionaryValue user_info, + base::Value::Dict user_info, gin::Arguments* args); // Returns the type name of the current user activity. @@ -179,7 +180,7 @@ class Browser : public WindowListObserver { // Updates the current user activity void UpdateCurrentActivity(const std::string& type, - base::DictionaryValue user_info); + base::Value::Dict user_info); // Indicates that an user activity is about to be resumed. bool WillContinueUserActivity(const std::string& type); @@ -190,16 +191,16 @@ class Browser : public WindowListObserver { // Resumes an activity via hand-off. bool ContinueUserActivity(const std::string& type, - base::DictionaryValue user_info, - base::DictionaryValue details); + base::Value::Dict user_info, + base::Value::Dict details); // Indicates that an activity was continued on another device. void UserActivityWasContinued(const std::string& type, - base::DictionaryValue user_info); + base::Value::Dict user_info); // Gives an opportunity to update the Handoff payload. bool UpdateUserActivityState(const std::string& type, - base::DictionaryValue user_info); + base::Value::Dict user_info); // Bounce the dock icon. enum class BounceType{ @@ -230,7 +231,7 @@ class Browser : public WindowListObserver { #endif // BUILDFLAG(IS_MAC) void ShowAboutPanel(); - void SetAboutPanelOptions(base::DictionaryValue options); + void SetAboutPanelOptions(base::Value::Dict options); #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) void ShowEmojiPanel(); @@ -287,7 +288,7 @@ class Browser : public WindowListObserver { // Tell the application the loading has been done. void WillFinishLaunching(); - void DidFinishLaunching(base::DictionaryValue launch_info); + void DidFinishLaunching(base::Value::Dict launch_info); void OnAccessibilitySupportChanged(); diff --git a/shell/browser/browser_linux.cc b/shell/browser/browser_linux.cc index 8b38c9ca67bf7..d7b7b96dfac6e 100644 --- a/shell/browser/browser_linux.cc +++ b/shell/browser/browser_linux.cc @@ -224,8 +224,8 @@ void Browser::ShowAboutPanel() { gtk_widget_destroy(dialogWidget); } -void Browser::SetAboutPanelOptions(base::DictionaryValue options) { - about_panel_options_ = std::move(options); +void Browser::SetAboutPanelOptions(base::Value::Dict options) { + about_panel_options_ = base::Value(std::move(options)); } } // namespace electron diff --git a/shell/browser/browser_mac.mm b/shell/browser/browser_mac.mm index 357c6723e44ff..16e5c4cc22803 100644 --- a/shell/browser/browser_mac.mm +++ b/shell/browser/browser_mac.mm @@ -117,6 +117,10 @@ [[AtomApplication sharedApplication] hide:nil]; } +bool Browser::IsHidden() { + return [[AtomApplication sharedApplication] isHidden]; +} + void Browser::Show() { [[AtomApplication sharedApplication] unhide:nil]; } @@ -231,14 +235,14 @@ } void Browser::SetUserActivity(const std::string& type, - base::DictionaryValue user_info, + base::Value::Dict user_info, gin::Arguments* args) { std::string url_string; args->GetNext(&url_string); [[AtomApplication sharedApplication] setCurrentActivity:base::SysUTF8ToNSString(type) - withUserInfo:DictionaryValueToNSDictionary(user_info) + withUserInfo:DictionaryValueToNSDictionary(std::move(user_info)) withWebpageURL:net::NSURLWithGURL(GURL(url_string))]; } @@ -257,10 +261,11 @@ } void Browser::UpdateCurrentActivity(const std::string& type, - base::DictionaryValue user_info) { + base::Value::Dict user_info) { [[AtomApplication sharedApplication] updateCurrentActivity:base::SysUTF8ToNSString(type) - withUserInfo:DictionaryValueToNSDictionary(user_info)]; + withUserInfo:DictionaryValueToNSDictionary( + std::move(user_info))]; } bool Browser::WillContinueUserActivity(const std::string& type) { @@ -277,25 +282,27 @@ } bool Browser::ContinueUserActivity(const std::string& type, - base::DictionaryValue user_info, - base::DictionaryValue details) { + base::Value::Dict user_info, + base::Value::Dict details) { bool prevent_default = false; for (BrowserObserver& observer : observers_) - observer.OnContinueUserActivity(&prevent_default, type, user_info, details); + observer.OnContinueUserActivity(&prevent_default, type, user_info.Clone(), + details.Clone()); return prevent_default; } void Browser::UserActivityWasContinued(const std::string& type, - base::DictionaryValue user_info) { + base::Value::Dict user_info) { for (BrowserObserver& observer : observers_) - observer.OnUserActivityWasContinued(type, user_info); + observer.OnUserActivityWasContinued(type, user_info.Clone()); } bool Browser::UpdateUserActivityState(const std::string& type, - base::DictionaryValue user_info) { + base::Value::Dict user_info) { bool prevent_default = false; for (BrowserObserver& observer : observers_) - observer.OnUpdateUserActivityState(&prevent_default, type, user_info); + observer.OnUpdateUserActivityState(&prevent_default, type, + user_info.Clone()); return prevent_default; } @@ -314,37 +321,6 @@ return settings; } -void RemoveFromLoginItems() { -#pragma clang diagnostic push // https://crbug.com/1154377 -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - // logic to find the login item copied from GetLoginItemForApp in - // base/mac/mac_util.mm - base::ScopedCFTypeRef login_items( - LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL)); - if (!login_items.get()) { - LOG(ERROR) << "Couldn't get a Login Items list."; - return; - } - base::scoped_nsobject login_items_array( - base::mac::CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL))); - NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]]; - for (NSUInteger i = 0; i < [login_items_array count]; ++i) { - LSSharedFileListItemRef item = - reinterpret_cast(login_items_array[i]); - base::ScopedCFTypeRef error; - CFURLRef item_url_ref = - LSSharedFileListItemCopyResolvedURL(item, 0, error.InitializeInto()); - if (!error && item_url_ref) { - base::ScopedCFTypeRef item_url(item_url_ref); - if (CFEqual(item_url, url)) { - LSSharedFileListItemRemove(login_items, item); - return; - } - } - } -#pragma clang diagnostic pop -} - void Browser::SetLoginItemSettings(LoginItemSettings settings) { #if defined(MAS_BUILD) if (!platform_util::SetLoginItemEnabled(settings.open_at_login)) { @@ -354,7 +330,7 @@ void RemoveFromLoginItems() { if (settings.open_at_login) { base::mac::AddToLoginItems(settings.open_as_hidden); } else { - RemoveFromLoginItems(); + base::mac::RemoveFromLoginItems(); } #endif } @@ -394,10 +370,10 @@ void RemoveFromLoginItems() { void Browser::DockHide() { // Transforming application state from UIElement to Foreground is an - // asyncronous operation, and unfortunately there is currently no way to know + // asynchronous operation, and unfortunately there is currently no way to know // when it is finished. // So if we call DockHide => DockShow => DockHide => DockShow in a very short - // time, we would triger a bug of macOS that, there would be multiple dock + // time, we would trigger a bug of macOS that, there would be multiple dock // icons of the app left in system. // To work around this, we make sure DockHide does nothing if it is called // immediately after DockShow. After some experiments, 1 second seems to be @@ -476,7 +452,8 @@ void RemoveFromLoginItems() { } void Browser::ShowAboutPanel() { - NSDictionary* options = DictionaryValueToNSDictionary(about_panel_options_); + NSDictionary* options = + DictionaryValueToNSDictionary(about_panel_options_.GetDict()); // Credits must be a NSAttributedString instead of NSString NSString* credits = (NSString*)options[@"Credits"]; @@ -498,11 +475,11 @@ void RemoveFromLoginItems() { orderFrontStandardAboutPanelWithOptions:options]; } -void Browser::SetAboutPanelOptions(base::DictionaryValue options) { +void Browser::SetAboutPanelOptions(base::Value::Dict options) { about_panel_options_.DictClear(); - for (const auto pair : options.DictItems()) { - std::string key = std::string(pair.first); + for (const auto pair : options) { + std::string key = pair.first; if (!key.empty() && pair.second.is_string()) { key[0] = base::ToUpperASCII(key[0]); auto val = std::make_unique(pair.second.Clone()); diff --git a/shell/browser/browser_observer.h b/shell/browser/browser_observer.h index 5b82aa50fac5b..16576a1e586a8 100644 --- a/shell/browser/browser_observer.h +++ b/shell/browser/browser_observer.h @@ -47,9 +47,9 @@ class BrowserObserver : public base::CheckedObserver { // The browser has finished loading. virtual void OnWillFinishLaunching() {} - virtual void OnFinishLaunching(const base::DictionaryValue& launch_info) {} + virtual void OnFinishLaunching(base::Value::Dict launch_info) {} - // The browser's accessibility suppport has changed. + // The browser's accessibility support has changed. virtual void OnAccessibilitySupportChanged() {} // The app message loop is ready @@ -70,17 +70,15 @@ class BrowserObserver : public base::CheckedObserver { // The browser wants to resume a user activity via handoff. (macOS only) virtual void OnContinueUserActivity(bool* prevent_default, const std::string& type, - const base::DictionaryValue& user_info, - const base::DictionaryValue& details) {} + base::Value::Dict user_info, + base::Value::Dict details) {} // The browser wants to notify that an user activity was resumed. (macOS only) - virtual void OnUserActivityWasContinued( - const std::string& type, - const base::DictionaryValue& user_info) {} + virtual void OnUserActivityWasContinued(const std::string& type, + base::Value::Dict user_info) {} // The browser wants to update an user activity payload. (macOS only) - virtual void OnUpdateUserActivityState( - bool* prevent_default, - const std::string& type, - const base::DictionaryValue& user_info) {} + virtual void OnUpdateUserActivityState(bool* prevent_default, + const std::string& type, + base::Value::Dict user_info) {} // User clicked the native macOS new tab button. (macOS only) virtual void OnNewWindowForTab() {} diff --git a/shell/browser/browser_process_impl.cc b/shell/browser/browser_process_impl.cc index 5f0bdc532ab6d..1d6fccb5e0b5c 100644 --- a/shell/browser/browser_process_impl.cc +++ b/shell/browser/browser_process_impl.cc @@ -110,7 +110,7 @@ void BrowserProcessImpl::PostEarlyInitialization() { // Only use a persistent prefs store when cookie encryption is enabled as that // is the only key that needs it base::FilePath prefs_path; - CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &prefs_path)); + CHECK(base::PathService::Get(electron::DIR_SESSION_DATA, &prefs_path)); prefs_path = prefs_path.Append(FILE_PATH_LITERAL("Local State")); base::ThreadRestrictions::ScopedAllowIO allow_io; scoped_refptr user_pref_store = @@ -293,6 +293,14 @@ HidPolicyAllowedDevices* BrowserProcessImpl::hid_policy_allowed_devices() { return nullptr; } +void BrowserProcessImpl::SetSystemLocale(const std::string& locale) { + system_locale_ = locale; +} + +const std::string& BrowserProcessImpl::GetSystemLocale() const { + return system_locale_; +} + void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) { locale_ = locale; } diff --git a/shell/browser/browser_process_impl.h b/shell/browser/browser_process_impl.h index 3a135cade0cbb..05bcd3f3ba3a0 100644 --- a/shell/browser/browser_process_impl.h +++ b/shell/browser/browser_process_impl.h @@ -49,6 +49,9 @@ class BrowserProcessImpl : public BrowserProcess { void PostDestroyThreads() {} void PostMainMessageLoopRun(); + void SetSystemLocale(const std::string& locale); + const std::string& GetSystemLocale() const; + void EndSession() override {} void FlushLocalStateAndReply(base::OnceClosure reply) override {} bool IsShuttingDown() override; @@ -110,6 +113,7 @@ class BrowserProcessImpl : public BrowserProcess { #endif std::unique_ptr local_state_; std::string locale_; + std::string system_locale_; }; #endif // ELECTRON_SHELL_BROWSER_BROWSER_PROCESS_IMPL_H_ diff --git a/shell/browser/browser_win.cc b/shell/browser/browser_win.cc index 56a62ac32548f..43364d65080ef 100644 --- a/shell/browser/browser_win.cc +++ b/shell/browser/browser_win.cc @@ -40,7 +40,9 @@ #include "shell/common/gin_helper/dictionary.h" #include "shell/common/skia_util.h" #include "skia/ext/legacy_display_globals.h" +#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkFont.h" +#include "third_party/skia/include/core/SkPaint.h" #include "ui/base/l10n/l10n_util.h" #include "ui/events/keycodes/keyboard_code_conversion_win.h" #include "ui/strings/grit/ui_strings.h" @@ -97,7 +99,7 @@ std::wstring GetAppInfoHelperForProtocol(ASSOCSTR assoc_str, const GURL& url) { return std::wstring(); wchar_t out_buffer[1024]; - DWORD buffer_size = base::size(out_buffer); + DWORD buffer_size = std::size(out_buffer); HRESULT hr = AssocQueryString(ASSOCF_IS_PROTOCOL, assoc_str, url_scheme.c_str(), NULL, out_buffer, &buffer_size); @@ -849,8 +851,8 @@ void Browser::ShowAboutPanel() { electron::ShowMessageBoxSync(settings); } -void Browser::SetAboutPanelOptions(base::DictionaryValue options) { - about_panel_options_ = std::move(options); +void Browser::SetAboutPanelOptions(base::Value::Dict options) { + about_panel_options_ = base::Value(std::move(options)); } } // namespace electron diff --git a/shell/browser/certificate_manager_model.cc b/shell/browser/certificate_manager_model.cc index e20503f20be4a..ea89a09b18901 100644 --- a/shell/browser/certificate_manager_model.cc +++ b/shell/browser/certificate_manager_model.cc @@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/logging.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -72,8 +71,8 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext( void CertificateManagerModel::Create(content::BrowserContext* browser_context, CreationCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - base::PostTask(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread, + content::GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread, browser_context->GetResourceContext(), std::move(callback))); } @@ -145,8 +144,8 @@ void CertificateManagerModel::DidGetCertDBOnIOThread( DCHECK_CURRENTLY_ON(BrowserThread::IO); bool is_user_db_available = !!cert_db->GetPublicSlot(); - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&CertificateManagerModel::DidGetCertDBOnUIThread, cert_db, is_user_db_available, std::move(callback))); } diff --git a/shell/browser/electron_autofill_driver.cc b/shell/browser/electron_autofill_driver.cc index 45b6aadd53ea7..951422d16d4f1 100644 --- a/shell/browser/electron_autofill_driver.cc +++ b/shell/browser/electron_autofill_driver.cc @@ -18,7 +18,7 @@ namespace electron { AutofillDriver::AutofillDriver(content::RenderFrameHost* render_frame_host) : render_frame_host_(render_frame_host) { autofill_popup_ = std::make_unique(); -} // namespace electron +} AutofillDriver::~AutofillDriver() = default; @@ -46,12 +46,13 @@ void AutofillDriver::ShowAutofillPopup( gfx::RectF popup_bounds(bounds); content::RenderFrameHost* embedder_frame_host = nullptr; if (embedder) { - auto* embedder_view = embedder->web_contents()->GetMainFrame()->GetView(); - auto* view = web_contents->web_contents()->GetMainFrame()->GetView(); + auto* embedder_view = + embedder->web_contents()->GetPrimaryMainFrame()->GetView(); + auto* view = web_contents->web_contents()->GetPrimaryMainFrame()->GetView(); auto offset = view->GetViewBounds().origin() - embedder_view->GetViewBounds().origin(); popup_bounds.Offset(offset); - embedder_frame_host = embedder->web_contents()->GetMainFrame(); + embedder_frame_host = embedder->web_contents()->GetPrimaryMainFrame(); } autofill_popup_->CreateView(render_frame_host_, embedder_frame_host, osr, diff --git a/shell/browser/electron_autofill_driver_factory.cc b/shell/browser/electron_autofill_driver_factory.cc index e49683744baa6..254836b82408d 100644 --- a/shell/browser/electron_autofill_driver_factory.cc +++ b/shell/browser/electron_autofill_driver_factory.cc @@ -80,7 +80,7 @@ AutofillDriver* AutofillDriverFactory::DriverForFrame( // 3. `SomeOtherWebContentsObserver::RenderFrameDeleted(render_frame_host)` // calls `DriverForFrame(render_frame_host)`. // 5. `render_frame_host->~RenderFrameHostImpl()` finishes. - if (render_frame_host->IsRenderFrameCreated()) { + if (render_frame_host->IsRenderFrameLive()) { driver = std::make_unique(render_frame_host); DCHECK_EQ(driver_map_.find(render_frame_host)->second.get(), driver.get()); diff --git a/shell/browser/electron_browser_client.cc b/shell/browser/electron_browser_client.cc index e4818fee6af51..a344b55023484 100644 --- a/shell/browser/electron_browser_client.cc +++ b/shell/browser/electron_browser_client.cc @@ -21,14 +21,16 @@ #include "base/no_destructor.h" #include "base/path_service.h" #include "base/stl_util.h" +#include "base/strings/escape.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "chrome/browser/browser_process.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_version.h" +#include "components/embedder_support/user_agent_utils.h" #include "components/net_log/chrome_net_log.h" #include "components/network_hints/common/network_hints.mojom.h" #include "content/browser/keyboard_lock/keyboard_lock_service_impl.h" // nogncheck @@ -47,23 +49,24 @@ #include "content/public/browser/tts_controller.h" #include "content/public/browser/tts_platform.h" #include "content/public/browser/url_loader_request_interceptor.h" +#include "content/public/browser/weak_document_ptr.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" #include "crypto/crypto_buildflags.h" #include "electron/buildflags/buildflags.h" -#include "electron/grit/electron_resources.h" #include "electron/shell/common/api/api.mojom.h" #include "extensions/browser/api/messaging/messaging_api_message_filter.h" #include "mojo/public/cpp/bindings/binder_map.h" -#include "net/base/escape.h" #include "net/ssl/ssl_cert_request_info.h" #include "ppapi/buildflags/buildflags.h" #include "ppapi/host/ppapi_host.h" #include "printing/buildflags/buildflags.h" #include "services/device/public/cpp/geolocation/location_provider.h" #include "services/network/public/cpp/features.h" +#include "services/network/public/cpp/is_potentially_trustworthy.h" +#include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/resource_request_body.h" #include "services/network/public/cpp/self_deleting_url_loader_factory.h" #include "shell/app/electron_crash_reporter_client.h" @@ -368,6 +371,21 @@ int GetCrashSignalFD(const base::CommandLine& command_line) { } #endif // BUILDFLAG(IS_LINUX) +void MaybeAppendSecureOriginsAllowlistSwitch(base::CommandLine* cmdline) { + // |allowlist| combines pref/policy + cmdline switch in the browser process. + // For renderer and utility (e.g. NetworkService) processes the switch is the + // only available source, so below the combined (pref/policy + cmdline) + // allowlist of secure origins is injected into |cmdline| for these other + // processes. + std::vector allowlist = + network::SecureOriginAllowlist::GetInstance().GetCurrentAllowlist(); + if (!allowlist.empty()) { + cmdline->AppendSwitchASCII( + network::switches::kUnsafelyTreatInsecureOriginAsSecure, + base::JoinString(allowlist, ",")); + } +} + } // namespace // static @@ -378,9 +396,8 @@ ElectronBrowserClient* ElectronBrowserClient::Get() { // static void ElectronBrowserClient::SetApplicationLocale(const std::string& locale) { if (!BrowserThread::IsThreadInitialized(BrowserThread::IO) || - !base::PostTask( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&SetApplicationLocaleOnIOThread, locale))) { + !content::GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&SetApplicationLocaleOnIOThread, locale))) { g_io_thread_application_locale.Get() = locale; } *g_application_locale = locale; @@ -436,6 +453,9 @@ void ElectronBrowserClient::RenderProcessWillLaunch( new extensions::MessagingAPIMessageFilter(process_id, browser_context)); #endif + // Remove in case the host is reused after a crash, otherwise noop. + host->RemoveObserver(this); + // ensure the ProcessPreferences is removed later host->AddObserver(this); } @@ -478,11 +498,6 @@ void ElectronBrowserClient::OverrideWebkitPrefs( ? blink::mojom::PreferredColorScheme::kDark : blink::mojom::PreferredColorScheme::kLight; - auto preloads = - SessionPreferences::GetValidPreloads(web_contents->GetBrowserContext()); - if (!preloads.empty()) - prefs->preloads = preloads; - SetFontDefaults(prefs); // Custom preferences of guest page. @@ -608,7 +623,11 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches( switches::kServiceWorkerSchemes, switches::kStreamingSchemes}; command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(), kCommonSwitchNames, - base::size(kCommonSwitchNames)); + std::size(kCommonSwitchNames)); + if (process_type == ::switches::kUtilityProcess || + content::RenderProcessHost::FromID(process_id)) { + MaybeAppendSecureOriginsAllowlistSwitch(command_line); + } } if (process_type == ::switches::kRendererProcess) { @@ -943,10 +962,8 @@ ElectronBrowserClient::GetSystemNetworkContext() { } std::unique_ptr -ElectronBrowserClient::CreateBrowserMainParts( - content::MainFunctionParams params) { - auto browser_main_parts = - std::make_unique(std::move(params)); +ElectronBrowserClient::CreateBrowserMainParts(bool /* is_integration_test */) { + auto browser_main_parts = std::make_unique(); #if BUILDFLAG(IS_MAC) browser_main_parts_ = browser_main_parts.get(); @@ -971,7 +988,7 @@ void ElectronBrowserClient::WebNotificationAllowed( return; } permission_helper->RequestWebNotificationPermission( - base::BindOnce(std::move(callback), web_contents->IsAudioMuted())); + rfh, base::BindOnce(std::move(callback), web_contents->IsAudioMuted())); } void ElectronBrowserClient::RenderProcessHostDestroyed( @@ -1006,6 +1023,7 @@ void OnOpenExternal(const GURL& escaped_url, bool allowed) { void HandleExternalProtocolInUI( const GURL& url, + content::WeakDocumentPtr document_ptr, content::WebContents::OnceGetter web_contents_getter, bool has_user_gesture) { content::WebContents* web_contents = std::move(web_contents_getter).Run(); @@ -1017,28 +1035,40 @@ void HandleExternalProtocolInUI( if (!permission_helper) return; - GURL escaped_url(net::EscapeExternalHandlerValue(url.spec())); + content::RenderFrameHost* rfh = document_ptr.AsRenderFrameHostIfValid(); + if (!rfh) { + // If the render frame host is not valid it means it was a top level + // navigation and the frame has already been disposed of. In this case we + // take the current main frame and declare it responsible for the + // transition. + rfh = web_contents->GetPrimaryMainFrame(); + } + + GURL escaped_url(base::EscapeExternalHandlerValue(url.spec())); auto callback = base::BindOnce(&OnOpenExternal, escaped_url); - permission_helper->RequestOpenExternalPermission(std::move(callback), + permission_helper->RequestOpenExternalPermission(rfh, std::move(callback), has_user_gesture, url); } bool ElectronBrowserClient::HandleExternalProtocol( const GURL& url, content::WebContents::Getter web_contents_getter, - int child_id, int frame_tree_node_id, content::NavigationUIData* navigation_data, - bool is_main_frame, + bool is_primary_main_frame, + bool is_in_fenced_frame_tree, network::mojom::WebSandboxFlags sandbox_flags, ui::PageTransition page_transition, bool has_user_gesture, const absl::optional& initiating_origin, content::RenderFrameHost* initiator_document, mojo::PendingRemote* out_factory) { - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&HandleExternalProtocolInUI, url, + initiator_document + ? initiator_document->GetWeakDocumentPtr() + : content::WeakDocumentPtr(), std::move(web_contents_getter), has_user_gesture)); return true; } @@ -1118,11 +1148,11 @@ void ElectronBrowserClient::OnNetworkServiceCreated( std::vector ElectronBrowserClient::GetNetworkContextsParentDirectory() { - base::FilePath user_data_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - DCHECK(!user_data_dir.empty()); + base::FilePath session_data; + base::PathService::Get(DIR_SESSION_DATA, &session_data); + DCHECK(!session_data.empty()); - return {user_data_dir}; + return {session_data}; } std::string ElectronBrowserClient::GetProduct() { @@ -1139,6 +1169,10 @@ void ElectronBrowserClient::SetUserAgent(const std::string& user_agent) { user_agent_override_ = user_agent; } +blink::UserAgentMetadata ElectronBrowserClient::GetUserAgentMetadata() { + return embedder_support::GetUserAgentMetadata(); +} + void ElectronBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories( int frame_tree_node_id, ukm::SourceIdObj ukm_source_id, @@ -1311,6 +1345,11 @@ void ElectronBrowserClient:: DCHECK(browser_context); DCHECK(factories); + auto* protocol_registry = + ProtocolRegistry::FromBrowserContext(browser_context); + protocol_registry->RegisterURLLoaderFactories(factories, + false /* allow_file_access */); + #if BUILDFLAG(ENABLE_EXTENSIONS) factories->emplace( extensions::kExtensionScheme, @@ -1457,16 +1496,11 @@ bool ElectronBrowserClient::WillCreateURLLoaderFactory( new ProxyingURLLoaderFactory( web_request.get(), protocol_registry->intercept_handlers(), render_process_id, - frame_host ? frame_host->GetRoutingID() : MSG_ROUTING_NONE, - frame_host ? frame_host->GetRenderViewHost()->GetRoutingID() - : MSG_ROUTING_NONE, - &next_id_, std::move(navigation_ui_data), std::move(navigation_id), + frame_host ? frame_host->GetRoutingID() : MSG_ROUTING_NONE, &next_id_, + std::move(navigation_ui_data), std::move(navigation_id), std::move(proxied_receiver), std::move(target_factory_remote), std::move(header_client_receiver), type); - if (bypass_redirect_checks) - *bypass_redirect_checks = true; - return true; } @@ -1516,10 +1550,9 @@ void ElectronBrowserClient::OverrideURLLoaderFactoryParams( bool ElectronBrowserClient::PreSpawnChild(sandbox::TargetPolicy* policy, sandbox::mojom::Sandbox sandbox_type, ChildSpawnFlags flags) { - // Allow crashpad to communicate via named pipe. - sandbox::ResultCode result = policy->AddRule( - sandbox::TargetPolicy::SUBSYS_FILES, - sandbox::TargetPolicy::FILES_ALLOW_ANY, L"\\??\\pipe\\crashpad_*"); + sandbox::ResultCode result = policy->GetConfig()->AddRule( + sandbox::SubSystem::kFiles, sandbox::Semantics::kFilesAllowAny, + L"\\??\\pipe\\crashpad_*"); if (result != sandbox::SBOX_ALL_OK) return false; return true; @@ -1537,58 +1570,63 @@ void ElectronBrowserClient:: if (contents) { auto* prefs = WebContentsPreferences::From(contents); if (render_frame_host.GetFrameTreeNodeId() == - contents->GetMainFrame()->GetFrameTreeNodeId() || + contents->GetPrimaryMainFrame()->GetFrameTreeNodeId() || (prefs && prefs->AllowsNodeIntegrationInSubFrames())) { - associated_registry.AddInterface(base::BindRepeating( + associated_registry.AddInterface( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver + receiver) { + ElectronApiIPCHandlerImpl::Create(render_frame_host, + std::move(receiver)); + }, + &render_frame_host)); + } + } + + associated_registry.AddInterface( + base::BindRepeating( [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver + mojo::PendingAssociatedReceiver receiver) { - ElectronApiIPCHandlerImpl::Create(render_frame_host, - std::move(receiver)); + ElectronWebContentsUtilityHandlerImpl::Create(render_frame_host, + std::move(receiver)); }, &render_frame_host)); - } - } - - associated_registry.AddInterface(base::BindRepeating( - [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver< - electron::mojom::ElectronWebContentsUtility> receiver) { - ElectronWebContentsUtilityHandlerImpl::Create(render_frame_host, - std::move(receiver)); - }, - &render_frame_host)); - associated_registry.AddInterface(base::BindRepeating( - [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver - receiver) { - AutofillDriverFactory::BindAutofillDriver(std::move(receiver), - render_frame_host); - }, - &render_frame_host)); + associated_registry.AddInterface( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver + receiver) { + AutofillDriverFactory::BindAutofillDriver(std::move(receiver), + render_frame_host); + }, + &render_frame_host)); #if BUILDFLAG(ENABLE_PRINTING) - associated_registry.AddInterface(base::BindRepeating( - [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver - receiver) { - PrintViewManagerElectron::BindPrintManagerHost(std::move(receiver), - render_frame_host); - }, - &render_frame_host)); + associated_registry.AddInterface( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver + receiver) { + PrintViewManagerElectron::BindPrintManagerHost(std::move(receiver), + render_frame_host); + }, + &render_frame_host)); #endif #if BUILDFLAG(ENABLE_EXTENSIONS) - associated_registry.AddInterface(base::BindRepeating( - [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver - receiver) { - extensions::ExtensionWebContentsObserver::BindLocalFrameHost( - std::move(receiver), render_frame_host); - }, - &render_frame_host)); + associated_registry.AddInterface( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver + receiver) { + extensions::ExtensionWebContentsObserver::BindLocalFrameHost( + std::move(receiver), render_frame_host); + }, + &render_frame_host)); #endif #if BUILDFLAG(ENABLE_PDF_VIEWER) - associated_registry.AddInterface(base::BindRepeating( + associated_registry.AddInterface(base::BindRepeating( [](content::RenderFrameHost* render_frame_host, mojo::PendingAssociatedReceiver receiver) { pdf::PDFWebContentsHelper::BindPdfService(std::move(receiver), @@ -1664,9 +1702,10 @@ void ElectronBrowserClient::ExposeInterfacesToRenderer( blink::AssociatedInterfaceRegistry* associated_registry, content::RenderProcessHost* render_process_host) { #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) - associated_registry->AddInterface(base::BindRepeating( - &extensions::EventRouter::BindForRenderer, render_process_host->GetID())); - associated_registry->AddInterface( + associated_registry->AddInterface( + base::BindRepeating(&extensions::EventRouter::BindForRenderer, + render_process_host->GetID())); + associated_registry->AddInterface( base::BindRepeating(&extensions::ExtensionsGuestView::CreateForExtensions, render_process_host->GetID())); #endif @@ -1797,6 +1836,7 @@ void BindBadgeServiceForServiceWorker( } void ElectronBrowserClient::RegisterBrowserInterfaceBindersForServiceWorker( + content::BrowserContext* browser_context, mojo::BinderMapWithContext* map) { map->Add( diff --git a/shell/browser/electron_browser_client.h b/shell/browser/electron_browser_client.h index c0b9827d4cf24..597eb58360ef9 100644 --- a/shell/browser/electron_browser_client.h +++ b/shell/browser/electron_browser_client.h @@ -82,6 +82,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient, content::RenderFrameHost* render_frame_host, mojo::BinderMapWithContext* map) override; void RegisterBrowserInterfaceBindersForServiceWorker( + content::BrowserContext* browser_context, mojo::BinderMapWithContext* map) override; #if BUILDFLAG(IS_LINUX) @@ -93,6 +94,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient, std::string GetUserAgent() override; void SetUserAgent(const std::string& user_agent); + blink::UserAgentMetadata GetUserAgentMetadata() override; content::SerialDelegate* GetSerialDelegate() override; @@ -181,7 +183,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient, std::unique_ptr CreateDevToolsManagerDelegate() override; std::unique_ptr CreateBrowserMainParts( - content::MainFunctionParams params) override; + bool /* is_integration_test */) override; base::FilePath GetDefaultDownloadDirectory() override; scoped_refptr GetSystemSharedURLLoaderFactory() override; @@ -253,10 +255,10 @@ class ElectronBrowserClient : public content::ContentBrowserClient, bool HandleExternalProtocol( const GURL& url, content::WebContents::Getter web_contents_getter, - int child_id, int frame_tree_node_id, content::NavigationUIData* navigation_data, - bool is_main_frame, + bool is_primary_main_frame, + bool is_in_fenced_frame_tree, network::mojom::WebSandboxFlags sandbox_flags, ui::PageTransition page_transition, bool has_user_gesture, diff --git a/shell/browser/electron_browser_context.cc b/shell/browser/electron_browser_context.cc index bdd2eb4d19c0c..4699a1c908c91 100644 --- a/shell/browser/electron_browser_context.cc +++ b/shell/browser/electron_browser_context.cc @@ -14,8 +14,8 @@ #include "base/files/file_path.h" #include "base/no_destructor.h" #include "base/path_service.h" +#include "base/strings/escape.h" #include "base/strings/string_util.h" -#include "base/task/post_task.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread_restrictions.h" #include "chrome/common/chrome_paths.h" @@ -33,7 +33,6 @@ #include "content/public/browser/cors_origin_pattern_setter.h" #include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/browser/storage_partition.h" -#include "net/base/escape.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/network_context.mojom.h" @@ -47,6 +46,7 @@ #include "shell/browser/protocol_registry.h" #include "shell/browser/special_storage_policy.h" #include "shell/browser/ui/inspectable_web_contents.h" +#include "shell/browser/web_contents_permission_helper.h" #include "shell/browser/web_view_manager.h" #include "shell/browser/zoom_level_delegate.h" #include "shell/common/application_info.h" @@ -88,7 +88,7 @@ namespace { // Convert string to lower case and escape it. std::string MakePartitionName(const std::string& input) { - return net::EscapePath(base::ToLowerASCII(input)); + return base::EscapePath(base::ToLowerASCII(input)); } } // namespace @@ -103,25 +103,22 @@ ElectronBrowserContext::browser_context_map() { ElectronBrowserContext::ElectronBrowserContext(const std::string& partition, bool in_memory, - base::DictionaryValue options) + base::Value::Dict options) : storage_policy_(base::MakeRefCounted()), protocol_registry_(base::WrapUnique(new ProtocolRegistry)), in_memory_(in_memory), ssl_config_(network::mojom::SSLConfig::New()) { - user_agent_ = ElectronBrowserClient::Get()->GetUserAgent(); - // Read options. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); use_cache_ = !command_line->HasSwitch(switches::kDisableHttpCache); - if (auto use_cache_opt = options.FindBoolKey("cache")) { + if (auto use_cache_opt = options.FindBool("cache")) { use_cache_ = use_cache_opt.value(); } base::StringToInt(command_line->GetSwitchValueASCII(switches::kDiskCacheSize), &max_cache_size_); - CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &path_)); - + base::PathService::Get(DIR_SESSION_DATA, &path_); if (!in_memory && !partition.empty()) path_ = path_.Append(FILE_PATH_LITERAL("Partitions")) .Append(base::FilePath::FromUTF8Unsafe( @@ -224,9 +221,10 @@ void ElectronBrowserContext::InitPrefs() { std::string default_code = spellcheck::GetCorrespondingSpellCheckLanguage( base::i18n::GetConfiguredLocale()); if (!default_code.empty()) { - base::ListValue language_codes; + base::Value::List language_codes; language_codes.Append(default_code); - prefs()->Set(spellcheck::prefs::kSpellCheckDictionaries, language_codes); + prefs()->Set(spellcheck::prefs::kSpellCheckDictionaries, + base::Value(std::move(language_codes))); } } #endif @@ -307,7 +305,7 @@ ElectronBrowserContext::GetSpecialStoragePolicy() { } std::string ElectronBrowserContext::GetUserAgent() const { - return user_agent_; + return user_agent_.value_or(ElectronBrowserClient::Get()->GetUserAgent()); } predictors::PreconnectManager* ElectronBrowserContext::GetPreconnectManager() { @@ -348,8 +346,6 @@ ElectronBrowserContext::GetURLLoaderFactory() { params->disable_web_security = false; auto* storage_partition = GetDefaultStoragePartition(); - params->url_loader_network_observer = - storage_partition->CreateURLLoaderNetworkObserverForNavigationRequest(-1); storage_partition->GetNetworkContext()->CreateURLLoaderFactory( std::move(factory_receiver), std::move(params)); url_loader_factory_ = @@ -393,6 +389,13 @@ ElectronBrowserContext::GetStorageNotificationService() { return nullptr; } +content::ReduceAcceptLanguageControllerDelegate* +ElectronBrowserContext::GetReduceAcceptLanguageControllerDelegate() { + // Needs implementation + // Refs https://chromium-review.googlesource.com/c/chromium/src/+/3687391 + return nullptr; +} + ResolveProxyHelper* ElectronBrowserContext::GetResolveProxyHelper() { if (!resolve_proxy_helper_) { resolve_proxy_helper_ = base::MakeRefCounted(this); @@ -416,11 +419,120 @@ void ElectronBrowserContext::SetSSLConfigClient( ssl_config_client_ = std::move(client); } +void ElectronBrowserContext::GrantDevicePermission( + const url::Origin& origin, + const base::Value& device, + blink::PermissionType permission_type) { + granted_devices_[permission_type][origin].push_back( + std::make_unique(device.Clone())); +} + +void ElectronBrowserContext::RevokeDevicePermission( + const url::Origin& origin, + const base::Value& device, + blink::PermissionType permission_type) { + const auto& current_devices_it = granted_devices_.find(permission_type); + if (current_devices_it == granted_devices_.end()) + return; + + const auto& origin_devices_it = current_devices_it->second.find(origin); + if (origin_devices_it == current_devices_it->second.end()) + return; + + for (auto it = origin_devices_it->second.begin(); + it != origin_devices_it->second.end();) { + if (DoesDeviceMatch(device, it->get(), permission_type)) { + it = origin_devices_it->second.erase(it); + } else { + ++it; + } + } +} + +bool ElectronBrowserContext::DoesDeviceMatch( + const base::Value& device, + const base::Value* device_to_compare, + blink::PermissionType permission_type) { + if (permission_type == + static_cast( + WebContentsPermissionHelper::PermissionType::HID)) { + if (device.GetDict().FindInt(kHidVendorIdKey) != + device_to_compare->GetDict().FindInt(kHidVendorIdKey) || + device.GetDict().FindInt(kHidProductIdKey) != + device_to_compare->GetDict().FindInt(kHidProductIdKey)) { + return false; + } + + const auto* serial_number = + device_to_compare->GetDict().FindString(kHidSerialNumberKey); + const auto* device_serial_number = + device.GetDict().FindString(kHidSerialNumberKey); + + if (serial_number && device_serial_number && + *device_serial_number == *serial_number) + return true; + } else if (permission_type == + static_cast( + WebContentsPermissionHelper::PermissionType::SERIAL)) { +#if BUILDFLAG(IS_WIN) + const auto* instance_id = device.GetDict().FindString(kDeviceInstanceIdKey); + const auto* port_instance_id = + device_to_compare->GetDict().FindString(kDeviceInstanceIdKey); + if (instance_id && port_instance_id && *instance_id == *port_instance_id) + return true; +#else + const auto* serial_number = device.GetDict().FindString(kSerialNumberKey); + const auto* port_serial_number = + device_to_compare->GetDict().FindString(kSerialNumberKey); + if (device.GetDict().FindInt(kVendorIdKey) != + device_to_compare->GetDict().FindInt(kVendorIdKey) || + device.GetDict().FindInt(kProductIdKey) != + device_to_compare->GetDict().FindInt(kProductIdKey) || + (serial_number && port_serial_number && + *port_serial_number != *serial_number)) { + return false; + } + +#if BUILDFLAG(IS_MAC) + const auto* usb_driver_key = device.GetDict().FindString(kUsbDriverKey); + const auto* port_usb_driver_key = + device_to_compare->GetDict().FindString(kUsbDriverKey); + if (usb_driver_key && port_usb_driver_key && + *usb_driver_key != *port_usb_driver_key) { + return false; + } +#endif // BUILDFLAG(IS_MAC) + return true; +#endif // BUILDFLAG(IS_WIN) + } + return false; +} + +bool ElectronBrowserContext::CheckDevicePermission( + const url::Origin& origin, + const base::Value& device, + blink::PermissionType permission_type) { + const auto& current_devices_it = granted_devices_.find(permission_type); + if (current_devices_it == granted_devices_.end()) + return false; + + const auto& origin_devices_it = current_devices_it->second.find(origin); + if (origin_devices_it == current_devices_it->second.end()) + return false; + + for (const auto& device_to_compare : origin_devices_it->second) { + if (DoesDeviceMatch(device, device_to_compare.get(), permission_type)) + return true; + } + + return false; +} + // static ElectronBrowserContext* ElectronBrowserContext::From( const std::string& partition, bool in_memory, - base::DictionaryValue options) { + base::Value::Dict options) { PartitionKey key(partition, in_memory); ElectronBrowserContext* browser_context = browser_context_map()[key].get(); if (browser_context) { diff --git a/shell/browser/electron_browser_context.h b/shell/browser/electron_browser_context.h index 3a646aad02ce4..2e1d3bbbb0c9e 100644 --- a/shell/browser/electron_browser_context.h +++ b/shell/browser/electron_browser_context.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "base/memory/weak_ptr.h" #include "chrome/browser/predictors/preconnect_manager.h" @@ -18,6 +19,7 @@ #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "shell/browser/media/media_device_id_salt.h" +#include "third_party/blink/public/common/permissions/permission_utils.h" class PrefService; class ValueMapPrefStore; @@ -38,7 +40,10 @@ class ElectronExtensionSystem; namespace electron { -class ElectronBrowserContext; +using DevicePermissionMap = + std::map>>>; + class ElectronDownloadManagerDelegate; class ElectronPermissionManager; class CookieChangeNotifier; @@ -76,10 +81,9 @@ class ElectronBrowserContext : public content::BrowserContext { // Get or create the BrowserContext according to its |partition| and // |in_memory|. The |options| will be passed to constructor when there is no // existing BrowserContext. - static ElectronBrowserContext* From( - const std::string& partition, - bool in_memory, - base::DictionaryValue options = base::DictionaryValue()); + static ElectronBrowserContext* From(const std::string& partition, + bool in_memory, + base::Value::Dict options = {}); static BrowserContextMap& browser_context_map(); @@ -114,6 +118,8 @@ class ElectronBrowserContext : public content::BrowserContext { content::ClientHintsControllerDelegate* GetClientHintsControllerDelegate() override; content::StorageNotificationService* GetStorageNotificationService() override; + content::ReduceAcceptLanguageControllerDelegate* + GetReduceAcceptLanguageControllerDelegate() override; CookieChangeNotifier* cookie_change_notifier() const { return cookie_change_notifier_.get(); @@ -148,14 +154,37 @@ class ElectronBrowserContext : public content::BrowserContext { ~ElectronBrowserContext() override; + // Grants |origin| access to |device|. + // To be used in place of ObjectPermissionContextBase::GrantObjectPermission. + void GrantDevicePermission(const url::Origin& origin, + const base::Value& device, + blink::PermissionType permissionType); + + // Revokes |origin| access to |device|. + // To be used in place of ObjectPermissionContextBase::RevokeObjectPermission. + void RevokeDevicePermission(const url::Origin& origin, + const base::Value& device, + blink::PermissionType permission_type); + + // Returns the list of devices that |origin| has been granted permission to + // access. To be used in place of + // ObjectPermissionContextBase::GetGrantedObjects. + bool CheckDevicePermission(const url::Origin& origin, + const base::Value& device, + blink::PermissionType permissionType); + private: ElectronBrowserContext(const std::string& partition, bool in_memory, - base::DictionaryValue options); + base::Value::Dict options); // Initialize pref registry. void InitPrefs(); + bool DoesDeviceMatch(const base::Value& device, + const base::Value* device_to_compare, + blink::PermissionType permission_type); + ValueMapPrefStore* in_memory_pref_store_ = nullptr; std::unique_ptr resource_context_; @@ -170,7 +199,7 @@ class ElectronBrowserContext : public content::BrowserContext { std::unique_ptr preconnect_manager_; std::unique_ptr protocol_registry_; - std::string user_agent_; + absl::optional user_agent_; base::FilePath path_; bool in_memory_ = false; bool use_cache_ = true; @@ -187,6 +216,9 @@ class ElectronBrowserContext : public content::BrowserContext { network::mojom::SSLConfigPtr ssl_config_; mojo::Remote ssl_config_client_; + // In-memory cache that holds objects that have been granted permissions. + DevicePermissionMap granted_devices_; + base::WeakPtrFactory weak_factory_{this}; }; diff --git a/shell/browser/electron_browser_main_parts.cc b/shell/browser/electron_browser_main_parts.cc index ad6509a7a3bcb..82a479866288f 100644 --- a/shell/browser/electron_browser_main_parts.cc +++ b/shell/browser/electron_browser_main_parts.cc @@ -11,12 +11,14 @@ #include "base/base_switches.h" #include "base/command_line.h" #include "base/feature_list.h" +#include "base/i18n/rtl.h" #include "base/metrics/field_trial.h" #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/icon_manager.h" +#include "chrome/browser/ui/color/chrome_color_mixers.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "components/os_crypt/key_storage_config_linux.h" @@ -25,6 +27,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/device_service.h" +#include "content/public/browser/first_party_sets_handler.h" #include "content/public/browser/web_ui_controller_factory.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" @@ -73,14 +76,15 @@ #include "ui/base/cursor/cursor_factory.h" #include "ui/base/ime/linux/linux_input_method_context_factory.h" #include "ui/gfx/color_utils.h" -#include "ui/gtk/gtk_compat.h" // nogncheck -#include "ui/gtk/gtk_ui_factory.h" // nogncheck -#include "ui/gtk/gtk_util.h" // nogncheck +#include "ui/gtk/gtk_compat.h" // nogncheck +#include "ui/gtk/gtk_util.h" // nogncheck +#include "ui/linux/linux_ui.h" +#include "ui/linux/linux_ui_factory.h" #include "ui/ozone/public/ozone_platform.h" -#include "ui/views/linux_ui/linux_ui.h" #endif #if BUILDFLAG(IS_WIN) +#include "base/win/dark_mode_support.h" #include "ui/base/l10n/l10n_util_win.h" #include "ui/display/win/dpi.h" #include "ui/gfx/system_fonts_win.h" @@ -178,8 +182,7 @@ class DarkThemeObserver : public ui::NativeThemeObserver { // static ElectronBrowserMainParts* ElectronBrowserMainParts::self_ = nullptr; -ElectronBrowserMainParts::ElectronBrowserMainParts( - const content::MainFunctionParams& params) +ElectronBrowserMainParts::ElectronBrowserMainParts() : fake_browser_process_(std::make_unique()), browser_(std::make_unique()), node_bindings_( @@ -217,8 +220,15 @@ int ElectronBrowserMainParts::PreEarlyInitialization() { HandleSIGCHLD(); #endif #if BUILDFLAG(IS_LINUX) + DetectOzonePlatform(); ui::OzonePlatform::PreEarlyInitialization(); #endif +#if BUILDFLAG(IS_MAC) + screen_ = std::make_unique(); +#endif + + ui::ColorProviderManager::Get().AppendColorProviderInitializer( + base::BindRepeating(AddChromeColorMixers)); return GetExitCode(); } @@ -274,16 +284,16 @@ void ElectronBrowserMainParts::PostEarlyInitialization() { } int ElectronBrowserMainParts::PreCreateThreads() { -#if defined(USE_AURA) - screen_ = views::CreateDesktopScreen(); - display::Screen::SetScreenInstance(screen_.get()); -#if BUILDFLAG(IS_LINUX) - views::LinuxUI::instance()->UpdateDeviceScaleFactor(); -#endif -#endif - - if (!views::LayoutProvider::Get()) + if (!views::LayoutProvider::Get()) { layout_provider_ = std::make_unique(); + } + + // Fetch the system locale for Electron. +#if BUILDFLAG(IS_MAC) + fake_browser_process_->SetSystemLocale(GetCurrentSystemLocale()); +#else + fake_browser_process_->SetSystemLocale(base::i18n::GetConfiguredLocale()); +#endif auto* command_line = base::CommandLine::ForCurrentProcess(); std::string locale = command_line->GetSwitchValueASCII(::switches::kLang); @@ -312,7 +322,15 @@ int ElectronBrowserMainParts::PreCreateThreads() { // Load resources bundle according to locale. std::string loaded_locale = LoadResourceBundle(locale); - // Initialize the app locale. +#if defined(USE_AURA) + // NB: must be called _after_ locale resource bundle is loaded, + // because ui lib makes use of it in X11 + if (!display::Screen::GetScreen()) { + screen_ = views::CreateDesktopScreen(); + } +#endif + + // Initialize the app locale for Electron and Chromium. std::string app_locale = l10n_util::GetApplicationLocale(loaded_locale); ElectronBrowserClient::SetApplicationLocale(app_locale); fake_browser_process_->SetApplicationLocale(app_locale); @@ -346,8 +364,8 @@ int ElectronBrowserMainParts::PreCreateThreads() { } void ElectronBrowserMainParts::PostCreateThreads() { - base::PostTask( - FROM_HERE, {content::BrowserThread::IO}, + content::GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&tracing::TracingSamplerProfiler::CreateOnChildThread)); } @@ -365,9 +383,7 @@ void ElectronBrowserMainParts::PostDestroyThreads() { void ElectronBrowserMainParts::ToolkitInitialized() { #if BUILDFLAG(IS_LINUX) - auto linux_ui = BuildGtkUi(); - linux_ui->Initialize(); - DCHECK(ui::LinuxInputMethodContextFactory::instance()); + auto linux_ui = ui::CreateLinuxUi(); // Try loading gtk symbols used by Electron. electron::InitializeElectron_gtk(gtk::GetLibGtk()); @@ -375,6 +391,10 @@ void ElectronBrowserMainParts::ToolkitInitialized() { electron::UninitializeElectron_gtk(); } + electron::InitializeElectron_gdk_pixbuf(gtk::GetLibGdkPixbuf()); + CHECK(electron::IsElectron_gdk_pixbufInitialized()) + << "Failed to initialize libgdk_pixbuf-2.0.so.0"; + // Chromium does not respect GTK dark theme setting, but they may change // in future and this code might be no longer needed. Check the Chromium // issue to keep updated: @@ -384,7 +404,7 @@ void ElectronBrowserMainParts::ToolkitInitialized() { // here returns a NativeThemeGtk, which monitors GTK settings. dark_theme_observer_ = std::make_unique(); linux_ui->GetNativeTheme(nullptr)->AddObserver(dark_theme_observer_.get()); - views::LinuxUI::SetInstance(std::move(linux_ui)); + ui::LinuxUi::SetInstance(std::move(linux_ui)); // Cursor theme changes are tracked by LinuxUI (via a CursorThemeManager // implementation). Start observing them once it's initialized. @@ -410,8 +430,8 @@ void ElectronBrowserMainParts::ToolkitInitialized() { int ElectronBrowserMainParts::PreMainMessageLoopRun() { // Run user's main script before most things get initialized, so we can have // a chance to setup everything. - node_bindings_->PrepareMessageLoop(); - node_bindings_->RunMessageLoop(); + node_bindings_->PrepareEmbedThread(); + node_bindings_->StartPolling(); // url::Add*Scheme are not threadsafe, this helps prevent data races. url::LockSchemeRegistries(); @@ -433,6 +453,11 @@ int ElectronBrowserMainParts::PreMainMessageLoopRun() { SpellcheckServiceFactory::GetInstance(); #endif +#if BUILDFLAG(IS_WIN) + // access ui native theme here to prevent blocking calls later + base::win::AllowDarkModeForApp(true); +#endif + content::WebUIControllerFactory::RegisterFactory( ElectronWebUIControllerFactory::GetInstance()); @@ -440,8 +465,8 @@ int ElectronBrowserMainParts::PreMainMessageLoopRun() { if (command_line->HasSwitch(switches::kRemoteDebuggingPipe)) { // --remote-debugging-pipe auto on_disconnect = base::BindOnce([]() { - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce([]() { Browser::Get()->Quit(); })); + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce([]() { Browser::Get()->Quit(); })); }); content::DevToolsAgentHost::StartRemoteDebuggingPipeHandler( std::move(on_disconnect)); @@ -453,7 +478,7 @@ int ElectronBrowserMainParts::PreMainMessageLoopRun() { #if !BUILDFLAG(IS_MAC) // The corresponding call in macOS is in ElectronApplicationDelegate. Browser::Get()->WillFinishLaunching(); - Browser::Get()->DidFinishLaunching(base::DictionaryValue()); + Browser::Get()->DidFinishLaunching(base::Value::Dict()); #endif // Notify observers that main thread message loop was initialized. @@ -495,7 +520,7 @@ void ElectronBrowserMainParts::PostCreateMainMessageLoop() { // https://source.chromium.org/chromium/chromium/src/+/master:chrome/common/chrome_switches.cc;l=689;drc=9d82515060b9b75fa941986f5db7390299669ef1 config->should_use_preference = command_line.HasSwitch(::switches::kEnableEncryptionSelection); - base::PathService::Get(chrome::DIR_USER_DATA, &config->user_data_path); + base::PathService::Get(DIR_SESSION_DATA, &config->user_data_path); OSCrypt::SetConfig(std::move(config)); #endif #if BUILDFLAG(IS_POSIX) diff --git a/shell/browser/electron_browser_main_parts.h b/shell/browser/electron_browser_main_parts.h index e41097ef35826..76d5d2d0774fc 100644 --- a/shell/browser/electron_browser_main_parts.h +++ b/shell/browser/electron_browser_main_parts.h @@ -12,11 +12,11 @@ #include "base/timer/timer.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_main_parts.h" -#include "content/public/common/main_function_params.h" #include "electron/buildflags/buildflags.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/device/public/mojom/geolocation_control.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/display/screen.h" #include "ui/views/layout/layout_provider.h" class BrowserProcessImpl; @@ -67,7 +67,7 @@ class DarkThemeObserver; class ElectronBrowserMainParts : public content::BrowserMainParts { public: - explicit ElectronBrowserMainParts(const content::MainFunctionParams& params); + ElectronBrowserMainParts(); ~ElectronBrowserMainParts() override; // disable copy @@ -122,10 +122,15 @@ class ElectronBrowserMainParts : public content::BrowserMainParts { const scoped_refptr& task_runner); #endif +#if BUILDFLAG(IS_LINUX) + void DetectOzonePlatform(); +#endif + #if BUILDFLAG(IS_MAC) void FreeAppDelegate(); void RegisterURLHandler(); void InitializeMainNib(); + static std::string GetCurrentSystemLocale(); #endif #if BUILDFLAG(IS_MAC) @@ -170,6 +175,7 @@ class ElectronBrowserMainParts : public content::BrowserMainParts { #if BUILDFLAG(IS_MAC) std::unique_ptr geolocation_manager_; + std::unique_ptr screen_; #endif static ElectronBrowserMainParts* self_; diff --git a/shell/browser/electron_browser_main_parts_linux.cc b/shell/browser/electron_browser_main_parts_linux.cc new file mode 100644 index 0000000000000..919cc085a2755 --- /dev/null +++ b/shell/browser/electron_browser_main_parts_linux.cc @@ -0,0 +1,134 @@ +// Copyright (c) 2022 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/electron_browser_main_parts.h" + +#include "base/command_line.h" +#include "base/environment.h" +#include "ui/ozone/public/ozone_switches.h" + +#if BUILDFLAG(OZONE_PLATFORM_WAYLAND) +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/nix/xdg_util.h" +#include "base/threading/thread_restrictions.h" +#endif + +#if BUILDFLAG(OZONE_PLATFORM_WAYLAND) + +constexpr char kPlatformWayland[] = "wayland"; + +bool HasWaylandDisplay(base::Environment* env) { + std::string wayland_display; + const bool has_wayland_display = + env->GetVar("WAYLAND_DISPLAY", &wayland_display) && + !wayland_display.empty(); + if (has_wayland_display) + return true; + + std::string xdg_runtime_dir; + const bool has_xdg_runtime_dir = + env->GetVar("XDG_RUNTIME_DIR", &xdg_runtime_dir) && + !xdg_runtime_dir.empty(); + if (has_xdg_runtime_dir) { + auto wayland_server_pipe = + base::FilePath(xdg_runtime_dir).Append("wayland-0"); + // Normally, this should happen exactly once, at the startup of the main + // process. + base::ScopedAllowBlocking allow_blocking; + return base::PathExists(wayland_server_pipe); + } + + return false; +} + +#endif // BUILDFLAG(OZONE_PLATFORM_WAYLAND) + +#if BUILDFLAG(OZONE_PLATFORM_X11) +constexpr char kPlatformX11[] = "x11"; +#endif + +namespace electron { + +namespace { + +// Evaluates the environment and returns the effective platform name for the +// given |ozone_platform_hint|. +// For the "auto" value, returns "wayland" if the XDG session type is "wayland", +// "x11" otherwise. +// For the "wayland" value, checks if the Wayland server is available, and +// returns "x11" if it is not. +// See https://crbug.com/1246928. +std::string MaybeFixPlatformName(const std::string& ozone_platform_hint) { +#if BUILDFLAG(OZONE_PLATFORM_WAYLAND) + // Wayland is selected if both conditions below are true: + // 1. The user selected either 'wayland' or 'auto'. + // 2. The XDG session type is 'wayland', OR the user has selected 'wayland' + // explicitly and a Wayland server is running. + // Otherwise, fall back to X11. + if (ozone_platform_hint == kPlatformWayland || + ozone_platform_hint == "auto") { + auto env(base::Environment::Create()); + + std::string xdg_session_type; + const bool has_xdg_session_type = + env->GetVar(base::nix::kXdgSessionTypeEnvVar, &xdg_session_type) && + !xdg_session_type.empty(); + + if ((has_xdg_session_type && xdg_session_type == "wayland") || + (ozone_platform_hint == kPlatformWayland && + HasWaylandDisplay(env.get()))) { + return kPlatformWayland; + } + } +#endif // BUILDFLAG(OZONE_PLATFORM_WAYLAND) + +#if BUILDFLAG(OZONE_PLATFORM_X11) + if (ozone_platform_hint == kPlatformX11) { + return kPlatformX11; + } +#if BUILDFLAG(OZONE_PLATFORM_WAYLAND) + if (ozone_platform_hint == kPlatformWayland || + ozone_platform_hint == "auto") { + // We are here if: + // - The binary has both X11 and Wayland backends. + // - The user wanted Wayland but that did not work, otherwise it would have + // been returned above. + if (ozone_platform_hint == kPlatformWayland) { + LOG(WARNING) << "No Wayland server is available. Falling back to X11."; + } else { + LOG(WARNING) << "This is not a Wayland session. Falling back to X11. " + "If you need to run Chrome on Wayland using some " + "embedded compositor, e. g., Weston, please specify " + "Wayland as your preferred Ozone platform, or use " + "--ozone-platform=wayland."; + } + return kPlatformX11; + } +#endif // BUILDFLAG(OZONE_PLATFORM_WAYLAND) +#endif // BUILDFLAG(OZONE_PLATFORM_X11) + + return ozone_platform_hint; +} + +} // namespace + +void ElectronBrowserMainParts::DetectOzonePlatform() { + auto* const command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(switches::kOzonePlatform)) { + const auto ozone_platform_hint = + command_line->GetSwitchValueASCII(switches::kOzonePlatformHint); + if (!ozone_platform_hint.empty()) { + command_line->AppendSwitchASCII( + switches::kOzonePlatform, MaybeFixPlatformName(ozone_platform_hint)); + } + } + + auto env = base::Environment::Create(); + std::string desktop_startup_id; + if (env->GetVar("DESKTOP_STARTUP_ID", &desktop_startup_id)) + command_line->AppendSwitchASCII("desktop-startup-id", desktop_startup_id); +} + +} // namespace electron diff --git a/shell/browser/electron_browser_main_parts_mac.mm b/shell/browser/electron_browser_main_parts_mac.mm index f280f66579f06..4ed64a912d769 100644 --- a/shell/browser/electron_browser_main_parts_mac.mm +++ b/shell/browser/electron_browser_main_parts_mac.mm @@ -4,6 +4,8 @@ #include "shell/browser/electron_browser_main_parts.h" +#include + #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" #include "base/path_service.h" @@ -74,4 +76,16 @@ [mainNib release]; } +std::string ElectronBrowserMainParts::GetCurrentSystemLocale() { + NSString* systemLocaleIdentifier = + [[NSLocale currentLocale] localeIdentifier]; + + // Mac OS X uses "_" instead of "-", so swap to get a real locale value. + std::string locale_value = [[systemLocaleIdentifier + stringByReplacingOccurrencesOfString:@"_" + withString:@"-"] UTF8String]; + + return locale_value; +} + } // namespace electron diff --git a/shell/browser/electron_browser_main_parts_posix.cc b/shell/browser/electron_browser_main_parts_posix.cc index 766dbd5785a7e..1eb33ae28c98f 100644 --- a/shell/browser/electron_browser_main_parts_posix.cc +++ b/shell/browser/electron_browser_main_parts_posix.cc @@ -15,7 +15,7 @@ #include "base/debug/leak_annotations.h" #include "base/posix/eintr_wrapper.h" -#include "base/task/post_task.h" +#include "base/threading/platform_thread.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "shell/browser/browser.h" diff --git a/shell/browser/electron_download_manager_delegate.cc b/shell/browser/electron_download_manager_delegate.cc index f1a54d9a6f15c..88fcc373c3383 100644 --- a/shell/browser/electron_download_manager_delegate.cc +++ b/shell/browser/electron_download_manager_delegate.cc @@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/files/file_util.h" -#include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/threading/thread_restrictions.h" #include "chrome/common/pref_names.h" @@ -31,6 +30,16 @@ #include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/options_switches.h" +#if BUILDFLAG(IS_WIN) +#include + +#include "base/i18n/case_conversion.h" +#include "base/win/registry.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/shell_dialogs/execute_select_file_win.h" +#include "ui/strings/grit/ui_strings.h" +#endif // BUILDFLAG(IS_WIN) + namespace electron { namespace { @@ -63,6 +72,116 @@ base::FilePath CreateDownloadPath(const GURL& url, return download_path.Append(generated_name); } +#if BUILDFLAG(IS_WIN) +// Get the file type description from the registry. This will be "Text Document" +// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't +// have an entry for the file type, we return false, true if the description was +// found. 'file_ext' must be in form ".txt". +// Modified from ui/shell_dialogs/select_file_dialog_win.cc +bool GetRegistryDescriptionFromExtension(const std::string& file_ext, + std::string* reg_description) { + DCHECK(reg_description); + base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, + base::UTF8ToWide(file_ext).c_str(), KEY_READ); + std::wstring reg_app; + if (reg_ext.ReadValue(nullptr, ®_app) == ERROR_SUCCESS && + !reg_app.empty()) { + base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ); + std::wstring description; + if (reg_link.ReadValue(nullptr, &description) == ERROR_SUCCESS) { + *reg_description = base::WideToUTF8(description); + return true; + } + } + return false; +} + +// Set up a filter for a Save/Open dialog, |ext_desc| as the text descriptions +// of the |file_ext| types (optional), and (optionally) the default 'All Files' +// view. The purpose of the filter is to show only files of a particular type in +// a Windows Save/Open dialog box. The resulting filter is returned. The filters +// created here are: +// 1. only files that have 'file_ext' as their extension +// 2. all files (only added if 'include_all_files' is true) +// If a description is not provided for a file extension, it will be retrieved +// from the registry. If the file extension does not exist in the registry, a +// default description will be created (e.g. "qqq" yields "QQQ File"). +// Modified from ui/shell_dialogs/select_file_dialog_win.cc +file_dialog::Filters FormatFilterForExtensions( + const std::vector& file_ext, + const std::vector& ext_desc, + bool include_all_files, + bool keep_extension_visible) { + const std::string all_ext = "*"; + const std::string all_desc = + l10n_util::GetStringUTF8(IDS_APP_SAVEAS_ALL_FILES); + + DCHECK(file_ext.size() >= ext_desc.size()); + + if (file_ext.empty()) + include_all_files = true; + + file_dialog::Filters result; + result.reserve(file_ext.size() + 1); + + for (size_t i = 0; i < file_ext.size(); ++i) { + std::string ext = file_ext[i]; + std::string desc; + if (i < ext_desc.size()) + desc = ext_desc[i]; + + if (ext.empty()) { + // Force something reasonable to appear in the dialog box if there is no + // extension provided. + include_all_files = true; + continue; + } + + if (desc.empty()) { + DCHECK(ext.find('.') != std::string::npos); + std::string first_extension = ext.substr(ext.find('.')); + size_t first_separator_index = first_extension.find(';'); + if (first_separator_index != std::string::npos) + first_extension = first_extension.substr(0, first_separator_index); + + // Find the extension name without the preceeding '.' character. + std::string ext_name = first_extension; + size_t ext_index = ext_name.find_first_not_of('.'); + if (ext_index != std::string::npos) + ext_name = ext_name.substr(ext_index); + + if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) { + // The extension doesn't exist in the registry. Create a description + // based on the unknown extension type (i.e. if the extension is .qqq, + // then we create a description "QQQ File"). + desc = l10n_util::GetStringFUTF8( + IDS_APP_SAVEAS_EXTENSION_FORMAT, + base::i18n::ToUpper(base::UTF8ToUTF16(ext_name))); + include_all_files = true; + } + if (desc.empty()) + desc = "*." + ext_name; + } else if (keep_extension_visible) { + // Having '*' in the description could cause the windows file dialog to + // not include the file extension in the file dialog. So strip out any '*' + // characters if `keep_extension_visible` is set. + base::ReplaceChars(desc, "*", base::StringPiece(), &desc); + } + + // Remove the preceeding '.' character from the extension. + size_t ext_index = ext.find_first_not_of('.'); + if (ext_index != std::string::npos) + ext = ext.substr(ext_index); + result.push_back({desc, {ext}}); + } + + if (include_all_files) + result.push_back({all_desc, {all_ext}}); + + return result; +} +#endif // BUILDFLAG(IS_WIN) + } // namespace ElectronDownloadManagerDelegate::ElectronDownloadManagerDelegate( @@ -131,6 +250,16 @@ void ElectronDownloadManagerDelegate::OnDownloadPathGenerated( const bool offscreen = !web_preferences || web_preferences->IsOffscreen(); settings.force_detached = offscreen; +#if BUILDFLAG(IS_WIN) + if (settings.filters.empty()) { + const std::wstring extension = settings.default_path.FinalExtension(); + if (!extension.empty()) { + settings.filters = FormatFilterForExtensions( + {base::WideToUTF8(extension)}, {""}, true, true); + } + } +#endif // BUILDFLAG(IS_WIN) + v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); v8::HandleScope scope(isolate); gin_helper::Promise dialog_promise(isolate); @@ -141,11 +270,11 @@ void ElectronDownloadManagerDelegate::OnDownloadPathGenerated( std::ignore = dialog_promise.Then(std::move(dialog_callback)); file_dialog::ShowSaveDialog(settings, std::move(dialog_promise)); } else { - std::move(callback).Run(path, - download::DownloadItem::TARGET_DISPOSITION_PROMPT, - download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, - item->GetMixedContentStatus(), path, absl::nullopt, - download::DOWNLOAD_INTERRUPT_REASON_NONE); + std::move(callback).Run( + path, download::DownloadItem::TARGET_DISPOSITION_PROMPT, + download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, + item->GetMixedContentStatus(), path, base::FilePath(), + std::string() /*mime_type*/, download::DOWNLOAD_INTERRUPT_REASON_NONE); } } @@ -184,8 +313,8 @@ void ElectronDownloadManagerDelegate::OnDownloadSaveDialogDone( std::move(download_callback) .Run(path, download::DownloadItem::TARGET_DISPOSITION_PROMPT, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, - item->GetMixedContentStatus(), path, absl::nullopt, - interrupt_reason); + item->GetMixedContentStatus(), path, base::FilePath(), + std::string() /*mime_type*/, interrupt_reason); } void ElectronDownloadManagerDelegate::Shutdown() { @@ -204,8 +333,8 @@ bool ElectronDownloadManagerDelegate::DetermineDownloadTarget( download::DownloadItem::TARGET_DISPOSITION_OVERWRITE, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, download::DownloadItem::MixedContentStatus::UNKNOWN, - download->GetForcedFilePath(), absl::nullopt, - download::DOWNLOAD_INTERRUPT_REASON_NONE); + download->GetForcedFilePath(), base::FilePath(), + std::string() /*mime_type*/, download::DOWNLOAD_INTERRUPT_REASON_NONE); return true; } @@ -217,7 +346,8 @@ bool ElectronDownloadManagerDelegate::DetermineDownloadTarget( save_path, download::DownloadItem::TARGET_DISPOSITION_OVERWRITE, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, download::DownloadItem::MixedContentStatus::UNKNOWN, save_path, - absl::nullopt, download::DOWNLOAD_INTERRUPT_REASON_NONE); + base::FilePath(), std::string() /*mime_type*/, + download::DOWNLOAD_INTERRUPT_REASON_NONE); return true; } diff --git a/shell/browser/electron_pdf_web_contents_helper_client.cc b/shell/browser/electron_pdf_web_contents_helper_client.cc index 0ddf94fe49cb5..ad0636bec40ac 100644 --- a/shell/browser/electron_pdf_web_contents_helper_client.cc +++ b/shell/browser/electron_pdf_web_contents_helper_client.cc @@ -14,7 +14,7 @@ ElectronPDFWebContentsHelperClient::~ElectronPDFWebContentsHelperClient() = content::RenderFrameHost* ElectronPDFWebContentsHelperClient::FindPdfFrame( content::WebContents* contents) { - content::RenderFrameHost* main_frame = contents->GetMainFrame(); + content::RenderFrameHost* main_frame = contents->GetPrimaryMainFrame(); content::RenderFrameHost* pdf_frame = pdf_frame_util::FindPdfChildFrame(main_frame); return pdf_frame ? pdf_frame : main_frame; diff --git a/shell/browser/electron_permission_manager.cc b/shell/browser/electron_permission_manager.cc index a6902499aaf9f..995a704bb6503 100644 --- a/shell/browser/electron_permission_manager.cc +++ b/shell/browser/electron_permission_manager.cc @@ -9,10 +9,10 @@ #include #include "base/values.h" +#include "content/browser/permissions/permission_util.h" // nogncheck #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/global_routing_id.h" #include "content/public/browser/permission_controller.h" -#include "content/public/browser/permission_type.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -21,14 +21,13 @@ #include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/electron_browser_client.h" #include "shell/browser/electron_browser_main_parts.h" -#include "shell/browser/hid/hid_chooser_context.h" -#include "shell/browser/serial/serial_chooser_context.h" #include "shell/browser/web_contents_permission_helper.h" #include "shell/browser/web_contents_preferences.h" #include "shell/common/gin_converters/content_converter.h" #include "shell/common/gin_converters/frame_converter.h" #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/event_emitter_caller.h" +#include "third_party/blink/public/common/permissions/permission_utils.h" namespace electron { @@ -53,7 +52,7 @@ void PermissionRequestResponseCallbackWrapper( class ElectronPermissionManager::PendingRequest { public: PendingRequest(content::RenderFrameHost* render_frame_host, - const std::vector& permissions, + const std::vector& permissions, StatusesCallback callback) : render_process_id_(render_frame_host->GetProcess()->GetID()), render_frame_id_(render_frame_host->GetGlobalId()), @@ -68,10 +67,10 @@ class ElectronPermissionManager::PendingRequest { if (status == blink::mojom::PermissionStatus::GRANTED) { const auto permission = permissions_[permission_id]; - if (permission == content::PermissionType::MIDI_SYSEX) { + if (permission == blink::PermissionType::MIDI_SYSEX) { content::ChildProcessSecurityPolicy::GetInstance() ->GrantSendMidiSysExMessage(render_process_id_); - } else if (permission == content::PermissionType::GEOLOCATION) { + } else if (permission == blink::PermissionType::GEOLOCATION) { ElectronBrowserMainParts::Get() ->GetGeolocationControl() ->UserDidOptIntoLocationServices(); @@ -98,7 +97,7 @@ class ElectronPermissionManager::PendingRequest { int render_process_id_; content::GlobalRenderFrameHostId render_frame_id_; StatusesCallback callback_; - std::vector permissions_; + std::vector permissions_; std::vector results_; size_t remaining_results_; }; @@ -131,48 +130,50 @@ void ElectronPermissionManager::SetDevicePermissionHandler( device_permission_handler_ = handler; } +void ElectronPermissionManager::SetBluetoothPairingHandler( + const BluetoothPairingHandler& handler) { + bluetooth_pairing_handler_ = handler; +} + void ElectronPermissionManager::RequestPermission( - content::PermissionType permission, + blink::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, StatusCallback response_callback) { RequestPermissionWithDetails(permission, render_frame_host, requesting_origin, - user_gesture, nullptr, - std::move(response_callback)); + user_gesture, {}, std::move(response_callback)); } void ElectronPermissionManager::RequestPermissionWithDetails( - content::PermissionType permission, + blink::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, - const base::DictionaryValue* details, + base::Value::Dict details, StatusCallback response_callback) { RequestPermissionsWithDetails( - std::vector(1, permission), render_frame_host, - requesting_origin, user_gesture, details, + std::vector(1, permission), render_frame_host, + user_gesture, std::move(details), base::BindOnce(PermissionRequestResponseCallbackWrapper, std::move(response_callback))); } void ElectronPermissionManager::RequestPermissions( - const std::vector& permissions, + const std::vector& permissions, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, StatusesCallback response_callback) { - RequestPermissionsWithDetails(permissions, render_frame_host, - requesting_origin, user_gesture, nullptr, - std::move(response_callback)); + RequestPermissionsWithDetails(permissions, render_frame_host, user_gesture, + {}, std::move(response_callback)); } void ElectronPermissionManager::RequestPermissionsWithDetails( - const std::vector& permissions, + const std::vector& permissions, content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, bool user_gesture, - const base::DictionaryValue* details, + base::Value::Dict details, StatusesCallback response_callback) { if (permissions.empty()) { std::move(response_callback).Run({}); @@ -182,11 +183,11 @@ void ElectronPermissionManager::RequestPermissionsWithDetails( if (request_handler_.is_null()) { std::vector statuses; for (auto permission : permissions) { - if (permission == content::PermissionType::MIDI_SYSEX) { + if (permission == blink::PermissionType::MIDI_SYSEX) { content::ChildProcessSecurityPolicy::GetInstance() ->GrantSendMidiSysExMessage( render_frame_host->GetProcess()->GetID()); - } else if (permission == content::PermissionType::GEOLOCATION) { + } else if (permission == blink::PermissionType::GEOLOCATION) { ElectronBrowserMainParts::Get() ->GetGeolocationControl() ->UserDidOptIntoLocationServices(); @@ -207,13 +208,11 @@ void ElectronPermissionManager::RequestPermissionsWithDetails( const auto callback = base::BindRepeating(&ElectronPermissionManager::OnPermissionResponse, base::Unretained(this), request_id, i); - auto mutable_details = - details == nullptr ? base::DictionaryValue() : details->Clone(); - mutable_details.SetStringKey( - "requestingUrl", render_frame_host->GetLastCommittedURL().spec()); - mutable_details.SetBoolKey("isMainFrame", - render_frame_host->GetParent() == nullptr); - request_handler_.Run(web_contents, permission, callback, mutable_details); + details.Set("requestingUrl", + render_frame_host->GetLastCommittedURL().spec()); + details.Set("isMainFrame", render_frame_host->GetParent() == nullptr); + request_handler_.Run(web_contents, permission, callback, + base::Value(std::move(details))); } } @@ -233,25 +232,46 @@ void ElectronPermissionManager::OnPermissionResponse( } void ElectronPermissionManager::ResetPermission( - content::PermissionType permission, + blink::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) {} +void ElectronPermissionManager::RequestPermissionsFromCurrentDocument( + const std::vector& permissions, + content::RenderFrameHost* render_frame_host, + bool user_gesture, + base::OnceCallback&)> + callback) { + RequestPermissionsWithDetails(permissions, render_frame_host, user_gesture, + {}, std::move(callback)); +} + blink::mojom::PermissionStatus ElectronPermissionManager::GetPermissionStatus( - content::PermissionType permission, + blink::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) { - base::DictionaryValue details; - details.SetString("embeddingOrigin", embedding_origin.spec()); - bool granted = CheckPermissionWithDetails(permission, nullptr, - requesting_origin, &details); + base::Value::Dict details; + details.Set("embeddingOrigin", embedding_origin.spec()); + bool granted = CheckPermissionWithDetails(permission, {}, requesting_origin, + std::move(details)); return granted ? blink::mojom::PermissionStatus::GRANTED : blink::mojom::PermissionStatus::DENIED; } +content::PermissionResult +ElectronPermissionManager::GetPermissionResultForOriginWithoutContext( + blink::PermissionType permission, + const url::Origin& origin) { + blink::mojom::PermissionStatus status = + GetPermissionStatus(permission, origin.GetURL(), origin.GetURL()); + return content::PermissionResult( + status, content::PermissionStatusSource::UNSPECIFIED); +} + ElectronPermissionManager::SubscriptionId ElectronPermissionManager::SubscribePermissionStatusChange( - content::PermissionType permission, + blink::PermissionType permission, + content::RenderProcessHost* render_process_host, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, base::RepeatingCallback callback) { @@ -261,11 +281,23 @@ ElectronPermissionManager::SubscribePermissionStatusChange( void ElectronPermissionManager::UnsubscribePermissionStatusChange( SubscriptionId id) {} +void ElectronPermissionManager::CheckBluetoothDevicePair( + gin_helper::Dictionary details, + PairCallback pair_callback) const { + if (bluetooth_pairing_handler_.is_null()) { + base::Value::Dict response; + response.Set("confirmed", false); + std::move(pair_callback).Run(std::move(response)); + } else { + bluetooth_pairing_handler_.Run(details, std::move(pair_callback)); + } +} + bool ElectronPermissionManager::CheckPermissionWithDetails( - content::PermissionType permission, + blink::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, - const base::DictionaryValue* details) const { + base::Value::Dict details) const { if (check_handler_.is_null()) { return true; } @@ -273,129 +305,85 @@ bool ElectronPermissionManager::CheckPermissionWithDetails( render_frame_host ? content::WebContents::FromRenderFrameHost(render_frame_host) : nullptr; - auto mutable_details = - details == nullptr ? base::DictionaryValue() : details->Clone(); if (render_frame_host) { - mutable_details.SetStringKey( - "requestingUrl", render_frame_host->GetLastCommittedURL().spec()); + details.Set("requestingUrl", + render_frame_host->GetLastCommittedURL().spec()); } - mutable_details.SetBoolKey( - "isMainFrame", - render_frame_host && render_frame_host->GetParent() == nullptr); + details.Set("isMainFrame", + render_frame_host && render_frame_host->GetParent() == nullptr); switch (permission) { - case content::PermissionType::AUDIO_CAPTURE: - mutable_details.SetStringKey("mediaType", "audio"); + case blink::PermissionType::AUDIO_CAPTURE: + details.Set("mediaType", "audio"); break; - case content::PermissionType::VIDEO_CAPTURE: - mutable_details.SetStringKey("mediaType", "video"); + case blink::PermissionType::VIDEO_CAPTURE: + details.Set("mediaType", "video"); break; default: break; } return check_handler_.Run(web_contents, permission, requesting_origin, - mutable_details); + base::Value(std::move(details))); } bool ElectronPermissionManager::CheckDevicePermission( - content::PermissionType permission, + blink::PermissionType permission, const url::Origin& origin, - const base::Value* device, - content::RenderFrameHost* render_frame_host) const { - auto* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - api::WebContents* api_web_contents = api::WebContents::From(web_contents); + const base::Value& device, + ElectronBrowserContext* browser_context) const { if (device_permission_handler_.is_null()) { - if (api_web_contents) { - std::vector granted_devices = - api_web_contents->GetGrantedDevices(origin, permission, - render_frame_host); - - for (const auto& granted_device : granted_devices) { - if (permission == - static_cast( - WebContentsPermissionHelper::PermissionType::HID)) { - if (device->FindIntKey(kHidVendorIdKey) != - granted_device.FindIntKey(kHidVendorIdKey) || - device->FindIntKey(kHidProductIdKey) != - granted_device.FindIntKey(kHidProductIdKey)) { - continue; - } - - const auto* serial_number = - granted_device.FindStringKey(kHidSerialNumberKey); - const auto* device_serial_number = - device->FindStringKey(kHidSerialNumberKey); - - if (serial_number && device_serial_number && - *device_serial_number == *serial_number) - return true; - } else if (permission == - static_cast( - WebContentsPermissionHelper::PermissionType::SERIAL)) { -#if BUILDFLAG(IS_WIN) - if (device->FindStringKey(kDeviceInstanceIdKey) == - granted_device.FindStringKey(kDeviceInstanceIdKey)) - return true; -#else - if (device->FindIntKey(kVendorIdKey) != - granted_device.FindIntKey(kVendorIdKey) || - device->FindIntKey(kProductIdKey) != - granted_device.FindIntKey(kProductIdKey) || - *device->FindStringKey(kSerialNumberKey) != - *granted_device.FindStringKey(kSerialNumberKey)) { - continue; - } - -#if BUILDFLAG(IS_MAC) - if (*device->FindStringKey(kUsbDriverKey) != - *granted_device.FindStringKey(kUsbDriverKey)) { - continue; - } -#endif // BUILDFLAG(IS_MAC) - return true; -#endif // BUILDFLAG(IS_WIN) - } - } - } - return false; + return browser_context->CheckDevicePermission(origin, device, permission); } else { v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); v8::HandleScope scope(isolate); v8::Local details = gin::DataObjectBuilder(isolate) .Set("deviceType", permission) .Set("origin", origin.Serialize()) - .Set("device", device->Clone()) - .Set("frame", render_frame_host) + .Set("device", device.Clone()) .Build(); return device_permission_handler_.Run(details); } } void ElectronPermissionManager::GrantDevicePermission( - content::PermissionType permission, + blink::PermissionType permission, const url::Origin& origin, - const base::Value* device, - content::RenderFrameHost* render_frame_host) const { + const base::Value& device, + ElectronBrowserContext* browser_context) const { if (device_permission_handler_.is_null()) { - auto* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - api::WebContents* api_web_contents = api::WebContents::From(web_contents); - if (api_web_contents) - api_web_contents->GrantDevicePermission(origin, device, permission, - render_frame_host); + browser_context->GrantDevicePermission(origin, device, permission); } } +void ElectronPermissionManager::RevokeDevicePermission( + blink::PermissionType permission, + const url::Origin& origin, + const base::Value& device, + ElectronBrowserContext* browser_context) const { + browser_context->RevokeDevicePermission(origin, device, permission); +} + blink::mojom::PermissionStatus -ElectronPermissionManager::GetPermissionStatusForFrame( - content::PermissionType permission, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin) { - base::DictionaryValue details; - bool granted = CheckPermissionWithDetails(permission, render_frame_host, - requesting_origin, &details); +ElectronPermissionManager::GetPermissionStatusForCurrentDocument( + blink::PermissionType permission, + content::RenderFrameHost* render_frame_host) { + base::Value::Dict details; + details.Set("embeddingOrigin", + content::PermissionUtil::GetLastCommittedOriginAsURL( + render_frame_host->GetMainFrame()) + .spec()); + bool granted = CheckPermissionWithDetails( + permission, render_frame_host, + render_frame_host->GetLastCommittedOrigin().GetURL(), std::move(details)); return granted ? blink::mojom::PermissionStatus::GRANTED : blink::mojom::PermissionStatus::DENIED; } +blink::mojom::PermissionStatus +ElectronPermissionManager::GetPermissionStatusForWorker( + blink::PermissionType permission, + content::RenderProcessHost* render_process_host, + const GURL& worker_origin) { + return GetPermissionStatus(permission, worker_origin, worker_origin); +} + } // namespace electron diff --git a/shell/browser/electron_permission_manager.h b/shell/browser/electron_permission_manager.h index 38cedf2ebfda6..3aa980ea22d71 100644 --- a/shell/browser/electron_permission_manager.h +++ b/shell/browser/electron_permission_manager.h @@ -12,9 +12,10 @@ #include "base/containers/id_map.h" #include "content/public/browser/permission_controller_delegate.h" #include "gin/dictionary.h" +#include "shell/browser/electron_browser_context.h" +#include "shell/common/gin_helper/dictionary.h" namespace base { -class DictionaryValue; class Value; } // namespace base @@ -38,68 +39,75 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { base::OnceCallback; using StatusesCallback = base::OnceCallback&)>; + using PairCallback = base::OnceCallback; using RequestHandler = base::RepeatingCallback; using CheckHandler = base::RepeatingCallback; using DeviceCheckHandler = base::RepeatingCallback&)>; + using BluetoothPairingHandler = + base::RepeatingCallback; // Handler to dispatch permission requests in JS. void SetPermissionRequestHandler(const RequestHandler& handler); void SetPermissionCheckHandler(const CheckHandler& handler); void SetDevicePermissionHandler(const DeviceCheckHandler& handler); + void SetBluetoothPairingHandler(const BluetoothPairingHandler& handler); // content::PermissionControllerDelegate: - void RequestPermission(content::PermissionType permission, + void RequestPermission(blink::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, StatusCallback callback) override; - void RequestPermissionWithDetails(content::PermissionType permission, + void RequestPermissionWithDetails(blink::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, - const base::DictionaryValue* details, + base::Value::Dict details, StatusCallback callback); - void RequestPermissions( - const std::vector& permissions, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, - bool user_gesture, - StatusesCallback callback) override; + void RequestPermissions(const std::vector& permissions, + content::RenderFrameHost* render_frame_host, + const GURL& requesting_origin, + bool user_gesture, + StatusesCallback callback) override; + void RequestPermissionsWithDetails( - const std::vector& permissions, + const std::vector& permissions, content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, bool user_gesture, - const base::DictionaryValue* details, + base::Value::Dict details, StatusesCallback callback); - blink::mojom::PermissionStatus GetPermissionStatusForFrame( - content::PermissionType permission, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin) override; - bool CheckPermissionWithDetails(content::PermissionType permission, + void CheckBluetoothDevicePair(gin_helper::Dictionary details, + PairCallback pair_callback) const; + + bool CheckPermissionWithDetails(blink::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, - const base::DictionaryValue* details) const; + base::Value::Dict details) const; - bool CheckDevicePermission(content::PermissionType permission, + bool CheckDevicePermission(blink::PermissionType permission, const url::Origin& origin, - const base::Value* object, - content::RenderFrameHost* render_frame_host) const; + const base::Value& object, + ElectronBrowserContext* browser_context) const; - void GrantDevicePermission(content::PermissionType permission, + void GrantDevicePermission(blink::PermissionType permission, const url::Origin& origin, - const base::Value* object, - content::RenderFrameHost* render_frame_host) const; + const base::Value& object, + ElectronBrowserContext* browser_context) const; + + void RevokeDevicePermission(blink::PermissionType permission, + const url::Origin& origin, + const base::Value& object, + ElectronBrowserContext* browser_context) const; protected: void OnPermissionResponse(int request_id, @@ -107,15 +115,33 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { blink::mojom::PermissionStatus status); // content::PermissionControllerDelegate: - void ResetPermission(content::PermissionType permission, + void ResetPermission(blink::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) override; blink::mojom::PermissionStatus GetPermissionStatus( - content::PermissionType permission, + blink::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) override; + void RequestPermissionsFromCurrentDocument( + const std::vector& permissions, + content::RenderFrameHost* render_frame_host, + bool user_gesture, + base::OnceCallback< + void(const std::vector&)> callback) + override; + content::PermissionResult GetPermissionResultForOriginWithoutContext( + blink::PermissionType permission, + const url::Origin& origin) override; + blink::mojom::PermissionStatus GetPermissionStatusForCurrentDocument( + blink::PermissionType permission, + content::RenderFrameHost* render_frame_host) override; + blink::mojom::PermissionStatus GetPermissionStatusForWorker( + blink::PermissionType permission, + content::RenderProcessHost* render_process_host, + const GURL& worker_origin) override; SubscriptionId SubscribePermissionStatusChange( - content::PermissionType permission, + blink::PermissionType permission, + content::RenderProcessHost* render_process_host, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, base::RepeatingCallback callback) @@ -129,6 +155,7 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate { RequestHandler request_handler_; CheckHandler check_handler_; DeviceCheckHandler device_permission_handler_; + BluetoothPairingHandler bluetooth_pairing_handler_; PendingRequestsMap pending_requests_; }; diff --git a/shell/browser/event_emitter_mixin.cc b/shell/browser/event_emitter_mixin.cc index f13201c64a171..43e052a7715c8 100644 --- a/shell/browser/event_emitter_mixin.cc +++ b/shell/browser/event_emitter_mixin.cc @@ -7,9 +7,7 @@ #include "gin/public/wrapper_info.h" #include "shell/browser/api/electron_api_event_emitter.h" -namespace gin_helper { - -namespace internal { +namespace gin_helper::internal { gin::WrapperInfo kWrapperInfo = {gin::kEmbedderNativeGin}; @@ -40,6 +38,4 @@ v8::Local GetEventEmitterTemplate(v8::Isolate* isolate) { return tmpl; } -} // namespace internal - -} // namespace gin_helper +} // namespace gin_helper::internal diff --git a/shell/browser/event_emitter_mixin.h b/shell/browser/event_emitter_mixin.h index 101e4d5e4591a..4f796c55ea8a2 100644 --- a/shell/browser/event_emitter_mixin.h +++ b/shell/browser/event_emitter_mixin.h @@ -29,7 +29,6 @@ class EventEmitterMixin { template bool Emit(base::StringPiece name, Args&&... args) { v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); v8::Local wrapper; if (!static_cast(this)->GetWrapper(isolate).ToLocal(&wrapper)) diff --git a/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc b/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc index f30b1bd24a62e..b25e082a93d60 100644 --- a/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc +++ b/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc @@ -39,9 +39,7 @@ #include "device/fido/win/webauthn_api.h" #endif // BUILDFLAG(IS_WIN) -namespace extensions { - -namespace api { +namespace extensions::api { namespace { @@ -255,18 +253,18 @@ CryptotokenPrivateCanAppIdGetAttestationFunction::Run() { return RespondNow(Error("no PermissionRequestManager")); // } - // // The created AttestationPermissionRequest deletes itself once complete. - // permission_request_manager->AddRequest( - // web_contents->GetMainFrame(), // Extension API targets a particular - // tab, - // // so select the current main frame to - // // handle the request. - // NewAttestationPermissionRequest( - // origin, - // base::BindOnce( - // &CryptotokenPrivateCanAppIdGetAttestationFunction::Complete, - // this))); - // return RespondLater(); +#if 0 // TODO(MarshallOfSound): why is this commented out? + // The created AttestationPermissionRequest deletes itself once complete. + permission_request_manager->AddRequest( + web_contents->GetPrimaryMainFrame(), + tab, + NewAttestationPermissionRequest( + origin, + base::BindOnce( + &CryptotokenPrivateCanAppIdGetAttestationFunction::Complete, + this))); + return RespondLater(); +#endif #endif } @@ -307,5 +305,4 @@ CryptotokenPrivateRecordSignRequestFunction::Run() { return RespondNow(NoArguments()); } -} // namespace api -} // namespace extensions +} // namespace extensions::api diff --git a/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h b/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h index 4b4dd509e137f..bbfe79338a6c8 100644 --- a/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h +++ b/shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h @@ -14,8 +14,7 @@ class PrefRegistrySyncable; // Implementations for chrome.cryptotokenPrivate API functions. -namespace extensions { -namespace api { +namespace extensions::api { // void CryptotokenRegisterProfilePrefs( // user_prefs::PrefRegistrySyncable* registry); @@ -80,7 +79,6 @@ class CryptotokenPrivateRecordSignRequestFunction : public ExtensionFunction { ResponseAction Run() override; }; -} // namespace api -} // namespace extensions +} // namespace extensions::api #endif // ELECTRON_SHELL_BROWSER_EXTENSIONS_API_CRYPTOTOKEN_PRIVATE_CRYPTOTOKEN_PRIVATE_API_H_ diff --git a/shell/browser/extensions/api/management/electron_management_api_delegate.cc b/shell/browser/extensions/api/management/electron_management_api_delegate.cc index 94eadd90b28dd..0b5558857f85e 100644 --- a/shell/browser/extensions/api/management/electron_management_api_delegate.cc +++ b/shell/browser/extensions/api/management/electron_management_api_delegate.cc @@ -13,7 +13,6 @@ #include "base/strings/strcat.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "chrome/common/extensions/extension_metrics.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/common/webui_url_constants.h" diff --git a/shell/browser/extensions/api/resources_private/resources_private_api.cc b/shell/browser/extensions/api/resources_private/resources_private_api.cc index 48cb45dc2d0ac..d0a2ebfbd694b 100644 --- a/shell/browser/extensions/api/resources_private/resources_private_api.cc +++ b/shell/browser/extensions/api/resources_private/resources_private_api.cc @@ -47,7 +47,6 @@ void AddStringsForPdf(base::DictionaryValue* dict) { {"pageReload", IDS_PDF_PAGE_RELOAD_BUTTON}, {"bookmarks", IDS_PDF_BOOKMARKS}, {"labelPageNumber", IDS_PDF_LABEL_PAGE_NUMBER}, - {"tooltipRotateCW", IDS_PDF_TOOLTIP_ROTATE_CW}, {"tooltipDownload", IDS_PDF_TOOLTIP_DOWNLOAD}, {"tooltipPrint", IDS_PDF_TOOLTIP_PRINT}, {"tooltipFitToPage", IDS_PDF_TOOLTIP_FIT_PAGE}, diff --git a/shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc b/shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc index 7cf0c0ad92de9..7bdb2ef92babc 100644 --- a/shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc +++ b/shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc @@ -87,7 +87,7 @@ bool ElectronRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { } return true; -} // namespace extensions +} bool ElectronRuntimeAPIDelegate::RestartDevice(std::string* error_message) { *error_message = "Restart is not supported in Electron"; diff --git a/shell/browser/extensions/api/streams_private/streams_private_api.cc b/shell/browser/extensions/api/streams_private/streams_private_api.cc index 4b0ef5df249b5..4ef72f4645b59 100644 --- a/shell/browser/extensions/api/streams_private/streams_private_api.cc +++ b/shell/browser/extensions/api/streams_private/streams_private_api.cc @@ -20,23 +20,15 @@ namespace extensions { void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent( const std::string& extension_id, - const std::string& view_id, + const std::string& stream_id, bool embedded, int frame_tree_node_id, - int render_process_id, - int render_frame_id, blink::mojom::TransferrableURLLoaderPtr transferrable_loader, const GURL& original_url) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - content::WebContents* web_contents = nullptr; - if (frame_tree_node_id != -1) { - web_contents = - content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); - } else { - web_contents = content::WebContents::FromRenderFrameHost( - content::RenderFrameHost::FromID(render_process_id, render_frame_id)); - } + content::WebContents* web_contents = + content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); if (!web_contents) return; @@ -66,8 +58,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent( tab_id, embedded, handler_url, extension_id, std::move(transferrable_loader), original_url); extensions::MimeHandlerStreamManager::Get(browser_context) - ->AddStream(view_id, std::move(stream_container), frame_tree_node_id, - render_process_id, render_frame_id); + ->AddStream(stream_id, std::move(stream_container), frame_tree_node_id); } } // namespace extensions diff --git a/shell/browser/extensions/api/streams_private/streams_private_api.h b/shell/browser/extensions/api/streams_private/streams_private_api.h index b5c6e573c4d8a..a580e97175fb2 100644 --- a/shell/browser/extensions/api/streams_private/streams_private_api.h +++ b/shell/browser/extensions/api/streams_private/streams_private_api.h @@ -15,24 +15,16 @@ namespace extensions { // rename and move it to make that clear. https://crbug.com/890401. class StreamsPrivateAPI { public: - // Send the onExecuteMimeTypeHandler event to |extension_id|. If the viewer is - // being opened in a BrowserPlugin, specify a non-empty |view_id| of the - // plugin. |embedded| should be set to whether the document is embedded - // within another document. The |frame_tree_node_id| parameter is used for the - // top level plugins case. (PDF, etc). If this parameter has a valid value - // then it overrides the |render_process_id| and |render_frame_id| parameters. - // The |render_process_id| is the id of the renderer process. The - // |render_frame_id| is the routing id of the RenderFrameHost. - // - // If the network service is not enabled, |stream| is used; otherwise, - // |transferrable_loader| and |original_url| are used instead. + // Send the onExecuteMimeTypeHandler event to |extension_id|. A non-empty + // |stream_id| will be used to identify the created stream during + // MimeHandlerViewGuest creation. |embedded| should be set to whether the + // document is embedded within another document. The |frame_tree_node_id| + // parameter is used for the top level plugins case. (PDF, etc). static void SendExecuteMimeTypeHandlerEvent( const std::string& extension_id, - const std::string& view_id, + const std::string& stream_id, bool embedded, int frame_tree_node_id, - int render_process_id, - int render_frame_id, blink::mojom::TransferrableURLLoaderPtr transferrable_loader, const GURL& original_url); }; diff --git a/shell/browser/extensions/electron_browser_context_keyed_service_factories.cc b/shell/browser/extensions/electron_browser_context_keyed_service_factories.cc index 5b6213f260b40..7fcede792439a 100644 --- a/shell/browser/extensions/electron_browser_context_keyed_service_factories.cc +++ b/shell/browser/extensions/electron_browser_context_keyed_service_factories.cc @@ -7,8 +7,7 @@ #include "extensions/browser/updater/update_service_factory.h" #include "shell/browser/extensions/electron_extension_system_factory.h" -namespace extensions { -namespace electron { +namespace extensions::electron { void EnsureBrowserContextKeyedServiceFactoriesBuilt() { // TODO(rockot): Remove this once UpdateService is supported across all @@ -18,5 +17,4 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() { ElectronExtensionSystemFactory::GetInstance(); } -} // namespace electron -} // namespace extensions +} // namespace extensions::electron diff --git a/shell/browser/extensions/electron_browser_context_keyed_service_factories.h b/shell/browser/extensions/electron_browser_context_keyed_service_factories.h index 7e9707d9cac33..b173755a9c5db 100644 --- a/shell/browser/extensions/electron_browser_context_keyed_service_factories.h +++ b/shell/browser/extensions/electron_browser_context_keyed_service_factories.h @@ -5,14 +5,12 @@ #ifndef ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_ #define ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_ -namespace extensions { -namespace electron { +namespace extensions::electron { // Ensures the existence of any BrowserContextKeyedServiceFactory provided by // the core extensions code. void EnsureBrowserContextKeyedServiceFactoriesBuilt(); -} // namespace electron -} // namespace extensions +} // namespace extensions::electron #endif // ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_ diff --git a/shell/browser/extensions/electron_component_extension_resource_manager.cc b/shell/browser/extensions/electron_component_extension_resource_manager.cc index 85ce840ee88f5..40e37cdffa7d0 100644 --- a/shell/browser/extensions/electron_component_extension_resource_manager.cc +++ b/shell/browser/extensions/electron_component_extension_resource_manager.cc @@ -39,8 +39,8 @@ ElectronComponentExtensionResourceManager:: pdf_extension_util::AddAdditionalData(true, &pdf_strings); ui::TemplateReplacements pdf_viewer_replacements; - ui::TemplateReplacementsFromDictionaryValue( - base::Value::AsDictionaryValue(pdf_strings), &pdf_viewer_replacements); + ui::TemplateReplacementsFromDictionaryValue(pdf_strings.GetDict(), + &pdf_viewer_replacements); extension_template_replacements_[extension_misc::kPdfExtensionId] = std::move(pdf_viewer_replacements); #endif diff --git a/shell/browser/extensions/electron_extension_message_filter.cc b/shell/browser/extensions/electron_extension_message_filter.cc index 688c76c024f04..e01dd2b21209f 100644 --- a/shell/browser/extensions/electron_extension_message_filter.cc +++ b/shell/browser/extensions/electron_extension_message_filter.cc @@ -14,7 +14,6 @@ #include "base/memory/ptr_util.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -40,7 +39,7 @@ ElectronExtensionMessageFilter::ElectronExtensionMessageFilter( int render_process_id, content::BrowserContext* browser_context) : BrowserMessageFilter(kExtensionFilteredMessageClasses, - base::size(kExtensionFilteredMessageClasses)), + std::size(kExtensionFilteredMessageClasses)), render_process_id_(render_process_id), browser_context_(browser_context) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -78,7 +77,7 @@ void ElectronExtensionMessageFilter::OnDestruct() const { if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { delete this; } else { - base::DeleteSoon(FROM_HERE, {BrowserThread::UI}, this); + content::GetUIThreadTaskRunner({})->DeleteSoon(FROM_HERE, this); } } diff --git a/shell/browser/extensions/electron_extension_system.cc b/shell/browser/extensions/electron_extension_system.cc index 20c2cf546ea52..be8485e912e2d 100644 --- a/shell/browser/extensions/electron_extension_system.cc +++ b/shell/browser/extensions/electron_extension_system.cc @@ -13,8 +13,8 @@ #include "base/files/file_util.h" #include "base/json/json_string_value_serializer.h" #include "base/path_service.h" -#include "base/task/post_task.h" #include "chrome/common/chrome_paths.h" +#include "chrome/grit/browser_resources.h" #include "components/value_store/value_store_factory_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -23,7 +23,6 @@ #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "electron/buildflags/buildflags.h" -#include "electron/grit/electron_resources.h" #include "extensions/browser/api/app_runtime/app_runtime_api.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/info_map.h" @@ -204,11 +203,12 @@ AppSorting* ElectronExtensionSystem::app_sorting() { void ElectronExtensionSystem::RegisterExtensionWithRequestContexts( const Extension* extension, base::OnceClosure callback) { - base::PostTaskAndReply(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&InfoMap::AddExtension, info_map(), - base::RetainedRef(extension), - base::Time::Now(), false, false), - std::move(callback)); + content::GetIOThreadTaskRunner({})->PostTaskAndReply( + FROM_HERE, + base::BindOnce(&InfoMap::AddExtension, info_map(), + base::RetainedRef(extension), base::Time::Now(), false, + false), + std::move(callback)); } void ElectronExtensionSystem::UnregisterExtensionWithRequestContexts( diff --git a/shell/browser/extensions/electron_extensions_api_client.cc b/shell/browser/extensions/electron_extensions_api_client.cc index b8ac568e10722..1a4c24700b9fc 100644 --- a/shell/browser/extensions/electron_extensions_api_client.cc +++ b/shell/browser/extensions/electron_extensions_api_client.cc @@ -19,7 +19,6 @@ #if BUILDFLAG(ENABLE_PRINTING) #include "components/printing/browser/print_manager_utils.h" -#include "shell/browser/printing/print_preview_message_handler.h" #include "shell/browser/printing/print_view_manager_electron.h" #endif @@ -86,7 +85,6 @@ MessagingDelegate* ElectronExtensionsAPIClient::GetMessagingDelegate() { void ElectronExtensionsAPIClient::AttachWebContentsHelpers( content::WebContents* web_contents) const { #if BUILDFLAG(ENABLE_PRINTING) - electron::PrintPreviewMessageHandler::CreateForWebContents(web_contents); electron::PrintViewManagerElectron::CreateForWebContents(web_contents); #endif diff --git a/shell/browser/extensions/electron_extensions_browser_client.cc b/shell/browser/extensions/electron_extensions_browser_client.cc index 26007fc9069dd..bf1fc1da6e87e 100644 --- a/shell/browser/extensions/electron_extensions_browser_client.cc +++ b/shell/browser/extensions/electron_extensions_browser_client.cc @@ -4,12 +4,12 @@ #include "shell/browser/extensions/electron_extensions_browser_client.h" +#include #include #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/path_service.h" -#include "base/task/post_task.h" #include "build/build_config.h" #include "chrome/browser/extensions/chrome_url_request_util.h" #include "chrome/common/chrome_paths.h" @@ -298,11 +298,11 @@ ElectronExtensionsBrowserClient::GetComponentExtensionResourceManager() { void ElectronExtensionsBrowserClient::BroadcastEventToRenderers( extensions::events::HistogramValue histogram_value, const std::string& event_name, - std::unique_ptr args, + base::Value::List args, bool dispatch_to_off_the_record_profiles) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &ElectronExtensionsBrowserClient::BroadcastEventToRenderers, base::Unretained(this), histogram_value, event_name, @@ -310,12 +310,12 @@ void ElectronExtensionsBrowserClient::BroadcastEventToRenderers( return; } - auto event = std::make_unique( - histogram_value, event_name, std::move(*args).TakeListDeprecated()); - auto& context_map = ElectronBrowserContext::browser_context_map(); - for (auto const& entry : context_map) { - if (entry.second) { - extensions::EventRouter::Get(entry.second.get()) + auto event = std::make_unique(histogram_value, event_name, + args.Clone()); + for (auto const& [key, browser_context] : + ElectronBrowserContext::browser_context_map()) { + if (browser_context) { + extensions::EventRouter::Get(browser_context.get()) ->BroadcastEvent(std::move(event)); } } diff --git a/shell/browser/extensions/electron_extensions_browser_client.h b/shell/browser/extensions/electron_extensions_browser_client.h index aaee2bd9845ef..7681112a75d7a 100644 --- a/shell/browser/extensions/electron_extensions_browser_client.h +++ b/shell/browser/extensions/electron_extensions_browser_client.h @@ -109,7 +109,7 @@ class ElectronExtensionsBrowserClient void BroadcastEventToRenderers( extensions::events::HistogramValue histogram_value, const std::string& event_name, - std::unique_ptr args, + base::Value::List args, bool dispatch_to_off_the_record_profiles) override; extensions::ExtensionCache* GetExtensionCache() override; bool IsBackgroundUpdateAllowed() override; diff --git a/shell/browser/extensions/electron_messaging_delegate.cc b/shell/browser/extensions/electron_messaging_delegate.cc index 3d05445222416..a2f509ea655c6 100644 --- a/shell/browser/extensions/electron_messaging_delegate.cc +++ b/shell/browser/extensions/electron_messaging_delegate.cc @@ -15,6 +15,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "electron/shell/common/extensions/api/tabs.h" #include "extensions/browser/api/messaging/extension_message_port.h" #include "extensions/browser/api/messaging/native_message_host.h" #include "extensions/browser/extension_api_frame_id_map.h" @@ -44,17 +45,13 @@ ElectronMessagingDelegate::MaybeGetTabInfo(content::WebContents* web_contents) { if (web_contents) { auto* api_contents = electron::api::WebContents::From(web_contents); if (api_contents) { - auto tab = std::make_unique(); - tab->SetWithoutPathExpansion( - "id", std::make_unique(api_contents->ID())); - tab->SetWithoutPathExpansion( - "url", std::make_unique(api_contents->GetURL().spec())); - tab->SetWithoutPathExpansion( - "title", std::make_unique(api_contents->GetTitle())); - tab->SetWithoutPathExpansion( - "audible", - std::make_unique(api_contents->IsCurrentlyAudible())); - return tab; + api::tabs::Tab tab; + tab.id = std::make_unique(api_contents->ID()); + tab.url = std::make_unique(api_contents->GetURL().spec()); + tab.title = std::make_unique( + base::UTF16ToUTF8(api_contents->GetTitle())); + tab.audible = std::make_unique(api_contents->IsCurrentlyAudible()); + return tab.ToValue(); } } return nullptr; @@ -75,13 +72,40 @@ std::unique_ptr ElectronMessagingDelegate::CreateReceiverForTab( const std::string& extension_id, const PortId& receiver_port_id, content::WebContents* receiver_contents, - int receiver_frame_id) { + int receiver_frame_id, + const std::string& receiver_document_id) { // Frame ID -1 is every frame in the tab. - bool include_child_frames = receiver_frame_id == -1; - content::RenderFrameHost* receiver_rfh = - include_child_frames ? receiver_contents->GetMainFrame() - : ExtensionApiFrameIdMap::GetRenderFrameHostById( - receiver_contents, receiver_frame_id); + bool include_child_frames = + receiver_frame_id == -1 && receiver_document_id.empty(); + + content::RenderFrameHost* receiver_rfh = nullptr; + if (include_child_frames) { + // The target is the active outermost main frame of the WebContents. + receiver_rfh = receiver_contents->GetPrimaryMainFrame(); + } else if (!receiver_document_id.empty()) { + ExtensionApiFrameIdMap::DocumentId document_id = + ExtensionApiFrameIdMap::DocumentIdFromString(receiver_document_id); + + // Return early for invalid documentIds. + if (!document_id) + return nullptr; + + receiver_rfh = + ExtensionApiFrameIdMap::Get()->GetRenderFrameHostByDocumentId( + document_id); + + // If both |document_id| and |receiver_frame_id| are provided they + // should find the same RenderFrameHost, if not return early. + if (receiver_frame_id != -1 && + ExtensionApiFrameIdMap::GetRenderFrameHostById( + receiver_contents, receiver_frame_id) != receiver_rfh) { + return nullptr; + } + } else { + DCHECK_GT(receiver_frame_id, -1); + receiver_rfh = ExtensionApiFrameIdMap::GetRenderFrameHostById( + receiver_contents, receiver_frame_id); + } if (!receiver_rfh) return nullptr; diff --git a/shell/browser/extensions/electron_messaging_delegate.h b/shell/browser/extensions/electron_messaging_delegate.h index ac82d85ca2029..3c0942e654245 100644 --- a/shell/browser/extensions/electron_messaging_delegate.h +++ b/shell/browser/extensions/electron_messaging_delegate.h @@ -37,7 +37,8 @@ class ElectronMessagingDelegate : public MessagingDelegate { const std::string& extension_id, const PortId& receiver_port_id, content::WebContents* receiver_contents, - int receiver_frame_id) override; + int receiver_frame_id, + const std::string& receiver_document_id) override; std::unique_ptr CreateReceiverForNativeApp( content::BrowserContext* browser_context, base::WeakPtr channel_delegate, diff --git a/shell/browser/file_select_helper.cc b/shell/browser/file_select_helper.cc index 6980915f6358b..dbd8b341fb673 100644 --- a/shell/browser/file_select_helper.cc +++ b/shell/browser/file_select_helper.cc @@ -22,6 +22,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/platform_util.h" #include "chrome/common/pref_names.h" +#include "chrome/grit/generated_resources.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -31,7 +32,6 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" -#include "electron/grit/electron_resources.h" #include "net/base/filename_util.h" #include "net/base/mime_util.h" #include "shell/browser/api/electron_api_web_contents.h" diff --git a/shell/browser/font_defaults.cc b/shell/browser/font_defaults.cc index 89fd78281b369..a4ac516fa24e4 100644 --- a/shell/browser/font_defaults.cc +++ b/shell/browser/font_defaults.cc @@ -103,7 +103,7 @@ const FontDefault kFontDefaults[] = { IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN}, #endif }; -const size_t kFontDefaultsLength = base::size(kFontDefaults); +const size_t kFontDefaultsLength = std::size(kFontDefaults); // ^^^^^ DO NOT EDIT ^^^^^ diff --git a/shell/browser/hid/electron_hid_delegate.cc b/shell/browser/hid/electron_hid_delegate.cc index 69d7f5e921956..0fef6977e96aa 100644 --- a/shell/browser/hid/electron_hid_delegate.cc +++ b/shell/browser/hid/electron_hid_delegate.cc @@ -8,19 +8,25 @@ #include #include "base/command_line.h" +#include "base/containers/contains.h" +#include "chrome/common/chrome_features.h" #include "content/public/browser/web_contents.h" #include "services/device/public/cpp/hid/hid_switches.h" +#include "shell/browser/electron_permission_manager.h" #include "shell/browser/hid/hid_chooser_context.h" #include "shell/browser/hid/hid_chooser_context_factory.h" #include "shell/browser/hid/hid_chooser_controller.h" #include "shell/browser/web_contents_permission_helper.h" +#include "third_party/blink/public/common/permissions/permission_utils.h" + +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/common/constants.h" +#endif // BUILDFLAG(ENABLE_EXTENSIONS) namespace { electron::HidChooserContext* GetChooserContext( - content::RenderFrameHost* frame) { - auto* web_contents = content::WebContents::FromRenderFrameHost(frame); - auto* browser_context = web_contents->GetBrowserContext(); + content::BrowserContext* browser_context) { return electron::HidChooserContextFactory::GetForBrowserContext( browser_context); } @@ -36,9 +42,11 @@ ElectronHidDelegate::~ElectronHidDelegate() = default; std::unique_ptr ElectronHidDelegate::RunChooser( content::RenderFrameHost* render_frame_host, std::vector filters, + std::vector exclusion_filters, content::HidChooser::Callback callback) { - electron::HidChooserContext* chooser_context = - GetChooserContext(render_frame_host); + DCHECK(render_frame_host); + auto* chooser_context = + GetChooserContext(render_frame_host->GetBrowserContext()); if (!device_observation_.IsObserving()) device_observation_.Observe(chooser_context); @@ -47,7 +55,7 @@ std::unique_ptr ElectronHidDelegate::RunChooser( DeleteControllerForFrame(render_frame_host); } AddControllerForFrame(render_frame_host, std::move(filters), - std::move(callback)); + std::move(exclusion_filters), std::move(callback)); // Return a nullptr because the return value isn't used for anything, eg // there is no mechanism to cancel navigator.hid.requestDevice(). The return @@ -57,67 +65,80 @@ std::unique_ptr ElectronHidDelegate::RunChooser( } bool ElectronHidDelegate::CanRequestDevicePermission( - content::RenderFrameHost* render_frame_host) { - auto* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - auto* permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - return permission_helper->CheckHIDAccessPermission( - web_contents->GetMainFrame()->GetLastCommittedOrigin()); + content::BrowserContext* browser_context, + const url::Origin& origin) { + base::Value::Dict details; + details.Set("securityOrigin", origin.GetURL().spec()); + auto* permission_manager = static_cast( + browser_context->GetPermissionControllerDelegate()); + return permission_manager->CheckPermissionWithDetails( + static_cast( + WebContentsPermissionHelper::PermissionType::HID), + nullptr, origin.GetURL(), std::move(details)); } bool ElectronHidDelegate::HasDevicePermission( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, + const url::Origin& origin, const device::mojom::HidDeviceInfo& device) { - auto* chooser_context = GetChooserContext(render_frame_host); - const auto& origin = - render_frame_host->GetMainFrame()->GetLastCommittedOrigin(); - return chooser_context->HasDevicePermission(origin, device, - render_frame_host); + return GetChooserContext(browser_context) + ->HasDevicePermission(origin, device); } void ElectronHidDelegate::RevokeDevicePermission( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, + const url::Origin& origin, const device::mojom::HidDeviceInfo& device) { - // TODO(jkleinsc) implement this for - // https://chromium-review.googlesource.com/c/chromium/src/+/3297868 + return GetChooserContext(browser_context) + ->RevokeDevicePermission(origin, device); } device::mojom::HidManager* ElectronHidDelegate::GetHidManager( - content::RenderFrameHost* render_frame_host) { - auto* chooser_context = GetChooserContext(render_frame_host); - return chooser_context->GetHidManager(); + content::BrowserContext* browser_context) { + return GetChooserContext(browser_context)->GetHidManager(); } -void ElectronHidDelegate::AddObserver( - content::RenderFrameHost* render_frame_host, - Observer* observer) { +void ElectronHidDelegate::AddObserver(content::BrowserContext* browser_context, + Observer* observer) { observer_list_.AddObserver(observer); - auto* chooser_context = GetChooserContext(render_frame_host); + auto* chooser_context = GetChooserContext(browser_context); if (!device_observation_.IsObserving()) device_observation_.Observe(chooser_context); } void ElectronHidDelegate::RemoveObserver( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, content::HidDelegate::Observer* observer) { observer_list_.RemoveObserver(observer); } const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, const std::string& guid) { - auto* chooser_context = GetChooserContext(render_frame_host); + auto* chooser_context = GetChooserContext(browser_context); return chooser_context->GetDeviceInfo(guid); } bool ElectronHidDelegate::IsFidoAllowedForOrigin( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, const url::Origin& origin) { return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableHidBlocklist); } +bool ElectronHidDelegate::IsServiceWorkerAllowedForOrigin( + const url::Origin& origin) { +#if BUILDFLAG(ENABLE_EXTENSIONS) + // WebHID is only available on extension service workers with feature flag + // enabled for now. + if (base::FeatureList::IsEnabled( + features::kEnableWebHidOnExtensionServiceWorker) && + origin.scheme() == extensions::kExtensionScheme) + return true; +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + return false; +} + void ElectronHidDelegate::OnDeviceAdded( const device::mojom::HidDeviceInfo& device_info) { for (auto& observer : observer_list_) @@ -156,12 +177,13 @@ HidChooserController* ElectronHidDelegate::ControllerForFrame( HidChooserController* ElectronHidDelegate::AddControllerForFrame( content::RenderFrameHost* render_frame_host, std::vector filters, + std::vector exclusion_filters, content::HidChooser::Callback callback) { auto* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); auto controller = std::make_unique( - render_frame_host, std::move(filters), std::move(callback), web_contents, - weak_factory_.GetWeakPtr()); + render_frame_host, std::move(filters), std::move(exclusion_filters), + std::move(callback), web_contents, weak_factory_.GetWeakPtr()); controller_map_.insert( std::make_pair(render_frame_host, std::move(controller))); return ControllerForFrame(render_frame_host); diff --git a/shell/browser/hid/electron_hid_delegate.h b/shell/browser/hid/electron_hid_delegate.h index 1b243c6ac15ee..2b09fa84f92bc 100644 --- a/shell/browser/hid/electron_hid_delegate.h +++ b/shell/browser/hid/electron_hid_delegate.h @@ -31,25 +31,29 @@ class ElectronHidDelegate : public content::HidDelegate, std::unique_ptr RunChooser( content::RenderFrameHost* render_frame_host, std::vector filters, + std::vector exclusion_filters, content::HidChooser::Callback callback) override; - bool CanRequestDevicePermission( - content::RenderFrameHost* render_frame_host) override; - bool HasDevicePermission(content::RenderFrameHost* render_frame_host, + bool CanRequestDevicePermission(content::BrowserContext* browser_context, + const url::Origin& origin) override; + bool HasDevicePermission(content::BrowserContext* browser_context, + const url::Origin& origin, const device::mojom::HidDeviceInfo& device) override; void RevokeDevicePermission( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, + const url::Origin& origin, const device::mojom::HidDeviceInfo& device) override; device::mojom::HidManager* GetHidManager( - content::RenderFrameHost* render_frame_host) override; - void AddObserver(content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context) override; + void AddObserver(content::BrowserContext* browser_context, content::HidDelegate::Observer* observer) override; - void RemoveObserver(content::RenderFrameHost* render_frame_host, + void RemoveObserver(content::BrowserContext* browser_context, content::HidDelegate::Observer* observer) override; const device::mojom::HidDeviceInfo* GetDeviceInfo( - content::RenderFrameHost* render_frame_host, + content::BrowserContext* browser_context, const std::string& guid) override; - bool IsFidoAllowedForOrigin(content::RenderFrameHost* render_frame_host, + bool IsFidoAllowedForOrigin(content::BrowserContext* browser_context, const url::Origin& origin) override; + bool IsServiceWorkerAllowedForOrigin(const url::Origin& origin) override; // HidChooserContext::DeviceObserver: void OnDeviceAdded(const device::mojom::HidDeviceInfo&) override; @@ -67,6 +71,7 @@ class ElectronHidDelegate : public content::HidDelegate, HidChooserController* AddControllerForFrame( content::RenderFrameHost* render_frame_host, std::vector filters, + std::vector exclusion_filters, content::HidChooser::Callback callback); base::ScopedObservationGrantHIDDevicePermission( - origin, DeviceInfoToValue(device), render_frame_host); + auto* permission_manager = static_cast( + browser_context_->GetPermissionControllerDelegate()); + + permission_manager->GrantDevicePermission( + static_cast( + WebContentsPermissionHelper::PermissionType::HID), + origin, DeviceInfoToValue(device), browser_context_); } else { ephemeral_devices_[origin].insert(device.guid); } } +void HidChooserContext::RevokeDevicePermission( + const url::Origin& origin, + const device::mojom::HidDeviceInfo& device) { + DCHECK(base::Contains(devices_, device.guid)); + if (CanStorePersistentEntry(device)) { + RevokePersistentDevicePermission(origin, device); + } else { + RevokeEphemeralDevicePermission(origin, device); + } + api::Session* session = api::Session::FromBrowserContext(browser_context_); + if (session) { + v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); + v8::HandleScope scope(isolate); + gin_helper::Dictionary details = + gin_helper::Dictionary::CreateEmpty(isolate); + details.Set("device", device.Clone()); + details.Set("origin", origin.Serialize()); + session->Emit("hid-device-revoked", details); + } +} + +void HidChooserContext::RevokePersistentDevicePermission( + const url::Origin& origin, + const device::mojom::HidDeviceInfo& device) { + auto* permission_manager = static_cast( + browser_context_->GetPermissionControllerDelegate()); + permission_manager->RevokeDevicePermission( + static_cast( + WebContentsPermissionHelper::PermissionType::HID), + origin, DeviceInfoToValue(device), browser_context_); + RevokeEphemeralDevicePermission(origin, device); +} + +void HidChooserContext::RevokeEphemeralDevicePermission( + const url::Origin& origin, + const device::mojom::HidDeviceInfo& device) { + auto it = ephemeral_devices_.find(origin); + if (it != ephemeral_devices_.end()) { + std::set& devices = it->second; + for (auto guid = devices.begin(); guid != devices.end();) { + DCHECK(base::Contains(devices_, *guid)); + + if (devices_[*guid]->physical_device_id != device.physical_device_id) { + ++guid; + continue; + } + + guid = devices.erase(guid); + if (devices.empty()) + ephemeral_devices_.erase(it); + } + } +} + bool HidChooserContext::HasDevicePermission( const url::Origin& origin, - const device::mojom::HidDeviceInfo& device, - content::RenderFrameHost* render_frame_host) { + const device::mojom::HidDeviceInfo& device) { if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableHidBlocklist) && - device::HidBlocklist::IsDeviceExcluded(device)) + device.is_excluded_by_blocklist) return false; auto it = ephemeral_devices_.find(origin); @@ -114,12 +176,12 @@ bool HidChooserContext::HasDevicePermission( return true; } - auto* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - auto* permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - return permission_helper->CheckHIDDevicePermission( - origin, DeviceInfoToValue(device), render_frame_host); + auto* permission_manager = static_cast( + browser_context_->GetPermissionControllerDelegate()); + return permission_manager->CheckDevicePermission( + static_cast( + WebContentsPermissionHelper::PermissionType::HID), + origin, DeviceInfoToValue(device), browser_context_); } void HidChooserContext::AddDeviceObserver(DeviceObserver* observer) { diff --git a/shell/browser/hid/hid_chooser_context.h b/shell/browser/hid/hid_chooser_context.h index a9c2f7e1def98..6e7bf2262f642 100644 --- a/shell/browser/hid/hid_chooser_context.h +++ b/shell/browser/hid/hid_chooser_context.h @@ -16,7 +16,6 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/unguessable_token.h" -#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -74,11 +73,11 @@ class HidChooserContext : public KeyedService, // HID-specific interface for granting and checking permissions. void GrantDevicePermission(const url::Origin& origin, - const device::mojom::HidDeviceInfo& device, - content::RenderFrameHost* render_frame_host); + const device::mojom::HidDeviceInfo& device); + void RevokeDevicePermission(const url::Origin& origin, + const device::mojom::HidDeviceInfo& device); bool HasDevicePermission(const url::Origin& origin, - const device::mojom::HidDeviceInfo& device, - content::RenderFrameHost* render_frame_host); + const device::mojom::HidDeviceInfo& device); // For ScopedObserver. void AddDeviceObserver(DeviceObserver* observer); @@ -111,6 +110,14 @@ class HidChooserContext : public KeyedService, std::vector devices); void OnHidManagerConnectionError(); + // HID-specific interface for revoking device permissions. + void RevokePersistentDevicePermission( + const url::Origin& origin, + const device::mojom::HidDeviceInfo& device); + void RevokeEphemeralDevicePermission( + const url::Origin& origin, + const device::mojom::HidDeviceInfo& device); + ElectronBrowserContext* browser_context_; bool is_initialized_ = false; diff --git a/shell/browser/hid/hid_chooser_controller.cc b/shell/browser/hid/hid_chooser_controller.cc index 7000999a0c1af..8e4fbd5443e99 100644 --- a/shell/browser/hid/hid_chooser_controller.cc +++ b/shell/browser/hid/hid_chooser_controller.cc @@ -20,6 +20,7 @@ #include "shell/browser/javascript_environment.h" #include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/content_converter.h" +#include "shell/common/gin_converters/hid_device_info_converter.h" #include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/node_includes.h" @@ -28,48 +29,64 @@ namespace { -std::string PhysicalDeviceIdFromDeviceInfo( - const device::mojom::HidDeviceInfo& device) { - // A single physical device may expose multiple HID interfaces, each - // represented by a HidDeviceInfo object. When a device exposes multiple - // HID interfaces, the HidDeviceInfo objects will share a common - // |physical_device_id|. Group these devices so that a single chooser item - // is shown for each physical device. If a device's physical device ID is - // empty, use its GUID instead. - return device.physical_device_id.empty() ? device.guid - : device.physical_device_id; -} - -} // namespace - -namespace gin { +bool FilterMatch(const blink::mojom::HidDeviceFilterPtr& filter, + const device::mojom::HidDeviceInfo& device) { + if (filter->device_ids) { + if (filter->device_ids->is_vendor()) { + if (filter->device_ids->get_vendor() != device.vendor_id) + return false; + } else if (filter->device_ids->is_vendor_and_product()) { + const auto& vendor_and_product = + filter->device_ids->get_vendor_and_product(); + if (vendor_and_product->vendor != device.vendor_id) + return false; + if (vendor_and_product->product != device.product_id) + return false; + } + } -template <> -struct Converter { - static v8::Local ToV8( - v8::Isolate* isolate, - const device::mojom::HidDeviceInfoPtr& device) { - base::Value value = electron::HidChooserContext::DeviceInfoToValue(*device); - value.SetStringKey("deviceId", PhysicalDeviceIdFromDeviceInfo(*device)); - return gin::ConvertToV8(isolate, value); + if (filter->usage) { + if (filter->usage->is_page()) { + const uint16_t usage_page = filter->usage->get_page(); + auto find_it = + std::find_if(device.collections.begin(), device.collections.end(), + [=](const device::mojom::HidCollectionInfoPtr& c) { + return usage_page == c->usage->usage_page; + }); + if (find_it == device.collections.end()) + return false; + } else if (filter->usage->is_usage_and_page()) { + const auto& usage_and_page = filter->usage->get_usage_and_page(); + auto find_it = std::find_if( + device.collections.begin(), device.collections.end(), + [&usage_and_page](const device::mojom::HidCollectionInfoPtr& c) { + return usage_and_page->usage_page == c->usage->usage_page && + usage_and_page->usage == c->usage->usage; + }); + if (find_it == device.collections.end()) + return false; + } } -}; + return true; +} -} // namespace gin +} // namespace namespace electron { HidChooserController::HidChooserController( content::RenderFrameHost* render_frame_host, std::vector filters, + std::vector exclusion_filters, content::HidChooser::Callback callback, content::WebContents* web_contents, base::WeakPtr hid_delegate) : WebContentsObserver(web_contents), filters_(std::move(filters)), + exclusion_filters_(std::move(exclusion_filters)), callback_(std::move(callback)), origin_(content::WebContents::FromRenderFrameHost(render_frame_host) - ->GetMainFrame() + ->GetPrimaryMainFrame() ->GetLastCommittedOrigin()), frame_tree_node_id_(render_frame_host->GetFrameTreeNodeId()), hid_delegate_(hid_delegate), @@ -88,6 +105,19 @@ HidChooserController::~HidChooserController() { std::move(callback_).Run(std::vector()); } +// static +std::string HidChooserController::PhysicalDeviceIdFromDeviceInfo( + const device::mojom::HidDeviceInfo& device) { + // A single physical device may expose multiple HID interfaces, each + // represented by a HidDeviceInfo object. When a device exposes multiple + // HID interfaces, the HidDeviceInfo objects will share a common + // |physical_device_id|. Group these devices so that a single chooser item + // is shown for each physical device. If a device's physical device ID is + // empty, use its GUID instead. + return device.physical_device_id.empty() ? device.guid + : device.physical_device_id; +} + api::Session* HidChooserController::GetSession() { if (!web_contents()) { return nullptr; @@ -166,8 +196,7 @@ void HidChooserController::OnDeviceChosen(gin::Arguments* args) { std::vector devices; devices.reserve(device_infos.size()); for (auto& device : device_infos) { - chooser_context_->GrantDevicePermission(origin_, *device, - web_contents()->GetMainFrame()); + chooser_context_->GrantDevicePermission(origin_, *device); devices.push_back(device->Clone()); } RunCallback(std::move(devices)); @@ -232,7 +261,7 @@ bool HidChooserController::DisplayDevice( if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableHidBlocklist)) { // Do not pass the device to the chooser if it is excluded by the blocklist. - if (device::HidBlocklist::IsDeviceExcluded(device)) + if (device.is_excluded_by_blocklist) return false; // Do not pass the device to the chooser if it has a top-level collection @@ -251,7 +280,7 @@ bool HidChooserController::DisplayDevice( return false; } - return FilterMatchesAny(device); + return FilterMatchesAny(device) && !IsExcluded(device); } bool HidChooserController::FilterMatchesAny( @@ -260,44 +289,18 @@ bool HidChooserController::FilterMatchesAny( return true; for (const auto& filter : filters_) { - if (filter->device_ids) { - if (filter->device_ids->is_vendor()) { - if (filter->device_ids->get_vendor() != device.vendor_id) - continue; - } else if (filter->device_ids->is_vendor_and_product()) { - const auto& vendor_and_product = - filter->device_ids->get_vendor_and_product(); - if (vendor_and_product->vendor != device.vendor_id) - continue; - if (vendor_and_product->product != device.product_id) - continue; - } - } + if (FilterMatch(filter, device)) + return true; + } - if (filter->usage) { - if (filter->usage->is_page()) { - const uint16_t usage_page = filter->usage->get_page(); - auto find_it = - std::find_if(device.collections.begin(), device.collections.end(), - [=](const device::mojom::HidCollectionInfoPtr& c) { - return usage_page == c->usage->usage_page; - }); - if (find_it == device.collections.end()) - continue; - } else if (filter->usage->is_usage_and_page()) { - const auto& usage_and_page = filter->usage->get_usage_and_page(); - auto find_it = std::find_if( - device.collections.begin(), device.collections.end(), - [&usage_and_page](const device::mojom::HidCollectionInfoPtr& c) { - return usage_and_page->usage_page == c->usage->usage_page && - usage_and_page->usage == c->usage->usage; - }); - if (find_it == device.collections.end()) - continue; - } - } + return false; +} - return true; +bool HidChooserController::IsExcluded( + const device::mojom::HidDeviceInfo& device) const { + for (const auto& exclusion_filter : exclusion_filters_) { + if (FilterMatch(exclusion_filter, device)) + return true; } return false; diff --git a/shell/browser/hid/hid_chooser_controller.h b/shell/browser/hid/hid_chooser_controller.h index ed5ef443a154d..63411c9f65b78 100644 --- a/shell/browser/hid/hid_chooser_controller.h +++ b/shell/browser/hid/hid_chooser_controller.h @@ -42,15 +42,21 @@ class HidChooserController // is closed, either by selecting an item or by dismissing the chooser dialog. // The callback is called with the selected device, or nullptr if no device is // selected. - HidChooserController(content::RenderFrameHost* render_frame_host, - std::vector filters, - content::HidChooser::Callback callback, - content::WebContents* web_contents, - base::WeakPtr hid_delegate); + HidChooserController( + content::RenderFrameHost* render_frame_host, + std::vector filters, + std::vector exclusion_filters, + content::HidChooser::Callback callback, + content::WebContents* web_contents, + base::WeakPtr hid_delegate); HidChooserController(HidChooserController&) = delete; HidChooserController& operator=(HidChooserController&) = delete; ~HidChooserController() override; + // static + static std::string PhysicalDeviceIdFromDeviceInfo( + const device::mojom::HidDeviceInfo& device); + // HidChooserContext::DeviceObserver: void OnDeviceAdded(const device::mojom::HidDeviceInfo& device_info) override; void OnDeviceRemoved( @@ -68,6 +74,7 @@ class HidChooserController void OnGotDevices(std::vector devices); bool DisplayDevice(const device::mojom::HidDeviceInfo& device) const; bool FilterMatchesAny(const device::mojom::HidDeviceInfo& device) const; + bool IsExcluded(const device::mojom::HidDeviceInfo& device) const; // Add |device_info| to |device_map_|. The device is added to the chooser item // representing the physical device. If the chooser item does not yet exist, a @@ -88,6 +95,7 @@ class HidChooserController void OnDeviceChosen(gin::Arguments* args); std::vector filters_; + std::vector exclusion_filters_; content::HidChooser::Callback callback_; const url::Origin origin_; const int frame_tree_node_id_; diff --git a/shell/browser/javascript_environment.cc b/shell/browser/javascript_environment.cc index 0a40c5ca356fd..2acd06cbbafa1 100644 --- a/shell/browser/javascript_environment.cc +++ b/shell/browser/javascript_environment.cc @@ -11,6 +11,7 @@ #include "base/allocator/partition_alloc_features.h" #include "base/allocator/partition_allocator/partition_alloc.h" +#include "base/bits.h" #include "base/command_line.h" #include "base/feature_list.h" #include "base/task/current_thread.h" @@ -72,81 +73,6 @@ struct base::trace_event::TraceValue::Helper< namespace electron { -class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { - public: - enum InitializationPolicy { kZeroInitialize, kDontInitialize }; - - ArrayBufferAllocator() { - // Ref. - // https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/wtf/allocator/partitions.cc;l=94;drc=062c315a858a87f834e16a144c2c8e9591af2beb - allocator_->init({base::PartitionOptions::AlignedAlloc::kDisallowed, - base::PartitionOptions::ThreadCache::kDisabled, - base::PartitionOptions::Quarantine::kAllowed, - base::PartitionOptions::Cookie::kAllowed, - base::PartitionOptions::BackupRefPtr::kDisabled, - base::PartitionOptions::UseConfigurablePool::kNo}); - } - - // Allocate() methods return null to signal allocation failure to V8, which - // should respond by throwing a RangeError, per - // http://www.ecma-international.org/ecma-262/6.0/#sec-createbytedatablock. - void* Allocate(size_t size) override { - void* result = AllocateMemoryOrNull(size, kZeroInitialize); - return result; - } - - void* AllocateUninitialized(size_t size) override { - void* result = AllocateMemoryOrNull(size, kDontInitialize); - return result; - } - - void Free(void* data, size_t size) override { - allocator_->root()->Free(data); - } - - private: - static void* AllocateMemoryOrNull(size_t size, InitializationPolicy policy) { - return AllocateMemoryWithFlags(size, policy, - base::PartitionAllocReturnNull); - } - - static void* AllocateMemoryWithFlags(size_t size, - InitializationPolicy policy, - int flags) { - // The array buffer contents are sometimes expected to be 16-byte aligned in - // order to get the best optimization of SSE, especially in case of audio - // and video buffers. Hence, align the given size up to 16-byte boundary. - // Technically speaking, 16-byte aligned size doesn't mean 16-byte aligned - // address, but this heuristics works with the current implementation of - // PartitionAlloc (and PartitionAlloc doesn't support a better way for now). - if (base::kAlignment < - 16) { // base::kAlignment is a compile-time constant. - size_t aligned_size = base::bits::AlignUp(size, 16); - if (size == 0) { - aligned_size = 16; - } - if (aligned_size >= size) { // Only when no overflow - size = aligned_size; - } - } - - if (policy == kZeroInitialize) { - flags |= base::PartitionAllocZeroFill; - } - void* data = allocator_->root()->AllocFlags(flags, size, "Electron"); - if (base::kAlignment < 16) { - char* ptr = reinterpret_cast(data); - DCHECK_EQ(base::bits::AlignUp(ptr, 16), ptr) - << "Pointer " << ptr << " not 16B aligned for size " << size; - } - return data; - } - - static base::NoDestructor allocator_; -}; - -base::NoDestructor ArrayBufferAllocator::allocator_{}; - JavascriptEnvironment::JavascriptEnvironment(uv_loop_t* event_loop) : isolate_(Initialize(event_loop)), isolate_holder_(base::ThreadTaskRunnerHandle::Get(), @@ -156,8 +82,6 @@ JavascriptEnvironment::JavascriptEnvironment(uv_loop_t* event_loop) gin::IsolateHolder::IsolateCreationMode::kNormal, nullptr, nullptr, - nullptr, - nullptr, isolate_), locker_(isolate_) { isolate_->Enter(); @@ -172,7 +96,6 @@ JavascriptEnvironment::~JavascriptEnvironment() { platform_->DrainTasks(isolate_); { - v8::Locker locker(isolate_); v8::HandleScope scope(isolate_); context_.Get(isolate_)->Exit(); } @@ -330,6 +253,7 @@ v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop) { // --js-flags. std::string js_flags = cmd->GetSwitchValueASCII(blink::switches::kJavaScriptFlags); + js_flags.append(" --no-freeze-flags-after-init"); if (!js_flags.empty()) v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size()); @@ -344,9 +268,11 @@ v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop) { v8::V8::InitializePlatform(platform_); gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode, - new ArrayBufferAllocator(), + gin::ArrayBufferAllocator::SharedInstance(), nullptr /* external_reference_table */, - js_flags, false /* create_v8_platform */); + js_flags, nullptr /* fatal_error_callback */, + nullptr /* oom_error_callback */, + false /* create_v8_platform */); v8::Isolate* isolate = v8::Isolate::Allocate(); platform_->RegisterIsolate(isolate, event_loop); @@ -370,7 +296,6 @@ void JavascriptEnvironment::OnMessageLoopCreated() { void JavascriptEnvironment::OnMessageLoopDestroying() { DCHECK(microtasks_runner_); { - v8::Locker locker(isolate_); v8::HandleScope scope(isolate_); gin_helper::CleanedUpAtExit::DoCleanup(); } diff --git a/shell/browser/lib/bluetooth_chooser.cc b/shell/browser/lib/bluetooth_chooser.cc index 3dec4d19be391..7c9942d7ba584 100644 --- a/shell/browser/lib/bluetooth_chooser.cc +++ b/shell/browser/lib/bluetooth_chooser.cc @@ -131,7 +131,7 @@ void BluetoothChooser::AddOrUpdateDevice(const std::string& device_id, "select-bluetooth-device", GetDeviceList(), base::BindOnce(&OnDeviceChosen, event_handler_)); - // If emit not implimented select first device that matches the filters + // If emit not implemented select first device that matches the filters // provided. if (!prevent_default) { event_handler_.Run(content::BluetoothChooserEvent::SELECTED, device_id); diff --git a/shell/browser/mac/dict_util.h b/shell/browser/mac/dict_util.h index 13b3bed0d9762..88ce5e58fe80b 100644 --- a/shell/browser/mac/dict_util.h +++ b/shell/browser/mac/dict_util.h @@ -7,17 +7,14 @@ #import -namespace base { -class ListValue; -class DictionaryValue; -} // namespace base +#include "base/values.h" namespace electron { -NSArray* ListValueToNSArray(const base::ListValue& value); -base::ListValue NSArrayToListValue(NSArray* arr); -NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value); -base::DictionaryValue NSDictionaryToDictionaryValue(NSDictionary* dict); +NSArray* ListValueToNSArray(const base::Value::List& value); +base::Value::List NSArrayToValue(NSArray* arr); +NSDictionary* DictionaryValueToNSDictionary(const base::Value::Dict& value); +base::Value::Dict NSDictionaryToValue(NSDictionary* dict); } // namespace electron diff --git a/shell/browser/mac/dict_util.mm b/shell/browser/mac/dict_util.mm index d48ecb13daf4a..1d31185bc5a2a 100644 --- a/shell/browser/mac/dict_util.mm +++ b/shell/browser/mac/dict_util.mm @@ -12,9 +12,9 @@ namespace electron { -NSArray* ListValueToNSArray(const base::ListValue& value) { +NSArray* ListValueToNSArray(const base::Value::List& value) { std::string json; - if (!base::JSONWriter::Write(value, &json)) + if (!base::JSONWriter::Write(base::Value(value.Clone()), &json)) return nil; NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()]; id obj = [NSJSONSerialization JSONObjectWithData:jsonData @@ -25,8 +25,8 @@ return obj; } -base::ListValue NSArrayToListValue(NSArray* arr) { - base::ListValue result; +base::Value::List NSArrayToValue(NSArray* arr) { + base::Value::List result; if (!arr) return result; @@ -44,9 +44,9 @@ else result.Append([value intValue]); } else if ([value isKindOfClass:[NSArray class]]) { - result.Append(NSArrayToListValue(value)); + result.Append(NSArrayToValue(value)); } else if ([value isKindOfClass:[NSDictionary class]]) { - result.Append(NSDictionaryToDictionaryValue(value)); + result.Append(NSDictionaryToValue(value)); } else { result.Append(base::SysNSStringToUTF8([value description])); } @@ -55,10 +55,9 @@ return result; } -NSDictionary* DictionaryValueToNSDictionary( - const base::DictionaryValue& value) { +NSDictionary* DictionaryValueToNSDictionary(const base::Value::Dict& value) { std::string json; - if (!base::JSONWriter::Write(value, &json)) + if (!base::JSONWriter::Write(base::Value(value.Clone()), &json)) return nil; NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()]; id obj = [NSJSONSerialization JSONObjectWithData:jsonData @@ -69,8 +68,8 @@ return obj; } -base::DictionaryValue NSDictionaryToDictionaryValue(NSDictionary* dict) { - base::DictionaryValue result; +base::Value::Dict NSDictionaryToValue(NSDictionary* dict) { + base::Value::Dict result; if (!dict) return result; @@ -80,24 +79,24 @@ id value = [dict objectForKey:key]; if ([value isKindOfClass:[NSString class]]) { - result.SetKey(str_key, base::Value(base::SysNSStringToUTF8(value))); + result.Set(str_key, base::Value(base::SysNSStringToUTF8(value))); } else if ([value isKindOfClass:[NSNumber class]]) { const char* objc_type = [value objCType]; if (strcmp(objc_type, @encode(BOOL)) == 0 || strcmp(objc_type, @encode(char)) == 0) - result.SetKey(str_key, base::Value([value boolValue])); + result.Set(str_key, base::Value([value boolValue])); else if (strcmp(objc_type, @encode(double)) == 0 || strcmp(objc_type, @encode(float)) == 0) - result.SetKey(str_key, base::Value([value doubleValue])); + result.Set(str_key, base::Value([value doubleValue])); else - result.SetKey(str_key, base::Value([value intValue])); + result.Set(str_key, base::Value([value intValue])); } else if ([value isKindOfClass:[NSArray class]]) { - result.SetKey(str_key, NSArrayToListValue(value)); + result.Set(str_key, NSArrayToValue(value)); } else if ([value isKindOfClass:[NSDictionary class]]) { - result.SetKey(str_key, NSDictionaryToDictionaryValue(value)); + result.Set(str_key, NSDictionaryToValue(value)); } else { - result.SetKey(str_key, - base::Value(base::SysNSStringToUTF8([value description]))); + result.Set(str_key, + base::Value(base::SysNSStringToUTF8([value description]))); } } diff --git a/shell/browser/mac/electron_application.mm b/shell/browser/mac/electron_application.mm index 468887cb5c4be..d6ff91475e75e 100644 --- a/shell/browser/mac/electron_application.mm +++ b/shell/browser/mac/electron_application.mm @@ -120,8 +120,8 @@ - (void)userActivityWillSave:(NSUserActivity*)userActivity { dispatch_sync_main(^{ std::string activity_type( base::SysNSStringToUTF8(userActivity.activityType)); - base::DictionaryValue user_info = - electron::NSDictionaryToDictionaryValue(userActivity.userInfo); + base::Value::Dict user_info = + electron::NSDictionaryToValue(userActivity.userInfo); electron::Browser* browser = electron::Browser::Get(); shouldWait = @@ -149,8 +149,8 @@ - (void)userActivityWasContinued:(NSUserActivity*)userActivity { dispatch_async(dispatch_get_main_queue(), ^{ std::string activity_type( base::SysNSStringToUTF8(userActivity.activityType)); - base::DictionaryValue user_info = - electron::NSDictionaryToDictionaryValue(userActivity.userInfo); + base::Value::Dict user_info = + electron::NSDictionaryToValue(userActivity.userInfo); electron::Browser* browser = electron::Browser::Get(); browser->UserActivityWasContinued(activity_type, std::move(user_info)); diff --git a/shell/browser/mac/electron_application_delegate.mm b/shell/browser/mac/electron_application_delegate.mm index 138400d625a87..7dc351f4cc654 100644 --- a/shell/browser/mac/electron_application_delegate.mm +++ b/shell/browser/mac/electron_application_delegate.mm @@ -13,36 +13,13 @@ #include "base/mac/scoped_objc_class_swizzler.h" #include "base/strings/sys_string_conversions.h" #include "base/values.h" +#include "shell/browser/api/electron_api_push_notifications.h" #include "shell/browser/browser.h" #include "shell/browser/mac/dict_util.h" #import "shell/browser/mac/electron_application.h" #import -#if BUILDFLAG(USE_ALLOCATOR_SHIM) -// On macOS 10.12, the IME system attempts to allocate a 2^64 size buffer, -// which would typically cause an OOM crash. To avoid this, the problematic -// method is swizzled out and the make-OOM-fatal bit is disabled for the -// duration of the original call. https://crbug.com/654695 -static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; -@interface OOMDisabledIMKInputSession : NSObject -@end -@implementation OOMDisabledIMKInputSession -- (void)_coreAttributesFromRange:(NSRange)range - whichAttributes:(long long)attributes // NOLINT(runtime/int) - completionHandler:(void (^)(void))block { - // The allocator flag is per-process, so other threads may temporarily - // not have fatal OOM occur while this method executes, but it is better - // than crashing when using IME. - base::allocator::SetCallNewHandlerOnMallocFailure(false); - g_swizzle_imk_input_session->InvokeOriginal< - void, NSRange, long long, void (^)(void)>( // NOLINT(runtime/int) - self, _cmd, range, attributes, block); - base::allocator::SetCallNewHandlerOnMallocFailure(true); -} -@end -#endif // BUILDFLAG(USE_ALLOCATOR_SHIM) - static NSDictionary* UNNotificationResponseToNSDictionary( UNNotificationResponse* response) API_AVAILABLE(macosx(10.14)) { // [response isKindOfClass:[UNNotificationResponse class]] @@ -108,17 +85,7 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notify { } electron::Browser::Get()->DidFinishLaunching( - electron::NSDictionaryToDictionaryValue(notification_info)); - -#if BUILDFLAG(USE_ALLOCATOR_SHIM) - // Disable fatal OOM to hack around an OS bug https://crbug.com/654695. - if (base::mac::IsOS10_12()) { - g_swizzle_imk_input_session = new base::mac::ScopedObjCClassSwizzler( - NSClassFromString(@"IMKInputSession"), - [OOMDisabledIMKInputSession class], - @selector(_coreAttributesFromRange:whichAttributes:completionHandler:)); - } -#endif + electron::NSDictionaryToValue(notification_info)); } - (void)applicationDidBecomeActive:(NSNotification*)notification { @@ -162,8 +129,8 @@ - (BOOL)application:(NSApplication*)sender electron::Browser* browser = electron::Browser::Get(); return browser->ContinueUserActivity( activity_type, - electron::NSDictionaryToDictionaryValue(userActivity.userInfo), - electron::NSDictionaryToDictionaryValue(details)) + electron::NSDictionaryToValue(userActivity.userInfo), + electron::NSDictionaryToValue(details)) ? YES : NO; } @@ -191,4 +158,43 @@ - (IBAction)newWindowForTab:(id)sender { electron::Browser::Get()->NewWindowForTab(); } +- (void)application:(NSApplication*)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { + // https://stackoverflow.com/a/16411517 + const char* token_data = static_cast([deviceToken bytes]); + NSMutableString* token_string = [NSMutableString string]; + for (NSUInteger i = 0; i < [deviceToken length]; i++) { + [token_string appendFormat:@"%02.2hhX", token_data[i]]; + } + // Resolve outstanding APNS promises created during registration attempts + electron::api::PushNotifications* push_notifications = + electron::api::PushNotifications::Get(); + if (push_notifications) { + push_notifications->ResolveAPNSPromiseSetWithToken( + base::SysNSStringToUTF8(token_string)); + } +} + +- (void)application:(NSApplication*)application + didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { + std::string error_message(base::SysNSStringToUTF8( + [NSString stringWithFormat:@"%ld %@ %@", [error code], [error domain], + [error userInfo]])); + electron::api::PushNotifications* push_notifications = + electron::api::PushNotifications::Get(); + if (push_notifications) { + push_notifications->RejectAPNSPromiseSetWithError(error_message); + } +} + +- (void)application:(NSApplication*)application + didReceiveRemoteNotification:(NSDictionary*)userInfo { + electron::api::PushNotifications* push_notifications = + electron::api::PushNotifications::Get(); + if (push_notifications) { + electron::api::PushNotifications::Get()->OnDidReceiveAPNSNotification( + electron::NSDictionaryToValue(userInfo)); + } +} + @end diff --git a/shell/browser/mac/in_app_purchase.mm b/shell/browser/mac/in_app_purchase.mm index 23c8ad22a6766..10194f49a7987 100644 --- a/shell/browser/mac/in_app_purchase.mm +++ b/shell/browser/mac/in_app_purchase.mm @@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/strings/sys_string_conversions.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -122,8 +121,8 @@ - (void)checkout:(SKProduct*)product { */ - (void)runCallback:(bool)isProductValid { if (callback_) { - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(std::move(callback_), isProductValid)); + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback_), isProductValid)); } // Release this delegate. [self release]; diff --git a/shell/browser/mac/in_app_purchase_observer.mm b/shell/browser/mac/in_app_purchase_observer.mm index f76093063b707..abf210960a512 100644 --- a/shell/browser/mac/in_app_purchase_observer.mm +++ b/shell/browser/mac/in_app_purchase_observer.mm @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/strings/sys_string_conversions.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -75,8 +74,8 @@ - (void)runCallback:(NSArray*)transactions { } // Send the callback to the browser thread. - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(callback_, converted)); + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(callback_, converted)); } /** diff --git a/shell/browser/mac/in_app_purchase_product.mm b/shell/browser/mac/in_app_purchase_product.mm index 1bd4eb1664f9d..da9a20fe53177 100644 --- a/shell/browser/mac/in_app_purchase_product.mm +++ b/shell/browser/mac/in_app_purchase_product.mm @@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/strings/sys_string_conversions.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -83,8 +82,8 @@ - (void)productsRequest:(SKProductsRequest*)request } // Send the callback to the browser thread. - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(std::move(callback_), converted)); + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback_), converted)); [self release]; } @@ -221,11 +220,9 @@ - (NSString*)formatPrice:(NSDecimalNumber*)price withLocal:product.priceLocale] UTF8String]; // Currency Information - if (@available(macOS 10.12, *)) { - if (product.priceLocale.currencyCode != nil) { - productStruct.currencyCode = - [product.priceLocale.currencyCode UTF8String]; - } + if (product.priceLocale.currencyCode != nil) { + productStruct.currencyCode = + [product.priceLocale.currencyCode UTF8String]; } } } diff --git a/shell/browser/media/media_capture_devices_dispatcher.cc b/shell/browser/media/media_capture_devices_dispatcher.cc index 84a2ad677551c..3ebafc583510a 100644 --- a/shell/browser/media/media_capture_devices_dispatcher.cc +++ b/shell/browser/media/media_capture_devices_dispatcher.cc @@ -12,23 +12,6 @@ using content::BrowserThread; namespace electron { -namespace { - -// Finds a device in |devices| that has |device_id|, or NULL if not found. -const blink::MediaStreamDevice* FindDeviceWithId( - const blink::MediaStreamDevices& devices, - const std::string& device_id) { - auto iter = devices.begin(); - for (; iter != devices.end(); ++iter) { - if (iter->id == device_id) { - return &(*iter); - } - } - return nullptr; -} - -} // namespace - MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() { return base::Singleton::get(); } @@ -41,84 +24,6 @@ MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher() { MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() = default; -const blink::MediaStreamDevices& -MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (is_device_enumeration_disabled_) - return test_audio_devices_; - return content::MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(); -} - -const blink::MediaStreamDevices& -MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (is_device_enumeration_disabled_) - return test_video_devices_; - return content::MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(); -} - -void MediaCaptureDevicesDispatcher::GetDefaultDevices( - bool audio, - bool video, - blink::MediaStreamDevices* devices) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(audio || video); - - if (audio) { - const blink::MediaStreamDevice* device = GetFirstAvailableAudioDevice(); - if (device) - devices->push_back(*device); - } - - if (video) { - const blink::MediaStreamDevice* device = GetFirstAvailableVideoDevice(); - if (device) - devices->push_back(*device); - } -} - -const blink::MediaStreamDevice* -MediaCaptureDevicesDispatcher::GetRequestedAudioDevice( - const std::string& requested_audio_device_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const blink::MediaStreamDevices& audio_devices = GetAudioCaptureDevices(); - const blink::MediaStreamDevice* const device = - FindDeviceWithId(audio_devices, requested_audio_device_id); - return device; -} - -const blink::MediaStreamDevice* -MediaCaptureDevicesDispatcher::GetFirstAvailableAudioDevice() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const blink::MediaStreamDevices& audio_devices = GetAudioCaptureDevices(); - if (audio_devices.empty()) - return nullptr; - return &(*audio_devices.begin()); -} - -const blink::MediaStreamDevice* -MediaCaptureDevicesDispatcher::GetRequestedVideoDevice( - const std::string& requested_video_device_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const blink::MediaStreamDevices& video_devices = GetVideoCaptureDevices(); - const blink::MediaStreamDevice* const device = - FindDeviceWithId(video_devices, requested_video_device_id); - return device; -} - -const blink::MediaStreamDevice* -MediaCaptureDevicesDispatcher::GetFirstAvailableVideoDevice() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const blink::MediaStreamDevices& video_devices = GetVideoCaptureDevices(); - if (video_devices.empty()) - return nullptr; - return &(*video_devices.begin()); -} - -void MediaCaptureDevicesDispatcher::DisableDeviceEnumerationForTesting() { - is_device_enumeration_disabled_ = true; -} - void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged() {} void MediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged() {} diff --git a/shell/browser/media/media_capture_devices_dispatcher.h b/shell/browser/media/media_capture_devices_dispatcher.h index d7b0957e09f40..cb513230aa5d8 100644 --- a/shell/browser/media/media_capture_devices_dispatcher.h +++ b/shell/browser/media/media_capture_devices_dispatcher.h @@ -8,48 +8,22 @@ #include #include "base/memory/singleton.h" +#include "components/webrtc/media_stream_device_enumerator_impl.h" #include "content/public/browser/media_observer.h" #include "content/public/browser/media_stream_request.h" #include "third_party/blink/public/common/mediastream/media_stream_request.h" +#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h" namespace electron { // This singleton is used to receive updates about media events from the content // layer. -class MediaCaptureDevicesDispatcher : public content::MediaObserver { +class MediaCaptureDevicesDispatcher + : public content::MediaObserver, + public webrtc::MediaStreamDeviceEnumeratorImpl { public: static MediaCaptureDevicesDispatcher* GetInstance(); - // Methods for observers. Called on UI thread. - const blink::MediaStreamDevices& GetAudioCaptureDevices(); - const blink::MediaStreamDevices& GetVideoCaptureDevices(); - - // Helper to get the default devices which can be used by the media request. - // Uses the first available devices if the default devices are not available. - // If the return list is empty, it means there is no available device on the - // OS. - // Called on the UI thread. - void GetDefaultDevices(bool audio, - bool video, - blink::MediaStreamDevices* devices); - - // Helpers for picking particular requested devices, identified by raw id. - // If the device requested is not available it will return NULL. - const blink::MediaStreamDevice* GetRequestedAudioDevice( - const std::string& requested_audio_device_id); - const blink::MediaStreamDevice* GetRequestedVideoDevice( - const std::string& requested_video_device_id); - - // Returns the first available audio or video device, or NULL if no devices - // are available. - const blink::MediaStreamDevice* GetFirstAvailableAudioDevice(); - const blink::MediaStreamDevice* GetFirstAvailableVideoDevice(); - - // Unittests that do not require actual device enumeration should call this - // API on the singleton. It is safe to call this multiple times on the - // singleton. - void DisableDeviceEnumerationForTesting(); - // Overridden from content::MediaObserver: void OnAudioCaptureDevicesChanged() override; void OnVideoCaptureDevicesChanged() override; @@ -77,15 +51,6 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver { MediaCaptureDevicesDispatcher(); ~MediaCaptureDevicesDispatcher() override; - - // Only for testing, a list of cached audio capture devices. - blink::MediaStreamDevices test_audio_devices_; - - // Only for testing, a list of cached video capture devices. - blink::MediaStreamDevices test_video_devices_; - - // Flag used by unittests to disable device enumeration. - bool is_device_enumeration_disabled_ = false; }; } // namespace electron diff --git a/shell/browser/media/media_stream_devices_controller.cc b/shell/browser/media/media_stream_devices_controller.cc deleted file mode 100644 index 771e4ba43ee7c..0000000000000 --- a/shell/browser/media/media_stream_devices_controller.cc +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE-CHROMIUM file. - -#include "shell/browser/media/media_stream_devices_controller.h" - -#include -#include - -#include "content/public/browser/desktop_media_id.h" -#include "content/public/browser/media_stream_request.h" -#include "shell/browser/media/media_capture_devices_dispatcher.h" - -namespace electron { - -namespace { - -bool HasAnyAvailableDevice() { - const blink::MediaStreamDevices& audio_devices = - MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices(); - const blink::MediaStreamDevices& video_devices = - MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices(); - - return !audio_devices.empty() || !video_devices.empty(); -} - -} // namespace - -MediaStreamDevicesController::MediaStreamDevicesController( - const content::MediaStreamRequest& request, - content::MediaResponseCallback callback) - : request_(request), - callback_(std::move(callback)), - // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam - // and microphone to avoid popping two infobars. - microphone_requested_( - request.audio_type == - blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE || - request.request_type == blink::MEDIA_OPEN_DEVICE_PEPPER_ONLY), - webcam_requested_( - request.video_type == - blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE || - request.request_type == blink::MEDIA_OPEN_DEVICE_PEPPER_ONLY) {} - -MediaStreamDevicesController::~MediaStreamDevicesController() { - if (!callback_.is_null()) { - std::move(callback_).Run( - blink::MediaStreamDevices(), - blink::mojom::MediaStreamRequestResult::FAILED_DUE_TO_SHUTDOWN, - std::unique_ptr()); - } -} - -bool MediaStreamDevicesController::TakeAction() { - // Do special handling of desktop screen cast. - if (request_.audio_type == - blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE || - request_.video_type == - blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE || - request_.audio_type == - blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE || - request_.video_type == - blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) { - HandleUserMediaRequest(); - return true; - } - - // Deny the request if there is no device attached to the OS. - if (!HasAnyAvailableDevice()) { - Deny(blink::mojom::MediaStreamRequestResult::NO_HARDWARE); - return true; - } - - Accept(); - return true; -} - -void MediaStreamDevicesController::Accept() { - // Get the default devices for the request. - blink::MediaStreamDevices devices; - if (microphone_requested_ || webcam_requested_) { - switch (request_.request_type) { - case blink::MEDIA_OPEN_DEVICE_PEPPER_ONLY: { - const blink::MediaStreamDevice* device = nullptr; - // For open device request pick the desired device or fall back to the - // first available of the given type. - if (request_.audio_type == - blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) { - device = - MediaCaptureDevicesDispatcher::GetInstance() - ->GetRequestedAudioDevice(request_.requested_audio_device_id); - // TODO(wjia): Confirm this is the intended behavior. - if (!device) { - device = MediaCaptureDevicesDispatcher::GetInstance() - ->GetFirstAvailableAudioDevice(); - } - } else if (request_.video_type == - blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) { - // Pepper API opens only one device at a time. - device = - MediaCaptureDevicesDispatcher::GetInstance() - ->GetRequestedVideoDevice(request_.requested_video_device_id); - // TODO(wjia): Confirm this is the intended behavior. - if (!device) { - device = MediaCaptureDevicesDispatcher::GetInstance() - ->GetFirstAvailableVideoDevice(); - } - } - if (device) - devices.push_back(*device); - break; - } - case blink::MEDIA_GENERATE_STREAM: { - bool needs_audio_device = microphone_requested_; - bool needs_video_device = webcam_requested_; - - // Get the exact audio or video device if an id is specified. - if (!request_.requested_audio_device_id.empty()) { - const blink::MediaStreamDevice* audio_device = - MediaCaptureDevicesDispatcher::GetInstance() - ->GetRequestedAudioDevice(request_.requested_audio_device_id); - if (audio_device) { - devices.push_back(*audio_device); - needs_audio_device = false; - } - } - if (!request_.requested_video_device_id.empty()) { - const blink::MediaStreamDevice* video_device = - MediaCaptureDevicesDispatcher::GetInstance() - ->GetRequestedVideoDevice(request_.requested_video_device_id); - if (video_device) { - devices.push_back(*video_device); - needs_video_device = false; - } - } - - // If either or both audio and video devices were requested but not - // specified by id, get the default devices. - if (needs_audio_device || needs_video_device) { - MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevices( - needs_audio_device, needs_video_device, &devices); - } - break; - } - case blink::MEDIA_DEVICE_ACCESS: { - // Get the default devices for the request. - MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevices( - microphone_requested_, webcam_requested_, &devices); - break; - } - case blink::MEDIA_DEVICE_UPDATE: { - NOTREACHED(); - break; - } - } - } - - std::move(callback_).Run(devices, blink::mojom::MediaStreamRequestResult::OK, - std::unique_ptr()); -} - -void MediaStreamDevicesController::Deny( - blink::mojom::MediaStreamRequestResult result) { - std::move(callback_).Run(blink::MediaStreamDevices(), result, - std::unique_ptr()); -} - -void MediaStreamDevicesController::HandleUserMediaRequest() { - blink::MediaStreamDevices devices; - - if (request_.audio_type == - blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE) { - devices.emplace_back(blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE, - "", ""); - } - if (request_.video_type == - blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE) { - devices.emplace_back(blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE, - "", ""); - } - if (request_.audio_type == - blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE) { - devices.emplace_back( - blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE, "loopback", - "System Audio"); - } - if (request_.video_type == - blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) { - content::DesktopMediaID screen_id; - // If the device id wasn't specified then this is a screen capture request - // (i.e. chooseDesktopMedia() API wasn't used to generate device id). - if (request_.requested_video_device_id.empty()) { - screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, - -1 /* kFullDesktopScreenId */); - } else { - screen_id = - content::DesktopMediaID::Parse(request_.requested_video_device_id); - } - - devices.emplace_back( - blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE, - screen_id.ToString(), "Screen"); - } - - std::move(callback_).Run( - devices, - devices.empty() ? blink::mojom::MediaStreamRequestResult::NO_HARDWARE - : blink::mojom::MediaStreamRequestResult::OK, - std::unique_ptr()); -} - -} // namespace electron diff --git a/shell/browser/media/media_stream_devices_controller.h b/shell/browser/media/media_stream_devices_controller.h deleted file mode 100644 index 780d38e7cb4eb..0000000000000 --- a/shell/browser/media/media_stream_devices_controller.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE-CHROMIUM file. - -#ifndef ELECTRON_SHELL_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ -#define ELECTRON_SHELL_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ - -#include "content/public/browser/web_contents_delegate.h" -#include "third_party/blink/public/common/mediastream/media_stream_request.h" - -namespace electron { - -class MediaStreamDevicesController { - public: - MediaStreamDevicesController(const content::MediaStreamRequest& request, - content::MediaResponseCallback callback); - - virtual ~MediaStreamDevicesController(); - - // disable copy - MediaStreamDevicesController(const MediaStreamDevicesController&) = delete; - MediaStreamDevicesController& operator=(const MediaStreamDevicesController&) = - delete; - - // Accept or deny the request based on the default policy. - bool TakeAction(); - - // Explicitly accept or deny the request. - void Accept(); - void Deny(blink::mojom::MediaStreamRequestResult result); - - private: - // Handle the request of desktop or tab screen cast. - void HandleUserMediaRequest(); - - // The original request for access to devices. - const content::MediaStreamRequest request_; - - // The callback that needs to be Run to notify WebRTC of whether access to - // audio/video devices was granted or not. - content::MediaResponseCallback callback_; - - bool microphone_requested_; - bool webcam_requested_; -}; - -} // namespace electron - -#endif // ELECTRON_SHELL_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_ diff --git a/shell/browser/native_browser_view_mac.mm b/shell/browser/native_browser_view_mac.mm index 9cb5d11d8610b..685b7194b5280 100644 --- a/shell/browser/native_browser_view_mac.mm +++ b/shell/browser/native_browser_view_mac.mm @@ -262,9 +262,21 @@ - (void)drawDebugRect:(NSRect)aRect { auto* view = iwc_view->GetNativeView().GetNativeNSView(); auto* superview = view.superview; const auto superview_height = superview ? superview.frame.size.height : 0; + + // We need to use the content rect to calculate the titlebar height if the + // superview is an framed NSWindow, otherwise it will be offset incorrectly by + // the height of the titlebar. + auto titlebar_height = 0; + if (auto* win = [superview window]) { + const auto content_rect_height = + [win contentRectForFrameRect:superview.frame].size.height; + titlebar_height = superview_height - content_rect_height; + } + + auto new_height = + superview_height - bounds.y() - bounds.height() + titlebar_height; view.frame = - NSMakeRect(bounds.x(), superview_height - bounds.y() - bounds.height(), - bounds.width(), bounds.height()); + NSMakeRect(bounds.x(), new_height, bounds.width(), bounds.height()); // Ensure draggable regions are properly updated to reflect new bounds. UpdateDraggableRegions(draggable_regions_); @@ -275,12 +287,23 @@ - (void)drawDebugRect:(NSRect)aRect { if (!iwc_view) return gfx::Rect(); NSView* view = iwc_view->GetNativeView().GetNativeNSView(); - const int superview_height = - (view.superview) ? view.superview.frame.size.height : 0; - return gfx::Rect( - view.frame.origin.x, - superview_height - view.frame.origin.y - view.frame.size.height, - view.frame.size.width, view.frame.size.height); + auto* superview = view.superview; + const int superview_height = superview ? superview.frame.size.height : 0; + + // We need to use the content rect to calculate the titlebar height if the + // superview is an framed NSWindow, otherwise it will be offset incorrectly by + // the height of the titlebar. + auto titlebar_height = 0; + if (auto* win = [superview window]) { + const auto content_rect_height = + [win contentRectForFrameRect:superview.frame].size.height; + titlebar_height = superview_height - content_rect_height; + } + + auto new_height = superview_height - view.frame.origin.y - + view.frame.size.height + titlebar_height; + return gfx::Rect(view.frame.origin.x, new_height, view.frame.size.width, + view.frame.size.height); } void NativeBrowserViewMac::SetBackgroundColor(SkColor color) { diff --git a/shell/browser/native_browser_view_views.cc b/shell/browser/native_browser_view_views.cc index 0120f2ac48acd..651a9ba449f0a 100644 --- a/shell/browser/native_browser_view_views.cc +++ b/shell/browser/native_browser_view_views.cc @@ -27,6 +27,9 @@ void NativeBrowserViewViews::SetAutoResizeFlags(uint8_t flags) { void NativeBrowserViewViews::UpdateDraggableRegions( const std::vector& regions) { + if (&draggable_regions_ != ®ions) + draggable_regions_ = mojo::Clone(regions); + // We need to snap the regions to the bounds of the current BrowserView. // For example, if an attached BrowserView is draggable but its bounds are // { x: 200, y: 100, width: 300, height: 300 } @@ -35,12 +38,10 @@ void NativeBrowserViewViews::UpdateDraggableRegions( // assumed that the regions begin in the top left corner as they // would for the main client window. auto const offset = GetBounds().OffsetFromOrigin(); - auto snapped_regions = mojo::Clone(regions); - for (auto& snapped_region : snapped_regions) { + for (auto& snapped_region : draggable_regions_) { snapped_region->bounds.Offset(offset); } - - draggable_region_ = DraggableRegionsToSkRegion(snapped_regions); + draggable_region_ = DraggableRegionsToSkRegion(draggable_regions_); } void NativeBrowserViewViews::SetAutoResizeProportions( @@ -128,6 +129,12 @@ void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) { auto* view = iwc_view->GetView(); view->SetBoundsRect(bounds); ResetAutoResizeProportions(); + + view->InvalidateLayout(); + view->SchedulePaint(); + + // Ensure draggable regions are properly updated to reflect new bounds. + UpdateDraggableRegions(draggable_regions_); } gfx::Rect NativeBrowserViewViews::GetBounds() { diff --git a/shell/browser/native_window.cc b/shell/browser/native_window.cc index 1ca962fa92746..931e7759073cb 100644 --- a/shell/browser/native_window.cc +++ b/shell/browser/native_window.cc @@ -176,7 +176,7 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) { // By default the window has a default maximum size that prevents it // from being resized larger than the screen, so we should only set this - // if th user has passed in values. + // if the user has passed in values. if (have_max_height || have_max_width || !max_size.IsEmpty()) size_constraints.set_maximum_size(gfx::Size(max_width, max_height)); @@ -479,7 +479,7 @@ void NativeWindow::SetWindowControlsOverlayRect(const gfx::Rect& overlay_rect) { overlay_rect_ = overlay_rect; } -void NativeWindow::NotifyWindowRequestPreferredWith(int* width) { +void NativeWindow::NotifyWindowRequestPreferredWidth(int* width) { for (NativeWindowObserver& observer : observers_) observer.RequestPreferredWidth(width); } @@ -658,9 +658,8 @@ void NativeWindow::NotifyWindowExecuteAppCommand(const std::string& command) { observer.OnExecuteAppCommand(command); } -void NativeWindow::NotifyTouchBarItemInteraction( - const std::string& item_id, - const base::DictionaryValue& details) { +void NativeWindow::NotifyTouchBarItemInteraction(const std::string& item_id, + base::Value::Dict details) { for (NativeWindowObserver& observer : observers_) observer.OnTouchBarItemResult(item_id, details); } @@ -718,6 +717,17 @@ std::string NativeWindow::GetAccessibleTitle() { return base::UTF16ToUTF8(accessible_title_); } +void NativeWindow::HandlePendingFullscreenTransitions() { + if (pending_transitions_.empty()) { + set_fullscreen_transition_type(FullScreenTransitionType::NONE); + return; + } + + bool next_transition = pending_transitions_.front(); + pending_transitions_.pop(); + SetFullScreen(next_transition); +} + // static int32_t NativeWindow::next_id_ = 0; diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h index 762552656a5df..6568f03127bf3 100644 --- a/shell/browser/native_window.h +++ b/shell/browser/native_window.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -269,7 +270,7 @@ class NativeWindow : public base::SupportsUserData, // Public API used by platform-dependent delegates and observers to send UI // related notifications. - void NotifyWindowRequestPreferredWith(int* width); + void NotifyWindowRequestPreferredWidth(int* width); void NotifyWindowCloseButtonClicked(); void NotifyWindowClosed(); void NotifyWindowEndSession(); @@ -303,7 +304,7 @@ class NativeWindow : public base::SupportsUserData, void NotifyWindowAlwaysOnTopChanged(); void NotifyWindowExecuteAppCommand(const std::string& command); void NotifyTouchBarItemInteraction(const std::string& item_id, - const base::DictionaryValue& details); + base::Value::Dict details); void NotifyNewWindowForTab(); void NotifyWindowSystemContextMenu(int x, int y, bool* prevent_default); void NotifyLayoutWindowControlsOverlay(); @@ -317,6 +318,27 @@ class NativeWindow : public base::SupportsUserData, observers_.RemoveObserver(obs); } + // Handle fullscreen transitions. + void HandlePendingFullscreenTransitions(); + + enum class FullScreenTransitionState { ENTERING, EXITING, NONE }; + + void set_fullscreen_transition_state(FullScreenTransitionState state) { + fullscreen_transition_state_ = state; + } + FullScreenTransitionState fullscreen_transition_state() const { + return fullscreen_transition_state_; + } + + enum class FullScreenTransitionType { HTML, NATIVE, NONE }; + + void set_fullscreen_transition_type(FullScreenTransitionType type) { + fullscreen_transition_type_ = type; + } + FullScreenTransitionType fullscreen_transition_type() const { + return fullscreen_transition_type_; + } + views::Widget* widget() const { return widget_.get(); } views::View* content_view() const { return content_view_; } @@ -375,6 +397,12 @@ class NativeWindow : public base::SupportsUserData, // The "titleBarStyle" option. TitleBarStyle title_bar_style_ = TitleBarStyle::kNormal; + std::queue pending_transitions_; + FullScreenTransitionState fullscreen_transition_state_ = + FullScreenTransitionState::NONE; + FullScreenTransitionType fullscreen_transition_type_ = + FullScreenTransitionType::NONE; + private: std::unique_ptr widget_; diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h index ae1e845c8a182..ef5ab1b10e12b 100644 --- a/shell/browser/native_window_mac.h +++ b/shell/browser/native_window_mac.h @@ -8,7 +8,6 @@ #import #include -#include #include #include @@ -166,16 +165,18 @@ class NativeWindowMac : public NativeWindow, void UpdateVibrancyRadii(bool fullscreen); + void UpdateWindowOriginalFrame(); + // Set the attribute of NSWindow while work around a bug of zoom button. + bool HasStyleMask(NSUInteger flag) const; void SetStyleMask(bool on, NSUInteger flag); void SetCollectionBehavior(bool on, NSUInteger flag); void SetWindowLevel(int level); - enum class FullScreenTransitionState { ENTERING, EXITING, NONE }; - - // Handle fullscreen transitions. - void SetFullScreenTransitionState(FullScreenTransitionState state); - void HandlePendingFullscreenTransitions(); + bool HandleDeferredClose(); + void SetHasDeferredWindowClose(bool defer_close) { + has_deferred_window_close_ = defer_close; + } enum class VisualEffectState { kFollowWindow, @@ -242,12 +243,11 @@ class NativeWindowMac : public NativeWindow, bool zoom_to_page_width_ = false; absl::optional traffic_light_position_; - std::queue pending_transitions_; - FullScreenTransitionState fullscreen_transition_state() const { - return fullscreen_transition_state_; - } - FullScreenTransitionState fullscreen_transition_state_ = - FullScreenTransitionState::NONE; + // Trying to close an NSWindow during a fullscreen transition will cause the + // window to lock up. Use this to track if CloseWindow was called during a + // fullscreen transition, to defer the -[NSWindow close] call until the + // transition is complete. + bool has_deferred_window_close_ = false; NSInteger attention_request_id_ = 0; // identifier from requestUserAttention diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index a6e40642e569c..2bb5e3a4c5064 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -16,7 +16,6 @@ #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" -#include "base/task/post_task.h" #include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h" #include "components/remote_cocoa/browser/scoped_cg_window_id.h" #include "content/public/browser/browser_accessibility_state.h" @@ -51,7 +50,7 @@ // This view would inform Chromium to resize the hosted views::View. // -// The overrided methods should behave the same with BridgedContentView. +// The overridden methods should behave the same with BridgedContentView. @interface ElectronAdaptedContentView : NSView { @private views::NativeWidgetMacNSWindowHost* bridge_host_; @@ -300,16 +299,16 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { bool rounded_corner = true; options.Get(options::kRoundedCorners, &rounded_corner); if (!rounded_corner && !has_frame()) - styleMask = 0; + styleMask = NSWindowStyleMaskBorderless; if (minimizable) - styleMask |= NSMiniaturizableWindowMask; + styleMask |= NSWindowStyleMaskMiniaturizable; if (closable) styleMask |= NSWindowStyleMaskClosable; if (resizable) - styleMask |= NSResizableWindowMask; + styleMask |= NSWindowStyleMaskResizable; if (!useStandardWindow || transparent() || !has_frame()) - styleMask |= NSTexturedBackgroundWindowMask; + styleMask |= NSWindowStyleMaskTexturedBackground; // Create views::Widget and assign window_ with it. // TODO(zcbenz): Get rid of the window_ in future. @@ -318,7 +317,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { params.bounds = bounds; params.delegate = this; params.type = views::Widget::InitParams::TYPE_WINDOW; - params.native_widget = new ElectronNativeWidgetMac(this, styleMask, widget()); + params.native_widget = + new ElectronNativeWidgetMac(this, windowType, styleMask, widget()); widget()->Init(std::move(params)); SetCanResize(resizable); window_ = static_cast( @@ -356,6 +356,10 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { NSWindowCollectionBehaviorIgnoresCycle)]; } + if (windowType == "panel") { + [window_ setLevel:NSFloatingWindowLevel]; + } + bool focusable; if (options.Get(options::kFocusable, &focusable) && !focusable) [window_ setDisableKeyOrMainWindow:YES]; @@ -364,7 +368,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // Don't show title bar. [window_ setTitlebarAppearsTransparent:YES]; [window_ setTitleVisibility:NSWindowTitleHidden]; - // Remove non-transparent corners, see http://git.io/vfonD. + // Remove non-transparent corners, see + // https://github.com/electron/electron/issues/517. [window_ setOpaque:NO]; // Show window buttons if titleBarStyle is not "normal". if (title_bar_style_ == TitleBarStyle::kNormal) { @@ -375,7 +380,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { if (traffic_light_position_) { [buttons_proxy_ setMargin:*traffic_light_position_]; } else if (title_bar_style_ == TitleBarStyle::kHiddenInset) { - // For macOS >= 11, while this value does not match offical macOS apps + // For macOS >= 11, while this value does not match official macOS apps // like Safari or Notes, it matches titleBarStyle's old implementation // before Electron <= 12. [buttons_proxy_ setMargin:gfx::Point(12, 11)]; @@ -383,7 +388,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) { [buttons_proxy_ setShowOnHover:YES]; } else { - // customButtonsOnHover does not show buttons initialiy. + // customButtonsOnHover does not show buttons initially. InternalSetWindowButtonVisibility(true); } } @@ -392,13 +397,9 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // Create a tab only if tabbing identifier is specified and window has // a native title bar. if (tabbingIdentifier.empty() || transparent() || !has_frame()) { - if (@available(macOS 10.12, *)) { - [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; - } + [window_ setTabbingMode:NSWindowTabbingModeDisallowed]; } else { - if (@available(macOS 10.12, *)) { - [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbingIdentifier)]; - } + [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbingIdentifier)]; } // Resize to content bounds. @@ -451,7 +452,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { SetContentView(new views::View()); AddContentViewLayers(); - original_frame_ = [window_ frame]; + UpdateWindowOriginalFrame(); original_level_ = [window_ level]; } @@ -474,11 +475,17 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { return; } + if (fullscreen_transition_state() != FullScreenTransitionState::NONE) { + SetHasDeferredWindowClose(true); + return; + } + // If a sheet is attached to the window when we call // [window_ performClose:nil], the window won't close properly // even after the user has ended the sheet. // Ensure it's closed before calling [window_ performClose:nil]. - SetEnabled(true); + if ([window_ attachedSheet]) + [window_ endSheet:[window_ attachedSheet]]; [window_ performClose:nil]; @@ -548,7 +555,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // If a sheet is attached to the window when we call [window_ orderOut:nil], // the sheet won't be able to show again on the same window. // Ensure it's closed before calling [window_ orderOut:nil]. - SetEnabled(true); + if ([window_ attachedSheet]) + [window_ endSheet:[window_ attachedSheet]]; if (is_modal() && parent()) { [window_ orderOut:nil]; @@ -565,7 +573,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } } - // Deattach the window from the parent before. + // Detach the window from the parent before. if (parent()) InternalSetParentWindow(parent(), false); @@ -581,20 +589,24 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { return [window_ isVisible] && !occluded && !IsMinimized(); } -void NativeWindowMac::SetFullScreenTransitionState( - FullScreenTransitionState state) { - fullscreen_transition_state_ = state; -} - bool NativeWindowMac::IsEnabled() { return [window_ attachedSheet] == nil; } void NativeWindowMac::SetEnabled(bool enable) { if (!enable) { - [window_ beginSheet:window_ + NSRect frame = [window_ frame]; + NSWindow* window = + [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, frame.size.width, + frame.size.height) + styleMask:NSWindowStyleMaskTitled + backing:NSBackingStoreBuffered + defer:NO]; + [window setAlphaValue:0.5]; + + [window_ beginSheet:window completionHandler:^(NSModalResponse returnCode) { - NSLog(@"modal enabled"); + NSLog(@"main window disabled"); return; }]; } else if ([window_ attachedSheet]) { @@ -613,7 +625,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // Take note of the current window size if (IsNormal()) - original_frame_ = [window_ frame]; + UpdateWindowOriginalFrame(); [window_ zoom:nil]; if (!is_visible) { @@ -641,7 +653,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } bool NativeWindowMac::IsMaximized() { - if (([window_ styleMask] & NSWindowStyleMaskResizable) != 0) + if (HasStyleMask(NSWindowStyleMaskResizable) != 0) return [window_ isZoomed]; NSRect rectScreen = GetAspectRatio() > 0.0 @@ -657,7 +669,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // Take note of the current window size if (IsNormal()) - original_frame_ = [window_ frame]; + UpdateWindowOriginalFrame(); [window_ miniaturize:nil]; } @@ -669,16 +681,19 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { return [window_ isMiniaturized]; } -void NativeWindowMac::HandlePendingFullscreenTransitions() { - if (pending_transitions_.empty()) - return; - - bool next_transition = pending_transitions_.front(); - pending_transitions_.pop(); - SetFullScreen(next_transition); +bool NativeWindowMac::HandleDeferredClose() { + if (has_deferred_window_close_) { + SetHasDeferredWindowClose(false); + Close(); + return true; + } + return false; } void NativeWindowMac::SetFullScreen(bool fullscreen) { + if (!has_frame() && !HasStyleMask(NSWindowStyleMaskTitled)) + return; + // [NSWindow -toggleFullScreen] is an asynchronous operation, which means // that it's possible to call it while a fullscreen transition is currently // in process. This can create weird behavior (incl. phantom windows), @@ -701,7 +716,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // Take note of the current window size if (IsNormal()) - original_frame_ = [window_ frame]; + UpdateWindowOriginalFrame(); // This needs to be set here because it can be the case that // SetFullScreen is called by a user before windowWillEnterFullScreen @@ -715,7 +730,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } bool NativeWindowMac::IsFullscreen() const { - return [window_ styleMask] & NSWindowStyleMaskFullScreen; + return HasStyleMask(NSWindowStyleMaskFullScreen); } void NativeWindowMac::SetBounds(const gfx::Rect& bounds, bool animate) { @@ -737,6 +752,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { [window_ setFrame:cocoa_bounds display:YES animate:animate]; user_set_bounds_maximized_ = IsMaximized() ? true : false; + UpdateWindowOriginalFrame(); } gfx::Rect NativeWindowMac::GetBounds() { @@ -810,12 +826,16 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } void NativeWindowMac::SetResizable(bool resizable) { + ScopedDisableResize disable_resize; SetStyleMask(resizable, NSWindowStyleMaskResizable); SetCanResize(resizable); } bool NativeWindowMac::IsResizable() { - return [window_ styleMask] & NSWindowStyleMaskResizable; + bool in_fs_transition = + fullscreen_transition_state() != FullScreenTransitionState::NONE; + bool has_rs_mask = HasStyleMask(NSWindowStyleMaskResizable); + return has_rs_mask && !IsFullscreen() && !in_fs_transition; } void NativeWindowMac::SetMovable(bool movable) { @@ -827,11 +847,11 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } void NativeWindowMac::SetMinimizable(bool minimizable) { - SetStyleMask(minimizable, NSMiniaturizableWindowMask); + SetStyleMask(minimizable, NSWindowStyleMaskMiniaturizable); } bool NativeWindowMac::IsMinimizable() { - return [window_ styleMask] & NSMiniaturizableWindowMask; + return HasStyleMask(NSWindowStyleMaskMiniaturizable); } void NativeWindowMac::SetMaximizable(bool maximizable) { @@ -861,7 +881,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } bool NativeWindowMac::IsClosable() { - return [window_ styleMask] & NSWindowStyleMaskClosable; + return HasStyleMask(NSWindowStyleMaskClosable); } void NativeWindowMac::SetAlwaysOnTop(ui::ZOrderLevel z_order, @@ -887,9 +907,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { level = NSPopUpMenuWindowLevel; } else if (level_name == "screen-saver") { level = NSScreenSaverWindowLevel; - } else if (level_name == "dock") { - // Deprecated by macOS, but kept for backwards compatibility - level = NSDockWindowLevel; } SetWindowLevel(level + relative_level); @@ -913,8 +930,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { level_name = "pop-up-menu"; } else if (level == NSScreenSaverWindowLevel) { level_name = "screen-saver"; - } else if (level == NSDockWindowLevel) { - level_name = "dock"; } return level_name; @@ -999,8 +1014,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { if (!is_simple_fullscreen_) return; - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&NativeWindow::UpdateFrame, GetWeakPtr())); + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&NativeWindow::UpdateFrame, GetWeakPtr())); } void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) { @@ -1011,7 +1026,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // Take note of the current window size and level if (IsNormal()) { - original_frame_ = [window_ frame]; + UpdateWindowOriginalFrame(); original_level_ = [window_ level]; } @@ -1149,6 +1164,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { void NativeWindowMac::SetRepresentedFilename(const std::string& filename) { [window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)]; + if (buttons_proxy_) + [buttons_proxy_ redraw]; } std::string NativeWindowMac::GetRepresentedFilename() { @@ -1374,8 +1391,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { NSVisualEffectView* vibrantView = [window_ vibrantView]; if (vibrantView != nil && !vibrancy_type_.empty()) { - const bool no_rounded_corner = - !([window_ styleMask] & NSWindowStyleMaskTitled); + const bool no_rounded_corner = !HasStyleMask(NSWindowStyleMaskTitled); if (!has_frame() && !is_modal() && !no_rounded_corner) { CGFloat radius; if (fullscreen) { @@ -1409,6 +1425,10 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } } +void NativeWindowMac::UpdateWindowOriginalFrame() { + original_frame_ = [window_ frame]; +} + void NativeWindowMac::SetVibrancy(const std::string& type) { NSVisualEffectView* vibrantView = [window_ vibrantView]; @@ -1513,12 +1533,15 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { void NativeWindowMac::SetWindowButtonVisibility(bool visible) { window_button_visibility_ = visible; - // The visibility of window buttons are managed by |buttons_proxy_| if the - // style is customButtonsOnHover. - if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) + if (buttons_proxy_) { + if (visible) + [buttons_proxy_ redraw]; [buttons_proxy_ setVisible:visible]; - else + } + + if (title_bar_style_ != TitleBarStyle::kCustomButtonsOnHover) InternalSetWindowButtonVisibility(visible); + NotifyLayoutWindowControlsOverlay(); } @@ -1555,68 +1578,51 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { void NativeWindowMac::SetTouchBar( std::vector items) { - if (@available(macOS 10.12.2, *)) { - touch_bar_.reset([[ElectronTouchBar alloc] - initWithDelegate:window_delegate_.get() - window:this - settings:std::move(items)]); - [window_ setTouchBar:nil]; - } + touch_bar_.reset([[ElectronTouchBar alloc] + initWithDelegate:window_delegate_.get() + window:this + settings:std::move(items)]); + [window_ setTouchBar:nil]; } void NativeWindowMac::RefreshTouchBarItem(const std::string& item_id) { - if (@available(macOS 10.12.2, *)) { - if (touch_bar_ && [window_ touchBar]) - [touch_bar_ refreshTouchBarItem:[window_ touchBar] id:item_id]; - } + if (touch_bar_ && [window_ touchBar]) + [touch_bar_ refreshTouchBarItem:[window_ touchBar] id:item_id]; } void NativeWindowMac::SetEscapeTouchBarItem( gin_helper::PersistentDictionary item) { - if (@available(macOS 10.12.2, *)) { - if (touch_bar_ && [window_ touchBar]) - [touch_bar_ setEscapeTouchBarItem:std::move(item) - forTouchBar:[window_ touchBar]]; - } + if (touch_bar_ && [window_ touchBar]) + [touch_bar_ setEscapeTouchBarItem:std::move(item) + forTouchBar:[window_ touchBar]]; } void NativeWindowMac::SelectPreviousTab() { - if (@available(macOS 10.12, *)) { - [window_ selectPreviousTab:nil]; - } + [window_ selectPreviousTab:nil]; } void NativeWindowMac::SelectNextTab() { - if (@available(macOS 10.12, *)) { - [window_ selectNextTab:nil]; - } + [window_ selectNextTab:nil]; } void NativeWindowMac::MergeAllWindows() { - if (@available(macOS 10.12, *)) { - [window_ mergeAllWindows:nil]; - } + [window_ mergeAllWindows:nil]; } void NativeWindowMac::MoveTabToNewWindow() { - if (@available(macOS 10.12, *)) { - [window_ moveTabToNewWindow:nil]; - } + [window_ moveTabToNewWindow:nil]; } void NativeWindowMac::ToggleTabBar() { - if (@available(macOS 10.12, *)) { - [window_ toggleTabBar:nil]; - } + [window_ toggleTabBar:nil]; } bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) { if (window_ == window->GetNativeWindow().GetNativeNSWindow()) { return false; } else { - if (@available(macOS 10.12, *)) - [window_ addTabbedWindow:window->GetNativeWindow().GetNativeNSWindow() - ordered:NSWindowAbove]; + [window_ addTabbedWindow:window->GetNativeWindow().GetNativeNSWindow() + ordered:NSWindowAbove]; } return true; } @@ -1743,6 +1749,10 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { AddContentViewLayers(); } +bool NativeWindowMac::HasStyleMask(NSUInteger flag) const { + return [window_ styleMask] & flag; +} + void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) { // Changing the styleMask of a frameless windows causes it to change size so // we explicitly disable resizing while setting it. @@ -1778,8 +1788,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } void NativeWindowMac::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&NativeWindow::RedrawTrafficLights, GetWeakPtr())); } diff --git a/shell/browser/native_window_observer.h b/shell/browser/native_window_observer.h index 64f06179ffede..6cbc941450642 100644 --- a/shell/browser/native_window_observer.h +++ b/shell/browser/native_window_observer.h @@ -93,7 +93,7 @@ class NativeWindowObserver : public base::CheckedObserver { virtual void OnWindowLeaveHtmlFullScreen() {} virtual void OnWindowAlwaysOnTopChanged() {} virtual void OnTouchBarItemResult(const std::string& item_id, - const base::DictionaryValue& details) {} + const base::Value::Dict& details) {} virtual void OnNewWindowForTab() {} virtual void OnSystemContextMenu(int x, int y, bool* prevent_default) {} diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index ea24660945d27..2fea92b1ed57a 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -51,6 +51,7 @@ #include "shell/browser/ui/views/client_frame_view_linux.h" #include "shell/browser/ui/views/frameless_view.h" #include "shell/browser/ui/views/native_frame_view.h" +#include "shell/common/platform_util.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/window/native_frame_view.h" @@ -271,6 +272,8 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options, // Set WM_CLASS. params.wm_class_name = base::ToLowerASCII(name); params.wm_class_class = name; + // Set Wayland application ID. + params.wayland_app_id = platform_util::GetXdgAppId(); auto* native_widget = new views::DesktopNativeWidgetAura(widget()); params.native_widget = native_widget; @@ -278,7 +281,24 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options, new ElectronDesktopWindowTreeHostLinux(this, native_widget); #endif + // Ref https://github.com/electron/electron/issues/30760 + // Set the can_resize param before initializing the widget. + // When resizable_ is true, this causes the WS_THICKFRAME style + // to be passed into CreateWindowEx and SetWindowLong calls in + // WindowImpl::Init and HwndMessageHandler::SizeConstraintsChanged + // respectively. As a result, the Windows 7 frame doesn't show, + // but it isn't clear why this is the case. + // When resizable_ is false, WS_THICKFRAME is not passed into the + // SetWindowLong call, so the Windows 7 frame still shows. + // One workaround would be to call set_can_resize(true) here, + // and then move the SetCanResize(resizable_) call after the + // SetWindowLong call around line 365, but that's a much larger change. + set_can_resize(true); widget()->Init(std::move(params)); + + // When the workaround above is not needed anymore, only this + // call should be necessary. + // With the workaround in place, this call doesn't do anything. SetCanResize(resizable_); bool fullscreen = false; @@ -303,10 +323,6 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options, // Before the window is mapped the SetWMSpecState can not work, so we have // to manually set the _NET_WM_STATE. std::vector state_atom_list; - bool skip_taskbar = false; - if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) { - state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_SKIP_TASKBAR")); - } // Before the window is mapped, there is no SHOW_FULLSCREEN_STATE. if (fullscreen) { @@ -494,6 +510,13 @@ void NativeWindowViews::Show() { if (global_menu_bar_) global_menu_bar_->OnWindowMapped(); #endif + +#if defined(USE_OZONE_PLATFORM_X11) + // On X11, setting Z order before showing the window doesn't take effect, + // so we have to call it again. + if (IsX11()) + widget()->SetZOrderLevel(widget()->GetZOrderLevel()); +#endif } void NativeWindowViews::ShowInactive() { @@ -718,7 +741,6 @@ void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) { #if BUILDFLAG(IS_WIN) if (is_moving_ || is_resizing_) { pending_bounds_change_ = bounds; - return; } #endif @@ -875,6 +897,11 @@ bool NativeWindowViews::IsMovable() { void NativeWindowViews::SetMinimizable(bool minimizable) { #if BUILDFLAG(IS_WIN) FlipWindowStyle(GetAcceleratedWidget(), minimizable, WS_MINIMIZEBOX); + if (IsWindowControlsOverlayEnabled()) { + auto* frame_view = + static_cast(widget()->non_client_view()->frame_view()); + frame_view->caption_button_container()->UpdateButtons(); + } #endif minimizable_ = minimizable; } @@ -890,6 +917,11 @@ bool NativeWindowViews::IsMinimizable() { void NativeWindowViews::SetMaximizable(bool maximizable) { #if BUILDFLAG(IS_WIN) FlipWindowStyle(GetAcceleratedWidget(), maximizable, WS_MAXIMIZEBOX); + if (IsWindowControlsOverlayEnabled()) { + auto* frame_view = + static_cast(widget()->non_client_view()->frame_view()); + frame_view->caption_button_container()->UpdateButtons(); + } #endif maximizable_ = maximizable; } @@ -925,6 +957,11 @@ void NativeWindowViews::SetClosable(bool closable) { } else { EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); } + if (IsWindowControlsOverlayEnabled()) { + auto* frame_view = + static_cast(widget()->non_client_view()->frame_view()); + frame_view->caption_button_container()->UpdateButtons(); + } #endif } @@ -1020,10 +1057,6 @@ void NativeWindowViews::SetSkipTaskbar(bool skip) { taskbar->AddTab(GetAcceleratedWidget()); taskbar_host_.RestoreThumbarButtons(GetAcceleratedWidget()); } -#elif defined(USE_OZONE_PLATFORM_X11) - if (IsX11()) - SetWMSpecState(static_cast(GetAcceleratedWidget()), skip, - x11::GetAtom("_NET_WM_STATE_SKIP_TASKBAR")); #endif } @@ -1516,7 +1549,7 @@ void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget, NativeWindow::NotifyWindowBlur(); } - // Hide menu bar when window is blured. + // Hide menu bar when window is blurred. if (!active && IsMenuBarAutoHide() && IsMenuBarVisible()) SetMenuBarVisibility(false); diff --git a/shell/browser/native_window_views.h b/shell/browser/native_window_views.h index 55b757a1040b7..6672e3c2c7fcf 100644 --- a/shell/browser/native_window_views.h +++ b/shell/browser/native_window_views.h @@ -13,6 +13,7 @@ #include #include "shell/common/api/api.mojom.h" +#include "third_party/skia/include/core/SkRegion.h" #include "ui/views/widget/widget_observer.h" #if defined(USE_OZONE) @@ -224,6 +225,7 @@ class NativeWindowViews : public NativeWindow, #if BUILDFLAG(IS_WIN) void HandleSizeEvent(WPARAM w_param, LPARAM l_param); + void ResetWindowControls(); void SetForwardMouseMessages(bool forward); static LRESULT CALLBACK SubclassProc(HWND hwnd, UINT msg, diff --git a/shell/browser/native_window_views_win.cc b/shell/browser/native_window_views_win.cc index 77988743a9297..e4288d047c304 100644 --- a/shell/browser/native_window_views_win.cc +++ b/shell/browser/native_window_views_win.cc @@ -11,6 +11,7 @@ #include "shell/browser/browser.h" #include "shell/browser/native_window_views.h" #include "shell/browser/ui/views/root_view.h" +#include "shell/browser/ui/views/win_frame_view.h" #include "shell/common/electron_constants.h" #include "ui/display/display.h" #include "ui/display/win/screen_win.h" @@ -296,6 +297,7 @@ bool NativeWindowViews::PreHandleMSG(UINT message, &prevent_default); if (prevent_default) { ::GetWindowRect(hwnd, reinterpret_cast(l_param)); + pending_bounds_change_.reset(); return true; // Tells Windows that the Sizing is handled. } return false; @@ -334,6 +336,7 @@ bool NativeWindowViews::PreHandleMSG(UINT message, NotifyWindowWillMove(dpi_bounds, &prevent_default); if (!movable_ || prevent_default) { ::GetWindowRect(hwnd, reinterpret_cast(l_param)); + pending_bounds_change_.reset(); return true; // Tells Windows that the Move is handled. If not true, // frameless windows can be moved using // -webkit-app-region: drag elements. @@ -410,8 +413,11 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { // multiple times for one resize because of the SetWindowPlacement call. if (w_param == SIZE_MAXIMIZED && last_window_state_ != ui::SHOW_STATE_MAXIMIZED) { + if (last_window_state_ == ui::SHOW_STATE_MINIMIZED) + NotifyWindowRestore(); last_window_state_ = ui::SHOW_STATE_MAXIMIZED; NotifyWindowMaximize(); + ResetWindowControls(); } else if (w_param == SIZE_MINIMIZED && last_window_state_ != ui::SHOW_STATE_MINIMIZED) { last_window_state_ = ui::SHOW_STATE_MINIMIZED; @@ -419,7 +425,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { } break; } - case SIZE_RESTORED: + case SIZE_RESTORED: { switch (last_window_state_) { case ui::SHOW_STATE_MAXIMIZED: last_window_state_ = ui::SHOW_STATE_NORMAL; @@ -437,7 +443,20 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { default: break; } + ResetWindowControls(); break; + } + } +} + +void NativeWindowViews::ResetWindowControls() { + // If a given window was minimized and has since been + // unminimized (restored/maximized), ensure the WCO buttons + // are reset to their default unpressed state. + auto* ncv = widget()->non_client_view(); + if (IsWindowControlsOverlayEnabled() && ncv) { + auto* frame_view = static_cast(ncv->frame_view()); + frame_view->caption_button_container()->ResetWindowControls(); } } @@ -483,7 +502,7 @@ LRESULT CALLBACK NativeWindowViews::SubclassProc(HWND hwnd, // windows can occur due to rapidly entering and leaving forwarding mode. // By consuming and ignoring the message, we're essentially telling // Chromium that we have not left the window despite somebody else getting - // the messages. As to why this is catched for the legacy window and not + // the messages. As to why this is caught for the legacy window and not // the actual browser window is simply that the legacy window somehow // makes use of these events; posting to the main window didn't work. if (window->forwarding_mouse_messages_) { diff --git a/shell/browser/net/asar/asar_url_loader.cc b/shell/browser/net/asar/asar_url_loader.cc index bfa2a7d0e4832..eadfc5af789a7 100644 --- a/shell/browser/net/asar/asar_url_loader.cc +++ b/shell/browser/net/asar/asar_url_loader.cc @@ -11,7 +11,6 @@ #include #include "base/strings/stringprintf.h" -#include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "content/public/browser/file_url_loader.h" #include "electron/fuses.h" @@ -63,7 +62,7 @@ class AsarURLLoader : public network::mojom::URLLoader { public: static void CreateAndStart( const network::ResourceRequest& request, - network::mojom::URLLoaderRequest loader, + mojo::PendingReceiver loader, mojo::PendingRemote client, scoped_refptr extra_response_headers) { // Owns itself. Will live as long as its URLLoader and URLLoaderClientPtr @@ -270,9 +269,7 @@ class AsarURLLoader : public network::mojom::URLLoader { head->headers->AddHeader(net::HttpRequestHeaders::kContentType, head->mime_type.c_str()); } - client_->OnReceiveResponse(std::move(head), - mojo::ScopedDataPipeConsumerHandle()); - client_->OnStartLoadingResponseBody(std::move(consumer_handle)); + client_->OnReceiveResponse(std::move(head), std::move(consumer_handle)); if (total_bytes_to_send == 0) { // There's definitely no more data, so we're already done. @@ -390,7 +387,7 @@ class AsarURLLoader : public network::mojom::URLLoader { void CreateAsarURLLoader( const network::ResourceRequest& request, - network::mojom::URLLoaderRequest loader, + mojo::PendingReceiver loader, mojo::PendingRemote client, scoped_refptr extra_response_headers) { auto task_runner = base::ThreadPool::CreateSequencedTaskRunner( diff --git a/shell/browser/net/asar/asar_url_loader.h b/shell/browser/net/asar/asar_url_loader.h index 09d255fd5d2d5..4cd61df37b69d 100644 --- a/shell/browser/net/asar/asar_url_loader.h +++ b/shell/browser/net/asar/asar_url_loader.h @@ -13,7 +13,7 @@ namespace asar { void CreateAsarURLLoader( const network::ResourceRequest& request, - network::mojom::URLLoaderRequest loader, + mojo::PendingReceiver loader, mojo::PendingRemote client, scoped_refptr extra_response_headers); diff --git a/shell/browser/net/electron_url_loader_factory.cc b/shell/browser/net/electron_url_loader_factory.cc index eb7b97952fcd0..b7418c82531cb 100644 --- a/shell/browser/net/electron_url_loader_factory.cc +++ b/shell/browser/net/electron_url_loader_factory.cc @@ -114,9 +114,9 @@ network::mojom::URLResponseHeadPtr ToResponseHead( bool has_mime_type = dict.Get("mimeType", &head->mime_type); bool has_content_type = false; - base::DictionaryValue headers; + base::Value::Dict headers; if (dict.Get("headers", &headers)) { - for (const auto iter : headers.DictItems()) { + for (const auto iter : headers) { if (iter.second.is_string()) { // key, value head->headers->AddHeader(iter.first, iter.second.GetString()); @@ -513,7 +513,7 @@ void ElectronURLLoaderFactory::StartLoadingHttp( if (!dict.Get("method", &request->method)) request->method = original_request.method; - base::DictionaryValue upload_data; + base::Value::Dict upload_data; if (request->method != net::HttpRequestHeaders::kGetMethod && request->method != net::HttpRequestHeaders::kHeadMethod) dict.Get("uploadData", &upload_data); @@ -554,13 +554,6 @@ void ElectronURLLoaderFactory::StartLoadingStream( } else if (stream->IsNullOrUndefined()) { mojo::Remote client_remote( std::move(client)); - // "data" was explicitly passed as null or undefined, assume the user wants - // to send an empty body. - // - // Note that We must submit a empty body otherwise NetworkService would - // crash. - client_remote->OnReceiveResponse(std::move(head), - mojo::ScopedDataPipeConsumerHandle()); mojo::ScopedDataPipeProducerHandle producer; mojo::ScopedDataPipeConsumerHandle consumer; if (mojo::CreateDataPipe(nullptr, producer, consumer) != MOJO_RESULT_OK) { @@ -568,8 +561,13 @@ void ElectronURLLoaderFactory::StartLoadingStream( network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES)); return; } + // "data" was explicitly passed as null or undefined, assume the user wants + // to send an empty body. + // + // Note that We must submit a empty body otherwise NetworkService would + // crash. + client_remote->OnReceiveResponse(std::move(head), std::move(consumer)); producer.reset(); // The data pipe is empty. - client_remote->OnStartLoadingResponseBody(std::move(consumer)); client_remote->OnComplete(network::URLLoaderCompletionStatus(net::OK)); return; } else if (!stream->IsObject()) { @@ -605,8 +603,6 @@ void ElectronURLLoaderFactory::SendContents( // Add header to ignore CORS. head->headers->AddHeader("Access-Control-Allow-Origin", "*"); - client_remote->OnReceiveResponse(std::move(head), - mojo::ScopedDataPipeConsumerHandle()); // Code below follows the pattern of data_url_loader_factory.cc. mojo::ScopedDataPipeProducerHandle producer; @@ -617,7 +613,7 @@ void ElectronURLLoaderFactory::SendContents( return; } - client_remote->OnStartLoadingResponseBody(std::move(consumer)); + client_remote->OnReceiveResponse(std::move(head), std::move(consumer)); auto write_data = std::make_unique(); write_data->client = std::move(client_remote); diff --git a/shell/browser/net/network_context_service.cc b/shell/browser/net/network_context_service.cc index be8f3403dc81a..176f28aa688da 100644 --- a/shell/browser/net/network_context_service.cc +++ b/shell/browser/net/network_context_service.cc @@ -80,14 +80,14 @@ void NetworkContextService::ConfigureNetworkContextParams( // Configure on-disk storage for persistent sessions. if (!in_memory) { // Configure the HTTP cache path and size. - network_context_params->http_cache_path = + network_context_params->http_cache_directory = path.Append(chrome::kCacheDirname); network_context_params->http_cache_max_size = browser_context_->GetMaxCacheSize(); network_context_params->file_paths = network::mojom::NetworkContextFilePaths::New(); - network_context_params->file_paths->data_path = + network_context_params->file_paths->data_directory = path.Append(chrome::kNetworkDataDirname); network_context_params->file_paths->unsandboxed_data_path = path; network_context_params->file_paths->trigger_migration = diff --git a/shell/browser/net/node_stream_loader.cc b/shell/browser/net/node_stream_loader.cc index c4d264a578390..2cd93a2d63d1d 100644 --- a/shell/browser/net/node_stream_loader.cc +++ b/shell/browser/net/node_stream_loader.cc @@ -30,7 +30,6 @@ NodeStreamLoader::NodeStreamLoader( } NodeStreamLoader::~NodeStreamLoader() { - v8::Locker locker(isolate_); v8::Isolate::Scope isolate_scope(isolate_); v8::HandleScope handle_scope(isolate_); @@ -59,9 +58,7 @@ void NodeStreamLoader::Start(network::mojom::URLResponseHeadPtr head) { } producer_ = std::make_unique(std::move(producer)); - client_->OnReceiveResponse(std::move(head), - mojo::ScopedDataPipeConsumerHandle()); - client_->OnStartLoadingResponseBody(std::move(consumer)); + client_->OnReceiveResponse(std::move(head), std::move(consumer)); auto weak = weak_factory_.GetWeakPtr(); On("end", @@ -154,7 +151,6 @@ void NodeStreamLoader::DidWrite(MojoResult result) { } void NodeStreamLoader::On(const char* event, EventCallback callback) { - v8::Locker locker(isolate_); v8::Isolate::Scope isolate_scope(isolate_); v8::HandleScope handle_scope(isolate_); diff --git a/shell/browser/net/proxying_url_loader_factory.cc b/shell/browser/net/proxying_url_loader_factory.cc index 6eb27c8395083..49b728631a059 100644 --- a/shell/browser/net/proxying_url_loader_factory.cc +++ b/shell/browser/net/proxying_url_loader_factory.cc @@ -38,7 +38,6 @@ ProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams:: ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest( ProxyingURLLoaderFactory* factory, uint64_t web_request_id, - int32_t view_routing_id, int32_t frame_routing_id, int32_t network_service_request_id, uint32_t options, @@ -51,7 +50,6 @@ ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest( original_initiator_(request.request_initiator), request_id_(web_request_id), network_service_request_id_(network_service_request_id), - view_routing_id_(view_routing_id), frame_routing_id_(frame_routing_id), options_(options), traffic_annotation_(traffic_annotation), @@ -120,7 +118,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::UpdateRequestInfo() { request_id_, factory_->render_process_id_, frame_routing_id_, factory_->navigation_ui_data_ ? factory_->navigation_ui_data_->DeepCopy() : nullptr, - view_routing_id_, request_for_info, false, + request_for_info, false, !(options_ & network::mojom::kURLLoadOptionSynchronous), factory_->IsForServiceWorkerScript(), factory_->navigation_id_, ukm::kInvalidSourceIdObj)); @@ -302,11 +300,6 @@ void ProxyingURLLoaderFactory::InProgressRequest::OnTransferSizeUpdated( target_client_->OnTransferSizeUpdated(transfer_size_diff); } -void ProxyingURLLoaderFactory::InProgressRequest::OnStartLoadingResponseBody( - mojo::ScopedDataPipeConsumerHandle body) { - target_client_->OnStartLoadingResponseBody(std::move(body)); -} - void ProxyingURLLoaderFactory::InProgressRequest::OnComplete( const network::URLLoaderCompletionStatus& status) { if (status.error_code != net::OK) { @@ -523,8 +516,9 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToStartRequest( if (has_any_extra_headers_listeners_) options |= network::mojom::kURLLoadOptionUseHeaderClient; factory_->target_factory_->CreateLoaderAndStart( - mojo::MakeRequest(&target_loader_), network_service_request_id_, - options, request_, proxied_client_receiver_.BindNewPipeAndPassRemote(), + target_loader_.BindNewPipeAndPassReceiver(), + network_service_request_id_, options, request_, + proxied_client_receiver_.BindNewPipeAndPassRemote(), traffic_annotation_); } @@ -756,11 +750,10 @@ ProxyingURLLoaderFactory::ProxyingURLLoaderFactory( const HandlersMap& intercepted_handlers, int render_process_id, int frame_routing_id, - int view_routing_id, uint64_t* request_id_generator, std::unique_ptr navigation_ui_data, absl::optional navigation_id, - network::mojom::URLLoaderFactoryRequest loader_request, + mojo::PendingReceiver loader_request, mojo::PendingRemote target_factory_remote, mojo::PendingReceiver header_client_receiver, @@ -769,7 +762,6 @@ ProxyingURLLoaderFactory::ProxyingURLLoaderFactory( intercepted_handlers_(intercepted_handlers), render_process_id_(render_process_id), frame_routing_id_(frame_routing_id), - view_routing_id_(view_routing_id), request_id_generator_(request_id_generator), navigation_ui_data_(std::move(navigation_ui_data)), navigation_id_(std::move(navigation_id)), @@ -865,9 +857,8 @@ void ProxyingURLLoaderFactory::CreateLoaderAndStart( auto result = requests_.emplace( web_request_id, std::make_unique( - this, web_request_id, view_routing_id_, frame_routing_id_, request_id, - options, request, traffic_annotation, std::move(loader), - std::move(client))); + this, web_request_id, frame_routing_id_, request_id, options, request, + traffic_annotation, std::move(loader), std::move(client))); result.first->second->Restart(); } diff --git a/shell/browser/net/proxying_url_loader_factory.h b/shell/browser/net/proxying_url_loader_factory.h index 35d8e89be9332..edee0a3ee31a1 100644 --- a/shell/browser/net/proxying_url_loader_factory.h +++ b/shell/browser/net/proxying_url_loader_factory.h @@ -28,6 +28,7 @@ #include "services/network/public/mojom/url_loader.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/network/public/mojom/url_response_head.mojom.h" +#include "services/network/url_loader_factory.h" #include "shell/browser/net/electron_url_loader_factory.h" #include "shell/browser/net/web_request_api_interface.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -53,7 +54,6 @@ class ProxyingURLLoaderFactory InProgressRequest( ProxyingURLLoaderFactory* factory, uint64_t web_request_id, - int32_t view_routing_id, int32_t frame_routing_id, int32_t network_service_request_id, uint32_t options, @@ -97,8 +97,6 @@ class ProxyingURLLoaderFactory OnUploadProgressCallback callback) override; void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override; void OnTransferSizeUpdated(int32_t transfer_size_diff) override; - void OnStartLoadingResponseBody( - mojo::ScopedDataPipeConsumerHandle body) override; void OnComplete(const network::URLLoaderCompletionStatus& status) override; void OnLoaderCreated( @@ -135,7 +133,6 @@ class ProxyingURLLoaderFactory const absl::optional original_initiator_; const uint64_t request_id_ = 0; const int32_t network_service_request_id_ = 0; - const int32_t view_routing_id_ = MSG_ROUTING_NONE; const int32_t frame_routing_id_ = MSG_ROUTING_NONE; const uint32_t options_ = 0; const net::MutableNetworkTrafficAnnotationTag traffic_annotation_; @@ -146,7 +143,7 @@ class ProxyingURLLoaderFactory mojo::Receiver proxied_client_receiver_{ this}; - network::mojom::URLLoaderPtr target_loader_; + mojo::Remote target_loader_; network::mojom::URLResponseHeadPtr current_response_; mojo::ScopedDataPipeConsumerHandle current_body_; @@ -194,11 +191,10 @@ class ProxyingURLLoaderFactory const HandlersMap& intercepted_handlers, int render_process_id, int frame_routing_id, - int view_routing_id, uint64_t* request_id_generator, std::unique_ptr navigation_ui_data, absl::optional navigation_id, - network::mojom::URLLoaderFactoryRequest loader_request, + mojo::PendingReceiver loader_request, mojo::PendingRemote target_factory_remote, mojo::PendingReceiver @@ -259,7 +255,6 @@ class ProxyingURLLoaderFactory const int render_process_id_; const int frame_routing_id_; - const int view_routing_id_; uint64_t* request_id_generator_; // managed by ElectronBrowserClient std::unique_ptr navigation_ui_data_; absl::optional navigation_id_; diff --git a/shell/browser/net/proxying_websocket.cc b/shell/browser/net/proxying_websocket.cc index 3d051e4d9f2da..0ed8edb01aeba 100644 --- a/shell/browser/net/proxying_websocket.cc +++ b/shell/browser/net/proxying_websocket.cc @@ -40,7 +40,6 @@ ProxyingWebSocket::ProxyingWebSocket( process_id, render_frame_id, nullptr, - MSG_ROUTING_NONE, request, /*is_download=*/false, /*is_async=*/true, diff --git a/shell/browser/net/system_network_context_manager.cc b/shell/browser/net/system_network_context_manager.cc index de3989ad88678..d1f474d59ead7 100644 --- a/shell/browser/net/system_network_context_manager.cc +++ b/shell/browser/net/system_network_context_manager.cc @@ -288,10 +288,6 @@ void SystemNetworkContextManager::OnNetworkServiceCreated( base::FeatureList::IsEnabled(features::kAsyncDns), default_secure_dns_mode, doh_config, additional_dns_query_types_enabled); - // Initializes first party sets component - // CL: https://chromium-review.googlesource.com/c/chromium/src/+/3449280 - content::GetNetworkService()->SetFirstPartySets(base::File()); - std::string app_name = electron::Browser::Get()->GetName(); #if BUILDFLAG(IS_MAC) KeychainPassword::GetServiceName() = app_name + " Safe Storage"; diff --git a/shell/browser/net/url_pipe_loader.cc b/shell/browser/net/url_pipe_loader.cc index b55dc3963dcfb..1729ded04a423 100644 --- a/shell/browser/net/url_pipe_loader.cc +++ b/shell/browser/net/url_pipe_loader.cc @@ -19,7 +19,7 @@ URLPipeLoader::URLPipeLoader( mojo::PendingReceiver loader, mojo::PendingRemote client, const net::NetworkTrafficAnnotationTag& annotation, - base::DictionaryValue upload_data) + base::Value::Dict upload_data) : url_loader_(this, std::move(loader)), client_(std::move(client)) { url_loader_.set_disconnect_handler(base::BindOnce( &URLPipeLoader::NotifyComplete, base::Unretained(this), net::ERR_FAILED)); @@ -37,17 +37,17 @@ void URLPipeLoader::Start( scoped_refptr factory, std::unique_ptr request, const net::NetworkTrafficAnnotationTag& annotation, - base::DictionaryValue upload_data) { + base::Value::Dict upload_data) { loader_ = network::SimpleURLLoader::Create(std::move(request), annotation); loader_->SetOnResponseStartedCallback(base::BindOnce( &URLPipeLoader::OnResponseStarted, weak_factory_.GetWeakPtr())); // TODO(zcbenz): The old protocol API only supports string as upload data, // we should seek to support more types in future. - std::string content_type, data; - if (upload_data.GetString("contentType", &content_type) && - upload_data.GetString("data", &data)) - loader_->AttachStringForUpload(data, content_type); + std::string* content_type = upload_data.FindString("contentType"); + std::string* data = upload_data.FindString("data"); + if (content_type && data) + loader_->AttachStringForUpload(*data, *content_type); loader_->DownloadAsStream(factory.get(), this); } @@ -70,9 +70,7 @@ void URLPipeLoader::OnResponseStarted( producer_ = std::make_unique(std::move(producer)); - client_->OnReceiveResponse(response_head.Clone(), - mojo::ScopedDataPipeConsumerHandle()); - client_->OnStartLoadingResponseBody(std::move(consumer)); + client_->OnReceiveResponse(response_head.Clone(), std::move(consumer)); } void URLPipeLoader::OnWrite(base::OnceClosure resume, MojoResult result) { diff --git a/shell/browser/net/url_pipe_loader.h b/shell/browser/net/url_pipe_loader.h index 09baa5f142619..e55a771ea1652 100644 --- a/shell/browser/net/url_pipe_loader.h +++ b/shell/browser/net/url_pipe_loader.h @@ -39,7 +39,7 @@ class URLPipeLoader : public network::mojom::URLLoader, mojo::PendingReceiver loader, mojo::PendingRemote client, const net::NetworkTrafficAnnotationTag& annotation, - base::DictionaryValue upload_data); + base::Value::Dict upload_data); // disable copy URLPipeLoader(const URLPipeLoader&) = delete; @@ -51,7 +51,7 @@ class URLPipeLoader : public network::mojom::URLLoader, void Start(scoped_refptr factory, std::unique_ptr request, const net::NetworkTrafficAnnotationTag& annotation, - base::DictionaryValue upload_data); + base::Value::Dict upload_data); void NotifyComplete(int result); void OnResponseStarted(const GURL& final_url, const network::mojom::URLResponseHead& response_head); diff --git a/shell/browser/notifications/linux/libnotify_notification.cc b/shell/browser/notifications/linux/libnotify_notification.cc index 07d7135788de1..3f7a2fa24f887 100644 --- a/shell/browser/notifications/linux/libnotify_notification.cc +++ b/shell/browser/notifications/linux/libnotify_notification.cc @@ -9,7 +9,6 @@ #include "base/files/file_enumerator.h" #include "base/logging.h" -#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "shell/browser/notifications/notification_delegate.h" #include "shell/browser/ui/gtk_util.h" @@ -138,13 +137,8 @@ void LibnotifyNotification::Show(const NotificationOptions& options) { // Send the desktop name to identify the application // The desktop-entry is the part before the .desktop - std::string desktop_id; - if (platform_util::GetDesktopName(&desktop_id)) { - const std::string suffix{".desktop"}; - if (base::EndsWith(desktop_id, suffix, - base::CompareCase::INSENSITIVE_ASCII)) { - desktop_id.resize(desktop_id.size() - suffix.size()); - } + std::string desktop_id = platform_util::GetXdgAppId(); + if (!desktop_id.empty()) { libnotify_loader_.notify_notification_set_hint_string( notification_, "desktop-entry", desktop_id.c_str()); } diff --git a/shell/browser/notifications/win/win32_desktop_notifications/desktop_notification_controller.cc b/shell/browser/notifications/win/win32_desktop_notifications/desktop_notification_controller.cc index d0de9f6ae1b65..03e435baee20e 100644 --- a/shell/browser/notifications/win/win32_desktop_notifications/desktop_notification_controller.cc +++ b/shell/browser/notifications/win/win32_desktop_notifications/desktop_notification_controller.cc @@ -13,6 +13,7 @@ #include "shell/browser/notifications/win/win32_desktop_notifications/desktop_notification_controller.h" #include +#include #include #include "base/check.h" @@ -238,14 +239,14 @@ void DesktopNotificationController::AnimateAll() { it = stable_partition(it, it2, is_alive); // purge the dead items - for_each(it, it2, [this](auto&& inst) { DestroyToast(&inst); }); + std::for_each(it, it2, [this](auto&& inst) { DestroyToast(&inst); }); if (it2 == instances_.end()) { instances_.erase(it, it2); break; } - it = move(it2); + it = std::move(it2); } } @@ -279,12 +280,12 @@ DesktopNotificationController::AddNotification(std::u16string caption, HBITMAP image) { auto data = std::make_shared(); data->controller = this; - data->caption = move(caption); - data->body_text = move(body_text); + data->caption = std::move(caption); + data->body_text = std::move(body_text); data->image = CopyBitmap(image); // Enqueue new notification - Notification ret{*queue_.insert(queue_.end(), move(data))}; + Notification ret{*queue_.insert(queue_.end(), std::move(data))}; CheckQueue(); return ret; } @@ -310,7 +311,7 @@ void DesktopNotificationController::CloseNotification( void DesktopNotificationController::CheckQueue() { while (instances_.size() < instances_.capacity() && !queue_.empty()) { - CreateToast(move(queue_.front())); + CreateToast(std::move(queue_.front())); queue_.pop_front(); } } @@ -408,8 +409,8 @@ void DesktopNotificationController::Notification::Set(std::u16string caption, if (data_->image) DeleteBitmap(data_->image); - data_->caption = move(caption); - data_->body_text = move(body_text); + data_->caption = std::move(caption); + data_->body_text = std::move(body_text); data_->image = CopyBitmap(image); auto* hwnd = data_->controller->GetToast(data_.get()); diff --git a/shell/browser/notifications/win/windows_toast_notification.cc b/shell/browser/notifications/win/windows_toast_notification.cc index d3dc051753d34..05d508bbe59c0 100644 --- a/shell/browser/notifications/win/windows_toast_notification.cc +++ b/shell/browser/notifications/win/windows_toast_notification.cc @@ -15,7 +15,6 @@ #include "base/logging.h" #include "base/strings/string_util_win.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "shell/browser/notifications/notification_delegate.h" @@ -600,8 +599,8 @@ ToastEventHandler::~ToastEventHandler() = default; IFACEMETHODIMP ToastEventHandler::Invoke( ABI::Windows::UI::Notifications::IToastNotification* sender, IInspectable* args) { - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&Notification::NotificationClicked, notification_)); if (IsDebuggingNotifications()) LOG(INFO) << "Notification clicked"; @@ -612,8 +611,8 @@ IFACEMETHODIMP ToastEventHandler::Invoke( IFACEMETHODIMP ToastEventHandler::Invoke( ABI::Windows::UI::Notifications::IToastNotification* sender, ABI::Windows::UI::Notifications::IToastDismissedEventArgs* e) { - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&Notification::NotificationDismissed, notification_)); if (IsDebuggingNotifications()) LOG(INFO) << "Notification dismissed"; @@ -628,8 +627,8 @@ IFACEMETHODIMP ToastEventHandler::Invoke( e->get_ErrorCode(&error); std::string errorMessage = "Notification failed. HRESULT:" + std::to_string(error); - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&Notification::NotificationFailed, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&Notification::NotificationFailed, notification_, errorMessage)); if (IsDebuggingNotifications()) LOG(INFO) << errorMessage; diff --git a/shell/browser/osr/osr_render_widget_host_view.cc b/shell/browser/osr/osr_render_widget_host_view.cc index f24cf051c5e96..fbf72675bb5a8 100644 --- a/shell/browser/osr/osr_render_widget_host_view.cc +++ b/shell/browser/osr/osr_render_widget_host_view.cc @@ -12,7 +12,6 @@ #include "base/callback_helpers.h" #include "base/location.h" #include "base/memory/ptr_util.h" -#include "base/task/post_task.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "components/viz/common/features.h" @@ -83,19 +82,19 @@ ui::MouseEvent UiMouseEventFromWebMouseEvent(blink::WebMouseEvent event) { int button_flags = 0; switch (event.button) { case blink::WebMouseEvent::Button::kBack: - button_flags |= ui::EventFlags::EF_BACK_MOUSE_BUTTON; + button_flags |= ui::EF_BACK_MOUSE_BUTTON; break; case blink::WebMouseEvent::Button::kForward: - button_flags |= ui::EventFlags::EF_FORWARD_MOUSE_BUTTON; + button_flags |= ui::EF_FORWARD_MOUSE_BUTTON; break; case blink::WebMouseEvent::Button::kLeft: - button_flags |= ui::EventFlags::EF_LEFT_MOUSE_BUTTON; + button_flags |= ui::EF_LEFT_MOUSE_BUTTON; break; case blink::WebMouseEvent::Button::kMiddle: - button_flags |= ui::EventFlags::EF_MIDDLE_MOUSE_BUTTON; + button_flags |= ui::EF_MIDDLE_MOUSE_BUTTON; break; case blink::WebMouseEvent::Button::kRight: - button_flags |= ui::EventFlags::EF_RIGHT_MOUSE_BUTTON; + button_flags |= ui::EF_RIGHT_MOUSE_BUTTON; break; default: button_flags = 0; @@ -397,7 +396,7 @@ void OffScreenRenderWidgetHostView::ResetFallbackToFirstNavigationSurface() { void OffScreenRenderWidgetHostView::InitAsPopup( content::RenderWidgetHostView* parent_host_view, - const gfx::Rect& pos, + const gfx::Rect& bounds, const gfx::Rect& anchor_rect) { DCHECK_EQ(parent_host_view_, parent_host_view); DCHECK_EQ(widget_type_, content::WidgetType::kPopup); @@ -411,13 +410,10 @@ void OffScreenRenderWidgetHostView::InitAsPopup( base::BindRepeating(&OffScreenRenderWidgetHostView::OnPopupPaint, parent_host_view_->weak_ptr_factory_.GetWeakPtr()); - popup_position_ = pos; + popup_position_ = bounds; - ResizeRootLayer(false); + ResizeRootLayer(true); SetPainting(parent_host_view_->IsPainting()); - if (video_consumer_) { - video_consumer_->SizeChanged(); - } Show(); } @@ -688,13 +684,8 @@ void OffScreenRenderWidgetHostView::OnPaint(const gfx::Rect& damage_rect, gfx::Size OffScreenRenderWidgetHostView::SizeInPixels() { float sf = GetDeviceScaleFactor(); - if (IsPopupWidget()) { - return gfx::ToFlooredSize( - gfx::ConvertSizeToPixels(popup_position_.size(), sf)); - } else { - return gfx::ToFlooredSize( - gfx::ConvertSizeToPixels(GetViewBounds().size(), sf)); - } + return gfx::ToFlooredSize( + gfx::ConvertSizeToPixels(GetViewBounds().size(), sf)); } void OffScreenRenderWidgetHostView::CompositeFrame( @@ -765,8 +756,8 @@ void OffScreenRenderWidgetHostView::ReleaseResize() { hold_resize_ = false; if (pending_resize_) { pending_resize_ = false; - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &OffScreenRenderWidgetHostView::SynchronizeVisualProperties, weak_ptr_factory_.GetWeakPtr())); @@ -870,8 +861,8 @@ void OffScreenRenderWidgetHostView::SendMouseWheelEvent( // Scrolling outside of the popup widget so destroy it. // Execute asynchronously to avoid deleting the widget from inside some // other callback. - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&OffScreenRenderWidgetHostView::CancelWidget, popup_host_view_->weak_ptr_factory_.GetWeakPtr())); } @@ -995,7 +986,7 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer(bool force) { display::Screen::GetScreen()->GetDisplayNearestView(GetNativeView()); const float scaleFactor = display.device_scale_factor(); float sf = GetDeviceScaleFactor(); - const bool scaleFactorDidChange = scaleFactor != sf; + const bool sf_did_change = scaleFactor != sf; // Initialize a screen_infos_ struct as needed, to cache the scale factor. if (screen_infos_.screen_infos.empty()) { @@ -1003,14 +994,9 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer(bool force) { } screen_infos_.mutable_current().device_scale_factor = scaleFactor; - gfx::Size size; - if (!IsPopupWidget()) - size = GetViewBounds().size(); - else - size = popup_position_.size(); + gfx::Size size = GetViewBounds().size(); - if (!force && !scaleFactorDidChange && - size == GetRootLayer()->bounds().size()) + if (!force && !sf_did_change && size == GetRootLayer()->bounds().size()) return; GetRootLayer()->SetBounds(gfx::Rect(size)); diff --git a/shell/browser/osr/osr_render_widget_host_view.h b/shell/browser/osr/osr_render_widget_host_view.h index 874fd68268b3d..d047e702941ae 100644 --- a/shell/browser/osr/osr_render_widget_host_view.h +++ b/shell/browser/osr/osr_render_widget_host_view.h @@ -121,7 +121,7 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, void ResetFallbackToFirstNavigationSurface() override; void InitAsPopup(content::RenderWidgetHostView* parent_host_view, - const gfx::Rect& pos, + const gfx::Rect& bounds, const gfx::Rect& anchor_rect) override; void UpdateCursor(const content::WebCursor&) override; void SetIsLoading(bool is_loading) override; diff --git a/shell/browser/osr/osr_video_consumer.cc b/shell/browser/osr/osr_video_consumer.cc index aeb60a7b5b28e..169e04c2b28cb 100644 --- a/shell/browser/osr/osr_video_consumer.cc +++ b/shell/browser/osr/osr_video_consumer.cc @@ -6,6 +6,7 @@ #include +#include "media/base/limits.h" #include "media/base/video_frame_metadata.h" #include "media/capture/mojom/video_capture_buffer.mojom.h" #include "media/capture/mojom/video_capture_types.mojom.h" @@ -13,6 +14,21 @@ #include "shell/browser/osr/osr_render_widget_host_view.h" #include "ui/gfx/skbitmap_operations.h" +namespace { + +bool IsValidMinAndMaxFrameSize(gfx::Size min_frame_size, + gfx::Size max_frame_size) { + // Returns true if + // 0 < |min_frame_size| <= |max_frame_size| <= media::limits::kMaxDimension. + return 0 < min_frame_size.width() && 0 < min_frame_size.height() && + min_frame_size.width() <= max_frame_size.width() && + min_frame_size.height() <= max_frame_size.height() && + max_frame_size.width() <= media::limits::kMaxDimension && + max_frame_size.height() <= media::limits::kMaxDimension; +} + +} // namespace + namespace electron { OffScreenVideoConsumer::OffScreenVideoConsumer( @@ -21,11 +37,11 @@ OffScreenVideoConsumer::OffScreenVideoConsumer( : callback_(callback), view_(view), video_capturer_(view->CreateVideoCapturer()) { - video_capturer_->SetResolutionConstraints(view_->SizeInPixels(), - view_->SizeInPixels(), true); video_capturer_->SetAutoThrottlingEnabled(false); video_capturer_->SetMinSizeChangePeriod(base::TimeDelta()); video_capturer_->SetFormat(media::PIXEL_FORMAT_ARGB); + + SizeChanged(view_->SizeInPixels()); SetFrameRate(view_->GetFrameRate()); } @@ -43,9 +59,10 @@ void OffScreenVideoConsumer::SetFrameRate(int frame_rate) { video_capturer_->SetMinCapturePeriod(base::Seconds(1) / frame_rate); } -void OffScreenVideoConsumer::SizeChanged() { - video_capturer_->SetResolutionConstraints(view_->SizeInPixels(), - view_->SizeInPixels(), true); +void OffScreenVideoConsumer::SizeChanged(const gfx::Size& size_in_pixels) { + DCHECK(IsValidMinAndMaxFrameSize(size_in_pixels, size_in_pixels)); + video_capturer_->SetResolutionConstraints(size_in_pixels, size_in_pixels, + true); video_capturer_->RequestRefreshFrame(); } @@ -58,9 +75,7 @@ void OffScreenVideoConsumer::OnFrameCaptured( auto& data_region = data->get_read_only_shmem_region(); if (!CheckContentRect(content_rect)) { - gfx::Size view_size = view_->SizeInPixels(); - video_capturer_->SetResolutionConstraints(view_size, view_size, true); - video_capturer_->RequestRefreshFrame(); + SizeChanged(view_->SizeInPixels()); return; } @@ -121,6 +136,8 @@ void OffScreenVideoConsumer::OnFrameCaptured( callback_.Run(*update_rect, bitmap); } +void OffScreenVideoConsumer::OnNewCropVersion(uint32_t crop_version) {} + void OffScreenVideoConsumer::OnFrameWithEmptyRegionCapture() {} void OffScreenVideoConsumer::OnStopped() {} diff --git a/shell/browser/osr/osr_video_consumer.h b/shell/browser/osr/osr_video_consumer.h index c6687965441e8..5427eb1251609 100644 --- a/shell/browser/osr/osr_video_consumer.h +++ b/shell/browser/osr/osr_video_consumer.h @@ -33,7 +33,7 @@ class OffScreenVideoConsumer : public viz::mojom::FrameSinkVideoConsumer { void SetActive(bool active); void SetFrameRate(int frame_rate); - void SizeChanged(); + void SizeChanged(const gfx::Size& size_in_pixels); private: // viz::mojom::FrameSinkVideoConsumer implementation. @@ -43,6 +43,7 @@ class OffScreenVideoConsumer : public viz::mojom::FrameSinkVideoConsumer { const gfx::Rect& content_rect, mojo::PendingRemote callbacks) override; + void OnNewCropVersion(uint32_t crop_version) override; void OnFrameWithEmptyRegionCapture() override; void OnStopped() override; void OnLog(const std::string& message) override; diff --git a/shell/browser/osr/osr_web_contents_view_mac.mm b/shell/browser/osr/osr_web_contents_view_mac.mm index 691b1d52e427b..919bec712feb3 100644 --- a/shell/browser/osr/osr_web_contents_view_mac.mm +++ b/shell/browser/osr/osr_web_contents_view_mac.mm @@ -15,7 +15,7 @@ - (void)drawRect:(NSRect)dirtyRect { NSString* str = @"No content under offscreen mode"; NSMutableParagraphStyle* paragraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease]; - [paragraphStyle setAlignment:NSCenterTextAlignment]; + [paragraphStyle setAlignment:NSTextAlignmentCenter]; NSDictionary* attributes = [NSDictionary dictionaryWithObject:paragraphStyle forKey:NSParagraphStyleAttributeName]; diff --git a/shell/browser/printing/print_preview_message_handler.cc b/shell/browser/printing/print_preview_message_handler.cc index 172bd53e33d15..6a6338aae37c6 100644 --- a/shell/browser/printing/print_preview_message_handler.cc +++ b/shell/browser/printing/print_preview_message_handler.cc @@ -11,7 +11,6 @@ #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_memory.h" -#include "base/task/post_task.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" @@ -24,7 +23,6 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_user_data.h" #include "mojo/public/cpp/bindings/callback_helpers.h" -#include "shell/common/gin_helper/locker.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "shell/common/node_includes.h" @@ -43,8 +41,8 @@ void StopWorker(int document_cookie) { std::unique_ptr printer_query = queue->PopPrinterQuery(document_cookie); if (printer_query.get()) { - base::PostTask(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&printing::PrinterQuery::StopWorker, + content::GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&printing::PrinterQuery::StopWorker, std::move(printer_query))); } } @@ -119,7 +117,7 @@ void PrintPreviewMessageHandler::DidPrepareDocumentForPreview( auto* focused_frame = web_contents_->GetFocusedFrame(); auto* rfh = focused_frame && focused_frame->HasSelection() ? focused_frame - : web_contents_->GetMainFrame(); + : web_contents_->GetPrimaryMainFrame(); client->DoPrepareForDocumentToPdf( document_cookie, rfh, @@ -181,7 +179,7 @@ void PrintPreviewMessageHandler::DidPreviewPage( auto* focused_frame = web_contents_->GetFocusedFrame(); auto* rfh = focused_frame && focused_frame->HasSelection() ? focused_frame - : web_contents_->GetMainFrame(); + : web_contents_->GetPrimaryMainFrame(); // Use utility process to convert skia metafile to pdf. client->DoCompositePageToPdf( @@ -219,7 +217,7 @@ void PrintPreviewMessageHandler::PrintToPDF( auto* focused_frame = web_contents_->GetFocusedFrame(); auto* rfh = focused_frame && focused_frame->HasSelection() ? focused_frame - : web_contents_->GetMainFrame(); + : web_contents_->GetPrimaryMainFrame(); if (!print_render_frame_.is_bound()) { rfh->GetRemoteAssociatedInterfaces()->GetInterface(&print_render_frame_); @@ -228,7 +226,7 @@ void PrintPreviewMessageHandler::PrintToPDF( print_render_frame_->SetPrintPreviewUI( receiver_.BindNewEndpointAndPassRemote()); } - print_render_frame_->PrintPreview(options.Clone()); + print_render_frame_->PrintPreview(options.GetDict().Clone()); } gin_helper::Promise> @@ -250,7 +248,6 @@ void PrintPreviewMessageHandler::ResolvePromise( gin_helper::Promise> promise = GetPromise(request_id); v8::Isolate* isolate = promise.isolate(); - gin_helper::Locker locker(isolate); v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope( v8::Local::New(isolate, promise.GetContext())); diff --git a/shell/browser/printing/print_preview_message_handler.h b/shell/browser/printing/print_preview_message_handler.h deleted file mode 100644 index 57d84767d7759..0000000000000 --- a/shell/browser/printing/print_preview_message_handler.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2018 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ELECTRON_SHELL_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ -#define ELECTRON_SHELL_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ - -#include - -#include "base/memory/ref_counted_memory.h" -#include "base/memory/weak_ptr.h" -#include "components/printing/common/print.mojom.h" -#include "components/services/print_compositor/public/mojom/print_compositor.mojom.h" -#include "content/public/browser/web_contents_user_data.h" -#include "mojo/public/cpp/bindings/associated_receiver.h" -#include "mojo/public/cpp/bindings/associated_remote.h" -#include "printing/mojom/print.mojom.h" -#include "shell/common/gin_helper/promise.h" -#include "v8/include/v8.h" - -namespace content { -class RenderFrameHost; -} - -namespace electron { - -// Manages the print preview handling for a WebContents. -class PrintPreviewMessageHandler - : public printing::mojom::PrintPreviewUI, - public content::WebContentsUserData { - public: - ~PrintPreviewMessageHandler() override; - - // disable copy - PrintPreviewMessageHandler(const PrintPreviewMessageHandler&) = delete; - PrintPreviewMessageHandler& operator=(const PrintPreviewMessageHandler&) = - delete; - - void PrintToPDF(base::DictionaryValue options, - gin_helper::Promise> promise); - - private: - friend class content::WebContentsUserData; - - explicit PrintPreviewMessageHandler(content::WebContents* web_contents); - - void OnCompositeDocumentToPdfDone( - int32_t request_id, - printing::mojom::PrintCompositor::Status status, - base::ReadOnlySharedMemoryRegion region); - void OnPrepareForDocumentToPdfDone( - int32_t request_id, - printing::mojom::PrintCompositor::Status status); - void OnCompositePdfPageDone(int page_number, - int document_cookie, - int32_t request_id, - printing::mojom::PrintCompositor::Status status, - base::ReadOnlySharedMemoryRegion region); - - // printing::mojo::PrintPreviewUI: - void SetOptionsFromDocument( - const printing::mojom::OptionsFromDocumentParamsPtr params, - int32_t request_id) override {} - void PrintPreviewFailed(int32_t document_cookie, int32_t request_id) override; - void PrintPreviewCancelled(int32_t document_cookie, - int32_t request_id) override; - void PrinterSettingsInvalid(int32_t document_cookie, - int32_t request_id) override {} - void DidPrepareDocumentForPreview(int32_t document_cookie, - int32_t request_id) override; - void DidPreviewPage(printing::mojom::DidPreviewPageParamsPtr params, - int32_t request_id) override; - void MetafileReadyForPrinting( - printing::mojom::DidPreviewDocumentParamsPtr params, - int32_t request_id) override; - void DidGetDefaultPageLayout( - printing::mojom::PageSizeMarginsPtr page_layout_in_points, - const gfx::Rect& printable_area_in_points, - bool has_custom_page_size_style, - int32_t request_id) override {} - void DidStartPreview(printing::mojom::DidStartPreviewParamsPtr params, - int32_t request_id) override {} - - gin_helper::Promise> GetPromise(int request_id); - - void ResolvePromise(int request_id, - scoped_refptr data_bytes); - void RejectPromise(int request_id); - - using PromiseMap = std::map>>; - PromiseMap promise_map_; - - // TODO(clavin): refactor to use the WebContents provided by the - // WebContentsUserData base class instead of storing a duplicate ref - content::WebContents* web_contents_ = nullptr; - - mojo::AssociatedRemote print_render_frame_; - - mojo::AssociatedReceiver receiver_{this}; - - base::WeakPtrFactory weak_ptr_factory_{this}; - - WEB_CONTENTS_USER_DATA_KEY_DECL(); -}; - -} // namespace electron - -#endif // ELECTRON_SHELL_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ diff --git a/shell/browser/printing/print_view_manager_electron.cc b/shell/browser/printing/print_view_manager_electron.cc index 505073093a7ca..9d33db221eb7b 100644 --- a/shell/browser/printing/print_view_manager_electron.cc +++ b/shell/browser/printing/print_view_manager_electron.cc @@ -6,14 +6,41 @@ #include +#include "base/bind.h" #include "build/build_config.h" -#include "content/public/browser/web_contents_user_data.h" +#include "components/printing/browser/print_to_pdf/pdf_print_utils.h" +#include "printing/mojom/print.mojom.h" +#include "printing/page_range.h" +#include "third_party/abseil-cpp/absl/types/variant.h" + +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +#include "mojo/public/cpp/bindings/message.h" +#endif namespace electron { +namespace { + +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +constexpr char kInvalidUpdatePrintSettingsCall[] = + "Invalid UpdatePrintSettings Call"; +constexpr char kInvalidSetupScriptedPrintPreviewCall[] = + "Invalid SetupScriptedPrintPreview Call"; +constexpr char kInvalidShowScriptedPrintPreviewCall[] = + "Invalid ShowScriptedPrintPreview Call"; +constexpr char kInvalidRequestPrintPreviewCall[] = + "Invalid RequestPrintPreview Call"; +#endif + +} // namespace + +// This file subclasses printing::PrintViewManagerBase +// but the implementations are duplicated from +// components/printing/browser/print_to_pdf/pdf_print_manager.cc. + PrintViewManagerElectron::PrintViewManagerElectron( content::WebContents* web_contents) - : PrintViewManagerBase(web_contents), + : printing::PrintViewManagerBase(web_contents), content::WebContentsUserData(*web_contents) {} PrintViewManagerElectron::~PrintViewManagerElectron() = default; @@ -25,26 +52,225 @@ void PrintViewManagerElectron::BindPrintManagerHost( auto* web_contents = content::WebContents::FromRenderFrameHost(rfh); if (!web_contents) return; + auto* print_manager = PrintViewManagerElectron::FromWebContents(web_contents); if (!print_manager) return; + print_manager->BindReceiver(std::move(receiver), rfh); } +// static +std::string PrintViewManagerElectron::PrintResultToString(PrintResult result) { + switch (result) { + case kPrintSuccess: + return std::string(); // no error message + case kPrintFailure: + return "Printing failed"; + case kInvalidPrinterSettings: + return "Show invalid printer settings error"; + case kInvalidMemoryHandle: + return "Invalid memory handle"; + case kMetafileMapError: + return "Map to shared memory error"; + case kMetafileInvalidHeader: + return "Invalid metafile header"; + case kMetafileGetDataError: + return "Get data from metafile error"; + case kSimultaneousPrintActive: + return "The previous printing job hasn't finished"; + case kPageRangeSyntaxError: + return "Page range syntax error"; + case kPageRangeInvalidRange: + return "Page range is invalid (start > end)"; + case kPageCountExceeded: + return "Page range exceeds page count"; + default: + NOTREACHED(); + return "Unknown PrintResult"; + } +} + +void PrintViewManagerElectron::PrintToPdf( + content::RenderFrameHost* rfh, + const std::string& page_ranges, + printing::mojom::PrintPagesParamsPtr print_pages_params, + PrintToPDFCallback callback) { + DCHECK(callback); + + if (callback_) { + std::move(callback).Run(kSimultaneousPrintActive, + base::MakeRefCounted()); + return; + } + + if (!rfh->IsRenderFrameLive()) { + std::move(callback).Run(kPrintFailure, + base::MakeRefCounted()); + return; + } + + absl::variant + parsed_ranges = print_to_pdf::TextPageRangesToPageRanges(page_ranges); + if (absl::holds_alternative(parsed_ranges)) { + DCHECK_NE(absl::get(parsed_ranges), + print_to_pdf::PdfPrintResult::kPrintSuccess); + std::move(callback).Run( + static_cast( + absl::get(parsed_ranges)), + base::MakeRefCounted()); + return; + } + + printing_rfh_ = rfh; + print_pages_params->pages = absl::get(parsed_ranges); + callback_ = std::move(callback); + + // There is no need for a weak pointer here since the mojo proxy is held + // in the base class. If we're gone, mojo will discard the callback. + GetPrintRenderFrame(rfh)->PrintWithParams( + std::move(print_pages_params), + base::BindOnce(&PrintViewManagerElectron::OnDidPrintWithParams, + base::Unretained(this))); +} + +void PrintViewManagerElectron::OnDidPrintWithParams( + printing::mojom::PrintWithParamsResultPtr result) { + if (result->is_failure_reason()) { + switch (result->get_failure_reason()) { + case printing::mojom::PrintFailureReason::kGeneralFailure: + FailJob(kPrintFailure); + return; + case printing::mojom::PrintFailureReason::kInvalidPageRange: + FailJob(kPageCountExceeded); + return; + } + } + + auto& content = *result->get_params()->content; + if (!content.metafile_data_region.IsValid()) { + FailJob(kInvalidMemoryHandle); + return; + } + + base::ReadOnlySharedMemoryMapping map = content.metafile_data_region.Map(); + if (!map.IsValid()) { + FailJob(kMetafileMapError); + return; + } + + std::string data = + std::string(static_cast(map.memory()), map.size()); + std::move(callback_).Run(kPrintSuccess, + base::RefCountedString::TakeString(&data)); + + Reset(); +} + +void PrintViewManagerElectron::GetDefaultPrintSettings( + GetDefaultPrintSettingsCallback callback) { + if (printing_rfh_) { + LOG(ERROR) << "Scripted print is not supported"; + std::move(callback).Run(printing::mojom::PrintParams::New()); + } else { + PrintViewManagerBase::GetDefaultPrintSettings(std::move(callback)); + } +} + +void PrintViewManagerElectron::ScriptedPrint( + printing::mojom::ScriptedPrintParamsPtr params, + ScriptedPrintCallback callback) { + auto entry = + std::find(headless_jobs_.begin(), headless_jobs_.end(), params->cookie); + if (entry == headless_jobs_.end()) { + PrintViewManagerBase::ScriptedPrint(std::move(params), std::move(callback)); + return; + } + + auto default_param = printing::mojom::PrintPagesParams::New(); + default_param->params = printing::mojom::PrintParams::New(); + LOG(ERROR) << "Scripted print is not supported"; + std::move(callback).Run(std::move(default_param), /*cancelled*/ false); +} + +void PrintViewManagerElectron::ShowInvalidPrinterSettingsError() { + if (headless_jobs_.size() == 0) { + PrintViewManagerBase::ShowInvalidPrinterSettingsError(); + return; + } + + FailJob(kInvalidPrinterSettings); +} + +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +void PrintViewManagerElectron::UpdatePrintSettings( + int32_t cookie, + base::Value::Dict job_settings, + UpdatePrintSettingsCallback callback) { + auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie); + if (entry == headless_jobs_.end()) { + PrintViewManagerBase::UpdatePrintSettings(cookie, std::move(job_settings), + std::move(callback)); + return; + } + + mojo::ReportBadMessage(kInvalidUpdatePrintSettingsCall); +} + void PrintViewManagerElectron::SetupScriptedPrintPreview( SetupScriptedPrintPreviewCallback callback) { - std::move(callback).Run(); + mojo::ReportBadMessage(kInvalidSetupScriptedPrintPreviewCall); } void PrintViewManagerElectron::ShowScriptedPrintPreview( - bool source_is_modifiable) {} + bool source_is_modifiable) { + mojo::ReportBadMessage(kInvalidShowScriptedPrintPreviewCall); +} void PrintViewManagerElectron::RequestPrintPreview( - printing::mojom::RequestPrintPreviewParamsPtr params) {} + printing::mojom::RequestPrintPreviewParamsPtr params) { + mojo::ReportBadMessage(kInvalidRequestPrintPreviewCall); +} void PrintViewManagerElectron::CheckForCancel(int32_t preview_ui_id, int32_t request_id, CheckForCancelCallback callback) { + std::move(callback).Run(false); +} +#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) + +void PrintViewManagerElectron::RenderFrameDeleted( + content::RenderFrameHost* render_frame_host) { + PrintViewManagerBase::RenderFrameDeleted(render_frame_host); + + if (printing_rfh_ != render_frame_host) + return; + + FailJob(kPrintFailure); +} + +void PrintViewManagerElectron::DidGetPrintedPagesCount(int32_t cookie, + uint32_t number_pages) { + auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie); + if (entry == headless_jobs_.end()) { + PrintViewManagerBase::DidGetPrintedPagesCount(cookie, number_pages); + } +} + +void PrintViewManagerElectron::Reset() { + printing_rfh_ = nullptr; + callback_.Reset(); + data_.clear(); +} + +void PrintViewManagerElectron::FailJob(PrintResult result) { + DCHECK_NE(result, kPrintSuccess); + if (callback_) { + std::move(callback_).Run(result, + base::MakeRefCounted()); + } + + Reset(); } WEB_CONTENTS_USER_DATA_KEY_IMPL(PrintViewManagerElectron); diff --git a/shell/browser/printing/print_view_manager_electron.h b/shell/browser/printing/print_view_manager_electron.h index 2127219f953ce..733e41ac4d748 100644 --- a/shell/browser/printing/print_view_manager_electron.h +++ b/shell/browser/printing/print_view_manager_electron.h @@ -5,9 +5,19 @@ #ifndef ELECTRON_SHELL_BROWSER_PRINTING_PRINT_VIEW_MANAGER_ELECTRON_H_ #define ELECTRON_SHELL_BROWSER_PRINTING_PRINT_VIEW_MANAGER_ELECTRON_H_ +#include +#include +#include + +#include "base/memory/raw_ptr.h" +#include "base/memory/ref_counted_memory.h" #include "build/build_config.h" #include "chrome/browser/printing/print_view_manager_base.h" +#include "components/printing/common/print.mojom.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +#include "printing/print_settings.h" namespace electron { @@ -15,9 +25,26 @@ class PrintViewManagerElectron : public printing::PrintViewManagerBase, public content::WebContentsUserData { public: + enum PrintResult { + kPrintSuccess, + kPrintFailure, + kInvalidPrinterSettings, + kInvalidMemoryHandle, + kMetafileMapError, + kMetafileInvalidHeader, + kMetafileGetDataError, + kSimultaneousPrintActive, + kPageRangeSyntaxError, + kPageRangeInvalidRange, + kPageCountExceeded, + }; + + using PrintToPDFCallback = + base::OnceCallback)>; + ~PrintViewManagerElectron() override; - // disable copy PrintViewManagerElectron(const PrintViewManagerElectron&) = delete; PrintViewManagerElectron& operator=(const PrintViewManagerElectron&) = delete; @@ -26,6 +53,34 @@ class PrintViewManagerElectron receiver, content::RenderFrameHost* rfh); + static std::string PrintResultToString(PrintResult result); + + void PrintToPdf(content::RenderFrameHost* rfh, + const std::string& page_ranges, + printing::mojom::PrintPagesParamsPtr print_page_params, + PrintToPDFCallback callback); + + private: + friend class content::WebContentsUserData; + + explicit PrintViewManagerElectron(content::WebContents* web_contents); + + void OnDidPrintWithParams(printing::mojom::PrintWithParamsResultPtr result); + + // WebContentsObserver overrides (via PrintManager): + void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; + + // printing::mojom::PrintManagerHost: + void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override; + void GetDefaultPrintSettings( + GetDefaultPrintSettingsCallback callback) override; + void ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr params, + ScriptedPrintCallback callback) override; + void ShowInvalidPrinterSettingsError() override; +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) + void UpdatePrintSettings(int32_t cookie, + base::Value::Dict job_settings, + UpdatePrintSettingsCallback callback) override; void SetupScriptedPrintPreview( SetupScriptedPrintPreviewCallback callback) override; void ShowScriptedPrintPreview(bool source_is_modifiable) override; @@ -34,10 +89,15 @@ class PrintViewManagerElectron void CheckForCancel(int32_t preview_ui_id, int32_t request_id, CheckForCancelCallback callback) override; +#endif - private: - friend class content::WebContentsUserData; - explicit PrintViewManagerElectron(content::WebContents* web_contents); + void FailJob(PrintResult result); + void Reset(); + + raw_ptr printing_rfh_ = nullptr; + PrintToPDFCallback callback_; + std::string data_; + std::vector headless_jobs_; WEB_CONTENTS_USER_DATA_KEY_DECL(); }; diff --git a/shell/browser/relauncher_linux.cc b/shell/browser/relauncher_linux.cc index a776309117369..9268775768d34 100644 --- a/shell/browser/relauncher_linux.cc +++ b/shell/browser/relauncher_linux.cc @@ -15,9 +15,7 @@ #include "base/process/launch.h" #include "base/synchronization/waitable_event.h" -namespace relauncher { - -namespace internal { +namespace relauncher::internal { // this is global to be visible to the sa_handler base::WaitableEvent parentWaiter; @@ -68,6 +66,4 @@ int LaunchProgram(const StringVector& relauncher_args, return process.IsValid() ? 0 : 1; } -} // namespace internal - -} // namespace relauncher +} // namespace relauncher::internal diff --git a/shell/browser/relauncher_mac.cc b/shell/browser/relauncher_mac.cc index 38294618d85f5..c46cec6aa5cde 100644 --- a/shell/browser/relauncher_mac.cc +++ b/shell/browser/relauncher_mac.cc @@ -16,9 +16,7 @@ #include "base/process/launch.h" #include "base/strings/sys_string_conversions.h" -namespace relauncher { - -namespace internal { +namespace relauncher::internal { void RelauncherSynchronizeWithParent() { base::ScopedFD relauncher_sync_fd(kRelauncherSyncFD); @@ -91,6 +89,4 @@ int LaunchProgram(const StringVector& relauncher_args, return process.IsValid() ? 0 : 1; } -} // namespace internal - -} // namespace relauncher +} // namespace relauncher::internal diff --git a/shell/browser/relauncher_win.cc b/shell/browser/relauncher_win.cc index 0a3a254ec1195..c732e9f287cb2 100644 --- a/shell/browser/relauncher_win.cc +++ b/shell/browser/relauncher_win.cc @@ -14,9 +14,7 @@ #include "sandbox/win/src/win_utils.h" #include "ui/base/win/shell.h" -namespace relauncher { - -namespace internal { +namespace relauncher::internal { namespace { @@ -125,6 +123,4 @@ int LaunchProgram(const StringVector& relauncher_args, return process.IsValid() ? 0 : 1; } -} // namespace internal - -} // namespace relauncher +} // namespace relauncher::internal diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index 1fef30734ace8..55164305f4d69 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 18,2,1,0 - PRODUCTVERSION 18,2,1,0 + FILEVERSION 21,2,0,0 + PRODUCTVERSION 21,2,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "18.2.1" + VALUE "FileVersion", "21.2.0" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "18.2.1" + VALUE "ProductVersion", "21.2.0" VALUE "SquirrelAwareVersion", "1" END END diff --git a/shell/browser/serial/electron_serial_delegate.cc b/shell/browser/serial/electron_serial_delegate.cc index c2b6df45041d8..0c7f63d4ab9fe 100644 --- a/shell/browser/serial/electron_serial_delegate.cc +++ b/shell/browser/serial/electron_serial_delegate.cc @@ -49,18 +49,16 @@ bool ElectronSerialDelegate::CanRequestPortPermission( auto* permission_helper = WebContentsPermissionHelper::FromWebContents(web_contents); return permission_helper->CheckSerialAccessPermission( - web_contents->GetMainFrame()->GetLastCommittedOrigin()); + web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin()); } bool ElectronSerialDelegate::HasPortPermission( content::RenderFrameHost* frame, const device::mojom::SerialPortInfo& port) { auto* web_contents = content::WebContents::FromRenderFrameHost(frame); - auto* browser_context = web_contents->GetBrowserContext(); - auto* chooser_context = - SerialChooserContextFactory::GetForBrowserContext(browser_context); - return chooser_context->HasPortPermission( - web_contents->GetMainFrame()->GetLastCommittedOrigin(), port, frame); + return GetChooserContext(frame)->HasPortPermission( + web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin(), port, + frame); } device::mojom::SerialPortManager* ElectronSerialDelegate::GetPortManager( @@ -68,17 +66,31 @@ device::mojom::SerialPortManager* ElectronSerialDelegate::GetPortManager( return GetChooserContext(frame)->GetPortManager(); } -void ElectronSerialDelegate::AddObserver(content::RenderFrameHost* frame, - Observer* observer) { - return GetChooserContext(frame)->AddPortObserver(observer); +void ElectronSerialDelegate::AddObserver( + content::RenderFrameHost* frame, + content::SerialDelegate::Observer* observer) { + observer_list_.AddObserver(observer); + auto* chooser_context = GetChooserContext(frame); + if (!port_observation_.IsObserving()) + port_observation_.Observe(chooser_context); } -void ElectronSerialDelegate::RemoveObserver(content::RenderFrameHost* frame, - Observer* observer) { - SerialChooserContext* serial_chooser_context = GetChooserContext(frame); - if (serial_chooser_context) { - return serial_chooser_context->RemovePortObserver(observer); - } +void ElectronSerialDelegate::RemoveObserver( + content::RenderFrameHost* frame, + content::SerialDelegate::Observer* observer) { + observer_list_.RemoveObserver(observer); +} + +void ElectronSerialDelegate::RevokePortPermissionWebInitiated( + content::RenderFrameHost* frame, + const base::UnguessableToken& token) { + // TODO(nornagon/jkleinsc): pass this on to the chooser context +} + +const device::mojom::SerialPortInfo* ElectronSerialDelegate::GetPortInfo( + content::RenderFrameHost* frame, + const base::UnguessableToken& token) { + return GetChooserContext(frame)->GetPortInfo(token); } SerialChooserController* ElectronSerialDelegate::ControllerForFrame( @@ -106,4 +118,27 @@ void ElectronSerialDelegate::DeleteControllerForFrame( controller_map_.erase(render_frame_host); } +// SerialChooserContext::PortObserver: +void ElectronSerialDelegate::OnPortAdded( + const device::mojom::SerialPortInfo& port) { + for (auto& observer : observer_list_) + observer.OnPortAdded(port); +} + +void ElectronSerialDelegate::OnPortRemoved( + const device::mojom::SerialPortInfo& port) { + for (auto& observer : observer_list_) + observer.OnPortRemoved(port); +} + +void ElectronSerialDelegate::OnPortManagerConnectionError() { + port_observation_.Reset(); + for (auto& observer : observer_list_) + observer.OnPortManagerConnectionError(); +} + +void ElectronSerialDelegate::OnSerialChooserContextShutdown() { + port_observation_.Reset(); +} + } // namespace electron diff --git a/shell/browser/serial/electron_serial_delegate.h b/shell/browser/serial/electron_serial_delegate.h index ef9c4af749ff4..add2c4471f1e4 100644 --- a/shell/browser/serial/electron_serial_delegate.h +++ b/shell/browser/serial/electron_serial_delegate.h @@ -11,13 +11,15 @@ #include "base/memory/weak_ptr.h" #include "content/public/browser/serial_delegate.h" +#include "shell/browser/serial/serial_chooser_context.h" #include "shell/browser/serial/serial_chooser_controller.h" namespace electron { class SerialChooserController; -class ElectronSerialDelegate : public content::SerialDelegate { +class ElectronSerialDelegate : public content::SerialDelegate, + public SerialChooserContext::PortObserver { public: ElectronSerialDelegate(); ~ElectronSerialDelegate() override; @@ -36,12 +38,25 @@ class ElectronSerialDelegate : public content::SerialDelegate { device::mojom::SerialPortManager* GetPortManager( content::RenderFrameHost* frame) override; void AddObserver(content::RenderFrameHost* frame, - Observer* observer) override; + content::SerialDelegate::Observer* observer) override; void RemoveObserver(content::RenderFrameHost* frame, - Observer* observer) override; + content::SerialDelegate::Observer* observer) override; + void RevokePortPermissionWebInitiated( + content::RenderFrameHost* frame, + const base::UnguessableToken& token) override; + const device::mojom::SerialPortInfo* GetPortInfo( + content::RenderFrameHost* frame, + const base::UnguessableToken& token) override; void DeleteControllerForFrame(content::RenderFrameHost* render_frame_host); + // SerialChooserContext::PortObserver: + void OnPortAdded(const device::mojom::SerialPortInfo& port) override; + void OnPortRemoved(const device::mojom::SerialPortInfo& port) override; + void OnPortManagerConnectionError() override; + void OnPermissionRevoked(const url::Origin& origin) override {} + void OnSerialChooserContextShutdown() override; + private: SerialChooserController* ControllerForFrame( content::RenderFrameHost* render_frame_host); @@ -50,6 +65,13 @@ class ElectronSerialDelegate : public content::SerialDelegate { std::vector filters, content::SerialChooser::Callback callback); + base::ScopedObservation + port_observation_{this}; + base::ObserverList observer_list_; + std::unordered_map> controller_map_; diff --git a/shell/browser/serial/serial_chooser_context.cc b/shell/browser/serial/serial_chooser_context.cc index 04156f3bee584..080a1030d4315 100644 --- a/shell/browser/serial/serial_chooser_context.cc +++ b/shell/browser/serial/serial_chooser_context.cc @@ -15,6 +15,7 @@ #include "content/public/browser/device_service.h" #include "content/public/browser/web_contents.h" #include "mojo/public/cpp/bindings/pending_remote.h" +#include "shell/browser/electron_permission_manager.h" #include "shell/browser/web_contents_permission_helper.h" namespace electron { @@ -86,34 +87,50 @@ base::Value PortInfoToValue(const device::mojom::SerialPortInfo& port) { return value; } -SerialChooserContext::SerialChooserContext() = default; +SerialChooserContext::SerialChooserContext(ElectronBrowserContext* context) + : browser_context_(context) {} -SerialChooserContext::~SerialChooserContext() = default; +SerialChooserContext::~SerialChooserContext() { + // Notify observers that the chooser context is about to be destroyed. + // Observers must remove themselves from the observer lists. + for (auto& observer : port_observer_list_) { + observer.OnSerialChooserContextShutdown(); + DCHECK(!port_observer_list_.HasObserver(&observer)); + } +} void SerialChooserContext::GrantPortPermission( const url::Origin& origin, const device::mojom::SerialPortInfo& port, content::RenderFrameHost* render_frame_host) { - base::Value value = PortInfoToValue(port); - auto* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - auto* permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - permission_helper->GrantSerialPortPermission(origin, std::move(value), - render_frame_host); + port_info_.insert({port.token, port.Clone()}); + + auto* permission_manager = static_cast( + browser_context_->GetPermissionControllerDelegate()); + return permission_manager->GrantDevicePermission( + static_cast( + WebContentsPermissionHelper::PermissionType::SERIAL), + origin, PortInfoToValue(port), browser_context_); } bool SerialChooserContext::HasPortPermission( const url::Origin& origin, const device::mojom::SerialPortInfo& port, content::RenderFrameHost* render_frame_host) { - auto* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - auto* permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - base::Value value = PortInfoToValue(port); - return permission_helper->CheckSerialPortPermission(origin, std::move(value), - render_frame_host); + auto* permission_manager = static_cast( + browser_context_->GetPermissionControllerDelegate()); + return permission_manager->CheckDevicePermission( + static_cast( + WebContentsPermissionHelper::PermissionType::SERIAL), + origin, PortInfoToValue(port), browser_context_); +} + +void SerialChooserContext::RevokePortPermissionWebInitiated( + const url::Origin& origin, + const base::UnguessableToken& token) { + auto it = port_info_.find(token); + if (it == port_info_.end()) + return; } // static @@ -150,6 +167,13 @@ bool SerialChooserContext::CanStorePersistentEntry( #endif // BUILDFLAG(IS_WIN) } +const device::mojom::SerialPortInfo* SerialChooserContext::GetPortInfo( + const base::UnguessableToken& token) { + DCHECK(is_initialized_); + auto it = port_info_.find(token); + return it == port_info_.end() ? nullptr : it->second.get(); +} + device::mojom::SerialPortManager* SerialChooserContext::GetPortManager() { EnsurePortManagerConnection(); return port_manager_.get(); @@ -168,6 +192,9 @@ base::WeakPtr SerialChooserContext::AsWeakPtr() { } void SerialChooserContext::OnPortAdded(device::mojom::SerialPortInfoPtr port) { + if (!base::Contains(port_info_, port->token)) + port_info_.insert({port->token, port->Clone()}); + for (auto& observer : port_observer_list_) observer.OnPortAdded(*port); } @@ -176,6 +203,8 @@ void SerialChooserContext::OnPortRemoved( device::mojom::SerialPortInfoPtr port) { for (auto& observer : port_observer_list_) observer.OnPortRemoved(*port); + + port_info_.erase(port->token); } void SerialChooserContext::EnsurePortManagerConnection() { @@ -196,6 +225,15 @@ void SerialChooserContext::SetUpPortManagerConnection( base::Unretained(this))); port_manager_->SetClient(client_receiver_.BindNewPipeAndPassRemote()); + port_manager_->GetDevices(base::BindOnce(&SerialChooserContext::OnGetDevices, + weak_factory_.GetWeakPtr())); +} + +void SerialChooserContext::OnGetDevices( + std::vector ports) { + for (auto& port : ports) + port_info_.insert({port->token, std::move(port)}); + is_initialized_ = true; } void SerialChooserContext::OnPortManagerConnectionError() { diff --git a/shell/browser/serial/serial_chooser_context.h b/shell/browser/serial/serial_chooser_context.h index 657ee7b10016c..148bf14996cad 100644 --- a/shell/browser/serial/serial_chooser_context.h +++ b/shell/browser/serial/serial_chooser_context.h @@ -46,9 +46,14 @@ extern const char kUsbDriverKey[]; class SerialChooserContext : public KeyedService, public device::mojom::SerialPortManagerClient { public: - using PortObserver = content::SerialDelegate::Observer; - - SerialChooserContext(); + class PortObserver : public content::SerialDelegate::Observer { + public: + // Called when the SerialChooserContext is shutting down. Observers must + // remove themselves before returning. + virtual void OnSerialChooserContextShutdown() = 0; + }; + + explicit SerialChooserContext(ElectronBrowserContext* context); ~SerialChooserContext() override; // disable copy @@ -72,20 +77,38 @@ class SerialChooserContext : public KeyedService, base::WeakPtr AsWeakPtr(); + bool is_initialized_ = false; + + // Map from port token to port info. + std::map port_info_; + // SerialPortManagerClient implementation. void OnPortAdded(device::mojom::SerialPortInfoPtr port) override; void OnPortRemoved(device::mojom::SerialPortInfoPtr port) override; + void RevokePortPermissionWebInitiated(const url::Origin& origin, + const base::UnguessableToken& token); + // Only call this if you're sure |port_info_| has been initialized + // before-hand. The returned raw pointer is owned by |port_info_| and will be + // destroyed when the port is removed. + const device::mojom::SerialPortInfo* GetPortInfo( + const base::UnguessableToken& token); private: void EnsurePortManagerConnection(); void SetUpPortManagerConnection( mojo::PendingRemote manager); + void OnGetDevices(std::vector ports); void OnPortManagerConnectionError(); + void RevokeObjectPermissionInternal(const url::Origin& origin, + const base::Value& object, + bool revoked_by_website); mojo::Remote port_manager_; mojo::Receiver client_receiver_{this}; base::ObserverList port_observer_list_; + ElectronBrowserContext* browser_context_; + base::WeakPtrFactory weak_factory_{this}; }; diff --git a/shell/browser/serial/serial_chooser_context_factory.cc b/shell/browser/serial/serial_chooser_context_factory.cc index 914bdd49998a2..c3f18c856b7a0 100644 --- a/shell/browser/serial/serial_chooser_context_factory.cc +++ b/shell/browser/serial/serial_chooser_context_factory.cc @@ -19,7 +19,9 @@ SerialChooserContextFactory::~SerialChooserContextFactory() = default; KeyedService* SerialChooserContextFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - return new SerialChooserContext(); + auto* browser_context = + static_cast(context); + return new SerialChooserContext(browser_context); } // static diff --git a/shell/browser/serial/serial_chooser_controller.cc b/shell/browser/serial/serial_chooser_controller.cc index 695d1f3161c66..017d951d4c01b 100644 --- a/shell/browser/serial/serial_chooser_controller.cc +++ b/shell/browser/serial/serial_chooser_controller.cc @@ -69,7 +69,7 @@ SerialChooserController::SerialChooserController( callback_(std::move(callback)), serial_delegate_(serial_delegate), render_frame_host_id_(render_frame_host->GetGlobalId()) { - origin_ = web_contents->GetMainFrame()->GetLastCommittedOrigin(); + origin_ = web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin(); chooser_context_ = SerialChooserContextFactory::GetForBrowserContext( web_contents->GetBrowserContext()) @@ -77,13 +77,11 @@ SerialChooserController::SerialChooserController( DCHECK(chooser_context_); chooser_context_->GetPortManager()->GetDevices(base::BindOnce( &SerialChooserController::OnGetDevices, weak_factory_.GetWeakPtr())); + observation_.Observe(chooser_context_.get()); } SerialChooserController::~SerialChooserController() { RunCallback(/*port=*/nullptr); - if (chooser_context_) { - chooser_context_->RemovePortObserver(this); - } } api::Session* SerialChooserController::GetSession() { @@ -116,6 +114,14 @@ void SerialChooserController::OnPortRemoved( } } +void SerialChooserController::OnPortManagerConnectionError() { + observation_.Reset(); +} + +void SerialChooserController::OnSerialChooserContextShutdown() { + observation_.Reset(); +} + void SerialChooserController::OnDeviceChosen(const std::string& port_id) { if (port_id.empty()) { RunCallback(/*port=*/nullptr); diff --git a/shell/browser/serial/serial_chooser_controller.h b/shell/browser/serial/serial_chooser_controller.h index 368cf18652a99..761065763fbdb 100644 --- a/shell/browser/serial/serial_chooser_controller.h +++ b/shell/browser/serial/serial_chooser_controller.h @@ -46,7 +46,9 @@ class SerialChooserController final : public SerialChooserContext::PortObserver, // SerialChooserContext::PortObserver: void OnPortAdded(const device::mojom::SerialPortInfo& port) override; void OnPortRemoved(const device::mojom::SerialPortInfo& port) override; - void OnPortManagerConnectionError() override {} + void OnPortManagerConnectionError() override; + void OnPermissionRevoked(const url::Origin& origin) override {} + void OnSerialChooserContextShutdown() override; private: api::Session* GetSession(); @@ -61,6 +63,12 @@ class SerialChooserController final : public SerialChooserContext::PortObserver, base::WeakPtr chooser_context_; + base::ScopedObservation + observation_{this}; + std::vector ports_; base::WeakPtr serial_delegate_; diff --git a/shell/browser/special_storage_policy.cc b/shell/browser/special_storage_policy.cc index 37ab036c7969a..351e831bef995 100644 --- a/shell/browser/special_storage_policy.cc +++ b/shell/browser/special_storage_policy.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "services/network/public/cpp/session_cookie_delete_predicate.h" namespace electron { @@ -37,9 +38,4 @@ bool SpecialStoragePolicy::HasSessionOnlyOrigins() { return false; } -network::DeleteCookiePredicate -SpecialStoragePolicy::CreateDeleteCookieOnExitPredicate() { - return network::DeleteCookiePredicate(); -} - } // namespace electron diff --git a/shell/browser/special_storage_policy.h b/shell/browser/special_storage_policy.h index aa0ac9cca583d..30aa4bd54fb5a 100644 --- a/shell/browser/special_storage_policy.h +++ b/shell/browser/special_storage_policy.h @@ -20,7 +20,6 @@ class SpecialStoragePolicy : public storage::SpecialStoragePolicy { bool HasIsolatedStorage(const GURL& origin) override; bool IsStorageSessionOnly(const GURL& origin) override; bool HasSessionOnlyOrigins() override; - network::DeleteCookiePredicate CreateDeleteCookieOnExitPredicate() override; protected: ~SpecialStoragePolicy() override; diff --git a/shell/browser/ui/accelerator_util.cc b/shell/browser/ui/accelerator_util.cc index c9c5fb511e824..c40f10bead1e5 100644 --- a/shell/browser/ui/accelerator_util.cc +++ b/shell/browser/ui/accelerator_util.cc @@ -71,8 +71,8 @@ bool StringToAccelerator(const std::string& shortcut, void GenerateAcceleratorTable(AcceleratorTable* table, electron::ElectronMenuModel* model) { - int count = model->GetItemCount(); - for (int i = 0; i < count; ++i) { + size_t count = model->GetItemCount(); + for (size_t i = 0; i < count; ++i) { electron::ElectronMenuModel::ItemType type = model->GetTypeAt(i); if (type == electron::ElectronMenuModel::TYPE_SUBMENU) { auto* submodel = model->GetSubmenuModelAt(i); diff --git a/shell/browser/ui/accelerator_util.h b/shell/browser/ui/accelerator_util.h index c573aeaab2260..35c44869aa6b6 100644 --- a/shell/browser/ui/accelerator_util.h +++ b/shell/browser/ui/accelerator_util.h @@ -14,7 +14,7 @@ namespace accelerator_util { typedef struct { - int position; + size_t position; electron::ElectronMenuModel* model; } MenuItem; typedef std::map AcceleratorTable; diff --git a/shell/browser/ui/autofill_popup.cc b/shell/browser/ui/autofill_popup.cc index dc40be4b03be1..93975bf676eaa 100644 --- a/shell/browser/ui/autofill_popup.cc +++ b/shell/browser/ui/autofill_popup.cc @@ -62,7 +62,7 @@ void CalculatePopupXAndWidthHorizontallyCentered( // Calculate how much the pop-up needs to grow into the non-preferred // direction. - int amount_to_grow_in_unpreffered_direction = + int amount_to_grow_in_unpreferred_direction = std::max(0, popup_width - space_to_grow_in_preferred_direction); bubble_bounds->set_width(popup_width); @@ -70,10 +70,10 @@ void CalculatePopupXAndWidthHorizontallyCentered( // Note, in RTL the |pop_up_width| must be subtracted to achieve // right-alignment of the pop-up with the element. bubble_bounds->set_x(preferred_starting_point - popup_width + - amount_to_grow_in_unpreffered_direction); + amount_to_grow_in_unpreferred_direction); } else { bubble_bounds->set_x(preferred_starting_point - - amount_to_grow_in_unpreffered_direction); + amount_to_grow_in_unpreferred_direction); } } diff --git a/shell/browser/ui/certificate_trust_mac.mm b/shell/browser/ui/certificate_trust_mac.mm index ae234d6fccf75..de9006728cec0 100644 --- a/shell/browser/ui/certificate_trust_mac.mm +++ b/shell/browser/ui/certificate_trust_mac.mm @@ -13,8 +13,7 @@ #include "base/strings/sys_string_conversions.h" #include "net/cert/cert_database.h" -#include "net/cert/x509_util_ios_and_mac.h" -#include "net/cert/x509_util_mac.h" +#include "net/cert/x509_util_apple.h" #include "shell/browser/native_window.h" @interface TrustDelegate : NSObject { diff --git a/shell/browser/ui/cocoa/electron_bundle_mover.mm b/shell/browser/ui/cocoa/electron_bundle_mover.mm index b7e61f97059dc..57dcadc9932d9 100644 --- a/shell/browser/ui/cocoa/electron_bundle_mover.mm +++ b/shell/browser/ui/cocoa/electron_bundle_mover.mm @@ -182,18 +182,27 @@ return IsInApplicationsFolder([[NSBundle mainBundle] bundlePath]); } +NSString* resolvePath(NSString* path) { + NSString* standardizedPath = [path stringByStandardizingPath]; + char resolved[PATH_MAX]; + if (realpath([standardizedPath UTF8String], resolved) == NULL) + return path; + return @(resolved); +} + bool ElectronBundleMover::IsInApplicationsFolder(NSString* bundlePath) { // Check all the normal Application directories NSArray* applicationDirs = NSSearchPathForDirectoriesInDomains( NSApplicationDirectory, NSAllDomainsMask, true); + NSString* resolvedBundlePath = resolvePath(bundlePath); for (NSString* appDir in applicationDirs) { - if ([bundlePath hasPrefix:appDir]) + if ([resolvedBundlePath hasPrefix:appDir]) return true; } // Also, handle the case that the user has some other Application directory // (perhaps on a separate data partition). - if ([[bundlePath pathComponents] containsObject:@"Applications"]) + if ([[resolvedBundlePath pathComponents] containsObject:@"Applications"]) return true; return false; @@ -291,9 +300,10 @@ AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0}; AuthorizationRights myRights = {1, &myItems}; - AuthorizationFlags myFlags = (AuthorizationFlags)( - kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights | - kAuthorizationFlagPreAuthorize); + AuthorizationFlags myFlags = + (AuthorizationFlags)(kAuthorizationFlagInteractionAllowed | + kAuthorizationFlagExtendRights | + kAuthorizationFlagPreAuthorize); err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL); diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm index 3f86dca5158e5..d223c823ca297 100644 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm +++ b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm @@ -176,8 +176,9 @@ - (void)setIsDocked:(BOOL)docked activate:(BOOL)activate { auto devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView(); if (!docked) { auto styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSMiniaturizableWindowMask | NSWindowStyleMaskResizable | - NSTexturedBackgroundWindowMask | + NSWindowStyleMaskMiniaturizable | + NSWindowStyleMaskResizable | + NSWindowStyleMaskTexturedBackground | NSWindowStyleMaskUnifiedTitleAndToolbar; devtools_window_.reset([[EventDispatchingWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600) diff --git a/shell/browser/ui/cocoa/electron_menu_controller.mm b/shell/browser/ui/cocoa/electron_menu_controller.mm index d2ffeb77637a3..9caeadd9fb407 100644 --- a/shell/browser/ui/cocoa/electron_menu_controller.mm +++ b/shell/browser/ui/cocoa/electron_menu_controller.mm @@ -12,7 +12,6 @@ #include "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "net/base/mac/url_conversions.h" @@ -227,7 +226,8 @@ - (void)cancel { if (model_) model_->MenuWillClose(); if (!closeCallback.is_null()) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(closeCallback)); + content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, + std::move(closeCallback)); } } } @@ -422,10 +422,8 @@ - (NSMenuItem*)menuItemForService:(NSSharingService*)service [item setKeyEquivalentModifierMask:modifier_mask]; } - if (@available(macOS 10.13, *)) { - [(id)item - setAllowsKeyEquivalentWhenHidden:(model->WorksWhenHiddenAt(index))]; - } + [(id)item + setAllowsKeyEquivalentWhenHidden:(model->WorksWhenHiddenAt(index))]; // Set menu item's role. [item setTarget:self]; @@ -536,7 +534,8 @@ - (void)menuDidClose:(NSMenu*)menu { // Post async task so that itemSelected runs before the close callback // deletes the controller from the map which deallocates it if (!closeCallback.is_null()) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(closeCallback)); + content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, + std::move(closeCallback)); } } } diff --git a/shell/browser/ui/cocoa/electron_native_widget_mac.h b/shell/browser/ui/cocoa/electron_native_widget_mac.h index 7fdfd0433a01a..2e378ce0fa7e3 100644 --- a/shell/browser/ui/cocoa/electron_native_widget_mac.h +++ b/shell/browser/ui/cocoa/electron_native_widget_mac.h @@ -5,6 +5,8 @@ #ifndef ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NATIVE_WIDGET_MAC_H_ #define ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NATIVE_WIDGET_MAC_H_ +#include + #include "ui/views/widget/native_widget_mac.h" namespace electron { @@ -14,6 +16,7 @@ class NativeWindowMac; class ElectronNativeWidgetMac : public views::NativeWidgetMac { public: ElectronNativeWidgetMac(NativeWindowMac* shell, + const std::string& window_type, NSUInteger style_mask, views::internal::NativeWidgetDelegate* delegate); ~ElectronNativeWidgetMac() override; @@ -29,6 +32,7 @@ class ElectronNativeWidgetMac : public views::NativeWidgetMac { private: NativeWindowMac* shell_; + std::string window_type_; NSUInteger style_mask_; }; diff --git a/shell/browser/ui/cocoa/electron_native_widget_mac.mm b/shell/browser/ui/cocoa/electron_native_widget_mac.mm index 4247a45229f93..12a9469b92ba6 100644 --- a/shell/browser/ui/cocoa/electron_native_widget_mac.mm +++ b/shell/browser/ui/cocoa/electron_native_widget_mac.mm @@ -4,24 +4,34 @@ #include "shell/browser/ui/cocoa/electron_native_widget_mac.h" +#include + +#include "shell/browser/ui/cocoa/electron_ns_panel.h" #include "shell/browser/ui/cocoa/electron_ns_window.h" namespace electron { ElectronNativeWidgetMac::ElectronNativeWidgetMac( NativeWindowMac* shell, + const std::string& window_type, NSUInteger style_mask, views::internal::NativeWidgetDelegate* delegate) : views::NativeWidgetMac(delegate), shell_(shell), + window_type_(window_type), style_mask_(style_mask) {} ElectronNativeWidgetMac::~ElectronNativeWidgetMac() = default; NativeWidgetMacNSWindow* ElectronNativeWidgetMac::CreateNSWindow( const remote_cocoa::mojom::CreateWindowParams* params) { - return [[[ElectronNSWindow alloc] initWithShell:shell_ - styleMask:style_mask_] autorelease]; + if (window_type_ == "panel") { + return [[[ElectronNSPanel alloc] initWithShell:shell_ + styleMask:style_mask_] autorelease]; + } else { + return [[[ElectronNSWindow alloc] initWithShell:shell_ + styleMask:style_mask_] autorelease]; + } } } // namespace electron diff --git a/shell/browser/ui/cocoa/electron_ns_panel.h b/shell/browser/ui/cocoa/electron_ns_panel.h new file mode 100644 index 0000000000000..755271acec135 --- /dev/null +++ b/shell/browser/ui/cocoa/electron_ns_panel.h @@ -0,0 +1,17 @@ +// Copyright (c) 2022 Microsoft, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NS_PANEL_H_ +#define ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NS_PANEL_H_ + +#include "shell/browser/ui/cocoa/electron_ns_window.h" + +@interface ElectronNSPanel : ElectronNSWindow +@property NSWindowStyleMask styleMask; +@property NSWindowStyleMask originalStyleMask; +- (id)initWithShell:(electron::NativeWindowMac*)shell + styleMask:(NSUInteger)styleMask; +@end + +#endif // ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NS_PANEL_H_ diff --git a/shell/browser/ui/cocoa/electron_ns_panel.mm b/shell/browser/ui/cocoa/electron_ns_panel.mm new file mode 100644 index 0000000000000..f046943772c85 --- /dev/null +++ b/shell/browser/ui/cocoa/electron_ns_panel.mm @@ -0,0 +1,39 @@ +// Copyright (c) 2022 Microsoft, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/ui/cocoa/electron_ns_panel.h" + +@implementation ElectronNSPanel + +@synthesize originalStyleMask; + +- (id)initWithShell:(electron::NativeWindowMac*)shell + styleMask:(NSUInteger)styleMask { + if (self = [super initWithShell:shell styleMask:styleMask]) { + originalStyleMask = styleMask; + } + return self; +} + +@dynamic styleMask; +// The Nonactivating mask is reserved for NSPanel, +// but we can use this workaround to add it at runtime +- (NSWindowStyleMask)styleMask { + return originalStyleMask | NSWindowStyleMaskNonactivatingPanel; +} + +- (void)setStyleMask:(NSWindowStyleMask)styleMask { + originalStyleMask = styleMask; + // Notify change of style mask. + [super setStyleMask:styleMask]; +} + +- (void)setCollectionBehavior:(NSWindowCollectionBehavior)collectionBehavior { + NSWindowCollectionBehavior panelBehavior = + (NSWindowCollectionBehaviorCanJoinAllSpaces | + NSWindowCollectionBehaviorFullScreenAuxiliary); + [super setCollectionBehavior:collectionBehavior | panelBehavior]; +} + +@end diff --git a/shell/browser/ui/cocoa/electron_ns_window.h b/shell/browser/ui/cocoa/electron_ns_window.h index 50ad1ca8a96d2..f5d7b80b0399b 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.h +++ b/shell/browser/ui/cocoa/electron_ns_window.h @@ -16,13 +16,14 @@ class NativeWindowMac; // Prevents window from resizing during the scope. class ScopedDisableResize { public: - ScopedDisableResize() { disable_resize_ = true; } - ~ScopedDisableResize() { disable_resize_ = false; } + ScopedDisableResize() { disable_resize_++; } + ~ScopedDisableResize() { disable_resize_--; } - static bool IsResizeDisabled() { return disable_resize_; } + // True if there are 1+ nested ScopedDisableResize objects in the scope + static bool IsResizeDisabled() { return disable_resize_ > 0; } private: - static bool disable_resize_; + static int disable_resize_; }; } // namespace electron diff --git a/shell/browser/ui/cocoa/electron_ns_window.mm b/shell/browser/ui/cocoa/electron_ns_window.mm index f4cc2bc5bcbf1..0ad17da24e967 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.mm +++ b/shell/browser/ui/cocoa/electron_ns_window.mm @@ -13,7 +13,7 @@ namespace electron { -bool ScopedDisableResize::disable_resize_ = false; +int ScopedDisableResize::disable_resize_ = 0; } // namespace electron @@ -56,7 +56,7 @@ - (NSRect)originalContentRectForFrameRect:(NSRect)frameRect { return [super contentRectForFrameRect:frameRect]; } -- (NSTouchBar*)makeTouchBar API_AVAILABLE(macosx(10.12.2)) { +- (NSTouchBar*)makeTouchBar { if (shell_->touch_bar()) return [shell_->touch_bar() makeTouchBar]; else diff --git a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm index 1723f5c6d55ea..243c2d3993dc3 100644 --- a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm +++ b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm @@ -19,7 +19,7 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle; using FullScreenTransitionState = - electron::NativeWindowMac::FullScreenTransitionState; + electron::NativeWindow::FullScreenTransitionState; @implementation ElectronNSWindowDelegate @@ -70,12 +70,12 @@ - (NSRect)windowWillUseStandardFrame:(NSWindow*)window } // If the shift key is down, maximize. - if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) + if ([[NSApp currentEvent] modifierFlags] & NSEventModifierFlagShift) return frame; // Get preferred width from observers. Usually the page width. int preferred_width = 0; - shell_->NotifyWindowRequestPreferredWith(&preferred_width); + shell_->NotifyWindowRequestPreferredWidth(&preferred_width); // Never shrink from the current size on zoom. NSRect window_frame = [window frame]; @@ -203,6 +203,7 @@ - (void)windowWillMiniaturize:(NSNotification*)notification { // windowDidDeminiaturize level_ = [window level]; shell_->SetWindowLevel(NSNormalWindowLevel); + shell_->UpdateWindowOriginalFrame(); } - (void)windowDidMiniaturize:(NSNotification*)notification { @@ -234,35 +235,43 @@ - (void)windowDidEndLiveResize:(NSNotification*)notification { } - (void)windowWillEnterFullScreen:(NSNotification*)notification { - shell_->SetFullScreenTransitionState(FullScreenTransitionState::ENTERING); + // Store resizable mask so it can be restored after exiting fullscreen. + is_resizable_ = shell_->HasStyleMask(NSWindowStyleMaskResizable); + + shell_->set_fullscreen_transition_state(FullScreenTransitionState::ENTERING); shell_->NotifyWindowWillEnterFullScreen(); - // Setting resizable to true before entering fullscreen. - is_resizable_ = shell_->IsResizable(); + // Set resizable to true before entering fullscreen. shell_->SetResizable(true); } - (void)windowDidEnterFullScreen:(NSNotification*)notification { - shell_->SetFullScreenTransitionState(FullScreenTransitionState::NONE); + shell_->set_fullscreen_transition_state(FullScreenTransitionState::NONE); shell_->NotifyWindowEnterFullScreen(); + if (shell_->HandleDeferredClose()) + return; + shell_->HandlePendingFullscreenTransitions(); } - (void)windowWillExitFullScreen:(NSNotification*)notification { - shell_->SetFullScreenTransitionState(FullScreenTransitionState::EXITING); + shell_->set_fullscreen_transition_state(FullScreenTransitionState::EXITING); shell_->NotifyWindowWillLeaveFullScreen(); } - (void)windowDidExitFullScreen:(NSNotification*)notification { - shell_->SetFullScreenTransitionState(FullScreenTransitionState::NONE); + shell_->set_fullscreen_transition_state(FullScreenTransitionState::NONE); shell_->SetResizable(is_resizable_); shell_->NotifyWindowLeaveFullScreen(); + if (shell_->HandleDeferredClose()) + return; + shell_->HandlePendingFullscreenTransitions(); } @@ -323,8 +332,7 @@ - (IBAction)newWindowForTab:(id)sender { #pragma mark - NSTouchBarDelegate - (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar - makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier - API_AVAILABLE(macosx(10.12.2)) { + makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { if (touchBar && shell_->touch_bar()) return [shell_->touch_bar() makeItemForIdentifier:identifier]; else diff --git a/shell/browser/ui/cocoa/electron_touch_bar.h b/shell/browser/ui/cocoa/electron_touch_bar.h index 9b299d27e9933..ff645042021ae 100644 --- a/shell/browser/ui/cocoa/electron_touch_bar.h +++ b/shell/browser/ui/cocoa/electron_touch_bar.h @@ -29,19 +29,16 @@ window:(electron::NativeWindow*)window settings:(std::vector)settings; -- (NSTouchBar*)makeTouchBar API_AVAILABLE(macosx(10.12.2)); -- (NSTouchBar*)touchBarFromItemIdentifiers:(NSMutableArray*)items - API_AVAILABLE(macosx(10.12.2)); +- (NSTouchBar*)makeTouchBar; +- (NSTouchBar*)touchBarFromItemIdentifiers:(NSMutableArray*)items; - (NSMutableArray*)identifiersFromSettings: (const std::vector&)settings; - (void)refreshTouchBarItem:(NSTouchBar*)touchBar - id:(const std::string&)item_id - API_AVAILABLE(macosx(10.12.2)); + id:(const std::string&)item_id; - (void)addNonDefaultTouchBarItems: (const std::vector&)items; - (void)setEscapeTouchBarItem:(gin_helper::PersistentDictionary)item - forTouchBar:(NSTouchBar*)touchBar - API_AVAILABLE(macosx(10.12.2)); + forTouchBar:(NSTouchBar*)touchBar; - (NSString*)idFromIdentifier:(NSString*)identifier withPrefix:(NSString*)prefix; @@ -52,47 +49,35 @@ // Selector actions - (void)buttonAction:(id)sender; -- (void)colorPickerAction:(id)sender API_AVAILABLE(macosx(10.12.2)); -- (void)sliderAction:(id)sender API_AVAILABLE(macosx(10.12.2)); +- (void)colorPickerAction:(id)sender; +- (void)sliderAction:(id)sender; // Helpers to create touch bar items -- (NSTouchBarItem*)makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier - API_AVAILABLE(macosx(10.12.2)); +- (NSTouchBarItem*)makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier; - (NSTouchBarItem*)makeButtonForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)); + withIdentifier:(NSString*)identifier; - (NSTouchBarItem*)makeLabelForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)); + withIdentifier:(NSString*)identifier; - (NSTouchBarItem*)makeColorPickerForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)); + withIdentifier:(NSString*)identifier; - (NSTouchBarItem*)makeSliderForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)); + withIdentifier:(NSString*)identifier; - (NSTouchBarItem*)makePopoverForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)); + withIdentifier:(NSString*)identifier; - (NSTouchBarItem*)makeGroupForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)); + withIdentifier:(NSString*)identifier; // Helpers to update touch bar items - (void)updateButton:(NSCustomTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)); + withSettings:(const gin_helper::PersistentDictionary&)settings; - (void)updateLabel:(NSCustomTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)); + withSettings:(const gin_helper::PersistentDictionary&)settings; - (void)updateColorPicker:(NSColorPickerTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)); + withSettings:(const gin_helper::PersistentDictionary&)settings; - (void)updateSlider:(NSSliderTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)); + withSettings:(const gin_helper::PersistentDictionary&)settings; - (void)updatePopover:(NSPopoverTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)); + withSettings:(const gin_helper::PersistentDictionary&)settings; @end diff --git a/shell/browser/ui/cocoa/electron_touch_bar.mm b/shell/browser/ui/cocoa/electron_touch_bar.mm index af690bd79d851..ae866e8629bbb 100644 --- a/shell/browser/ui/cocoa/electron_touch_bar.mm +++ b/shell/browser/ui/cocoa/electron_touch_bar.mm @@ -67,38 +67,36 @@ - (NSMutableArray*)identifiersFromSettings: bool has_other_items_proxy = false; - if (@available(macOS 10.12.2, *)) { - for (const auto& item : dicts) { - std::string type; - std::string item_id; - if (item.Get("type", &type) && item.Get("id", &item_id)) { - NSTouchBarItemIdentifier identifier = nil; - if (type == "spacer") { - std::string size; - item.Get("size", &size); - if (size == "large") { - identifier = NSTouchBarItemIdentifierFixedSpaceLarge; - } else if (size == "flexible") { - identifier = NSTouchBarItemIdentifierFlexibleSpace; - } else { - identifier = NSTouchBarItemIdentifierFixedSpaceSmall; - } - } else if (type == "other_items_proxy") { - identifier = NSTouchBarItemIdentifierOtherItemsProxy; - has_other_items_proxy = true; + for (const auto& item : dicts) { + std::string type; + std::string item_id; + if (item.Get("type", &type) && item.Get("id", &item_id)) { + NSTouchBarItemIdentifier identifier = nil; + if (type == "spacer") { + std::string size; + item.Get("size", &size); + if (size == "large") { + identifier = NSTouchBarItemIdentifierFixedSpaceLarge; + } else if (size == "flexible") { + identifier = NSTouchBarItemIdentifierFlexibleSpace; } else { - identifier = [self identifierFromID:item_id type:type]; + identifier = NSTouchBarItemIdentifierFixedSpaceSmall; } + } else if (type == "other_items_proxy") { + identifier = NSTouchBarItemIdentifierOtherItemsProxy; + has_other_items_proxy = true; + } else { + identifier = [self identifierFromID:item_id type:type]; + } - if (identifier) { - settings_[item_id] = item; - [identifiers addObject:identifier]; - } + if (identifier) { + settings_[item_id] = item; + [identifiers addObject:identifier]; } } - if (!has_other_items_proxy) - [identifiers addObject:NSTouchBarItemIdentifierOtherItemsProxy]; } + if (!has_other_items_proxy) + [identifiers addObject:NSTouchBarItemIdentifierOtherItemsProxy]; return identifiers; } @@ -140,8 +138,7 @@ - (NSTouchBarItem*)makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { - (void)refreshTouchBarItem:(NSTouchBar*)touchBar id:(NSTouchBarItemIdentifier)identifier withType:(const std::string&)item_type - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)) { + withSettings:(const gin_helper::PersistentDictionary&)settings { NSTouchBarItem* item = [touchBar itemForIdentifier:identifier]; if (!item) return; @@ -244,8 +241,7 @@ - (void)refreshTouchBarItem:(NSTouchBar*)touchBar - (void)buttonAction:(id)sender { NSString* item_id = [NSString stringWithFormat:@"%ld", ((NSButton*)sender).tag]; - window_->NotifyTouchBarItemInteraction([item_id UTF8String], - base::DictionaryValue()); + window_->NotifyTouchBarItemInteraction([item_id UTF8String], {}); } - (void)colorPickerAction:(id)sender { @@ -255,19 +251,20 @@ - (void)colorPickerAction:(id)sender { NSColor* color = ((NSColorPickerTouchBarItem*)sender).color; std::string hex_color = electron::ToRGBHex(skia::NSDeviceColorToSkColor(color)); - base::DictionaryValue details; - details.SetString("color", hex_color); - window_->NotifyTouchBarItemInteraction([item_id UTF8String], details); + base::Value::Dict details; + details.Set("color", hex_color); + window_->NotifyTouchBarItemInteraction([item_id UTF8String], + std::move(details)); } - (void)sliderAction:(id)sender { NSString* identifier = ((NSSliderTouchBarItem*)sender).identifier; NSString* item_id = [self idFromIdentifier:identifier withPrefix:SliderIdentifier]; - base::DictionaryValue details; - details.SetInteger("value", - [((NSSliderTouchBarItem*)sender).slider intValue]); - window_->NotifyTouchBarItemInteraction([item_id UTF8String], details); + base::Value::Dict details; + details.Set("value", [((NSSliderTouchBarItem*)sender).slider intValue]); + window_->NotifyTouchBarItemInteraction([item_id UTF8String], + std::move(details)); } - (NSString*)idFromIdentifier:(NSString*)identifier @@ -278,34 +275,33 @@ - (NSString*)idFromIdentifier:(NSString*)identifier - (void)segmentedControlAction:(id)sender { NSString* item_id = [NSString stringWithFormat:@"%ld", ((NSSegmentedControl*)sender).tag]; - base::DictionaryValue details; - details.SetInteger("selectedIndex", - ((NSSegmentedControl*)sender).selectedSegment); - details.SetBoolean( + base::Value::Dict details; + details.Set("selectedIndex", + static_cast(((NSSegmentedControl*)sender).selectedSegment)); + details.Set( "isSelected", [((NSSegmentedControl*)sender) isSelectedForSegment:((NSSegmentedControl*)sender).selectedSegment]); - window_->NotifyTouchBarItemInteraction([item_id UTF8String], details); + window_->NotifyTouchBarItemInteraction([item_id UTF8String], + std::move(details)); } - (void)scrubber:(NSScrubber*)scrubber - didSelectItemAtIndex:(NSInteger)selectedIndex - API_AVAILABLE(macosx(10.12.2)) { - base::DictionaryValue details; - details.SetInteger("selectedIndex", selectedIndex); - details.SetString("type", "select"); + didSelectItemAtIndex:(NSInteger)selectedIndex { + base::Value::Dict details; + details.Set("selectedIndex", static_cast(selectedIndex)); + details.Set("type", "select"); window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String], - details); + std::move(details)); } - (void)scrubber:(NSScrubber*)scrubber - didHighlightItemAtIndex:(NSInteger)highlightedIndex - API_AVAILABLE(macosx(10.12.2)) { - base::DictionaryValue details; - details.SetInteger("highlightedIndex", highlightedIndex); - details.SetString("type", "highlight"); + didHighlightItemAtIndex:(NSInteger)highlightedIndex { + base::Value::Dict details; + details.Set("highlightedIndex", static_cast(highlightedIndex)); + details.Set("type", "highlight"); window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String], - details); + std::move(details)); } - (NSTouchBarItemIdentifier)identifierFromID:(const std::string&)item_id @@ -592,8 +588,7 @@ - (NSTouchBarItem*)makeGroupForID:(NSString*)id } - (void)updateGroup:(NSGroupTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)) { + withSettings:(const gin_helper::PersistentDictionary&)settings { v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate(); v8::HandleScope handle_scope(isolate); @@ -609,8 +604,7 @@ - (void)updateGroup:(NSGroupTouchBarItem*)item } - (NSTouchBarItem*)makeSegmentedControlForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)) { + withIdentifier:(NSString*)identifier { std::string s_id([id UTF8String]); if (![self hasItemWithID:s_id]) return nil; @@ -635,8 +629,8 @@ - (NSTouchBarItem*)makeSegmentedControlForID:(NSString*)id } - (void)updateSegmentedControl:(NSCustomTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)) { + withSettings: + (const gin_helper::PersistentDictionary&)settings { NSSegmentedControl* control = item.view; std::string segmentStyle; @@ -697,8 +691,7 @@ - (void)updateSegmentedControl:(NSCustomTouchBarItem*)item } - (NSTouchBarItem*)makeScrubberForID:(NSString*)id - withIdentifier:(NSString*)identifier - API_AVAILABLE(macosx(10.12.2)) { + withIdentifier:(NSString*)identifier { std::string s_id([id UTF8String]); if (![self hasItemWithID:s_id]) return nil; @@ -729,8 +722,7 @@ - (NSTouchBarItem*)makeScrubberForID:(NSString*)id } - (void)updateScrubber:(NSCustomTouchBarItem*)item - withSettings:(const gin_helper::PersistentDictionary&)settings - API_AVAILABLE(macosx(10.12.2)) { + withSettings:(const gin_helper::PersistentDictionary&)settings { NSScrubber* scrubber = item.view; bool showsArrowButtons = false; @@ -780,8 +772,7 @@ - (void)updateScrubber:(NSCustomTouchBarItem*)item [scrubber reloadData]; } -- (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber - API_AVAILABLE(macosx(10.12.2)) { +- (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber { std::string s_id([[scrubber identifier] UTF8String]); if (![self hasItemWithID:s_id]) return 0; @@ -796,8 +787,7 @@ - (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber } - (NSScrubberItemView*)scrubber:(NSScrubber*)scrubber - viewForItemAtIndex:(NSInteger)index - API_AVAILABLE(macosx(10.12.2)) { + viewForItemAtIndex:(NSInteger)index { std::string s_id([[scrubber identifier] UTF8String]); if (![self hasItemWithID:s_id]) return nil; @@ -839,7 +829,7 @@ - (NSScrubberItemView*)scrubber:(NSScrubber*)scrubber - (NSSize)scrubber:(NSScrubber*)scrubber layout:(NSScrubberFlowLayout*)layout - sizeForItemAtIndex:(NSInteger)itemIndex API_AVAILABLE(macosx(10.12.2)) { + sizeForItemAtIndex:(NSInteger)itemIndex { NSInteger width = 50; NSInteger height = 30; NSInteger margin = 15; diff --git a/shell/browser/ui/cocoa/event_dispatching_window.mm b/shell/browser/ui/cocoa/event_dispatching_window.mm index b98e547730473..16273b6c4a3a0 100644 --- a/shell/browser/ui/cocoa/event_dispatching_window.mm +++ b/shell/browser/ui/cocoa/event_dispatching_window.mm @@ -20,8 +20,8 @@ - (BOOL)performKeyEquivalent:(NSEvent*)event { - (void)redispatchKeyEvent:(NSEvent*)event { NSEventType eventType = [event type]; - if (eventType != NSKeyDown && eventType != NSKeyUp && - eventType != NSFlagsChanged) { + if (eventType != NSEventTypeKeyDown && eventType != NSEventTypeKeyUp && + eventType != NSEventTypeFlagsChanged) { return; } diff --git a/shell/browser/ui/devtools_manager_delegate.cc b/shell/browser/ui/devtools_manager_delegate.cc index 40773b35b2f21..2945d50cd5727 100644 --- a/shell/browser/ui/devtools_manager_delegate.cc +++ b/shell/browser/ui/devtools_manager_delegate.cc @@ -91,10 +91,10 @@ const char kBrowserCloseMethod[] = "Browser.close"; // static void DevToolsManagerDelegate::StartHttpHandler() { - base::FilePath user_dir; - base::PathService::Get(chrome::DIR_USER_DATA, &user_dir); + base::FilePath session_data; + base::PathService::Get(DIR_SESSION_DATA, &session_data); content::DevToolsAgentHost::StartRemoteDebuggingServer( - CreateSocketFactory(), user_dir, base::FilePath()); + CreateSocketFactory(), session_data, base::FilePath()); } DevToolsManagerDelegate::DevToolsManagerDelegate() = default; @@ -117,8 +117,8 @@ void DevToolsManagerDelegate::HandleCommand( // Since we only have one method and it is supposed to close Electron, // we don't need to add this complexity. Should we decide to support // methods like Browser.setWindowBounds, we'll need to do it though. - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce([]() { Browser::Get()->Quit(); })); + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce([]() { Browser::Get()->Quit(); })); return; } std::move(callback).Run(message); diff --git a/shell/browser/ui/devtools_ui.cc b/shell/browser/ui/devtools_ui.cc index ab9f2ffcee28b..0da78f52fb272 100644 --- a/shell/browser/ui/devtools_ui.cc +++ b/shell/browser/ui/devtools_ui.cc @@ -31,8 +31,8 @@ std::string PathWithoutParams(const std::string& path) { .substr(1); } -std::string GetMimeTypeForPath(const std::string& path) { - std::string filename = PathWithoutParams(path); +std::string GetMimeTypeForUrl(const GURL& url) { + std::string filename = url.ExtractFileName(); if (base::EndsWith(filename, ".html", base::CompareCase::INSENSITIVE_ASCII)) { return "text/html"; } else if (base::EndsWith(filename, ".css", @@ -95,8 +95,8 @@ class BundledDataSource : public content::URLDataSource { std::move(callback).Run(nullptr); } - std::string GetMimeType(const std::string& path) override { - return GetMimeTypeForPath(path); + std::string GetMimeType(const GURL& url) override { + return GetMimeTypeForUrl(url); } bool ShouldAddContentSecurityPolicy() override { return false; } diff --git a/shell/browser/ui/drag_util_mac.mm b/shell/browser/ui/drag_util_mac.mm index 811a0c8d103b1..36656ea362941 100644 --- a/shell/browser/ui/drag_util_mac.mm +++ b/shell/browser/ui/drag_util_mac.mm @@ -10,52 +10,79 @@ #include "base/strings/sys_string_conversions.h" #include "shell/browser/ui/drag_util.h" -namespace electron { +// Contents largely copied from +// chrome/browser/download/drag_download_item_mac.mm. + +@interface DragDownloadItemSource : NSObject +@end + +@implementation DragDownloadItemSource + +- (NSDragOperation)draggingSession:(NSDraggingSession*)session + sourceOperationMaskForDraggingContext:(NSDraggingContext)context { + return context == NSDraggingContextOutsideApplication ? NSDragOperationCopy + : NSDragOperationEvery; +} + +@end namespace { -// Write information about the file being dragged to the pasteboard. -void AddFilesToPasteboard(NSPasteboard* pasteboard, - const std::vector& files) { - NSMutableArray* fileList = [NSMutableArray array]; - for (const base::FilePath& file : files) - [fileList addObject:base::SysUTF8ToNSString(file.value())]; - [pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] - owner:nil]; - [pasteboard setPropertyList:fileList forType:NSFilenamesPboardType]; +id GetDraggingSource() { + static id source = [[DragDownloadItemSource alloc] init]; + return source; } } // namespace +namespace electron { + void DragFileItems(const std::vector& files, const gfx::Image& icon, gfx::NativeView view) { - NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - AddFilesToPasteboard(pasteboard, files); + auto* native_view = view.GetNativeNSView(); + NSPoint current_position = + [[native_view window] mouseLocationOutsideOfEventStream]; + current_position = + [native_view backingAlignedRect:NSMakeRect(current_position.x, + current_position.y, 0, 0) + options:NSAlignAllEdgesOutward] + .origin; + + NSMutableArray* file_items = [NSMutableArray array]; + for (auto const& file : files) { + NSURL* file_url = + [NSURL fileURLWithPath:base::SysUTF8ToNSString(file.value())]; + NSDraggingItem* file_item = [[[NSDraggingItem alloc] + initWithPasteboardWriter:file_url] autorelease]; + NSImage* file_image = icon.ToNSImage(); + NSSize image_size = file_image.size; + NSRect image_rect = NSMakeRect(current_position.x - image_size.width / 2, + current_position.y - image_size.height / 2, + image_size.width, image_size.height); + [file_item setDraggingFrame:image_rect contents:file_image]; + [file_items addObject:file_item]; + } // Synthesize a drag event, since we don't have access to the actual event // that initiated a drag (possibly consumed by the Web UI, for example). - NSWindow* window = [view.GetNativeNSView() window]; - NSPoint position = [window mouseLocationOutsideOfEventStream]; + NSPoint position = [[native_view window] mouseLocationOutsideOfEventStream]; NSTimeInterval eventTime = [[NSApp currentEvent] timestamp]; - NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged - location:position - modifierFlags:NSLeftMouseDraggedMask - timestamp:eventTime - windowNumber:[window windowNumber] - context:nil - eventNumber:0 - clickCount:1 - pressure:1.0]; + NSEvent* dragEvent = + [NSEvent mouseEventWithType:NSEventTypeLeftMouseDragged + location:position + modifierFlags:0 + timestamp:eventTime + windowNumber:[[native_view window] windowNumber] + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; // Run the drag operation. - [window dragImage:icon.ToNSImage() - at:position - offset:NSZeroSize - event:dragEvent - pasteboard:pasteboard - source:view.GetNativeNSView() - slideBack:YES]; + [native_view beginDraggingSessionWithItems:file_items + event:dragEvent + source:GetDraggingSource()]; } } // namespace electron diff --git a/shell/browser/ui/electron_desktop_window_tree_host_linux.cc b/shell/browser/ui/electron_desktop_window_tree_host_linux.cc index 045e7d9dcff9e..0ab1f292619c3 100644 --- a/shell/browser/ui/electron_desktop_window_tree_host_linux.cc +++ b/shell/browser/ui/electron_desktop_window_tree_host_linux.cc @@ -16,8 +16,8 @@ #include "shell/browser/ui/views/client_frame_view_linux.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/skia_conversions.h" +#include "ui/linux/linux_ui.h" #include "ui/platform_window/platform_window.h" -#include "ui/views/linux_ui/linux_ui.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h" #include "ui/views/window/non_client_view.h" @@ -148,7 +148,7 @@ void ElectronDesktopWindowTreeHostLinux::UpdateClientDecorationHints( if (showing_frame) { insets = view->GetBorderDecorationInsets(); if (base::i18n::IsRTL()) { - insets.Set(insets.top(), insets.right(), insets.bottom(), insets.left()); + insets.set_left_right(insets.right(), insets.left()); } input_insets = view->GetInputInsets(); diff --git a/shell/browser/ui/electron_desktop_window_tree_host_linux.h b/shell/browser/ui/electron_desktop_window_tree_host_linux.h index 4560af4f41df7..6a6130b4489b6 100644 --- a/shell/browser/ui/electron_desktop_window_tree_host_linux.h +++ b/shell/browser/ui/electron_desktop_window_tree_host_linux.h @@ -12,9 +12,10 @@ #include "base/scoped_observation.h" #include "shell/browser/native_window_views.h" #include "shell/browser/ui/views/client_frame_view_linux.h" +#include "third_party/skia/include/core/SkRRect.h" +#include "ui/linux/device_scale_factor_observer.h" #include "ui/native_theme/native_theme_observer.h" #include "ui/platform_window/platform_window.h" -#include "ui/views/linux_ui/device_scale_factor_observer.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h" namespace electron { @@ -22,7 +23,7 @@ namespace electron { class ElectronDesktopWindowTreeHostLinux : public views::DesktopWindowTreeHostLinux, public ui::NativeThemeObserver, - public views::DeviceScaleFactorObserver { + public ui::DeviceScaleFactorObserver { public: ElectronDesktopWindowTreeHostLinux( NativeWindowViews* native_window_view, @@ -61,10 +62,10 @@ class ElectronDesktopWindowTreeHostLinux base::ScopedObservation theme_observation_{this}; - base::ScopedObservation + base::ScopedObservation scale_observation_{this}; ui::PlatformWindowState window_state_ = ui::PlatformWindowState::kUnknown; }; diff --git a/shell/browser/ui/electron_gdk_pixbuf.sigs b/shell/browser/ui/electron_gdk_pixbuf.sigs new file mode 100644 index 0000000000000..c19eb4679265f --- /dev/null +++ b/shell/browser/ui/electron_gdk_pixbuf.sigs @@ -0,0 +1,3 @@ +GdkPixbuf* gdk_pixbuf_new(GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height) +GdkPixbuf* gdk_pixbuf_scale_simple(const GdkPixbuf* src, int dest_width, int dest_height, GdkInterpType interp_type) +guchar* gdk_pixbuf_get_pixels(const GdkPixbuf* pixbuf) diff --git a/shell/browser/ui/electron_gtk.fragment b/shell/browser/ui/electron_gtk.fragment index 74a31b23585ac..677c382087029 100644 --- a/shell/browser/ui/electron_gtk.fragment +++ b/shell/browser/ui/electron_gtk.fragment @@ -1 +1,2 @@ -#include \ No newline at end of file +#include +#include diff --git a/shell/browser/ui/electron_gtk.sigs b/shell/browser/ui/electron_gtk.sigs index 568a270165cbb..41f3890096e09 100644 --- a/shell/browser/ui/electron_gtk.sigs +++ b/shell/browser/ui/electron_gtk.sigs @@ -3,4 +3,5 @@ void gtk_native_dialog_set_modal(GtkNativeDialog* self, gboolean modal); void gtk_native_dialog_show(GtkNativeDialog* self); void gtk_native_dialog_hide(GtkNativeDialog* self); gint gtk_native_dialog_run(GtkNativeDialog* self); -void gtk_native_dialog_destroy(GtkNativeDialog* self); \ No newline at end of file +void gtk_native_dialog_destroy(GtkNativeDialog* self); +GType gtk_native_dialog_get_type(void); diff --git a/shell/browser/ui/electron_menu_model.cc b/shell/browser/ui/electron_menu_model.cc index 23e0dd079327f..3f305cb515ed3 100644 --- a/shell/browser/ui/electron_menu_model.cc +++ b/shell/browser/ui/electron_menu_model.cc @@ -27,42 +27,43 @@ ElectronMenuModel::ElectronMenuModel(Delegate* delegate) ElectronMenuModel::~ElectronMenuModel() = default; -void ElectronMenuModel::SetToolTip(int index, const std::u16string& toolTip) { +void ElectronMenuModel::SetToolTip(size_t index, + const std::u16string& toolTip) { int command_id = GetCommandIdAt(index); toolTips_[command_id] = toolTip; } -std::u16string ElectronMenuModel::GetToolTipAt(int index) { +std::u16string ElectronMenuModel::GetToolTipAt(size_t index) { const int command_id = GetCommandIdAt(index); const auto iter = toolTips_.find(command_id); return iter == std::end(toolTips_) ? std::u16string() : iter->second; } -void ElectronMenuModel::SetRole(int index, const std::u16string& role) { +void ElectronMenuModel::SetRole(size_t index, const std::u16string& role) { int command_id = GetCommandIdAt(index); roles_[command_id] = role; } -std::u16string ElectronMenuModel::GetRoleAt(int index) { +std::u16string ElectronMenuModel::GetRoleAt(size_t index) { const int command_id = GetCommandIdAt(index); const auto iter = roles_.find(command_id); return iter == std::end(roles_) ? std::u16string() : iter->second; } -void ElectronMenuModel::SetSecondaryLabel(int index, +void ElectronMenuModel::SetSecondaryLabel(size_t index, const std::u16string& sublabel) { int command_id = GetCommandIdAt(index); sublabels_[command_id] = sublabel; } -std::u16string ElectronMenuModel::GetSecondaryLabelAt(int index) const { +std::u16string ElectronMenuModel::GetSecondaryLabelAt(size_t index) const { int command_id = GetCommandIdAt(index); const auto iter = sublabels_.find(command_id); return iter == std::end(sublabels_) ? std::u16string() : iter->second; } bool ElectronMenuModel::GetAcceleratorAtWithParams( - int index, + size_t index, bool use_default_accelerator, ui::Accelerator* accelerator) const { if (delegate_) { @@ -72,7 +73,7 @@ bool ElectronMenuModel::GetAcceleratorAtWithParams( return false; } -bool ElectronMenuModel::ShouldRegisterAcceleratorAt(int index) const { +bool ElectronMenuModel::ShouldRegisterAcceleratorAt(size_t index) const { if (delegate_) { return delegate_->ShouldRegisterAcceleratorForCommandId( GetCommandIdAt(index)); @@ -80,7 +81,7 @@ bool ElectronMenuModel::ShouldRegisterAcceleratorAt(int index) const { return true; } -bool ElectronMenuModel::WorksWhenHiddenAt(int index) const { +bool ElectronMenuModel::WorksWhenHiddenAt(size_t index) const { if (delegate_) { return delegate_->ShouldCommandIdWorkWhenHidden(GetCommandIdAt(index)); } @@ -88,7 +89,8 @@ bool ElectronMenuModel::WorksWhenHiddenAt(int index) const { } #if BUILDFLAG(IS_MAC) -bool ElectronMenuModel::GetSharingItemAt(int index, SharingItem* item) const { +bool ElectronMenuModel::GetSharingItemAt(size_t index, + SharingItem* item) const { if (delegate_) return delegate_->GetSharingItemForCommandId(GetCommandIdAt(index), item); return false; @@ -118,7 +120,7 @@ void ElectronMenuModel::MenuWillShow() { } } -ElectronMenuModel* ElectronMenuModel::GetSubmenuModelAt(int index) { +ElectronMenuModel* ElectronMenuModel::GetSubmenuModelAt(size_t index) { return static_cast( ui::SimpleMenuModel::GetSubmenuModelAt(index)); } diff --git a/shell/browser/ui/electron_menu_model.h b/shell/browser/ui/electron_menu_model.h index 355a3f7040927..63999ad1614ba 100644 --- a/shell/browser/ui/electron_menu_model.h +++ b/shell/browser/ui/electron_menu_model.h @@ -81,20 +81,20 @@ class ElectronMenuModel : public ui::SimpleMenuModel { void AddObserver(Observer* obs) { observers_.AddObserver(obs); } void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); } - void SetToolTip(int index, const std::u16string& toolTip); - std::u16string GetToolTipAt(int index); - void SetRole(int index, const std::u16string& role); - std::u16string GetRoleAt(int index); - void SetSecondaryLabel(int index, const std::u16string& sublabel); - std::u16string GetSecondaryLabelAt(int index) const override; - bool GetAcceleratorAtWithParams(int index, + void SetToolTip(size_t index, const std::u16string& toolTip); + std::u16string GetToolTipAt(size_t index); + void SetRole(size_t index, const std::u16string& role); + std::u16string GetRoleAt(size_t index); + void SetSecondaryLabel(size_t index, const std::u16string& sublabel); + std::u16string GetSecondaryLabelAt(size_t index) const override; + bool GetAcceleratorAtWithParams(size_t index, bool use_default_accelerator, ui::Accelerator* accelerator) const; - bool ShouldRegisterAcceleratorAt(int index) const; - bool WorksWhenHiddenAt(int index) const; + bool ShouldRegisterAcceleratorAt(size_t index) const; + bool WorksWhenHiddenAt(size_t index) const; #if BUILDFLAG(IS_MAC) // Return the SharingItem of menu item. - bool GetSharingItemAt(int index, SharingItem* item) const; + bool GetSharingItemAt(size_t index, SharingItem* item) const; // Set/Get the SharingItem of this menu. void SetSharingItem(SharingItem item); const absl::optional& GetSharingItem() const; @@ -109,7 +109,7 @@ class ElectronMenuModel : public ui::SimpleMenuModel { } using SimpleMenuModel::GetSubmenuModelAt; - ElectronMenuModel* GetSubmenuModelAt(int index); + ElectronMenuModel* GetSubmenuModelAt(size_t index); private: Delegate* delegate_; // weak ref. diff --git a/shell/browser/ui/file_dialog_gtk.cc b/shell/browser/ui/file_dialog_gtk.cc index 74df37b57d5f1..99f0e1524c36f 100644 --- a/shell/browser/ui/file_dialog_gtk.cc +++ b/shell/browser/ui/file_dialog_gtk.cc @@ -32,8 +32,11 @@ static const int kPreviewWidth = 256; static const int kPreviewHeight = 512; std::string MakeCaseInsensitivePattern(const std::string& extension) { - std::string pattern("*."); + // If the extension is the "all files" extension, no change needed. + if (extension == "*") + return extension; + std::string pattern("*."); for (std::size_t i = 0, n = extension.size(); i < n; i++) { char ch = extension[i]; if (!base::IsAsciiAlpha(ch)) { diff --git a/shell/browser/ui/file_dialog_mac.mm b/shell/browser/ui/file_dialog_mac.mm index d4572bdd7e1fe..fa7cfa424ef07 100644 --- a/shell/browser/ui/file_dialog_mac.mm +++ b/shell/browser/ui/file_dialog_mac.mm @@ -16,7 +16,6 @@ #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" -#include "base/task/post_task.h" #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -233,7 +232,7 @@ void SetupSaveDialogForProperties(NSSavePanel* dialog, int properties) { // Run modal dialog with parent window and return user's choice. int RunModalDialog(NSSavePanel* dialog, const DialogSettings& settings) { - __block int chosen = NSFileHandlingPanelCancelButton; + __block int chosen = NSModalResponseCancel; if (!settings.parent_window || !settings.parent_window->GetNativeWindow() || settings.force_detached) { chosen = [dialog runModal]; @@ -301,13 +300,12 @@ void ResolvePromiseInNextTick(gin_helper::Promise> promise, // users will run in the microtask, we have to delay the resolution until // next tick, otherwise crash like this may happen: // https://github.com/electron/electron/issues/26884 - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( [](gin_helper::Promise> promise, v8::Global global) { v8::Isolate* isolate = promise.isolate(); - v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); v8::Local value = global.Get(isolate); promise.Resolve(value); @@ -326,7 +324,7 @@ bool ShowOpenDialogSync(const DialogSettings& settings, SetupOpenDialogForProperties(dialog, settings.properties); int chosen = RunModalDialog(dialog, settings); - if (chosen == NSFileHandlingPanelCancelButton) + if (chosen == NSModalResponseCancel) return false; ReadDialogPaths(dialog, paths); @@ -339,7 +337,7 @@ void OpenDialogCompletion(int chosen, gin_helper::Promise promise) { v8::HandleScope scope(promise.isolate()); gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(promise.isolate()); - if (chosen == NSFileHandlingPanelCancelButton) { + if (chosen == NSModalResponseCancel) { dict.Set("canceled", true); dict.Set("filePaths", std::vector()); #if defined(MAS_BUILD) @@ -404,7 +402,7 @@ bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) { SetupSaveDialogForProperties(dialog, settings.properties); int chosen = RunModalDialog(dialog, settings); - if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL]) + if (chosen == NSModalResponseCancel || ![[dialog URL] isFileURL]) return false; *path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path])); @@ -417,7 +415,7 @@ void SaveDialogCompletion(int chosen, gin_helper::Promise promise) { v8::HandleScope scope(promise.isolate()); gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(promise.isolate()); - if (chosen == NSFileHandlingPanelCancelButton) { + if (chosen == NSModalResponseCancel) { dict.Set("canceled", true); dict.Set("filePath", base::FilePath()); #if defined(MAS_BUILD) diff --git a/shell/browser/ui/file_dialog_win.cc b/shell/browser/ui/file_dialog_win.cc index 5aeaa238c2108..7cd094d2d6692 100644 --- a/shell/browser/ui/file_dialog_win.cc +++ b/shell/browser/ui/file_dialog_win.cc @@ -206,7 +206,7 @@ bool ShowOpenDialogSync(const DialogSettings& settings, wchar_t file_name[MAX_PATH]; hr = GetFileNameFromShellItem(item, SIGDN_FILESYSPATH, file_name, - base::size(file_name)); + std::size(file_name)); if (FAILED(hr)) return false; @@ -221,7 +221,6 @@ void ShowOpenDialog(const DialogSettings& settings, gin_helper::Promise promise) { auto done = [](gin_helper::Promise promise, bool success, std::vector result) { - v8::Locker locker(promise.isolate()); v8::HandleScope handle_scope(promise.isolate()); gin::Dictionary dict = gin::Dictionary::CreateEmpty(promise.isolate()); dict.Set("canceled", !success); @@ -271,7 +270,6 @@ void ShowSaveDialog(const DialogSettings& settings, gin_helper::Promise promise) { auto done = [](gin_helper::Promise promise, bool success, base::FilePath result) { - v8::Locker locker(promise.isolate()); v8::HandleScope handle_scope(promise.isolate()); gin::Dictionary dict = gin::Dictionary::CreateEmpty(promise.isolate()); dict.Set("canceled", !success); diff --git a/shell/browser/ui/gtk/app_indicator_icon.cc b/shell/browser/ui/gtk/app_indicator_icon.cc index a6ccb75cb79c4..602f2bf94ee72 100644 --- a/shell/browser/ui/gtk/app_indicator_icon.cc +++ b/shell/browser/ui/gtk/app_indicator_icon.cc @@ -20,7 +20,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "content/public/browser/browser_thread.h" #include "shell/browser/ui/gtk/app_indicator_icon_menu.h" @@ -153,9 +152,7 @@ void DeleteTempDirectory(const base::FilePath& dir_path) { } // namespace -namespace electron { - -namespace gtkui { +namespace electron::gtkui { AppIndicatorIcon::AppIndicatorIcon(std::string id, const gfx::ImageSkia& image, @@ -376,6 +373,4 @@ void AppIndicatorIcon::OnClickActionReplacementMenuItemActivated() { delegate()->OnClick(); } -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui diff --git a/shell/browser/ui/gtk/app_indicator_icon.h b/shell/browser/ui/gtk/app_indicator_icon.h index 3219beb5ee154..8695545d9b4d9 100644 --- a/shell/browser/ui/gtk/app_indicator_icon.h +++ b/shell/browser/ui/gtk/app_indicator_icon.h @@ -11,8 +11,9 @@ #include "base/files/file_path.h" #include "base/memory/weak_ptr.h" #include "base/nix/xdg_util.h" +#include "third_party/skia/include/core/SkImage.h" #include "ui/base/glib/glib_signal.h" -#include "ui/views/linux_ui/status_icon_linux.h" +#include "ui/linux/status_icon_linux.h" typedef struct _AppIndicator AppIndicator; typedef struct _GtkWidget GtkWidget; @@ -27,14 +28,12 @@ namespace ui { class MenuModel; } -namespace electron { - -namespace gtkui { +namespace electron::gtkui { class AppIndicatorIconMenu; // Status icon implementation which uses libappindicator. -class AppIndicatorIcon : public views::StatusIconLinux { +class AppIndicatorIcon : public ui::StatusIconLinux { public: // The id uniquely identifies the new status icon from other chrome status // icons. @@ -50,7 +49,7 @@ class AppIndicatorIcon : public views::StatusIconLinux { // Indicates whether libappindicator so could be opened. static bool CouldOpen(); - // Overridden from views::StatusIconLinux: + // Overridden from ui::StatusIconLinux: void SetIcon(const gfx::ImageSkia& image) override; void SetToolTip(const std::u16string& tool_tip) override; void UpdatePlatformContextMenu(ui::MenuModel* menu) override; @@ -110,8 +109,6 @@ class AppIndicatorIcon : public views::StatusIconLinux { base::WeakPtrFactory weak_factory_{this}; }; -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui #endif // ELECTRON_SHELL_BROWSER_UI_GTK_APP_INDICATOR_ICON_H_ diff --git a/shell/browser/ui/gtk/app_indicator_icon_menu.cc b/shell/browser/ui/gtk/app_indicator_icon_menu.cc index ea7c0f552f282..1d2cd04428e7e 100644 --- a/shell/browser/ui/gtk/app_indicator_icon_menu.cc +++ b/shell/browser/ui/gtk/app_indicator_icon_menu.cc @@ -11,9 +11,7 @@ #include "shell/browser/ui/gtk/menu_util.h" #include "ui/base/models/menu_model.h" -namespace electron { - -namespace gtkui { +namespace electron::gtkui { AppIndicatorIconMenu::AppIndicatorIconMenu(ui::MenuModel* model) : menu_model_(model) { @@ -115,6 +113,4 @@ void AppIndicatorIconMenu::OnMenuItemActivated(GtkWidget* menu_item) { ExecuteCommand(model, id); } -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui diff --git a/shell/browser/ui/gtk/app_indicator_icon_menu.h b/shell/browser/ui/gtk/app_indicator_icon_menu.h index e4987eb69df30..cafcb3c601de1 100644 --- a/shell/browser/ui/gtk/app_indicator_icon_menu.h +++ b/shell/browser/ui/gtk/app_indicator_icon_menu.h @@ -15,9 +15,7 @@ namespace ui { class MenuModel; } -namespace electron { - -namespace gtkui { +namespace electron::gtkui { // The app indicator icon's menu. class AppIndicatorIconMenu { @@ -70,8 +68,6 @@ class AppIndicatorIconMenu { bool block_activation_ = false; }; -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui #endif // ELECTRON_SHELL_BROWSER_UI_GTK_APP_INDICATOR_ICON_MENU_H_ diff --git a/shell/browser/ui/gtk/gtk_status_icon.cc b/shell/browser/ui/gtk/gtk_status_icon.cc index ecad7d470c5e4..69843f30b8ac3 100644 --- a/shell/browser/ui/gtk/gtk_status_icon.cc +++ b/shell/browser/ui/gtk/gtk_status_icon.cc @@ -15,9 +15,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS -namespace electron { - -namespace gtkui { +namespace electron::gtkui { GtkStatusIcon::GtkStatusIcon(const gfx::ImageSkia& image, const std::u16string& tool_tip) { @@ -81,6 +79,4 @@ void GtkStatusIcon::OnContextMenuRequested(GtkStatusIcon* status_icon, } } -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui diff --git a/shell/browser/ui/gtk/gtk_status_icon.h b/shell/browser/ui/gtk/gtk_status_icon.h index b8b67259c671a..7d7163cea96bd 100644 --- a/shell/browser/ui/gtk/gtk_status_icon.h +++ b/shell/browser/ui/gtk/gtk_status_icon.h @@ -9,7 +9,7 @@ #include "ui/base/glib/glib_integers.h" #include "ui/base/glib/glib_signal.h" -#include "ui/views/linux_ui/status_icon_linux.h" +#include "ui/linux/status_icon_linux.h" typedef struct _GtkStatusIcon GtkStatusIcon; @@ -21,14 +21,13 @@ namespace ui { class MenuModel; } -namespace electron { +namespace electron::gtkui { -namespace gtkui { class AppIndicatorIconMenu; // Status icon implementation which uses the system tray X11 spec (via // GtkStatusIcon). -class GtkStatusIcon : public views::StatusIconLinux { +class GtkStatusIcon : public ui::StatusIconLinux { public: GtkStatusIcon(const gfx::ImageSkia& image, const std::u16string& tool_tip); ~GtkStatusIcon() override; @@ -37,7 +36,7 @@ class GtkStatusIcon : public views::StatusIconLinux { GtkStatusIcon(const GtkStatusIcon&) = delete; GtkStatusIcon& operator=(const GtkStatusIcon&) = delete; - // Overridden from views::StatusIconLinux: + // Overridden from ui::StatusIconLinux: void SetIcon(const gfx::ImageSkia& image) override; void SetToolTip(const std::u16string& tool_tip) override; void UpdatePlatformContextMenu(ui::MenuModel* menu) override; @@ -58,8 +57,6 @@ class GtkStatusIcon : public views::StatusIconLinux { std::unique_ptr menu_; }; -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui #endif // ELECTRON_SHELL_BROWSER_UI_GTK_GTK_STATUS_ICON_H_ diff --git a/shell/browser/ui/gtk/menu_util.cc b/shell/browser/ui/gtk/menu_util.cc index fb1c0e63e91ac..08f16d2e754ee 100644 --- a/shell/browser/ui/gtk/menu_util.cc +++ b/shell/browser/ui/gtk/menu_util.cc @@ -30,9 +30,7 @@ #include "ui/ozone/public/ozone_platform.h" #endif -namespace electron { - -namespace gtkui { +namespace electron::gtkui { namespace { @@ -152,7 +150,7 @@ void ExecuteCommand(ui::MenuModel* model, int id) { if (event && event->type == GDK_BUTTON_RELEASE) event_flags = EventFlagsFromGdkState(event->button.state); - model->ActivatedAt(id, event_flags); + model->ActivatedAt(static_cast(id), event_flags); if (event) gdk_event_free(event); @@ -165,7 +163,7 @@ void BuildSubmenuFromModel(ui::MenuModel* model, void* this_ptr) { std::map radio_groups; GtkWidget* menu_item = nullptr; - for (int i = 0; i < model->GetItemCount(); ++i) { + for (size_t i = 0; i < model->GetItemCount(); ++i) { std::string label = ui::ConvertAcceleratorsFromWindowsStyle( base::UTF16ToUTF8(model->GetLabelAt(i))); @@ -330,6 +328,4 @@ void SetMenuItemInfo(GtkWidget* widget, void* block_activation_ptr) { } } -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui diff --git a/shell/browser/ui/gtk/menu_util.h b/shell/browser/ui/gtk/menu_util.h index 6d46c49b3f7da..ee4042eea4534 100644 --- a/shell/browser/ui/gtk/menu_util.h +++ b/shell/browser/ui/gtk/menu_util.h @@ -15,9 +15,7 @@ namespace ui { class MenuModel; } -namespace electron { - -namespace gtkui { +namespace electron::gtkui { // Builds GtkImageMenuItems. GtkWidget* BuildMenuItemWithImage(const std::string& label, GtkWidget* image); @@ -56,8 +54,6 @@ void BuildSubmenuFromModel(ui::MenuModel* model, // Sets the check mark, enabled/disabled state and dynamic labels on menu items. void SetMenuItemInfo(GtkWidget* widget, void* block_activation_ptr); -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui #endif // ELECTRON_SHELL_BROWSER_UI_GTK_MENU_UTIL_H_ diff --git a/shell/browser/ui/gtk/status_icon.cc b/shell/browser/ui/gtk/status_icon.cc index 975f2a2ef89a6..dea4a7f952794 100644 --- a/shell/browser/ui/gtk/status_icon.cc +++ b/shell/browser/ui/gtk/status_icon.cc @@ -16,9 +16,7 @@ #include "shell/browser/ui/gtk/app_indicator_icon.h" #include "shell/browser/ui/gtk/gtk_status_icon.h" -namespace electron { - -namespace gtkui { +namespace electron::gtkui { namespace { @@ -35,7 +33,7 @@ bool IsStatusIconSupported() { #endif } -std::unique_ptr CreateLinuxStatusIcon( +std::unique_ptr CreateLinuxStatusIcon( const gfx::ImageSkia& image, const std::u16string& tool_tip, const char* id_prefix) { @@ -55,6 +53,4 @@ std::unique_ptr CreateLinuxStatusIcon( #endif } -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui diff --git a/shell/browser/ui/gtk/status_icon.h b/shell/browser/ui/gtk/status_icon.h index 10e17f2781f09..df80d03157e04 100644 --- a/shell/browser/ui/gtk/status_icon.h +++ b/shell/browser/ui/gtk/status_icon.h @@ -13,20 +13,16 @@ #include "base/strings/string_util.h" #include "ui/gfx/image/image_skia.h" -#include "ui/views/linux_ui/status_icon_linux.h" +#include "ui/linux/status_icon_linux.h" -namespace electron { - -namespace gtkui { +namespace electron::gtkui { bool IsStatusIconSupported(); -std::unique_ptr CreateLinuxStatusIcon( +std::unique_ptr CreateLinuxStatusIcon( const gfx::ImageSkia& image, const std::u16string& tool_tip, const char* id_prefix); -} // namespace gtkui - -} // namespace electron +} // namespace electron::gtkui #endif // ELECTRON_SHELL_BROWSER_UI_GTK_STATUS_ICON_H_ diff --git a/shell/browser/ui/gtk_util.cc b/shell/browser/ui/gtk_util.cc index 3d279485cf505..7fc6154bf99f3 100644 --- a/shell/browser/ui/gtk_util.cc +++ b/shell/browser/ui/gtk_util.cc @@ -12,6 +12,7 @@ #include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" +#include "electron/electron_gtk_stubs.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkUnPreMultiply.h" diff --git a/shell/browser/ui/inspectable_web_contents.cc b/shell/browser/ui/inspectable_web_contents.cc index 4779ee6c77f1e..16bf86cb016e7 100644 --- a/shell/browser/ui/inspectable_web_contents.cc +++ b/shell/browser/ui/inspectable_web_contents.cc @@ -19,7 +19,6 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "base/values.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -142,7 +141,7 @@ void SetZoomLevelForWebContents(content::WebContents* web_contents, double GetNextZoomLevel(double level, bool out) { double factor = blink::PageZoomLevelToZoomFactor(level); - size_t size = base::size(kPresetZoomFactors); + size_t size = std::size(kPresetZoomFactors); for (size_t i = 0; i < size; ++i) { if (!blink::PageZoomValuesEqual(kPresetZoomFactors[i], factor)) continue; @@ -272,8 +271,9 @@ class InspectableWebContents::NetworkResourceLoader base::Value id(stream_id_); base::Value encodedValue(encoded); - bindings_->CallClientFunction("DevToolsAPI.streamWrite", &id, &chunkValue, - &encodedValue); + bindings_->CallClientFunction("DevToolsAPI", "streamWrite", std::move(id), + std::move(chunkValue), + std::move(encodedValue)); std::move(resume).Run(); } @@ -401,7 +401,7 @@ content::WebContents* InspectableWebContents::GetDevToolsWebContents() const { void InspectableWebContents::InspectElement(int x, int y) { if (agent_host_) - agent_host_->InspectElement(web_contents_->GetMainFrame(), x, y); + agent_host_->InspectElement(web_contents_->GetPrimaryMainFrame(), x, y); } void InspectableWebContents::SetDelegate( @@ -511,30 +511,29 @@ void InspectableWebContents::Reattach(DispatchCallback callback) { } void InspectableWebContents::CallClientFunction( - const std::string& function_name, - const base::Value* arg1, - const base::Value* arg2, - const base::Value* arg3) { + const std::string& object_name, + const std::string& method_name, + base::Value arg1, + base::Value arg2, + base::Value arg3, + base::OnceCallback cb) { if (!GetDevToolsWebContents()) return; - std::string javascript = function_name + "("; - if (arg1) { - std::string json; - base::JSONWriter::Write(*arg1, &json); - javascript.append(json); - if (arg2) { - base::JSONWriter::Write(*arg2, &json); - javascript.append(", ").append(json); - if (arg3) { - base::JSONWriter::Write(*arg3, &json); - javascript.append(", ").append(json); + base::Value::List arguments; + if (!arg1.is_none()) { + arguments.Append(std::move(arg1)); + if (!arg2.is_none()) { + arguments.Append(std::move(arg2)); + if (!arg3.is_none()) { + arguments.Append(std::move(arg3)); } } } - javascript.append(");"); - GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript( - base::UTF8ToUTF16(javascript), base::NullCallback()); + + GetDevToolsWebContents()->GetPrimaryMainFrame()->ExecuteJavaScriptMethod( + base::ASCIIToUTF16(object_name), base::ASCIIToUTF16(method_name), + std::move(arguments), std::move(cb)); } gfx::Rect InspectableWebContents::GetDevToolsBounds() const { @@ -581,7 +580,7 @@ void InspectableWebContents::LoadCompleted() { } std::u16string javascript = base::UTF8ToUTF16( "UI.DockController.instance().setDockSide(\"" + dock_state_ + "\");"); - GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript( + GetDevToolsWebContents()->GetPrimaryMainFrame()->ExecuteJavaScript( javascript, base::NullCallback()); } @@ -602,7 +601,7 @@ void InspectableWebContents::AddDevToolsExtensionsToClient() { if (!registry) return; - base::ListValue results; + base::Value::List results; for (auto& extension : registry->enabled_extensions()) { auto devtools_page_url = extensions::chrome_manifest_urls::GetDevToolsPage(extension.get()); @@ -613,20 +612,20 @@ void InspectableWebContents::AddDevToolsExtensionsToClient() { // process. Grant the devtools process the ability to request URLs from the // extension. content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestOrigin( - web_contents_->GetMainFrame()->GetProcess()->GetID(), + web_contents_->GetPrimaryMainFrame()->GetProcess()->GetID(), url::Origin::Create(extension->url())); - auto extension_info = std::make_unique(); - extension_info->SetString("startPage", devtools_page_url.spec()); - extension_info->SetString("name", extension->name()); - extension_info->SetBoolean( - "exposeExperimentalAPIs", - extension->permissions_data()->HasAPIPermission( - extensions::mojom::APIPermissionID::kExperimental)); - results.Append(std::move(extension_info)); + base::Value::Dict extension_info; + extension_info.Set("startPage", devtools_page_url.spec()); + extension_info.Set("name", extension->name()); + extension_info.Set("exposeExperimentalAPIs", + extension->permissions_data()->HasAPIPermission( + extensions::mojom::APIPermissionID::kExperimental)); + results.Append(base::Value(std::move(extension_info))); } - CallClientFunction("DevToolsAPI.addExtensions", &results, NULL, NULL); + CallClientFunction("DevToolsAPI", "addExtensions", + base::Value(std::move(results))); } #endif @@ -904,32 +903,25 @@ void InspectableWebContents::RegisterExtensionsAPI(const std::string& origin, } void InspectableWebContents::HandleMessageFromDevToolsFrontend( - base::Value message) { + base::Value::Dict message) { // TODO(alexeykuzmin): Should we expect it to exist? if (!embedder_message_dispatcher_) { return; } - const std::string* method = nullptr; - base::Value* params = nullptr; - - if (message.is_dict()) { - method = message.FindStringKey(kFrontendHostMethod); - params = message.FindKey(kFrontendHostParams); - } + const std::string* method = message.FindString(kFrontendHostMethod); + base::Value* params = message.Find(kFrontendHostParams); if (!method || (params && !params->is_list())) { LOG(ERROR) << "Invalid message was sent to embedder: " << message; return; } - base::Value empty_params(base::Value::Type::LIST); - if (!params) { - params = &empty_params; - } - int id = message.FindIntKey(kFrontendHostId).value_or(0); - std::vector params_list; - if (params) - params_list = std::move(*params).TakeListDeprecated(); + + const base::Value::List no_params; + const base::Value::List& params_list = + params != nullptr && params->is_list() ? params->GetList() : no_params; + + const int id = message.FindInt(kFrontendHostId).value_or(0); embedder_message_dispatcher_->Dispatch( base::BindRepeating(&InspectableWebContents::SendMessageAck, weak_factory_.GetWeakPtr(), id), @@ -944,22 +936,21 @@ void InspectableWebContents::DispatchProtocolMessage( base::StringPiece str_message(reinterpret_cast(message.data()), message.size()); - if (str_message.size() < kMaxMessageChunkSize) { - std::string param; - base::EscapeJSONString(str_message, true, ¶m); - std::u16string javascript = - base::UTF8ToUTF16("DevToolsAPI.dispatchMessage(" + param + ");"); - GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript( - javascript, base::NullCallback()); - return; - } - - base::Value total_size(static_cast(str_message.length())); - for (size_t pos = 0; pos < str_message.length(); - pos += kMaxMessageChunkSize) { - base::Value message_value(str_message.substr(pos, kMaxMessageChunkSize)); - CallClientFunction("DevToolsAPI.dispatchMessageChunk", &message_value, - pos ? nullptr : &total_size, nullptr); + if (str_message.length() < kMaxMessageChunkSize) { + CallClientFunction("DevToolsAPI", "dispatchMessage", + base::Value(std::string(str_message))); + } else { + size_t total_size = str_message.length(); + for (size_t pos = 0; pos < str_message.length(); + pos += kMaxMessageChunkSize) { + base::StringPiece str_message_chunk = + str_message.substr(pos, kMaxMessageChunkSize); + + CallClientFunction( + "DevToolsAPI", "dispatchMessageChunk", + base::Value(std::string(str_message_chunk)), + base::Value(base::NumberToString(pos ? 0 : total_size))); + } } } @@ -1033,12 +1024,12 @@ void InspectableWebContents::ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) { if (navigation_handle->IsInMainFrame()) { if (navigation_handle->GetRenderFrameHost() == - GetDevToolsWebContents()->GetMainFrame() && + GetDevToolsWebContents()->GetPrimaryMainFrame() && frontend_host_) { return; } frontend_host_ = content::DevToolsFrontendHost::Create( - web_contents()->GetMainFrame(), + web_contents()->GetPrimaryMainFrame(), base::BindRepeating( &InspectableWebContents::HandleMessageFromDevToolsFrontend, base::Unretained(this))); @@ -1071,8 +1062,13 @@ void InspectableWebContents::DidFinishNavigation( void InspectableWebContents::SendMessageAck(int request_id, const base::Value* arg) { - base::Value id_value(request_id); - CallClientFunction("DevToolsAPI.embedderMessageAck", &id_value, arg, nullptr); + if (arg) { + CallClientFunction("DevToolsAPI", "embedderMessageAck", + base::Value(request_id), arg->Clone()); + } else { + CallClientFunction("DevToolsAPI", "embedderMessageAck", + base::Value(request_id)); + } } } // namespace electron diff --git a/shell/browser/ui/inspectable_web_contents.h b/shell/browser/ui/inspectable_web_contents.h index bfc6cbae896d5..b283c48ff6137 100644 --- a/shell/browser/ui/inspectable_web_contents.h +++ b/shell/browser/ui/inspectable_web_contents.h @@ -70,10 +70,13 @@ class InspectableWebContents bool IsDevToolsViewShowing(); void AttachTo(scoped_refptr); void Detach(); - void CallClientFunction(const std::string& function_name, - const base::Value* arg1, - const base::Value* arg2, - const base::Value* arg3); + void CallClientFunction( + const std::string& object_name, + const std::string& method_name, + const base::Value arg1 = {}, + const base::Value arg2 = {}, + const base::Value arg3 = {}, + base::OnceCallback cb = base::NullCallback()); void InspectElement(int x, int y); // Return the last position and size of devtools window. @@ -85,7 +88,7 @@ class InspectableWebContents void UpdateDevToolsZoomLevel(double level); private: - // DevToolsEmbedderMessageDispacher::Delegate + // DevToolsEmbedderMessageDispatcher::Delegate void ActivateWindow() override; void CloseWindow() override; void LoadCompleted() override; @@ -167,7 +170,7 @@ class InspectableWebContents const std::string& trigger) override {} // content::DevToolsFrontendHostDelegate: - void HandleMessageFromDevToolsFrontend(base::Value message); + void HandleMessageFromDevToolsFrontend(base::Value::Dict message); // content::DevToolsAgentHostClient: void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host, diff --git a/shell/browser/ui/message_box_gtk.cc b/shell/browser/ui/message_box_gtk.cc index 3efc453fc97bd..6266dad29ef51 100644 --- a/shell/browser/ui/message_box_gtk.cc +++ b/shell/browser/ui/message_box_gtk.cc @@ -11,6 +11,7 @@ #include "base/no_destructor.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "electron/electron_gtk_stubs.h" #include "shell/browser/browser.h" #include "shell/browser/native_window_observer.h" #include "shell/browser/native_window_views.h" diff --git a/shell/browser/ui/message_box_mac.mm b/shell/browser/ui/message_box_mac.mm index faad840b68c3c..9ab03a0472eae 100644 --- a/shell/browser/ui/message_box_mac.mm +++ b/shell/browser/ui/message_box_mac.mm @@ -17,7 +17,6 @@ #include "base/mac/scoped_nsobject.h" #include "base/no_destructor.h" #include "base/strings/sys_string_conversions.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "shell/browser/native_window.h" @@ -46,14 +45,14 @@ switch (settings.type) { case MessageBoxType::kInformation: - alert.alertStyle = NSInformationalAlertStyle; + alert.alertStyle = NSAlertStyleInformational; break; case MessageBoxType::kWarning: case MessageBoxType::kError: - // NSWarningAlertStyle shows the app icon while NSCriticalAlertStyle + // NSWarningAlertStyle shows the app icon while NSAlertStyleCritical // shows a warning icon with an app icon badge. Since there is no - // error variant, lets just use NSCriticalAlertStyle. - alert.alertStyle = NSCriticalAlertStyle; + // error variant, lets just use NSAlertStyleCritical. + alert.alertStyle = NSAlertStyleCritical; break; default: break; @@ -178,8 +177,8 @@ void ShowMessageBox(const MessageBoxSettings& settings, // users will run in the callback, we have to delay running the callback // until next tick, otherwise crash like this may happen: // https://github.com/electron/electron/issues/26884 - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback_), response, suppressed)); }; [alert beginSheetModalForWindow:window completionHandler:handler]; @@ -199,7 +198,7 @@ void ShowErrorBox(const std::u16string& title, const std::u16string& content) { NSAlert* alert = [[NSAlert alloc] init]; [alert setMessageText:base::SysUTF16ToNSString(title)]; [alert setInformativeText:base::SysUTF16ToNSString(content)]; - [alert setAlertStyle:NSCriticalAlertStyle]; + [alert setAlertStyle:NSAlertStyleCritical]; [alert runModal]; [alert release]; } diff --git a/shell/browser/ui/message_box_win.cc b/shell/browser/ui/message_box_win.cc index 724228e010189..02499bf9c9c23 100644 --- a/shell/browser/ui/message_box_win.cc +++ b/shell/browser/ui/message_box_win.cc @@ -16,7 +16,6 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" -#include "base/task/post_task.h" #include "base/win/scoped_gdi_object.h" #include "shell/browser/browser.h" #include "shell/browser/native_window_views.h" @@ -48,7 +47,7 @@ std::map>& GetDialogsMap() { return *dialogs; } -// Speical HWND used by the dialogs map. +// Special HWND used by the dialogs map. // // - ID is used but window has not been created yet. const HWND kHwndReserve = reinterpret_cast(-1); diff --git a/shell/browser/ui/tray_icon_cocoa.mm b/shell/browser/ui/tray_icon_cocoa.mm index 0a37e4fea727e..25776c7ca6aba 100644 --- a/shell/browser/ui/tray_icon_cocoa.mm +++ b/shell/browser/ui/tray_icon_cocoa.mm @@ -10,7 +10,6 @@ #include "base/message_loop/message_pump_mac.h" #include "base/strings/sys_string_conversions.h" #include "base/task/current_thread.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "shell/browser/ui/cocoa/NSString+ANSI.h" @@ -190,9 +189,9 @@ - (void)mouseDown:(NSEvent*)event { gfx::ScreenPointFromNSPoint([event locationInWindow]), ui::EventFlagsFromModifiers([event modifierFlags])); - // Pass click to superclass to show menu. Custom mouseUp handler won't be - // invoked. - if (menuController_) { + // Pass click to superclass to show menu if one exists and has a non-zero + // number of items. Custom mouseUp handler won't be invoked in this case. + if (menuController_ && [[menuController_ menu] numberOfItems] > 0) { [self handleClickNotifications:event]; [super mouseDown:event]; } else { @@ -365,8 +364,8 @@ - (BOOL)performDragOperation:(id)sender { void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos, ElectronMenuModel* menu_model) { - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&TrayIconCocoa::PopUpOnUI, weak_factory_.GetWeakPtr(), base::Unretained(menu_model))); } diff --git a/shell/browser/ui/tray_icon_gtk.h b/shell/browser/ui/tray_icon_gtk.h index c01621aed24a1..7da8890d6b702 100644 --- a/shell/browser/ui/tray_icon_gtk.h +++ b/shell/browser/ui/tray_icon_gtk.h @@ -9,11 +9,11 @@ #include #include "shell/browser/ui/tray_icon.h" -#include "ui/views/linux_ui/status_icon_linux.h" +#include "ui/linux/status_icon_linux.h" namespace electron { -class TrayIconGtk : public TrayIcon, public views::StatusIconLinux::Delegate { +class TrayIconGtk : public TrayIcon, public ui::StatusIconLinux::Delegate { public: TrayIconGtk(); ~TrayIconGtk() override; @@ -23,7 +23,7 @@ class TrayIconGtk : public TrayIcon, public views::StatusIconLinux::Delegate { void SetToolTip(const std::string& tool_tip) override; void SetContextMenu(ElectronMenuModel* menu_model) override; - // views::StatusIconLinux::Delegate + // ui::StatusIconLinux::Delegate void OnClick() override; bool HasClickAction() override; // The following four methods are only used by StatusIconLinuxDbus, which we @@ -34,7 +34,7 @@ class TrayIconGtk : public TrayIcon, public views::StatusIconLinux::Delegate { void OnImplInitializationFailed() override; private: - std::unique_ptr icon_; + std::unique_ptr icon_; gfx::ImageSkia image_; std::u16string tool_tip_; ui::MenuModel* menu_model_; diff --git a/shell/browser/ui/views/autofill_popup_view.cc b/shell/browser/ui/views/autofill_popup_view.cc index fbe475d5b7e9d..fd2e50921460a 100644 --- a/shell/browser/ui/views/autofill_popup_view.cc +++ b/shell/browser/ui/views/autofill_popup_view.cc @@ -174,7 +174,7 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, const int text_align = is_rtl ? gfx::Canvas::TEXT_ALIGN_RIGHT : gfx::Canvas::TEXT_ALIGN_LEFT; gfx::Rect value_rect = entry_rect; - value_rect.Inset(kEndPadding, 0); + value_rect.Inset(gfx::Insets::VH(0, kEndPadding)); int x_align_left = value_rect.x(); const int value_width = gfx::GetStringWidth( diff --git a/shell/browser/ui/views/client_frame_view_linux.cc b/shell/browser/ui/views/client_frame_view_linux.cc index caf69b0f49ff4..97905462a45b9 100644 --- a/shell/browser/ui/views/client_frame_view_linux.cc +++ b/shell/browser/ui/views/client_frame_view_linux.cc @@ -23,14 +23,15 @@ #include "ui/gfx/text_constants.h" #include "ui/gtk/gtk_compat.h" // nogncheck #include "ui/gtk/gtk_util.h" // nogncheck +#include "ui/linux/linux_ui.h" +#include "ui/linux/nav_button_provider.h" #include "ui/native_theme/native_theme.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/controls/button/image_button.h" -#include "ui/views/linux_ui/linux_ui.h" -#include "ui/views/linux_ui/nav_button_provider.h" #include "ui/views/style/typography.h" #include "ui/views/widget/widget.h" #include "ui/views/window/frame_buttons.h" +#include "ui/views/window/window_button_order_provider.h" namespace electron { @@ -40,6 +41,25 @@ namespace { constexpr int kResizeOutsideBorderSize = 10; constexpr int kResizeInsideBoundsSize = 5; +ui::NavButtonProvider::ButtonState ButtonStateToNavButtonProviderState( + views::Button::ButtonState state) { + switch (state) { + case views::Button::STATE_NORMAL: + return ui::NavButtonProvider::ButtonState::kNormal; + case views::Button::STATE_HOVERED: + return ui::NavButtonProvider::ButtonState::kHovered; + case views::Button::STATE_PRESSED: + return ui::NavButtonProvider::ButtonState::kPressed; + case views::Button::STATE_DISABLED: + return ui::NavButtonProvider::ButtonState::kDisabled; + + case views::Button::STATE_COUNT: + default: + NOTREACHED(); + return ui::NavButtonProvider::ButtonState::kNormal; + } +} + } // namespace // static @@ -47,19 +67,18 @@ const char ClientFrameViewLinux::kViewClassName[] = "ClientFrameView"; ClientFrameViewLinux::ClientFrameViewLinux() : theme_(ui::NativeTheme::GetInstanceForNativeUi()), - nav_button_provider_( - views::LinuxUI::instance()->CreateNavButtonProvider()), + nav_button_provider_(ui::LinuxUi::instance()->CreateNavButtonProvider()), nav_buttons_{ - NavButton{views::NavButtonProvider::FrameButtonDisplayType::kClose, + NavButton{ui::NavButtonProvider::FrameButtonDisplayType::kClose, views::FrameButton::kClose, &views::Widget::Close, IDS_APP_ACCNAME_CLOSE, HTCLOSE}, - NavButton{views::NavButtonProvider::FrameButtonDisplayType::kMaximize, + NavButton{ui::NavButtonProvider::FrameButtonDisplayType::kMaximize, views::FrameButton::kMaximize, &views::Widget::Maximize, IDS_APP_ACCNAME_MAXIMIZE, HTMAXBUTTON}, - NavButton{views::NavButtonProvider::FrameButtonDisplayType::kRestore, + NavButton{ui::NavButtonProvider::FrameButtonDisplayType::kRestore, views::FrameButton::kMaximize, &views::Widget::Restore, IDS_APP_ACCNAME_RESTORE, HTMAXBUTTON}, - NavButton{views::NavButtonProvider::FrameButtonDisplayType::kMinimize, + NavButton{ui::NavButtonProvider::FrameButtonDisplayType::kMinimize, views::FrameButton::kMinimize, &views::Widget::Minimize, IDS_APP_ACCNAME_MINIMIZE, HTMINBUTTON}, }, @@ -83,11 +102,16 @@ ClientFrameViewLinux::ClientFrameViewLinux() AddChildView(title_); native_theme_observer_.Observe(theme_); - window_button_order_observer_.Observe(views::LinuxUI::instance()); + + if (ui::LinuxUi* ui = ui::LinuxUi::instance()) { + ui->AddWindowButtonOrderObserver(this); + OnWindowButtonOrderingChange(); + } } ClientFrameViewLinux::~ClientFrameViewLinux() { - views::LinuxUI::instance()->RemoveWindowButtonOrderObserver(this); + if (ui::LinuxUi* ui = ui::LinuxUi::instance()) + ui->RemoveWindowButtonOrderObserver(this); theme_->RemoveObserver(this); } @@ -106,8 +130,8 @@ void ClientFrameViewLinux::Init(NativeWindowViews* window, window->GetAcceleratedWidget())); host_supports_client_frame_shadow_ = tree_host->SupportsClientFrameShadow(); - frame_provider_ = views::LinuxUI::instance()->GetWindowFrameProvider( - !host_supports_client_frame_shadow_); + frame_provider_ = ui::LinuxUi::instance()->GetWindowFrameProvider( + !host_supports_client_frame_shadow_, frame_->IsMaximized()); UpdateWindowTitle(); @@ -159,11 +183,10 @@ void ClientFrameViewLinux::OnNativeThemeUpdated( UpdateThemeValues(); } -void ClientFrameViewLinux::OnWindowButtonOrderingChange( - const std::vector& leading_buttons, - const std::vector& trailing_buttons) { - leading_frame_buttons_ = leading_buttons; - trailing_frame_buttons_ = trailing_buttons; +void ClientFrameViewLinux::OnWindowButtonOrderingChange() { + auto* provider = views::WindowButtonOrderProvider::GetInstance(); + leading_frame_buttons_ = provider->leading_buttons(); + trailing_frame_buttons_ = provider->trailing_buttons(); InvalidateLayout(); } @@ -178,7 +201,8 @@ gfx::Rect ClientFrameViewLinux::GetBoundsForClientView() const { gfx::Rect client_bounds = bounds(); if (!frame_->IsFullscreen()) { client_bounds.Inset(GetBorderDecorationInsets()); - client_bounds.Inset(0, GetTitlebarBounds().height(), 0, 0); + client_bounds.Inset( + gfx::Insets::TLBR(GetTitlebarBounds().height(), 0, 0, 0)); } return client_bounds; } @@ -250,6 +274,9 @@ void ClientFrameViewLinux::Layout() { return; } + frame_provider_ = ui::LinuxUi::instance()->GetWindowFrameProvider( + !host_supports_client_frame_shadow_, frame_->IsMaximized()); + UpdateButtonImages(); LayoutButtons(); @@ -320,11 +347,11 @@ void ClientFrameViewLinux::UpdateThemeValues() { SchedulePaint(); } -views::NavButtonProvider::FrameButtonDisplayType +ui::NavButtonProvider::FrameButtonDisplayType ClientFrameViewLinux::GetButtonTypeToSkip() const { return frame_->IsMaximized() - ? views::NavButtonProvider::FrameButtonDisplayType::kMaximize - : views::NavButtonProvider::FrameButtonDisplayType::kRestore; + ? ui::NavButtonProvider::FrameButtonDisplayType::kMaximize + : ui::NavButtonProvider::FrameButtonDisplayType::kRestore; } void ClientFrameViewLinux::UpdateButtonImages() { @@ -332,7 +359,7 @@ void ClientFrameViewLinux::UpdateButtonImages() { frame_->IsMaximized(), ShouldPaintAsActive()); - views::NavButtonProvider::FrameButtonDisplayType skip_type = + ui::NavButtonProvider::FrameButtonDisplayType skip_type = GetButtonTypeToSkip(); for (NavButton& button : nav_buttons_) { @@ -345,7 +372,8 @@ void ClientFrameViewLinux::UpdateButtonImages() { views::Button::ButtonState state = static_cast(state_id); button.button->SetImage( - state, nav_button_provider_->GetImage(button.type, state)); + state, nav_button_provider_->GetImage( + button.type, ButtonStateToNavButtonProviderState(state))); } } } @@ -363,7 +391,7 @@ void ClientFrameViewLinux::LayoutButtons() { void ClientFrameViewLinux::LayoutButtonsOnSide( ButtonSide side, gfx::Rect* remaining_content_bounds) { - views::NavButtonProvider::FrameButtonDisplayType skip_type = + ui::NavButtonProvider::FrameButtonDisplayType skip_type = GetButtonTypeToSkip(); std::vector frame_buttons; @@ -460,4 +488,9 @@ gfx::Size ClientFrameViewLinux::SizeWithDecorations(gfx::Size size) const { return size; } +views::View* ClientFrameViewLinux::TargetForRect(views::View* root, + const gfx::Rect& rect) { + return views::NonClientFrameView::TargetForRect(root, rect); +} + } // namespace electron diff --git a/shell/browser/ui/views/client_frame_view_linux.h b/shell/browser/ui/views/client_frame_view_linux.h index 404c0e6b7db91..cd0acf7b8af07 100644 --- a/shell/browser/ui/views/client_frame_view_linux.h +++ b/shell/browser/ui/views/client_frame_view_linux.h @@ -11,14 +11,14 @@ #include "base/scoped_observation.h" #include "shell/browser/ui/views/frameless_view.h" +#include "ui/linux/linux_ui.h" +#include "ui/linux/nav_button_provider.h" +#include "ui/linux/window_button_order_observer.h" +#include "ui/linux/window_frame_provider.h" #include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme_observer.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/label.h" -#include "ui/views/linux_ui/linux_ui.h" -#include "ui/views/linux_ui/nav_button_provider.h" -#include "ui/views/linux_ui/window_button_order_observer.h" -#include "ui/views/linux_ui/window_frame_provider.h" #include "ui/views/widget/widget.h" #include "ui/views/window/frame_buttons.h" @@ -26,7 +26,7 @@ namespace electron { class ClientFrameViewLinux : public FramelessView, public ui::NativeThemeObserver, - public views::WindowButtonOrderObserver { + public ui::WindowButtonOrderObserver { public: static const char kViewClassName[]; ClientFrameViewLinux(); @@ -45,14 +45,12 @@ class ClientFrameViewLinux : public FramelessView, void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override; // views::WindowButtonOrderObserver: - void OnWindowButtonOrderingChange( - const std::vector& leading_buttons, - const std::vector& trailing_buttons) override; + void OnWindowButtonOrderingChange() override; - // Overriden from FramelessView: + // Overridden from FramelessView: int ResizingBorderHitTest(const gfx::Point& point) override; - // Overriden from views::NonClientFrameView: + // Overridden from views::NonClientFrameView: gfx::Rect GetBoundsForClientView() const override; gfx::Rect GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const override; @@ -69,11 +67,14 @@ class ClientFrameViewLinux : public FramelessView, void OnPaint(gfx::Canvas* canvas) override; const char* GetClassName() const override; + // Overriden from views::ViewTargeterDelegate + views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override; + private: static constexpr int kNavButtonCount = 4; struct NavButton { - views::NavButtonProvider::FrameButtonDisplayType type; + ui::NavButtonProvider::FrameButtonDisplayType type; views::FrameButton frame_button; void (views::Widget::*callback)(); int accessibility_id; @@ -100,7 +101,7 @@ class ClientFrameViewLinux : public FramelessView, enum class ButtonSide { kLeading, kTrailing }; - views::NavButtonProvider::FrameButtonDisplayType GetButtonTypeToSkip() const; + ui::NavButtonProvider::FrameButtonDisplayType GetButtonTypeToSkip() const; void UpdateButtonImages(); void LayoutButtons(); void LayoutButtonsOnSide(ButtonSide side, @@ -117,7 +118,7 @@ class ClientFrameViewLinux : public FramelessView, views::Label* title_; - std::unique_ptr nav_button_provider_; + std::unique_ptr nav_button_provider_; std::array nav_buttons_; std::vector leading_frame_buttons_; @@ -125,14 +126,14 @@ class ClientFrameViewLinux : public FramelessView, bool host_supports_client_frame_shadow_ = false; - views::WindowFrameProvider* frame_provider_; + ui::WindowFrameProvider* frame_provider_; base::ScopedObservation native_theme_observer_{this}; - base::ScopedObservation + base::ScopedObservation window_button_order_observer_{this}; base::CallbackListSubscription paint_as_active_changed_subscription_; diff --git a/shell/browser/ui/views/electron_views_delegate.cc b/shell/browser/ui/views/electron_views_delegate.cc index 6f7859f2246fc..3510b896fc3c1 100644 --- a/shell/browser/ui/views/electron_views_delegate.cc +++ b/shell/browser/ui/views/electron_views_delegate.cc @@ -12,7 +12,7 @@ #if BUILDFLAG(IS_LINUX) #include "base/environment.h" #include "base/nix/xdg_util.h" -#include "ui/views/linux_ui/linux_ui.h" +#include "ui/linux/linux_ui.h" #endif namespace { diff --git a/shell/browser/ui/views/electron_views_delegate_win.cc b/shell/browser/ui/views/electron_views_delegate_win.cc index a25fb6f29abf7..10cb4ca82050a 100644 --- a/shell/browser/ui/views/electron_views_delegate_win.cc +++ b/shell/browser/ui/views/electron_views_delegate_win.cc @@ -10,7 +10,6 @@ #include #include "base/bind.h" -#include "base/task/post_task.h" #include "base/task/thread_pool.h" namespace { @@ -52,7 +51,7 @@ bool MonitorHasAutohideTaskbarForEdge(UINT edge, HMONITOR monitor) { // There is a potential race condition here: // 1. A maximized chrome window is fullscreened. // 2. It is switched back to maximized. - // 3. In the process the window gets a WM_NCCACLSIZE message which calls us to + // 3. In the process the window gets a WM_NCCALCSIZE message which calls us to // get the autohide state. // 4. The worker thread is invoked. It calls the API to get the autohide // state. On Windows versions earlier than Windows 7, taskbars could diff --git a/shell/browser/ui/views/global_menu_bar_x11.cc b/shell/browser/ui/views/global_menu_bar_x11.cc index 27f90b94b46cf..785a59866faf2 100644 --- a/shell/browser/ui/views/global_menu_bar_x11.cc +++ b/shell/browser/ui/views/global_menu_bar_x11.cc @@ -143,7 +143,7 @@ ElectronMenuModel* ModelForMenuItem(DbusmenuMenuitem* item) { g_object_get_data(G_OBJECT(item), "model")); } -bool GetMenuItemID(DbusmenuMenuitem* item, int* id) { +bool GetMenuItemID(DbusmenuMenuitem* item, size_t* id) { gpointer id_ptr = g_object_get_data(G_OBJECT(item), "menu-id"); if (id_ptr != nullptr) { *id = GPOINTER_TO_INT(id_ptr) - 1; @@ -162,7 +162,7 @@ void SetMenuItemID(DbusmenuMenuitem* item, int id) { std::string GetMenuModelStatus(ElectronMenuModel* model) { std::string ret; - for (int i = 0; i < model->GetItemCount(); ++i) { + for (size_t i = 0; i < model->GetItemCount(); ++i) { int status = model->GetTypeAt(i) | (model->IsVisibleAt(i) << 3) | (model->IsEnabledAt(i) << 4) | (model->IsItemCheckedAt(i) << 5); @@ -231,7 +231,7 @@ void GlobalMenuBarX11::OnWindowUnmapped() { void GlobalMenuBarX11::BuildMenuFromModel(ElectronMenuModel* model, DbusmenuMenuitem* parent) { - for (int i = 0; i < model->GetItemCount(); ++i) { + for (size_t i = 0; i < model->GetItemCount(); ++i) { DbusmenuMenuitem* item = menuitem_new(); menuitem_property_set_bool(item, kPropertyVisible, model->IsVisibleAt(i)); @@ -309,14 +309,14 @@ void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item, void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item, unsigned int timestamp) { - int id; + size_t id; ElectronMenuModel* model = ModelForMenuItem(item); if (model && GetMenuItemID(item, &id)) model->ActivatedAt(id, 0); } void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) { - int id; + size_t id; ElectronMenuModel* model = ModelForMenuItem(item); if (!model || !GetMenuItemID(item, &id)) return; diff --git a/shell/browser/ui/views/menu_bar.cc b/shell/browser/ui/views/menu_bar.cc index 380ce55efdf42..7a0ba8139e1f0 100644 --- a/shell/browser/ui/views/menu_bar.cc +++ b/shell/browser/ui/views/menu_bar.cc @@ -38,8 +38,7 @@ MenuBar::MenuBar(NativeWindow* window, RootView* root_view) RefreshColorCache(theme); UpdateViewColors(); #if BUILDFLAG(IS_WIN) - SetBackground( - views::CreateThemedSolidBackground(this, ui::kColorMenuBackground)); + SetBackground(views::CreateThemedSolidBackground(ui::kColorMenuBackground)); background_color_ = GetBackground()->get_color(); #endif SetFocusBehavior(FocusBehavior::ALWAYS); @@ -82,7 +81,7 @@ void MenuBar::ActivateAccelerator(char16_t key) { static_cast(child)->Activate(nullptr); } -int MenuBar::GetItemCount() const { +size_t MenuBar::GetItemCount() const { return menu_model_ ? menu_model_->GetItemCount() : 0; } @@ -93,7 +92,7 @@ bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& screenPoint, return false; auto children = GetChildrenInZOrder(); - for (int i = 0, n = children.size(); i < n; ++i) { + for (size_t i = 0, n = children.size(); i < n; ++i) { if (children[i]->GetBoundsInScreen().Contains(screenPoint) && (menu_model_->GetTypeAt(i) == ElectronMenuModel::TYPE_SUBMENU)) { *menu_model = menu_model_->GetSubmenuModelAt(i); @@ -175,7 +174,7 @@ const char* MenuBar::GetClassName() const { return kViewClassName; } -void MenuBar::ButtonPressed(int id, const ui::Event& event) { +void MenuBar::ButtonPressed(size_t id, const ui::Event& event) { // Hide the accelerator when a submenu is activated. SetAcceleratorVisibility(pane_has_focus()); @@ -194,7 +193,8 @@ void MenuBar::ButtonPressed(int id, const ui::Event& event) { SubmenuButton* source = nullptr; for (auto* child : children()) { auto* button = static_cast(child); - if (button->tag() == id) { + int button_id = button->GetID(); + if (button_id >= 0 && static_cast(button_id) == id) { source = button; break; } @@ -223,11 +223,11 @@ void MenuBar::RefreshColorCache(const ui::NativeTheme* theme) { void MenuBar::RebuildChildren() { RemoveAllChildViews(); - for (int i = 0, n = GetItemCount(); i < n; ++i) { + for (size_t i = 0, n = GetItemCount(); i < n; ++i) { auto* button = new SubmenuButton( base::BindRepeating(&MenuBar::ButtonPressed, base::Unretained(this), i), menu_model_->GetLabelAt(i), background_color_); - button->set_tag(i); + button->SetID(i); AddChildView(button); } UpdateViewColors(); diff --git a/shell/browser/ui/views/menu_bar.h b/shell/browser/ui/views/menu_bar.h index 4ef178538a6ca..91546fb33cc55 100644 --- a/shell/browser/ui/views/menu_bar.h +++ b/shell/browser/ui/views/menu_bar.h @@ -43,7 +43,7 @@ class MenuBar : public views::AccessiblePaneView, void ActivateAccelerator(char16_t key); // Returns there are how many items in the root menu. - int GetItemCount() const; + size_t GetItemCount() const; // Get the menu under specified screen point. bool GetMenuButtonFromScreenPoint(const gfx::Point& point, @@ -71,7 +71,7 @@ class MenuBar : public views::AccessiblePaneView, const char* GetClassName() const override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void ButtonPressed(int id, const ui::Event& event); + void ButtonPressed(size_t id, const ui::Event& event); void RebuildChildren(); void UpdateViewColors(); diff --git a/shell/browser/ui/views/menu_delegate.cc b/shell/browser/ui/views/menu_delegate.cc index 3a088af6348c4..e6f4c49b57f88 100644 --- a/shell/browser/ui/views/menu_delegate.cc +++ b/shell/browser/ui/views/menu_delegate.cc @@ -6,7 +6,6 @@ #include -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "shell/browser/ui/views/menu_bar.h" @@ -35,7 +34,7 @@ void MenuDelegate::RunMenu(ElectronMenuModel* model, hold_first_switch_ = true; } - id_ = button->tag(); + id_ = button->GetID(); adapter_ = std::make_unique(model); auto* item = new views::MenuItemView(this); @@ -128,14 +127,14 @@ views::MenuItemView* MenuDelegate::GetSiblingMenu( views::MenuButton* button; ElectronMenuModel* model; if (menu_bar_->GetMenuButtonFromScreenPoint(screen_point, &model, &button) && - button->tag() != id_) { + button->GetID() != id_) { bool switch_in_progress = !!button_to_open_; // Always update target to open. button_to_open_ = button; // Switching menu asynchronously to avoid crash. if (!switch_in_progress) { - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&views::MenuRunner::Cancel, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&views::MenuRunner::Cancel, base::Unretained(menu_runner_.get()))); } } diff --git a/shell/browser/ui/views/menu_model_adapter.cc b/shell/browser/ui/views/menu_model_adapter.cc index be8083833d01d..99958ffaaa793 100644 --- a/shell/browser/ui/views/menu_model_adapter.cc +++ b/shell/browser/ui/views/menu_model_adapter.cc @@ -14,7 +14,7 @@ MenuModelAdapter::~MenuModelAdapter() = default; bool MenuModelAdapter::GetAccelerator(int id, ui::Accelerator* accelerator) const { ui::MenuModel* model = menu_model_; - int index = 0; + size_t index = 0; if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { return static_cast(model)->GetAcceleratorAtWithParams( index, true, accelerator); diff --git a/shell/browser/ui/views/win_caption_button.cc b/shell/browser/ui/views/win_caption_button.cc index a3a52244ff206..9d90fc6a6fd27 100644 --- a/shell/browser/ui/views/win_caption_button.cc +++ b/shell/browser/ui/views/win_caption_button.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Modified from chrome/browser/ui/views/frame/windows_10_caption_button.cc +// Modified from chrome/browser/ui/views/frame/windows_caption_button.cc #include "shell/browser/ui/views/win_caption_button.h" @@ -10,6 +10,7 @@ #include "base/i18n/rtl.h" #include "base/numerics/safe_conversions.h" +#include "base/win/windows_version.h" #include "chrome/grit/theme_resources.h" #include "shell/browser/ui/views/win_frame_view.h" #include "shell/common/color_util.h" @@ -28,6 +29,7 @@ WinCaptionButton::WinCaptionButton(PressedCallback callback, const std::u16string& accessible_name) : views::Button(std::move(callback)), frame_view_(frame_view), + icon_painter_(CreateIconPainter()), button_type_(button_type) { SetAnimateOnStateChange(true); // Not focusable by default, only for accessibility. @@ -35,6 +37,15 @@ WinCaptionButton::WinCaptionButton(PressedCallback callback, SetAccessibleName(accessible_name); } +WinCaptionButton::~WinCaptionButton() = default; + +std::unique_ptr WinCaptionButton::CreateIconPainter() { + if (base::win::GetVersion() >= base::win::Version::WIN11) { + return std::make_unique(); + } + return std::make_unique(); +} + gfx::Size WinCaptionButton::CalculatePreferredSize() const { // TODO(bsep): The sizes in this function are for 1x device scale and don't // match Windows button sizes at hidpi. @@ -50,9 +61,10 @@ void WinCaptionButton::OnPaintBackground(gfx::Canvas* canvas) { const SkAlpha theme_alpha = SkColorGetA(bg_color); gfx::Rect bounds = GetContentsBounds(); - bounds.Inset(0, 0, 0, 0); + bounds.Inset(gfx::Insets::TLBR(0, GetBetweenButtonSpacing(), 0, 0)); - canvas->FillRect(bounds, SkColorSetA(bg_color, theme_alpha)); + if (theme_alpha > 0) + canvas->FillRect(bounds, SkColorSetA(bg_color, theme_alpha)); SkColor base_color; SkAlpha hovered_alpha, pressed_alpha; @@ -136,21 +148,6 @@ int WinCaptionButton::GetButtonDisplayOrderIndex() const { return button_display_order; } -namespace { - -// Canvas::DrawRect's stroke can bleed out of |rect|'s bounds, so this draws a -// rectangle inset such that the result is constrained to |rect|'s size. -void DrawRect(gfx::Canvas* canvas, - const gfx::Rect& rect, - const cc::PaintFlags& flags) { - gfx::RectF rect_f(rect); - float stroke_half_width = flags.getStrokeWidth() / 2; - rect_f.Inset(stroke_half_width, stroke_half_width); - canvas->DrawRect(rect_f, flags); -} - -} // namespace - void WinCaptionButton::PaintSymbol(gfx::Canvas* canvas) { SkColor symbol_color = frame_view_->window()->overlay_symbol_color(); @@ -183,32 +180,21 @@ void WinCaptionButton::PaintSymbol(gfx::Canvas* canvas) { switch (button_type_) { case VIEW_ID_MINIMIZE_BUTTON: { - const int y = symbol_rect.CenterPoint().y(); - const gfx::Point p1 = gfx::Point(symbol_rect.x(), y); - const gfx::Point p2 = gfx::Point(symbol_rect.right(), y); - canvas->DrawLine(p1, p2, flags); + icon_painter_->PaintMinimizeIcon(canvas, symbol_rect, flags); return; } - case VIEW_ID_MAXIMIZE_BUTTON: - DrawRect(canvas, symbol_rect, flags); + case VIEW_ID_MAXIMIZE_BUTTON: { + icon_painter_->PaintMaximizeIcon(canvas, symbol_rect, flags); return; + } case VIEW_ID_RESTORE_BUTTON: { - // Bottom left ("in front") square. - const int separation = std::floor(2 * scale); - symbol_rect.Inset(0, separation, separation, 0); - DrawRect(canvas, symbol_rect, flags); - - // Top right ("behind") square. - canvas->ClipRect(symbol_rect, SkClipOp::kDifference); - symbol_rect.Offset(separation, -separation); - DrawRect(canvas, symbol_rect, flags); + icon_painter_->PaintRestoreIcon(canvas, symbol_rect, flags); return; } case VIEW_ID_CLOSE_BUTTON: { - flags.setAntiAlias(true); // The close button's X is surrounded by a "halo" of transparent pixels. // When the X is white, the transparent pixels need to be a bit brighter // to be visible. @@ -216,15 +202,7 @@ void WinCaptionButton::PaintSymbol(gfx::Canvas* canvas) { stroke_width * (symbol_color == SK_ColorWHITE ? 0.1f : 0.05f); flags.setStrokeWidth(stroke_width + stroke_halo); - // TODO(bsep): This sometimes draws misaligned at fractional device scales - // because the button's origin isn't necessarily aligned to pixels. - canvas->ClipRect(symbol_rect); - SkPath path; - path.moveTo(symbol_rect.x(), symbol_rect.y()); - path.lineTo(symbol_rect.right(), symbol_rect.bottom()); - path.moveTo(symbol_rect.right(), symbol_rect.y()); - path.lineTo(symbol_rect.x(), symbol_rect.bottom()); - canvas->DrawPath(path, flags); + icon_painter_->PaintCloseIcon(canvas, symbol_rect, flags); return; } diff --git a/shell/browser/ui/views/win_caption_button.h b/shell/browser/ui/views/win_caption_button.h index fafa3e414bcff..801474b5e3f4b 100644 --- a/shell/browser/ui/views/win_caption_button.h +++ b/shell/browser/ui/views/win_caption_button.h @@ -7,8 +7,11 @@ #ifndef ELECTRON_SHELL_BROWSER_UI_VIEWS_WIN_CAPTION_BUTTON_H_ #define ELECTRON_SHELL_BROWSER_UI_VIEWS_WIN_CAPTION_BUTTON_H_ +#include + #include "chrome/browser/ui/frame/window_frame_util.h" #include "chrome/browser/ui/view_ids.h" +#include "shell/browser/ui/views/win_icon_painter.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/gfx/canvas.h" #include "ui/views/controls/button/button.h" @@ -23,6 +26,8 @@ class WinCaptionButton : public views::Button { WinFrameView* frame_view, ViewID button_type, const std::u16string& accessible_name); + ~WinCaptionButton() override; + WinCaptionButton(const WinCaptionButton&) = delete; WinCaptionButton& operator=(const WinCaptionButton&) = delete; @@ -35,6 +40,7 @@ class WinCaptionButton : public views::Button { void SetSize(gfx::Size size); private: + std::unique_ptr CreateIconPainter(); // Returns the amount we should visually reserve on the left (right in RTL) // for spacing between buttons. We do this instead of repositioning the // buttons to avoid the sliver of deadspace that would result. @@ -53,6 +59,7 @@ class WinCaptionButton : public views::Button { void PaintSymbol(gfx::Canvas* canvas); WinFrameView* frame_view_; + std::unique_ptr icon_painter_; ViewID button_type_; int base_width_ = WindowFrameUtil::kWindows10GlassCaptionButtonWidth; diff --git a/shell/browser/ui/views/win_caption_button_container.cc b/shell/browser/ui/views/win_caption_button_container.cc index 9995c9741279c..99a7fc4bc057b 100644 --- a/shell/browser/ui/views/win_caption_button_container.cc +++ b/shell/browser/ui/views/win_caption_button_container.cc @@ -14,6 +14,7 @@ #include "shell/browser/ui/views/win_frame_view.h" #include "ui/base/l10n/l10n_util.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/background.h" #include "ui/views/layout/flex_layout.h" #include "ui/views/view_class_properties.h" @@ -128,6 +129,8 @@ void WinCaptionButtonContainer::AddedToWidget() { UpdateButtons(); if (frame_view_->window()->IsWindowControlsOverlayEnabled()) { + SetBackground(views::CreateSolidBackground( + frame_view_->window()->overlay_button_color())); SetPaintToLayer(); } } @@ -148,11 +151,31 @@ void WinCaptionButtonContainer::UpdateButtons() { restore_button_->SetVisible(is_maximized); maximize_button_->SetVisible(!is_maximized); + const bool minimizable = frame_view_->window()->IsMinimizable(); + minimize_button_->SetEnabled(minimizable); + // In touch mode, windows cannot be taken out of fullscreen or tiled mode, so // the maximize/restore button should be disabled. const bool is_touch = ui::TouchUiController::Get()->touch_ui(); restore_button_->SetEnabled(!is_touch); - maximize_button_->SetEnabled(!is_touch); + + // In touch mode, windows cannot be taken out of fullscreen or tiled mode, so + // the maximize/restore button should be disabled, unless the window is not + // maximized. + const bool maximizable = frame_view_->window()->IsMaximizable(); + maximize_button_->SetEnabled(!(is_touch && is_maximized) && maximizable); + + const bool closable = frame_view_->window()->IsClosable(); + close_button_->SetEnabled(closable); + + // If all three of closable, maximizable, and minimizable are disabled, + // Windows natively only shows the disabled closable button. Copy that + // behavior here. + if (!maximizable && !closable && !minimizable) { + minimize_button_->SetVisible(false); + maximize_button_->SetVisible(false); + } + InvalidateLayout(); } } // namespace electron diff --git a/shell/browser/ui/views/win_caption_button_container.h b/shell/browser/ui/views/win_caption_button_container.h index 9a40ae1be3415..90c5973491c8e 100644 --- a/shell/browser/ui/views/win_caption_button_container.h +++ b/shell/browser/ui/views/win_caption_button_container.h @@ -41,6 +41,14 @@ class WinCaptionButtonContainer : public views::View, gfx::Size GetButtonSize() const; void SetButtonSize(gfx::Size size); + // Sets caption button visibility and enabled state based on window state. + // Only one of maximize or restore button should ever be visible at the same + // time, and both are disabled in tablet UI mode. + void UpdateButtons(); + + // Reset window button states to STATE_NORMAL. + void ResetWindowControls(); + private: // views::View: void AddedToWidget() override; @@ -50,13 +58,6 @@ class WinCaptionButtonContainer : public views::View, void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) override; - void ResetWindowControls(); - - // Sets caption button visibility and enabled state based on window state. - // Only one of maximize or restore button should ever be visible at the same - // time, and both are disabled in tablet UI mode. - void UpdateButtons(); - WinFrameView* const frame_view_; WinCaptionButton* const minimize_button_; WinCaptionButton* const maximize_button_; diff --git a/shell/browser/ui/views/win_frame_view.cc b/shell/browser/ui/views/win_frame_view.cc index 3ab47ed9ad917..ad01b0cbac91e 100644 --- a/shell/browser/ui/views/win_frame_view.cc +++ b/shell/browser/ui/views/win_frame_view.cc @@ -19,6 +19,7 @@ #include "ui/display/win/dpi.h" #include "ui/display/win/screen_win.h" #include "ui/gfx/geometry/dip_util.h" +#include "ui/views/background.h" #include "ui/views/widget/widget.h" #include "ui/views/win/hwnd_util.h" @@ -55,9 +56,11 @@ SkColor WinFrameView::GetReadableFeatureColor(SkColor background_color) { } void WinFrameView::InvalidateCaptionButtons() { - // Ensure that the caption buttons container exists - DCHECK(caption_button_container_); + if (!caption_button_container_) + return; + caption_button_container_->SetBackground( + views::CreateSolidBackground(window()->overlay_button_color())); caption_button_container_->InvalidateLayout(); caption_button_container_->SchedulePaint(); } @@ -143,7 +146,7 @@ int WinFrameView::NonClientHitTest(const gfx::Point& point) { // show the resize cursor when resizing is possible. The cost of which // is also maybe showing it over the portion of the DIP that isn't the // outermost pixel. - buttons.Inset(0, kCaptionButtonTopInset, 0, 0); + buttons.Inset(gfx::Insets::TLBR(0, kCaptionButtonTopInset, 0, 0)); if (buttons.Contains(point)) return HTNOWHERE; } @@ -154,8 +157,8 @@ int WinFrameView::NonClientHitTest(const gfx::Point& point) { // pixels at the end of the top and bottom edges trigger diagonal resizing. constexpr int kResizeCornerWidth = 16; int window_component = GetHTComponentForFrame( - point, gfx::Insets(top_border_thickness, 0, 0, 0), top_border_thickness, - kResizeCornerWidth - FrameBorderThickness(), + point, gfx::Insets::TLBR(top_border_thickness, 0, 0, 0), + top_border_thickness, kResizeCornerWidth - FrameBorderThickness(), frame()->widget_delegate()->CanResize()); if (window_component != HTNOWHERE) return window_component; diff --git a/shell/browser/ui/views/win_frame_view.h b/shell/browser/ui/views/win_frame_view.h index 460474e03bb66..3dddee8af6cac 100644 --- a/shell/browser/ui/views/win_frame_view.h +++ b/shell/browser/ui/views/win_frame_view.h @@ -13,6 +13,7 @@ #include "shell/browser/native_window_views.h" #include "shell/browser/ui/views/frameless_view.h" #include "shell/browser/ui/views/win_caption_button.h" +#include "shell/browser/ui/views/win_caption_button_container.h" namespace electron { @@ -43,6 +44,9 @@ class WinFrameView : public FramelessView { NativeWindowViews* window() const { return window_; } views::Widget* frame() const { return frame_; } + WinCaptionButtonContainer* caption_button_container() { + return caption_button_container_; + } bool IsMaximized() const; diff --git a/shell/browser/ui/views/win_icon_painter.cc b/shell/browser/ui/views/win_icon_painter.cc new file mode 100644 index 0000000000000..d89d63d439051 --- /dev/null +++ b/shell/browser/ui/views/win_icon_painter.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2022 Microsoft, Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "shell/browser/ui/views/win_icon_painter.h" + +#include "base/numerics/safe_conversions.h" +#include "ui/gfx/color_utils.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/skia_conversions.h" +#include "ui/gfx/scoped_canvas.h" + +namespace { + +// Canvas::DrawRect's stroke can bleed out of |rect|'s bounds, so this draws a +// rectangle inset such that the result is constrained to |rect|'s size. +void DrawRect(gfx::Canvas* canvas, + const gfx::Rect& rect, + const cc::PaintFlags& flags) { + gfx::RectF rect_f(rect); + float stroke_half_width = flags.getStrokeWidth() / 2; + rect_f.Inset(stroke_half_width); + canvas->DrawRect(rect_f, flags); +} + +void DrawRoundRect(gfx::Canvas* canvas, + const gfx::Rect& rect, + float radius, + const cc::PaintFlags& flags) { + gfx::RectF rect_f(rect); + float stroke_half_width = flags.getStrokeWidth() / 2; + rect_f.Inset(stroke_half_width); + canvas->DrawRoundRect(rect_f, radius, flags); +} + +// Draws a path containing the top and right edges of a rounded rectangle. +void DrawRoundRectEdges(gfx::Canvas* canvas, + const gfx::Rect& rect, + float radius, + const cc::PaintFlags& flags) { + gfx::RectF symbol_rect_f(rect); + float stroke_half_width = flags.getStrokeWidth() / 2; + symbol_rect_f.Inset(stroke_half_width); + SkPath path; + path.moveTo(symbol_rect_f.x(), symbol_rect_f.y()); + path.arcTo(symbol_rect_f.right(), symbol_rect_f.y(), symbol_rect_f.right(), + symbol_rect_f.y() + radius, radius); + path.lineTo(symbol_rect_f.right(), symbol_rect_f.bottom()); + canvas->DrawPath(path, flags); +} + +} // namespace + +namespace electron { + +WinIconPainter::WinIconPainter() = default; +WinIconPainter::~WinIconPainter() = default; + +void WinIconPainter::PaintMinimizeIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) { + const int y = symbol_rect.CenterPoint().y(); + const gfx::Point p1 = gfx::Point(symbol_rect.x(), y); + const gfx::Point p2 = gfx::Point(symbol_rect.right(), y); + canvas->DrawLine(p1, p2, flags); +} + +void WinIconPainter::PaintMaximizeIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) { + DrawRect(canvas, symbol_rect, flags); +} + +void WinIconPainter::PaintRestoreIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) { + const int separation = base::ClampFloor(2 * canvas->image_scale()); + gfx::Rect icon_rect = symbol_rect; + icon_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation)); + + // Bottom left ("in front") square. + DrawRect(canvas, icon_rect, flags); + + // Top right ("behind") square. + canvas->ClipRect(icon_rect, SkClipOp::kDifference); + icon_rect.Offset(separation, -separation); + DrawRect(canvas, icon_rect, flags); +} + +void WinIconPainter::PaintCloseIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) { + // TODO(bsep): This sometimes draws misaligned at fractional device scales + // because the button's origin isn't necessarily aligned to pixels. + cc::PaintFlags paint_flags = flags; + paint_flags.setAntiAlias(true); + + canvas->ClipRect(symbol_rect); + SkPath path; + path.moveTo(symbol_rect.x(), symbol_rect.y()); + path.lineTo(symbol_rect.right(), symbol_rect.bottom()); + path.moveTo(symbol_rect.right(), symbol_rect.y()); + path.lineTo(symbol_rect.x(), symbol_rect.bottom()); + canvas->DrawPath(path, flags); +} + +Win11IconPainter::Win11IconPainter() = default; +Win11IconPainter::~Win11IconPainter() = default; + +void Win11IconPainter::PaintMaximizeIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) { + cc::PaintFlags paint_flags = flags; + paint_flags.setAntiAlias(true); + + const float corner_radius = canvas->image_scale(); + DrawRoundRect(canvas, symbol_rect, corner_radius, flags); +} + +void Win11IconPainter::PaintRestoreIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) { + const int separation = base::ClampFloor(2 * canvas->image_scale()); + gfx::Rect icon_rect = symbol_rect; + icon_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation)); + + cc::PaintFlags paint_flags = flags; + paint_flags.setAntiAlias(true); + + // Bottom left ("in front") rounded square. + const float bottom_rect_radius = canvas->image_scale(); + DrawRoundRect(canvas, icon_rect, bottom_rect_radius, flags); + + // Top right ("behind") top+right edges of rounded square (2.5x). + icon_rect.Offset(separation, -separation); + + const float top_rect_radius = 2.5f * canvas->image_scale(); + DrawRoundRectEdges(canvas, icon_rect, top_rect_radius, flags); +} +} // namespace electron diff --git a/shell/browser/ui/views/win_icon_painter.h b/shell/browser/ui/views/win_icon_painter.h new file mode 100644 index 0000000000000..d3c85be296a0b --- /dev/null +++ b/shell/browser/ui/views/win_icon_painter.h @@ -0,0 +1,64 @@ +// Copyright (c) 2022 Microsoft, Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_BROWSER_UI_VIEWS_WIN_ICON_PAINTER_H_ +#define ELECTRON_SHELL_BROWSER_UI_VIEWS_WIN_ICON_PAINTER_H_ + +#include "base/memory/raw_ptr.h" +#include "ui/gfx/canvas.h" + +namespace electron { + +class WinIconPainter { + public: + WinIconPainter(); + virtual ~WinIconPainter(); + + WinIconPainter(const WinIconPainter&) = delete; + WinIconPainter& operator=(const WinIconPainter&) = delete; + + public: + // Paints the minimize icon for the button + virtual void PaintMinimizeIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags); + + // Paints the maximize icon for the button + virtual void PaintMaximizeIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags); + + // Paints the restore icon for the button + virtual void PaintRestoreIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags); + + // Paints the close icon for the button + virtual void PaintCloseIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags); +}; + +class Win11IconPainter : public WinIconPainter { + public: + Win11IconPainter(); + ~Win11IconPainter() override; + + Win11IconPainter(const Win11IconPainter&) = delete; + Win11IconPainter& operator=(const Win11IconPainter&) = delete; + + public: + // Paints the maximize icon for the button + void PaintMaximizeIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) override; + + // Paints the restore icon for the button + void PaintRestoreIcon(gfx::Canvas* canvas, + const gfx::Rect& symbol_rect, + const cc::PaintFlags& flags) override; +}; +} // namespace electron + +#endif // ELECTRON_SHELL_BROWSER_UI_VIEWS_WIN_ICON_PAINTER_H_ diff --git a/shell/browser/ui/webui/accessibility_ui.cc b/shell/browser/ui/webui/accessibility_ui.cc index 92b3d1e4a13bc..608899531ea9e 100644 --- a/shell/browser/ui/webui/accessibility_ui.cc +++ b/shell/browser/ui/webui/accessibility_ui.cc @@ -13,6 +13,7 @@ #include "base/callback_helpers.h" #include "base/command_line.h" #include "base/json/json_writer.h" +#include "base/strings/escape.h" #include "base/strings/pattern.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -37,7 +38,6 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_ui_data_source.h" -#include "net/base/escape.h" #include "shell/browser/native_window.h" #include "shell/browser/window_list.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -83,7 +83,7 @@ static const char kDisabled[] = "disabled"; static const char kOff[] = "off"; static const char kOn[] = "on"; -std::unique_ptr BuildTargetDescriptor( +base::Value::Dict BuildTargetDescriptor( const GURL& url, const std::string& name, const GURL& favicon_url, @@ -91,20 +91,20 @@ std::unique_ptr BuildTargetDescriptor( int routing_id, ui::AXMode accessibility_mode, base::ProcessHandle handle = base::kNullProcessHandle) { - auto target_data = std::make_unique(); - target_data->SetInteger(kProcessIdField, process_id); - target_data->SetInteger(kRoutingIdField, routing_id); - target_data->SetString(kUrlField, url.spec()); - target_data->SetString(kNameField, net::EscapeForHTML(name)); - target_data->SetInteger(kPidField, base::GetProcId(handle)); - target_data->SetString(kFaviconUrlField, favicon_url.spec()); - target_data->SetInteger(kAccessibilityModeField, accessibility_mode.mode()); - target_data->SetString(kTypeField, kPage); + base::Value::Dict target_data; + target_data.Set(kProcessIdField, process_id); + target_data.Set(kRoutingIdField, routing_id); + target_data.Set(kUrlField, url.spec()); + target_data.Set(kNameField, base::EscapeForHTML(name)); + target_data.Set(kPidField, static_cast(base::GetProcId(handle))); + target_data.Set(kFaviconUrlField, favicon_url.spec()); + target_data.Set(kAccessibilityModeField, + static_cast(accessibility_mode.mode())); + target_data.Set(kTypeField, kPage); return target_data; } -std::unique_ptr BuildTargetDescriptor( - content::RenderViewHost* rvh) { +base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) { content::WebContents* web_contents = content::WebContents::FromRenderViewHost(rvh); ui::AXMode accessibility_mode; @@ -132,12 +132,11 @@ std::unique_ptr BuildTargetDescriptor( accessibility_mode); } -std::unique_ptr BuildTargetDescriptor( - electron::NativeWindow* window) { - auto target_data = std::make_unique(); - target_data->SetInteger(kSessionIdField, window->window_id()); - target_data->SetString(kNameField, window->GetTitle()); - target_data->SetString(kTypeField, kBrowser); +base::Value::Dict BuildTargetDescriptor(electron::NativeWindow* window) { + base::Value::Dict target_data; + target_data.Set(kSessionIdField, window->window_id()); + target_data.Set(kNameField, window->GetTitle()); + target_data.Set(kTypeField, kBrowser); return target_data; } @@ -196,7 +195,7 @@ std::string RecursiveDumpAXPlatformNodeAsString( } } str += "\n"; - for (int i = 0; i < node->GetDelegate()->GetChildCount(); i++) { + for (size_t i = 0; i < node->GetDelegate()->GetChildCount(); i++) { gfx::NativeViewAccessible child = node->GetDelegate()->ChildAtIndex(i); const ui::AXPlatformNode* child_node = ui::AXPlatformNode::FromNativeViewAccessible(child); @@ -216,7 +215,7 @@ void HandleAccessibilityRequestCallback( content::WebUIDataSource::GotDataCallback callback) { DCHECK(ShouldHandleAccessibilityRequestCallback(path)); - base::DictionaryValue data; + base::Value::Dict data; ui::AXMode mode = content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode(); bool is_native_enabled = content::BrowserAccessibilityState::GetInstance() @@ -230,17 +229,16 @@ void HandleAccessibilityRequestCallback( // The "native" and "web" flags are disabled if // --disable-renderer-accessibility is set. - data.SetString(kNative, - is_native_enabled ? (native ? kOn : kOff) : kDisabled); - data.SetString(kWeb, is_native_enabled ? (web ? kOn : kOff) : kDisabled); + data.Set(kNative, is_native_enabled ? (native ? kOn : kOff) : kDisabled); + data.Set(kWeb, is_native_enabled ? (web ? kOn : kOff) : kDisabled); // The "text", "screenreader" and "html" flags are only // meaningful if "web" is enabled. bool is_web_enabled = is_native_enabled && web; - data.SetString(kText, is_web_enabled ? (text ? kOn : kOff) : kDisabled); - data.SetString(kScreenReader, - is_web_enabled ? (screenreader ? kOn : kOff) : kDisabled); - data.SetString(kHTML, is_web_enabled ? (html ? kOn : kOff) : kDisabled); + data.Set(kText, is_web_enabled ? (text ? kOn : kOff) : kDisabled); + data.Set(kScreenReader, + is_web_enabled ? (screenreader ? kOn : kOff) : kDisabled); + data.Set(kHTML, is_web_enabled ? (html ? kOn : kOff) : kDisabled); // TODO(codebytere): enable use of this flag. // @@ -249,15 +247,15 @@ void HandleAccessibilityRequestCallback( // command line switch has been used. Since this is so closely tied into user // prefs and causes bugs, we're disabling it for now. bool are_accessibility_image_labels_enabled = is_web_enabled; - data.SetString(kLabelImages, kDisabled); + data.Set(kLabelImages, kDisabled); // The "pdf" flag is independent of the others. - data.SetString(kPDF, pdf ? kOn : kOff); + data.Set(kPDF, pdf ? kOn : kOff); // Always dump the Accessibility tree. - data.SetString(kInternal, kOn); + data.Set(kInternal, kOn); - auto rvh_list = std::make_unique(); + base::Value::List rvh_list; std::unique_ptr widgets( content::RenderWidgetHost::GetRenderWidgetHosts()); @@ -280,26 +278,24 @@ void HandleAccessibilityRequestCallback( if (context != current_context) continue; - std::unique_ptr descriptor = - BuildTargetDescriptor(rvh); - descriptor->SetBoolean(kNative, is_native_enabled); - descriptor->SetBoolean(kWeb, is_web_enabled); - descriptor->SetBoolean(kLabelImages, - are_accessibility_image_labels_enabled); - rvh_list->Append(std::move(descriptor)); + base::Value::Dict descriptor = BuildTargetDescriptor(rvh); + descriptor.Set(kNative, is_native_enabled); + descriptor.Set(kWeb, is_web_enabled); + descriptor.Set(kLabelImages, are_accessibility_image_labels_enabled); + rvh_list.Append(base::Value(std::move(descriptor))); } data.Set(kPagesField, std::move(rvh_list)); - auto window_list = std::make_unique(); + base::Value::List window_list; for (auto* window : electron::WindowList::GetWindows()) { - window_list->Append(BuildTargetDescriptor(window)); + window_list.Append(BuildTargetDescriptor(window)); } data.Set(kBrowsersField, std::move(window_list)); std::string json_string; - base::JSONWriter::Write(data, &json_string); + base::JSONWriter::Write(base::Value(std::move(data)), &json_string); std::move(callback).Run(base::RefCountedString::TakeString(&json_string)); } @@ -336,80 +332,76 @@ ElectronAccessibilityUIMessageHandler::ElectronAccessibilityUIMessageHandler() = default; void ElectronAccessibilityUIMessageHandler::RequestNativeUITree( - const base::ListValue* args) { - const base::DictionaryValue* data; - CHECK(args->GetDictionary(0, &data)); + const base::Value::List& args) { + const base::Value::Dict& data = args.front().GetDict(); - int window_id = *data->FindIntPath(kSessionIdField); - const std::string* request_type_p = data->FindStringPath(kRequestTypeField); + const int window_id = *data.FindInt(kSessionIdField); + const std::string* const request_type_p = data.FindString(kRequestTypeField); CHECK(IsValidJSValue(request_type_p)); std::string request_type = *request_type_p; CHECK(request_type == kShowOrRefreshTree || request_type == kCopyTree); request_type = "accessibility." + request_type; - const std::string* allow_p = data->FindStringPath("filters.allow"); + const std::string* const allow_p = + data.FindStringByDottedPath("filters.allow"); CHECK(IsValidJSValue(allow_p)); - std::string allow = *allow_p; - const std::string* allow_empty_p = data->FindStringPath("filters.allowEmpty"); + const std::string* const allow_empty_p = + data.FindStringByDottedPath("filters.allowEmpty"); CHECK(IsValidJSValue(allow_empty_p)); - std::string allow_empty = *allow_empty_p; - const std::string* deny_p = data->FindStringPath("filters.deny"); + const std::string* const deny_p = data.FindStringByDottedPath("filters.deny"); CHECK(IsValidJSValue(deny_p)); - std::string deny = *deny_p; AllowJavascript(); std::vector property_filters; - AddPropertyFilters(&property_filters, allow, ui::AXPropertyFilter::ALLOW); - AddPropertyFilters(&property_filters, allow_empty, + AddPropertyFilters(&property_filters, *allow_p, ui::AXPropertyFilter::ALLOW); + AddPropertyFilters(&property_filters, *allow_empty_p, ui::AXPropertyFilter::ALLOW_EMPTY); - AddPropertyFilters(&property_filters, deny, ui::AXPropertyFilter::DENY); + AddPropertyFilters(&property_filters, *deny_p, ui::AXPropertyFilter::DENY); for (auto* window : electron::WindowList::GetWindows()) { if (window->window_id() == window_id) { - std::unique_ptr result( - BuildTargetDescriptor(window)); + base::Value::Dict result = BuildTargetDescriptor(window); gfx::NativeWindow native_window = window->GetNativeWindow(); ui::AXPlatformNode* node = ui::AXPlatformNode::FromNativeWindow(native_window); - result->SetKey(kTreeField, - base::Value(RecursiveDumpAXPlatformNodeAsString( - node, 0, property_filters))); - CallJavascriptFunction(request_type, *(result.get())); + result.Set(kTreeField, base::Value(RecursiveDumpAXPlatformNodeAsString( + node, 0, property_filters))); + CallJavascriptFunction(request_type, base::Value(std::move(result))); return; } } // No browser with the specified |id| was found. - auto result = std::make_unique(); - result->SetInteger(kSessionIdField, window_id); - result->SetString(kTypeField, kBrowser); - result->SetString(kErrorField, "Window no longer exists."); - CallJavascriptFunction(request_type, *(result.get())); + base::Value::Dict result; + result.Set(kSessionIdField, window_id); + result.Set(kTypeField, kBrowser); + result.Set(kErrorField, "Window no longer exists."); + CallJavascriptFunction(request_type, base::Value(std::move(result))); } void ElectronAccessibilityUIMessageHandler::RegisterMessages() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( "toggleAccessibility", base::BindRepeating(&AccessibilityUIMessageHandler::ToggleAccessibility, base::Unretained(this))); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( "setGlobalFlag", base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalFlag, base::Unretained(this))); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( "requestWebContentsTree", base::BindRepeating( &AccessibilityUIMessageHandler::RequestWebContentsTree, base::Unretained(this))); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( "requestNativeUITree", base::BindRepeating( &ElectronAccessibilityUIMessageHandler::RequestNativeUITree, base::Unretained(this))); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( "requestAccessibilityEvents", base::BindRepeating( &AccessibilityUIMessageHandler::RequestAccessibilityEvents, diff --git a/shell/browser/ui/webui/accessibility_ui.h b/shell/browser/ui/webui/accessibility_ui.h index 8d8dd02721ea8..a9796934a50e2 100644 --- a/shell/browser/ui/webui/accessibility_ui.h +++ b/shell/browser/ui/webui/accessibility_ui.h @@ -32,7 +32,7 @@ class ElectronAccessibilityUIMessageHandler void RegisterMessages() final; private: - void RequestNativeUITree(const base::ListValue* args); + void RequestNativeUITree(const base::Value::List& args); }; #endif // ELECTRON_SHELL_BROWSER_UI_WEBUI_ACCESSIBILITY_UI_H_ diff --git a/shell/browser/ui/win/dialog_thread.h b/shell/browser/ui/win/dialog_thread.h index 80172d272b4a4..8984d998f3f8b 100644 --- a/shell/browser/ui/win/dialog_thread.h +++ b/shell/browser/ui/win/dialog_thread.h @@ -8,7 +8,7 @@ #include #include "base/memory/scoped_refptr.h" -#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" namespace dialog_thread { @@ -33,8 +33,8 @@ void Run(base::OnceCallback execute, base::OnceCallback done) { [](TaskRunner task_runner, base::OnceCallback execute, base::OnceCallback done) { R r = std::move(execute).Run(); - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( [](TaskRunner task_runner, base::OnceCallback done, R r) { diff --git a/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc b/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc index 03d0846c7f8f5..e8922f8b2c280 100644 --- a/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc +++ b/shell/browser/ui/win/electron_desktop_window_tree_host_win.cc @@ -7,13 +7,10 @@ #include "base/win/windows_version.h" #include "electron/buildflags/buildflags.h" #include "shell/browser/ui/views/win_frame_view.h" +#include "shell/browser/win/dark_mode.h" #include "ui/base/win/hwnd_metrics.h" #include "ui/base/win/shell.h" -#if BUILDFLAG(ENABLE_WIN_DARK_MODE_WINDOW_UI) -#include "shell/browser/win/dark_mode.h" -#endif - namespace electron { ElectronDesktopWindowTreeHostWin::ElectronDesktopWindowTreeHostWin( @@ -29,14 +26,13 @@ bool ElectronDesktopWindowTreeHostWin::PreHandleMSG(UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) { -#if BUILDFLAG(ENABLE_WIN_DARK_MODE_WINDOW_UI) - if (message == WM_NCCREATE) { - HWND const hwnd = GetAcceleratedWidget(); - auto const theme_source = - ui::NativeTheme::GetInstanceForNativeUi()->theme_source(); - win::SetDarkModeForWindow(hwnd, theme_source); + const bool dark_mode_supported = win::IsDarkModeSupported(); + if (dark_mode_supported && message == WM_NCCREATE) { + win::SetDarkModeForWindow(GetAcceleratedWidget()); + ui::NativeTheme::GetInstanceForNativeUi()->AddObserver(this); + } else if (dark_mode_supported && message == WM_DESTROY) { + ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this); } -#endif return native_window_view_->PreHandleMSG(message, w_param, l_param, result); } @@ -80,23 +76,49 @@ bool ElectronDesktopWindowTreeHostWin::GetDwmFrameInsetsInPixels( bool ElectronDesktopWindowTreeHostWin::GetClientAreaInsets( gfx::Insets* insets, HMONITOR monitor) const { - // Windows by deafult extends the maximized window slightly larger than + // Windows by default extends the maximized window slightly larger than // current workspace, for frameless window since the standard frame has been // removed, the client area would then be drew outside current workspace. // // Indenting the client area can fix this behavior. if (IsMaximized() && !native_window_view_->has_frame()) { // The insets would be eventually passed to WM_NCCALCSIZE, which takes - // the metrics under the DPI of _main_ monitor instead of current moniotr. + // the metrics under the DPI of _main_ monitor instead of current monitor. // // Please make sure you tested maximized frameless window under multiple // monitors with different DPIs before changing this code. const int thickness = ::GetSystemMetrics(SM_CXSIZEFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER); - insets->Set(thickness, thickness, thickness, thickness); + *insets = gfx::Insets::TLBR(thickness, thickness, thickness, thickness); return true; } return false; } +bool ElectronDesktopWindowTreeHostWin::HandleMouseEventForCaption( + UINT message) const { + // Windows does not seem to generate WM_NCPOINTERDOWN/UP touch events for + // caption buttons with WCO. This results in a no-op for + // HWNDMessageHandler::HandlePointerEventTypeTouchOrNonClient and + // WM_SYSCOMMAND is not generated for the touch action. However, Windows will + // also generate a mouse event for every touch action and this gets handled in + // HWNDMessageHandler::HandleMouseEventInternal. + // With https://chromium-review.googlesource.com/c/chromium/src/+/1048877/ + // Chromium lets the OS handle caption buttons for FrameMode::SYSTEM_DRAWN but + // again this does not generate the SC_MINIMIZE, SC_MAXIMIZE, SC_RESTORE + // commands when Non-client mouse events are generated for HTCLOSE, + // HTMINBUTTON, HTMAXBUTTON. To workaround this issue, wit this delegate we + // let chromium handle the mouse events via + // HWNDMessageHandler::HandleMouseInputForCaption instead of the OS and this + // will generate the necessary system commands to perform caption button + // actions due to the DefWindowProc call. + // https://source.chromium.org/chromium/chromium/src/+/main:ui/views/win/hwnd_message_handler.cc;l=3611 + return native_window_view_->IsWindowControlsOverlayEnabled(); +} + +void ElectronDesktopWindowTreeHostWin::OnNativeThemeUpdated( + ui::NativeTheme* observed_theme) { + win::SetDarkModeForWindow(GetAcceleratedWidget()); +} + } // namespace electron diff --git a/shell/browser/ui/win/electron_desktop_window_tree_host_win.h b/shell/browser/ui/win/electron_desktop_window_tree_host_win.h index 3fd831aae1ed0..2f63f34f63b63 100644 --- a/shell/browser/ui/win/electron_desktop_window_tree_host_win.h +++ b/shell/browser/ui/win/electron_desktop_window_tree_host_win.h @@ -12,8 +12,8 @@ namespace electron { -class ElectronDesktopWindowTreeHostWin - : public views::DesktopWindowTreeHostWin { +class ElectronDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin, + public ::ui::NativeThemeObserver { public: ElectronDesktopWindowTreeHostWin( NativeWindowViews* native_window_view, @@ -36,6 +36,10 @@ class ElectronDesktopWindowTreeHostWin bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override; bool GetClientAreaInsets(gfx::Insets* insets, HMONITOR monitor) const override; + bool HandleMouseEventForCaption(UINT message) const override; + + // ui::NativeThemeObserver: + void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override; private: NativeWindowViews* native_window_view_; // weak ref diff --git a/shell/browser/ui/win/jump_list.cc b/shell/browser/ui/win/jump_list.cc index eb985984a7b36..12311f6377d1e 100644 --- a/shell/browser/ui/win/jump_list.cc +++ b/shell/browser/ui/win/jump_list.cc @@ -93,7 +93,7 @@ bool ConvertShellLinkToJumpListItem(IShellLink* shell_link, item->type = JumpListItem::Type::kTask; wchar_t path[MAX_PATH]; - if (FAILED(shell_link->GetPath(path, base::size(path), nullptr, 0))) + if (FAILED(shell_link->GetPath(path, std::size(path), nullptr, 0))) return false; item->path = base::FilePath(path); @@ -111,18 +111,18 @@ bool ConvertShellLinkToJumpListItem(IShellLink* shell_link, item->title = prop.get().pwszVal; } - if (SUCCEEDED(shell_link->GetWorkingDirectory(path, base::size(path)))) + if (SUCCEEDED(shell_link->GetWorkingDirectory(path, std::size(path)))) item->working_dir = base::FilePath(path); int icon_index; if (SUCCEEDED( - shell_link->GetIconLocation(path, base::size(path), &icon_index))) { + shell_link->GetIconLocation(path, std::size(path), &icon_index))) { item->icon_path = base::FilePath(path); item->icon_index = icon_index; } wchar_t item_desc[INFOTIPSIZE]; - if (SUCCEEDED(shell_link->GetDescription(item_desc, base::size(item_desc)))) + if (SUCCEEDED(shell_link->GetDescription(item_desc, std::size(item_desc)))) item->description = item_desc; return true; diff --git a/shell/browser/web_contents_permission_helper.cc b/shell/browser/web_contents_permission_helper.cc index 2fd8cb0a6c699..31d32cf53ddb4 100644 --- a/shell/browser/web_contents_permission_helper.cc +++ b/shell/browser/web_contents_permission_helper.cc @@ -12,7 +12,10 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents_user_data.h" #include "shell/browser/electron_permission_manager.h" -#include "shell/browser/media/media_stream_devices_controller.h" +// #include "shell/browser/media/media_stream_devices_controller.h" +#include "components/content_settings/core/common/content_settings.h" +#include "components/webrtc/media_stream_devices_controller.h" +#include "shell/browser/media/media_capture_devices_dispatcher.h" namespace { @@ -33,14 +36,99 @@ namespace electron { namespace { +// Handles requests for legacy-style `navigator.getUserMedia(...)` calls. +// This includes desktop capture through the chromeMediaSource / +// chromeMediaSourceId constraints. +void HandleUserMediaRequest(const content::MediaStreamRequest& request, + content::MediaResponseCallback callback) { + blink::mojom::StreamDevicesSetPtr stream_devices_set = + blink::mojom::StreamDevicesSet::New(); + stream_devices_set->stream_devices.emplace_back( + blink::mojom::StreamDevices::New()); + blink::mojom::StreamDevices& devices = *stream_devices_set->stream_devices[0]; + + if (request.audio_type == + blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE) { + devices.audio_device = blink::MediaStreamDevice( + blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE, "", ""); + } + if (request.video_type == + blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE) { + devices.video_device = blink::MediaStreamDevice( + blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE, "", ""); + } + if (request.audio_type == + blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE) { + devices.audio_device = blink::MediaStreamDevice( + blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE, "loopback", + "System Audio"); + } + if (request.video_type == + blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) { + content::DesktopMediaID screen_id; + // If the device id wasn't specified then this is a screen capture request + // (i.e. chooseDesktopMedia() API wasn't used to generate device id). + if (request.requested_video_device_id.empty()) { + screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, + -1 /* kFullDesktopScreenId */); + } else { + screen_id = + content::DesktopMediaID::Parse(request.requested_video_device_id); + } + + devices.video_device = blink::MediaStreamDevice( + blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE, + screen_id.ToString(), "Screen"); + } + + bool empty = + !devices.audio_device.has_value() && !devices.video_device.has_value(); + std::move(callback).Run( + *stream_devices_set, + empty ? blink::mojom::MediaStreamRequestResult::NO_HARDWARE + : blink::mojom::MediaStreamRequestResult::OK, + nullptr); +} + +void OnMediaStreamRequestResponse( + content::MediaResponseCallback callback, + const blink::mojom::StreamDevicesSet& stream_devices_set, + blink::mojom::MediaStreamRequestResult result, + bool blocked_by_permissions_policy, + ContentSetting audio_setting, + ContentSetting video_setting) { + std::move(callback).Run(stream_devices_set, result, nullptr); +} + void MediaAccessAllowed(const content::MediaStreamRequest& request, content::MediaResponseCallback callback, bool allowed) { - MediaStreamDevicesController controller(request, std::move(callback)); - if (allowed) - controller.TakeAction(); - else - controller.Deny(blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED); + if (allowed) { + if (request.video_type == + blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE || + request.audio_type == + blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE || + request.video_type == + blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE || + request.audio_type == + blink::mojom::MediaStreamType::GUM_TAB_AUDIO_CAPTURE) + HandleUserMediaRequest(request, std::move(callback)); + else if (request.video_type == + blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE || + request.audio_type == + blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) + webrtc::MediaStreamDevicesController::RequestPermissions( + request, MediaCaptureDevicesDispatcher::GetInstance(), + base::BindOnce(&OnMediaStreamRequestResponse, std::move(callback))); + else + std::move(callback).Run( + blink::mojom::StreamDevicesSet(), + blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr); + } else { + std::move(callback).Run( + blink::mojom::StreamDevicesSet(), + blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr); + } } void OnPermissionResponse(base::OnceCallback callback, @@ -61,56 +149,36 @@ WebContentsPermissionHelper::WebContentsPermissionHelper( WebContentsPermissionHelper::~WebContentsPermissionHelper() = default; void WebContentsPermissionHelper::RequestPermission( - content::PermissionType permission, + content::RenderFrameHost* requesting_frame, + blink::PermissionType permission, base::OnceCallback callback, bool user_gesture, - const base::DictionaryValue* details) { - auto* rfh = web_contents_->GetMainFrame(); + base::Value::Dict details) { auto* permission_manager = static_cast( web_contents_->GetBrowserContext()->GetPermissionControllerDelegate()); auto origin = web_contents_->GetLastCommittedURL(); permission_manager->RequestPermissionWithDetails( - permission, rfh, origin, false, details, + permission, requesting_frame, origin, false, std::move(details), base::BindOnce(&OnPermissionResponse, std::move(callback))); } bool WebContentsPermissionHelper::CheckPermission( - content::PermissionType permission, - const base::DictionaryValue* details) const { - auto* rfh = web_contents_->GetMainFrame(); + blink::PermissionType permission, + base::Value::Dict details) const { + auto* rfh = web_contents_->GetPrimaryMainFrame(); auto* permission_manager = static_cast( web_contents_->GetBrowserContext()->GetPermissionControllerDelegate()); auto origin = web_contents_->GetLastCommittedURL(); return permission_manager->CheckPermissionWithDetails(permission, rfh, origin, - details); -} - -bool WebContentsPermissionHelper::CheckDevicePermission( - content::PermissionType permission, - const url::Origin& origin, - const base::Value* device, - content::RenderFrameHost* render_frame_host) const { - auto* permission_manager = static_cast( - web_contents_->GetBrowserContext()->GetPermissionControllerDelegate()); - return permission_manager->CheckDevicePermission(permission, origin, device, - render_frame_host); -} - -void WebContentsPermissionHelper::GrantDevicePermission( - content::PermissionType permission, - const url::Origin& origin, - const base::Value* device, - content::RenderFrameHost* render_frame_host) const { - auto* permission_manager = static_cast( - web_contents_->GetBrowserContext()->GetPermissionControllerDelegate()); - permission_manager->GrantDevicePermission(permission, origin, device, - render_frame_host); + std::move(details)); } void WebContentsPermissionHelper::RequestFullscreenPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback) { RequestPermission( - static_cast(PermissionType::FULLSCREEN), + requesting_frame, + static_cast(PermissionType::FULLSCREEN), std::move(callback)); } @@ -120,28 +188,31 @@ void WebContentsPermissionHelper::RequestMediaAccessPermission( auto callback = base::BindOnce(&MediaAccessAllowed, request, std::move(response_callback)); - base::DictionaryValue details; - auto media_types = std::make_unique(); + base::Value::Dict details; + base::Value::List media_types; if (request.audio_type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) { - media_types->Append("audio"); + media_types.Append("audio"); } if (request.video_type == blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) { - media_types->Append("video"); + media_types.Append("video"); } - details.SetList("mediaTypes", std::move(media_types)); - details.SetString("securityOrigin", request.security_origin.spec()); + details.Set("mediaTypes", std::move(media_types)); + details.Set("securityOrigin", request.security_origin.spec()); // The permission type doesn't matter here, AUDIO_CAPTURE/VIDEO_CAPTURE // are presented as same type in content_converter.h. - RequestPermission(content::PermissionType::AUDIO_CAPTURE, std::move(callback), - false, &details); + RequestPermission(content::RenderFrameHost::FromID(request.render_process_id, + request.render_frame_id), + blink::PermissionType::AUDIO_CAPTURE, std::move(callback), + false, std::move(details)); } void WebContentsPermissionHelper::RequestWebNotificationPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback) { - RequestPermission(content::PermissionType::NOTIFICATIONS, + RequestPermission(requesting_frame, blink::PermissionType::NOTIFICATIONS, std::move(callback)); } @@ -151,84 +222,45 @@ void WebContentsPermissionHelper::RequestPointerLockPermission( base::OnceCallback callback) { RequestPermission( - static_cast(PermissionType::POINTER_LOCK), + web_contents_->GetPrimaryMainFrame(), + static_cast(PermissionType::POINTER_LOCK), base::BindOnce(std::move(callback), web_contents_, user_gesture, last_unlocked_by_target), user_gesture); } void WebContentsPermissionHelper::RequestOpenExternalPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback, bool user_gesture, const GURL& url) { - base::DictionaryValue details; - details.SetString("externalURL", url.spec()); + base::Value::Dict details; + details.Set("externalURL", url.spec()); RequestPermission( - static_cast(PermissionType::OPEN_EXTERNAL), - std::move(callback), user_gesture, &details); + requesting_frame, + static_cast(PermissionType::OPEN_EXTERNAL), + std::move(callback), user_gesture, std::move(details)); } bool WebContentsPermissionHelper::CheckMediaAccessPermission( const GURL& security_origin, blink::mojom::MediaStreamType type) const { - base::DictionaryValue details; - details.SetString("securityOrigin", security_origin.spec()); - details.SetString("mediaType", MediaStreamTypeToString(type)); + base::Value::Dict details; + details.Set("securityOrigin", security_origin.spec()); + details.Set("mediaType", MediaStreamTypeToString(type)); // The permission type doesn't matter here, AUDIO_CAPTURE/VIDEO_CAPTURE // are presented as same type in content_converter.h. - return CheckPermission(content::PermissionType::AUDIO_CAPTURE, &details); + return CheckPermission(blink::PermissionType::AUDIO_CAPTURE, + std::move(details)); } bool WebContentsPermissionHelper::CheckSerialAccessPermission( const url::Origin& embedding_origin) const { - base::DictionaryValue details; - details.SetString("securityOrigin", embedding_origin.GetURL().spec()); - return CheckPermission( - static_cast(PermissionType::SERIAL), &details); -} - -bool WebContentsPermissionHelper::CheckSerialPortPermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const { - return CheckDevicePermission( - static_cast(PermissionType::SERIAL), origin, - &device, render_frame_host); -} - -void WebContentsPermissionHelper::GrantSerialPortPermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const { - return GrantDevicePermission( - static_cast(PermissionType::SERIAL), origin, - &device, render_frame_host); -} - -bool WebContentsPermissionHelper::CheckHIDAccessPermission( - const url::Origin& embedding_origin) const { - base::DictionaryValue details; - details.SetString("securityOrigin", embedding_origin.GetURL().spec()); + base::Value::Dict details; + details.Set("securityOrigin", embedding_origin.GetURL().spec()); return CheckPermission( - static_cast(PermissionType::HID), &details); -} - -bool WebContentsPermissionHelper::CheckHIDDevicePermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const { - return CheckDevicePermission( - static_cast(PermissionType::HID), origin, - &device, render_frame_host); -} - -void WebContentsPermissionHelper::GrantHIDDevicePermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const { - return GrantDevicePermission( - static_cast(PermissionType::HID), origin, - &device, render_frame_host); + static_cast(PermissionType::SERIAL), + std::move(details)); } WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsPermissionHelper); diff --git a/shell/browser/web_contents_permission_helper.h b/shell/browser/web_contents_permission_helper.h index 639dcd8a8829a..43a5ca63ec307 100644 --- a/shell/browser/web_contents_permission_helper.h +++ b/shell/browser/web_contents_permission_helper.h @@ -7,9 +7,9 @@ #include "base/values.h" #include "content/public/browser/media_stream_request.h" -#include "content/public/browser/permission_type.h" #include "content/public/browser/web_contents_user_data.h" #include "third_party/blink/public/common/mediastream/media_stream_request.h" +#include "third_party/blink/public/common/permissions/permission_utils.h" namespace electron { @@ -25,7 +25,7 @@ class WebContentsPermissionHelper delete; enum class PermissionType { - POINTER_LOCK = static_cast(content::PermissionType::NUM) + 1, + POINTER_LOCK = static_cast(blink::PermissionType::NUM) + 1, FULLSCREEN, OPEN_EXTERNAL, SERIAL, @@ -33,7 +33,8 @@ class WebContentsPermissionHelper }; // Asynchronous Requests - void RequestFullscreenPermission(base::OnceCallback callback); + void RequestFullscreenPermission(content::RenderFrameHost* requesting_frame, + base::OnceCallback callback); void RequestMediaAccessPermission(const content::MediaStreamRequest& request, content::MediaResponseCallback callback); void RequestPointerLockPermission( @@ -42,8 +43,10 @@ class WebContentsPermissionHelper base::OnceCallback callback); void RequestWebNotificationPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback); - void RequestOpenExternalPermission(base::OnceCallback callback, + void RequestOpenExternalPermission(content::RenderFrameHost* requesting_frame, + base::OnceCallback callback, bool user_gesture, const GURL& url); @@ -51,45 +54,19 @@ class WebContentsPermissionHelper bool CheckMediaAccessPermission(const GURL& security_origin, blink::mojom::MediaStreamType type) const; bool CheckSerialAccessPermission(const url::Origin& embedding_origin) const; - bool CheckSerialPortPermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const; - void GrantSerialPortPermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const; - bool CheckHIDAccessPermission(const url::Origin& embedding_origin) const; - bool CheckHIDDevicePermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const; - void GrantHIDDevicePermission( - const url::Origin& origin, - base::Value device, - content::RenderFrameHost* render_frame_host) const; private: explicit WebContentsPermissionHelper(content::WebContents* web_contents); friend class content::WebContentsUserData; - void RequestPermission(content::PermissionType permission, + void RequestPermission(content::RenderFrameHost* requesting_frame, + blink::PermissionType permission, base::OnceCallback callback, bool user_gesture = false, - const base::DictionaryValue* details = nullptr); + base::Value::Dict details = {}); - bool CheckPermission(content::PermissionType permission, - const base::DictionaryValue* details) const; - - bool CheckDevicePermission(content::PermissionType permission, - const url::Origin& origin, - const base::Value* device, - content::RenderFrameHost* render_frame_host) const; - - void GrantDevicePermission(content::PermissionType permission, - const url::Origin& origin, - const base::Value* device, - content::RenderFrameHost* render_frame_host) const; + bool CheckPermission(blink::PermissionType permission, + base::Value::Dict details) const; // TODO(clavin): refactor to use the WebContents provided by the // WebContentsUserData base class instead of storing a duplicate ref diff --git a/shell/browser/web_contents_preferences.cc b/shell/browser/web_contents_preferences.cc index 642b83675170a..14069bfdde30e 100644 --- a/shell/browser/web_contents_preferences.cc +++ b/shell/browser/web_contents_preferences.cc @@ -176,11 +176,7 @@ void WebContentsPreferences::Clear() { void WebContentsPreferences::SetFromDictionary( const gin_helper::Dictionary& web_preferences) { Clear(); - Merge(web_preferences); -} -void WebContentsPreferences::Merge( - const gin_helper::Dictionary& web_preferences) { web_preferences.Get(options::kPlugins, &plugins_); web_preferences.Get(options::kExperimentalFeatures, &experimental_features_); web_preferences.Get(options::kNodeIntegration, &node_integration_); @@ -258,15 +254,6 @@ void WebContentsPreferences::Merge( } else { LOG(ERROR) << "preload script must have absolute path."; } - } else if (web_preferences.Get(options::kPreloadURL, &preload_url_str)) { - // Translate to file path if there is "preload-url" option. - base::FilePath preload; - GURL preload_url(preload_url_str); - if (net::FileURLToFilePath(preload_url, &preload)) { - preload_path_ = preload; - } else { - LOG(ERROR) << "preload url must be file:// protocol."; - } } std::string type; @@ -325,9 +312,7 @@ bool WebContentsPreferences::IsSandboxed() const { if (sandbox_) return *sandbox_; bool sandbox_disabled_by_default = - node_integration_ || node_integration_in_worker_ || preload_path_ || - !SessionPreferences::GetValidPreloads(web_contents_->GetBrowserContext()) - .empty(); + node_integration_ || node_integration_in_worker_; return !sandbox_disabled_by_default; } @@ -336,7 +321,8 @@ content::WebContents* WebContentsPreferences::GetWebContentsFromProcessID( int process_id) { for (WebContentsPreferences* preferences : Instances()) { content::WebContents* web_contents = preferences->web_contents_; - if (web_contents->GetMainFrame()->GetProcess()->GetID() == process_id) + if (web_contents->GetPrimaryMainFrame()->GetProcess()->GetID() == + process_id) return web_contents; } return nullptr; @@ -397,7 +383,7 @@ void WebContentsPreferences::AppendCommandLineSwitches( // We are appending args to a webContents so let's save the current state // of our preferences object so that during the lifetime of the WebContents - // we can fetch the options used to initally configure the WebContents + // we can fetch the options used to initially configure the WebContents // last_preference_ = preference_.Clone(); SaveLastPreferences(); } @@ -495,10 +481,6 @@ void WebContentsPreferences::OverrideWebkitPrefs( prefs->offscreen = offscreen_; - // The preload script. - if (preload_path_) - prefs->preload = *preload_path_; - prefs->node_integration = node_integration_; prefs->node_integration_in_worker = node_integration_in_worker_; prefs->node_integration_in_sub_frames = node_integration_in_sub_frames_; diff --git a/shell/browser/web_contents_preferences.h b/shell/browser/web_contents_preferences.h index 544bc54a80e46..eac4f7e51eeb7 100644 --- a/shell/browser/web_contents_preferences.h +++ b/shell/browser/web_contents_preferences.h @@ -40,11 +40,9 @@ class WebContentsPreferences WebContentsPreferences(const WebContentsPreferences&) = delete; WebContentsPreferences& operator=(const WebContentsPreferences&) = delete; - void Merge(const gin_helper::Dictionary& new_web_preferences); - void SetFromDictionary(const gin_helper::Dictionary& new_web_preferences); - // Append command paramters according to preferences. + // Append command parameters according to preferences. void AppendCommandLineSwitches(base::CommandLine* command_line, bool is_subframe); diff --git a/shell/browser/web_contents_zoom_controller.cc b/shell/browser/web_contents_zoom_controller.cc index 0cf515f05729a..da377b5c20499 100644 --- a/shell/browser/web_contents_zoom_controller.cc +++ b/shell/browser/web_contents_zoom_controller.cc @@ -46,7 +46,7 @@ void WebContentsZoomController::SetEmbedderZoomController( } void WebContentsZoomController::SetZoomLevel(double level) { - if (!web_contents()->GetRenderViewHost()->IsRenderViewLive() || + if (!web_contents()->GetPrimaryMainFrame()->IsRenderFrameLive() || blink::PageZoomValuesEqual(GetZoomLevel(), level) || zoom_mode_ == ZoomMode::kDisabled) return; diff --git a/shell/browser/web_view_guest_delegate.cc b/shell/browser/web_view_guest_delegate.cc index 8f8b24082b83a..465e25e5e554a 100644 --- a/shell/browser/web_view_guest_delegate.cc +++ b/shell/browser/web_view_guest_delegate.cc @@ -32,7 +32,7 @@ void WebViewGuestDelegate::AttachToIframe( embedder_web_contents_ = embedder_web_contents; int embedder_process_id = - embedder_web_contents_->GetMainFrame()->GetProcess()->GetID(); + embedder_web_contents_->GetPrimaryMainFrame()->GetProcess()->GetID(); auto* embedder_frame = content::RenderFrameHost::FromID(embedder_process_id, embedder_frame_id); DCHECK_EQ(embedder_web_contents_, @@ -49,7 +49,10 @@ void WebViewGuestDelegate::AttachToIframe( // frame |embedder_frame| hosts the inner WebContents. embedder_web_contents_->AttachInnerWebContents( base::WrapUnique(guest_web_contents), - embedder_frame, false); + embedder_frame, + /*remote_frame=*/mojo::NullAssociatedRemote(), + /*remote_frame_host_receiver=*/mojo::NullAssociatedReceiver(), + /*is_full_page=*/false); ResetZoomController(); diff --git a/shell/browser/win/dark_mode.cc b/shell/browser/win/dark_mode.cc index c85bf18786c20..559c572ddac62 100644 --- a/shell/browser/win/dark_mode.cc +++ b/shell/browser/win/dark_mode.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Microsoft Inc. All rights reserved. +// Copyright (c) 2022 Microsoft Inc. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-CHROMIUM file. @@ -6,175 +6,55 @@ #include // DwmSetWindowAttribute() -#include "base/files/file_path.h" -#include "base/scoped_native_library.h" -#include "base/win/pe_image.h" -#include "base/win/win_util.h" #include "base/win/windows_version.h" +// This flag works since Win10 20H1 but is not documented until Windows 11 +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 + // This namespace contains code originally from -// https://github.com/ysc3839/win32-darkmode/ -// governed by the MIT license and (c) Richard Yu +// https://github.com/microsoft/terminal +// governed by the MIT license and (c) Microsoft Corporation. namespace { -// 1903 18362 -enum PreferredAppMode { Default, AllowDark, ForceDark, ForceLight, Max }; - -bool g_darkModeSupported = false; -bool g_darkModeEnabled = false; -DWORD g_buildNumber = 0; - -enum WINDOWCOMPOSITIONATTRIB { - WCA_USEDARKMODECOLORS = 26 // build 18875+ -}; -struct WINDOWCOMPOSITIONATTRIBDATA { - WINDOWCOMPOSITIONATTRIB Attrib; - PVOID pvData; - SIZE_T cbData; -}; - -using fnSetWindowCompositionAttribute = - BOOL(WINAPI*)(HWND hWnd, WINDOWCOMPOSITIONATTRIBDATA*); -fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = nullptr; - -bool IsHighContrast() { - HIGHCONTRASTW highContrast = {sizeof(highContrast)}; - if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), - &highContrast, FALSE)) - return highContrast.dwFlags & HCF_HIGHCONTRASTON; - return false; -} +// https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +HRESULT TrySetWindowTheme(HWND hWnd, bool dark) { + const BOOL isDarkMode = dark; + HRESULT result = DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, + &isDarkMode, sizeof(isDarkMode)); -void RefreshTitleBarThemeColor(HWND hWnd, bool dark) { - LONG ldark = dark; - if (g_buildNumber >= 20161) { - // DWMA_USE_IMMERSIVE_DARK_MODE = 20 - DwmSetWindowAttribute(hWnd, 20, &ldark, sizeof dark); - return; - } - if (g_buildNumber >= 18363) { - auto data = WINDOWCOMPOSITIONATTRIBDATA{WCA_USEDARKMODECOLORS, &ldark, - sizeof ldark}; - _SetWindowCompositionAttribute(hWnd, &data); - return; - } - DwmSetWindowAttribute(hWnd, 0x13, &ldark, sizeof ldark); -} + if (FAILED(result)) + return result; -void InitDarkMode() { - // confirm that we're running on a version of Windows - // where the Dark Mode API is known auto* os_info = base::win::OSInfo::GetInstance(); - g_buildNumber = os_info->version_number().build; auto const version = os_info->version(); - if ((version < base::win::Version::WIN10_RS5) || - (version > base::win::Version::WIN10_20H1)) { - return; - } - // load "SetWindowCompositionAttribute", used in RefreshTitleBarThemeColor() - _SetWindowCompositionAttribute = - reinterpret_cast( - base::win::GetUser32FunctionPointer("SetWindowCompositionAttribute")); - if (_SetWindowCompositionAttribute == nullptr) { - return; + // Toggle the nonclient area active state to force a redraw (Win10 workaround) + if (version < base::win::Version::WIN11) { + HWND activeWindow = GetActiveWindow(); + SendMessage(hWnd, WM_NCACTIVATE, hWnd != activeWindow, 0); + SendMessage(hWnd, WM_NCACTIVATE, hWnd == activeWindow, 0); } - // load the dark mode functions from uxtheme.dll - // * RefreshImmersiveColorPolicyState() - // * ShouldAppsUseDarkMode() - // * AllowDarkModeForApp() - // * SetPreferredAppMode() - // * AllowDarkModeForApp() (build < 18362) - // * SetPreferredAppMode() (build >= 18362) - - base::NativeLibrary uxtheme = - base::PinSystemLibrary(FILE_PATH_LITERAL("uxtheme.dll")); - if (!uxtheme) { - return; - } - auto ux_pei = base::win::PEImage(uxtheme); - auto get_ux_proc_from_ordinal = [&ux_pei](int ordinal, auto* setme) { - FARPROC proc = ux_pei.GetProcAddress(reinterpret_cast(ordinal)); - *setme = reinterpret_cast(proc); - }; - - // ordinal 104 - using fnRefreshImmersiveColorPolicyState = VOID(WINAPI*)(); - fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = {}; - get_ux_proc_from_ordinal(104, &_RefreshImmersiveColorPolicyState); - - // ordinal 132 - using fnShouldAppsUseDarkMode = BOOL(WINAPI*)(); - fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = {}; - get_ux_proc_from_ordinal(132, &_ShouldAppsUseDarkMode); - - // ordinal 135, in 1809 - using fnAllowDarkModeForApp = BOOL(WINAPI*)(BOOL allow); - fnAllowDarkModeForApp _AllowDarkModeForApp = {}; - - // ordinal 135, in 1903 - typedef PreferredAppMode(WINAPI * - fnSetPreferredAppMode)(PreferredAppMode appMode); - fnSetPreferredAppMode _SetPreferredAppMode = {}; - - if (g_buildNumber < 18362) { - get_ux_proc_from_ordinal(135, &_AllowDarkModeForApp); - } else { - get_ux_proc_from_ordinal(135, &_SetPreferredAppMode); - } - - // dark mode is supported iff we found the functions - g_darkModeSupported = _RefreshImmersiveColorPolicyState && - _ShouldAppsUseDarkMode && - (_AllowDarkModeForApp || _SetPreferredAppMode); - if (!g_darkModeSupported) { - return; - } - - // initial setup: allow dark mode to be used - if (_AllowDarkModeForApp) { - _AllowDarkModeForApp(true); - } else if (_SetPreferredAppMode) { - _SetPreferredAppMode(AllowDark); - } - _RefreshImmersiveColorPolicyState(); - - // check to see if dark mode is currently enabled - g_darkModeEnabled = _ShouldAppsUseDarkMode() && !IsHighContrast(); + return S_OK; } } // namespace -namespace electron { +namespace electron::win { -void EnsureInitialized() { - static bool initialized = false; - if (!initialized) { - initialized = true; - ::InitDarkMode(); - } -} +bool IsDarkModeSupported() { + auto* os_info = base::win::OSInfo::GetInstance(); + auto const version = os_info->version(); -bool IsDarkPreferred(ui::NativeTheme::ThemeSource theme_source) { - switch (theme_source) { - case ui::NativeTheme::ThemeSource::kForcedLight: - return false; - case ui::NativeTheme::ThemeSource::kForcedDark: - return g_darkModeSupported; - case ui::NativeTheme::ThemeSource::kSystem: - return g_darkModeEnabled; - } + return version >= base::win::Version::WIN10_20H1; } -namespace win { +void SetDarkModeForWindow(HWND hWnd) { + ui::NativeTheme* theme = ui::NativeTheme::GetInstanceForNativeUi(); + bool dark = + theme->ShouldUseDarkColors() && !theme->UserHasContrastPreference(); -void SetDarkModeForWindow(HWND hWnd, - ui::NativeTheme::ThemeSource theme_source) { - EnsureInitialized(); - RefreshTitleBarThemeColor(hWnd, IsDarkPreferred(theme_source)); + TrySetWindowTheme(hWnd, dark); } -} // namespace win - -} // namespace electron +} // namespace electron::win diff --git a/shell/browser/win/dark_mode.h b/shell/browser/win/dark_mode.h index c6d14f9bfa7e7..8bd34a39e01fa 100644 --- a/shell/browser/win/dark_mode.h +++ b/shell/browser/win/dark_mode.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Microsoft Inc. All rights reserved. +// Copyright (c) 2022 Microsoft Inc. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-CHROMIUM file. @@ -15,14 +15,11 @@ #include "ui/native_theme/native_theme.h" -namespace electron { +namespace electron::win { -namespace win { +bool IsDarkModeSupported(); +void SetDarkModeForWindow(HWND hWnd); -void SetDarkModeForWindow(HWND hWnd, ui::NativeTheme::ThemeSource theme_source); - -} // namespace win - -} // namespace electron +} // namespace electron::win #endif // ELECTRON_SHELL_BROWSER_WIN_DARK_MODE_H_ diff --git a/shell/browser/zoom_level_delegate.cc b/shell/browser/zoom_level_delegate.cc index bbe8ce0daee38..a49cd01af0abf 100644 --- a/shell/browser/zoom_level_delegate.cc +++ b/shell/browser/zoom_level_delegate.cc @@ -6,12 +6,12 @@ #include #include +#include #include #include "base/bind.h" #include "base/files/file_path.h" #include "base/strings/string_number_conversions.h" -#include "base/values.h" #include "components/prefs/json_pref_store.h" #include "components/prefs/pref_filter.h" #include "components/prefs/pref_registry_simple.h" @@ -63,18 +63,11 @@ void ZoomLevelDelegate::SetDefaultZoomLevelPref(double level) { } double ZoomLevelDelegate::GetDefaultZoomLevelPref() const { - double default_zoom_level = 0.0; - - const base::Value* default_zoom_level_dictionary = - pref_service_->GetDictionary(kPartitionDefaultZoomLevel); + const base::Value::Dict& default_zoom_level_dictionary = + pref_service_->GetValueDict(kPartitionDefaultZoomLevel); // If no default has been previously set, the default returned is the // value used to initialize default_zoom_level in this function. - absl::optional maybe_default_zoom_level = - default_zoom_level_dictionary->FindDoubleKey(partition_key_); - if (maybe_default_zoom_level.has_value()) - default_zoom_level = maybe_default_zoom_level.value(); - - return default_zoom_level; + return default_zoom_level_dictionary.FindDouble(partition_key_).value_or(0.0); } void ZoomLevelDelegate::OnZoomLevelChanged( @@ -84,35 +77,33 @@ void ZoomLevelDelegate::OnZoomLevelChanged( double level = change.zoom_level; DictionaryPrefUpdate update(pref_service_, kPartitionPerHostZoomLevels); - base::Value* host_zoom_dictionaries = update.Get(); - DCHECK(host_zoom_dictionaries); + base::Value* host_zoom_update = update.Get(); + DCHECK(host_zoom_update); + base::Value::Dict& host_zoom_dictionaries = host_zoom_update->GetDict(); bool modification_is_removal = blink::PageZoomValuesEqual(level, host_zoom_map_->GetDefaultZoomLevel()); - base::Value* host_zoom_dictionary = - host_zoom_dictionaries->FindDictKey(partition_key_); + base::Value::Dict* host_zoom_dictionary = + host_zoom_dictionaries.FindDict(partition_key_); if (!host_zoom_dictionary) { - host_zoom_dictionaries->SetKey(partition_key_, - base::Value(base::Value::Type::DICTIONARY)); - host_zoom_dictionary = host_zoom_dictionaries->FindDictKey(partition_key_); + base::Value::Dict dict; + host_zoom_dictionaries.Set(partition_key_, std::move(dict)); + host_zoom_dictionary = host_zoom_dictionaries.FindDict(partition_key_); } if (modification_is_removal) - host_zoom_dictionary->RemoveKey(change.host); + host_zoom_dictionary->Remove(change.host); else - host_zoom_dictionary->SetKey(change.host, base::Value(level)); + host_zoom_dictionary->Set(change.host, base::Value(level)); } void ZoomLevelDelegate::ExtractPerHostZoomLevels( - const base::DictionaryValue* host_zoom_dictionary) { + const base::Value::Dict& host_zoom_dictionary) { std::vector keys_to_remove; - std::unique_ptr host_zoom_dictionary_copy = - host_zoom_dictionary->DeepCopyWithoutEmptyChildren(); - for (base::DictionaryValue::Iterator i(*host_zoom_dictionary_copy); - !i.IsAtEnd(); i.Advance()) { - const std::string& host(i.key()); - const absl::optional zoom_level = i.value().GetIfDouble(); + base::Value::Dict host_zoom_dictionary_copy = host_zoom_dictionary.Clone(); + for (auto [host, value] : host_zoom_dictionary_copy) { + const absl::optional zoom_level = value.GetIfDouble(); // Filter out A) the empty host, B) zoom levels equal to the default; and // remember them, so that we can later erase them from Prefs. @@ -120,14 +111,14 @@ void ZoomLevelDelegate::ExtractPerHostZoomLevels( // level was set to its current value. In either case, SetZoomLevelForHost // will ignore type B values, thus, to have consistency with HostZoomMap's // internal state, these values must also be removed from Prefs. - if (host.empty() || !zoom_level || - blink::PageZoomValuesEqual(*zoom_level, + if (host.empty() || !zoom_level.has_value() || + blink::PageZoomValuesEqual(zoom_level.value(), host_zoom_map_->GetDefaultZoomLevel())) { keys_to_remove.push_back(host); continue; } - host_zoom_map_->SetZoomLevelForHost(host, *zoom_level); + host_zoom_map_->SetZoomLevelForHost(host, zoom_level.value()); } // Sanitize prefs to remove entries that match the default zoom level and/or @@ -155,16 +146,15 @@ void ZoomLevelDelegate::InitHostZoomMap(content::HostZoomMap* host_zoom_map) { // Initialize the HostZoomMap with per-host zoom levels from the persisted // zoom-level preference values. - const base::Value* host_zoom_dictionaries = - pref_service_->GetDictionary(kPartitionPerHostZoomLevels); - const base::Value* host_zoom_dictionary = - host_zoom_dictionaries->FindDictKey(partition_key_); + const base::Value::Dict& host_zoom_dictionaries = + pref_service_->GetValueDict(kPartitionPerHostZoomLevels); + const base::Value::Dict* host_zoom_dictionary = + host_zoom_dictionaries.FindDict(partition_key_); if (host_zoom_dictionary) { // Since we're calling this before setting up zoom_subscription_ below we // don't need to worry that host_zoom_dictionary is indirectly affected // by calls to HostZoomMap::SExtractPerHostZoomLevelsetZoomLevelForHost(). - ExtractPerHostZoomLevels( - &base::Value::AsDictionaryValue(*host_zoom_dictionary)); + ExtractPerHostZoomLevels(*host_zoom_dictionary); } zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(base::BindRepeating( diff --git a/shell/browser/zoom_level_delegate.h b/shell/browser/zoom_level_delegate.h index 56dcba7e68eb0..1c4302fadf8b1 100644 --- a/shell/browser/zoom_level_delegate.h +++ b/shell/browser/zoom_level_delegate.h @@ -7,12 +7,12 @@ #include +#include "base/values.h" #include "components/prefs/pref_service.h" #include "content/public/browser/host_zoom_map.h" #include "content/public/browser/zoom_level_delegate.h" namespace base { -class DictionaryValue; class FilePath; } // namespace base @@ -45,8 +45,7 @@ class ZoomLevelDelegate : public content::ZoomLevelDelegate { void InitHostZoomMap(content::HostZoomMap* host_zoom_map) override; private: - void ExtractPerHostZoomLevels( - const base::DictionaryValue* host_zoom_dictionary); + void ExtractPerHostZoomLevels(const base::Value::Dict& host_zoom_dictionary); // This is a callback function that receives notifications from HostZoomMap // when per-host zoom levels change. It is used to update the per-host diff --git a/shell/common/api/electron_api_clipboard.cc b/shell/common/api/electron_api_clipboard.cc index a130d0eb39a43..b7370b949378a 100644 --- a/shell/common/api/electron_api_clipboard.cc +++ b/shell/common/api/electron_api_clipboard.cc @@ -17,9 +17,7 @@ #include "ui/base/clipboard/scoped_clipboard_writer.h" #include "ui/gfx/codec/png_codec.h" -namespace electron { - -namespace api { +namespace electron::api { ui::ClipboardBuffer Clipboard::GetClipboardBuffer(gin_helper::Arguments* args) { std::string type; @@ -260,9 +258,7 @@ void Clipboard::Clear(gin_helper::Arguments* args) { ui::Clipboard::GetForCurrentThread()->Clear(GetClipboardBuffer(args)); } -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/common/api/electron_api_clipboard.h b/shell/common/api/electron_api_clipboard.h index 158e33bb3bab8..b0fa62c3b6470 100644 --- a/shell/common/api/electron_api_clipboard.h +++ b/shell/common/api/electron_api_clipboard.h @@ -17,9 +17,7 @@ class Arguments; class Dictionary; } // namespace gin_helper -namespace electron { - -namespace api { +namespace electron::api { class Clipboard { public: @@ -67,8 +65,6 @@ class Clipboard { gin_helper::Arguments* args); }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_COMMON_API_ELECTRON_API_CLIPBOARD_H_ diff --git a/shell/common/api/electron_api_clipboard_mac.mm b/shell/common/api/electron_api_clipboard_mac.mm index 7f101c259bd26..5607885c4c5e6 100644 --- a/shell/common/api/electron_api_clipboard_mac.mm +++ b/shell/common/api/electron_api_clipboard_mac.mm @@ -6,9 +6,7 @@ #include "shell/common/api/electron_api_clipboard.h" #include "ui/base/cocoa/find_pasteboard.h" -namespace electron { - -namespace api { +namespace electron::api { void Clipboard::WriteFindText(const std::u16string& text) { NSString* text_ns = base::SysUTF16ToNSString(text); @@ -16,9 +14,7 @@ } std::u16string Clipboard::ReadFindText() { - return GetFindPboardText(); + return base::SysNSStringToUTF16([[FindPasteboard sharedInstance] findText]); } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/common/api/electron_api_key_weak_map.h b/shell/common/api/electron_api_key_weak_map.h index f26fa29297ad8..2b9d1e92d5883 100644 --- a/shell/common/api/electron_api_key_weak_map.h +++ b/shell/common/api/electron_api_key_weak_map.h @@ -11,9 +11,7 @@ #include "shell/common/gin_helper/wrappable.h" #include "shell/common/key_weak_map.h" -namespace electron { - -namespace api { +namespace electron::api { template class KeyWeakMap : public gin_helper::Wrappable> { @@ -59,8 +57,6 @@ class KeyWeakMap : public gin_helper::Wrappable> { electron::KeyWeakMap key_weak_map_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_COMMON_API_ELECTRON_API_KEY_WEAK_MAP_H_ diff --git a/shell/common/api/electron_api_native_image.cc b/shell/common/api/electron_api_native_image.cc index 0dbda357a755c..dfb6b8cf1d883 100644 --- a/shell/common/api/electron_api_native_image.cc +++ b/shell/common/api/electron_api_native_image.cc @@ -48,9 +48,7 @@ #include "ui/gfx/icon_util.h" #endif -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -271,10 +269,6 @@ std::string NativeImage::ToDataURL(gin::Arguments* args) { image_.AsImageSkia().GetRepresentation(scale_factor).GetBitmap()); } -void SkUnref(char* data, void* hint) { - reinterpret_cast(hint)->unref(); -} - v8::Local NativeImage::GetBitmap(gin::Arguments* args) { float scale_factor = GetScaleFactorFromOptions(args); @@ -283,10 +277,9 @@ v8::Local NativeImage::GetBitmap(gin::Arguments* args) { SkPixelRef* ref = bitmap.pixelRef(); if (!ref) return node::Buffer::New(args->isolate(), 0).ToLocalChecked(); - ref->ref(); - return node::Buffer::New(args->isolate(), - reinterpret_cast(ref->pixels()), - bitmap.computeByteSize(), &SkUnref, ref) + return node::Buffer::Copy(args->isolate(), + reinterpret_cast(ref->pixels()), + bitmap.computeByteSize()) .ToLocalChecked(); } @@ -336,24 +329,24 @@ float NativeImage::GetAspectRatio(const absl::optional scale_factor) { } gin::Handle NativeImage::Resize(gin::Arguments* args, - base::DictionaryValue options) { + base::Value::Dict options) { float scale_factor = GetScaleFactorFromOptions(args); gfx::Size size = GetSize(scale_factor); - int width = size.width(); - int height = size.height(); - bool width_set = options.GetInteger("width", &width); - bool height_set = options.GetInteger("height", &height); + absl::optional new_width = options.FindInt("width"); + absl::optional new_height = options.FindInt("height"); + int width = new_width.value_or(size.width()); + int height = new_height.value_or(size.height()); size.SetSize(width, height); if (width <= 0 && height <= 0) { return CreateEmpty(args->isolate()); - } else if (width_set && !height_set) { + } else if (new_width && !new_height) { // Scale height to preserve original aspect ratio size.set_height(width); size = gfx::ScaleToRoundedSize(size, 1.f, 1.f / GetAspectRatio(scale_factor)); - } else if (height_set && !width_set) { + } else if (new_height && !new_width) { // Scale width to preserve original aspect ratio size.set_width(height); size = gfx::ScaleToRoundedSize(size, GetAspectRatio(scale_factor), 1.f); @@ -361,11 +354,10 @@ gin::Handle NativeImage::Resize(gin::Arguments* args, skia::ImageOperations::ResizeMethod method = skia::ImageOperations::ResizeMethod::RESIZE_BEST; - std::string quality; - options.GetString("quality", &quality); - if (quality == "good") + std::string* quality = options.FindString("quality"); + if (quality && *quality == "good") method = skia::ImageOperations::ResizeMethod::RESIZE_GOOD; - else if (quality == "better") + else if (quality && *quality == "better") method = skia::ImageOperations::ResizeMethod::RESIZE_BETTER; gfx::ImageSkia resized = gfx::ImageSkiaOperations::CreateResizedImage( @@ -618,9 +610,7 @@ const char* NativeImage::GetTypeName() { // static gin::WrapperInfo NativeImage::kWrapperInfo = {gin::kEmbedderNativeGin}; -} // namespace api - -} // namespace electron +} // namespace electron::api namespace { diff --git a/shell/common/api/electron_api_native_image.h b/shell/common/api/electron_api_native_image.h index 7be02ad27b7af..3330765ff5d10 100644 --- a/shell/common/api/electron_api_native_image.h +++ b/shell/common/api/electron_api_native_image.h @@ -14,6 +14,7 @@ #include "gin/wrappable.h" #include "shell/common/gin_helper/error_thrower.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_skia_rep.h" #if BUILDFLAG(IS_WIN) #include "base/files/file_path.h" @@ -39,9 +40,7 @@ namespace gin { class Arguments; } -namespace electron { - -namespace api { +namespace electron::api { class NativeImage : public gin::Wrappable { public: @@ -113,7 +112,7 @@ class NativeImage : public gin::Wrappable { v8::Local GetBitmap(gin::Arguments* args); v8::Local GetNativeHandle(gin_helper::ErrorThrower thrower); gin::Handle Resize(gin::Arguments* args, - base::DictionaryValue options); + base::Value::Dict options); gin::Handle Crop(v8::Isolate* isolate, const gfx::Rect& rect); std::string ToDataURL(gin::Arguments* args); bool IsEmpty(); @@ -139,8 +138,6 @@ class NativeImage : public gin::Wrappable { int32_t memory_usage_ = 0; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_COMMON_API_ELECTRON_API_NATIVE_IMAGE_H_ diff --git a/shell/common/api/electron_api_native_image_mac.mm b/shell/common/api/electron_api_native_image_mac.mm index 68aacfdf28b25..a6ba907a0992a 100644 --- a/shell/common/api/electron_api_native_image_mac.mm +++ b/shell/common/api/electron_api_native_image_mac.mm @@ -10,20 +10,20 @@ #import #import +#import #include "base/mac/foundation_util.h" +#include "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #include "gin/arguments.h" #include "shell/common/gin_converters/image_converter.h" #include "shell/common/gin_helper/promise.h" #include "ui/gfx/color_utils.h" -#include "ui/gfx/image/image.h" +#include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_operations.h" -namespace electron { - -namespace api { +namespace electron::api { NSData* bufferFromNSImage(NSImage* image) { CGImageRef ref = [image CGImageForProposedRect:nil context:nil hints:nil]; @@ -53,32 +53,81 @@ } CGSize cg_size = size.ToCGSize(); - base::ScopedCFTypeRef cfurl = base::mac::FilePathToCFURL(path); - base::ScopedCFTypeRef ql_thumbnail( - QLThumbnailCreate(kCFAllocatorDefault, cfurl, cg_size, NULL)); - __block gin_helper::Promise p = std::move(promise); - // we do not want to blocking the main thread while waiting for quicklook to - // generate the thumbnail - QLThumbnailDispatchAsync( - ql_thumbnail, - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, /*flags*/ 0), ^{ - base::ScopedCFTypeRef cg_thumbnail( - QLThumbnailCopyImage(ql_thumbnail)); - if (cg_thumbnail) { - NSImage* result = - [[[NSImage alloc] initWithCGImage:cg_thumbnail - size:cg_size] autorelease]; - gfx::Image thumbnail(result); - dispatch_async(dispatch_get_main_queue(), ^{ - p.Resolve(thumbnail); - }); - } else { - dispatch_async(dispatch_get_main_queue(), ^{ - p.RejectWithErrorMessage("unable to retrieve thumbnail preview " - "image for the given path"); - }); - } - }); + + if (@available(macOS 10.15, *)) { + NSURL* nsurl = base::mac::FilePathToNSURL(path); + + // We need to explicitly check if the user has passed an invalid path + // because QLThumbnailGenerationRequest will generate a stock file icon + // and pass silently if we do not. + if (![[NSFileManager defaultManager] fileExistsAtPath:[nsurl path]]) { + promise.RejectWithErrorMessage( + "unable to retrieve thumbnail preview image for the given path"); + return handle; + } + + NSScreen* screen = [[NSScreen screens] firstObject]; + base::scoped_nsobject request( + [[QLThumbnailGenerationRequest alloc] + initWithFileAtURL:nsurl + size:cg_size + scale:[screen backingScaleFactor] + representationTypes: + QLThumbnailGenerationRequestRepresentationTypeAll]); + __block gin_helper::Promise p = std::move(promise); + [[QLThumbnailGenerator sharedGenerator] + generateBestRepresentationForRequest:request + completionHandler:^( + QLThumbnailRepresentation* thumbnail, + NSError* error) { + if (error || !thumbnail) { + std::string err_msg( + [error.localizedDescription UTF8String]); + dispatch_async(dispatch_get_main_queue(), ^{ + p.RejectWithErrorMessage( + "unable to retrieve thumbnail preview " + "image for the given path: " + + err_msg); + }); + } else { + NSImage* result = [[[NSImage alloc] + initWithCGImage:[thumbnail CGImage] + size:cg_size] autorelease]; + gfx::Image image(result); + dispatch_async(dispatch_get_main_queue(), ^{ + p.Resolve(image); + }); + } + }]; + } else { + base::ScopedCFTypeRef cfurl = base::mac::FilePathToCFURL(path); + base::ScopedCFTypeRef ql_thumbnail( + QLThumbnailCreate(kCFAllocatorDefault, cfurl, cg_size, NULL)); + __block gin_helper::Promise p = std::move(promise); + // Do not block the main thread waiting for quicklook to generate the + // thumbnail. + QLThumbnailDispatchAsync( + ql_thumbnail, + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, /*flags*/ 0), ^{ + base::ScopedCFTypeRef cg_thumbnail( + QLThumbnailCopyImage(ql_thumbnail)); + if (cg_thumbnail) { + NSImage* result = + [[[NSImage alloc] initWithCGImage:cg_thumbnail + size:cg_size] autorelease]; + gfx::Image thumbnail(result); + dispatch_async(dispatch_get_main_queue(), ^{ + p.Resolve(thumbnail); + }); + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + p.RejectWithErrorMessage("unable to retrieve thumbnail preview " + "image for the given path"); + }); + } + }); + } + return handle; } @@ -132,6 +181,4 @@ return [image_.AsNSImage() isTemplate]; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/common/api/electron_api_native_image_win.cc b/shell/common/api/electron_api_native_image_win.cc index 3b971bee56d20..1cc998d3de53d 100644 --- a/shell/common/api/electron_api_native_image_win.cc +++ b/shell/common/api/electron_api_native_image_win.cc @@ -17,9 +17,7 @@ #include "ui/gfx/icon_util.h" #include "ui/gfx/image/image_skia.h" -namespace electron { - -namespace api { +namespace electron::api { // static v8::Local NativeImage::CreateThumbnailFromPath( @@ -102,6 +100,4 @@ v8::Local NativeImage::CreateThumbnailFromPath( return handle; } -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/common/api/electron_api_shell.cc b/shell/common/api/electron_api_shell.cc index 20fd7929ee540..e279f3a73fe14 100644 --- a/shell/common/api/electron_api_shell.cc +++ b/shell/common/api/electron_api_shell.cc @@ -15,6 +15,7 @@ #include "shell/common/platform_util.h" #if BUILDFLAG(IS_WIN) +#include "base/threading/thread_restrictions.h" #include "base/win/scoped_com_initializer.h" #include "base/win/shortcut.h" @@ -105,6 +106,11 @@ v8::Local TrashItem(v8::Isolate* isolate, } #if BUILDFLAG(IS_WIN) +// The use of the ForTesting flavors is a hack workaround to avoid having to +// patch these as friends into the associated guard classes. +class ShortcutAccessScopedAllowBlocking + : public base::ScopedAllowBlockingForTesting {}; + bool WriteShortcutLink(const base::FilePath& shortcut_path, gin_helper::Arguments* args) { base::win::ShortcutOperation operation = @@ -136,6 +142,7 @@ bool WriteShortcutLink(const base::FilePath& shortcut_path, if (options.Get("toastActivatorClsid", &toastActivatorClsid)) properties.set_toast_activator_clsid(toastActivatorClsid); + ShortcutAccessScopedAllowBlocking allow_blocking; base::win::ScopedCOMInitializer com_initializer; return base::win::CreateOrUpdateShortcutLink(shortcut_path, properties, operation); @@ -145,6 +152,7 @@ v8::Local ReadShortcutLink(gin_helper::ErrorThrower thrower, const base::FilePath& path) { using base::win::ShortcutProperties; gin::Dictionary options = gin::Dictionary::CreateEmpty(thrower.isolate()); + ShortcutAccessScopedAllowBlocking allow_blocking; base::win::ScopedCOMInitializer com_initializer; base::win::ShortcutProperties properties; if (!base::win::ResolveShortcutProperties( diff --git a/shell/common/api/electron_api_v8_util.cc b/shell/common/api/electron_api_v8_util.cc index 8c55a47919b79..07396528851a0 100644 --- a/shell/common/api/electron_api_v8_util.cc +++ b/shell/common/api/electron_api_v8_util.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. +#include #include #include "base/hash/hash.h" @@ -106,9 +107,11 @@ void RequestGarbageCollectionForTesting(v8::Isolate* isolate) { // This causes a fatal error by creating a circular extension dependency. void TriggerFatalErrorForTesting(v8::Isolate* isolate) { static const char* aDeps[] = {"B"}; - v8::RegisterExtension(std::make_unique("A", "", 1, aDeps)); + v8::RegisterExtension( + std::make_unique("A", "", std::size(aDeps), aDeps)); static const char* bDeps[] = {"A"}; - v8::RegisterExtension(std::make_unique("B", "", 1, bDeps)); + v8::RegisterExtension( + std::make_unique("B", "", std::size(aDeps), bDeps)); v8::ExtensionConfiguration config(1, bDeps); v8::Context::New(isolate, &config); } diff --git a/shell/common/api/electron_bindings.cc b/shell/common/api/electron_bindings.cc index 50509dec3401a..5cd1930a8bcd2 100644 --- a/shell/common/api/electron_bindings.cc +++ b/shell/common/api/electron_bindings.cc @@ -250,7 +250,6 @@ void ElectronBindings::DidReceiveMemoryDump( bool success, std::unique_ptr global_dump) { v8::Isolate* isolate = promise.isolate(); - gin_helper::Locker locker(isolate); v8::HandleScope handle_scope(isolate); gin_helper::MicrotasksScope microtasks_scope(isolate, true); v8::Context::Scope context_scope( diff --git a/shell/common/api/features.cc b/shell/common/api/features.cc index 92208cfba036d..48d733f16a031 100644 --- a/shell/common/api/features.cc +++ b/shell/common/api/features.cc @@ -54,10 +54,6 @@ bool IsPictureInPictureEnabled() { return BUILDFLAG(ENABLE_PICTURE_IN_PICTURE); } -bool IsWinDarkModeWindowUiEnabled() { - return BUILDFLAG(ENABLE_WIN_DARK_MODE_WINDOW_UI); -} - bool IsComponentBuild() { #if defined(COMPONENT_BUILD) return true; @@ -84,7 +80,6 @@ void Initialize(v8::Local exports, dict.SetMethod("isPictureInPictureEnabled", &IsPictureInPictureEnabled); dict.SetMethod("isComponentBuild", &IsComponentBuild); dict.SetMethod("isExtensionsEnabled", &IsExtensionsEnabled); - dict.SetMethod("isWinDarkModeWindowUiEnabled", &IsWinDarkModeWindowUiEnabled); } } // namespace diff --git a/shell/common/asar/archive.cc b/shell/common/asar/archive.cc index 709950fd65841..450eff88926e0 100644 --- a/shell/common/asar/archive.cc +++ b/shell/common/asar/archive.cc @@ -15,7 +15,6 @@ #include "base/logging.h" #include "base/pickle.h" #include "base/strings/string_number_conversions.h" -#include "base/task/post_task.h" #include "base/threading/thread_restrictions.h" #include "base/values.h" #include "electron/fuses.h" @@ -36,83 +35,75 @@ const char kSeparators[] = "\\/"; const char kSeparators[] = "/"; #endif -bool GetNodeFromPath(std::string path, - const base::DictionaryValue* root, - const base::DictionaryValue** out); +const base::Value::Dict* GetNodeFromPath(std::string path, + const base::Value::Dict& root); // Gets the "files" from "dir". -bool GetFilesNode(const base::DictionaryValue* root, - const base::DictionaryValue* dir, - const base::DictionaryValue** out) { +const base::Value::Dict* GetFilesNode(const base::Value::Dict& root, + const base::Value::Dict& dir) { // Test for symbol linked directory. - const std::string* link = dir->FindStringKey("link"); + const std::string* link = dir.FindString("link"); if (link != nullptr) { - const base::DictionaryValue* linked_node = nullptr; - if (!GetNodeFromPath(*link, root, &linked_node)) - return false; - dir = linked_node; + const base::Value::Dict* linked_node = GetNodeFromPath(*link, root); + if (!linked_node) + return nullptr; + return linked_node->FindDict("files"); } - return dir->GetDictionaryWithoutPathExpansion("files", out); + return dir.FindDict("files"); } // Gets sub-file "name" from "dir". -bool GetChildNode(const base::DictionaryValue* root, - const std::string& name, - const base::DictionaryValue* dir, - const base::DictionaryValue** out) { - if (name.empty()) { - *out = root; - return true; - } - - const base::DictionaryValue* files = nullptr; - return GetFilesNode(root, dir, &files) && - files->GetDictionaryWithoutPathExpansion(name, out); +const base::Value::Dict* GetChildNode(const base::Value::Dict& root, + const std::string& name, + const base::Value::Dict& dir) { + if (name.empty()) + return &root; + + const base::Value::Dict* files = GetFilesNode(root, dir); + return files ? files->FindDict(name) : nullptr; } // Gets the node of "path" from "root". -bool GetNodeFromPath(std::string path, - const base::DictionaryValue* root, - const base::DictionaryValue** out) { - if (path.empty()) { - *out = root; - return true; - } +const base::Value::Dict* GetNodeFromPath(std::string path, + const base::Value::Dict& root) { + if (path.empty()) + return &root; - const base::DictionaryValue* dir = root; + const base::Value::Dict* dir = &root; for (size_t delimiter_position = path.find_first_of(kSeparators); delimiter_position != std::string::npos; delimiter_position = path.find_first_of(kSeparators)) { - const base::DictionaryValue* child = nullptr; - if (!GetChildNode(root, path.substr(0, delimiter_position), dir, &child)) - return false; + const base::Value::Dict* child = + GetChildNode(root, path.substr(0, delimiter_position), *dir); + if (!child) + return nullptr; dir = child; path.erase(0, delimiter_position + 1); } - return GetChildNode(root, path, dir, out); + return GetChildNode(root, path, *dir); } bool FillFileInfoWithNode(Archive::FileInfo* info, uint32_t header_size, bool load_integrity, - const base::DictionaryValue* node) { - if (auto size = node->FindIntKey("size")) { - info->size = static_cast(size.value()); + const base::Value::Dict* node) { + if (absl::optional size = node->FindInt("size")) { + info->size = static_cast(*size); } else { return false; } - if (auto unpacked = node->FindBoolKey("unpacked")) { - info->unpacked = unpacked.value(); + if (absl::optional unpacked = node->FindBool("unpacked")) { + info->unpacked = *unpacked; if (info->unpacked) { return true; } } - auto* offset = node->FindStringKey("offset"); + const std::string* offset = node->FindString("offset"); if (offset && base::StringToUint64(base::StringPiece(*offset), &info->offset)) { info->offset += header_size; @@ -120,26 +111,26 @@ bool FillFileInfoWithNode(Archive::FileInfo* info, return false; } - if (auto executable = node->FindBoolKey("executable")) { - info->executable = executable.value(); + if (absl::optional executable = node->FindBool("executable")) { + info->executable = *executable; } #if BUILDFLAG(IS_MAC) if (load_integrity && electron::fuses::IsEmbeddedAsarIntegrityValidationEnabled()) { - if (auto* integrity = node->FindDictKey("integrity")) { - auto* algorithm = integrity->FindStringKey("algorithm"); - auto* hash = integrity->FindStringKey("hash"); - auto block_size = integrity->FindIntKey("blockSize"); - auto* blocks = integrity->FindListKey("blocks"); + if (const base::Value::Dict* integrity = node->FindDict("integrity")) { + const std::string* algorithm = integrity->FindString("algorithm"); + const std::string* hash = integrity->FindString("hash"); + absl::optional block_size = integrity->FindInt("blockSize"); + const base::Value::List* blocks = integrity->FindList("blocks"); if (algorithm && hash && block_size && block_size > 0 && blocks) { IntegrityPayload integrity_payload; integrity_payload.hash = *hash; integrity_payload.block_size = static_cast(block_size.value()); - for (auto& value : blocks->GetListDeprecated()) { - if (auto* block = value.GetIfString()) { + for (auto& value : *blocks) { + if (const std::string* block = value.GetIfString()) { integrity_payload.blocks.push_back(*block); } else { LOG(FATAL) @@ -280,8 +271,7 @@ bool Archive::Init() { } header_size_ = 8 + size; - header_ = base::DictionaryValue::From( - base::Value::ToUniquePtrValue(std::move(*value))); + header_ = std::move(value->GetDict()); return true; } @@ -299,13 +289,14 @@ bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) const { if (!header_) return false; - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) + const base::Value::Dict* node = + GetNodeFromPath(path.AsUTF8Unsafe(), *header_); + if (!node) return false; - std::string link; - if (node->GetString("link", &link)) - return GetFileInfo(base::FilePath::FromUTF8Unsafe(link), info); + const std::string* link = node->FindString("link"); + if (link) + return GetFileInfo(base::FilePath::FromUTF8Unsafe(*link), info); return FillFileInfoWithNode(info, header_size_, header_validated_, node); } @@ -314,17 +305,18 @@ bool Archive::Stat(const base::FilePath& path, Stats* stats) const { if (!header_) return false; - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) + const base::Value::Dict* node = + GetNodeFromPath(path.AsUTF8Unsafe(), *header_); + if (!node) return false; - if (node->FindKey("link")) { + if (node->Find("link")) { stats->is_file = false; stats->is_link = true; return true; } - if (node->FindKey("files")) { + if (node->Find("files")) { stats->is_file = false; stats->is_directory = true; return true; @@ -338,19 +330,17 @@ bool Archive::Readdir(const base::FilePath& path, if (!header_) return false; - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) + const base::Value::Dict* node = + GetNodeFromPath(path.AsUTF8Unsafe(), *header_); + if (!node) return false; - const base::DictionaryValue* files_node; - if (!GetFilesNode(header_.get(), node, &files_node)) + const base::Value::Dict* files_node = GetFilesNode(*header_, *node); + if (!files_node) return false; - base::DictionaryValue::Iterator iter(*files_node); - while (!iter.IsAtEnd()) { - files->push_back(base::FilePath::FromUTF8Unsafe(iter.key())); - iter.Advance(); - } + for (const auto iter : *files_node) + files->push_back(base::FilePath::FromUTF8Unsafe(iter.first)); return true; } @@ -359,13 +349,14 @@ bool Archive::Realpath(const base::FilePath& path, if (!header_) return false; - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) + const base::Value::Dict* node = + GetNodeFromPath(path.AsUTF8Unsafe(), *header_); + if (!node) return false; - std::string link; - if (node->GetString("link", &link)) { - *realpath = base::FilePath::FromUTF8Unsafe(link); + const std::string* link = node->FindString("link"); + if (link) { + *realpath = base::FilePath::FromUTF8Unsafe(*link); return true; } diff --git a/shell/common/asar/archive.h b/shell/common/asar/archive.h index 51e75ec75b346..d420f3fa4a0fd 100644 --- a/shell/common/asar/archive.h +++ b/shell/common/asar/archive.h @@ -13,12 +13,9 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/synchronization/lock.h" +#include "base/values.h" #include "third_party/abseil-cpp/absl/types/optional.h" -namespace base { -class DictionaryValue; -} - namespace asar { class ScopedTemporaryFile; @@ -104,7 +101,7 @@ class Archive { base::File file_; int fd_ = -1; uint32_t header_size_ = 0; - std::unique_ptr header_; + absl::optional header_; // Cached external temporary files. base::Lock external_files_lock_; diff --git a/shell/common/asar/archive_mac.mm b/shell/common/asar/archive_mac.mm index 3ad60faf24c58..c3550e24e26f9 100644 --- a/shell/common/asar/archive_mac.mm +++ b/shell/common/asar/archive_mac.mm @@ -11,6 +11,7 @@ #include #include +#include "base/files/file_util.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" @@ -21,7 +22,8 @@ namespace asar { absl::optional Archive::RelativePath() const { - base::FilePath bundle_path = base::mac::MainBundlePath().Append("Contents"); + base::FilePath bundle_path = base::MakeAbsoluteFilePath( + base::mac::MainBundlePath().Append("Contents")); base::FilePath relative_path; if (!bundle_path.AppendRelativePath(path_, &relative_path)) diff --git a/shell/common/color_util.cc b/shell/common/color_util.cc index afa4c7f7a40bc..73bbc162cca97 100644 --- a/shell/common/color_util.cc +++ b/shell/common/color_util.cc @@ -16,7 +16,7 @@ namespace { -bool IsHexFormat(const std::string& str) { +bool IsHexFormatWithAlpha(const std::string& str) { // Must be either #ARGB or #AARRGGBB. bool is_hex_length = str.length() == 5 || str.length() == 9; if (str[0] != '#' || !is_hex_length) @@ -35,20 +35,17 @@ namespace electron { SkColor ParseCSSColor(const std::string& color_string) { // ParseCssColorString expects RGBA and we historically use ARGB // so we need to convert before passing to ParseCssColorString. - std::string color_str = color_string; - if (IsHexFormat(color_str)) { - if (color_str.length() == 5) { - // #ARGB => #RGBA - std::swap(color_str[1], color_str[4]); - } else { - // #AARRGGBB => #RRGGBBAA - std::swap(color_str[1], color_str[7]); - std::swap(color_str[2], color_str[8]); - } + std::string converted_color_str; + if (IsHexFormatWithAlpha(color_string)) { + std::string temp = color_string; + int len = color_string.length() == 5 ? 1 : 2; + converted_color_str = temp.erase(1, len) + color_string.substr(1, len); + } else { + converted_color_str = color_string; } SkColor color; - if (!content::ParseCssColorString(color_str, &color)) + if (!content::ParseCssColorString(converted_color_str, &color)) color = SK_ColorWHITE; return color; diff --git a/shell/common/crash_keys.cc b/shell/common/crash_keys.cc index 16e11125b21e5..d084adc257814 100644 --- a/shell/common/crash_keys.cc +++ b/shell/common/crash_keys.cc @@ -23,9 +23,7 @@ #include "shell/common/process_util.h" #include "third_party/crashpad/crashpad/client/annotation.h" -namespace electron { - -namespace crash_keys { +namespace electron::crash_keys { namespace { @@ -167,6 +165,4 @@ void SetPlatformCrashKey() { #endif } -} // namespace crash_keys - -} // namespace electron +} // namespace electron::crash_keys diff --git a/shell/common/crash_keys.h b/shell/common/crash_keys.h index 70f731d29f38c..e3c89f895be63 100644 --- a/shell/common/crash_keys.h +++ b/shell/common/crash_keys.h @@ -12,9 +12,7 @@ namespace base { class CommandLine; } -namespace electron { - -namespace crash_keys { +namespace electron::crash_keys { void SetCrashKey(const std::string& key, const std::string& value); void ClearCrashKey(const std::string& key); @@ -23,8 +21,6 @@ void GetCrashKeys(std::map* keys); void SetCrashKeysFromCommandLine(const base::CommandLine& command_line); void SetPlatformCrashKey(); -} // namespace crash_keys - -} // namespace electron +} // namespace electron::crash_keys #endif // ELECTRON_SHELL_COMMON_CRASH_KEYS_H_ diff --git a/shell/common/electron_paths.h b/shell/common/electron_paths.h index 6854e97d6ae48..c614f992940bb 100644 --- a/shell/common/electron_paths.h +++ b/shell/common/electron_paths.h @@ -23,7 +23,8 @@ enum { PATH_START = 11000, DIR_USER_CACHE = PATH_START, // Directory where user cache can be written. - DIR_APP_LOGS, // Directory where app logs live + DIR_APP_LOGS, // Directory where app logs live. + DIR_SESSION_DATA, // Where cookies, localStorage are stored. #if BUILDFLAG(IS_WIN) DIR_RECENT, // Directory where recent files live diff --git a/shell/common/extensions/api/cryptotoken_private.idl b/shell/common/extensions/api/cryptotoken_private.idl index bd761504f24ed..3bb5745d87a5c 100644 --- a/shell/common/extensions/api/cryptotoken_private.idl +++ b/shell/common/extensions/api/cryptotoken_private.idl @@ -19,7 +19,7 @@ namespace cryptotokenPrivate { DOMString appId; // The origin of the caller. DOMString origin; - // Identifies the tab in which the registration is occuring so that any + // Identifies the tab in which the registration is occurring so that any // permissions prompt is correctly located. long tabId; }; diff --git a/shell/common/extensions/api/i18n.json b/shell/common/extensions/api/i18n.json index d819d3117ba4e..01bc8b1759d87 100644 --- a/shell/common/extensions/api/i18n.json +++ b/shell/common/extensions/api/i18n.json @@ -93,7 +93,7 @@ { "type": "object", "name": "result", - "description": "LanguageDetectionResult object that holds detected langugae reliability and array of DetectedLanguage", + "description": "LanguageDetectionResult object that holds detected language reliability and array of DetectedLanguage", "properties": { "isReliable": { "type": "boolean", "description": "CLD detected language reliability" }, "languages": diff --git a/shell/common/extensions/electron_extensions_client.cc b/shell/common/extensions/electron_extensions_client.cc index c2f9a573701ce..76baa9df41c5d 100644 --- a/shell/common/extensions/electron_extensions_client.cc +++ b/shell/common/extensions/electron_extensions_client.cc @@ -67,6 +67,7 @@ base::LazyInstance::DestructorAtExit ElectronExtensionsClient::ElectronExtensionsClient() : webstore_base_url_(extension_urls::kChromeWebstoreBaseURL), + new_webstore_base_url_(extension_urls::kNewChromeWebstoreBaseURL), webstore_update_url_(extension_urls::kChromeWebstoreUpdateURL) { AddAPIProvider(std::make_unique()); AddAPIProvider(std::make_unique()); @@ -127,6 +128,10 @@ const GURL& ElectronExtensionsClient::GetWebstoreBaseURL() const { return webstore_base_url_; } +const GURL& ElectronExtensionsClient::GetNewWebstoreBaseURL() const { + return new_webstore_base_url_; +} + const GURL& ElectronExtensionsClient::GetWebstoreUpdateURL() const { return webstore_update_url_; } diff --git a/shell/common/extensions/electron_extensions_client.h b/shell/common/extensions/electron_extensions_client.h index c69a875b5dcb7..885f85554f62e 100644 --- a/shell/common/extensions/electron_extensions_client.h +++ b/shell/common/extensions/electron_extensions_client.h @@ -52,11 +52,13 @@ class ElectronExtensionsClient : public extensions::ExtensionsClient { const GURL& GetWebstoreBaseURL() const override; const GURL& GetWebstoreUpdateURL() const override; bool IsBlocklistUpdateURL(const GURL& url) const override; + const GURL& GetNewWebstoreBaseURL() const override; private: ScriptingAllowlist scripting_allowlist_; const GURL webstore_base_url_; + const GURL new_webstore_base_url_; const GURL webstore_update_url_; }; diff --git a/shell/common/gin_converters/content_converter.cc b/shell/common/gin_converters/content_converter.cc index 600b525df71c7..f2456f4eda450 100644 --- a/shell/common/gin_converters/content_converter.cc +++ b/shell/common/gin_converters/content_converter.cc @@ -134,67 +134,67 @@ bool Converter::FromV8( } // static -v8::Local Converter::ToV8( +v8::Local Converter::ToV8( v8::Isolate* isolate, - const content::PermissionType& val) { + const blink::PermissionType& val) { using PermissionType = electron::WebContentsPermissionHelper::PermissionType; // Based on mappings from content/browser/devtools/protocol/browser_handler.cc // Not all permissions are currently used by Electron but this will future // proof these conversions. switch (val) { - case content::PermissionType::ACCESSIBILITY_EVENTS: + case blink::PermissionType::ACCESSIBILITY_EVENTS: return StringToV8(isolate, "accessibility-events"); - case content::PermissionType::AR: + case blink::PermissionType::AR: return StringToV8(isolate, "ar"); - case content::PermissionType::BACKGROUND_FETCH: + case blink::PermissionType::BACKGROUND_FETCH: return StringToV8(isolate, "background-fetch"); - case content::PermissionType::BACKGROUND_SYNC: + case blink::PermissionType::BACKGROUND_SYNC: return StringToV8(isolate, "background-sync"); - case content::PermissionType::CLIPBOARD_READ_WRITE: + case blink::PermissionType::CLIPBOARD_READ_WRITE: return StringToV8(isolate, "clipboard-read"); - case content::PermissionType::CLIPBOARD_SANITIZED_WRITE: + case blink::PermissionType::CLIPBOARD_SANITIZED_WRITE: return StringToV8(isolate, "clipboard-sanitized-write"); - case content::PermissionType::FONT_ACCESS: - return StringToV8(isolate, "font-access"); - case content::PermissionType::IDLE_DETECTION: + case blink::PermissionType::LOCAL_FONTS: + return StringToV8(isolate, "local-fonts"); + case blink::PermissionType::IDLE_DETECTION: return StringToV8(isolate, "idle-detection"); - case content::PermissionType::MIDI_SYSEX: + case blink::PermissionType::MIDI_SYSEX: return StringToV8(isolate, "midiSysex"); - case content::PermissionType::NFC: + case blink::PermissionType::NFC: return StringToV8(isolate, "nfc"); - case content::PermissionType::NOTIFICATIONS: + case blink::PermissionType::NOTIFICATIONS: return StringToV8(isolate, "notifications"); - case content::PermissionType::PAYMENT_HANDLER: + case blink::PermissionType::PAYMENT_HANDLER: return StringToV8(isolate, "payment-handler"); - case content::PermissionType::PERIODIC_BACKGROUND_SYNC: + case blink::PermissionType::PERIODIC_BACKGROUND_SYNC: return StringToV8(isolate, "periodic-background-sync"); - case content::PermissionType::DURABLE_STORAGE: + case blink::PermissionType::DURABLE_STORAGE: return StringToV8(isolate, "persistent-storage"); - case content::PermissionType::GEOLOCATION: + case blink::PermissionType::GEOLOCATION: return StringToV8(isolate, "geolocation"); - case content::PermissionType::CAMERA_PAN_TILT_ZOOM: - case content::PermissionType::AUDIO_CAPTURE: - case content::PermissionType::VIDEO_CAPTURE: + case blink::PermissionType::CAMERA_PAN_TILT_ZOOM: + case blink::PermissionType::AUDIO_CAPTURE: + case blink::PermissionType::VIDEO_CAPTURE: return StringToV8(isolate, "media"); - case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER: + case blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER: return StringToV8(isolate, "mediaKeySystem"); - case content::PermissionType::MIDI: + case blink::PermissionType::MIDI: return StringToV8(isolate, "midi"); - case content::PermissionType::WAKE_LOCK_SCREEN: + case blink::PermissionType::WAKE_LOCK_SCREEN: return StringToV8(isolate, "screen-wake-lock"); - case content::PermissionType::SENSORS: + case blink::PermissionType::SENSORS: return StringToV8(isolate, "sensors"); - case content::PermissionType::STORAGE_ACCESS_GRANT: + case blink::PermissionType::STORAGE_ACCESS_GRANT: return StringToV8(isolate, "storage-access"); - case content::PermissionType::VR: + case blink::PermissionType::VR: return StringToV8(isolate, "vr"); - case content::PermissionType::WAKE_LOCK_SYSTEM: + case blink::PermissionType::WAKE_LOCK_SYSTEM: return StringToV8(isolate, "system-wake-lock"); - case content::PermissionType::WINDOW_PLACEMENT: + case blink::PermissionType::WINDOW_PLACEMENT: return StringToV8(isolate, "window-placement"); - case content::PermissionType::DISPLAY_CAPTURE: + case blink::PermissionType::DISPLAY_CAPTURE: return StringToV8(isolate, "display-capture"); - case content::PermissionType::NUM: + case blink::PermissionType::NUM: break; } diff --git a/shell/common/gin_converters/content_converter.h b/shell/common/gin_converters/content_converter.h index e157b9f4a05f4..5482813214629 100644 --- a/shell/common/gin_converters/content_converter.h +++ b/shell/common/gin_converters/content_converter.h @@ -7,10 +7,10 @@ #include -#include "content/public/browser/permission_type.h" #include "content/public/common/referrer.h" #include "content/public/common/stop_find_action.h" #include "gin/converter.h" +#include "third_party/blink/public/common/permissions/permission_utils.h" #include "third_party/blink/public/mojom/choosers/popup_menu.mojom.h" #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h" @@ -47,9 +47,9 @@ struct Converter { }; template <> -struct Converter { +struct Converter { static v8::Local ToV8(v8::Isolate* isolate, - const content::PermissionType& val); + const blink::PermissionType& val); }; template <> diff --git a/shell/common/gin_converters/extension_converter.cc b/shell/common/gin_converters/extension_converter.cc index a81d6a81dc5b1..49e99e93905e4 100644 --- a/shell/common/gin_converters/extension_converter.cc +++ b/shell/common/gin_converters/extension_converter.cc @@ -22,7 +22,8 @@ v8::Local Converter::ToV8( dict.Set("path", extension->path()); dict.Set("url", extension->url()); dict.Set("version", extension->VersionString()); - dict.Set("manifest", *(extension->manifest()->value())); + dict.Set("manifest", + *static_cast(extension->manifest()->value())); return gin::ConvertToV8(isolate, dict); } diff --git a/shell/common/gin_converters/hid_device_info_converter.h b/shell/common/gin_converters/hid_device_info_converter.h new file mode 100644 index 0000000000000..6175b77ab0d3c --- /dev/null +++ b/shell/common/gin_converters/hid_device_info_converter.h @@ -0,0 +1,31 @@ +// Copyright (c) 2022 Microsoft, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_COMMON_GIN_CONVERTERS_HID_DEVICE_INFO_CONVERTER_H_ +#define ELECTRON_SHELL_COMMON_GIN_CONVERTERS_HID_DEVICE_INFO_CONVERTER_H_ + +#include "gin/converter.h" +#include "services/device/public/mojom/hid.mojom.h" +#include "shell/browser/hid/hid_chooser_context.h" +#include "shell/browser/hid/hid_chooser_controller.h" + +namespace gin { + +template <> +struct Converter { + static v8::Local ToV8( + v8::Isolate* isolate, + const device::mojom::HidDeviceInfoPtr& device) { + base::Value value = electron::HidChooserContext::DeviceInfoToValue(*device); + value.SetStringKey( + "deviceId", + electron::HidChooserController::PhysicalDeviceIdFromDeviceInfo( + *device)); + return gin::ConvertToV8(isolate, value); + } +}; + +} // namespace gin + +#endif // ELECTRON_SHELL_COMMON_GIN_CONVERTERS_HID_DEVICE_INFO_CONVERTER_H_ diff --git a/shell/common/gin_converters/net_converter.cc b/shell/common/gin_converters/net_converter.cc index d2b93166b3647..687d7610a8be9 100644 --- a/shell/common/gin_converters/net_converter.cc +++ b/shell/common/gin_converters/net_converter.cc @@ -153,20 +153,20 @@ v8::Local Converter::ToV8( v8::Local Converter::ToV8( v8::Isolate* isolate, net::HttpResponseHeaders* headers) { - base::DictionaryValue response_headers; + base::Value::Dict response_headers; if (headers) { size_t iter = 0; std::string key; std::string value; while (headers->EnumerateHeaderLines(&iter, &key, &value)) { key = base::ToLowerASCII(key); - base::Value* values = response_headers.FindListKey(key); + base::Value::List* values = response_headers.FindList(key); if (!values) - values = response_headers.SetKey(key, base::ListValue()); + values = &response_headers.Set(key, base::Value::List())->GetList(); values->Append(value); } } - return ConvertToV8(isolate, response_headers); + return ConvertToV8(isolate, base::Value(std::move(response_headers))); } bool Converter::FromV8( @@ -234,13 +234,13 @@ v8::Local Converter::ToV8( bool Converter::FromV8(v8::Isolate* isolate, v8::Local val, net::HttpRequestHeaders* out) { - base::DictionaryValue dict; + base::Value::Dict dict; if (!ConvertFromV8(isolate, val, &dict)) return false; - for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - if (it.value().is_string()) { - std::string value = it.value().GetString(); - out->SetHeader(it.key(), value); + for (const auto it : dict) { + if (it.second.is_string()) { + std::string value = it.second.GetString(); + out->SetHeader(it.first, value); } } return true; @@ -313,33 +313,31 @@ bool Converter>::FromV8( v8::Isolate* isolate, v8::Local val, scoped_refptr* out) { - auto list = std::make_unique(); - if (!ConvertFromV8(isolate, val, list.get())) + base::Value list_value; + if (!ConvertFromV8(isolate, val, &list_value) || !list_value.is_list()) return false; + base::Value::List& list = list_value.GetList(); *out = base::MakeRefCounted(); - for (size_t i = 0; i < list->GetListDeprecated().size(); ++i) { - base::DictionaryValue* dict = nullptr; - std::string type; - if (!list->GetDictionary(i, &dict)) + for (size_t i = 0; i < list.size(); ++i) { + base::Value& dict_value = list[i]; + if (!dict_value.is_dict()) return false; - dict->GetString("type", &type); - if (type == "rawData") { - const base::Value::BlobStorage* bytes = dict->FindBlobKey("bytes"); + base::Value::Dict& dict = dict_value.GetDict(); + std::string* type = dict.FindString("type"); + if (!type) + return false; + if (*type == "rawData") { + const base::Value::BlobStorage* bytes = dict.FindBlob("bytes"); (*out)->AppendBytes(reinterpret_cast(bytes->data()), base::checked_cast(bytes->size())); - } else if (type == "file") { - const std::string* file = dict->FindStringKey("filePath"); - if (file == nullptr) { + } else if (*type == "file") { + const std::string* file = dict.FindString("filePath"); + if (!file) return false; - } - int offset = 0, length = -1; - double modification_time = 0.0; - absl::optional maybe_modification_time = - dict->FindDoubleKey("modificationTime"); - if (maybe_modification_time.has_value()) - modification_time = maybe_modification_time.value(); - dict->GetInteger("offset", &offset); - dict->GetInteger("file", &length); + double modification_time = + dict.FindDouble("modificationTime").value_or(0.0); + int offset = dict.FindInt("offset").value_or(0); + int length = dict.FindInt("length").value_or(-1); (*out)->AppendFileRange(base::FilePath::FromUTF8Unsafe(*file), static_cast(offset), static_cast(length), diff --git a/shell/common/gin_converters/value_converter.cc b/shell/common/gin_converters/value_converter.cc index db89b6a63edf4..8510f50a0efec 100644 --- a/shell/common/gin_converters/value_converter.cc +++ b/shell/common/gin_converters/value_converter.cc @@ -7,38 +7,38 @@ #include #include -#include "base/values.h" -#include "shell/common/v8_value_converter.h" +#include "content/public/renderer/v8_value_converter.h" namespace gin { -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - base::DictionaryValue* out) { - electron::V8ValueConverter converter; - std::unique_ptr value( - converter.FromV8Value(val, isolate->GetCurrentContext())); +bool Converter::FromV8(v8::Isolate* isolate, + v8::Local val, + base::Value::Dict* out) { + std::unique_ptr value = + content::V8ValueConverter::Create()->FromV8Value( + val, isolate->GetCurrentContext()); if (value && value->is_dict()) { - out->Swap(static_cast(value.get())); + *out = std::move(value->GetDict()); return true; } else { return false; } } -v8::Local Converter::ToV8( +v8::Local Converter::ToV8( v8::Isolate* isolate, - const base::DictionaryValue& val) { - electron::V8ValueConverter converter; - return converter.ToV8Value(&val, isolate->GetCurrentContext()); + const base::Value::Dict& val) { + base::Value value(val.Clone()); + return content::V8ValueConverter::Create()->ToV8Value( + value, isolate->GetCurrentContext()); } bool Converter::FromV8(v8::Isolate* isolate, v8::Local val, base::Value* out) { - electron::V8ValueConverter converter; - std::unique_ptr value( - converter.FromV8Value(val, isolate->GetCurrentContext())); + std::unique_ptr value = + content::V8ValueConverter::Create()->FromV8Value( + val, isolate->GetCurrentContext()); if (value) { *out = std::move(*value); return true; @@ -49,29 +49,30 @@ bool Converter::FromV8(v8::Isolate* isolate, v8::Local Converter::ToV8(v8::Isolate* isolate, const base::Value& val) { - electron::V8ValueConverter converter; - return converter.ToV8Value(&val, isolate->GetCurrentContext()); + return content::V8ValueConverter::Create()->ToV8Value( + val, isolate->GetCurrentContext()); } -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - base::ListValue* out) { - electron::V8ValueConverter converter; - std::unique_ptr value( - converter.FromV8Value(val, isolate->GetCurrentContext())); +bool Converter::FromV8(v8::Isolate* isolate, + v8::Local val, + base::Value::List* out) { + std::unique_ptr value = + content::V8ValueConverter::Create()->FromV8Value( + val, isolate->GetCurrentContext()); if (value && value->is_list()) { - out->Swap(static_cast(value.get())); + *out = std::move(value->GetList()); return true; } else { return false; } } -v8::Local Converter::ToV8( +v8::Local Converter::ToV8( v8::Isolate* isolate, - const base::ListValue& val) { - electron::V8ValueConverter converter; - return converter.ToV8Value(&val, isolate->GetCurrentContext()); + const base::Value::List& val) { + base::Value value(val.Clone()); + return content::V8ValueConverter::Create()->ToV8Value( + value, isolate->GetCurrentContext()); } } // namespace gin diff --git a/shell/common/gin_converters/value_converter.h b/shell/common/gin_converters/value_converter.h index 16a79af43b9e0..a5c7996883d6b 100644 --- a/shell/common/gin_converters/value_converter.h +++ b/shell/common/gin_converters/value_converter.h @@ -5,23 +5,18 @@ #ifndef ELECTRON_SHELL_COMMON_GIN_CONVERTERS_VALUE_CONVERTER_H_ #define ELECTRON_SHELL_COMMON_GIN_CONVERTERS_VALUE_CONVERTER_H_ +#include "base/values.h" #include "gin/converter.h" -namespace base { -class DictionaryValue; -class ListValue; -class Value; -} // namespace base - namespace gin { template <> -struct Converter { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Local val, - base::DictionaryValue* out); + base::Value::Dict* out); static v8::Local ToV8(v8::Isolate* isolate, - const base::DictionaryValue& val); + const base::Value::Dict& val); }; template <> @@ -34,12 +29,12 @@ struct Converter { }; template <> -struct Converter { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Local val, - base::ListValue* out); + base::Value::List* out); static v8::Local ToV8(v8::Isolate* isolate, - const base::ListValue& val); + const base::Value::List& val); }; } // namespace gin diff --git a/shell/common/gin_helper/callback.cc b/shell/common/gin_helper/callback.cc index a5abed2c7020b..4c68b5e14f4fc 100644 --- a/shell/common/gin_helper/callback.cc +++ b/shell/common/gin_helper/callback.cc @@ -15,7 +15,7 @@ namespace { struct TranslaterHolder { explicit TranslaterHolder(v8::Isolate* isolate) : handle(isolate, v8::External::New(isolate, this)) { - handle.SetWeak(this, &GC, v8::WeakCallbackType::kFinalizer); + handle.SetWeak(this, &GC, v8::WeakCallbackType::kParameter); } ~TranslaterHolder() { if (!handle.IsEmpty()) { @@ -147,7 +147,7 @@ v8::Local BindFunctionWith(v8::Isolate* isolate, CHECK(!bind.IsEmpty()); v8::Local bind_func = bind.ToLocalChecked().As(); v8::Local converted[] = {func, arg1, arg2}; - return bind_func->Call(context, func, base::size(converted), converted) + return bind_func->Call(context, func, std::size(converted), converted) .ToLocalChecked(); } diff --git a/shell/common/gin_helper/event_emitter.cc b/shell/common/gin_helper/event_emitter.cc index 32a3e4b1b8183..5ebb9c93539b7 100644 --- a/shell/common/gin_helper/event_emitter.cc +++ b/shell/common/gin_helper/event_emitter.cc @@ -10,9 +10,7 @@ #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/object_template_builder.h" -namespace gin_helper { - -namespace internal { +namespace gin_helper::internal { namespace { @@ -75,6 +73,4 @@ v8::Local CreateNativeEvent( return event; } -} // namespace internal - -} // namespace gin_helper +} // namespace gin_helper::internal diff --git a/shell/common/gin_helper/event_emitter.h b/shell/common/gin_helper/event_emitter.h index 90af3f7478df4..c600e896af947 100644 --- a/shell/common/gin_helper/event_emitter.h +++ b/shell/common/gin_helper/event_emitter.h @@ -40,7 +40,7 @@ class EventEmitter : public gin_helper::Wrappable { using Base = gin_helper::Wrappable; using ValueArray = std::vector>; - // Make the convinient methods visible: + // Make the convenient methods visible: // https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members v8::Isolate* isolate() const { return Base::isolate(); } v8::Local GetWrapper() const { return Base::GetWrapper(); } @@ -61,7 +61,6 @@ class EventEmitter : public gin_helper::Wrappable { // this.emit(name, new Event(), args...); template bool Emit(base::StringPiece name, Args&&... args) { - v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); v8::Local wrapper = GetWrapper(); if (wrapper.IsEmpty()) diff --git a/shell/common/gin_helper/event_emitter_caller.cc b/shell/common/gin_helper/event_emitter_caller.cc index 8676732d32402..be112f55fa5d1 100644 --- a/shell/common/gin_helper/event_emitter_caller.cc +++ b/shell/common/gin_helper/event_emitter_caller.cc @@ -8,9 +8,7 @@ #include "shell/common/gin_helper/microtasks_scope.h" #include "shell/common/node_includes.h" -namespace gin_helper { - -namespace internal { +namespace gin_helper::internal { v8::Local CallMethodWithArgs(v8::Isolate* isolate, v8::Local obj, @@ -33,6 +31,4 @@ v8::Local CallMethodWithArgs(v8::Isolate* isolate, return v8::Boolean::New(isolate, false); } -} // namespace internal - -} // namespace gin_helper +} // namespace gin_helper::internal diff --git a/shell/common/gin_helper/function_template.h b/shell/common/gin_helper/function_template.h index 025c917fbc34f..c6d6410f9456d 100644 --- a/shell/common/gin_helper/function_template.h +++ b/shell/common/gin_helper/function_template.h @@ -208,7 +208,7 @@ class Invoker, ArgTypes...> // GCC thinks that create_flags is going unused, even though the // expansion above clearly makes use of it. Per jyasskin@, casting // to void is the commonly accepted way to convince the compiler - // that you're actually using a parameter/varible. + // that you're actually using a parameter/variable. (void)create_flags; } @@ -313,7 +313,7 @@ struct CallbackTraits> { // Specialization for member function pointers. We need to handle this case // specially because the first parameter for callbacks to MFP should typically -// come from the the JavaScript "this" object the function was called on, not +// come from the JavaScript "this" object the function was called on, not // from the first normal parameter. template struct CallbackTraits< diff --git a/shell/common/gin_helper/locker.cc b/shell/common/gin_helper/locker.cc index 0c7be54cd4ea8..dbbaf7879fc46 100644 --- a/shell/common/gin_helper/locker.cc +++ b/shell/common/gin_helper/locker.cc @@ -13,4 +13,10 @@ Locker::Locker(v8::Isolate* isolate) { Locker::~Locker() = default; +void Locker::SetIsBrowserProcess(bool is_browser_process) { + g_is_browser_process = is_browser_process; +} + +bool Locker::g_is_browser_process = false; + } // namespace gin_helper diff --git a/shell/common/gin_helper/locker.h b/shell/common/gin_helper/locker.h index 09eee5aa7ff60..9fb11ad4b358d 100644 --- a/shell/common/gin_helper/locker.h +++ b/shell/common/gin_helper/locker.h @@ -23,13 +23,17 @@ class Locker { // Returns whether current process is browser process, currently we detect it // by checking whether current has used V8 Lock, but it might be a bad idea. - static inline bool IsBrowserProcess() { return v8::Locker::WasEverUsed(); } + static inline bool IsBrowserProcess() { return g_is_browser_process; } + + static void SetIsBrowserProcess(bool is_browser_process); private: void* operator new(size_t size); void operator delete(void*, size_t); std::unique_ptr locker_; + + static bool g_is_browser_process; }; } // namespace gin_helper diff --git a/shell/common/gin_helper/pinnable.h b/shell/common/gin_helper/pinnable.h index 42b98f55179d8..a5e5f68cc6236 100644 --- a/shell/common/gin_helper/pinnable.h +++ b/shell/common/gin_helper/pinnable.h @@ -14,7 +14,6 @@ class Pinnable { protected: // Prevent the object from being garbage collected until Unpin() is called. void Pin(v8::Isolate* isolate) { - v8::Locker locker(isolate); v8::HandleScope scope(isolate); v8::Local wrapper; if (static_cast(this)->GetWrapper(isolate).ToLocal(&wrapper)) { diff --git a/shell/common/gin_helper/promise.cc b/shell/common/gin_helper/promise.cc index e17881ef2c4a6..bc34dfa6310b9 100644 --- a/shell/common/gin_helper/promise.cc +++ b/shell/common/gin_helper/promise.cc @@ -24,7 +24,6 @@ PromiseBase::~PromiseBase() = default; PromiseBase& PromiseBase::operator=(PromiseBase&&) = default; v8::Maybe PromiseBase::Reject() { - gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); @@ -33,7 +32,6 @@ v8::Maybe PromiseBase::Reject() { } v8::Maybe PromiseBase::Reject(v8::Local except) { - gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); @@ -42,7 +40,6 @@ v8::Maybe PromiseBase::Reject(v8::Local except) { } v8::Maybe PromiseBase::RejectWithErrorMessage(base::StringPiece message) { - gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); @@ -68,8 +65,8 @@ v8::Local PromiseBase::GetInner() const { void Promise::ResolvePromise(Promise promise) { if (gin_helper::Locker::IsBrowserProcess() && !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce([](Promise promise) { promise.Resolve(); }, std::move(promise))); } else { @@ -85,7 +82,6 @@ v8::Local Promise::ResolvedPromise(v8::Isolate* isolate) { } v8::Maybe Promise::Resolve() { - gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); diff --git a/shell/common/gin_helper/promise.h b/shell/common/gin_helper/promise.h index 961ce961a65e3..c720b588d7718 100644 --- a/shell/common/gin_helper/promise.h +++ b/shell/common/gin_helper/promise.h @@ -11,7 +11,6 @@ #include #include "base/strings/string_piece.h" -#include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "shell/common/gin_converters/std_converter.h" @@ -48,8 +47,8 @@ class PromiseBase { static void RejectPromise(PromiseBase&& promise, base::StringPiece errmsg) { if (gin_helper::Locker::IsBrowserProcess() && !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - base::PostTask( - FROM_HERE, {content::BrowserThread::UI}, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( // Note that this callback can not take StringPiece, // as StringPiece only references string internally and @@ -91,8 +90,8 @@ class Promise : public PromiseBase { static void ResolvePromise(Promise promise, RT result) { if (gin_helper::Locker::IsBrowserProcess() && !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - base::PostTask(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce([](Promise promise, + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce([](Promise promise, RT result) { promise.Resolve(result); }, std::move(promise), std::move(result))); } else { diff --git a/shell/common/key_weak_map.h b/shell/common/key_weak_map.h index 09111d48dcd02..038349b8e9661 100644 --- a/shell/common/key_weak_map.h +++ b/shell/common/key_weak_map.h @@ -50,7 +50,7 @@ class KeyWeakMap { return v8::Local::New(isolate, iter->second.second); } - // Whethere there is an object with |key| in this WeakMap. + // Whether there is an object with |key| in this WeakMap. bool Has(const K& key) const { return map_.find(key) != map_.end(); } // Returns all objects. diff --git a/shell/common/logging.cc b/shell/common/logging.cc index a74702c7e5a93..5a109d9798ac4 100644 --- a/shell/common/logging.cc +++ b/shell/common/logging.cc @@ -141,7 +141,7 @@ void InitElectronLogging(const base::CommandLine& command_line, : APPEND_TO_OLD_LOG_FILE; bool success = InitLogging(settings); if (!success) { - PLOG(FATAL) << "Failed to init logging"; + PLOG(ERROR) << "Failed to init logging"; } SetLogItems(true /* pid */, false, true /* timestamp */, false); diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index b0e628093d48b..f6b548215fdc6 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -37,6 +37,7 @@ #include "shell/common/mac/main_application_bundle.h" #include "shell/common/node_includes.h" #include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h" // nogncheck +#include "third_party/electron_node/src/debug_utils.h" #if !defined(MAS_BUILD) #include "shell/common/crash_keys.h" @@ -55,13 +56,17 @@ V(electron_browser_in_app_purchase) \ V(electron_browser_menu) \ V(electron_browser_message_port) \ + V(electron_browser_native_theme) \ V(electron_browser_net) \ + V(electron_browser_notification) \ V(electron_browser_power_monitor) \ V(electron_browser_power_save_blocker) \ V(electron_browser_protocol) \ V(electron_browser_printing) \ + V(electron_browser_push_notifications) \ V(electron_browser_safe_storage) \ V(electron_browser_session) \ + V(electron_browser_screen) \ V(electron_browser_system_preferences) \ V(electron_browser_base_window) \ V(electron_browser_tray) \ @@ -77,9 +82,6 @@ V(electron_common_environment) \ V(electron_common_features) \ V(electron_common_native_image) \ - V(electron_common_native_theme) \ - V(electron_common_notification) \ - V(electron_common_screen) \ V(electron_common_shell) \ V(electron_common_v8_util) \ V(electron_renderer_context_bridge) \ @@ -135,6 +137,7 @@ void stop_and_close_uv_loop(uv_loop_t* loop) { break; DCHECK_EQ(0, uv_loop_alive(loop)); + node::CheckedUvLoopClose(loop); } bool g_is_initialized = false; @@ -322,6 +325,9 @@ NodeBindings::NodeBindings(BrowserEnvironment browser_env) } else { uv_loop_ = uv_default_loop(); } + + // Interrupt embed polling when a handle is started. + uv_loop_configure(uv_loop_, UV_LOOP_INTERRUPT_ON_IO_CHANGE); } NodeBindings::~NodeBindings() { @@ -365,7 +371,6 @@ bool NodeBindings::IsInitialized() { void NodeBindings::Initialize() { TRACE_EVENT0("electron", "NodeBindings::Initialize"); // Open node's error reporting system for browser process. - node::g_upstream_node_mode = false; #if BUILDFLAG(IS_LINUX) // Get real command line in renderer process forked by zygote. @@ -381,14 +386,17 @@ void NodeBindings::Initialize() { auto env = base::Environment::Create(); SetNodeOptions(env.get()); - node::Environment::should_read_node_options_from_env_ = - fuses::IsNodeOptionsEnabled(); std::vector argv = {"electron"}; std::vector exec_argv; std::vector errors; + uint64_t process_flags = node::ProcessFlags::kEnableStdioInheritance; + if (!fuses::IsNodeOptionsEnabled()) + process_flags |= node::ProcessFlags::kDisableNodeOptionsEnv; - int exit_code = node::InitializeNodeWithArgs(&argv, &exec_argv, &errors); + int exit_code = node::InitializeNodeWithArgs( + &argv, &exec_argv, &errors, + static_cast(process_flags)); for (const std::string& error : errors) fprintf(stderr, "%s: %s\n", argv[0].c_str(), error.c_str()); @@ -475,26 +483,35 @@ node::Environment* NodeBindings::CreateEnvironment( // in renderer processes this should be blink. We need to tell Node.js // not to register its handler (overriding blinks) in non-browser processes. flags |= node::EnvironmentFlags::kNoRegisterESMLoader | - node::EnvironmentFlags::kNoInitializeInspector; - v8::TryCatch try_catch(context->GetIsolate()); + node::EnvironmentFlags::kNoCreateInspector; + } + + if (!electron::fuses::IsNodeCliInspectEnabled()) { + // If --inspect and friends are disabled we also shouldn't listen for + // SIGUSR1 + flags |= node::EnvironmentFlags::kNoStartDebugSignalHandler; + } + + { + v8::TryCatch try_catch(isolate); env = node::CreateEnvironment( isolate_data_, context, args, exec_args, static_cast(flags)); - DCHECK(env); - // This will only be caught when something has gone terrible wrong as all - // electron scripts are wrapped in a try {} catch {} by webpack if (try_catch.HasCaught()) { - LOG(ERROR) << "Failed to initialize node environment in process: " - << process_type; + std::string err_msg = + "Failed to initialize node environment in process: " + process_type; + v8::Local message = try_catch.Message(); + std::string msg; + if (!message.IsEmpty() && + gin::ConvertFromV8(isolate, message->Get(), &msg)) + err_msg += " , with error: " + msg; + LOG(ERROR) << err_msg; } - } else { - env = node::CreateEnvironment( - isolate_data_, context, args, exec_args, - static_cast(flags)); - DCHECK(env); } + DCHECK(env); + // Clean up the global _noBrowserGlobals that we unironically injected into // the global scope if (browser_env_ != BrowserEnvironment::kBrowser) { @@ -573,7 +590,16 @@ void NodeBindings::LoadEnvironment(node::Environment* env) { gin_helper::EmitEvent(env->isolate(), env->process_object(), "loaded"); } -void NodeBindings::PrepareMessageLoop() { +void NodeBindings::PrepareEmbedThread() { + // IOCP does not change for the process until the loop is recreated, + // we ensure that there is only a single polling thread satisfying + // the concurrency limit set from CreateIoCompletionPort call by + // uv_loop_init for the lifetime of this process. + // More background can be found at: + // https://github.com/microsoft/vscode/issues/142786#issuecomment-1061673400 + if (initialized_) + return; + // Add dummy handle for libuv, otherwise libuv would quit when there is // nothing to do. uv_async_init(uv_loop_, dummy_uv_handle_.get(), nullptr); @@ -583,7 +609,15 @@ void NodeBindings::PrepareMessageLoop() { uv_thread_create(&embed_thread_, EmbedThreadRunner, this); } -void NodeBindings::RunMessageLoop() { +void NodeBindings::StartPolling() { + // Avoid calling UvRunOnce if the loop is already active, + // otherwise it can lead to situations were the number of active + // threads processing on IOCP is greater than the concurrency limit. + if (initialized_) + return; + + initialized_ = true; + // The MessageLoop should have been created, remember the one in main thread. task_runner_ = base::ThreadTaskRunnerHandle::Get(); @@ -600,8 +634,6 @@ void NodeBindings::UvRunOnce() { if (!env) return; - // Use Locker in browser process. - gin_helper::Locker locker(env->isolate()); v8::HandleScope handle_scope(env->isolate()); // Enter node context while dealing with uv events. diff --git a/shell/common/node_bindings.h b/shell/common/node_bindings.h index 204cf12d5cc6c..54bed07a39aab 100644 --- a/shell/common/node_bindings.h +++ b/shell/common/node_bindings.h @@ -92,11 +92,11 @@ class NodeBindings { // Load node.js in the environment. void LoadEnvironment(node::Environment* env); - // Prepare for message loop integration. - virtual void PrepareMessageLoop(); + // Prepare embed thread for message loop integration. + void PrepareEmbedThread(); - // Do message loop integration. - virtual void RunMessageLoop(); + // Notify embed thread to start polling after environment is loaded. + void StartPolling(); // Gets/sets the per isolate data. void set_isolate_data(node::IsolateData* isolate_data) { @@ -144,6 +144,9 @@ class NodeBindings { // Thread to poll uv events. static void EmbedThreadRunner(void* arg); + // Indicates whether polling thread has been created. + bool initialized_ = false; + // Whether the libuv loop has ended. bool embed_closed_ = false; diff --git a/shell/common/node_bindings_linux.cc b/shell/common/node_bindings_linux.cc index d361daec953e0..5fc157da00e58 100644 --- a/shell/common/node_bindings_linux.cc +++ b/shell/common/node_bindings_linux.cc @@ -17,43 +17,6 @@ NodeBindingsLinux::NodeBindingsLinux(BrowserEnvironment browser_env) epoll_ctl(epoll_, EPOLL_CTL_ADD, backend_fd, &ev); } -NodeBindingsLinux::~NodeBindingsLinux() = default; - -void NodeBindingsLinux::PrepareMessageLoop() { - int handle = uv_backend_fd(uv_loop_); - - // If the backend fd hasn't changed, don't proceed. - if (handle == handle_) - return; - - NodeBindings::PrepareMessageLoop(); -} - -void NodeBindingsLinux::RunMessageLoop() { - int handle = uv_backend_fd(uv_loop_); - - // If the backend fd hasn't changed, don't proceed. - if (handle == handle_) - return; - - handle_ = handle; - - // Get notified when libuv's watcher queue changes. - uv_loop_->data = this; - uv_loop_->on_watcher_queue_updated = OnWatcherQueueChanged; - - NodeBindings::RunMessageLoop(); -} - -// static -void NodeBindingsLinux::OnWatcherQueueChanged(uv_loop_t* loop) { - NodeBindingsLinux* self = static_cast(loop->data); - - // We need to break the io polling in the epoll thread when loop's watcher - // queue changes, otherwise new events cannot be notified. - self->WakeupEmbedThread(); -} - void NodeBindingsLinux::PollEvents() { int timeout = uv_backend_timeout(uv_loop_); diff --git a/shell/common/node_bindings_linux.h b/shell/common/node_bindings_linux.h index 934ed68c597b8..db8a8ed32ad58 100644 --- a/shell/common/node_bindings_linux.h +++ b/shell/common/node_bindings_linux.h @@ -13,22 +13,12 @@ namespace electron { class NodeBindingsLinux : public NodeBindings { public: explicit NodeBindingsLinux(BrowserEnvironment browser_env); - ~NodeBindingsLinux() override; - - void PrepareMessageLoop() override; - void RunMessageLoop() override; private: - // Called when uv's watcher queue changes. - static void OnWatcherQueueChanged(uv_loop_t* loop); - void PollEvents() override; // Epoll to poll for uv's backend fd. int epoll_; - - // uv's backend fd. - int handle_ = -1; }; } // namespace electron diff --git a/shell/common/node_bindings_mac.cc b/shell/common/node_bindings_mac.cc index 7107d20c11b93..fe9b0d6986196 100644 --- a/shell/common/node_bindings_mac.cc +++ b/shell/common/node_bindings_mac.cc @@ -17,43 +17,6 @@ namespace electron { NodeBindingsMac::NodeBindingsMac(BrowserEnvironment browser_env) : NodeBindings(browser_env) {} -NodeBindingsMac::~NodeBindingsMac() = default; - -void NodeBindingsMac::PrepareMessageLoop() { - int handle = uv_backend_fd(uv_loop_); - - // If the backend fd hasn't changed, don't proceed. - if (handle == handle_) - return; - - NodeBindings::PrepareMessageLoop(); -} - -void NodeBindingsMac::RunMessageLoop() { - int handle = uv_backend_fd(uv_loop_); - - // If the backend fd hasn't changed, don't proceed. - if (handle == handle_) - return; - - handle_ = handle; - - // Get notified when libuv's watcher queue changes. - uv_loop_->data = this; - uv_loop_->on_watcher_queue_updated = OnWatcherQueueChanged; - - NodeBindings::RunMessageLoop(); -} - -// static -void NodeBindingsMac::OnWatcherQueueChanged(uv_loop_t* loop) { - NodeBindingsMac* self = static_cast(loop->data); - - // We need to break the io polling in the kqueue thread when loop's watcher - // queue changes, otherwise new events cannot be notified. - self->WakeupEmbedThread(); -} - void NodeBindingsMac::PollEvents() { struct timeval tv; int timeout = uv_backend_timeout(uv_loop_); diff --git a/shell/common/node_bindings_mac.h b/shell/common/node_bindings_mac.h index 7687f85a7b8d3..cae9540edbe7c 100644 --- a/shell/common/node_bindings_mac.h +++ b/shell/common/node_bindings_mac.h @@ -13,19 +13,9 @@ namespace electron { class NodeBindingsMac : public NodeBindings { public: explicit NodeBindingsMac(BrowserEnvironment browser_env); - ~NodeBindingsMac() override; - - void PrepareMessageLoop() override; - void RunMessageLoop() override; private: - // Called when uv's watcher queue changes. - static void OnWatcherQueueChanged(uv_loop_t* loop); - void PollEvents() override; - - // uv's backend fd. - int handle_ = -1; }; } // namespace electron diff --git a/shell/common/node_bindings_win.cc b/shell/common/node_bindings_win.cc index 1410925f195c5..9b2319cfdc86b 100644 --- a/shell/common/node_bindings_win.cc +++ b/shell/common/node_bindings_win.cc @@ -27,31 +27,6 @@ NodeBindingsWin::NodeBindingsWin(BrowserEnvironment browser_env) } } -NodeBindingsWin::~NodeBindingsWin() = default; - -void NodeBindingsWin::PrepareMessageLoop() { - // IOCP does not change for the process until the loop is recreated, - // we ensure that there is only a single polling thread satisfying - // the concurrency limit set from CreateIoCompletionPort call by - // uv_loop_init for the lifetime of this process. - if (initialized_) - return; - - NodeBindings::PrepareMessageLoop(); -} - -void NodeBindingsWin::RunMessageLoop() { - // Avoid calling UvRunOnce if the loop is already active, - // otherwise it can lead to situations were the number of active - // threads processing on IOCP is greater than the concurrency limit. - if (initialized_) - return; - - initialized_ = true; - - NodeBindings::RunMessageLoop(); -} - void NodeBindingsWin::PollEvents() { // If there are other kinds of events pending, uv_backend_timeout will // instruct us not to wait. diff --git a/shell/common/node_bindings_win.h b/shell/common/node_bindings_win.h index 59d7469b0ff75..a0dcd3378f909 100644 --- a/shell/common/node_bindings_win.h +++ b/shell/common/node_bindings_win.h @@ -13,16 +13,9 @@ namespace electron { class NodeBindingsWin : public NodeBindings { public: explicit NodeBindingsWin(BrowserEnvironment browser_env); - ~NodeBindingsWin() override; - - void PrepareMessageLoop() override; - void RunMessageLoop() override; private: void PollEvents() override; - - // Indicates whether polling thread has been created. - bool initialized_ = false; }; } // namespace electron diff --git a/shell/common/node_util.cc b/shell/common/node_util.cc index 09ae24a66ee89..7cee76b7c4fa8 100644 --- a/shell/common/node_util.cc +++ b/shell/common/node_util.cc @@ -7,9 +7,7 @@ #include "base/logging.h" #include "shell/common/node_includes.h" -namespace electron { - -namespace util { +namespace electron::util { v8::MaybeLocal CompileAndCall( v8::Local context, @@ -36,6 +34,4 @@ v8::MaybeLocal CompileAndCall( return ret; } -} // namespace util - -} // namespace electron +} // namespace electron::util diff --git a/shell/common/node_util.h b/shell/common/node_util.h index fd7db87a46937..e8cc05370c9af 100644 --- a/shell/common/node_util.h +++ b/shell/common/node_util.h @@ -13,9 +13,7 @@ namespace node { class Environment; } -namespace electron { - -namespace util { +namespace electron::util { // Run a script with JS source bundled inside the binary as if it's wrapped // in a function called with a null receiver and arguments specified in C++. @@ -29,8 +27,6 @@ v8::MaybeLocal CompileAndCall( std::vector>* arguments, node::Environment* optional_env); -} // namespace util - -} // namespace electron +} // namespace electron::util #endif // ELECTRON_SHELL_COMMON_NODE_UTIL_H_ diff --git a/shell/common/options_switches.cc b/shell/common/options_switches.cc index 5ae559c437eb9..94ffb637ff124 100644 --- a/shell/common/options_switches.cc +++ b/shell/common/options_switches.cc @@ -120,9 +120,6 @@ const char kPreloadScript[] = "preload"; const char kPreloadScripts[] = "preloadScripts"; -// Like --preload, but the passed argument is an URL. -const char kPreloadURL[] = "preloadURL"; - // Enable the node integration. const char kNodeIntegration[] = "nodeIntegration"; diff --git a/shell/common/options_switches.h b/shell/common/options_switches.h index cfe8a4a191ccc..d8f4819067911 100644 --- a/shell/common/options_switches.h +++ b/shell/common/options_switches.h @@ -66,7 +66,6 @@ extern const char kOverlayHeight[]; extern const char kZoomFactor[]; extern const char kPreloadScript[]; extern const char kPreloadScripts[]; -extern const char kPreloadURL[]; extern const char kNodeIntegration[]; extern const char kContextIsolation[]; extern const char kExperimentalFeatures[]; diff --git a/shell/common/platform_util.h b/shell/common/platform_util.h index ba8f9652dba29..085c7e3a7d926 100644 --- a/shell/common/platform_util.h +++ b/shell/common/platform_util.h @@ -56,6 +56,10 @@ bool SetLoginItemEnabled(bool enabled); // Returns a success flag. // Unlike libgtkui, does *not* use "chromium-browser.desktop" as a fallback. bool GetDesktopName(std::string* setme); + +// The XDG application ID must match the name of the desktop entry file without +// the .desktop extension. +std::string GetXdgAppId(); #endif } // namespace platform_util diff --git a/shell/common/platform_util_internal.h b/shell/common/platform_util_internal.h index 9a3681bed5ae6..3eaa80a7828a6 100644 --- a/shell/common/platform_util_internal.h +++ b/shell/common/platform_util_internal.h @@ -13,14 +13,12 @@ namespace base { class FilePath; } -namespace platform_util { -namespace internal { +namespace platform_util::internal { // Called by platform_util.cc on to invoke platform specific logic to move // |path| to trash using a suitable handler. bool PlatformTrashItem(const base::FilePath& path, std::string* error); -} // namespace internal -} // namespace platform_util +} // namespace platform_util::internal #endif // ELECTRON_SHELL_COMMON_PLATFORM_UTIL_INTERNAL_H_ diff --git a/shell/common/platform_util_linux.cc b/shell/common/platform_util_linux.cc index 11d455d6095fe..2018c6d8864bf 100644 --- a/shell/common/platform_util_linux.cc +++ b/shell/common/platform_util_linux.cc @@ -20,6 +20,7 @@ #include "base/posix/eintr_wrapper.h" #include "base/process/kill.h" #include "base/process/launch.h" +#include "base/strings/string_util.h" #include "base/threading/thread_restrictions.h" #include "components/dbus/thread_linux/dbus_thread_linux.h" #include "content/public/browser/browser_thread.h" @@ -119,7 +120,7 @@ class ShowItemHelper { bool owned = false; if (!reader.PopBool(&owned)) { - LOG(ERROR) << "Failed to read " << kMethodNameHasOwner << " resposne"; + LOG(ERROR) << "Failed to read " << kMethodNameHasOwner << " response"; } else if (owned) { is_running = true; } @@ -403,4 +404,18 @@ bool GetDesktopName(std::string* setme) { return base::Environment::Create()->GetVar("CHROME_DESKTOP", setme); } +std::string GetXdgAppId() { + std::string desktop_file_name; + if (GetDesktopName(&desktop_file_name)) { + const std::string kDesktopExtension{".desktop"}; + if (base::EndsWith(desktop_file_name, kDesktopExtension, + base::CompareCase::INSENSITIVE_ASCII)) { + desktop_file_name.resize(desktop_file_name.size() - + kDesktopExtension.size()); + } + } + + return desktop_file_name; +} + } // namespace platform_util diff --git a/shell/common/platform_util_win.cc b/shell/common/platform_util_win.cc index d85fb8167cee0..a89c1c42ba6ee 100644 --- a/shell/common/platform_util_win.cc +++ b/shell/common/platform_util_win.cc @@ -21,9 +21,9 @@ #include "base/files/file_util.h" #include "base/logging.h" #include "base/stl_util.h" +#include "base/strings/escape.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" #include "base/win/registry.h" @@ -32,7 +32,6 @@ #include "base/win/windows_version.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "net/base/escape.h" #include "shell/common/electron_paths.h" #include "ui/base/win/shell.h" #include "url/gurl.h" @@ -243,7 +242,7 @@ std::string OpenExternalOnWorkerThread( // parameters unexpected by the external program. This url should already // have been escaped. std::wstring escaped_url = - L"\"" + base::UTF8ToWide(net::EscapeExternalHandlerValue(url.spec())) + + L"\"" + base::UTF8ToWide(base::EscapeExternalHandlerValue(url.spec())) + L"\""; std::wstring working_dir = options.working_dir.value(); @@ -289,7 +288,7 @@ void ShowItemInFolderOnWorkerThread(const base::FilePath& full_path) { return; const ITEMIDLIST* highlight[] = {file_item}; - hr = SHOpenFolderAndSelectItems(dir_item, base::size(highlight), highlight, + hr = SHOpenFolderAndSelectItems(dir_item, std::size(highlight), highlight, NULL); if (FAILED(hr)) { // On some systems, the above call mysteriously fails with "file not diff --git a/shell/common/skia_util.cc b/shell/common/skia_util.cc index 63f42a13ab41c..eeeccbac5cfc1 100644 --- a/shell/common/skia_util.cc +++ b/shell/common/skia_util.cc @@ -21,15 +21,14 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/image/image_util.h" #if BUILDFLAG(IS_WIN) #include "ui/gfx/icon_util.h" #endif -namespace electron { - -namespace util { +namespace electron::util { struct ScaleFactorPair { const char* name; @@ -163,6 +162,4 @@ bool ReadImageSkiaFromICO(gfx::ImageSkia* image, HICON icon) { } #endif -} // namespace util - -} // namespace electron +} // namespace electron::util diff --git a/shell/common/skia_util.h b/shell/common/skia_util.h index 76830d8443689..2fd4376595d68 100644 --- a/shell/common/skia_util.h +++ b/shell/common/skia_util.h @@ -13,9 +13,7 @@ namespace gfx { class ImageSkia; } -namespace electron { - -namespace util { +namespace electron::util { bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image, const base::FilePath& path); @@ -41,8 +39,6 @@ bool AddImageSkiaRepFromPNG(gfx::ImageSkia* image, bool ReadImageSkiaFromICO(gfx::ImageSkia* image, HICON icon); #endif -} // namespace util - -} // namespace electron +} // namespace electron::util #endif // ELECTRON_SHELL_COMMON_SKIA_UTIL_H_ diff --git a/shell/common/v8_value_converter.cc b/shell/common/v8_value_converter.cc deleted file mode 100644 index 00235ec21057d..0000000000000 --- a/shell/common/v8_value_converter.cc +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "shell/common/v8_value_converter.h" - -#include -#include -#include -#include -#include - -#include "base/logging.h" -#include "base/values.h" -#include "shell/common/gin_helper/dictionary.h" -#include "shell/common/node_bindings.h" -#include "shell/common/node_includes.h" - -namespace electron { - -namespace { - -const int kMaxRecursionDepth = 100; - -} // namespace - -// The state of a call to FromV8Value. -class V8ValueConverter::FromV8ValueState { - public: - // Level scope which updates the current depth of some FromV8ValueState. - class Level { - public: - explicit Level(FromV8ValueState* state) : state_(state) { - state_->max_recursion_depth_--; - } - ~Level() { state_->max_recursion_depth_++; } - - private: - FromV8ValueState* state_; - }; - - FromV8ValueState() : max_recursion_depth_(kMaxRecursionDepth) {} - - // If |handle| is not in |unique_map_|, then add it to |unique_map_| and - // return true. - // - // Otherwise do nothing and return false. Here "A is unique" means that no - // other handle B in the map points to the same object as A. Note that A can - // be unique even if there already is another handle with the same identity - // hash (key) in the map, because two objects can have the same hash. - bool AddToUniquenessCheck(v8::Local handle) { - int hash; - auto iter = GetIteratorInMap(handle, &hash); - if (iter != unique_map_.end()) - return false; - - unique_map_.insert(std::make_pair(hash, handle)); - return true; - } - - bool RemoveFromUniquenessCheck(v8::Local handle) { - int unused_hash; - auto iter = GetIteratorInMap(handle, &unused_hash); - if (iter == unique_map_.end()) - return false; - unique_map_.erase(iter); - return true; - } - - bool HasReachedMaxRecursionDepth() { return max_recursion_depth_ < 0; } - - private: - using HashToHandleMap = std::multimap>; - using Iterator = HashToHandleMap::const_iterator; - - Iterator GetIteratorInMap(v8::Local handle, int* hash) { - *hash = handle->GetIdentityHash(); - // We only compare using == with handles to objects with the same identity - // hash. Different hash obviously means different objects, but two objects - // in a couple of thousands could have the same identity hash. - std::pair range = unique_map_.equal_range(*hash); - for (auto it = range.first; it != range.second; ++it) { - // Operator == for handles actually compares the underlying objects. - if (it->second == handle) - return it; - } - // Not found. - return unique_map_.end(); - } - - HashToHandleMap unique_map_; - - int max_recursion_depth_; -}; - -// A class to ensure that objects/arrays that are being converted by -// this V8ValueConverterImpl do not have cycles. -// -// An example of cycle: var v = {}; v = {key: v}; -// Not an example of cycle: var v = {}; a = [v, v]; or w = {a: v, b: v}; -class V8ValueConverter::ScopedUniquenessGuard { - public: - ScopedUniquenessGuard(V8ValueConverter::FromV8ValueState* state, - v8::Local value) - : state_(state), - value_(value), - is_valid_(state_->AddToUniquenessCheck(value_)) {} - ~ScopedUniquenessGuard() { - if (is_valid_) { - bool removed = state_->RemoveFromUniquenessCheck(value_); - DCHECK(removed); - } - } - - // disable copy - ScopedUniquenessGuard(const ScopedUniquenessGuard&) = delete; - ScopedUniquenessGuard& operator=(const ScopedUniquenessGuard&) = delete; - - bool is_valid() const { return is_valid_; } - - private: - typedef std::multimap> HashToHandleMap; - V8ValueConverter::FromV8ValueState* state_; - v8::Local value_; - bool is_valid_; -}; - -V8ValueConverter::V8ValueConverter() = default; - -void V8ValueConverter::SetRegExpAllowed(bool val) { - reg_exp_allowed_ = val; -} - -void V8ValueConverter::SetFunctionAllowed(bool val) { - function_allowed_ = val; -} - -void V8ValueConverter::SetStripNullFromObjects(bool val) { - strip_null_from_objects_ = val; -} - -v8::Local V8ValueConverter::ToV8Value( - const base::Value* value, - v8::Local context) const { - v8::Context::Scope context_scope(context); - v8::EscapableHandleScope handle_scope(context->GetIsolate()); - return handle_scope.Escape(ToV8ValueImpl(context->GetIsolate(), value)); -} - -std::unique_ptr V8ValueConverter::FromV8Value( - v8::Local val, - v8::Local context) const { - v8::Context::Scope context_scope(context); - v8::HandleScope handle_scope(context->GetIsolate()); - FromV8ValueState state; - return FromV8ValueImpl(&state, val, context->GetIsolate()); -} - -v8::Local V8ValueConverter::ToV8ValueImpl( - v8::Isolate* isolate, - const base::Value* value) const { - switch (value->type()) { - case base::Value::Type::NONE: - return v8::Null(isolate); - - case base::Value::Type::BOOLEAN: { - bool val = value->GetBool(); - return v8::Boolean::New(isolate, val); - } - - case base::Value::Type::INTEGER: { - int val = value->GetInt(); - return v8::Integer::New(isolate, val); - } - - case base::Value::Type::DOUBLE: { - double val = value->GetDouble(); - return v8::Number::New(isolate, val); - } - - case base::Value::Type::STRING: { - std::string val = value->GetString(); - return v8::String::NewFromUtf8(isolate, val.c_str(), - v8::NewStringType::kNormal, val.length()) - .ToLocalChecked(); - } - - case base::Value::Type::LIST: - return ToV8Array(isolate, static_cast(value)); - - case base::Value::Type::DICTIONARY: - return ToV8Object(isolate, - static_cast(value)); - - case base::Value::Type::BINARY: - return ToArrayBuffer(isolate, static_cast(value)); - - default: - LOG(ERROR) << "Unexpected value type: " << value->type(); - return v8::Null(isolate); - } -} - -v8::Local V8ValueConverter::ToV8Array( - v8::Isolate* isolate, - const base::ListValue* val) const { - v8::Local result( - v8::Array::New(isolate, val->GetListDeprecated().size())); - auto context = isolate->GetCurrentContext(); - - for (size_t i = 0; i < val->GetListDeprecated().size(); ++i) { - const base::Value& child = val->GetListDeprecated()[i]; - - v8::Local child_v8 = ToV8ValueImpl(isolate, &child); - - v8::TryCatch try_catch(isolate); - result->Set(context, static_cast(i), child_v8).Check(); - if (try_catch.HasCaught()) - LOG(ERROR) << "Setter for index " << i << " threw an exception."; - } - - return result; -} - -v8::Local V8ValueConverter::ToV8Object( - v8::Isolate* isolate, - const base::DictionaryValue* val) const { - gin_helper::Dictionary result = gin::Dictionary::CreateEmpty(isolate); - result.SetHidden("simple", true); - - for (base::DictionaryValue::Iterator iter(*val); !iter.IsAtEnd(); - iter.Advance()) { - const std::string& key = iter.key(); - v8::Local child_v8 = ToV8ValueImpl(isolate, &iter.value()); - - v8::TryCatch try_catch(isolate); - result.Set(key, child_v8); - if (try_catch.HasCaught()) { - LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " - << "exception."; - } - } - - return result.GetHandle(); -} - -v8::Local V8ValueConverter::ToArrayBuffer( - v8::Isolate* isolate, - const base::Value* value) const { - const auto* data = reinterpret_cast(value->GetBlob().data()); - size_t length = value->GetBlob().size(); - - if (NodeBindings::IsInitialized()) { - return node::Buffer::Copy(isolate, data, length).ToLocalChecked(); - } - - if (length > node::Buffer::kMaxLength) { - return v8::Local(); - } - auto context = isolate->GetCurrentContext(); - auto array_buffer = v8::ArrayBuffer::New(isolate, length); - std::shared_ptr backing_store = - array_buffer->GetBackingStore(); - memcpy(backing_store->Data(), data, length); - // From this point, if something goes wrong(can't find Buffer class for - // example) we'll simply return a Uint8Array based on the created ArrayBuffer. - // This can happen if no preload script was specified to the renderer. - gin_helper::Dictionary global(isolate, context->Global()); - v8::Local buffer_value; - - // Get the Buffer class stored as a hidden value in the global object. We'll - // use it return a browserified Buffer. - if (!global.GetHidden("Buffer", &buffer_value) || - !buffer_value->IsFunction()) { - return v8::Uint8Array::New(array_buffer, 0, length); - } - - gin::Dictionary buffer_class( - isolate, - buffer_value->ToObject(isolate->GetCurrentContext()).ToLocalChecked()); - v8::Local from_value; - if (!buffer_class.Get("from", &from_value) || !from_value->IsFunction()) { - return v8::Uint8Array::New(array_buffer, 0, length); - } - - v8::Local args[] = {array_buffer}; - auto func = from_value.As(); - auto result = func->Call(context, v8::Null(isolate), 1, args); - if (!result.IsEmpty()) { - return result.ToLocalChecked(); - } - - return v8::Uint8Array::New(array_buffer, 0, length); -} - -std::unique_ptr V8ValueConverter::FromV8ValueImpl( - FromV8ValueState* state, - v8::Local val, - v8::Isolate* isolate) const { - FromV8ValueState::Level state_level(state); - if (state->HasReachedMaxRecursionDepth()) - return nullptr; - - if (val->IsExternal()) - return std::make_unique(); - - if (val->IsNull()) - return std::make_unique(); - - auto context = isolate->GetCurrentContext(); - - if (val->IsBoolean()) - return std::make_unique(val->ToBoolean(isolate)->Value()); - - if (val->IsInt32()) - return std::make_unique(val.As()->Value()); - - if (val->IsNumber()) { - double val_as_double = val.As()->Value(); - if (!std::isfinite(val_as_double)) - return nullptr; - return std::make_unique(val_as_double); - } - - if (val->IsString()) { - v8::String::Utf8Value utf8(isolate, val); - return std::make_unique(std::string(*utf8, utf8.length())); - } - - if (val->IsUndefined()) - // JSON.stringify ignores undefined. - return nullptr; - - if (val->IsDate()) { - v8::Date* date = v8::Date::Cast(*val); - v8::Local toISOString = - date->Get(context, v8::String::NewFromUtf8(isolate, "toISOString", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .ToLocalChecked(); - if (toISOString->IsFunction()) { - v8::MaybeLocal result = - toISOString.As()->Call(context, val, 0, nullptr); - if (!result.IsEmpty()) { - v8::String::Utf8Value utf8(isolate, result.ToLocalChecked()); - return std::make_unique(std::string(*utf8, utf8.length())); - } - } - } - - if (val->IsRegExp()) { - if (!reg_exp_allowed_) - // JSON.stringify converts to an object. - return FromV8Object(val.As(), state, isolate); - return std::make_unique(*v8::String::Utf8Value(isolate, val)); - } - - // v8::Value doesn't have a ToArray() method for some reason. - if (val->IsArray()) - return FromV8Array(val.As(), state, isolate); - - if (val->IsFunction()) { - if (!function_allowed_) - // JSON.stringify refuses to convert function(){}. - return nullptr; - return FromV8Object(val.As(), state, isolate); - } - - if (node::Buffer::HasInstance(val)) { - return FromNodeBuffer(val, state, isolate); - } - - if (val->IsObject()) { - return FromV8Object(val.As(), state, isolate); - } - - LOG(ERROR) << "Unexpected v8 value type encountered."; - return nullptr; -} - -std::unique_ptr V8ValueConverter::FromV8Array( - v8::Local val, - FromV8ValueState* state, - v8::Isolate* isolate) const { - ScopedUniquenessGuard uniqueness_guard(state, val); - if (!uniqueness_guard.is_valid()) - return std::make_unique(); - - std::unique_ptr scope; - // If val was created in a different context than our current one, change to - // that context, but change back after val is converted. - if (!val->CreationContext().IsEmpty() && - val->CreationContext() != isolate->GetCurrentContext()) - scope = std::make_unique(val->CreationContext()); - - auto result = std::make_unique(); - - // Only fields with integer keys are carried over to the ListValue. - for (uint32_t i = 0; i < val->Length(); ++i) { - v8::TryCatch try_catch(isolate); - v8::Local child_v8; - v8::MaybeLocal maybe_child = - val->Get(isolate->GetCurrentContext(), i); - if (try_catch.HasCaught() || !maybe_child.ToLocal(&child_v8)) { - LOG(ERROR) << "Getter for index " << i << " threw an exception."; - child_v8 = v8::Null(isolate); - } - - if (!val->HasRealIndexedProperty(isolate->GetCurrentContext(), i) - .FromMaybe(false)) { - result->Append(std::make_unique()); - continue; - } - - std::unique_ptr child = - FromV8ValueImpl(state, child_v8, isolate); - if (child) - result->Append(std::move(child)); - else - // JSON.stringify puts null in places where values don't serialize, for - // example undefined and functions. Emulate that behavior. - result->Append(std::make_unique()); - } - return std::move(result); -} - -std::unique_ptr V8ValueConverter::FromNodeBuffer( - v8::Local value, - FromV8ValueState* state, - v8::Isolate* isolate) const { - std::vector buffer( - node::Buffer::Data(value), - node::Buffer::Data(value) + node::Buffer::Length(value)); - return std::make_unique(std::move(buffer)); -} - -std::unique_ptr V8ValueConverter::FromV8Object( - v8::Local val, - FromV8ValueState* state, - v8::Isolate* isolate) const { - ScopedUniquenessGuard uniqueness_guard(state, val); - if (!uniqueness_guard.is_valid()) - return std::make_unique(); - - std::unique_ptr scope; - // If val was created in a different context than our current one, change to - // that context, but change back after val is converted. - if (!val->CreationContext().IsEmpty() && - val->CreationContext() != isolate->GetCurrentContext()) - scope = std::make_unique(val->CreationContext()); - - auto result = std::make_unique(); - v8::Local property_names; - if (!val->GetOwnPropertyNames(isolate->GetCurrentContext()) - .ToLocal(&property_names)) { - return std::move(result); - } - - for (uint32_t i = 0; i < property_names->Length(); ++i) { - v8::Local key = - property_names->Get(isolate->GetCurrentContext(), i).ToLocalChecked(); - - // Extend this test to cover more types as necessary and if sensible. - if (!key->IsString() && !key->IsNumber()) { - NOTREACHED() << "Key \"" << *v8::String::Utf8Value(isolate, key) - << "\" " - "is neither a string nor a number"; - continue; - } - - v8::String::Utf8Value name_utf8(isolate, key); - - v8::TryCatch try_catch(isolate); - v8::Local child_v8; - v8::MaybeLocal maybe_child = - val->Get(isolate->GetCurrentContext(), key); - if (try_catch.HasCaught() || !maybe_child.ToLocal(&child_v8)) { - LOG(ERROR) << "Getter for property " << *name_utf8 - << " threw an exception."; - child_v8 = v8::Null(isolate); - } - - std::unique_ptr child = - FromV8ValueImpl(state, child_v8, isolate); - if (!child) - // JSON.stringify skips properties whose values don't serialize, for - // example undefined and functions. Emulate that behavior. - continue; - - // Strip null if asked (and since undefined is turned into null, undefined - // too). The use case for supporting this is JSON-schema support, - // specifically for extensions, where "optional" JSON properties may be - // represented as null, yet due to buggy legacy code elsewhere isn't - // treated as such (potentially causing crashes). For example, the - // "tabs.create" function takes an object as its first argument with an - // optional "windowId" property. - // - // Given just - // - // tabs.create({}) - // - // this will work as expected on code that only checks for the existence of - // a "windowId" property (such as that legacy code). However given - // - // tabs.create({windowId: null}) - // - // there *is* a "windowId" property, but since it should be an int, code - // on the browser which doesn't additionally check for null will fail. - // We can avoid all bugs related to this by stripping null. - if (strip_null_from_objects_ && child->is_none()) - continue; - - result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), - std::move(child)); - } - - return std::move(result); -} - -} // namespace electron diff --git a/shell/common/v8_value_converter.h b/shell/common/v8_value_converter.h deleted file mode 100644 index 5a1c5e21b90c0..0000000000000 --- a/shell/common/v8_value_converter.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ELECTRON_SHELL_COMMON_V8_VALUE_CONVERTER_H_ -#define ELECTRON_SHELL_COMMON_V8_VALUE_CONVERTER_H_ - -#include - -#include "base/compiler_specific.h" -#include "v8/include/v8.h" - -namespace base { -class DictionaryValue; -class ListValue; -class Value; -} // namespace base - -namespace electron { - -class V8ValueConverter { - public: - V8ValueConverter(); - - // disable copy - V8ValueConverter(const V8ValueConverter&) = delete; - V8ValueConverter& operator=(const V8ValueConverter&) = delete; - - void SetRegExpAllowed(bool val); - void SetFunctionAllowed(bool val); - void SetStripNullFromObjects(bool val); - v8::Local ToV8Value(const base::Value* value, - v8::Local context) const; - std::unique_ptr FromV8Value( - v8::Local value, - v8::Local context) const; - - private: - class FromV8ValueState; - class ScopedUniquenessGuard; - - v8::Local ToV8ValueImpl(v8::Isolate* isolate, - const base::Value* value) const; - v8::Local ToV8Array(v8::Isolate* isolate, - const base::ListValue* list) const; - v8::Local ToV8Object( - v8::Isolate* isolate, - const base::DictionaryValue* dictionary) const; - v8::Local ToArrayBuffer(v8::Isolate* isolate, - const base::Value* value) const; - - std::unique_ptr FromV8ValueImpl(FromV8ValueState* state, - v8::Local value, - v8::Isolate* isolate) const; - std::unique_ptr FromV8Array(v8::Local array, - FromV8ValueState* state, - v8::Isolate* isolate) const; - std::unique_ptr FromNodeBuffer(v8::Local value, - FromV8ValueState* state, - v8::Isolate* isolate) const; - std::unique_ptr FromV8Object(v8::Local object, - FromV8ValueState* state, - v8::Isolate* isolate) const; - - // If true, we will convert RegExp JavaScript objects to string. - bool reg_exp_allowed_ = false; - - // If true, we will convert Function JavaScript objects to dictionaries. - bool function_allowed_ = false; - - // If true, undefined and null values are ignored when converting v8 objects - // into Values. - bool strip_null_from_objects_ = false; -}; - -} // namespace electron - -#endif // ELECTRON_SHELL_COMMON_V8_VALUE_CONVERTER_H_ diff --git a/shell/common/v8_value_serializer.h b/shell/common/v8_value_serializer.h index b75ed82a3228b..958677581bd47 100644 --- a/shell/common/v8_value_serializer.h +++ b/shell/common/v8_value_serializer.h @@ -6,6 +6,7 @@ #define ELECTRON_SHELL_COMMON_V8_VALUE_SERIALIZER_H_ #include "base/containers/span.h" +#include "ui/gfx/image/image_skia_rep.h" namespace v8 { class Isolate; diff --git a/shell/renderer/api/context_bridge/object_cache.cc b/shell/renderer/api/context_bridge/object_cache.cc index 928124bab451a..47870fd95ec70 100644 --- a/shell/renderer/api/context_bridge/object_cache.cc +++ b/shell/renderer/api/context_bridge/object_cache.cc @@ -8,11 +8,7 @@ #include "shell/common/api/object_life_monitor.h" -namespace electron { - -namespace api { - -namespace context_bridge { +namespace electron::api::context_bridge { ObjectCache::ObjectCache() = default; ObjectCache::~ObjectCache() = default; @@ -50,8 +46,4 @@ v8::MaybeLocal ObjectCache::GetCachedProxiedObject( return v8::MaybeLocal(); } -} // namespace context_bridge - -} // namespace api - -} // namespace electron +} // namespace electron::api::context_bridge diff --git a/shell/renderer/api/context_bridge/object_cache.h b/shell/renderer/api/context_bridge/object_cache.h index 4d6a2dbd2f95e..2039e061378eb 100644 --- a/shell/renderer/api/context_bridge/object_cache.h +++ b/shell/renderer/api/context_bridge/object_cache.h @@ -15,11 +15,7 @@ #include "shell/renderer/electron_render_frame_observer.h" #include "third_party/blink/public/web/web_local_frame.h" -namespace electron { - -namespace api { - -namespace context_bridge { +namespace electron::api::context_bridge { using ObjectCachePair = std::pair, v8::Local>; @@ -38,10 +34,6 @@ class ObjectCache final { std::unordered_map> proxy_map_; }; -} // namespace context_bridge - -} // namespace api - -} // namespace electron +} // namespace electron::api::context_bridge #endif // ELECTRON_SHELL_RENDERER_API_CONTEXT_BRIDGE_OBJECT_CACHE_H_ diff --git a/shell/renderer/api/electron_api_context_bridge.cc b/shell/renderer/api/electron_api_context_bridge.cc index f1e93b724e993..22f8c0adada0d 100644 --- a/shell/renderer/api/electron_api_context_bridge.cc +++ b/shell/renderer/api/electron_api_context_bridge.cc @@ -188,7 +188,7 @@ v8::MaybeLocal PassValueToOtherContext( // creation context of the original method. If it's not we proceed // with the proxy logic if (maybe_original_fn.ToLocal(&proxy_func) && proxy_func->IsFunction() && - proxy_func.As()->CreationContext() == + proxy_func.As()->GetCreationContextChecked() == destination_context) { return v8::MaybeLocal(proxy_func); } @@ -408,7 +408,8 @@ void ProxyFunctionWrapper(const v8::FunctionCallbackInfo& info) { return; v8::Local func = func_value.As(); - v8::Local func_owning_context = func->CreationContext(); + v8::Local func_owning_context = + func->GetCreationContextChecked(); { v8::Context::Scope func_owning_context_scope(func_owning_context); @@ -636,9 +637,9 @@ void OverrideGlobalValueFromIsolatedWorld( { v8::Context::Scope main_context_scope(main_context); context_bridge::ObjectCache object_cache; - v8::MaybeLocal maybe_proxy = - PassValueToOtherContext(value->CreationContext(), main_context, value, - &object_cache, support_dynamic_properties, 1); + v8::MaybeLocal maybe_proxy = PassValueToOtherContext( + value->GetCreationContextChecked(), main_context, value, &object_cache, + support_dynamic_properties, 1); DCHECK(!maybe_proxy.IsEmpty()); auto proxy = maybe_proxy.ToLocalChecked(); @@ -672,16 +673,16 @@ bool OverrideGlobalPropertyFromIsolatedWorld( v8::Local getter_proxy; v8::Local setter_proxy; if (!getter->IsNullOrUndefined()) { - v8::MaybeLocal maybe_getter_proxy = - PassValueToOtherContext(getter->CreationContext(), main_context, - getter, &object_cache, false, 1); + v8::MaybeLocal maybe_getter_proxy = PassValueToOtherContext( + getter->GetCreationContextChecked(), main_context, getter, + &object_cache, false, 1); DCHECK(!maybe_getter_proxy.IsEmpty()); getter_proxy = maybe_getter_proxy.ToLocalChecked(); } if (!setter->IsNullOrUndefined() && setter->IsObject()) { - v8::MaybeLocal maybe_setter_proxy = - PassValueToOtherContext(getter->CreationContext(), main_context, - setter, &object_cache, false, 1); + v8::MaybeLocal maybe_setter_proxy = PassValueToOtherContext( + getter->GetCreationContextChecked(), main_context, setter, + &object_cache, false, 1); DCHECK(!maybe_setter_proxy.IsEmpty()); setter_proxy = maybe_setter_proxy.ToLocalChecked(); } diff --git a/shell/renderer/api/electron_api_context_bridge.h b/shell/renderer/api/electron_api_context_bridge.h index 86f793904ebb9..bc60d2356a92c 100644 --- a/shell/renderer/api/electron_api_context_bridge.h +++ b/shell/renderer/api/electron_api_context_bridge.h @@ -12,9 +12,7 @@ namespace gin_helper { class Arguments; } -namespace electron { - -namespace api { +namespace electron::api { void ProxyFunctionWrapper(const v8::FunctionCallbackInfo& info); @@ -51,8 +49,6 @@ v8::MaybeLocal CreateProxyForAPI( bool support_dynamic_properties, int recursion_depth); -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_RENDERER_API_ELECTRON_API_CONTEXT_BRIDGE_H_ diff --git a/shell/renderer/api/electron_api_ipc_renderer.cc b/shell/renderer/api/electron_api_ipc_renderer.cc index 6f24ed17c4a3d..97f7010643b6d 100644 --- a/shell/renderer/api/electron_api_ipc_renderer.cc +++ b/shell/renderer/api/electron_api_ipc_renderer.cc @@ -4,7 +4,6 @@ #include -#include "base/task/post_task.h" #include "base/values.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame_observer.h" diff --git a/shell/renderer/api/electron_api_spell_check_client.cc b/shell/renderer/api/electron_api_spell_check_client.cc index 48d9e38e0d152..12d2e207bf06c 100644 --- a/shell/renderer/api/electron_api_spell_check_client.cc +++ b/shell/renderer/api/electron_api_spell_check_client.cc @@ -4,6 +4,7 @@ #include "shell/renderer/api/electron_api_spell_check_client.h" +#include #include #include #include @@ -21,9 +22,7 @@ #include "third_party/blink/public/web/web_text_checking_result.h" #include "third_party/icu/source/common/unicode/uscript.h" -namespace electron { - -namespace api { +namespace electron::api { namespace { @@ -229,7 +228,8 @@ void SpellCheckClient::SpellCheckWords(const SpellCheckScope& scope, v8::Local args[] = {gin::ConvertToV8(isolate_, words), templ->GetFunction(context).ToLocalChecked()}; // Call javascript with the words and the callback function - scope.spell_check_->Call(context, scope.provider_, 2, args).IsEmpty(); + scope.spell_check_->Call(context, scope.provider_, std::size(args), args) + .IsEmpty(); } // Returns whether or not the given string is a contraction. @@ -273,6 +273,4 @@ SpellCheckClient::SpellCheckScope::SpellCheckScope( SpellCheckClient::SpellCheckScope::~SpellCheckScope() = default; -} // namespace api - -} // namespace electron +} // namespace electron::api diff --git a/shell/renderer/api/electron_api_spell_check_client.h b/shell/renderer/api/electron_api_spell_check_client.h index d0b0a9b1956aa..bee731c1a68ec 100644 --- a/shell/renderer/api/electron_api_spell_check_client.h +++ b/shell/renderer/api/electron_api_spell_check_client.h @@ -23,9 +23,7 @@ struct WebTextCheckingResult; class WebTextCheckingCompletion; } // namespace blink -namespace electron { - -namespace api { +namespace electron::api { class SpellCheckClient : public blink::WebSpellCheckPanelHostClient, public blink::WebTextCheckClient, @@ -109,8 +107,6 @@ class SpellCheckClient : public blink::WebSpellCheckPanelHostClient, v8::Global spell_check_; }; -} // namespace api - -} // namespace electron +} // namespace electron::api #endif // ELECTRON_SHELL_RENDERER_API_ELECTRON_API_SPELL_CHECK_CLIENT_H_ diff --git a/shell/renderer/api/electron_api_web_frame.cc b/shell/renderer/api/electron_api_web_frame.cc index 6ec08e583da96..d2399e50c0415 100644 --- a/shell/renderer/api/electron_api_web_frame.cc +++ b/shell/renderer/api/electron_api_web_frame.cc @@ -15,7 +15,6 @@ #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_visitor.h" -#include "content/public/renderer/render_view.h" #include "gin/handle.h" #include "gin/object_template_builder.h" #include "gin/wrappable.h" @@ -24,6 +23,7 @@ #include "shell/common/gin_converters/blink_converter.h" #include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/file_path_converter.h" +#include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/function_template_extensions.h" @@ -58,38 +58,17 @@ namespace gin { template <> -struct Converter { +struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebLocalFrame::ScriptExecutionType* out) { - std::string execution_type; - if (!ConvertFromV8(isolate, val, &execution_type)) - return false; - if (execution_type == "asynchronous") { - *out = blink::WebLocalFrame::kAsynchronous; - } else if (execution_type == "asynchronousBlockingOnload") { - *out = blink::WebLocalFrame::kAsynchronousBlockingOnload; - } else if (execution_type == "synchronous") { - *out = blink::WebLocalFrame::kSynchronous; - } else { - return false; - } - return true; - } -}; - -template <> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - blink::WebDocument::CSSOrigin* out) { + blink::WebCssOrigin* out) { std::string css_origin; if (!ConvertFromV8(isolate, val, &css_origin)) return false; if (css_origin == "user") { - *out = blink::WebDocument::CSSOrigin::kUserOrigin; + *out = blink::WebCssOrigin::kUser; } else if (css_origin == "author") { - *out = blink::WebDocument::CSSOrigin::kAuthorOrigin; + *out = blink::WebCssOrigin::kAuthor; } else { return false; } @@ -102,7 +81,7 @@ struct Converter { namespace electron { content::RenderFrame* GetRenderFrame(v8::Local value) { - v8::Local context = value->CreationContext(); + v8::Local context = value->GetCreationContextChecked(); if (context.IsEmpty()) return nullptr; blink::WebLocalFrame* frame = blink::WebLocalFrame::FrameForContext(context); @@ -133,7 +112,7 @@ bool SpellCheckWord(content::RenderFrame* render_frame, #endif -class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { +class ScriptExecutionCallback { public: // for compatibility with the older version of this, error is after result using CompletionCallback = @@ -145,7 +124,7 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { CompletionCallback callback) : promise_(std::move(promise)), callback_(std::move(callback)) {} - ~ScriptExecutionCallback() override = default; + ~ScriptExecutionCallback() = default; // disable copy ScriptExecutionCallback(const ScriptExecutionCallback&) = delete; @@ -161,9 +140,9 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { { v8::TryCatch try_catch(isolate); context_bridge::ObjectCache object_cache; - maybe_result = PassValueToOtherContext(result->CreationContext(), - promise_.GetContext(), result, - &object_cache, false, 0); + maybe_result = PassValueToOtherContext( + result->GetCreationContextChecked(), promise_.GetContext(), result, + &object_cache, false, 0); if (maybe_result.IsEmpty() || try_catch.HasCaught()) { success = false; } @@ -194,8 +173,7 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { } } - void Completed( - const blink::WebVector>& result) override { + void Completed(const blink::WebVector>& result) { v8::Isolate* isolate = promise_.isolate(); if (!result.empty()) { if (!result[0].IsEmpty()) { @@ -206,7 +184,7 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { bool should_clone_value = !(value->IsObject() && promise_.GetContext() == - value.As()->CreationContext()) && + value.As()->GetCreationContextChecked()) && value->IsObject(); if (should_clone_value) { CopyResultToCallingContextAndFinalize(isolate, @@ -496,9 +474,7 @@ class WebFrameRenderer : public gin::Wrappable, const auto& prefs = render_frame->GetBlinkPreferences(); - if (pref_name == options::kPreloadScripts) { - return gin::ConvertToV8(isolate, prefs.preloads); - } else if (pref_name == "isWebView") { + if (pref_name == "isWebView") { // FIXME(zcbenz): For child windows opened with window.open('') from // webview, the WebPreferences is inherited from webview and the value // of |is_webview| is wrong. @@ -511,24 +487,8 @@ class WebFrameRenderer : public gin::Wrappable, } else if (pref_name == options::kHiddenPage) { // NOTE: hiddenPage is internal-only. return gin::ConvertToV8(isolate, prefs.hidden_page); - } else if (pref_name == options::kOffscreen) { - return gin::ConvertToV8(isolate, prefs.offscreen); - } else if (pref_name == options::kPreloadScript) { - return gin::ConvertToV8(isolate, prefs.preload.value()); } else if (pref_name == options::kNodeIntegration) { return gin::ConvertToV8(isolate, prefs.node_integration); - } else if (pref_name == options::kNodeIntegrationInWorker) { - return gin::ConvertToV8(isolate, prefs.node_integration_in_worker); - } else if (pref_name == options::kNodeIntegrationInSubFrames) { - return gin::ConvertToV8(isolate, true); -#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) - } else if (pref_name == options::kSpellcheck) { - return gin::ConvertToV8(isolate, prefs.enable_spellcheck); -#endif - } else if (pref_name == options::kPlugins) { - return gin::ConvertToV8(isolate, prefs.enable_plugins); - } else if (pref_name == options::kEnableWebSQL) { - return gin::ConvertToV8(isolate, prefs.enable_websql); } else if (pref_name == options::kWebviewTag) { return gin::ConvertToV8(isolate, prefs.webview_tag); } @@ -613,8 +573,7 @@ class WebFrameRenderer : public gin::Wrappable, std::u16string InsertCSS(v8::Isolate* isolate, const std::string& css, gin::Arguments* args) { - blink::WebDocument::CSSOrigin css_origin = - blink::WebDocument::CSSOrigin::kAuthorOrigin; + blink::WebCssOrigin css_origin = blink::WebCssOrigin::kAuthor; gin_helper::Dictionary options; if (args->GetNext(&options)) @@ -680,13 +639,20 @@ class WebFrameRenderer : public gin::Wrappable, ScriptExecutionCallback::CompletionCallback completion_callback; args->GetNext(&completion_callback); + auto* self = new ScriptExecutionCallback(std::move(promise), + std::move(completion_callback)); + render_frame->GetWebFrame()->RequestExecuteScript( blink::DOMWrapperWorld::kMainWorldId, base::make_span(&source, 1), - has_user_gesture, blink::WebLocalFrame::kSynchronous, - new ScriptExecutionCallback(std::move(promise), - std::move(completion_callback)), + has_user_gesture ? blink::mojom::UserActivationOption::kActivate + : blink::mojom::UserActivationOption::kDoNotActivate, + blink::mojom::EvaluationTiming::kSynchronous, + blink::mojom::LoadEventBlockingOption::kDoNotBlock, + base::NullCallback(), + base::BindOnce(&ScriptExecutionCallback::Completed, + base::Unretained(self)), blink::BackForwardCacheAware::kAllow, - blink::WebLocalFrame::PromiseBehavior::kDontWait); + blink::mojom::PromiseResultOption::kDoNotWait); return handle; } @@ -712,9 +678,19 @@ class WebFrameRenderer : public gin::Wrappable, bool has_user_gesture = false; args->GetNext(&has_user_gesture); - blink::WebLocalFrame::ScriptExecutionType scriptExecutionType = - blink::WebLocalFrame::kSynchronous; - args->GetNext(&scriptExecutionType); + blink::mojom::EvaluationTiming script_execution_type = + blink::mojom::EvaluationTiming::kSynchronous; + blink::mojom::LoadEventBlockingOption load_blocking_option = + blink::mojom::LoadEventBlockingOption::kDoNotBlock; + std::string execution_type; + args->GetNext(&execution_type); + + if (execution_type == "asynchronous") { + script_execution_type = blink::mojom::EvaluationTiming::kAsynchronous; + } else if (execution_type == "asynchronousBlockingOnload") { + script_execution_type = blink::mojom::EvaluationTiming::kAsynchronous; + load_blocking_option = blink::mojom::LoadEventBlockingOption::kBlock; + } ScriptExecutionCallback::CompletionCallback completion_callback; args->GetNext(&completion_callback); @@ -744,13 +720,19 @@ class WebFrameRenderer : public gin::Wrappable, blink::WebURL(GURL(url))); } + // Deletes itself. + auto* self = new ScriptExecutionCallback(std::move(promise), + std::move(completion_callback)); + render_frame->GetWebFrame()->RequestExecuteScript( - world_id, base::make_span(sources), has_user_gesture, - scriptExecutionType, - new ScriptExecutionCallback(std::move(promise), - std::move(completion_callback)), + world_id, base::make_span(sources), + has_user_gesture ? blink::mojom::UserActivationOption::kActivate + : blink::mojom::UserActivationOption::kDoNotActivate, + script_execution_type, load_blocking_option, base::NullCallback(), + base::BindOnce(&ScriptExecutionCallback::Completed, + base::Unretained(self)), blink::BackForwardCacheAware::kPossiblyDisallow, - blink::WebLocalFrame::PromiseBehavior::kDontWait); + blink::mojom::PromiseResultOption::kDoNotWait); return handle; } diff --git a/shell/renderer/browser_exposed_renderer_interfaces.cc b/shell/renderer/browser_exposed_renderer_interfaces.cc index 55781e58edd5d..04e82d7daa2b9 100644 --- a/shell/renderer/browser_exposed_renderer_interfaces.cc +++ b/shell/renderer/browser_exposed_renderer_interfaces.cc @@ -33,7 +33,8 @@ void ExposeElectronRendererInterfacesToBrowser( electron::RendererClientBase* client, mojo::BinderMap* binders) { #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) - binders->Add(base::BindRepeating(&BindSpellChecker, client), - base::SequencedTaskRunnerHandle::Get()); + binders->Add( + base::BindRepeating(&BindSpellChecker, client), + base::SequencedTaskRunnerHandle::Get()); #endif } diff --git a/shell/renderer/electron_api_service_impl.cc b/shell/renderer/electron_api_service_impl.cc index 7c39544973936..0a8f35bac6bc5 100644 --- a/shell/renderer/electron_api_service_impl.cc +++ b/shell/renderer/electron_api_service_impl.cc @@ -107,8 +107,8 @@ ElectronApiServiceImpl::ElectronApiServiceImpl( RendererClientBase* renderer_client) : content::RenderFrameObserver(render_frame), renderer_client_(renderer_client) { - registry_.AddInterface(base::BindRepeating(&ElectronApiServiceImpl::BindTo, - base::Unretained(this))); + registry_.AddInterface(base::BindRepeating( + &ElectronApiServiceImpl::BindTo, base::Unretained(this))); } void ElectronApiServiceImpl::BindTo( diff --git a/shell/renderer/electron_autofill_agent.cc b/shell/renderer/electron_autofill_agent.cc index ff3ae3deceb56..c648ee17fb2a2 100644 --- a/shell/renderer/electron_autofill_agent.cc +++ b/shell/renderer/electron_autofill_agent.cc @@ -8,7 +8,6 @@ #include #include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_view.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/input/web_keyboard_event.h" #include "third_party/blink/public/platform/web_string.h" @@ -53,8 +52,8 @@ AutofillAgent::AutofillAgent(content::RenderFrame* frame, blink::AssociatedInterfaceRegistry* registry) : content::RenderFrameObserver(frame) { render_frame()->GetWebFrame()->SetAutofillClient(this); - registry->AddInterface(base::BindRepeating(&AutofillAgent::BindReceiver, - base::Unretained(this))); + registry->AddInterface(base::BindRepeating( + &AutofillAgent::BindReceiver, base::Unretained(this))); } AutofillAgent::~AutofillAgent() = default; diff --git a/shell/renderer/electron_render_frame_observer.cc b/shell/renderer/electron_render_frame_observer.cc index cb27b1f5eb65f..3fbdf4e5bbb50 100644 --- a/shell/renderer/electron_render_frame_observer.cc +++ b/shell/renderer/electron_render_frame_observer.cc @@ -8,10 +8,10 @@ #include #include "base/command_line.h" +#include "base/memory/ref_counted_memory.h" #include "base/strings/string_number_conversions.h" #include "base/trace_event/trace_event.h" #include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_view.h" #include "electron/buildflags/buildflags.h" #include "electron/shell/common/api/api.mojom.h" #include "ipc/ipc_message_macros.h" @@ -82,9 +82,9 @@ void ElectronRenderFrameObserver::DidInstallConditionalFeatures( v8::Handle context, int world_id) { // When a child window is created with window.open, its WebPreferences will - // be copied from its parent, and Chromium will intialize JS context in it + // be copied from its parent, and Chromium will initialize JS context in it // immediately. - // Normally the WebPreferences is overriden in browser before navigation, + // Normally the WebPreferences is overridden in browser before navigation, // but this behavior bypasses the browser side navigation and the child // window will get wrong WebPreferences in the initialization. // This will end up initializing Node.js in the child window with wrong @@ -92,7 +92,7 @@ void ElectronRenderFrameObserver::DidInstallConditionalFeatures( // while "nodeIntegration=no" is passed. // We work around this issue by delaying the child window's initialization of // Node.js if this is the initial empty document, and only do it when the - // acutal page has started to load. + // actual page has started to load. auto* web_frame = static_cast(render_frame_->GetWebFrame()); if (web_frame->Opener() && web_frame->IsOnInitialEmptyDocument()) { diff --git a/shell/renderer/electron_renderer_client.cc b/shell/renderer/electron_renderer_client.cc index 263cd39410083..c3884cb6ba191 100644 --- a/shell/renderer/electron_renderer_client.cc +++ b/shell/renderer/electron_renderer_client.cc @@ -21,18 +21,10 @@ #include "third_party/blink/public/common/web_preferences/web_preferences.h" #include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_local_frame.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" // nogncheck namespace electron { -namespace { - -bool IsDevToolsExtension(content::RenderFrame* render_frame) { - return static_cast(render_frame->GetWebFrame()->GetDocument().Url()) - .SchemeIs("chrome-extension"); -} - -} // namespace - ElectronRendererClient::ElectronRendererClient() : node_bindings_( NodeBindings::Create(NodeBindings::BrowserEnvironment::kRenderer)), @@ -50,7 +42,7 @@ void ElectronRendererClient::RenderFrameCreated( void ElectronRendererClient::RunScriptsAtDocumentStart( content::RenderFrame* render_frame) { RendererClientBase::RunScriptsAtDocumentStart(render_frame); - // Inform the document start pharse. + // Inform the document start phase. v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); node::Environment* env = GetEnvironment(render_frame); if (env) @@ -61,7 +53,7 @@ void ElectronRendererClient::RunScriptsAtDocumentStart( void ElectronRendererClient::RunScriptsAtDocumentEnd( content::RenderFrame* render_frame) { RendererClientBase::RunScriptsAtDocumentEnd(render_frame); - // Inform the document end pharse. + // Inform the document end phase. v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); node::Environment* env = GetEnvironment(render_frame); if (env) @@ -77,15 +69,7 @@ void ElectronRendererClient::DidCreateScriptContext( // Only load Node.js if we are a main frame or a devtools extension // unless Node.js support has been explicitly enabled for subframes. - auto prefs = render_frame->GetBlinkPreferences(); - bool is_main_frame = render_frame->IsMainFrame(); - bool is_devtools = IsDevToolsExtension(render_frame); - bool allow_node_in_subframes = prefs.node_integration_in_sub_frames; - - bool should_load_node = - (is_main_frame || is_devtools || allow_node_in_subframes) && - !IsWebViewFrame(renderer_context, render_frame); - if (!should_load_node) + if (!ShouldLoadPreload(renderer_context, render_frame)) return; injected_frames_.insert(render_frame); @@ -93,9 +77,7 @@ void ElectronRendererClient::DidCreateScriptContext( if (!node_integration_initialized_) { node_integration_initialized_ = true; node_bindings_->Initialize(); - node_bindings_->PrepareMessageLoop(); - } else { - node_bindings_->PrepareMessageLoop(); + node_bindings_->PrepareEmbedThread(); } // Setup node tracing controller. @@ -131,7 +113,7 @@ void ElectronRendererClient::DidCreateScriptContext( node_bindings_->set_uv_env(env); // Give the node loop a run to make sure everything is ready. - node_bindings_->RunMessageLoop(); + node_bindings_->StartPolling(); } } @@ -175,8 +157,15 @@ void ElectronRendererClient::WillReleaseScriptContext( void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread( v8::Local context) { - // TODO(loc): Note that this will not be correct for in-process child windows - // with webPreferences that have a different value for nodeIntegrationInWorker + // We do not create a Node.js environment in service or shared workers + // owing to an inability to customize sandbox policies in these workers + // given that they're run out-of-process. + auto* ec = blink::ExecutionContext::From(context); + if (ec->IsServiceWorkerGlobalScope() || ec->IsSharedWorkerGlobalScope()) + return; + + // This won't be correct for in-process child windows with webPreferences + // that have a different value for nodeIntegrationInWorker if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kNodeIntegrationInWorker)) { WebWorkerObserver::GetCurrent()->WorkerScriptReadyForEvaluation(context); @@ -185,6 +174,10 @@ void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread( void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread( v8::Local context) { + auto* ec = blink::ExecutionContext::From(context); + if (ec->IsServiceWorkerGlobalScope() || ec->IsSharedWorkerGlobalScope()) + return; + // TODO(loc): Note that this will not be correct for in-process child windows // with webPreferences that have a different value for nodeIntegrationInWorker if (base::CommandLine::ForCurrentProcess()->HasSwitch( diff --git a/shell/renderer/electron_sandboxed_renderer_client.cc b/shell/renderer/electron_sandboxed_renderer_client.cc index c1f1ae7a61c28..a73404ac026a6 100644 --- a/shell/renderer/electron_sandboxed_renderer_client.cc +++ b/shell/renderer/electron_sandboxed_renderer_client.cc @@ -36,16 +36,6 @@ namespace { const char kLifecycleKey[] = "lifecycle"; const char kModuleCacheKey[] = "native-module-cache"; -bool IsDevTools(content::RenderFrame* render_frame) { - return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs( - "devtools"); -} - -bool IsDevToolsExtension(content::RenderFrame* render_frame) { - return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs( - "chrome-extension"); -} - v8::Local GetModuleCache(v8::Isolate* isolate) { auto context = isolate->GetCurrentContext(); gin_helper::Dictionary global(isolate, context->Global()); @@ -207,17 +197,7 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext( // Only allow preload for the main frame or // For devtools we still want to run the preload_bundle script // Or when nodeSupport is explicitly enabled in sub frames - bool is_main_frame = render_frame->IsMainFrame(); - bool is_devtools = - IsDevTools(render_frame) || IsDevToolsExtension(render_frame); - - bool allow_node_in_sub_frames = - render_frame->GetBlinkPreferences().node_integration_in_sub_frames; - - bool should_load_preload = - (is_main_frame || is_devtools || allow_node_in_sub_frames) && - !IsWebViewFrame(context, render_frame); - if (!should_load_preload) + if (!ShouldLoadPreload(context, render_frame)) return; injected_frames_.insert(render_frame); diff --git a/shell/renderer/printing/print_render_frame_helper_delegate.cc b/shell/renderer/printing/print_render_frame_helper_delegate.cc index 8eb83a3be249a..c104cb145d5fd 100644 --- a/shell/renderer/printing/print_render_frame_helper_delegate.cc +++ b/shell/renderer/printing/print_render_frame_helper_delegate.cc @@ -4,12 +4,15 @@ #include "shell/renderer/printing/print_render_frame_helper_delegate.h" +#include + #include "content/public/renderer/render_frame.h" #include "extensions/buildflags/buildflags.h" #include "third_party/blink/public/web/web_element.h" #include "third_party/blink/public/web/web_local_frame.h" #if BUILDFLAG(ENABLE_EXTENSIONS) +#include "chrome/common/pdf_util.h" #include "extensions/common/constants.h" #include "extensions/renderer/guest_view/mime_handler_view/post_message_support.h" #endif // BUILDFLAG(ENABLE_EXTENSIONS) @@ -24,22 +27,11 @@ PrintRenderFrameHelperDelegate::~PrintRenderFrameHelperDelegate() = default; blink::WebElement PrintRenderFrameHelperDelegate::GetPdfElement( blink::WebLocalFrame* frame) { #if BUILDFLAG(ENABLE_EXTENSIONS) - GURL url = frame->GetDocument().Url(); - bool inside_pdf_extension = - url.SchemeIs(extensions::kExtensionScheme) && - url.host_piece() == extension_misc::kPdfExtensionId; - if (inside_pdf_extension) { - // with id="plugin" is created in - // chrome/browser/resources/pdf/pdf_viewer_base.js. - auto viewer_element = frame->GetDocument().GetElementById("viewer"); - if (!viewer_element.IsNull() && !viewer_element.ShadowRoot().IsNull()) { - auto plugin_element = - viewer_element.ShadowRoot().QuerySelector("#plugin"); - if (!plugin_element.IsNull()) { - return plugin_element; - } - } - NOTREACHED(); + if (frame->Parent() && + IsPdfInternalPluginAllowedOrigin(frame->Parent()->GetSecurityOrigin())) { + auto plugin_element = frame->GetDocument().QuerySelector("embed"); + DCHECK(!plugin_element.IsNull()); + return plugin_element; } #endif // BUILDFLAG(ENABLE_EXTENSIONS) return blink::WebElement(); @@ -59,9 +51,9 @@ bool PrintRenderFrameHelperDelegate::OverridePrint( // instructs the PDF plugin to print. This is to make window.print() on a // PDF plugin document correctly print the PDF. See // https://crbug.com/448720. - base::DictionaryValue message; - message.SetString("type", "print"); - post_message_support->PostMessageFromValue(message); + base::Value::Dict message; + message.Set("type", "print"); + post_message_support->PostMessageFromValue(base::Value(std::move(message))); return true; } #endif // BUILDFLAG(ENABLE_EXTENSIONS) diff --git a/shell/renderer/renderer_client_base.cc b/shell/renderer/renderer_client_base.cc index 6a36fc06274ef..9187dca38e7d4 100644 --- a/shell/renderer/renderer_client_base.cc +++ b/shell/renderer/renderer_client_base.cc @@ -18,7 +18,6 @@ #include "content/public/common/content_switches.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" -#include "content/public/renderer/render_view.h" #include "electron/buildflags/buildflags.h" #include "printing/buildflags/buildflags.h" #include "shell/browser/api/electron_api_protocol.h" @@ -37,7 +36,6 @@ #include "shell/renderer/electron_autofill_agent.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" -#include "third_party/blink/public/platform/media/multi_buffer_data_source.h" #include "third_party/blink/public/web/blink.h" #include "third_party/blink/public/web/web_custom_element.h" // NOLINT(build/include_alpha) #include "third_party/blink/public/web/web_frame_widget.h" @@ -46,7 +44,9 @@ #include "third_party/blink/public/web/web_script_source.h" #include "third_party/blink/public/web/web_security_policy.h" #include "third_party/blink/public/web/web_view.h" +#include "third_party/blink/renderer/platform/media/multi_buffer_data_source.h" // nogncheck #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" // nogncheck +#include "third_party/widevine/cdm/buildflags.h" #if BUILDFLAG(IS_MAC) #include "base/strings/sys_string_conversions.h" @@ -56,6 +56,10 @@ #include #endif +#if BUILDFLAG(ENABLE_WIDEVINE) +#include "chrome/renderer/media/chrome_key_systems.h" // nogncheck +#endif + #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) #include "components/spellcheck/renderer/spellcheck.h" #include "components/spellcheck/renderer/spellcheck_provider.h" @@ -64,7 +68,6 @@ #if BUILDFLAG(ENABLE_PDF_VIEWER) #include "chrome/common/pdf_util.h" #include "components/pdf/common/internal_plugin_helpers.h" -#include "components/pdf/renderer/internal_plugin_renderer_helpers.h" #include "components/pdf/renderer/pdf_internal_plugin_delegate.h" #include "shell/common/electron_constants.h" #endif // BUILDFLAG(ENABLE_PDF_VIEWER) @@ -131,6 +134,16 @@ class ChromePdfInternalPluginDelegate final // static RendererClientBase* g_renderer_client_base = nullptr; +bool IsDevTools(content::RenderFrame* render_frame) { + return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs( + "devtools"); +} + +bool IsDevToolsExtension(content::RenderFrame* render_frame) { + return render_frame->GetWebFrame()->GetDocument().Url().ProtocolIs( + "chrome-extension"); +} + } // namespace RendererClientBase::RendererClientBase() { @@ -193,6 +206,19 @@ void RendererClientBase::BindProcess(v8::Isolate* isolate, process->SetReadOnly("contextId", context_id); } +bool RendererClientBase::ShouldLoadPreload( + v8::Handle context, + content::RenderFrame* render_frame) const { + auto prefs = render_frame->GetBlinkPreferences(); + bool is_main_frame = render_frame->IsMainFrame(); + bool is_devtools = + IsDevTools(render_frame) || IsDevToolsExtension(render_frame); + bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames; + + return (is_main_frame || is_devtools || allow_node_in_sub_frames) && + !IsWebViewFrame(context, render_frame); +} + void RendererClientBase::RenderThreadStarted() { auto* command_line = base::CommandLine::ForCurrentProcess(); @@ -209,12 +235,6 @@ void RendererClientBase::RenderThreadStarted() { thread->AddObserver(extensions_renderer_client_->GetDispatcher()); #endif -#if BUILDFLAG(ENABLE_PDF_VIEWER) - // Enables printing from Chrome PDF viewer. - pdf_print_client_ = std::make_unique(); - pdf::PepperPDFHost::SetPrintClient(pdf_print_client_.get()); -#endif - #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) spellcheck_ = std::make_unique(this); #endif @@ -302,10 +322,11 @@ void RendererClientBase::RenderFrameCreated( dispatcher->OnRenderFrameCreated(render_frame); - render_frame->GetAssociatedInterfaceRegistry()->AddInterface( - base::BindRepeating( - &extensions::MimeHandlerViewContainerManager::BindReceiver, - render_frame->GetRoutingID())); + render_frame->GetAssociatedInterfaceRegistry() + ->AddInterface( + base::BindRepeating( + &extensions::MimeHandlerViewContainerManager::BindReceiver, + render_frame->GetRoutingID())); #endif #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) @@ -340,15 +361,8 @@ bool RendererClientBase::OverrideCreatePlugin( blink::WebPlugin** plugin) { #if BUILDFLAG(ENABLE_PDF_VIEWER) if (params.mime_type.Utf8() == pdf::kInternalPluginMimeType) { - content::WebPluginInfo info; - info.type = content::WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS; - info.name = base::ASCIIToUTF16(kPDFInternalPluginName); - info.path = base::FilePath(kPdfPluginPath); - info.background_color = content::WebPluginInfo::kDefaultBackgroundColor; - info.mime_types.emplace_back(pdf::kInternalPluginMimeType, "pdf", - "Portable Document Format"); *plugin = pdf::CreateInternalPlugin( - info, std::move(params), render_frame, + std::move(params), render_frame, std::make_unique()); return true; } @@ -364,16 +378,10 @@ bool RendererClientBase::OverrideCreatePlugin( void RendererClientBase::GetSupportedKeySystems( media::GetSupportedKeySystemsCB cb) { -#if defined(WIDEVINE_CDM_AVAILABLE) - key_systems_provider_.GetSupportedKeySystems(std::move(cb)); -#endif -} - -bool RendererClientBase::IsKeySystemsUpdateNeeded() { -#if defined(WIDEVINE_CDM_AVAILABLE) - return key_systems_provider_.IsKeySystemsUpdateNeeded(); +#if BUILDFLAG(ENABLE_WIDEVINE) + GetChromeKeySystems(std::move(cb)); #else - return false; + std::move(cb).Run({}); #endif } @@ -429,12 +437,6 @@ bool RendererClientBase::IsPluginHandledExternally( #endif } -bool RendererClientBase::IsOriginIsolatedPepperPlugin( - const base::FilePath& plugin_path) { - // Isolate all Pepper plugins, including the PDF plugin. - return true; -} - v8::Local RendererClientBase::GetScriptableObject( const blink::WebElement& plugin_element, v8::Isolate* isolate) { @@ -625,7 +627,7 @@ void RendererClientBase::AllowGuestViewElementDefinition( v8::Local context, v8::Local register_cb) { v8::HandleScope handle_scope(isolate); - v8::Context::Scope context_scope(context->CreationContext()); + v8::Context::Scope context_scope(context->GetCreationContextChecked()); blink::WebCustomElement::EmbedderNamesAllowedScope embedder_names_scope; content::RenderFrame* render_frame = GetRenderFrame(context); @@ -633,8 +635,8 @@ void RendererClientBase::AllowGuestViewElementDefinition( return; render_frame->GetWebFrame()->RequestExecuteV8Function( - context->CreationContext(), register_cb, v8::Null(isolate), 0, nullptr, - nullptr); + context->GetCreationContextChecked(), register_cb, v8::Null(isolate), 0, + nullptr, base::NullCallback()); } } // namespace electron diff --git a/shell/renderer/renderer_client_base.h b/shell/renderer/renderer_client_base.h index 84acea819e8c6..474a5e1a44e69 100644 --- a/shell/renderer/renderer_client_base.h +++ b/shell/renderer/renderer_client_base.h @@ -16,12 +16,8 @@ // In SHARED_INTERMEDIATE_DIR. #include "widevine_cdm_version.h" // NOLINT(build/include_directory) -#if defined(WIDEVINE_CDM_AVAILABLE) -#include "chrome/renderer/media/chrome_key_systems_provider.h" // nogncheck -#endif - #if BUILDFLAG(ENABLE_PDF_VIEWER) -#include "chrome/renderer/pepper/chrome_pdf_print_client.h" // nogncheck +#include "components/pdf/renderer/internal_plugin_renderer_helpers.h" #endif // BUILDFLAG(ENABLE_PDF_VIEWER) #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) @@ -97,6 +93,9 @@ class RendererClientBase : public content::ContentRendererClient gin_helper::Dictionary* process, content::RenderFrame* render_frame); + bool ShouldLoadPreload(v8::Handle context, + content::RenderFrame* render_frame) const; + // content::ContentRendererClient: void RenderThreadStarted() override; void ExposeInterfacesToBrowser(mojo::BinderMap* binders) override; @@ -105,13 +104,11 @@ class RendererClientBase : public content::ContentRendererClient const blink::WebPluginParams& params, blink::WebPlugin** plugin) override; void GetSupportedKeySystems(media::GetSupportedKeySystemsCB cb) override; - bool IsKeySystemsUpdateNeeded() override; void DidSetUserAgent(const std::string& user_agent) override; bool IsPluginHandledExternally(content::RenderFrame* render_frame, const blink::WebElement& plugin_element, const GURL& original_url, const std::string& mime_type) override; - bool IsOriginIsolatedPepperPlugin(const base::FilePath& plugin_path) override; v8::Local GetScriptableObject( const blink::WebElement& plugin_element, v8::Isolate* isolate) override; @@ -155,9 +152,6 @@ class RendererClientBase : public content::ContentRendererClient std::unique_ptr extensions_renderer_client_; #endif -#if defined(WIDEVINE_CDM_AVAILABLE) - ChromeKeySystemsProvider key_systems_provider_; -#endif std::string renderer_client_id_; // An increasing ID used for identifying an V8 context in this process. int64_t next_context_id_ = 0; @@ -165,9 +159,6 @@ class RendererClientBase : public content::ContentRendererClient #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER) std::unique_ptr spellcheck_; #endif -#if BUILDFLAG(ENABLE_PDF_VIEWER) - std::unique_ptr pdf_print_client_; -#endif }; } // namespace electron diff --git a/shell/renderer/web_worker_observer.cc b/shell/renderer/web_worker_observer.cc index ca929bf9e4bb9..ea5f60daba426 100644 --- a/shell/renderer/web_worker_observer.cc +++ b/shell/renderer/web_worker_observer.cc @@ -56,7 +56,7 @@ void WebWorkerObserver::WorkerScriptReadyForEvaluation( isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); // Start the embed thread. - node_bindings_->PrepareMessageLoop(); + node_bindings_->PrepareEmbedThread(); // Setup node tracing controller. if (!node::tracing::TraceEventHelper::GetAgent()) @@ -78,7 +78,7 @@ void WebWorkerObserver::WorkerScriptReadyForEvaluation( node_bindings_->set_uv_env(env); // Give the node loop a run to make sure everything is ready. - node_bindings_->RunMessageLoop(); + node_bindings_->StartPolling(); } void WebWorkerObserver::ContextWillDestroy(v8::Local context) { diff --git a/shell/utility/electron_content_utility_client.cc b/shell/utility/electron_content_utility_client.cc index c53e537dad067..0a711e13e8497 100644 --- a/shell/utility/electron_content_utility_client.cc +++ b/shell/utility/electron_content_utility_client.cc @@ -94,7 +94,7 @@ void ElectronContentUtilityClient::ExposeInterfacesToBrowser( // interfaces to the BinderMap. if (!utility_process_running_elevated_) { #if BUILDFLAG(ENABLE_PRINTING) && BUILDFLAG(IS_WIN) - binders->Add( + binders->Add( base::BindRepeating(printing::PdfToEmfConverterFactory::Create), base::ThreadTaskRunnerHandle::Get()); #endif diff --git a/spec/BUILD.gn b/spec-chromium/BUILD.gn similarity index 100% rename from spec/BUILD.gn rename to spec-chromium/BUILD.gn diff --git a/spec/configs/browsertests.yml b/spec-chromium/configs/browsertests.yml similarity index 100% rename from spec/configs/browsertests.yml rename to spec-chromium/configs/browsertests.yml diff --git a/spec/configs/unittests.yml b/spec-chromium/configs/unittests.yml similarity index 100% rename from spec/configs/unittests.yml rename to spec-chromium/configs/unittests.yml diff --git a/spec-main/api-app-spec.ts b/spec-main/api-app-spec.ts index 62608d0ec14e8..a244364fdf253 100644 --- a/spec-main/api-app-spec.ts +++ b/spec-main/api-app-spec.ts @@ -3,13 +3,13 @@ import * as cp from 'child_process'; import * as https from 'https'; import * as http from 'http'; import * as net from 'net'; -import * as fs from 'fs'; +import * as fs from 'fs-extra'; import * as path from 'path'; import { promisify } from 'util'; import { app, BrowserWindow, Menu, session, net as electronNet } from 'electron/main'; import { emittedOnce } from './events-helpers'; import { closeWindow, closeAllWindows } from './window-helpers'; -import { ifdescribe, ifit } from './spec-helpers'; +import { ifdescribe, ifit, waitUntil } from './spec-helpers'; import split = require('split') const fixturesPath = path.resolve(__dirname, '../spec/fixtures'); @@ -90,9 +90,9 @@ describe('app module', () => { it('overrides the name', () => { expect(app.name).to.equal('Electron Test Main'); - app.name = 'test-name'; + app.name = 'electron-test-name'; - expect(app.name).to.equal('test-name'); + expect(app.name).to.equal('electron-test-name'); app.name = 'Electron Test Main'; }); }); @@ -104,9 +104,9 @@ describe('app module', () => { it('overrides the name', () => { expect(app.getName()).to.equal('Electron Test Main'); - app.setName('test-name'); + app.setName('electron-test-name'); - expect(app.getName()).to.equal('test-name'); + expect(app.getName()).to.equal('electron-test-name'); app.setName('Electron Test Main'); }); }); @@ -118,6 +118,12 @@ describe('app module', () => { }); }); + describe('app.getSystemLocale()', () => { + it('should not be empty', () => { + expect(app.getSystemLocale()).to.not.equal(''); + }); + }); + describe('app.getLocaleCountryCode()', () => { it('should be empty or have length of two', () => { const localeCountryCode = app.getLocaleCountryCode(); @@ -127,7 +133,7 @@ describe('app module', () => { }); describe('app.isPackaged', () => { - it('should be false durings tests', () => { + it('should be false during tests', () => { expect(app.isPackaged).to.equal(false); }); }); @@ -208,23 +214,18 @@ describe('app module', () => { interface SingleInstanceLockTestArgs { args: string[]; expectedAdditionalData: unknown; - expectedAck: unknown; } it('prevents the second launch of app', async function () { - this.timeout(60000); - const appPath = path.join(fixturesPath, 'api', 'singleton'); + this.timeout(120000); + const appPath = path.join(fixturesPath, 'api', 'singleton-data'); const first = cp.spawn(process.execPath, [appPath]); - const firstExited = emittedOnce(first, 'exit'); await emittedOnce(first.stdout, 'data'); - // Start second app when received output. const second = cp.spawn(process.execPath, [appPath]); - const secondExited = emittedOnce(second, 'exit'); - - const [code2] = await secondExited; + const [code2] = await emittedOnce(second, 'exit'); expect(code2).to.equal(1); - const [code1] = await firstExited; + const [code1] = await emittedOnce(first, 'exit'); expect(code1).to.equal(0); }); @@ -250,11 +251,6 @@ describe('app module', () => { const secondInstanceArgs = [process.execPath, appPath, ...testArgs.args, '--some-switch', 'some-arg']; const second = cp.spawn(secondInstanceArgs[0], secondInstanceArgs.slice(1)); const secondExited = emittedOnce(second, 'exit'); - const secondStdoutLines = second.stdout.pipe(split()); - let ackData; - while ((ackData = await emittedOnce(secondStdoutLines, 'data'))[0].toString().length === 0) { - // This isn't valid data. - } const [code2] = await secondExited; expect(code2).to.equal(1); @@ -264,7 +260,6 @@ describe('app module', () => { const [args, additionalData] = dataFromSecondInstance[0].toString('ascii').split('||'); const secondInstanceArgsReceived: string[] = JSON.parse(args.toString('ascii')); const secondInstanceDataReceived = JSON.parse(additionalData.toString('ascii')); - const dataAckReceived = JSON.parse(ackData[0].toString('ascii')); // Ensure secondInstanceArgs is a subset of secondInstanceArgsReceived for (const arg of secondInstanceArgs) { @@ -273,113 +268,69 @@ describe('app module', () => { } expect(secondInstanceDataReceived).to.be.deep.equal(testArgs.expectedAdditionalData, `received data ${JSON.stringify(secondInstanceDataReceived)} is not equal to expected data ${JSON.stringify(testArgs.expectedAdditionalData)}.`); - expect(dataAckReceived).to.be.deep.equal(testArgs.expectedAck, - `received data ${JSON.stringify(dataAckReceived)} is not equal to expected data ${JSON.stringify(testArgs.expectedAck)}.`); } - const expectedAdditionalData = { - level: 1, - testkey: 'testvalue1', - inner: { - level: 2, - testkey: 'testvalue2' - } - }; - - const expectedAck = { - level: 1, - testkey: 'acktestvalue1', - inner: { - level: 2, - testkey: 'acktestvalue2' - } - }; - - it('passes arguments to the second-instance event with no additional data', async () => { + it('passes arguments to the second-instance event no additional data', async () => { await testArgumentPassing({ args: [], - expectedAdditionalData: null, - expectedAck: null + expectedAdditionalData: null }); }); - it('passes arguments to the second-instance event', async () => { + it('sends and receives JSON object data', async () => { + const expectedAdditionalData = { + level: 1, + testkey: 'testvalue1', + inner: { + level: 2, + testkey: 'testvalue2' + } + }; await testArgumentPassing({ args: ['--send-data'], - expectedAdditionalData, - expectedAck: null - }); - }); - - it('gets back an ack after preventing default', async () => { - await testArgumentPassing({ - args: ['--send-ack', '--prevent-default'], - expectedAdditionalData: null, - expectedAck - }); - }); - - it('is able to send back empty ack after preventing default', async () => { - await testArgumentPassing({ - args: ['--prevent-default'], - expectedAdditionalData: null, - expectedAck: null - }); - }); - - it('sends and receives data', async () => { - await testArgumentPassing({ - args: ['--send-ack', '--prevent-default', '--send-data'], - expectedAdditionalData, - expectedAck + expectedAdditionalData }); }); it('sends and receives numerical data', async () => { await testArgumentPassing({ - args: ['--send-ack', '--ack-content=1', '--prevent-default', '--send-data', '--data-content=2'], - expectedAdditionalData: 2, - expectedAck: 1 + args: ['--send-data', '--data-content=2'], + expectedAdditionalData: 2 }); }); it('sends and receives string data', async () => { await testArgumentPassing({ - args: ['--send-ack', '--ack-content="ack"', '--prevent-default', '--send-data', '--data-content="data"'], - expectedAdditionalData: 'data', - expectedAck: 'ack' + args: ['--send-data', '--data-content="data"'], + expectedAdditionalData: 'data' }); }); it('sends and receives boolean data', async () => { await testArgumentPassing({ - args: ['--send-ack', '--ack-content=true', '--prevent-default', '--send-data', '--data-content=false'], - expectedAdditionalData: false, - expectedAck: true + args: ['--send-data', '--data-content=false'], + expectedAdditionalData: false }); }); it('sends and receives array data', async () => { await testArgumentPassing({ - args: ['--send-ack', '--ack-content=[1, 2, 3]', '--prevent-default', '--send-data', '--data-content=[2, 3, 4]'], - expectedAdditionalData: [2, 3, 4], - expectedAck: [1, 2, 3] + args: ['--send-data', '--data-content=[2, 3, 4]'], + expectedAdditionalData: [2, 3, 4] }); }); it('sends and receives mixed array data', async () => { await testArgumentPassing({ - args: ['--send-ack', '--ack-content=["1", true, 3]', '--prevent-default', '--send-data', '--data-content=["2", false, 4]'], - expectedAdditionalData: ['2', false, 4], - expectedAck: ['1', true, 3] + args: ['--send-data', '--data-content=["2", true, 4]'], + expectedAdditionalData: ['2', true, 4] }); }); it('sends and receives null data', async () => { await testArgumentPassing({ - args: ['--send-ack', '--ack-content=null', '--prevent-default', '--send-data', '--data-content=null'], - expectedAdditionalData: null, - expectedAck: null + args: ['--send-data', '--data-content=null'], + expectedAdditionalData: null }); }); @@ -387,8 +338,7 @@ describe('app module', () => { try { await testArgumentPassing({ args: ['--send-ack', '--ack-content="undefined"', '--prevent-default', '--send-data', '--data-content="undefined"'], - expectedAdditionalData: undefined, - expectedAck: undefined + expectedAdditionalData: undefined }); assert(false); } catch (e) { @@ -426,9 +376,11 @@ describe('app module', () => { server!.once('error', error => done(error)); server!.on('connection', client => { client.once('data', data => { - if (String(data) === 'false' && state === 'none') { + if (String(data) === '--first' && state === 'none') { state = 'first-launch'; - } else if (String(data) === 'true' && state === 'first-launch') { + } else if (String(data) === '--second' && state === 'first-launch') { + state = 'second-launch'; + } else if (String(data) === '--third' && state === 'second-launch') { done(); } else { done(`Unexpected state: "${state}", data: "${data}"`); @@ -437,7 +389,7 @@ describe('app module', () => { }); const appPath = path.join(fixturesPath, 'api', 'relaunch'); - const child = cp.spawn(process.execPath, [appPath]); + const child = cp.spawn(process.execPath, [appPath, '--first']); child.stdout.on('data', (c) => console.log(c.toString())); child.stderr.on('data', (c) => console.log(c.toString())); child.on('exit', (code, signal) => { @@ -552,7 +504,7 @@ describe('app module', () => { expect(window.id).to.equal(w.id); }); - it('should emit browser-window-blur event when window is blured', async () => { + it('should emit browser-window-blur event when window is blurred', async () => { const emitted = emittedOnce(app, 'browser-window-blur'); w = new BrowserWindow({ show: false }); w.emit('blur'); @@ -1043,7 +995,7 @@ describe('app module', () => { it('gets the folder for recent files', () => { const recent = app.getPath('recent'); - // We expect that one of our test machines have overriden this + // We expect that one of our test machines have overridden this // to be something crazy, it'll always include the word "Recent" // unless people have been registry-hacking like crazy expect(recent).to.include('Recent'); @@ -1078,6 +1030,54 @@ describe('app module', () => { expect(() => { app.getPath(badPath as any); }).to.throw(); }); + + describe('sessionData', () => { + const appPath = path.join(__dirname, 'fixtures', 'apps', 'set-path'); + const appName = fs.readJsonSync(path.join(appPath, 'package.json')).name; + const userDataPath = path.join(app.getPath('appData'), appName); + const tempBrowserDataPath = path.join(app.getPath('temp'), appName); + + const sessionFiles = [ + 'Preferences', + 'Code Cache', + 'Local Storage', + 'IndexedDB', + 'Service Worker' + ]; + const hasSessionFiles = (dir: string) => { + for (const file of sessionFiles) { + if (!fs.existsSync(path.join(dir, file))) { + return false; + } + } + return true; + }; + + beforeEach(() => { + fs.removeSync(userDataPath); + fs.removeSync(tempBrowserDataPath); + }); + + it('writes to userData by default', () => { + expect(hasSessionFiles(userDataPath)).to.equal(false); + cp.spawnSync(process.execPath, [appPath]); + expect(hasSessionFiles(userDataPath)).to.equal(true); + }); + + it('can be changed', () => { + expect(hasSessionFiles(userDataPath)).to.equal(false); + cp.spawnSync(process.execPath, [appPath, 'sessionData', tempBrowserDataPath]); + expect(hasSessionFiles(userDataPath)).to.equal(false); + expect(hasSessionFiles(tempBrowserDataPath)).to.equal(true); + }); + + it('changing userData affects default sessionData', () => { + expect(hasSessionFiles(userDataPath)).to.equal(false); + cp.spawnSync(process.execPath, [appPath, 'userData', tempBrowserDataPath]); + expect(hasSessionFiles(userDataPath)).to.equal(false); + expect(hasSessionFiles(tempBrowserDataPath)).to.equal(true); + }); + }); }); describe('setAppLogsPath(path)', () => { @@ -1582,6 +1582,23 @@ describe('app module', () => { }); }); + ifdescribe(process.platform === 'darwin')('app hide and show API', () => { + describe('app.isHidden', () => { + it('returns true when the app is hidden', async () => { + app.hide(); + await expect( + waitUntil(() => app.isHidden()) + ).to.eventually.be.fulfilled(); + }); + it('returns false when the app is shown', async () => { + app.show(); + await expect( + waitUntil(() => !app.isHidden()) + ).to.eventually.be.fulfilled(); + }); + }); + }); + const dockDescribe = process.platform === 'darwin' ? describe : describe.skip; dockDescribe('dock APIs', () => { after(async () => { diff --git a/spec-main/api-autoupdater-darwin-spec.ts b/spec-main/api-autoupdater-darwin-spec.ts index c4535337f9015..18c075f0c7695 100644 --- a/spec-main/api-autoupdater-darwin-spec.ts +++ b/spec-main/api-autoupdater-darwin-spec.ts @@ -7,6 +7,8 @@ import * as os from 'os'; import * as path from 'path'; import { AddressInfo } from 'net'; import { ifdescribe, ifit } from './spec-helpers'; +import * as uuid from 'uuid'; +import { systemPreferences } from 'electron'; const features = process._linkedBinding('electron_common_features'); @@ -132,7 +134,7 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch === await signApp(secondAppPath); await mutateAppPostSign?.mutate(secondAppPath); updateZipPath = path.resolve(dir, 'update.zip'); - await spawn('zip', ['-r', '--symlinks', updateZipPath, './'], { + await spawn('zip', ['-0', '-r', '--symlinks', updateZipPath, './'], { cwd: dir }); }, false); @@ -321,6 +323,64 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch === }); }); + describe('with SquirrelMacEnableDirectContentsWrite enabled', () => { + let previousValue: any; + + beforeEach(() => { + previousValue = systemPreferences.getUserDefault('SquirrelMacEnableDirectContentsWrite', 'boolean'); + systemPreferences.setUserDefault('SquirrelMacEnableDirectContentsWrite', 'boolean', true as any); + }); + + afterEach(() => { + systemPreferences.setUserDefault('SquirrelMacEnableDirectContentsWrite', 'boolean', previousValue as any); + }); + + it('should hit the download endpoint when an update is available and update successfully when the zip is provided leaving the parent directory untouched', async () => { + await withUpdatableApp({ + nextVersion: '2.0.0', + startFixture: 'update', + endFixture: 'update' + }, async (appPath, updateZipPath) => { + const randomID = uuid.v4(); + cp.spawnSync('xattr', ['-w', 'spec-id', randomID, appPath]); + server.get('/update-file', (req, res) => { + res.download(updateZipPath); + }); + server.get('/update-check', (req, res) => { + res.json({ + url: `http://localhost:${port}/update-file`, + name: 'My Release Name', + notes: 'Theses are some release notes innit', + pub_date: (new Date()).toString() + }); + }); + const relaunchPromise = new Promise((resolve) => { + server.get('/update-check/updated/:version', (req, res) => { + res.status(204).send(); + resolve(); + }); + }); + const launchResult = await launchApp(appPath, [`http://localhost:${port}/update-check`]); + logOnError(launchResult, () => { + expect(launchResult).to.have.property('code', 0); + expect(launchResult.out).to.include('Update Downloaded'); + expect(requests).to.have.lengthOf(2); + expect(requests[0]).to.have.property('url', '/update-check'); + expect(requests[1]).to.have.property('url', '/update-file'); + expect(requests[0].header('user-agent')).to.include('Electron/'); + expect(requests[1].header('user-agent')).to.include('Electron/'); + }); + + await relaunchPromise; + expect(requests).to.have.lengthOf(3); + expect(requests[2].url).to.equal('/update-check/updated/2.0.0'); + expect(requests[2].header('user-agent')).to.include('Electron/'); + const result = cp.spawnSync('xattr', ['-l', appPath]); + expect(result.stdout.toString()).to.include(`spec-id: ${randomID}`); + }); + }); + }); + it('should hit the download endpoint when an update is available and fail when the zip signature is invalid', async () => { await withUpdatableApp({ nextVersion: '2.0.0', diff --git a/spec-main/api-browser-view-spec.ts b/spec-main/api-browser-view-spec.ts index 8d54b9efe1cae..ef32bef9feaa2 100644 --- a/spec-main/api-browser-view-spec.ts +++ b/spec-main/api-browser-view-spec.ts @@ -1,9 +1,10 @@ import { expect } from 'chai'; import * as path from 'path'; import { emittedOnce } from './events-helpers'; -import { BrowserView, BrowserWindow, webContents } from 'electron/main'; +import { BrowserView, BrowserWindow, screen, webContents } from 'electron/main'; import { closeWindow } from './window-helpers'; -import { defer, startRemoteControlApp } from './spec-helpers'; +import { defer, ifit, startRemoteControlApp } from './spec-helpers'; +import { areColorsSimilar, captureScreen, getPixelColor } from './screen-helpers'; describe('BrowserView module', () => { const fixtures = path.resolve(__dirname, '..', 'spec', 'fixtures'); @@ -60,6 +61,56 @@ describe('BrowserView module', () => { view.setBackgroundColor(null as any); }).to.throw(/conversion failure/); }); + + // Linux and arm64 platforms (WOA and macOS) do not return any capture sources + ifit(process.platform !== 'linux' && process.arch !== 'arm64')('sets the background color to transparent if none is set', async () => { + const display = screen.getPrimaryDisplay(); + const WINDOW_BACKGROUND_COLOR = '#55ccbb'; + + w.show(); + w.setBounds(display.bounds); + w.setBackgroundColor(WINDOW_BACKGROUND_COLOR); + await w.loadURL('about:blank'); + + view = new BrowserView(); + view.setBounds(display.bounds); + w.setBrowserView(view); + await view.webContents.loadURL('data:text/html,hello there'); + + const screenCapture = await captureScreen(); + const centerColor = getPixelColor(screenCapture, { + x: display.size.width / 2, + y: display.size.height / 2 + }); + + expect(areColorsSimilar(centerColor, WINDOW_BACKGROUND_COLOR)).to.be.true(); + }); + + // Linux and arm64 platforms (WOA and macOS) do not return any capture sources + ifit(process.platform !== 'linux' && process.arch !== 'arm64')('successfully applies the background color', async () => { + const WINDOW_BACKGROUND_COLOR = '#55ccbb'; + const VIEW_BACKGROUND_COLOR = '#ff00ff'; + const display = screen.getPrimaryDisplay(); + + w.show(); + w.setBounds(display.bounds); + w.setBackgroundColor(WINDOW_BACKGROUND_COLOR); + await w.loadURL('about:blank'); + + view = new BrowserView(); + view.setBounds(display.bounds); + w.setBrowserView(view); + w.setBackgroundColor(VIEW_BACKGROUND_COLOR); + await view.webContents.loadURL('data:text/html,hello there'); + + const screenCapture = await captureScreen(); + const centerColor = getPixelColor(screenCapture, { + x: display.size.width / 2, + y: display.size.height / 2 + }); + + expect(areColorsSimilar(centerColor, VIEW_BACKGROUND_COLOR)).to.be.true(); + }); }); describe('BrowserView.setAutoResize()', () => { @@ -95,7 +146,14 @@ describe('BrowserView module', () => { }); describe('BrowserView.getBounds()', () => { - it('returns the current bounds', () => { + it('returns correct bounds on a framed window', () => { + view = new BrowserView(); + const bounds = { x: 10, y: 20, width: 30, height: 40 }; + view.setBounds(bounds); + expect(view.getBounds()).to.deep.equal(bounds); + }); + + it('returns correct bounds on a frameless window', () => { view = new BrowserView(); const bounds = { x: 10, y: 20, width: 30, height: 40 }; view.setBounds(bounds); diff --git a/spec-main/api-browser-window-spec.ts b/spec-main/api-browser-window-spec.ts index d7c29a507a539..a55316e21d31d 100644 --- a/spec-main/api-browser-window-spec.ts +++ b/spec-main/api-browser-window-spec.ts @@ -2,10 +2,8 @@ import { expect } from 'chai'; import * as childProcess from 'child_process'; import * as path from 'path'; import * as fs from 'fs'; -import * as os from 'os'; import * as qs from 'querystring'; import * as http from 'http'; -import * as semver from 'semver'; import { AddressInfo } from 'net'; import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersListenerDetails, protocol, screen, webContents, session, WebContents, BrowserWindowConstructorOptions } from 'electron/main'; @@ -694,12 +692,12 @@ describe('BrowserWindow module', () => { }); describe('BrowserWindow.show()', () => { - it('should focus on window', () => { - w.show(); + it('should focus on window', async () => { + await emittedOnce(w, 'focus', () => w.show()); expect(w.isFocused()).to.equal(true); }); - it('should make the window visible', () => { - w.show(); + it('should make the window visible', async () => { + await emittedOnce(w, 'focus', () => w.show()); expect(w.isVisible()).to.equal(true); }); it('emits when window is shown', async () => { @@ -895,7 +893,7 @@ describe('BrowserWindow module', () => { describe('BrowserWindow.getFocusedWindow()', () => { it('returns the opener window when dev tools window is focused', async () => { - w.show(); + await emittedOnce(w, 'focus', () => w.show()); w.webContents.openDevTools({ mode: 'undocked' }); await emittedOnce(w.webContents, 'devtools-focused'); expect(BrowserWindow.getFocusedWindow()).to.equal(w); @@ -1042,7 +1040,7 @@ describe('BrowserWindow module', () => { const boundsUpdate = { width: 200 }; w.setBounds(boundsUpdate as any); - const expectedBounds = Object.assign(fullBounds, boundsUpdate); + const expectedBounds = { ...fullBounds, ...boundsUpdate }; expectBoundsEqual(w.getBounds(), expectedBounds); }); @@ -1230,6 +1228,7 @@ describe('BrowserWindow module', () => { await resize; expectBoundsEqual(w.getNormalBounds(), w.getBounds()); }); + it('checks normal bounds after move', async () => { const pos = [10, 10]; const move = emittedOnce(w, 'move'); @@ -1248,6 +1247,51 @@ describe('BrowserWindow module', () => { await maximize; expectBoundsEqual(w.getNormalBounds(), bounds); }); + + it('updates normal bounds after resize and maximize', async () => { + const size = [300, 400]; + const resize = emittedOnce(w, 'resize'); + w.setSize(size[0], size[1]); + await resize; + const original = w.getBounds(); + + const maximize = emittedOnce(w, 'maximize'); + w.maximize(); + await maximize; + + const normal = w.getNormalBounds(); + const bounds = w.getBounds(); + + expect(normal).to.deep.equal(original); + expect(normal).to.not.deep.equal(bounds); + + const close = emittedOnce(w, 'close'); + w.close(); + await close; + }); + + it('updates normal bounds after move and maximize', async () => { + const pos = [10, 10]; + const move = emittedOnce(w, 'move'); + w.setPosition(pos[0], pos[1]); + await move; + const original = w.getBounds(); + + const maximize = emittedOnce(w, 'maximize'); + w.maximize(); + await maximize; + + const normal = w.getNormalBounds(); + const bounds = w.getBounds(); + + expect(normal).to.deep.equal(original); + expect(normal).to.not.deep.equal(bounds); + + const close = emittedOnce(w, 'close'); + w.close(); + await close; + }); + it('checks normal bounds when unmaximized', async () => { const bounds = w.getBounds(); w.once('maximize', () => { @@ -1259,6 +1303,7 @@ describe('BrowserWindow module', () => { await unmaximize; expectBoundsEqual(w.getNormalBounds(), bounds); }); + it('does not change size for a frameless window with min size', async () => { w.destroy(); w = new BrowserWindow({ @@ -1279,6 +1324,7 @@ describe('BrowserWindow module', () => { await unmaximize; expectBoundsEqual(w.getNormalBounds(), bounds); }); + it('correctly checks transparent window maximization state', async () => { w.destroy(); w = new BrowserWindow({ @@ -1298,6 +1344,7 @@ describe('BrowserWindow module', () => { await unmaximize; expect(w.isMaximized()).to.equal(false); }); + it('returns the correct value for windows with an aspect ratio', async () => { w.destroy(); w = new BrowserWindow({ @@ -1307,7 +1354,7 @@ describe('BrowserWindow module', () => { w.setAspectRatio(16 / 11); - const maximize = emittedOnce(w, 'resize'); + const maximize = emittedOnce(w, 'maximize'); w.show(); w.maximize(); await maximize; @@ -1327,6 +1374,41 @@ describe('BrowserWindow module', () => { await minimize; expectBoundsEqual(w.getNormalBounds(), bounds); }); + + it('updates normal bounds after move and minimize', async () => { + const pos = [10, 10]; + const move = emittedOnce(w, 'move'); + w.setPosition(pos[0], pos[1]); + await move; + const original = w.getBounds(); + + const minimize = emittedOnce(w, 'minimize'); + w.minimize(); + await minimize; + + const normal = w.getNormalBounds(); + + expect(original).to.deep.equal(normal); + expectBoundsEqual(normal, w.getBounds()); + }); + + it('updates normal bounds after resize and minimize', async () => { + const size = [300, 400]; + const resize = emittedOnce(w, 'resize'); + w.setSize(size[0], size[1]); + await resize; + const original = w.getBounds(); + + const minimize = emittedOnce(w, 'minimize'); + w.minimize(); + await minimize; + + const normal = w.getNormalBounds(); + + expect(original).to.deep.equal(normal); + expectBoundsEqual(normal, w.getBounds()); + }); + it('checks normal bounds when restored', async () => { const bounds = w.getBounds(); w.once('minimize', () => { @@ -1338,6 +1420,7 @@ describe('BrowserWindow module', () => { await restore; expectBoundsEqual(w.getNormalBounds(), bounds); }); + it('does not change size for a frameless window with min size', async () => { w.destroy(); w = new BrowserWindow({ @@ -1367,6 +1450,11 @@ describe('BrowserWindow module', () => { expect(w.fullScreen).to.be.true(); }); + it('does not go fullscreen if roundedCorners are enabled', async () => { + w = new BrowserWindow({ frame: false, roundedCorners: false, fullscreen: true }); + expect(w.fullScreen).to.be.false(); + }); + it('can be changed', () => { w.fullScreen = false; expect(w.fullScreen).to.be.false(); @@ -1383,6 +1471,50 @@ describe('BrowserWindow module', () => { expectBoundsEqual(w.getNormalBounds(), bounds); }); + it('updates normal bounds after resize and fullscreen', async () => { + const size = [300, 400]; + const resize = emittedOnce(w, 'resize'); + w.setSize(size[0], size[1]); + await resize; + const original = w.getBounds(); + + const fsc = emittedOnce(w, 'enter-full-screen'); + w.fullScreen = true; + await fsc; + + const normal = w.getNormalBounds(); + const bounds = w.getBounds(); + + expect(normal).to.deep.equal(original); + expect(normal).to.not.deep.equal(bounds); + + const close = emittedOnce(w, 'close'); + w.close(); + await close; + }); + + it('updates normal bounds after move and fullscreen', async () => { + const pos = [10, 10]; + const move = emittedOnce(w, 'move'); + w.setPosition(pos[0], pos[1]); + await move; + const original = w.getBounds(); + + const fsc = emittedOnce(w, 'enter-full-screen'); + w.fullScreen = true; + await fsc; + + const normal = w.getNormalBounds(); + const bounds = w.getBounds(); + + expect(normal).to.deep.equal(original); + expect(normal).to.not.deep.equal(bounds); + + const close = emittedOnce(w, 'close'); + w.close(); + await close; + }); + it('checks normal bounds when unfullscreen\'ed', async () => { const bounds = w.getBounds(); w.once('enter-full-screen', () => { @@ -1420,6 +1552,50 @@ describe('BrowserWindow module', () => { expectBoundsEqual(w.getNormalBounds(), bounds); }); + it('updates normal bounds after resize and fullscreen', async () => { + const size = [300, 400]; + const resize = emittedOnce(w, 'resize'); + w.setSize(size[0], size[1]); + await resize; + const original = w.getBounds(); + + const fsc = emittedOnce(w, 'enter-full-screen'); + w.setFullScreen(true); + await fsc; + + const normal = w.getNormalBounds(); + const bounds = w.getBounds(); + + expect(normal).to.deep.equal(original); + expect(normal).to.not.deep.equal(bounds); + + const close = emittedOnce(w, 'close'); + w.close(); + await close; + }); + + it('updates normal bounds after move and fullscreen', async () => { + const pos = [10, 10]; + const move = emittedOnce(w, 'move'); + w.setPosition(pos[0], pos[1]); + await move; + const original = w.getBounds(); + + const fsc = emittedOnce(w, 'enter-full-screen'); + w.setFullScreen(true); + await fsc; + + const normal = w.getNormalBounds(); + const bounds = w.getBounds(); + + expect(normal).to.deep.equal(original); + expect(normal).to.not.deep.equal(bounds); + + const close = emittedOnce(w, 'close'); + w.close(); + await close; + }); + it('checks normal bounds when unfullscreen\'ed', async () => { const bounds = w.getBounds(); w.show(); @@ -1825,10 +2001,46 @@ describe('BrowserWindow module', () => { w.setWindowButtonVisibility(false); expect(w._getWindowButtonVisibility()).to.equal(false); }); + + it('correctly updates when entering/exiting fullscreen for hidden style', async () => { + const w = new BrowserWindow({ show: false, frame: false, titleBarStyle: 'hidden' }); + expect(w._getWindowButtonVisibility()).to.equal(true); + w.setWindowButtonVisibility(false); + expect(w._getWindowButtonVisibility()).to.equal(false); + + const enterFS = emittedOnce(w, 'enter-full-screen'); + w.setFullScreen(true); + await enterFS; + + const leaveFS = emittedOnce(w, 'leave-full-screen'); + w.setFullScreen(false); + await leaveFS; + + w.setWindowButtonVisibility(true); + expect(w._getWindowButtonVisibility()).to.equal(true); + }); + + it('correctly updates when entering/exiting fullscreen for hiddenInset style', async () => { + const w = new BrowserWindow({ show: false, frame: false, titleBarStyle: 'hiddenInset' }); + expect(w._getWindowButtonVisibility()).to.equal(true); + w.setWindowButtonVisibility(false); + expect(w._getWindowButtonVisibility()).to.equal(false); + + const enterFS = emittedOnce(w, 'enter-full-screen'); + w.setFullScreen(true); + await enterFS; + + const leaveFS = emittedOnce(w, 'leave-full-screen'); + w.setFullScreen(false); + await leaveFS; + + w.setWindowButtonVisibility(true); + expect(w._getWindowButtonVisibility()).to.equal(true); + }); }); ifdescribe(process.platform === 'darwin')('BrowserWindow.setVibrancy(type)', () => { - let appProcess: childProcess.ChildProcessWithoutNullStreams | undefined; + let appProcess: childProcess.ChildProcessWithoutNullStreams | childProcess.ChildProcess | undefined; afterEach(() => { if (appProcess && !appProcess.killed) { @@ -1856,10 +2068,13 @@ describe('BrowserWindow module', () => { }).to.not.throw(); }); - it('Allows setting a transparent window via CSS', async () => { + // TODO(nornagon): disabled due to flakiness. + it.skip('Allows setting a transparent window via CSS', async () => { const appPath = path.join(__dirname, 'fixtures', 'apps', 'background-color-transparent'); - appProcess = childProcess.spawn(process.execPath, [appPath]); + appProcess = childProcess.spawn(process.execPath, [appPath], { + stdio: 'inherit' + }); const [code] = await emittedOnce(appProcess, 'exit'); expect(code).to.equal(0); @@ -1937,6 +2152,26 @@ describe('BrowserWindow module', () => { }); }); + describe('Opening a BrowserWindow from a link', () => { + let appProcess: childProcess.ChildProcessWithoutNullStreams | undefined; + + afterEach(() => { + if (appProcess && !appProcess.killed) { + appProcess.kill(); + appProcess = undefined; + } + }); + + it('can properly open and load a new window from a link', async () => { + const appPath = path.join(__dirname, 'fixtures', 'apps', 'open-new-window-from-link'); + + appProcess = childProcess.spawn(process.execPath, [appPath]); + + const [code] = await emittedOnce(appProcess, 'exit'); + expect(code).to.equal(0); + }); + }); + describe('BrowserWindow.fromWebContents(webContents)', () => { afterEach(closeAllWindows); @@ -2128,7 +2363,7 @@ describe('BrowserWindow module', () => { }); }); - ifdescribe(process.platform === 'win32' || (process.platform === 'darwin' && semver.gte(os.release(), '14.0.0')))('"titleBarStyle" option', () => { + ifdescribe(['win32', 'darwin'].includes(process.platform))('"titleBarStyle" option', () => { const testWindowsOverlay = async (style: any) => { const w = new BrowserWindow({ show: false, @@ -2167,8 +2402,10 @@ describe('BrowserWindow module', () => { const [, newOverlayRect] = await geometryChange; expect(newOverlayRect.width).to.equal(overlayRect.width + 400); }; - afterEach(closeAllWindows); - afterEach(() => { ipcMain.removeAllListeners('geometrychange'); }); + afterEach(async () => { + await closeAllWindows(); + ipcMain.removeAllListeners('geometrychange'); + }); it('creates browser window with hidden title bar', () => { const w = new BrowserWindow({ show: false, @@ -2195,9 +2432,44 @@ describe('BrowserWindow module', () => { ifit(process.platform === 'darwin')('sets Window Control Overlay with hidden inset title bar', async () => { await testWindowsOverlay('hiddenInset'); }); + + ifdescribe(process.platform === 'win32')('when an invalid titleBarStyle is initially set', () => { + let w: BrowserWindow; + + beforeEach(() => { + w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + }, + titleBarOverlay: { + color: '#0000f0', + symbolColor: '#ffffff' + }, + titleBarStyle: 'hiddenInset' + }); + }); + + afterEach(async () => { + await closeAllWindows(); + }); + + it('does not crash changing minimizability ', () => { + expect(() => { + w.setMinimizable(false); + }).to.not.throw(); + }); + + it('does not crash changing maximizability', () => { + expect(() => { + w.setMaximizable(false); + }).to.not.throw(); + }); + }); }); - ifdescribe(process.platform === 'win32' || (process.platform === 'darwin' && semver.gte(os.release(), '14.0.0')))('"titleBarOverlay" option', () => { + ifdescribe(['win32', 'darwin'].includes(process.platform))('"titleBarOverlay" option', () => { const testWindowsOverlayHeight = async (size: any) => { const w = new BrowserWindow({ show: false, @@ -2223,9 +2495,15 @@ describe('BrowserWindow module', () => { const overlayEnabled = await w.webContents.executeJavaScript('navigator.windowControlsOverlay.visible'); expect(overlayEnabled).to.be.true('overlayEnabled'); const overlayRectPreMax = await w.webContents.executeJavaScript('getJSOverlayProperties()'); - await w.maximize(); - const max = await w.isMaximized(); - expect(max).to.equal(true); + + if (!w.isMaximized()) { + const maximize = emittedOnce(w, 'maximize'); + w.show(); + w.maximize(); + await maximize; + } + + expect(w.isMaximized()).to.be.true('not maximized'); const overlayRectPostMax = await w.webContents.executeJavaScript('getJSOverlayProperties()'); expect(overlayRectPreMax.y).to.equal(0); @@ -2240,13 +2518,96 @@ describe('BrowserWindow module', () => { // Confirm that maximization only affected the height of the buttons and not the title bar expect(overlayRectPostMax.height).to.equal(size); }; - afterEach(closeAllWindows); - afterEach(() => { ipcMain.removeAllListeners('geometrychange'); }); + afterEach(async () => { + await closeAllWindows(); + ipcMain.removeAllListeners('geometrychange'); + }); it('sets Window Control Overlay with title bar height of 40', async () => { await testWindowsOverlayHeight(40); }); }); + ifdescribe(process.platform === 'win32')('BrowserWindow.setTitlebarOverlay', () => { + afterEach(async () => { + await closeAllWindows(); + ipcMain.removeAllListeners('geometrychange'); + }); + + it('does not crash when an invalid titleBarStyle was initially set', () => { + const win = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + }, + titleBarOverlay: { + color: '#0000f0', + symbolColor: '#ffffff' + }, + titleBarStyle: 'hiddenInset' + }); + + expect(() => { + win.setTitleBarOverlay({ + color: '#000000' + }); + }).to.not.throw(); + }); + + it('correctly updates the height of the overlay', async () => { + const testOverlay = async (w: BrowserWindow, size: Number, firstRun: boolean) => { + const overlayHTML = path.join(__dirname, 'fixtures', 'pages', 'overlay.html'); + const overlayReady = emittedOnce(ipcMain, 'geometrychange'); + await w.loadFile(overlayHTML); + if (firstRun) { + await overlayReady; + } + + const overlayEnabled = await w.webContents.executeJavaScript('navigator.windowControlsOverlay.visible'); + expect(overlayEnabled).to.be.true('overlayEnabled'); + const { height: preMaxHeight } = await w.webContents.executeJavaScript('getJSOverlayProperties()'); + + if (!w.isMaximized()) { + const maximize = emittedOnce(w, 'maximize'); + w.show(); + w.maximize(); + await maximize; + } + + expect(w.isMaximized()).to.be.true('not maximized'); + const { x, y, width, height } = await w.webContents.executeJavaScript('getJSOverlayProperties()'); + expect(x).to.equal(0); + expect(y).to.equal(0); + expect(width).to.be.greaterThan(0); + expect(height).to.equal(size); + expect(preMaxHeight).to.equal(size); + }; + + const INITIAL_SIZE = 40; + const w = new BrowserWindow({ + show: false, + width: 400, + height: 400, + titleBarStyle: 'hidden', + webPreferences: { + nodeIntegration: true, + contextIsolation: false + }, + titleBarOverlay: { + height: INITIAL_SIZE + } + }); + + await testOverlay(w, INITIAL_SIZE, true); + + w.setTitleBarOverlay({ + height: INITIAL_SIZE + 10 + }); + + await testOverlay(w, INITIAL_SIZE + 10, false); + }); + }); + ifdescribe(process.platform === 'darwin')('"enableLargerThanScreen" option', () => { afterEach(closeAllWindows); it('can move the window out of screen', () => { @@ -2395,7 +2756,7 @@ describe('BrowserWindow module', () => { for (const isolatedGlobal of isolated.globals) { notIsolatedGlobals.delete(isolatedGlobal); } - expect([...notIsolatedGlobals]).to.deep.equal([], 'non-isoalted renderer should have no additional globals'); + expect([...notIsolatedGlobals]).to.deep.equal([], 'non-isolated renderer should have no additional globals'); }); it('loads the script before other scripts in window', async () => { @@ -2979,11 +3340,16 @@ describe('BrowserWindow module', () => { }); w.webContents.setWindowOpenHandler(() => ({ action: 'allow', - overrideBrowserWindowOptions: { show: false, webPreferences: { contextIsolation: false, webviewTag: true, nodeIntegrationInSubFrames: true } } + overrideBrowserWindowOptions: { + show: false, + webPreferences: { + contextIsolation: false, + webviewTag: true, + nodeIntegrationInSubFrames: true, + preload + } + } })); - w.webContents.once('new-window', (event, url, frameName, disposition, options) => { - options.show = false; - }); const webviewLoaded = emittedOnce(ipcMain, 'webview-loaded'); w.loadFile(path.join(fixtures, 'api', 'new-window-webview.html')); @@ -3516,9 +3882,14 @@ describe('BrowserWindow module', () => { describe('beginFrameSubscription method', () => { it('does not crash when callback returns nothing', (done) => { const w = new BrowserWindow({ show: false }); + let called = false; w.loadFile(path.join(fixtures, 'api', 'frame-subscriber.html')); w.webContents.on('dom-ready', () => { w.webContents.beginFrameSubscription(function () { + // This callback might be called twice. + if (called) return; + called = true; + // Pending endFrameSubscription to next tick can reliably reproduce // a crash which happens when nothing is returned in the callback. setTimeout(() => { @@ -3965,6 +4336,14 @@ describe('BrowserWindow module', () => { await createTwo(); }); + ifit(process.platform !== 'darwin')('can disable and enable a window', () => { + const w = new BrowserWindow({ show: false }); + w.setEnabled(false); + expect(w.isEnabled()).to.be.false('w.isEnabled()'); + w.setEnabled(true); + expect(w.isEnabled()).to.be.true('!w.isEnabled()'); + }); + ifit(process.platform !== 'darwin')('disables parent window', () => { const w = new BrowserWindow({ show: false }); const c = new BrowserWindow({ show: false, parent: w, modal: true }); @@ -4534,12 +4913,13 @@ describe('BrowserWindow module', () => { }); ifdescribe(process.platform === 'darwin')('fullscreen state with resizable set', () => { - it('resizable flag should be set to true and restored', async () => { + it('resizable flag should be set to false and restored', async () => { const w = new BrowserWindow({ resizable: false }); + const enterFullScreen = emittedOnce(w, 'enter-full-screen'); w.setFullScreen(true); await enterFullScreen; - expect(w.resizable).to.be.true('resizable'); + expect(w.resizable).to.be.false('resizable'); await delay(); const leaveFullScreen = emittedOnce(w, 'leave-full-screen'); @@ -4547,6 +4927,21 @@ describe('BrowserWindow module', () => { await leaveFullScreen; expect(w.resizable).to.be.false('resizable'); }); + + it('default resizable flag should be restored after entering/exiting fullscreen', async () => { + const w = new BrowserWindow(); + + const enterFullScreen = emittedOnce(w, 'enter-full-screen'); + w.setFullScreen(true); + await enterFullScreen; + expect(w.resizable).to.be.false('resizable'); + + await delay(); + const leaveFullScreen = emittedOnce(w, 'leave-full-screen'); + w.setFullScreen(false); + await leaveFullScreen; + expect(w.resizable).to.be.true('resizable'); + }); }); ifdescribe(process.platform === 'darwin')('fullscreen state', () => { @@ -4564,6 +4959,23 @@ describe('BrowserWindow module', () => { await leaveFullScreen; }); + it('should be able to load a URL while transitioning to fullscreen', async () => { + const w = new BrowserWindow({ fullscreen: true }); + w.loadFile(path.join(fixtures, 'pages', 'c.html')); + + const load = emittedOnce(w.webContents, 'did-finish-load'); + const enterFS = emittedOnce(w, 'enter-full-screen'); + + await Promise.all([enterFS, load]); + expect(w.fullScreen).to.be.true(); + + await delay(); + + const leaveFullScreen = emittedOnce(w, 'leave-full-screen'); + w.setFullScreen(false); + await leaveFullScreen; + }); + it('can be changed with setFullScreen method', async () => { const w = new BrowserWindow(); const enterFullScreen = emittedOnce(w, 'enter-full-screen'); @@ -4599,19 +5011,80 @@ describe('BrowserWindow module', () => { expect(w.isFullScreen()).to.be.false('is fullscreen'); }); + it('handles several HTML fullscreen transitions', async () => { + const w = new BrowserWindow(); + await w.loadFile(path.join(fixtures, 'pages', 'a.html')); + + expect(w.isFullScreen()).to.be.false('is fullscreen'); + + const enterFullScreen = emittedOnce(w, 'enter-full-screen'); + const leaveFullScreen = emittedOnce(w, 'leave-full-screen'); + + await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await enterFullScreen; + await w.webContents.executeJavaScript('document.exitFullscreen()', true); + await leaveFullScreen; + + expect(w.isFullScreen()).to.be.false('is fullscreen'); + + await delay(); + + await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await enterFullScreen; + await w.webContents.executeJavaScript('document.exitFullscreen()', true); + await leaveFullScreen; + + expect(w.isFullScreen()).to.be.false('is fullscreen'); + }); + it('handles several transitions in close proximity', async () => { const w = new BrowserWindow(); expect(w.isFullScreen()).to.be.false('is fullscreen'); + const enterFS = emittedNTimes(w, 'enter-full-screen', 2); + const leaveFS = emittedNTimes(w, 'leave-full-screen', 2); + w.setFullScreen(true); w.setFullScreen(false); w.setFullScreen(true); + w.setFullScreen(false); - const enterFullScreen = emittedNTimes(w, 'enter-full-screen', 2); - await enterFullScreen; + await Promise.all([enterFS, leaveFS]); - expect(w.isFullScreen()).to.be.true('not fullscreen'); + expect(w.isFullScreen()).to.be.false('not fullscreen'); + }); + + it('handles several chromium-initiated transitions in close proximity', async () => { + const w = new BrowserWindow(); + await w.loadFile(path.join(fixtures, 'pages', 'a.html')); + + expect(w.isFullScreen()).to.be.false('is fullscreen'); + + let enterCount = 0; + let exitCount = 0; + + const done = new Promise(resolve => { + const checkDone = () => { + if (enterCount === 2 && exitCount === 2) resolve(); + }; + + w.webContents.on('enter-html-full-screen', () => { + enterCount++; + checkDone(); + }); + + w.webContents.on('leave-html-full-screen', () => { + exitCount++; + checkDone(); + }); + }); + + await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await w.webContents.executeJavaScript('document.exitFullscreen()'); + await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true); + await w.webContents.executeJavaScript('document.exitFullscreen()'); + await done; }); it('does not crash when exiting simpleFullScreen (properties)', async () => { @@ -4787,7 +5260,8 @@ describe('BrowserWindow module', () => { }); }); - describe('contextIsolation option with and without sandbox option', () => { + // TODO (jkleinsc) renable these tests on mas arm64 + ifdescribe(!process.mas || process.arch !== 'arm64')('contextIsolation option with and without sandbox option', () => { const expectedContextData = { preloadContext: { preloadProperty: 'number', @@ -5150,8 +5624,8 @@ describe('BrowserWindow module', () => { describe('"backgroundColor" option', () => { afterEach(closeAllWindows); - // Linux and arm64 platforms (WOA and macOS) do not return any capture sources - ifit(process.platform !== 'linux' && process.arch !== 'arm64')('should display the set color', async () => { + // Linux/WOA doesn't return any capture sources. + ifit(process.platform !== 'linux' && (process.platform !== 'win32' || process.arch !== 'arm64'))('should display the set color', async () => { const display = screen.getPrimaryDisplay(); const w = new BrowserWindow({ diff --git a/spec/api-clipboard-spec.js b/spec-main/api-clipboard-spec.ts similarity index 92% rename from spec/api-clipboard-spec.js rename to spec-main/api-clipboard-spec.ts index fb08eb768f6da..604c8d03bfa4e 100644 --- a/spec/api-clipboard-spec.js +++ b/spec-main/api-clipboard-spec.ts @@ -1,9 +1,8 @@ -const { expect } = require('chai'); -const path = require('path'); -const { Buffer } = require('buffer'); -const { ifdescribe, ifit } = require('./spec-helpers'); - -const { clipboard, nativeImage } = require('electron'); +import { expect } from 'chai'; +import * as path from 'path'; +import { Buffer } from 'buffer'; +import { ifdescribe, ifit } from './spec-helpers'; +import { clipboard, nativeImage } from 'electron/common'; // FIXME(zcbenz): Clipboard tests are failing on WOA. ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('clipboard module', () => { @@ -13,7 +12,7 @@ ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('clipboard it('returns NativeImage instance', () => { const p = path.join(fixtures, 'assets', 'logo.png'); const i = nativeImage.createFromPath(p); - clipboard.writeImage(p); + clipboard.writeImage(i); const readImage = clipboard.readImage(); expect(readImage.toDataURL()).to.equal(i.toDataURL()); }); @@ -67,7 +66,7 @@ ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('clipboard const type = process.platform === 'darwin' ? 'NSFilenamesPboardType' : 'FileNameW'; expect(() => { - const result = clipboard.read(type); + clipboard.read(type); }).to.not.throw(); }); it('can read data written with writeBuffer', () => { @@ -91,7 +90,7 @@ ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('clipboard html: 'Hi', rtf: '{\\rtf1\\utf8 text}', bookmark: 'a title', - image: p + image: i }); expect(clipboard.readText()).to.equal(text); @@ -126,7 +125,7 @@ ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('clipboard it('throws an error when a non-Buffer is specified', () => { expect(() => { - clipboard.writeBuffer('public/utf8-plain-text', 'hello'); + clipboard.writeBuffer('public/utf8-plain-text', 'hello' as any); }).to.throw(/buffer must be a node Buffer/); }); diff --git a/spec-main/api-debugger-spec.ts b/spec-main/api-debugger-spec.ts index d75d786b2b8aa..a37f45b67b06f 100644 --- a/spec-main/api-debugger-spec.ts +++ b/spec-main/api-debugger-spec.ts @@ -133,39 +133,26 @@ describe('debugger module', () => { w.webContents.debugger.detach(); }); - // TODO(deepak1556): Fix and enable with upgrade - it.skip('handles valid unicode characters in message', (done) => { - try { - w.webContents.debugger.attach(); - } catch (err) { - done(`unexpected error : ${err}`); - } - - let requestId : number; - w.webContents.debugger.on('message', (event, method, params) => { - if (method === 'Network.responseReceived' && - params.response.url.startsWith('http://127.0.0.1')) { - requestId = params.requestId; - } else if (method === 'Network.loadingFinished' && - params.requestId === requestId) { - w.webContents.debugger.sendCommand('Network.getResponseBody', { - requestId: params.requestId - }).then(data => { - expect(data.body).to.equal('\u0024'); - done(); - }).catch(result => done(result)); - } - }); - + it('handles valid unicode characters in message', async () => { server = http.createServer((req, res) => { res.setHeader('Content-Type', 'text/plain; charset=utf-8'); res.end('\u0024'); }); + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); - server.listen(0, '127.0.0.1', () => { - w.webContents.debugger.sendCommand('Network.enable'); - w.loadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}`); - }); + w.loadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}`); + // If we do this synchronously, it's fast enough to attach and enable + // network capture before the load. If we do it before the loadURL, for + // some reason network capture doesn't get enabled soon enough and we get + // an error when calling `Network.getResponseBody`. + w.webContents.debugger.attach(); + w.webContents.debugger.sendCommand('Network.enable'); + const [,, { requestId }] = await emittedUntil(w.webContents.debugger, 'message', (_event: any, method: string, params: any) => + method === 'Network.responseReceived' && params.response.url.startsWith('http://127.0.0.1')); + await emittedUntil(w.webContents.debugger, 'message', (_event: any, method: string, params: any) => + method === 'Network.loadingFinished' && params.requestId === requestId); + const { body } = await w.webContents.debugger.sendCommand('Network.getResponseBody', { requestId }); + expect(body).to.equal('\u0024'); }); it('does not crash for invalid unicode characters in message', (done) => { diff --git a/spec-main/api-desktop-capturer-spec.ts b/spec-main/api-desktop-capturer-spec.ts index d5455a812a230..ad343b9305ce7 100644 --- a/spec-main/api-desktop-capturer-spec.ts +++ b/spec-main/api-desktop-capturer-spec.ts @@ -1,7 +1,8 @@ import { expect } from 'chai'; import { screen, desktopCapturer, BrowserWindow } from 'electron/main'; +import { delay, ifdescribe, ifit } from './spec-helpers'; import { emittedOnce } from './events-helpers'; -import { ifdescribe, ifit } from './spec-helpers'; + import { closeAllWindows } from './window-helpers'; const features = process._linkedBinding('electron_common_features'); @@ -154,26 +155,37 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt } }); - // TODO(deepak1556): currently fails on all ci, enable it after upgrade. - it.skip('moveAbove should move the window at the requested place', async () => { + it('moveAbove should move the window at the requested place', async () => { // DesktopCapturer.getSources() is guaranteed to return in the correct // z-order from foreground to background. const MAX_WIN = 4; - const mainWindow = w; - const wList = [mainWindow]; + const wList: BrowserWindow[] = []; + + const destroyWindows = () => { + for (const w of wList) { + w.destroy(); + } + }; + try { - for (let i = 0; i < MAX_WIN - 1; i++) { - const w = new BrowserWindow({ show: true, width: 100, height: 100 }); + for (let i = 0; i < MAX_WIN; i++) { + const w = new BrowserWindow({ show: false, width: 100, height: 100 }); wList.push(w); } expect(wList.length).to.equal(MAX_WIN); // Show and focus all the windows. - wList.forEach(async (w) => { + for (const w of wList) { + const wShown = emittedOnce(w, 'show'); const wFocused = emittedOnce(w, 'focus'); + + w.show(); w.focus(); + + await wShown; await wFocused; - }); + } + // At this point our windows should be showing from bottom to top. // DesktopCapturer.getSources() returns sources sorted from foreground to @@ -187,11 +199,7 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt // bots while it is not on my workstation, as expected, with and without // the --ci parameter. if (process.platform === 'linux' && sources.length === 0) { - wList.forEach((w) => { - if (w !== mainWindow) { - w.destroy(); - } - }); + destroyWindows(); it.skip('desktopCapturer.getSources returned an empty source list'); return; } @@ -205,44 +213,40 @@ ifdescribe(!process.arch.includes('arm') && process.platform !== 'win32')('deskt expect(sources.length).to.equal(wList.length); // Check that the sources and wList are sorted in the reverse order. - const wListReversed = wList.slice(0).reverse(); - const canGoFurther = sources.every( + // If they're not, skip remaining checks because either focus or + // window placement are not reliable in the running test environment. + const wListReversed = wList.slice().reverse(); + const proceed = sources.every( (source, index) => source.id === wListReversed[index].getMediaSourceId()); - if (!canGoFurther) { - // Skip remaining checks because either focus or window placement are - // not reliable in the running test environment. So there is no point - // to go further to test moveAbove as requirements are not met. - return; - } - - // Do the real work, i.e. move each window above the next one so that - // wList is sorted from foreground to background. - wList.forEach(async (w, index) => { - if (index < (wList.length - 1)) { - const wNext = wList[index + 1]; - w.moveAbove(wNext.getMediaSourceId()); + if (!proceed) return; + + // Move windows so wList is sorted from foreground to background. + for (const [i, w] of wList.entries()) { + if (i < wList.length - 1) { + const next = wList[wList.length - 1]; + w.focus(); + w.moveAbove(next.getMediaSourceId()); + // Ensure the window has time to move. + await delay(2000); } - }); + } sources = await desktopCapturer.getSources({ types: ['window'], thumbnailSize: { width: 0, height: 0 } }); - // Only keep our windows again. - sources.splice(MAX_WIN, sources.length - MAX_WIN); + + sources.splice(MAX_WIN, sources.length); expect(sources.length).to.equal(MAX_WIN); expect(sources.length).to.equal(wList.length); // Check that the sources and wList are sorted in the same order. - sources.forEach((source, index) => { - expect(source.id).to.equal(wList[index].getMediaSourceId()); - }); + for (const [index, source] of sources.entries()) { + const wID = wList[index].getMediaSourceId(); + expect(source.id).to.equal(wID); + } } finally { - wList.forEach((w) => { - if (w !== mainWindow) { - w.destroy(); - } - }); + destroyWindows(); } }); }); diff --git a/spec-main/api-global-shortcut-spec.ts b/spec-main/api-global-shortcut-spec.ts index 689ea56bbb363..36d5191e5642f 100644 --- a/spec-main/api-global-shortcut-spec.ts +++ b/spec-main/api-global-shortcut-spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { globalShortcut, BrowserWindow } from 'electron/main'; +import { globalShortcut } from 'electron/main'; import { ifdescribe } from './spec-helpers'; ifdescribe(process.platform !== 'win32')('globalShortcut module', () => { @@ -55,20 +55,4 @@ ifdescribe(process.platform !== 'win32')('globalShortcut module', () => { globalShortcut.unregisterAll(); }); - - it('successfully registers and calls the callback for media keys', function (done) { - let robotjs; - try { - robotjs = require('robotjs'); - } catch (err) { - this.skip(); - } - - globalShortcut.register('MediaPlayPause', () => done()); - - const w = new BrowserWindow({ show: false }); - w.loadURL('about:blank'); - - robotjs.keyTap('audio_play'); - }); }); diff --git a/spec-main/api-ipc-spec.ts b/spec-main/api-ipc-spec.ts index 0595531be86ff..c63c9ba94eb85 100644 --- a/spec-main/api-ipc-spec.ts +++ b/spec-main/api-ipc-spec.ts @@ -3,8 +3,13 @@ import { expect } from 'chai'; import { BrowserWindow, ipcMain, IpcMainInvokeEvent, MessageChannelMain, WebContents } from 'electron/main'; import { closeAllWindows } from './window-helpers'; import { emittedOnce } from './events-helpers'; +import { defer } from './spec-helpers'; +import * as path from 'path'; +import * as http from 'http'; +import { AddressInfo } from 'net'; const v8Util = process._linkedBinding('electron_common_v8_util'); +const fixturesPath = path.resolve(__dirname, 'fixtures'); describe('ipc module', () => { describe('invoke', () => { @@ -90,7 +95,7 @@ describe('ipc module', () => { }); it('throws an error when invoking a handler that was removed', async () => { - ipcMain.handle('test', () => {}); + ipcMain.handle('test', () => { }); ipcMain.removeHandler('test'); const done = new Promise(resolve => ipcMain.once('result', (e, arg) => { expect(arg.error).to.match(/No handler registered/); @@ -101,9 +106,9 @@ describe('ipc module', () => { }); it('forbids multiple handlers', async () => { - ipcMain.handle('test', () => {}); + ipcMain.handle('test', () => { }); try { - expect(() => { ipcMain.handle('test', () => {}); }).to.throw(/second handler/); + expect(() => { ipcMain.handle('test', () => { }); }).to.throw(/second handler/); } finally { ipcMain.removeHandler('test'); } @@ -563,4 +568,195 @@ describe('ipc module', () => { generateTests('WebContents.postMessage', contents => contents.postMessage.bind(contents)); generateTests('WebFrameMain.postMessage', contents => contents.mainFrame.postMessage.bind(contents.mainFrame)); }); + + describe('WebContents.ipc', () => { + afterEach(closeAllWindows); + + it('receives ipc messages sent from the WebContents', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.send(\'test\', 42)'); + const [, num] = await emittedOnce(w.webContents.ipc, 'test'); + expect(num).to.equal(42); + }); + + it('receives sync-ipc messages sent from the WebContents', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.ipc.on('test', (event, arg) => { + event.returnValue = arg * 2; + }); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.sendSync(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('receives postMessage messages sent from the WebContents, w/ MessagePorts', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.postMessage(\'test\', null, [(new MessageChannel).port1])'); + const [event] = await emittedOnce(w.webContents.ipc, 'test'); + expect(event.ports.length).to.equal(1); + }); + + it('handles invoke messages sent from the WebContents', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.ipc.handle('test', (_event, arg) => arg * 2); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.invoke(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('cascades to ipcMain', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + let gotFromIpcMain = false; + const ipcMainReceived = new Promise(resolve => ipcMain.on('test', () => { gotFromIpcMain = true; resolve(); })); + const ipcReceived = new Promise(resolve => w.webContents.ipc.on('test', () => { resolve(gotFromIpcMain); })); + defer(() => ipcMain.removeAllListeners('test')); + w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.send(\'test\', 42)'); + + // assert that they are delivered in the correct order + expect(await ipcReceived).to.be.false(); + await ipcMainReceived; + }); + + it('overrides ipcMain handlers', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.ipc.handle('test', (_event, arg) => arg * 2); + ipcMain.handle('test', () => { throw new Error('should not be called'); }); + defer(() => ipcMain.removeHandler('test')); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.invoke(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('falls back to ipcMain handlers', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + ipcMain.handle('test', (_event, arg) => { return arg * 2; }); + defer(() => ipcMain.removeHandler('test')); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.invoke(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('receives ipcs from child frames', async () => { + const server = http.createServer((req, res) => { + res.setHeader('content-type', 'text/html'); + res.end(''); + }); + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); + const port = (server.address() as AddressInfo).port; + defer(() => { + server.close(); + }); + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegrationInSubFrames: true, preload: path.resolve(fixturesPath, 'preload-expose-ipc.js') } }); + // Preloads don't run in about:blank windows, and file:// urls can't be loaded in iframes, so use a blank http page. + await w.loadURL(`data:text/html,`); + w.webContents.mainFrame.frames[0].executeJavaScript('ipc.send(\'test\', 42)'); + const [, arg] = await emittedOnce(w.webContents.ipc, 'test'); + expect(arg).to.equal(42); + }); + }); + + describe('WebFrameMain.ipc', () => { + afterEach(closeAllWindows); + it('responds to ipc messages in the main frame', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.send(\'test\', 42)'); + const [, arg] = await emittedOnce(w.webContents.mainFrame.ipc, 'test'); + expect(arg).to.equal(42); + }); + + it('responds to sync ipc messages in the main frame', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.mainFrame.ipc.on('test', (event, arg) => { + event.returnValue = arg * 2; + }); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.sendSync(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('receives postMessage messages sent from the WebContents, w/ MessagePorts', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.postMessage(\'test\', null, [(new MessageChannel).port1])'); + const [event] = await emittedOnce(w.webContents.mainFrame.ipc, 'test'); + expect(event.ports.length).to.equal(1); + }); + + it('handles invoke messages sent from the WebContents', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.mainFrame.ipc.handle('test', (_event, arg) => arg * 2); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.invoke(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('cascades to WebContents and ipcMain', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + let gotFromIpcMain = false; + let gotFromWebContents = false; + const ipcMainReceived = new Promise(resolve => ipcMain.on('test', () => { gotFromIpcMain = true; resolve(); })); + const ipcWebContentsReceived = new Promise(resolve => w.webContents.ipc.on('test', () => { gotFromWebContents = true; resolve(gotFromIpcMain); })); + const ipcReceived = new Promise(resolve => w.webContents.mainFrame.ipc.on('test', () => { resolve(gotFromWebContents); })); + defer(() => ipcMain.removeAllListeners('test')); + w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.send(\'test\', 42)'); + + // assert that they are delivered in the correct order + expect(await ipcReceived).to.be.false(); + expect(await ipcWebContentsReceived).to.be.false(); + await ipcMainReceived; + }); + + it('overrides ipcMain handlers', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.mainFrame.ipc.handle('test', (_event, arg) => arg * 2); + ipcMain.handle('test', () => { throw new Error('should not be called'); }); + defer(() => ipcMain.removeHandler('test')); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.invoke(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('overrides WebContents handlers', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.ipc.handle('test', () => { throw new Error('should not be called'); }); + w.webContents.mainFrame.ipc.handle('test', (_event, arg) => arg * 2); + ipcMain.handle('test', () => { throw new Error('should not be called'); }); + defer(() => ipcMain.removeHandler('test')); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.invoke(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('falls back to WebContents handlers', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + w.webContents.ipc.handle('test', (_event, arg) => { return arg * 2; }); + const result = await w.webContents.executeJavaScript('require(\'electron\').ipcRenderer.invoke(\'test\', 42)'); + expect(result).to.equal(42 * 2); + }); + + it('receives ipcs from child frames', async () => { + const server = http.createServer((req, res) => { + res.setHeader('content-type', 'text/html'); + res.end(''); + }); + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); + const port = (server.address() as AddressInfo).port; + defer(() => { + server.close(); + }); + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegrationInSubFrames: true, preload: path.resolve(fixturesPath, 'preload-expose-ipc.js') } }); + // Preloads don't run in about:blank windows, and file:// urls can't be loaded in iframes, so use a blank http page. + await w.loadURL(`data:text/html,`); + w.webContents.mainFrame.frames[0].executeJavaScript('ipc.send(\'test\', 42)'); + w.webContents.mainFrame.ipc.on('test', () => { throw new Error('should not be called'); }); + const [, arg] = await emittedOnce(w.webContents.mainFrame.frames[0].ipc, 'test'); + expect(arg).to.equal(42); + }); + }); }); diff --git a/spec/api-native-image-spec.js b/spec-main/api-native-image-spec.ts similarity index 76% rename from spec/api-native-image-spec.js rename to spec-main/api-native-image-spec.ts index 715655f15fd2a..57b09ec8f6e0e 100644 --- a/spec/api-native-image-spec.js +++ b/spec-main/api-native-image-spec.ts @@ -1,119 +1,53 @@ -'use strict'; - -const { expect } = require('chai'); -const { nativeImage } = require('electron'); -const { ifdescribe, ifit } = require('./spec-helpers'); -const path = require('path'); +import { expect } from 'chai'; +import { nativeImage } from 'electron/common'; +import { ifdescribe, ifit } from './spec-helpers'; +import * as path from 'path'; describe('nativeImage module', () => { - const ImageFormat = { - PNG: 'png', - JPEG: 'jpeg' - }; - - const images = [ - { - filename: 'logo.png', - format: ImageFormat.PNG, - hasAlphaChannel: true, - hasDataUrl: false, - width: 538, - height: 190 - }, - { - dataUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYlWNgAAIAAAUAAdafFs0AAAAASUVORK5CYII=', - filename: '1x1.png', - format: ImageFormat.PNG, - hasAlphaChannel: true, - hasDataUrl: true, - height: 1, - width: 1 - }, - { - dataUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAFklEQVQYlWP8//8/AwMDEwMDAwMDAwAkBgMBBMzldwAAAABJRU5ErkJggg==', - filename: '2x2.jpg', - format: ImageFormat.JPEG, - hasAlphaChannel: false, - hasDataUrl: true, - height: 2, - width: 2 - }, - { - dataUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAADElEQVQYlWNgIAoAAAAnAAGZWEMnAAAAAElFTkSuQmCC', - filename: '3x3.png', - format: ImageFormat.PNG, - hasAlphaChannel: true, - hasDataUrl: true, - height: 3, - width: 3 - } - ]; + const fixturesPath = path.join(__dirname, '..', 'spec', 'fixtures'); - /** - * @param {?string} filename - * @returns {?string} Full path. - */ - const getImagePathFromFilename = (filename) => { - return (filename === null) ? null - : path.join(__dirname, 'fixtures', 'assets', filename); + const imageLogo = { + path: path.join(fixturesPath, 'assets', 'logo.png'), + width: 538, + height: 190 }; - - /** - * @param {!Object} image - * @param {Object} filters - * @returns {boolean} - */ - const imageMatchesTheFilters = (image, filters = null) => { - if (filters === null) { - return true; - } - - return Object.entries(filters) - .every(([key, value]) => image[key] === value); + const image1x1 = { + dataUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYlWNgAAIAAAUAAdafFs0AAAAASUVORK5CYII=', + path: path.join(fixturesPath, 'assets', '1x1.png'), + height: 1, + width: 1 }; - - /** - * @param {!Object} filters - * @returns {!Array} A matching images list. - */ - const getImages = (filters) => { - const matchingImages = images - .filter(i => imageMatchesTheFilters(i, filters)); - - // Add `.path` property to every image. - matchingImages - .forEach(i => { i.path = getImagePathFromFilename(i.filename); }); - - return matchingImages; + const image2x2 = { + dataUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAFklEQVQYlWP8//8/AwMDEwMDAwMDAwAkBgMBBMzldwAAAABJRU5ErkJggg==', + path: path.join(fixturesPath, 'assets', '2x2.jpg'), + height: 2, + width: 2 }; - - /** - * @param {!Object} filters - * @returns {Object} A matching image if any. - */ - const getImage = (filters) => { - const matchingImages = getImages(filters); - - let matchingImage = null; - if (matchingImages.length > 0) { - matchingImage = matchingImages[0]; - } - - return matchingImage; + const image3x3 = { + dataUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAADElEQVQYlWNgIAoAAAAnAAGZWEMnAAAAAElFTkSuQmCC', + path: path.join(fixturesPath, 'assets', '3x3.png'), + height: 3, + width: 3 }; + const dataUrlImages = [ + image1x1, + image2x2, + image3x3 + ]; + ifdescribe(process.platform === 'darwin')('isMacTemplateImage state', () => { describe('with properties', () => { it('correctly recognizes a template image', () => { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); expect(image.isMacTemplateImage).to.be.false(); - const templateImage = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo_Template.png')); + const templateImage = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo_Template.png')); expect(templateImage.isMacTemplateImage).to.be.true(); }); it('sets a template image', function () { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); expect(image.isMacTemplateImage).to.be.false(); image.isMacTemplateImage = true; @@ -123,15 +57,15 @@ describe('nativeImage module', () => { describe('with functions', () => { it('correctly recognizes a template image', () => { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); expect(image.isTemplateImage()).to.be.false(); - const templateImage = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo_Template.png')); + const templateImage = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo_Template.png')); expect(templateImage.isTemplateImage()).to.be.true(); }); it('sets a template image', function () { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); expect(image.isTemplateImage()).to.be.false(); image.setTemplateImage(true); @@ -168,7 +102,7 @@ describe('nativeImage module', () => { }); it('returns an image created from the given buffer', () => { - const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const imageA = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); const imageB = nativeImage.createFromBitmap(imageA.toBitmap(), imageA.getSize()); expect(imageB.getSize()).to.deep.equal({ width: 538, height: 190 }); @@ -178,10 +112,10 @@ describe('nativeImage module', () => { }); it('throws on invalid arguments', () => { - expect(() => nativeImage.createFromBitmap(null, {})).to.throw('buffer must be a node Buffer'); - expect(() => nativeImage.createFromBitmap([12, 14, 124, 12], {})).to.throw('buffer must be a node Buffer'); - expect(() => nativeImage.createFromBitmap(Buffer.from([]), {})).to.throw('width is required'); - expect(() => nativeImage.createFromBitmap(Buffer.from([]), { width: 1 })).to.throw('height is required'); + expect(() => nativeImage.createFromBitmap(null as any, {} as any)).to.throw('buffer must be a node Buffer'); + expect(() => nativeImage.createFromBitmap([12, 14, 124, 12] as any, {} as any)).to.throw('buffer must be a node Buffer'); + expect(() => nativeImage.createFromBitmap(Buffer.from([]), {} as any)).to.throw('width is required'); + expect(() => nativeImage.createFromBitmap(Buffer.from([]), { width: 1 } as any)).to.throw('height is required'); expect(() => nativeImage.createFromBitmap(Buffer.from([]), { width: 1, height: 1 })).to.throw('invalid buffer size'); }); }); @@ -197,7 +131,7 @@ describe('nativeImage module', () => { }); it('returns an image created from the given buffer', () => { - const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const imageA = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); const imageB = nativeImage.createFromBuffer(imageA.toPNG()); expect(imageB.getSize()).to.deep.equal({ width: 538, height: 190 }); @@ -231,8 +165,8 @@ describe('nativeImage module', () => { }); it('throws on invalid arguments', () => { - expect(() => nativeImage.createFromBuffer(null)).to.throw('buffer must be a node Buffer'); - expect(() => nativeImage.createFromBuffer([12, 14, 124, 12])).to.throw('buffer must be a node Buffer'); + expect(() => nativeImage.createFromBuffer(null as any)).to.throw('buffer must be a node Buffer'); + expect(() => nativeImage.createFromBuffer([12, 14, 124, 12] as any)).to.throw('buffer must be a node Buffer'); }); }); @@ -242,15 +176,14 @@ describe('nativeImage module', () => { }); it('returns an image created from the given string', () => { - const imagesData = getImages({ hasDataUrl: true }); - for (const imageData of imagesData) { + for (const imageData of dataUrlImages) { const imageFromPath = nativeImage.createFromPath(imageData.path); - const imageFromDataUrl = nativeImage.createFromDataURL(imageData.dataUrl); + const imageFromDataUrl = nativeImage.createFromDataURL(imageData.dataUrl!); expect(imageFromDataUrl.isEmpty()).to.be.false(); expect(imageFromDataUrl.getSize()).to.deep.equal(imageFromPath.getSize()); expect(imageFromDataUrl.toBitmap()).to.satisfy( - bitmap => imageFromPath.toBitmap().equals(bitmap)); + (bitmap: any) => imageFromPath.toBitmap().equals(bitmap)); expect(imageFromDataUrl.toDataURL()).to.equal(imageFromPath.toDataURL()); } }); @@ -258,9 +191,8 @@ describe('nativeImage module', () => { describe('toDataURL()', () => { it('returns a PNG data URL', () => { - const imagesData = getImages({ hasDataUrl: true }); - for (const imageData of imagesData) { - const imageFromPath = nativeImage.createFromPath(imageData.path); + for (const imageData of dataUrlImages) { + const imageFromPath = nativeImage.createFromPath(imageData.path!); const scaleFactors = [1.0, 2.0]; for (const scaleFactor of scaleFactors) { @@ -270,7 +202,7 @@ describe('nativeImage module', () => { }); it('returns a data URL at 1x scale factor by default', () => { - const imageData = getImage({ filename: 'logo.png' }); + const imageData = imageLogo; const image = nativeImage.createFromPath(imageData.path); const imageOne = nativeImage.createFromBuffer(image.toPNG(), { @@ -289,7 +221,7 @@ describe('nativeImage module', () => { }); it('supports a scale factor', () => { - const imageData = getImage({ filename: 'logo.png' }); + const imageData = imageLogo; const image = nativeImage.createFromPath(imageData.path); const expectedSize = { width: imageData.width, height: imageData.height }; @@ -305,7 +237,7 @@ describe('nativeImage module', () => { describe('toPNG()', () => { it('returns a buffer at 1x scale factor by default', () => { - const imageData = getImage({ filename: 'logo.png' }); + const imageData = imageLogo; const imageA = nativeImage.createFromPath(imageData.path); const imageB = nativeImage.createFromBuffer(imageA.toPNG(), { @@ -324,7 +256,7 @@ describe('nativeImage module', () => { }); it('supports a scale factor', () => { - const imageData = getImage({ filename: 'logo.png' }); + const imageData = imageLogo; const image = nativeImage.createFromPath(imageData.path); const imageFromBufferOne = nativeImage.createFromBuffer( @@ -349,28 +281,28 @@ describe('nativeImage module', () => { }); it('loads images from paths relative to the current working directory', () => { - const imagePath = path.relative('.', path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const imagePath = path.relative('.', path.join(fixturesPath, 'assets', 'logo.png')); const image = nativeImage.createFromPath(imagePath); expect(image.isEmpty()).to.be.false(); expect(image.getSize()).to.deep.equal({ width: 538, height: 190 }); }); it('loads images from paths with `.` segments', () => { - const imagePath = `${path.join(__dirname, 'fixtures')}${path.sep}.${path.sep}${path.join('assets', 'logo.png')}`; + const imagePath = `${path.join(fixturesPath)}${path.sep}.${path.sep}${path.join('assets', 'logo.png')}`; const image = nativeImage.createFromPath(imagePath); expect(image.isEmpty()).to.be.false(); expect(image.getSize()).to.deep.equal({ width: 538, height: 190 }); }); it('loads images from paths with `..` segments', () => { - const imagePath = `${path.join(__dirname, 'fixtures', 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`; + const imagePath = `${path.join(fixturesPath, 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`; const image = nativeImage.createFromPath(imagePath); expect(image.isEmpty()).to.be.false(); expect(image.getSize()).to.deep.equal({ width: 538, height: 190 }); }); ifit(process.platform === 'darwin')('Gets an NSImage pointer on macOS', function () { - const imagePath = `${path.join(__dirname, 'fixtures', 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`; + const imagePath = `${path.join(fixturesPath, 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`; const image = nativeImage.createFromPath(imagePath); const nsimage = image.getNativeHandle(); @@ -382,7 +314,7 @@ describe('nativeImage module', () => { }); ifit(process.platform === 'win32')('loads images from .ico files on Windows', function () { - const imagePath = path.join(__dirname, 'fixtures', 'assets', 'icon.ico'); + const imagePath = path.join(fixturesPath, 'assets', 'icon.ico'); const image = nativeImage.createFromPath(imagePath); expect(image.isEmpty()).to.be.false(); expect(image.getSize()).to.deep.equal({ width: 256, height: 256 }); @@ -413,7 +345,7 @@ describe('nativeImage module', () => { describe('resize(options)', () => { it('returns a resized image', () => { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); for (const [resizeTo, expectedSize] of new Map([ [{}, { width: 538, height: 190 }], [{ width: 269 }, { width: 269, height: 95 }], @@ -436,7 +368,7 @@ describe('nativeImage module', () => { }); it('supports a quality option', () => { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); const good = image.resize({ width: 100, height: 100, quality: 'good' }); const better = image.resize({ width: 100, height: 100, quality: 'better' }); const best = image.resize({ width: 100, height: 100, quality: 'best' }); @@ -453,7 +385,7 @@ describe('nativeImage module', () => { }); it('returns an empty image when the bounds are invalid', () => { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); expect(image.crop({ width: 0, height: 0, x: 0, y: 0 }).isEmpty()).to.be.true(); expect(image.crop({ width: -1, height: 10, x: 0, y: 0 }).isEmpty()).to.be.true(); expect(image.crop({ width: 10, height: -35, x: 0, y: 0 }).isEmpty()).to.be.true(); @@ -461,7 +393,7 @@ describe('nativeImage module', () => { }); it('returns a cropped image', () => { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); const cropA = image.crop({ width: 25, height: 64, x: 0, y: 0 }); const cropB = image.crop({ width: 25, height: 64, x: 30, y: 40 }); expect(cropA.getSize()).to.deep.equal({ width: 25, height: 64 }); @@ -470,7 +402,7 @@ describe('nativeImage module', () => { }); it('toBitmap() returns a buffer of the right size', () => { - const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')); + const image = nativeImage.createFromPath(path.join(fixturesPath, 'assets', 'logo.png')); const crop = image.crop({ width: 25, height: 64, x: 0, y: 0 }); expect(crop.toBitmap().length).to.equal(25 * 64 * 4); }); @@ -482,7 +414,7 @@ describe('nativeImage module', () => { }); it('returns an aspect ratio of an image', () => { - const imageData = getImage({ filename: 'logo.png' }); + const imageData = imageLogo; // imageData.width / imageData.height = 2.831578947368421 const expectedAspectRatio = 2.8315789699554443; @@ -510,7 +442,7 @@ describe('nativeImage module', () => { }); it('returns native image given valid params', async () => { - const goodPath = path.join(__dirname, 'fixtures', 'assets', 'logo.png'); + const goodPath = path.join(fixturesPath, 'assets', 'logo.png'); const goodSize = { width: 100, height: 100 }; const result = await nativeImage.createThumbnailFromPath(goodPath, goodSize); expect(result.isEmpty()).to.equal(false); @@ -533,7 +465,7 @@ describe('nativeImage module', () => { it('supports adding a buffer representation for a scale factor', () => { const image = nativeImage.createEmpty(); - const imageDataOne = getImage({ width: 1, height: 1 }); + const imageDataOne = image1x1; image.addRepresentation({ scaleFactor: 1.0, buffer: nativeImage.createFromPath(imageDataOne.path).toPNG() @@ -541,7 +473,7 @@ describe('nativeImage module', () => { expect(image.getScaleFactors()).to.deep.equal([1]); - const imageDataTwo = getImage({ width: 2, height: 2 }); + const imageDataTwo = image2x2; image.addRepresentation({ scaleFactor: 2.0, buffer: nativeImage.createFromPath(imageDataTwo.path).toPNG() @@ -549,7 +481,7 @@ describe('nativeImage module', () => { expect(image.getScaleFactors()).to.deep.equal([1, 2]); - const imageDataThree = getImage({ width: 3, height: 3 }); + const imageDataThree = image3x3; image.addRepresentation({ scaleFactor: 3.0, buffer: nativeImage.createFromPath(imageDataThree.path).toPNG() @@ -559,7 +491,7 @@ describe('nativeImage module', () => { image.addRepresentation({ scaleFactor: 4.0, - buffer: 'invalid' + buffer: 'invalid' as any }); // this one failed, so it shouldn't show up in the scale factors @@ -577,19 +509,19 @@ describe('nativeImage module', () => { it('supports adding a data URL representation for a scale factor', () => { const image = nativeImage.createEmpty(); - const imageDataOne = getImage({ width: 1, height: 1 }); + const imageDataOne = image1x1; image.addRepresentation({ scaleFactor: 1.0, dataURL: imageDataOne.dataUrl }); - const imageDataTwo = getImage({ width: 2, height: 2 }); + const imageDataTwo = image2x2; image.addRepresentation({ scaleFactor: 2.0, dataURL: imageDataTwo.dataUrl }); - const imageDataThree = getImage({ width: 3, height: 3 }); + const imageDataThree = image3x3; image.addRepresentation({ scaleFactor: 3.0, dataURL: imageDataThree.dataUrl @@ -610,16 +542,16 @@ describe('nativeImage module', () => { }); it('supports adding a representation to an existing image', () => { - const imageDataOne = getImage({ width: 1, height: 1 }); + const imageDataOne = image1x1; const image = nativeImage.createFromPath(imageDataOne.path); - const imageDataTwo = getImage({ width: 2, height: 2 }); + const imageDataTwo = image2x2; image.addRepresentation({ scaleFactor: 2.0, dataURL: imageDataTwo.dataUrl }); - const imageDataThree = getImage({ width: 3, height: 3 }); + const imageDataThree = image3x3; image.addRepresentation({ scaleFactor: 2.0, dataURL: imageDataThree.dataUrl diff --git a/spec-main/api-net-log-spec.ts b/spec-main/api-net-log-spec.ts index 4cae12478a73b..f7fed76843ae8 100644 --- a/spec-main/api-net-log-spec.ts +++ b/spec-main/api-net-log-spec.ts @@ -134,7 +134,7 @@ describe('netLog module', () => { expect(fs.existsSync(dumpFile)).to.be.true('dump file exists'); }); - ifit(process.platform !== 'linux')('should begin and end logging automtically when --log-net-log is passed, and behave correctly when .startLogging() and .stopLogging() is called', async () => { + ifit(process.platform !== 'linux')('should begin and end logging automatically when --log-net-log is passed, and behave correctly when .startLogging() and .stopLogging() is called', async () => { const appProcess = ChildProcess.spawn(process.execPath, [appPath], { env: { diff --git a/spec-main/api-net-spec.ts b/spec-main/api-net-spec.ts index 2386aacaff80a..fc70135fa38ed 100644 --- a/spec-main/api-net-spec.ts +++ b/spec-main/api-net-spec.ts @@ -1811,7 +1811,12 @@ describe('net module', () => { urlRequest.on('response', () => {}); urlRequest.end(); await delay(2000); - expect(numChunksSent).to.be.at.most(20); + // TODO(nornagon): I think this ought to max out at 20, but in practice + // it seems to exceed that sometimes. This is at 25 to avoid test flakes, + // but we should investigate if there's actually something broken here and + // if so fix it and reset this to max at 20, and if not then delete this + // comment. + expect(numChunksSent).to.be.at.most(25); }); }); diff --git a/spec-main/api-power-monitor-spec.ts b/spec-main/api-power-monitor-spec.ts index c1f55fc5606ae..1867e8f97b0e3 100644 --- a/spec-main/api-power-monitor-spec.ts +++ b/spec-main/api-power-monitor-spec.ts @@ -14,8 +14,7 @@ import { promisify } from 'util'; describe('powerMonitor', () => { let logindMock: any, dbusMockPowerMonitor: any, getCalls: any, emitSignal: any, reset: any; - // TODO(deepak1556): Enable on arm64 after upgrade, it crashes at the moment. - ifdescribe(process.platform === 'linux' && process.arch !== 'arm64' && process.env.DBUS_SYSTEM_BUS_ADDRESS != null)('when powerMonitor module is loaded with dbus mock', () => { + ifdescribe(process.platform === 'linux' && process.env.DBUS_SYSTEM_BUS_ADDRESS != null)('when powerMonitor module is loaded with dbus mock', () => { before(async () => { const systemBus = dbus.systemBus(); const loginService = systemBus.getService('org.freedesktop.login1'); diff --git a/spec-main/api-process-spec.ts b/spec-main/api-process-spec.ts new file mode 100644 index 0000000000000..163839349d70a --- /dev/null +++ b/spec-main/api-process-spec.ts @@ -0,0 +1,231 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { expect } from 'chai'; +import { BrowserWindow } from 'electron'; +import { defer, ifdescribe } from './spec-helpers'; +import { app } from 'electron/main'; +import { closeAllWindows } from './window-helpers'; + +describe('process module', () => { + describe('renderer process', () => { + let w: BrowserWindow; + before(async () => { + w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + await w.loadURL('about:blank'); + }); + after(closeAllWindows); + + describe('process.getCreationTime()', () => { + it('returns a creation time', async () => { + const creationTime = await w.webContents.executeJavaScript('process.getCreationTime()'); + expect(creationTime).to.be.a('number').and.be.at.least(0); + }); + }); + + describe('process.getCPUUsage()', () => { + it('returns a cpu usage object', async () => { + const cpuUsage = await w.webContents.executeJavaScript('process.getCPUUsage()'); + expect(cpuUsage.percentCPUUsage).to.be.a('number'); + expect(cpuUsage.idleWakeupsPerSecond).to.be.a('number'); + }); + }); + + ifdescribe(process.platform !== 'darwin')('process.getIOCounters()', () => { + it('returns an io counters object', async () => { + const ioCounters = await w.webContents.executeJavaScript('process.getIOCounters()'); + expect(ioCounters.readOperationCount).to.be.a('number'); + expect(ioCounters.writeOperationCount).to.be.a('number'); + expect(ioCounters.otherOperationCount).to.be.a('number'); + expect(ioCounters.readTransferCount).to.be.a('number'); + expect(ioCounters.writeTransferCount).to.be.a('number'); + expect(ioCounters.otherTransferCount).to.be.a('number'); + }); + }); + + describe('process.getBlinkMemoryInfo()', () => { + it('returns blink memory information object', async () => { + const heapStats = await w.webContents.executeJavaScript('process.getBlinkMemoryInfo()'); + expect(heapStats.allocated).to.be.a('number'); + expect(heapStats.total).to.be.a('number'); + }); + }); + + describe('process.getProcessMemoryInfo()', () => { + it('resolves promise successfully with valid data', async () => { + const memoryInfo = await w.webContents.executeJavaScript('process.getProcessMemoryInfo()'); + expect(memoryInfo).to.be.an('object'); + if (process.platform === 'linux' || process.platform === 'win32') { + expect(memoryInfo.residentSet).to.be.a('number').greaterThan(0); + } + expect(memoryInfo.private).to.be.a('number').greaterThan(0); + // Shared bytes can be zero + expect(memoryInfo.shared).to.be.a('number').greaterThan(-1); + }); + }); + + describe('process.getSystemMemoryInfo()', () => { + it('returns system memory info object', async () => { + const systemMemoryInfo = await w.webContents.executeJavaScript('process.getSystemMemoryInfo()'); + expect(systemMemoryInfo.free).to.be.a('number'); + expect(systemMemoryInfo.total).to.be.a('number'); + }); + }); + + describe('process.getSystemVersion()', () => { + it('returns a string', async () => { + const systemVersion = await w.webContents.executeJavaScript('process.getSystemVersion()'); + expect(systemVersion).to.be.a('string'); + }); + }); + + describe('process.getHeapStatistics()', () => { + it('returns heap statistics object', async () => { + const heapStats = await w.webContents.executeJavaScript('process.getHeapStatistics()'); + expect(heapStats.totalHeapSize).to.be.a('number'); + expect(heapStats.totalHeapSizeExecutable).to.be.a('number'); + expect(heapStats.totalPhysicalSize).to.be.a('number'); + expect(heapStats.totalAvailableSize).to.be.a('number'); + expect(heapStats.usedHeapSize).to.be.a('number'); + expect(heapStats.heapSizeLimit).to.be.a('number'); + expect(heapStats.mallocedMemory).to.be.a('number'); + expect(heapStats.peakMallocedMemory).to.be.a('number'); + expect(heapStats.doesZapGarbage).to.be.a('boolean'); + }); + }); + + describe('process.takeHeapSnapshot()', () => { + it('returns true on success', async () => { + const filePath = path.join(app.getPath('temp'), 'test.heapsnapshot'); + defer(() => { + try { + fs.unlinkSync(filePath); + } catch (e) { + // ignore error + } + }); + + const success = await w.webContents.executeJavaScript(`process.takeHeapSnapshot(${JSON.stringify(filePath)})`); + expect(success).to.be.true(); + const stats = fs.statSync(filePath); + expect(stats.size).not.to.be.equal(0); + }); + + it('returns false on failure', async () => { + const success = await w.webContents.executeJavaScript('process.takeHeapSnapshot("")'); + expect(success).to.be.false(); + }); + }); + + describe('process.contextId', () => { + it('is a string', async () => { + const contextId = await w.webContents.executeJavaScript('process.contextId'); + expect(contextId).to.be.a('string'); + }); + }); + }); + + describe('main process', () => { + describe('process.getCreationTime()', () => { + it('returns a creation time', () => { + const creationTime = process.getCreationTime(); + expect(creationTime).to.be.a('number').and.be.at.least(0); + }); + }); + + describe('process.getCPUUsage()', () => { + it('returns a cpu usage object', () => { + const cpuUsage = process.getCPUUsage(); + expect(cpuUsage.percentCPUUsage).to.be.a('number'); + expect(cpuUsage.idleWakeupsPerSecond).to.be.a('number'); + }); + }); + + ifdescribe(process.platform !== 'darwin')('process.getIOCounters()', () => { + it('returns an io counters object', () => { + const ioCounters = process.getIOCounters(); + expect(ioCounters.readOperationCount).to.be.a('number'); + expect(ioCounters.writeOperationCount).to.be.a('number'); + expect(ioCounters.otherOperationCount).to.be.a('number'); + expect(ioCounters.readTransferCount).to.be.a('number'); + expect(ioCounters.writeTransferCount).to.be.a('number'); + expect(ioCounters.otherTransferCount).to.be.a('number'); + }); + }); + + describe('process.getBlinkMemoryInfo()', () => { + it('returns blink memory information object', () => { + const heapStats = process.getBlinkMemoryInfo(); + expect(heapStats.allocated).to.be.a('number'); + expect(heapStats.total).to.be.a('number'); + }); + }); + + describe('process.getProcessMemoryInfo()', () => { + it('resolves promise successfully with valid data', async () => { + const memoryInfo = await process.getProcessMemoryInfo(); + expect(memoryInfo).to.be.an('object'); + if (process.platform === 'linux' || process.platform === 'win32') { + expect(memoryInfo.residentSet).to.be.a('number').greaterThan(0); + } + expect(memoryInfo.private).to.be.a('number').greaterThan(0); + // Shared bytes can be zero + expect(memoryInfo.shared).to.be.a('number').greaterThan(-1); + }); + }); + + describe('process.getSystemMemoryInfo()', () => { + it('returns system memory info object', () => { + const systemMemoryInfo = process.getSystemMemoryInfo(); + expect(systemMemoryInfo.free).to.be.a('number'); + expect(systemMemoryInfo.total).to.be.a('number'); + }); + }); + + describe('process.getSystemVersion()', () => { + it('returns a string', () => { + const systemVersion = process.getSystemVersion(); + expect(systemVersion).to.be.a('string'); + }); + }); + + describe('process.getHeapStatistics()', () => { + it('returns heap statistics object', async () => { + const heapStats = process.getHeapStatistics(); + expect(heapStats.totalHeapSize).to.be.a('number'); + expect(heapStats.totalHeapSizeExecutable).to.be.a('number'); + expect(heapStats.totalPhysicalSize).to.be.a('number'); + expect(heapStats.totalAvailableSize).to.be.a('number'); + expect(heapStats.usedHeapSize).to.be.a('number'); + expect(heapStats.heapSizeLimit).to.be.a('number'); + expect(heapStats.mallocedMemory).to.be.a('number'); + expect(heapStats.peakMallocedMemory).to.be.a('number'); + expect(heapStats.doesZapGarbage).to.be.a('boolean'); + }); + }); + + describe('process.takeHeapSnapshot()', () => { + // TODO(nornagon): this seems to take a really long time when run in the + // main process, for unknown reasons. + it.skip('returns true on success', () => { + const filePath = path.join(app.getPath('temp'), 'test.heapsnapshot'); + defer(() => { + try { + fs.unlinkSync(filePath); + } catch (e) { + // ignore error + } + }); + + const success = process.takeHeapSnapshot(filePath); + expect(success).to.be.true(); + const stats = fs.statSync(filePath); + expect(stats.size).not.to.be.equal(0); + }); + + it('returns false on failure', async () => { + const success = process.takeHeapSnapshot(''); + expect(success).to.be.false(); + }); + }); + }); +}); diff --git a/spec-main/api-protocol-spec.ts b/spec-main/api-protocol-spec.ts index 4ffaa3e047d68..7988724baf5b4 100644 --- a/spec-main/api-protocol-spec.ts +++ b/spec-main/api-protocol-spec.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as qs from 'querystring'; import * as stream from 'stream'; import { EventEmitter } from 'events'; -import { closeWindow } from './window-helpers'; +import { closeAllWindows, closeWindow } from './window-helpers'; import { emittedOnce } from './events-helpers'; import { WebmGenerator } from './video-helpers'; import { delay } from './spec-helpers'; @@ -216,6 +216,8 @@ describe('protocol module', () => { const normalPath = path.join(fixturesPath, 'pages', 'a.html'); const normalContent = fs.readFileSync(normalPath); + afterEach(closeAllWindows); + it('sends file path as response', async () => { registerFileProtocol(protocolName, (request, callback) => callback(filePath)); const r = await ajax(protocolName + '://fake-host'); @@ -239,6 +241,25 @@ describe('protocol module', () => { expect(r.headers).to.have.property('x-great-header', 'sogreat'); }); + it('can load iframes with custom protocols', (done) => { + registerFileProtocol('custom', (request, callback) => { + const filename = request.url.substring(9); + const p = path.join(__dirname, 'fixtures', 'pages', filename); + callback({ path: p }); + }); + + const w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true, + contextIsolation: false + } + }); + + w.loadFile(path.join(__dirname, 'fixtures', 'pages', 'iframe-protocol.html')); + ipcMain.once('loaded-iframe-custom-protocol', () => done()); + }); + it.skip('throws an error when custom headers are invalid', (done) => { registerFileProtocol(protocolName, (request, callback) => { expect(() => callback({ @@ -764,10 +785,7 @@ describe('protocol module', () => { await expect(contents.executeJavaScript(`navigator.serviceWorker.register('${v4()}.notjs', {scope: './'})`)).to.be.rejected(); }); - // TODO(nornagon): I'm not sure why this isn't working, but I'm choosing to - // disable this test for now to land the roll. See - // https://github.com/electron/electron/issues/32664. - it.skip('should be able to register service worker for custom scheme', async () => { + it('should be able to register service worker for custom scheme', async () => { await contents.loadURL(`${serviceWorkerScheme}://${v4()}.com`); await contents.executeJavaScript(`navigator.serviceWorker.register('${v4()}.js', {scope: './'})`); }); diff --git a/spec-main/api-safe-storage-spec.ts b/spec-main/api-safe-storage-spec.ts index b89f909513bd1..098095e2fde06 100644 --- a/spec-main/api-safe-storage-spec.ts +++ b/spec-main/api-safe-storage-spec.ts @@ -12,8 +12,27 @@ import * as fs from 'fs'; * * Because all encryption methods are gated by isEncryptionAvailable, the methods will never return the correct values * when run on CI and linux. +* Refs: https://github.com/electron/electron/issues/30424. */ +describe('safeStorage module', () => { + it('safeStorage before and after app is ready', async () => { + const appPath = path.join(__dirname, 'fixtures', 'crash-cases', 'safe-storage'); + const appProcess = cp.spawn(process.execPath, [appPath]); + + let output = ''; + appProcess.stdout.on('data', data => { output += data; }); + appProcess.stderr.on('data', data => { output += data; }); + + const code = (await emittedOnce(appProcess, 'exit'))[0] ?? 1; + + if (code !== 0 && output) { + console.log(output); + } + expect(code).to.equal(0); + }); +}); + ifdescribe(process.platform !== 'linux')('safeStorage module', () => { after(async () => { const pathToEncryptedString = path.resolve(__dirname, 'fixtures', 'api', 'safe-storage', 'encrypted.txt'); diff --git a/spec-main/api-session-spec.ts b/spec-main/api-session-spec.ts index f504d0db6d464..f7817c7e03376 100644 --- a/spec-main/api-session-spec.ts +++ b/spec-main/api-session-spec.ts @@ -4,7 +4,7 @@ import * as https from 'https'; import * as path from 'path'; import * as fs from 'fs'; import * as ChildProcess from 'child_process'; -import { app, session, BrowserWindow, net, ipcMain, Session } from 'electron/main'; +import { app, session, BrowserWindow, net, ipcMain, Session, webFrameMain, WebFrameMain } from 'electron/main'; import * as send from 'send'; import * as auth from 'basic-auth'; import { closeAllWindows } from './window-helpers'; @@ -216,7 +216,8 @@ describe('session module', () => { }); }); - it('should survive an app restart for persistent partition', async () => { + it('should survive an app restart for persistent partition', async function () { + this.timeout(60000); const appPath = path.join(fixtures, 'api', 'cookie-app'); const runAppWithPhase = (phase: string) => { @@ -528,6 +529,50 @@ describe('session module', () => { }); }); + describe('ses.getBlobData2()', () => { + const scheme = 'cors-blob'; + const protocol = session.defaultSession.protocol; + const url = `${scheme}://host`; + after(async () => { + await protocol.unregisterProtocol(scheme); + }); + afterEach(closeAllWindows); + + it('returns blob data for uuid', (done) => { + const content = ` + + `; + + protocol.registerStringProtocol(scheme, (request, callback) => { + try { + if (request.method === 'GET') { + callback({ data: content, mimeType: 'text/html' }); + } else if (request.method === 'POST') { + const uuid = request.uploadData![1].blobUUID; + expect(uuid).to.be.a('string'); + session.defaultSession.getBlobData(uuid!).then(result => { + try { + const data = new Array(65_537).fill('a'); + expect(result.toString()).to.equal(data.join('')); + done(); + } catch (e) { + done(e); + } + }); + } + } catch (e) { + done(e); + } + }); + const w = new BrowserWindow({ show: false }); + w.loadURL(url); + }); + }); + describe('ses.setCertificateVerifyProc(callback)', () => { let server: http.Server; @@ -1012,7 +1057,7 @@ describe('session module', () => { const w = new BrowserWindow({ show: false, webPreferences: { - partition: 'very-temp-permision-handler', + partition: 'very-temp-permission-handler', nodeIntegration: true, contextIsolation: false } @@ -1042,6 +1087,90 @@ describe('session module', () => { }); }); + describe('ses.setPermissionCheckHandler(handler)', () => { + afterEach(closeAllWindows); + it('details provides requestingURL for mainFrame', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + partition: 'very-temp-permission-handler' + } + }); + const ses = w.webContents.session; + const loadUrl = 'https://myfakesite/'; + let handlerDetails : Electron.PermissionCheckHandlerHandlerDetails; + + ses.protocol.interceptStringProtocol('https', (req, cb) => { + cb(''); + }); + + ses.setPermissionCheckHandler((wc, permission, requestingOrigin, details) => { + if (permission === 'clipboard-read') { + handlerDetails = details; + return true; + } + return false; + }); + + const readClipboardPermission: any = () => { + return w.webContents.executeJavaScript(` + navigator.permissions.query({name: 'clipboard-read'}) + .then(permission => permission.state).catch(err => err.message); + `, true); + }; + + await w.loadURL(loadUrl); + const state = await readClipboardPermission(); + expect(state).to.equal('granted'); + expect(handlerDetails!.requestingUrl).to.equal(loadUrl); + }); + + it('details provides requestingURL for cross origin subFrame', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + partition: 'very-temp-permission-handler' + } + }); + const ses = w.webContents.session; + const loadUrl = 'https://myfakesite/'; + let handlerDetails : Electron.PermissionCheckHandlerHandlerDetails; + + ses.protocol.interceptStringProtocol('https', (req, cb) => { + cb(''); + }); + + ses.setPermissionCheckHandler((wc, permission, requestingOrigin, details) => { + if (permission === 'clipboard-read') { + handlerDetails = details; + return true; + } + return false; + }); + + const readClipboardPermission: any = (frame: WebFrameMain) => { + return frame.executeJavaScript(` + navigator.permissions.query({name: 'clipboard-read'}) + .then(permission => permission.state).catch(err => err.message); + `, true); + }; + + await w.loadFile(path.join(fixtures, 'api', 'blank.html')); + w.webContents.executeJavaScript(` + var iframe = document.createElement('iframe'); + iframe.src = '${loadUrl}'; + document.body.appendChild(iframe); + null; + `); + const [,, frameProcessId, frameRoutingId] = await emittedOnce(w.webContents, 'did-frame-finish-load'); + const state = await readClipboardPermission(webFrameMain.fromId(frameProcessId, frameRoutingId)); + expect(state).to.equal('granted'); + expect(handlerDetails!.requestingUrl).to.equal(loadUrl); + expect(handlerDetails!.isMainFrame).to.be.false(); + expect(handlerDetails!.embeddingOrigin).to.equal('file:///'); + }); + }); + describe('ses.isPersistent()', () => { afterEach(closeAllWindows); @@ -1130,7 +1259,7 @@ describe('session module', () => { session.defaultSession.setCodeCachePath(''); }).to.throw('Absolute path must be provided to store code cache.'); expect(() => { - session.defaultSession.setCodeCachePath(path.join(app.getPath('userData'), 'test-code-cache')); + session.defaultSession.setCodeCachePath(path.join(app.getPath('userData'), 'electron-test-code-cache')); }).to.not.throw(); }); }); diff --git a/spec-main/api-shell-spec.ts b/spec-main/api-shell-spec.ts index 33bc29791fa78..f2cd1cdf8f744 100644 --- a/spec-main/api-shell-spec.ts +++ b/spec-main/api-shell-spec.ts @@ -2,9 +2,10 @@ import { BrowserWindow, app } from 'electron/main'; import { shell } from 'electron/common'; import { closeAllWindows } from './window-helpers'; import { emittedOnce } from './events-helpers'; -import { ifit } from './spec-helpers'; +import { ifdescribe, ifit } from './spec-helpers'; import * as http from 'http'; import * as fs from 'fs-extra'; +import * as os from 'os'; import * as path from 'path'; import { AddressInfo } from 'net'; import { expect } from 'chai'; @@ -84,4 +85,73 @@ describe('shell module', () => { await expect(w.webContents.executeJavaScript('require(\'electron\').shell.trashItem(\'does-not-exist\')')).to.be.rejectedWith(/does-not-exist|Failed to move item|Failed to create FileOperation/); }); }); + + const shortcutOptions = { + target: 'C:\\target', + description: 'description', + cwd: 'cwd', + args: 'args', + appUserModelId: 'appUserModelId', + icon: 'icon', + iconIndex: 1, + toastActivatorClsid: '{0E3CFA27-6FEA-410B-824F-A174B6E865E5}' + }; + ifdescribe(process.platform === 'win32')('shell.readShortcutLink(shortcutPath)', () => { + it('throws when failed', () => { + expect(() => { + shell.readShortcutLink('not-exist'); + }).to.throw('Failed to read shortcut link'); + }); + + const fixtures = path.resolve(__dirname, '..', 'spec', 'fixtures'); + it('reads all properties of a shortcut', () => { + const shortcut = shell.readShortcutLink(path.join(fixtures, 'assets', 'shortcut.lnk')); + expect(shortcut).to.deep.equal(shortcutOptions); + }); + }); + + ifdescribe(process.platform === 'win32')('shell.writeShortcutLink(shortcutPath[, operation], options)', () => { + const tmpShortcut = path.join(os.tmpdir(), `${Date.now()}.lnk`); + + afterEach(() => { + fs.unlinkSync(tmpShortcut); + }); + + it('writes the shortcut', () => { + expect(shell.writeShortcutLink(tmpShortcut, { target: 'C:\\' })).to.be.true(); + expect(fs.existsSync(tmpShortcut)).to.be.true(); + }); + + it('correctly sets the fields', () => { + expect(shell.writeShortcutLink(tmpShortcut, shortcutOptions)).to.be.true(); + expect(shell.readShortcutLink(tmpShortcut)).to.deep.equal(shortcutOptions); + }); + + it('updates the shortcut', () => { + expect(shell.writeShortcutLink(tmpShortcut, 'update', shortcutOptions)).to.be.false(); + expect(shell.writeShortcutLink(tmpShortcut, 'create', shortcutOptions)).to.be.true(); + expect(shell.readShortcutLink(tmpShortcut)).to.deep.equal(shortcutOptions); + const change = { target: 'D:\\' }; + expect(shell.writeShortcutLink(tmpShortcut, 'update', change)).to.be.true(); + expect(shell.readShortcutLink(tmpShortcut)).to.deep.equal({ ...shortcutOptions, ...change }); + }); + + it('replaces the shortcut', () => { + expect(shell.writeShortcutLink(tmpShortcut, 'replace', shortcutOptions)).to.be.false(); + expect(shell.writeShortcutLink(tmpShortcut, 'create', shortcutOptions)).to.be.true(); + expect(shell.readShortcutLink(tmpShortcut)).to.deep.equal(shortcutOptions); + const change = { + target: 'D:\\', + description: 'description2', + cwd: 'cwd2', + args: 'args2', + appUserModelId: 'appUserModelId2', + icon: 'icon2', + iconIndex: 2, + toastActivatorClsid: '{C51A3996-CAD9-4934-848B-16285D4A1496}' + }; + expect(shell.writeShortcutLink(tmpShortcut, 'replace', change)).to.be.true(); + expect(shell.readShortcutLink(tmpShortcut)).to.deep.equal(change); + }); + }); }); diff --git a/spec-main/api-system-preferences-spec.ts b/spec-main/api-system-preferences-spec.ts index 38a16045ddb13..d050e40d816a0 100644 --- a/spec-main/api-system-preferences-spec.ts +++ b/spec-main/api-system-preferences-spec.ts @@ -46,7 +46,6 @@ describe('systemPreferences module', () => { const badDefaults = [ 1, null, - new Date(), { one: null } ]; diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index 3d04494a50d1a..f19fc67d49c70 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -4,10 +4,9 @@ import * as path from 'path'; import * as fs from 'fs'; import * as http from 'http'; import { BrowserWindow, ipcMain, webContents, session, WebContents, app, BrowserView } from 'electron/main'; -import { clipboard } from 'electron/common'; import { emittedOnce } from './events-helpers'; import { closeAllWindows } from './window-helpers'; -import { ifdescribe, ifit, delay, defer } from './spec-helpers'; +import { ifdescribe, delay, defer, waitUntil } from './spec-helpers'; const pdfjs = require('pdfjs-dist'); const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures'); @@ -47,6 +46,28 @@ describe('webContents module', () => { }); }); + describe('fromFrame()', () => { + it('returns WebContents for mainFrame', () => { + const contents = (webContents as any).create() as WebContents; + expect(webContents.fromFrame(contents.mainFrame)).to.equal(contents); + }); + it('returns undefined for disposed frame', async () => { + const contents = (webContents as any).create() as WebContents; + const { mainFrame } = contents; + contents.destroy(); + await waitUntil(() => typeof webContents.fromFrame(mainFrame) === 'undefined'); + }); + it('throws when passing invalid argument', async () => { + let errored = false; + try { + webContents.fromFrame({} as any); + } catch { + errored = true; + } + expect(errored).to.be.true(); + }); + }); + describe('fromDevToolsTargetId()', () => { it('returns WebContents for attached DevTools target', async () => { const w = new BrowserWindow({ show: false }); @@ -179,10 +200,12 @@ describe('webContents module', () => { }).to.throw('webContents.print(): Invalid optional callback provided.'); }); - ifit(process.platform !== 'linux')('throws when an invalid deviceName is passed', () => { - expect(() => { - w.webContents.print({ deviceName: 'i-am-a-nonexistent-printer' }, () => {}); - }).to.throw('webContents.print(): Invalid deviceName provided.'); + it('fails when an invalid deviceName is passed', (done) => { + w.webContents.print({ deviceName: 'i-am-a-nonexistent-printer' }, (success, reason) => { + expect(success).to.equal(false); + expect(reason).to.match(/Invalid deviceName provided/); + done(); + }); }); it('throws when an invalid pageSize is passed', () => { @@ -247,7 +270,7 @@ describe('webContents module', () => { const result = await w.webContents.executeJavaScript(code); expect(result).to.equal(expected); }); - it('resolves the returned promise with the result if the code returns an asyncronous promise', async () => { + it('resolves the returned promise with the result if the code returns an asynchronous promise', async () => { const result = await w.webContents.executeJavaScript(asyncCode); expect(result).to.equal(expected); }); @@ -325,6 +348,7 @@ describe('webContents module', () => { describe('loadURL() promise API', () => { let w: BrowserWindow; + beforeEach(async () => { w = new BrowserWindow({ show: false }); }); @@ -356,6 +380,35 @@ describe('webContents module', () => { .and.have.property('code', 'ERR_FAILED'); }); + it('does not crash when loading a new URL with emulation settings set', async () => { + const setEmulation = async () => { + if (w.webContents) { + w.webContents.debugger.attach('1.3'); + + const deviceMetrics = { + width: 700, + height: 600, + deviceScaleFactor: 2, + mobile: true, + dontSetVisibleSize: true + }; + await w.webContents.debugger.sendCommand( + 'Emulation.setDeviceMetricsOverride', + deviceMetrics + ); + } + }; + + try { + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + await setEmulation(); + await w.loadURL('data:text/html,

HELLO

'); + await setEmulation(); + } catch (e) { + expect((e as Error).message).to.match(/Debugger is already attached to the target/); + } + }); + it('sets appropriate error information on rejection', async () => { let err: any; try { @@ -883,7 +936,7 @@ describe('webContents module', () => { describe('getOSProcessId()', () => { afterEach(closeAllWindows); - it('returns a valid procress id', async () => { + it('returns a valid process id', async () => { const w = new BrowserWindow({ show: false }); expect(w.webContents.getOSProcessId()).to.equal(0); @@ -901,6 +954,12 @@ describe('webContents module', () => { }); describe('userAgent APIs', () => { + it('is not empty by default', () => { + const w = new BrowserWindow({ show: false }); + const userAgent = w.webContents.getUserAgent(); + expect(userAgent).to.be.a('string').that.is.not.empty(); + }); + it('can set the user agent (functions)', () => { const w = new BrowserWindow({ show: false }); const userAgent = w.webContents.getUserAgent(); @@ -1244,6 +1303,54 @@ describe('webContents module', () => { }); }); + describe('opener api', () => { + afterEach(closeAllWindows); + it('can get opener with window.open()', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } }); + await w.loadURL('about:blank'); + const childPromise = emittedOnce(w.webContents, 'did-create-window'); + w.webContents.executeJavaScript('window.open("about:blank")', true); + const [childWindow] = await childPromise; + expect(childWindow.webContents.opener).to.equal(w.webContents.mainFrame); + }); + it('has no opener when using "noopener"', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } }); + await w.loadURL('about:blank'); + const childPromise = emittedOnce(w.webContents, 'did-create-window'); + w.webContents.executeJavaScript('window.open("about:blank", undefined, "noopener")', true); + const [childWindow] = await childPromise; + expect(childWindow.webContents.opener).to.be.null(); + }); + it('can get opener with a[target=_blank][rel=opener]', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } }); + await w.loadURL('about:blank'); + const childPromise = emittedOnce(w.webContents, 'did-create-window'); + w.webContents.executeJavaScript(`(function() { + const a = document.createElement('a'); + a.target = '_blank'; + a.rel = 'opener'; + a.href = 'about:blank'; + a.click(); + }())`, true); + const [childWindow] = await childPromise; + expect(childWindow.webContents.opener).to.equal(w.webContents.mainFrame); + }); + it('has no opener with a[target=_blank][rel=noopener]', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } }); + await w.loadURL('about:blank'); + const childPromise = emittedOnce(w.webContents, 'did-create-window'); + w.webContents.executeJavaScript(`(function() { + const a = document.createElement('a'); + a.target = '_blank'; + a.rel = 'noopener'; + a.href = 'about:blank'; + a.click(); + }())`, true); + const [childWindow] = await childPromise; + expect(childWindow.webContents.opener).to.be.null(); + }); + }); + describe('render view deleted events', () => { let server: http.Server; let serverUrl: string; @@ -1563,9 +1670,10 @@ describe('webContents module', () => { server.listen(0, '127.0.0.1', () => { const url = 'http://127.0.0.1:' + (server.address() as AddressInfo).port + '/'; w.webContents.once('did-finish-load', () => { - w.webContents.once('new-window', (event, newUrl, frameName, disposition, options, features, referrer) => { - expect(referrer.url).to.equal(url); - expect(referrer.policy).to.equal('strict-origin-when-cross-origin'); + w.webContents.setWindowOpenHandler(details => { + expect(details.referrer.url).to.equal(url); + expect(details.referrer.policy).to.equal('strict-origin-when-cross-origin'); + return { action: 'allow' }; }); w.webContents.executeJavaScript('a.click()'); }); @@ -1591,9 +1699,10 @@ describe('webContents module', () => { server.listen(0, '127.0.0.1', () => { const url = 'http://127.0.0.1:' + (server.address() as AddressInfo).port + '/'; w.webContents.once('did-finish-load', () => { - w.webContents.once('new-window', (event, newUrl, frameName, disposition, options, features, referrer) => { - expect(referrer.url).to.equal(url); - expect(referrer.policy).to.equal('no-referrer-when-downgrade'); + w.webContents.setWindowOpenHandler(details => { + expect(details.referrer.url).to.equal(url); + expect(details.referrer.policy).to.equal('no-referrer-when-downgrade'); + return { action: 'allow' }; }); w.webContents.executeJavaScript('window.open(location.href + "should_have_referrer")'); }); @@ -1811,14 +1920,16 @@ describe('webContents module', () => { it('rejects on incorrectly typed parameters', async () => { const badTypes = { - marginsType: 'terrible', - scaleFactor: 'not-a-number', landscape: [], - pageRanges: { oops: 'im-not-the-right-key' }, - headerFooter: '123', - printSelectionOnly: 1, + displayHeaderFooter: '123', printBackground: 2, - pageSize: 'IAmAPageSize' + scale: 'not-a-number', + pageSize: 'IAmAPageSize', + margins: 'terrible', + pageRanges: { oops: 'im-not-the-right-key' }, + headerTemplate: [1, 2, 3], + footerTemplate: [4, 5, 6], + preferCSSPageSize: 'no' }; // These will hard crash in Chromium unless we type-check @@ -1857,8 +1968,7 @@ describe('webContents module', () => { } }); - // TODO(codebytere): Re-enable after Chromium fixes upstream v8_scriptormodule_legacy_lifetime crash. - xdescribe('using a large document', () => { + describe('using a large document', () => { beforeEach(async () => { w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } }); await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'print-to-pdf.html')); @@ -1868,10 +1978,7 @@ describe('webContents module', () => { it('respects custom settings', async () => { const data = await w.webContents.printToPDF({ - pageRanges: { - from: 0, - to: 2 - }, + pageRanges: '1-3', landscape: true }); @@ -1904,60 +2011,6 @@ describe('webContents module', () => { }); }); - describe('devtools window', () => { - let hasRobotJS = false; - try { - // We have other tests that check if native modules work, if we fail to require - // robotjs let's skip this test to avoid false negatives - require('robotjs'); - hasRobotJS = true; - } catch (err) { /* no-op */ } - - afterEach(closeAllWindows); - - // NB. on macOS, this requires that you grant your terminal the ability to - // control your computer. Open System Preferences > Security & Privacy > - // Privacy > Accessibility and grant your terminal the permission to control - // your computer. - ifit(hasRobotJS)('can receive and handle menu events', async () => { - const w = new BrowserWindow({ show: true, webPreferences: { nodeIntegration: true } }); - w.loadFile(path.join(fixturesPath, 'pages', 'key-events.html')); - - // Ensure the devtools are loaded - w.webContents.closeDevTools(); - const opened = emittedOnce(w.webContents, 'devtools-opened'); - w.webContents.openDevTools(); - await opened; - await emittedOnce(w.webContents.devToolsWebContents!, 'did-finish-load'); - w.webContents.devToolsWebContents!.focus(); - - // Focus an input field - await w.webContents.devToolsWebContents!.executeJavaScript(` - const input = document.createElement('input') - document.body.innerHTML = '' - document.body.appendChild(input) - input.focus() - `); - - // Write something to the clipboard - clipboard.writeText('test value'); - - const pasted = w.webContents.devToolsWebContents!.executeJavaScript(`new Promise(resolve => { - document.querySelector('input').addEventListener('paste', (e) => { - resolve(e.target.value) - }) - })`); - - // Fake a paste request using robotjs to emulate a REAL keyboard paste event - require('robotjs').keyTap('v', process.platform === 'darwin' ? ['command'] : ['control']); - - const val = await pasted; - - // Once we're done expect the paste to have been successful - expect(val).to.equal('test value', 'value should eventually become the pasted value'); - }); - }); - describe('Shared Workers', () => { afterEach(closeAllWindows); diff --git a/spec-main/api-web-frame-main-spec.ts b/spec-main/api-web-frame-main-spec.ts index 49545c4eaf992..9ce8f071e2f17 100644 --- a/spec-main/api-web-frame-main-spec.ts +++ b/spec-main/api-web-frame-main-spec.ts @@ -2,11 +2,11 @@ import { expect } from 'chai'; import * as http from 'http'; import * as path from 'path'; import * as url from 'url'; -import { BrowserWindow, WebFrameMain, webFrameMain, ipcMain } from 'electron/main'; +import { BrowserWindow, WebFrameMain, webFrameMain, ipcMain, app, WebContents } from 'electron/main'; import { closeAllWindows } from './window-helpers'; import { emittedOnce, emittedNTimes } from './events-helpers'; import { AddressInfo } from 'net'; -import { ifit, waitUntil } from './spec-helpers'; +import { defer, ifit, waitUntil } from './spec-helpers'; describe('webFrameMain module', () => { const fixtures = path.resolve(__dirname, '..', 'spec-main', 'fixtures'); @@ -39,7 +39,7 @@ describe('webFrameMain module', () => { let webFrame: WebFrameMain; beforeEach(async () => { - w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }); + w = new BrowserWindow({ show: false }); await w.loadFile(path.join(subframesPath, 'frame-with-frame-container.html')); webFrame = w.webContents.mainFrame; }); @@ -88,8 +88,8 @@ describe('webFrameMain module', () => { }); describe('cross-origin', () => { - let serverA = null as unknown as Server; - let serverB = null as unknown as Server; + let serverA: Server; + let serverB: Server; before(async () => { serverA = await createServer(); @@ -112,7 +112,7 @@ describe('webFrameMain module', () => { describe('WebFrame.url', () => { it('should report correct address for each subframe', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }); + const w = new BrowserWindow({ show: false }); await w.loadFile(path.join(subframesPath, 'frame-with-frame-container.html')); const webFrame = w.webContents.mainFrame; @@ -122,9 +122,59 @@ describe('webFrameMain module', () => { }); }); + describe('WebFrame.origin', () => { + it('should be null for a fresh WebContents', () => { + const w = new BrowserWindow({ show: false }); + expect(w.webContents.mainFrame.origin).to.equal('null'); + }); + + it('should be file:// for file frames', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadFile(path.join(fixtures, 'blank.html')); + expect(w.webContents.mainFrame.origin).to.equal('file://'); + }); + + it('should be http:// for an http frame', async () => { + const w = new BrowserWindow({ show: false }); + const s = await createServer(); + defer(() => s.server.close()); + await w.loadURL(s.url); + expect(w.webContents.mainFrame.origin).to.equal(s.url.replace(/\/$/, '')); + }); + + it('should show parent origin when child page is about:blank', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadFile(path.join(fixtures, 'blank.html')); + const webContentsCreated: Promise<[unknown, WebContents]> = emittedOnce(app, 'web-contents-created') as any; + expect(w.webContents.mainFrame.origin).to.equal('file://'); + await w.webContents.executeJavaScript('window.open("", null, "show=false"), null'); + const [, childWebContents] = await webContentsCreated; + expect(childWebContents.mainFrame.origin).to.equal('file://'); + }); + + it('should show parent frame\'s origin when about:blank child window opened through cross-origin subframe', async () => { + const w = new BrowserWindow({ show: false }); + const serverA = await createServer(); + const serverB = await createServer(); + defer(() => { + serverA.server.close(); + serverB.server.close(); + }); + await w.loadURL(serverA.url + '?frameSrc=' + encodeURIComponent(serverB.url)); + const { mainFrame } = w.webContents; + expect(mainFrame.origin).to.equal(serverA.url.replace(/\/$/, '')); + const [childFrame] = mainFrame.frames; + expect(childFrame.origin).to.equal(serverB.url.replace(/\/$/, '')); + const webContentsCreated: Promise<[unknown, WebContents]> = emittedOnce(app, 'web-contents-created') as any; + await childFrame.executeJavaScript('window.open("", null, "show=false"), null'); + const [, childWebContents] = await webContentsCreated; + expect(childWebContents.mainFrame.origin).to.equal(childFrame.origin); + }); + }); + describe('WebFrame IDs', () => { it('has properties for various identifiers', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }); + const w = new BrowserWindow({ show: false }); await w.loadFile(path.join(subframesPath, 'frame.html')); const webFrame = w.webContents.mainFrame; expect(webFrame).to.have.ownProperty('url').that.is.a('string'); @@ -137,7 +187,9 @@ describe('webFrameMain module', () => { }); describe('WebFrame.visibilityState', () => { - it('should match window state', async () => { + // TODO(MarshallOfSound): Fix flaky test + // @flaky-test + it.skip('should match window state', async () => { const w = new BrowserWindow({ show: true }); await w.loadURL('about:blank'); const webFrame = w.webContents.mainFrame; @@ -152,7 +204,7 @@ describe('webFrameMain module', () => { describe('WebFrame.executeJavaScript', () => { it('can inject code into any subframe', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }); + const w = new BrowserWindow({ show: false }); await w.loadFile(path.join(subframesPath, 'frame-with-frame-container.html')); const webFrame = w.webContents.mainFrame; @@ -161,11 +213,49 @@ describe('webFrameMain module', () => { expect(await getUrl(webFrame.frames[0])).to.equal(fileUrl('frame-with-frame.html')); expect(await getUrl(webFrame.frames[0].frames[0])).to.equal(fileUrl('frame.html')); }); + + it('can resolve promise', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadFile(path.join(subframesPath, 'frame.html')); + const webFrame = w.webContents.mainFrame; + const p = () => webFrame.executeJavaScript('new Promise(resolve => setTimeout(resolve(42), 2000));'); + const result = await p(); + expect(result).to.equal(42); + }); + + it('can reject with error', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadFile(path.join(subframesPath, 'frame.html')); + const webFrame = w.webContents.mainFrame; + const p = () => webFrame.executeJavaScript('new Promise((r,e) => setTimeout(e("error!"), 500));'); + await expect(p()).to.be.eventually.rejectedWith('error!'); + const errorTypes = new Set([ + Error, + ReferenceError, + EvalError, + RangeError, + SyntaxError, + TypeError, + URIError + ]); + for (const error of errorTypes) { + await expect(webFrame.executeJavaScript(`Promise.reject(new ${error.name}("Wamp-wamp"))`)) + .to.eventually.be.rejectedWith(/Error/); + } + }); + + it('can reject when script execution fails', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadFile(path.join(subframesPath, 'frame.html')); + const webFrame = w.webContents.mainFrame; + const p = () => webFrame.executeJavaScript('console.log(test)'); + await expect(p()).to.be.eventually.rejectedWith(/ReferenceError/); + }); }); describe('WebFrame.reload', () => { it('reloads a frame', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }); + const w = new BrowserWindow({ show: false }); await w.loadFile(path.join(subframesPath, 'frame.html')); const webFrame = w.webContents.mainFrame; @@ -198,7 +288,7 @@ describe('webFrameMain module', () => { let w: BrowserWindow; beforeEach(async () => { - w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }); + w = new BrowserWindow({ show: false }); }); // TODO(jkleinsc) fix this flaky test on linux @@ -222,6 +312,37 @@ describe('webFrameMain module', () => { expect(w.webContents.mainFrame).to.equal(mainFrame); expect(mainFrame.url).to.equal(crossOriginUrl); }); + + it('recovers from renderer crash on same-origin', async () => { + const server = await createServer(); + // Keep reference to mainFrame alive throughout crash and recovery. + const { mainFrame } = w.webContents; + await w.webContents.loadURL(server.url); + const crashEvent = emittedOnce(w.webContents, 'render-process-gone'); + w.webContents.forcefullyCrashRenderer(); + await crashEvent; + await w.webContents.loadURL(server.url); + // Log just to keep mainFrame in scope. + console.log('mainFrame.url', mainFrame.url); + }); + + // Fixed by #34411 + it('recovers from renderer crash on cross-origin', async () => { + const server = await createServer(); + // 'localhost' is treated as a separate origin. + const crossOriginUrl = server.url.replace('127.0.0.1', 'localhost'); + // Keep reference to mainFrame alive throughout crash and recovery. + const { mainFrame } = w.webContents; + await w.webContents.loadURL(server.url); + const crashEvent = emittedOnce(w.webContents, 'render-process-gone'); + w.webContents.forcefullyCrashRenderer(); + await crashEvent; + // A short wait seems to be required to reproduce the crash. + await new Promise(resolve => setTimeout(resolve, 100)); + await w.webContents.loadURL(crossOriginUrl); + // Log just to keep mainFrame in scope. + console.log('mainFrame.url', mainFrame.url); + }); }); describe('webFrameMain.fromId', () => { @@ -230,7 +351,7 @@ describe('webFrameMain module', () => { }); it('can find each frame from navigation events', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }); + const w = new BrowserWindow({ show: false }); // frame-with-frame-container.html, frame-with-frame.html, frame.html const didFrameFinishLoad = emittedNTimes(w.webContents, 'did-frame-finish-load', 3); diff --git a/spec-main/api-web-frame-spec.ts b/spec-main/api-web-frame-spec.ts index f7d9d9ffb138a..5b6b71b93f4b9 100644 --- a/spec-main/api-web-frame-spec.ts +++ b/spec-main/api-web-frame-spec.ts @@ -1,23 +1,22 @@ import { expect } from 'chai'; import * as path from 'path'; -import { BrowserWindow, ipcMain } from 'electron/main'; -import { closeAllWindows } from './window-helpers'; +import { BrowserWindow, ipcMain, WebContents } from 'electron/main'; import { emittedOnce } from './events-helpers'; +import { defer } from './spec-helpers'; describe('webFrame module', () => { const fixtures = path.resolve(__dirname, '..', 'spec', 'fixtures'); - afterEach(closeAllWindows); - it('can use executeJavaScript', async () => { const w = new BrowserWindow({ - show: true, + show: false, webPreferences: { nodeIntegration: true, contextIsolation: true, preload: path.join(fixtures, 'pages', 'world-safe-preload.js') } }); + defer(() => w.close()); const isSafe = emittedOnce(ipcMain, 'executejs-safe'); w.loadURL('about:blank'); const [, wasSafe] = await isSafe; @@ -26,13 +25,14 @@ describe('webFrame module', () => { it('can use executeJavaScript and catch conversion errors', async () => { const w = new BrowserWindow({ - show: true, + show: false, webPreferences: { nodeIntegration: true, contextIsolation: true, preload: path.join(fixtures, 'pages', 'world-safe-preload-error.js') } }); + defer(() => w.close()); const execError = emittedOnce(ipcMain, 'executejs-safe'); w.loadURL('about:blank'); const [, error] = await execError; @@ -48,6 +48,7 @@ describe('webFrame module', () => { contextIsolation: false } }); + defer(() => w.close()); await w.loadFile(path.join(fixtures, 'pages', 'webframe-spell-check.html')); w.focus(); await w.webContents.executeJavaScript('document.querySelector("input").focus()', true); @@ -70,4 +71,126 @@ describe('webFrame module', () => { expect(words.sort()).to.deep.equal(['spleling', 'test', 'you\'re', 'you', 're'].sort()); expect(callbackDefined).to.be.true(); }); + + describe('api', () => { + let w: WebContents; + before(async () => { + const win = new BrowserWindow({ show: false, webPreferences: { contextIsolation: false, nodeIntegration: true } }); + await win.loadURL('about:blank'); + w = win.webContents; + await w.executeJavaScript('webFrame = require(\'electron\').webFrame; null'); + }); + it('top is self for top frame', async () => { + const equal = await w.executeJavaScript('webFrame.top.context === webFrame.context'); + expect(equal).to.be.true(); + }); + + it('opener is null for top frame', async () => { + const equal = await w.executeJavaScript('webFrame.opener === null'); + expect(equal).to.be.true(); + }); + + it('firstChild is null for top frame', async () => { + const equal = await w.executeJavaScript('webFrame.firstChild === null'); + expect(equal).to.be.true(); + }); + + it('getFrameForSelector() does not crash when not found', async () => { + const equal = await w.executeJavaScript('webFrame.getFrameForSelector(\'unexist-selector\') === null'); + expect(equal).to.be.true(); + }); + + it('findFrameByName() does not crash when not found', async () => { + const equal = await w.executeJavaScript('webFrame.findFrameByName(\'unexist-name\') === null'); + expect(equal).to.be.true(); + }); + + it('findFrameByRoutingId() does not crash when not found', async () => { + const equal = await w.executeJavaScript('webFrame.findFrameByRoutingId(-1) === null'); + expect(equal).to.be.true(); + }); + + describe('executeJavaScript', () => { + before(() => { + w.executeJavaScript(` + childFrameElement = document.createElement('iframe'); + document.body.appendChild(childFrameElement); + childFrame = webFrame.firstChild; + null + `); + }); + + after(() => { + w.executeJavaScript(` + childFrameElement.remove(); + null + `); + }); + + it('executeJavaScript() yields results via a promise and a sync callback', async () => { + const { callbackResult, callbackError, result } = await w.executeJavaScript(`new Promise(resolve => { + let callbackResult, callbackError; + childFrame + .executeJavaScript('1 + 1', (result, error) => { + callbackResult = result; + callbackError = error; + }).then(result => resolve({callbackResult, callbackError, result})) + })`); + + expect(callbackResult).to.equal(2); + expect(callbackError).to.be.undefined(); + expect(result).to.equal(2); + }); + + it('executeJavaScriptInIsolatedWorld() yields results via a promise and a sync callback', async () => { + const { callbackResult, callbackError, result } = await w.executeJavaScript(`new Promise(resolve => { + let callbackResult, callbackError; + childFrame + .executeJavaScriptInIsolatedWorld(999, [{code: '1 + 1'}], (result, error) => { + callbackResult = result; + callbackError = error; + }).then(result => resolve({callbackResult, callbackError, result})) + })`); + + expect(callbackResult).to.equal(2); + expect(callbackError).to.be.undefined(); + expect(result).to.equal(2); + }); + + it('executeJavaScript() yields errors via a promise and a sync callback', async () => { + const { callbackResult, callbackError, error } = await w.executeJavaScript(`new Promise(resolve => { + let callbackResult, callbackError; + childFrame + .executeJavaScript('thisShouldProduceAnError()', (result, error) => { + callbackResult = result; + callbackError = error; + }).then(result => {throw new Error}, error => resolve({callbackResult, callbackError, error})) + })`); + + expect(callbackResult).to.be.undefined(); + expect(callbackError).to.be.an('error'); + expect(error).to.be.an('error'); + }); + + it('executeJavaScriptInIsolatedWorld() yields errors via a promise and a sync callback', async () => { + const { callbackResult, callbackError, error } = await w.executeJavaScript(`new Promise(resolve => { + let callbackResult, callbackError; + childFrame + .executeJavaScriptInIsolatedWorld(999, [{code: 'thisShouldProduceAnError()'}], (result, error) => { + callbackResult = result; + callbackError = error; + }).then(result => {throw new Error}, error => resolve({callbackResult, callbackError, error})) + })`); + + expect(callbackResult).to.be.undefined(); + expect(callbackError).to.be.an('error'); + expect(error).to.be.an('error'); + }); + + it('executeJavaScript(InIsolatedWorld) can be used without a callback', async () => { + expect(await w.executeJavaScript('webFrame.executeJavaScript(\'1 + 1\')')).to.equal(2); + expect(await w.executeJavaScript('webFrame.executeJavaScriptInIsolatedWorld(999, [{code: \'1 + 1\'}])')).to.equal(2); + }); + }); + }); }); diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index 80920d99b631c..75181a8ffda20 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -10,9 +10,10 @@ import * as url from 'url'; import * as ChildProcess from 'child_process'; import { EventEmitter } from 'events'; import { promisify } from 'util'; -import { ifit, ifdescribe, delay, defer } from './spec-helpers'; +import { ifit, ifdescribe, defer, delay } from './spec-helpers'; import { AddressInfo } from 'net'; import { PipeTransport } from './pipe-transport'; +import * as ws from 'ws'; const features = process._linkedBinding('electron_common_features'); @@ -238,8 +239,7 @@ describe('web security', () => { await p; }); - // TODO(codebytere): Re-enable after Chromium fixes upstream v8_scriptormodule_legacy_lifetime crash. - xit('bypasses CORB when web security is disabled', async () => { + it('bypasses CORB when web security is disabled', async () => { const w = new BrowserWindow({ show: false, webPreferences: { webSecurity: false, nodeIntegration: true, contextIsolation: false } }); const p = emittedOnce(ipcMain, 'success'); await w.loadURL(`data:text/html, @@ -346,7 +346,7 @@ describe('web security', () => { it('wasm codegen is disallowed by default', async () => { const r = await loadWasm(''); - expect(r).to.equal('WebAssembly.instantiate(): Wasm code generation disallowed by embedder'); + expect(r).to.equal('WebAssembly.instantiate(): Refused to compile or instantiate WebAssembly module because \'unsafe-eval\' is not an allowed source of script in the following Content Security Policy directive: "script-src \'self\' \'unsafe-inline\'"'); }); it('wasm codegen is allowed with "wasm-unsafe-eval" csp', async () => { @@ -374,6 +374,7 @@ describe('command line switches', () => { }); describe('--lang switch', () => { const currentLocale = app.getLocale(); + const currentSystemLocale = app.getSystemLocale(); const testLocale = async (locale: string, result: string, printEnv: boolean = false) => { const appPath = path.join(fixturesPath, 'api', 'locale-check'); const args = [appPath, `--set-lang=${locale}`]; @@ -396,8 +397,9 @@ describe('command line switches', () => { expect(output).to.equal(result); }; - it('should set the locale', async () => testLocale('fr', 'fr')); - it('should not set an invalid locale', async () => testLocale('asdfkl', currentLocale)); + it('should set the locale', async () => testLocale('fr', `fr|${currentSystemLocale}`)); + it('should set the locale with country code', async () => testLocale('zh-CN', `zh-CN|${currentSystemLocale}`)); + it('should not set an invalid locale', async () => testLocale('asdfkl', `${currentLocale}|${currentSystemLocale}`)); const lcAll = String(process.env.LC_ALL); ifit(process.platform === 'linux')('current process has a valid LC_ALL env', async () => { @@ -496,6 +498,37 @@ describe('chromium features', () => { }); }); + describe('first party sets', () => { + const fps = [ + 'https://fps-member1.glitch.me', + 'https://fps-member2.glitch.me', + 'https://fps-member3.glitch.me' + ]; + + it('loads first party sets', async () => { + const appPath = path.join(fixturesPath, 'api', 'first-party-sets', 'base'); + const fpsProcess = ChildProcess.spawn(process.execPath, [appPath]); + + let output = ''; + fpsProcess.stdout.on('data', data => { output += data; }); + await emittedOnce(fpsProcess, 'exit'); + + expect(output).to.include(fps.join(',')); + }); + + it('loads sets from the command line', async () => { + const appPath = path.join(fixturesPath, 'api', 'first-party-sets', 'command-line'); + const args = [appPath, `--use-first-party-set=${fps}`]; + const fpsProcess = ChildProcess.spawn(process.execPath, args); + + let output = ''; + fpsProcess.stdout.on('data', data => { output += data; }); + await emittedOnce(fpsProcess, 'exit'); + + expect(output).to.include(fps.join(',')); + }); + }); + describe('loading jquery', () => { it('does not crash', (done) => { const w = new BrowserWindow({ show: false }); @@ -619,7 +652,7 @@ describe('chromium features', () => { w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'custom-scheme-index.html')); }); - it('should not crash when nodeIntegration is enabled', (done) => { + it('should not allow nodeIntegrationInWorker', async () => { const w = new BrowserWindow({ show: false, webPreferences: { @@ -630,31 +663,23 @@ describe('chromium features', () => { } }); - w.webContents.on('ipc-message', (event, channel, message) => { - if (channel === 'reload') { - w.webContents.reload(); - } else if (channel === 'error') { - done(`unexpected error : ${message}`); - } else if (channel === 'response') { - expect(message).to.equal('Hello from serviceWorker!'); - session.fromPartition('sw-file-scheme-worker-spec').clearStorageData({ - storages: ['serviceworkers'] - }).then(() => done()); - } - }); + await w.loadURL(`file://${fixturesPath}/pages/service-worker/empty.html`); - w.webContents.on('crashed', () => done(new Error('WebContents crashed.'))); - w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'index.html')); - }); - }); + const data = await w.webContents.executeJavaScript(` + navigator.serviceWorker.register('worker-no-node.js', { + scope: './' + }).then(() => navigator.serviceWorker.ready) - describe('navigator.geolocation', () => { - before(function () { - if (!features.isFakeLocationProviderEnabled()) { - return this.skip(); - } + new Promise((resolve) => { + navigator.serviceWorker.onmessage = event => resolve(event.data); + }); + `); + + expect(data).to.equal('undefined undefined undefined undefined'); }); + }); + ifdescribe(features.isFakeLocationProviderEnabled())('navigator.geolocation', () => { it('returns error when permission is denied', async () => { const w = new BrowserWindow({ show: false, @@ -676,6 +701,17 @@ describe('chromium features', () => { const [, channel] = await message; expect(channel).to.equal('success', 'unexpected response from geolocation api'); }); + + it('returns position when permission is granted', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const position = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => + navigator.geolocation.getCurrentPosition( + x => resolve({coords: x.coords, timestamp: x.timestamp}), + reject))`); + expect(position).to.have.property('coords'); + expect(position).to.have.property('timestamp'); + }); }); describe('web workers', () => { @@ -696,6 +732,79 @@ describe('chromium features', () => { const [code] = await emittedOnce(appProcess, 'exit'); expect(code).to.equal(0); }); + + it('Worker can work', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new Worker('../workers/worker.js'); + const message = 'ping'; + const eventPromise = new Promise((resolve) => { worker.onmessage = resolve; }); + worker.postMessage(message); + eventPromise.then(t => t.data) + `); + expect(data).to.equal('ping'); + }); + + it('Worker has no node integration by default', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new Worker('../workers/worker_node.js'); + new Promise((resolve) => { worker.onmessage = e => resolve(e.data); }) + `); + expect(data).to.equal('undefined undefined undefined undefined'); + }); + + it('Worker has node integration with nodeIntegrationInWorker', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nodeIntegrationInWorker: true, contextIsolation: false } }); + w.loadURL(`file://${fixturesPath}/pages/worker.html`); + const [, data] = await emittedOnce(ipcMain, 'worker-result'); + expect(data).to.equal('object function object function'); + }); + + describe('SharedWorker', () => { + it('can work', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new SharedWorker('../workers/shared_worker.js'); + const message = 'ping'; + const eventPromise = new Promise((resolve) => { worker.port.onmessage = e => resolve(e.data); }); + worker.port.postMessage(message); + eventPromise + `); + expect(data).to.equal('ping'); + }); + + it('has no node integration by default', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new SharedWorker('../workers/shared_worker_node.js'); + new Promise((resolve) => { worker.port.onmessage = e => resolve(e.data); }) + `); + expect(data).to.equal('undefined undefined undefined undefined'); + }); + + it('does not have node integration with nodeIntegrationInWorker', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + nodeIntegration: true, + nodeIntegrationInWorker: true, + contextIsolation: false + } + }); + + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const data = await w.webContents.executeJavaScript(` + const worker = new SharedWorker('../workers/shared_worker_node.js'); + new Promise((resolve) => { worker.port.onmessage = e => resolve(e.data); }) + `); + expect(data).to.equal('undefined undefined undefined undefined'); + }); + }); }); describe('form submit', () => { @@ -789,10 +898,10 @@ describe('chromium features', () => { defer(() => { w.close(); }); - const newWindow = emittedOnce(w.webContents, 'new-window'); + const promise = emittedOnce(app, 'browser-window-created'); w.loadFile(path.join(fixturesPath, 'pages', 'window-open.html')); - const [,,,, options] = await newWindow; - expect(options.show).to.equal(true); + const [, newWindow] = await promise; + expect(newWindow.isVisible()).to.equal(true); }); } @@ -901,8 +1010,12 @@ describe('chromium features', () => { const w = new BrowserWindow({ show: false }); w.loadURL('about:blank'); w.webContents.executeJavaScript('{ b = window.open(\'\', \'__proto__\'); null }'); - const [, , frameName] = await emittedOnce(w.webContents, 'new-window'); - + const frameName = await new Promise((resolve) => { + w.webContents.setWindowOpenHandler(details => { + setImmediate(() => resolve(details.frameName)); + return { action: 'allow' }; + }); + }); expect(frameName).to.equal('__proto__'); }); }); @@ -1003,6 +1116,14 @@ describe('chromium features', () => { }).then((stream) => stream.getVideoTracks())`); expect(labels.some((l: any) => l)).to.be.true(); }); + + it('fails with "not supported" for getDisplayMedia', async () => { + const w = new BrowserWindow({ show: false }); + w.loadFile(path.join(fixturesPath, 'pages', 'blank.html')); + const { ok, err } = await w.webContents.executeJavaScript('navigator.mediaDevices.getDisplayMedia({video: true}).then(s => ({ok: true}), e => ({ok: false, err: e.message}))'); + expect(ok).to.be.false(); + expect(err).to.equal('Not supported'); + }); }); describe('window.opener access', () => { @@ -1461,6 +1582,34 @@ describe('chromium features', () => { expect((w.webContents as any).length()).to.equal(2); }); }); + + describe('window.history.back', () => { + it('should not allow sandboxed iframe to modify main frame state', async () => { + const w = new BrowserWindow({ show: false }); + w.loadURL('data:text/html,'); + await Promise.all([ + emittedOnce(w.webContents, 'navigation-entry-committed'), + emittedOnce(w.webContents, 'did-frame-navigate'), + emittedOnce(w.webContents, 'did-navigate') + ]); + + w.webContents.executeJavaScript('window.history.pushState(1, "")'); + await Promise.all([ + emittedOnce(w.webContents, 'navigation-entry-committed'), + emittedOnce(w.webContents, 'did-navigate-in-page') + ]); + + (w.webContents as any).once('navigation-entry-committed', () => { + expect.fail('Unexpected navigation-entry-committed'); + }); + w.webContents.once('did-navigate-in-page', () => { + expect.fail('Unexpected did-navigate-in-page'); + }); + await w.webContents.mainFrame.frames[0].executeJavaScript('window.history.back()'); + expect(await w.webContents.executeJavaScript('window.history.state')).to.equal(1); + expect((w.webContents as any).getActiveIndex()).to.equal(1); + }); + }); }); describe('chrome://media-internals', () => { @@ -1509,6 +1658,178 @@ describe('chromium features', () => { expect(focus).to.be.false(); }); }); + + describe('navigator.userAgentData', () => { + // These tests are done on an http server because navigator.userAgentData + // requires a secure context. + let server: http.Server; + let serverUrl: string; + before(async () => { + server = http.createServer((req, res) => { + res.setHeader('Content-Type', 'text/html'); + res.end(''); + }); + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); + serverUrl = `http://localhost:${(server.address() as any).port}`; + }); + after(() => { + server.close(); + }); + + describe('is not empty', () => { + it('by default', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(serverUrl); + const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform'); + expect(platform).not.to.be.empty(); + }); + + it('when there is a session-wide UA override', async () => { + const ses = session.fromPartition(`${Math.random()}`); + ses.setUserAgent('foobar'); + const w = new BrowserWindow({ show: false, webPreferences: { session: ses } }); + await w.loadURL(serverUrl); + const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform'); + expect(platform).not.to.be.empty(); + }); + + it('when there is a WebContents-specific UA override', async () => { + const w = new BrowserWindow({ show: false }); + w.webContents.setUserAgent('foo'); + await w.loadURL(serverUrl); + const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform'); + expect(platform).not.to.be.empty(); + }); + + it('when there is a WebContents-specific UA override at load time', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(serverUrl, { + userAgent: 'foo' + }); + const platform = await w.webContents.executeJavaScript('navigator.userAgentData.platform'); + expect(platform).not.to.be.empty(); + }); + }); + + describe('brand list', () => { + it('contains chromium', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(serverUrl); + const brands = await w.webContents.executeJavaScript('navigator.userAgentData.brands'); + expect(brands.map((b: any) => b.brand)).to.include('Chromium'); + }); + }); + }); + + describe('Badging API', () => { + it('does not crash', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + await w.webContents.executeJavaScript('navigator.setAppBadge(42)'); + await w.webContents.executeJavaScript('navigator.setAppBadge()'); + await w.webContents.executeJavaScript('navigator.clearAppBadge()'); + }); + }); + + describe('navigator.webkitGetUserMedia', () => { + it('calls its callbacks', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + await w.webContents.executeJavaScript(`new Promise((resolve) => { + navigator.webkitGetUserMedia({ + audio: true, + video: false + }, () => resolve(), + () => resolve()); + })`); + }); + }); + + describe('navigator.language', () => { + it('should not be empty', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL('about:blank'); + expect(await w.webContents.executeJavaScript('navigator.language')).to.not.equal(''); + }); + }); + + describe('heap snapshot', () => { + it('does not crash', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL('about:blank'); + await w.webContents.executeJavaScript('process._linkedBinding(\'electron_common_v8_util\').takeHeapSnapshot()'); + }); + }); + + ifdescribe(process.platform !== 'win32' && process.platform !== 'linux')('webgl', () => { + it('can be gotten as context in canvas', async () => { + const w = new BrowserWindow({ show: false }); + w.loadURL('about:blank'); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const canWebglContextBeCreated = await w.webContents.executeJavaScript(` + document.createElement('canvas').getContext('webgl') != null; + `); + expect(canWebglContextBeCreated).to.be.true(); + }); + }); + + describe('iframe', () => { + it('does not have node integration', async () => { + const w = new BrowserWindow({ show: false }); + await w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const result = await w.webContents.executeJavaScript(` + const iframe = document.createElement('iframe') + iframe.src = './set-global.html'; + document.body.appendChild(iframe); + new Promise(resolve => iframe.onload = e => resolve(iframe.contentWindow.test)) + `); + expect(result).to.equal('undefined undefined undefined'); + }); + }); + + describe('websockets', () => { + it('has user agent', async () => { + const server = http.createServer(); + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); + const port = (server.address() as AddressInfo).port; + const wss = new ws.Server({ server: server }); + const finished = new Promise((resolve, reject) => { + wss.on('error', reject); + wss.on('connection', (ws, upgradeReq) => { + resolve(upgradeReq.headers['user-agent']); + }); + }); + const w = new BrowserWindow({ show: false }); + w.loadURL('about:blank'); + w.webContents.executeJavaScript(` + new WebSocket('ws://127.0.0.1:${port}'); + `); + expect(await finished).to.include('Electron'); + }); + }); + + describe('fetch', () => { + it('does not crash', async () => { + const server = http.createServer((req, res) => { + res.end('test'); + }); + defer(() => server.close()); + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); + const port = (server.address() as AddressInfo).port; + const w = new BrowserWindow({ show: false }); + w.loadURL(`file://${fixturesPath}/pages/blank.html`); + const x = await w.webContents.executeJavaScript(` + fetch('http://127.0.0.1:${port}').then((res) => res.body.getReader()) + .then((reader) => { + return reader.read().then((r) => { + reader.cancel(); + return r.value; + }); + }) + `); + expect(x).to.deep.equal(new Uint8Array([116, 101, 115, 116])); + }); + }); }); describe('font fallback', () => { @@ -1591,7 +1912,7 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', () server.close(); }); - it('can fullscreen from out-of-process iframes (OOPIFs)', async () => { + ifit(process.platform !== 'darwin')('can fullscreen from out-of-process iframes (non-macOS)', async () => { const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange'); const html = ''; @@ -1615,8 +1936,37 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', () expect(width).to.equal(0); }); + ifit(process.platform === 'darwin')('can fullscreen from out-of-process iframes (macOS)', async () => { + await emittedOnce(w, 'enter-full-screen'); + const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange'); + const html = + ''; + w.loadURL(`data:text/html,${html}`); + await fullscreenChange; + + const fullscreenWidth = await w.webContents.executeJavaScript( + "document.querySelector('iframe').offsetWidth" + ); + expect(fullscreenWidth > 0).to.be.true(); + + await w.webContents.executeJavaScript( + "document.querySelector('iframe').contentWindow.postMessage('exitFullscreen', '*')" + ); + await emittedOnce(w.webContents, 'leave-html-full-screen'); + + const width = await w.webContents.executeJavaScript( + "document.querySelector('iframe').offsetWidth" + ); + expect(width).to.equal(0); + + w.setFullScreen(false); + await emittedOnce(w, 'leave-full-screen'); + }); + // TODO(jkleinsc) fix this flaky test on WOA ifit(process.platform !== 'win32' || process.arch !== 'arm64')('can fullscreen from in-process iframes', async () => { + if (process.platform === 'darwin') await emittedOnce(w, 'enter-full-screen'); + const fullscreenChange = emittedOnce(ipcMain, 'fullscreenChange'); w.loadFile(path.join(fixturesPath, 'pages', 'fullscreen-ipif.html')); await fullscreenChange; @@ -1679,11 +2029,39 @@ describe('navigator.serial', () => { }); it('returns a port when select-serial-port event is defined', async () => { + let havePorts = false; w.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => { - callback(portList[0].portId); + if (portList.length > 0) { + havePorts = true; + callback(portList[0].portId); + } else { + callback(''); + } }); const port = await getPorts(); - expect(port).to.equal('[object SerialPort]'); + if (havePorts) { + expect(port).to.equal('[object SerialPort]'); + } else { + expect(port).to.equal('NotFoundError: No port selected by the user.'); + } + }); + + it('navigator.serial.getPorts() returns values', async () => { + let havePorts = false; + + w.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => { + if (portList.length > 0) { + havePorts = true; + callback(portList[0].portId); + } else { + callback(''); + } + }); + await getPorts(); + if (havePorts) { + const grantedPorts = await w.webContents.executeJavaScript('navigator.serial.getPorts()'); + expect(grantedPorts).to.not.be.empty(); + } }); }); @@ -1891,7 +2269,7 @@ describe('navigator.hid', () => { serverUrl = `http://localhost:${(server.address() as any).port}`; }); - const getDevices: any = () => { + const requestDevices: any = () => { return w.webContents.executeJavaScript(` navigator.hid.requestDevice({filters: []}).then(device => device.toString()).catch(err => err.toString()); `, true); @@ -1909,7 +2287,7 @@ describe('navigator.hid', () => { it('does not return a device if select-hid-device event is not defined', async () => { w.loadFile(path.join(fixturesPath, 'pages', 'blank.html')); - const device = await getDevices(); + const device = await requestDevices(); expect(device).to.equal(''); }); @@ -1920,7 +2298,7 @@ describe('navigator.hid', () => { callback(); }); session.defaultSession.setPermissionCheckHandler(() => false); - const device = await getDevices(); + const device = await requestDevices(); expect(selectFired).to.be.false(); expect(device).to.equal(''); }); @@ -1938,7 +2316,7 @@ describe('navigator.hid', () => { callback(); } }); - const device = await getDevices(); + const device = await requestDevices(); expect(selectFired).to.be.true(); if (haveDevices) { expect(device).to.contain('[object HIDDevice]'); @@ -1987,7 +2365,7 @@ describe('navigator.hid', () => { return true; }); await w.webContents.executeJavaScript('navigator.hid.getDevices();', true); - const device = await getDevices(); + const device = await requestDevices(); expect(selectFired).to.be.true(); if (haveDevices) { expect(device).to.contain('[object HIDDevice]'); @@ -1996,4 +2374,81 @@ describe('navigator.hid', () => { expect(device).to.equal(''); } }); + + it('excludes a device when a exclusionFilter is specified', async () => { + const exclusionFilters = []; + let haveDevices = false; + let checkForExcludedDevice = false; + + w.webContents.session.on('select-hid-device', (event, details, callback) => { + if (details.deviceList.length > 0) { + details.deviceList.find((device) => { + if (device.name && device.name !== '' && device.serialNumber && device.serialNumber !== '') { + if (checkForExcludedDevice) { + const compareDevice = { + vendorId: device.vendorId, + productId: device.productId + }; + expect(compareDevice).to.not.equal(exclusionFilters[0], 'excluded device should not be returned'); + } else { + haveDevices = true; + exclusionFilters.push({ + vendorId: device.vendorId, + productId: device.productId + }); + return true; + } + } + }); + } + callback(); + }); + + await requestDevices(); + if (haveDevices) { + // We have devices to exclude, so check if exclusionFilters work + checkForExcludedDevice = true; + await w.webContents.executeJavaScript(` + navigator.hid.requestDevice({filters: [], exclusionFilters: ${JSON.stringify(exclusionFilters)}}).then(device => device.toString()).catch(err => err.toString()); + + `, true); + } + }); + + it('supports device.forget()', async () => { + let deletedDeviceFromEvent; + let haveDevices = false; + w.webContents.session.on('select-hid-device', (event, details, callback) => { + if (details.deviceList.length > 0) { + haveDevices = true; + callback(details.deviceList[0].deviceId); + } else { + callback(); + } + }); + w.webContents.session.on('hid-device-revoked', (event, details) => { + deletedDeviceFromEvent = details.device; + }); + await requestDevices(); + if (haveDevices) { + const grantedDevices = await w.webContents.executeJavaScript('navigator.hid.getDevices()'); + if (grantedDevices.length > 0) { + const deletedDevice = await w.webContents.executeJavaScript(` + navigator.hid.getDevices().then(devices => { + devices[0].forget(); + return { + vendorId: devices[0].vendorId, + productId: devices[0].productId, + name: devices[0].productName + } + }) + `); + const grantedDevices2 = await w.webContents.executeJavaScript('navigator.hid.getDevices()'); + expect(grantedDevices2.length).to.be.lessThan(grantedDevices.length); + if (deletedDevice.name !== '' && deletedDevice.productId && deletedDevice.vendorId) { + expect(deletedDeviceFromEvent).to.include(deletedDevice); + } + } + } + }); }); diff --git a/spec-main/crash-spec.ts b/spec-main/crash-spec.ts index eb9718dac5acd..803d9117d1a13 100644 --- a/spec-main/crash-spec.ts +++ b/spec-main/crash-spec.ts @@ -2,6 +2,7 @@ import { expect } from 'chai'; import * as cp from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; +import { ifit } from './spec-helpers'; const fixturePath = path.resolve(__dirname, 'fixtures', 'crash-cases'); @@ -41,7 +42,8 @@ describe('crash cases', () => { const cases = fs.readdirSync(fixturePath); for (const crashCase of cases) { - it(`the "${crashCase}" case should not crash`, () => { + // TODO(jkleinsc) fix this flaky test on Windows 32-bit + ifit(process.platform !== 'win32' || process.arch !== 'ia32' || crashCase !== 'quit-on-crashed-event')(`the "${crashCase}" case should not crash`, () => { const fixture = path.resolve(fixturePath, crashCase); const argsFile = path.resolve(fixture, 'electron.args'); const args = [fixture]; diff --git a/spec-main/extensions-spec.ts b/spec-main/extensions-spec.ts index 5c382d53e03b3..b2dc6d7f96c21 100644 --- a/spec-main/extensions-spec.ts +++ b/spec-main/extensions-spec.ts @@ -110,6 +110,12 @@ describe('chrome extensions', () => { expect(bg).to.equal('red'); }); + it('does not crash when loading an extension with missing manifest', async () => { + const customSession = session.fromPartition(`persist:${uuid.v4()}`); + const promise = customSession.loadExtension(path.join(fixtures, 'extensions', 'missing-manifest')); + await expect(promise).to.eventually.be.rejectedWith(/Manifest file is missing or unreadable/); + }); + it('does not crash when failing to load an extension', async () => { const customSession = session.fromPartition(`persist:${uuid.v4()}`); const promise = customSession.loadExtension(path.join(fixtures, 'extensions', 'load-error')); diff --git a/spec-main/fixtures/api/context-bridge/context-bridge-mutability/package.json b/spec-main/fixtures/api/context-bridge/context-bridge-mutability/package.json index d1fc13838e5fe..91b9749095be8 100644 --- a/spec-main/fixtures/api/context-bridge/context-bridge-mutability/package.json +++ b/spec-main/fixtures/api/context-bridge/context-bridge-mutability/package.json @@ -1,4 +1,4 @@ { - "name": "context-bridge-mutability", + "name": "electron-test-context-bridge-mutability", "main": "main.js" -} \ No newline at end of file +} diff --git a/spec-main/fixtures/api/safe-storage/decrypt-app/package.json b/spec-main/fixtures/api/safe-storage/decrypt-app/package.json index cb5d6ffc41906..f4e7a5ad938a1 100644 --- a/spec-main/fixtures/api/safe-storage/decrypt-app/package.json +++ b/spec-main/fixtures/api/safe-storage/decrypt-app/package.json @@ -1,4 +1,4 @@ { - "name": "electron-safe-storage", + "name": "electron-test-safe-storage", "main": "main.js" } diff --git a/spec-main/fixtures/api/safe-storage/encrypt-app/package.json b/spec-main/fixtures/api/safe-storage/encrypt-app/package.json index 2fa2fabcd1e84..1b14cccc1d787 100644 --- a/spec-main/fixtures/api/safe-storage/encrypt-app/package.json +++ b/spec-main/fixtures/api/safe-storage/encrypt-app/package.json @@ -1,4 +1,4 @@ { - "name": "electron-safe-storage", + "name": "electron-test-safe-storage", "main": "main.js" } diff --git a/spec-main/fixtures/apps/background-color-transparent/main.js b/spec-main/fixtures/apps/background-color-transparent/main.js index 8d1da05c6c1db..3086db0dc6b97 100644 --- a/spec-main/fixtures/apps/background-color-transparent/main.js +++ b/spec-main/fixtures/apps/background-color-transparent/main.js @@ -21,6 +21,7 @@ async function createWindow () { transparent: true, vibrancy: 'under-window', webPreferences: { + backgroundThrottling: false, contextIsolation: false, nodeIntegration: true } @@ -43,6 +44,7 @@ ipcMain.on('set-transparent', async () => { colors.transparent = result[0].hex(); const { green, transparent } = colors; + console.log({ green, transparent }); process.exit(green === transparent ? 1 : 0); }); diff --git a/spec-main/fixtures/apps/background-color-transparent/package.json b/spec-main/fixtures/apps/background-color-transparent/package.json index 0ea4852f44c3f..6b8e31a17749e 100644 --- a/spec-main/fixtures/apps/background-color-transparent/package.json +++ b/spec-main/fixtures/apps/background-color-transparent/package.json @@ -1,4 +1,4 @@ { - "name": "background-color-transparent", + "name": "electron-test-background-color-transparent", "main": "main.js" } diff --git a/spec-main/fixtures/apps/libuv-hang/main.js b/spec-main/fixtures/apps/libuv-hang/main.js index 4ca4ef15d9024..3c9b9d0b6f26a 100644 --- a/spec-main/fixtures/apps/libuv-hang/main.js +++ b/spec-main/fixtures/apps/libuv-hang/main.js @@ -5,7 +5,8 @@ async function createWindow () { const mainWindow = new BrowserWindow({ show: false, webPreferences: { - preload: path.join(__dirname, 'preload.js') + preload: path.join(__dirname, 'preload.js'), + sandbox: false } }); diff --git a/spec-main/fixtures/apps/open-new-window-from-link/index.html b/spec-main/fixtures/apps/open-new-window-from-link/index.html new file mode 100644 index 0000000000000..b7584564e0010 --- /dev/null +++ b/spec-main/fixtures/apps/open-new-window-from-link/index.html @@ -0,0 +1,11 @@ + + + + + + Hello World! + + + Open New Window + + diff --git a/spec-main/fixtures/apps/open-new-window-from-link/main.js b/spec-main/fixtures/apps/open-new-window-from-link/main.js new file mode 100644 index 0000000000000..7d41b3bb29ee5 --- /dev/null +++ b/spec-main/fixtures/apps/open-new-window-from-link/main.js @@ -0,0 +1,64 @@ +const { app, BrowserWindow } = require('electron'); +const path = require('path'); + +async function createWindow () { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600, + x: 100, + y: 100, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + contextIsolation: false, + nodeIntegration: true + } + }); + + await mainWindow.loadFile('index.html'); + + const rect = await mainWindow.webContents.executeJavaScript('JSON.parse(JSON.stringify(document.querySelector("a").getBoundingClientRect()))'); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + + function click (x, y, options) { + x = Math.floor(x); + y = Math.floor(y); + mainWindow.webContents.sendInputEvent({ + type: 'mouseDown', + button: 'left', + x, + y, + clickCount: 1, + ...options + }); + + mainWindow.webContents.sendInputEvent({ + type: 'mouseUp', + button: 'left', + x, + y, + clickCount: 1, + ...options + }); + } + + click(x, y, { modifiers: ['shift'] }); +} + +app.whenReady().then(() => { + app.on('web-contents-created', (e, wc) => { + wc.on('render-process-gone', (e, details) => { + console.error(details); + process.exit(1); + }); + + wc.on('did-finish-load', () => { + const title = wc.getTitle(); + if (title === 'Window From Link') { + process.exit(0); + } + }); + }); + + createWindow(); +}); diff --git a/spec-main/fixtures/apps/open-new-window-from-link/new-window-page.html b/spec-main/fixtures/apps/open-new-window-from-link/new-window-page.html new file mode 100644 index 0000000000000..ac919774f3b27 --- /dev/null +++ b/spec-main/fixtures/apps/open-new-window-from-link/new-window-page.html @@ -0,0 +1,11 @@ + + + + + + Window From Link + + + I'm a window opened from a link! + + diff --git a/spec-main/fixtures/apps/open-new-window-from-link/package.json b/spec-main/fixtures/apps/open-new-window-from-link/package.json new file mode 100644 index 0000000000000..ff9319a62ae99 --- /dev/null +++ b/spec-main/fixtures/apps/open-new-window-from-link/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron-test-open-new-window-from-link", + "main": "main.js" +} diff --git a/spec-main/fixtures/apps/open-new-window-from-link/preload.js b/spec-main/fixtures/apps/open-new-window-from-link/preload.js new file mode 100644 index 0000000000000..edb91c4291072 --- /dev/null +++ b/spec-main/fixtures/apps/open-new-window-from-link/preload.js @@ -0,0 +1,3 @@ +window.addEventListener('click', e => { + console.log('click', e); +}); diff --git a/spec-main/fixtures/apps/set-path/main.js b/spec-main/fixtures/apps/set-path/main.js new file mode 100644 index 0000000000000..efc6a624eef5b --- /dev/null +++ b/spec-main/fixtures/apps/set-path/main.js @@ -0,0 +1,43 @@ +const http = require('http'); +const { app, ipcMain, BrowserWindow } = require('electron'); + +if (process.argv.length > 3) { + app.setPath(process.argv[2], process.argv[3]); +} + +const html = ` + +`; + +const js = 'console.log("From service worker")'; + +app.once('ready', () => { + ipcMain.on('success', () => { + app.quit(); + }); + + const server = http.createServer((request, response) => { + if (request.url === '/') { + response.writeHead(200, { 'Content-Type': 'text/html' }); + response.end(html); + } else if (request.url === '/sw.js') { + response.writeHead(200, { 'Content-Type': 'text/javascript' }); + response.end(js); + } + }).listen(0, '127.0.0.1', () => { + const serverUrl = 'http://127.0.0.1:' + server.address().port; + const mainWindow = new BrowserWindow({ show: false, webPreferences: { webSecurity: true, nodeIntegration: true, contextIsolation: false } }); + mainWindow.loadURL(serverUrl); + }); +}); diff --git a/spec-main/fixtures/apps/set-path/package.json b/spec-main/fixtures/apps/set-path/package.json new file mode 100644 index 0000000000000..84edf0f3a389a --- /dev/null +++ b/spec-main/fixtures/apps/set-path/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron-test-set-path", + "main": "main.js" +} diff --git a/spec-main/fixtures/apps/xwindow-icon/package.json b/spec-main/fixtures/apps/xwindow-icon/package.json index 595e59b0f0f46..9e9503d422d03 100644 --- a/spec-main/fixtures/apps/xwindow-icon/package.json +++ b/spec-main/fixtures/apps/xwindow-icon/package.json @@ -1,4 +1,4 @@ { - "name": "electron-xwindow-icon", + "name": "electron-test-xwindow-icon", "main": "main.js" - } \ No newline at end of file + } diff --git a/spec-main/fixtures/auto-update/check-with-headers/package.json b/spec-main/fixtures/auto-update/check-with-headers/package.json index 05b06e42b92f0..b5362baed5a4c 100644 --- a/spec-main/fixtures/auto-update/check-with-headers/package.json +++ b/spec-main/fixtures/auto-update/check-with-headers/package.json @@ -1,5 +1,5 @@ { - "name": "electron-test-initial-app", + "name": "electron-test-check-with-headers", "version": "1.0.0", "main": "./index.js" -} \ No newline at end of file +} diff --git a/spec-main/fixtures/auto-update/check/package.json b/spec-main/fixtures/auto-update/check/package.json index 05b06e42b92f0..d127bfd349293 100644 --- a/spec-main/fixtures/auto-update/check/package.json +++ b/spec-main/fixtures/auto-update/check/package.json @@ -1,5 +1,5 @@ { - "name": "electron-test-initial-app", + "name": "electron-test-check", "version": "1.0.0", "main": "./index.js" -} \ No newline at end of file +} diff --git a/spec-main/fixtures/auto-update/update-json/package.json b/spec-main/fixtures/auto-update/update-json/package.json index 5edc5dc51ce71..ef434f0b40912 100644 --- a/spec-main/fixtures/auto-update/update-json/package.json +++ b/spec-main/fixtures/auto-update/update-json/package.json @@ -1,5 +1,5 @@ { - "name": "initial-app", + "name": "electron-test-update-json", "version": "1.0.0", "main": "./index.js" -} \ No newline at end of file +} diff --git a/spec-main/fixtures/auto-update/update/package.json b/spec-main/fixtures/auto-update/update/package.json index 5edc5dc51ce71..c9bb15fe643a5 100644 --- a/spec-main/fixtures/auto-update/update/package.json +++ b/spec-main/fixtures/auto-update/update/package.json @@ -1,5 +1,5 @@ { - "name": "initial-app", + "name": "electron-test-update", "version": "1.0.0", "main": "./index.js" -} \ No newline at end of file +} diff --git a/spec-main/fixtures/crash-cases/quit-on-crashed-event/index.js b/spec-main/fixtures/crash-cases/quit-on-crashed-event/index.js index a095bf69f490c..87ec0d6ada4f4 100644 --- a/spec-main/fixtures/crash-cases/quit-on-crashed-event/index.js +++ b/spec-main/fixtures/crash-cases/quit-on-crashed-event/index.js @@ -15,5 +15,6 @@ app.once('ready', async () => { process.exit(details.exitCode); } }); - await w.webContents.loadURL('chrome://checkcrash'); + await w.webContents.loadURL('about:blank'); + w.webContents.executeJavaScript('process.crash()'); }); diff --git a/spec-main/fixtures/crash-cases/safe-storage/index.js b/spec-main/fixtures/crash-cases/safe-storage/index.js new file mode 100644 index 0000000000000..151751820a8d5 --- /dev/null +++ b/spec-main/fixtures/crash-cases/safe-storage/index.js @@ -0,0 +1,39 @@ +const { app, safeStorage } = require('electron'); +const { expect } = require('chai'); + +(async () => { + if (!app.isReady()) { + // isEncryptionAvailable() returns false before the app is ready on + // Linux: https://github.com/electron/electron/issues/32206 + // and + // Windows: https://github.com/electron/electron/issues/33640. + expect(safeStorage.isEncryptionAvailable()).to.equal(process.platform === 'darwin'); + if (safeStorage.isEncryptionAvailable()) { + const plaintext = 'plaintext'; + const ciphertext = safeStorage.encryptString(plaintext); + expect(Buffer.isBuffer(ciphertext)).to.equal(true); + expect(safeStorage.decryptString(ciphertext)).to.equal(plaintext); + } else { + expect(() => safeStorage.encryptString('plaintext')).to.throw(/safeStorage cannot be used before app is ready/); + expect(() => safeStorage.decryptString(Buffer.from(''))).to.throw(/safeStorage cannot be used before app is ready/); + } + } + await app.whenReady(); + // isEncryptionAvailable() will always return false on CI due to a mocked + // dbus as mentioned above. + expect(safeStorage.isEncryptionAvailable()).to.equal(process.platform !== 'linux'); + if (safeStorage.isEncryptionAvailable()) { + const plaintext = 'plaintext'; + const ciphertext = safeStorage.encryptString(plaintext); + expect(Buffer.isBuffer(ciphertext)).to.equal(true); + expect(safeStorage.decryptString(ciphertext)).to.equal(plaintext); + } else { + expect(() => safeStorage.encryptString('plaintext')).to.throw(/Encryption is not available/); + expect(() => safeStorage.decryptString(Buffer.from(''))).to.throw(/Decryption is not available/); + } +})() + .then(app.quit) + .catch((err) => { + console.error(err); + app.exit(1); + }); diff --git a/spec-main/fixtures/extensions/missing-manifest/main.js b/spec-main/fixtures/extensions/missing-manifest/main.js new file mode 100644 index 0000000000000..d1e760d7b9d07 --- /dev/null +++ b/spec-main/fixtures/extensions/missing-manifest/main.js @@ -0,0 +1 @@ +console.log('oh no where is my manifest'); diff --git a/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp b/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp index 00beb974c1a72..7e2438f5006d2 100644 --- a/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp +++ b/spec-main/fixtures/native-addon/uv-dlopen/foo.cpp @@ -1,2 +1 @@ -extern "C" -void foo() { } \ No newline at end of file +extern "C" void foo() {} \ No newline at end of file diff --git a/spec-main/fixtures/native-addon/uv-dlopen/main.cpp b/spec-main/fixtures/native-addon/uv-dlopen/main.cpp index 4d34850a6254c..5edef8a0ea627 100644 --- a/spec-main/fixtures/native-addon/uv-dlopen/main.cpp +++ b/spec-main/fixtures/native-addon/uv-dlopen/main.cpp @@ -8,22 +8,26 @@ napi_value TestLoadLibrary(napi_env env, napi_callback_info info) { napi_value argv; napi_status status; status = napi_get_cb_info(env, info, &argc, &argv, NULL, NULL); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); char lib_path[256]; status = napi_get_value_string_utf8(env, argv, lib_path, 256, NULL); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); uv_lib_t lib; auto uv_status = uv_dlopen(lib_path, &lib); if (uv_status == 0) { napi_value result; status = napi_get_boolean(env, true, &result); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); return result; } else { status = napi_throw_error(env, NULL, uv_dlerror(&lib)); - if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0); + if (status != napi_ok) + napi_fatal_error(NULL, 0, NULL, 0); } } diff --git a/spec-main/fixtures/pages/iframe-protocol.html b/spec-main/fixtures/pages/iframe-protocol.html new file mode 100644 index 0000000000000..a283115b19382 --- /dev/null +++ b/spec-main/fixtures/pages/iframe-protocol.html @@ -0,0 +1,11 @@ + + + + diff --git a/spec-main/fixtures/preload-expose-ipc.js b/spec-main/fixtures/preload-expose-ipc.js new file mode 100644 index 0000000000000..131399e0b0185 --- /dev/null +++ b/spec-main/fixtures/preload-expose-ipc.js @@ -0,0 +1,14 @@ +const { contextBridge, ipcRenderer } = require('electron'); + +// NOTE: Never do this in an actual app! Very insecure! +contextBridge.exposeInMainWorld('ipc', { + send (...args) { + return ipcRenderer.send(...args); + }, + sendSync (...args) { + return ipcRenderer.sendSync(...args); + }, + invoke (...args) { + return ipcRenderer.invoke(...args); + } +}); diff --git a/spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt b/spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt deleted file mode 100644 index b7ed882540099..0000000000000 --- a/spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt +++ /dev/null @@ -1,166 +0,0 @@ -[ - [ - "top=5,left=10,resizable=no", - { - "sender": "[WebContents]", - "frameId": 1, - "processId": "placeholder-process-id" - }, - "about:blank", - "frame-name", - "new-window", - { - "show": true, - "width": 800, - "height": 600, - "top": 5, - "left": 10, - "resizable": false, - "x": 10, - "y": 5, - "webPreferences": { - "contextIsolation": true, - "nodeIntegration": false, - "webviewTag": false, - "nodeIntegrationInSubFrames": false - }, - "webContents": "[WebContents]" - }, - [], - { - "url": "", - "policy": "strict-origin-when-cross-origin" - }, - null - ], - [ - "zoomFactor=2,resizable=0,x=0,y=10", - { - "sender": "[WebContents]", - "frameId": 1, - "processId": "placeholder-process-id" - }, - "about:blank", - "frame-name", - "new-window", - { - "show": true, - "width": 800, - "height": 600, - "resizable": false, - "x": 0, - "y": 10, - "webPreferences": { - "zoomFactor": "2", - "contextIsolation": true, - "nodeIntegration": false, - "webviewTag": false, - "nodeIntegrationInSubFrames": false - }, - "webContents": "[WebContents]" - }, - [], - { - "url": "", - "policy": "strict-origin-when-cross-origin" - }, - null - ], - [ - "backgroundColor=gray,webPreferences=0,x=100,y=100", - { - "sender": "[WebContents]", - "frameId": 1, - "processId": "placeholder-process-id" - }, - "about:blank", - "frame-name", - "new-window", - { - "show": true, - "width": 800, - "height": 600, - "backgroundColor": "gray", - "webPreferences": { - "contextIsolation": true, - "nodeIntegration": false, - "webviewTag": false, - "nodeIntegrationInSubFrames": false - }, - "x": 100, - "y": 100, - "webContents": "[WebContents]" - }, - [], - { - "url": "", - "policy": "strict-origin-when-cross-origin" - }, - null - ], - [ - "x=50,y=20,title=sup", - { - "sender": "[WebContents]", - "frameId": 1, - "processId": "placeholder-process-id" - }, - "about:blank", - "frame-name", - "new-window", - { - "show": true, - "width": 800, - "height": 600, - "x": 50, - "y": 20, - "title": "sup", - "webPreferences": { - "contextIsolation": true, - "nodeIntegration": false, - "webviewTag": false, - "nodeIntegrationInSubFrames": false - }, - "webContents": "[WebContents]" - }, - [], - { - "url": "", - "policy": "strict-origin-when-cross-origin" - }, - null - ], - [ - "show=false,top=1,left=1", - { - "sender": "[WebContents]", - "frameId": 1, - "processId": "placeholder-process-id" - }, - "about:blank", - "frame-name", - "new-window", - { - "show": false, - "width": 800, - "height": 600, - "top": 1, - "left": 1, - "x": 1, - "y": 1, - "webPreferences": { - "contextIsolation": true, - "nodeIntegration": false, - "webviewTag": false, - "nodeIntegrationInSubFrames": false - }, - "webContents": "[WebContents]" - }, - [], - { - "url": "", - "policy": "strict-origin-when-cross-origin" - }, - null - ] -] diff --git a/spec-main/fixtures/webview/fullscreen/frame.html b/spec-main/fixtures/webview/fullscreen/frame.html index c92571eef4a8b..d7307f0b83bc4 100644 --- a/spec-main/fixtures/webview/fullscreen/frame.html +++ b/spec-main/fixtures/webview/fullscreen/frame.html @@ -2,6 +2,7 @@
WebView
+ - - - - - diff --git a/spec/fixtures/api/electron-module-app/node_modules/electron/package.json b/spec/fixtures/api/electron-module-app/node_modules/electron/package.json deleted file mode 100644 index 07e3804ebb16e..0000000000000 --- a/spec/fixtures/api/electron-module-app/node_modules/electron/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "electron", - "main": "index.js" -} diff --git a/spec/fixtures/api/electron-module-app/node_modules/foo/index.js b/spec/fixtures/api/electron-module-app/node_modules/foo/index.js deleted file mode 100644 index 41f3ba446f69d..0000000000000 --- a/spec/fixtures/api/electron-module-app/node_modules/foo/index.js +++ /dev/null @@ -1 +0,0 @@ -exports.bar = function () {}; diff --git a/spec/fixtures/api/electron-module-app/node_modules/foo/package.json b/spec/fixtures/api/electron-module-app/node_modules/foo/package.json deleted file mode 100644 index 596ac286ecadc..0000000000000 --- a/spec/fixtures/api/electron-module-app/node_modules/foo/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "foo", - "main": "index.js" -} diff --git a/spec/fixtures/api/first-party-sets/base/main.js b/spec/fixtures/api/first-party-sets/base/main.js new file mode 100644 index 0000000000000..68865b517607a --- /dev/null +++ b/spec/fixtures/api/first-party-sets/base/main.js @@ -0,0 +1,20 @@ +const { app } = require('electron'); + +const sets = [ + 'https://fps-member1.glitch.me', + 'https://fps-member2.glitch.me', + 'https://fps-member3.glitch.me' +]; + +app.commandLine.appendSwitch('use-first-party-set', sets.join(',')); + +app.whenReady().then(function () { + const hasSwitch = app.commandLine.hasSwitch('use-first-party-set'); + const value = app.commandLine.getSwitchValue('use-first-party-set'); + if (hasSwitch) { + process.stdout.write(JSON.stringify(value)); + process.stdout.end(); + } + + app.quit(); +}); diff --git a/spec/fixtures/api/first-party-sets/base/package.json b/spec/fixtures/api/first-party-sets/base/package.json new file mode 100644 index 0000000000000..1766d06684600 --- /dev/null +++ b/spec/fixtures/api/first-party-sets/base/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron-test-first-party-sets-base", + "main": "main.js" +} diff --git a/spec/fixtures/api/first-party-sets/command-line/main.js b/spec/fixtures/api/first-party-sets/command-line/main.js new file mode 100644 index 0000000000000..8e2782f31dc0e --- /dev/null +++ b/spec/fixtures/api/first-party-sets/command-line/main.js @@ -0,0 +1,12 @@ +const { app } = require('electron'); + +app.whenReady().then(function () { + const hasSwitch = app.commandLine.hasSwitch('use-first-party-set'); + const value = app.commandLine.getSwitchValue('use-first-party-set'); + if (hasSwitch) { + process.stdout.write(JSON.stringify(value)); + process.stdout.end(); + } + + app.quit(); +}); diff --git a/spec/fixtures/api/first-party-sets/command-line/package.json b/spec/fixtures/api/first-party-sets/command-line/package.json new file mode 100644 index 0000000000000..c4b5839bdcc60 --- /dev/null +++ b/spec/fixtures/api/first-party-sets/command-line/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron-test-first-party-sets-command-line", + "main": "main.js" +} diff --git a/spec/fixtures/api/locale-check/main.js b/spec/fixtures/api/locale-check/main.js index 929a9e0e9519a..dd4e6317dbb61 100644 --- a/spec/fixtures/api/locale-check/main.js +++ b/spec/fixtures/api/locale-check/main.js @@ -9,7 +9,7 @@ app.whenReady().then(() => { if (process.argv[3] === '--print-env') { process.stdout.write(String(process.env.LC_ALL)); } else { - process.stdout.write(app.getLocale()); + process.stdout.write(`${app.getLocale()}|${app.getSystemLocale()}`); } process.stdout.end(); diff --git a/spec/fixtures/api/mixed-sandbox-app/package.json b/spec/fixtures/api/mixed-sandbox-app/package.json index c5b70811e60c5..e7c1a4105eedc 100644 --- a/spec/fixtures/api/mixed-sandbox-app/package.json +++ b/spec/fixtures/api/mixed-sandbox-app/package.json @@ -1,5 +1,5 @@ { - "name": "electron-app-mixed-sandbox", + "name": "electron-test-mixed-sandbox", "main": "main.js" } diff --git a/spec/fixtures/api/quit-app/package.json b/spec/fixtures/api/quit-app/package.json index fbdee7f90f955..5ca705eee7141 100644 --- a/spec/fixtures/api/quit-app/package.json +++ b/spec/fixtures/api/quit-app/package.json @@ -1,4 +1,4 @@ { - "name": "electron-quit-app", + "name": "electron-test-quit-app", "main": "main.js" } diff --git a/spec/fixtures/api/relaunch/main.js b/spec/fixtures/api/relaunch/main.js index 272c41f4421aa..94898f6059d65 100644 --- a/spec/fixtures/api/relaunch/main.js +++ b/spec/fixtures/api/relaunch/main.js @@ -11,11 +11,15 @@ app.whenReady().then(() => { const lastArg = process.argv[process.argv.length - 1]; const client = net.connect(socketPath); client.once('connect', () => { - client.end(String(lastArg === '--second')); + client.end(lastArg); }); client.once('end', () => { - if (lastArg !== '--second') { - app.relaunch({ args: process.argv.slice(1).concat('--second') }); + if (lastArg === '--first') { + // Once without execPath specified + app.relaunch({ args: process.argv.slice(1, -1).concat('--second') }); + } else if (lastArg === '--second') { + // And once with execPath specified + app.relaunch({ execPath: process.argv[0], args: process.argv.slice(1, -1).concat('--third') }); } app.exit(0); }); diff --git a/spec/fixtures/api/relaunch/package.json b/spec/fixtures/api/relaunch/package.json index dbaabc84896d2..93edb1ae8aeb5 100644 --- a/spec/fixtures/api/relaunch/package.json +++ b/spec/fixtures/api/relaunch/package.json @@ -1,5 +1,5 @@ { - "name": "electron-app-relaunch", + "name": "electron-test-relaunch", "main": "main.js" } diff --git a/spec/fixtures/api/singleton-data/main.js b/spec/fixtures/api/singleton-data/main.js index f79ed9ccc9bce..50a623410ea89 100644 --- a/spec/fixtures/api/singleton-data/main.js +++ b/spec/fixtures/api/singleton-data/main.js @@ -1,17 +1,11 @@ const { app } = require('electron'); -app.whenReady().then(() => { - console.log('started'); // ping parent -}); - // Send data from the second instance to the first instance. const sendAdditionalData = app.commandLine.hasSwitch('send-data'); -// Prevent the default behaviour of second-instance, which sends back an empty ack. -const preventDefault = app.commandLine.hasSwitch('prevent-default'); - -// Send an object back for the ack rather than undefined. -const sendAck = app.commandLine.hasSwitch('send-ack'); +app.whenReady().then(() => { + console.log('started'); // ping parent +}); let obj = { level: 1, @@ -21,45 +15,20 @@ let obj = { testkey: 'testvalue2' } }; -let ackObj = { - level: 1, - testkey: 'acktestvalue1', - inner: { - level: 2, - testkey: 'acktestvalue2' - } -}; - if (app.commandLine.hasSwitch('data-content')) { obj = JSON.parse(app.commandLine.getSwitchValue('data-content')); if (obj === 'undefined') { obj = undefined; } } -if (app.commandLine.hasSwitch('ack-content')) { - ackObj = JSON.parse(app.commandLine.getSwitchValue('ack-content')); - if (ackObj === 'undefined') { - ackObj = undefined; - } -} - -app.on('first-instance-ack', (event, additionalData) => { - console.log(JSON.stringify(additionalData)); -}); const gotTheLock = sendAdditionalData ? app.requestSingleInstanceLock(obj) : app.requestSingleInstanceLock(); -app.on('second-instance', (event, args, workingDirectory, data, ackCallback) => { - if (preventDefault) { - event.preventDefault(); - } +app.on('second-instance', (event, args, workingDirectory, data) => { setImmediate(() => { console.log([JSON.stringify(args), JSON.stringify(data)].join('||')); - sendAck ? ackCallback(ackObj) : ackCallback(); - setImmediate(() => { - app.exit(0); - }); + app.exit(0); }); }); diff --git a/spec/fixtures/api/singleton-data/package.json b/spec/fixtures/api/singleton-data/package.json index 3c20945331c14..a1498100b0fea 100644 --- a/spec/fixtures/api/singleton-data/package.json +++ b/spec/fixtures/api/singleton-data/package.json @@ -1,5 +1,5 @@ { - "name": "electron-app-singleton-data", + "name": "electron-test-singleton-data", "main": "main.js" } diff --git a/spec/fixtures/api/singleton/package.json b/spec/fixtures/api/singleton/package.json index ebf7c8f4892e2..42299dda77359 100644 --- a/spec/fixtures/api/singleton/package.json +++ b/spec/fixtures/api/singleton/package.json @@ -1,5 +1,5 @@ { - "name": "electron-app-singleton", + "name": "electron-test-singleton", "main": "main.js" } diff --git a/spec/fixtures/pages/fullscreen.html b/spec/fixtures/pages/fullscreen.html index 4e5648e0194d2..ee8e403f43220 100644 --- a/spec/fixtures/pages/fullscreen.html +++ b/spec/fixtures/pages/fullscreen.html @@ -1 +1 @@ - + \ No newline at end of file diff --git a/spec/fixtures/api/electron-module-app/node_modules/electron/index.js b/spec/fixtures/pages/service-worker/empty.html similarity index 100% rename from spec/fixtures/api/electron-module-app/node_modules/electron/index.js rename to spec/fixtures/pages/service-worker/empty.html diff --git a/spec/fixtures/pages/service-worker/worker-no-node.js b/spec/fixtures/pages/service-worker/worker-no-node.js new file mode 100644 index 0000000000000..e22b7ca012cd8 --- /dev/null +++ b/spec/fixtures/pages/service-worker/worker-no-node.js @@ -0,0 +1,6 @@ +self.clients.matchAll({ includeUncontrolled: true }).then((clients) => { + if (!clients?.length) return; + + const msg = [typeof process, typeof setImmediate, typeof global, typeof Buffer].join(' '); + clients[0].postMessage(msg); +}); diff --git a/spec/fixtures/pages/shared_worker.html b/spec/fixtures/pages/shared_worker.html deleted file mode 100644 index 7a0d0757ab262..0000000000000 --- a/spec/fixtures/pages/shared_worker.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/spec/fixtures/pages/worker.html b/spec/fixtures/pages/worker.html index c84ef52065e02..95aceac6c08aa 100644 --- a/spec/fixtures/pages/worker.html +++ b/spec/fixtures/pages/worker.html @@ -4,7 +4,7 @@ const {ipcRenderer} = require('electron') let worker = new Worker(`../workers/worker_node.js`) worker.onmessage = function (event) { - ipcRenderer.sendToHost(event.data) + ipcRenderer.send('worker-result', event.data) worker.terminate() } diff --git a/spec/node-spec.js b/spec/node-spec.js index 05af8764c08c6..2d3fdd53afb26 100644 --- a/spec/node-spec.js +++ b/spec/node-spec.js @@ -45,7 +45,7 @@ describe('node feature', () => { expect(msg).to.equal('message'); }); - it('works in forked process when options.env is specifed', async () => { + it('works in forked process when options.env is specified', async () => { const child = ChildProcess.fork(path.join(fixtures, 'module', 'fork_ping.js'), [], { path: process.env.PATH }); diff --git a/spec/package.json b/spec/package.json index 38ab98be7c26b..d14f50aac78e2 100644 --- a/spec/package.json +++ b/spec/package.json @@ -3,15 +3,12 @@ "productName": "Electron Test", "main": "static/main.js", "version": "0.1.0", - "scripts": { - "postinstall": "node ../script/run-if-exists.js node_modules/robotjs node-gyp rebuild" - }, "devDependencies": { "basic-auth": "^2.0.1", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "coffeescript": "^2.4.1", - "dbus-native": "github:jkleinsc/dbus-native#master", + "dbus-native": "github:nornagon/dbus-native#master", "dirty-chai": "^2.0.1", "graceful-fs": "^4.1.15", "is-valid-window": "0.0.5", @@ -30,5 +27,8 @@ }, "dependencies": { "mocha-appveyor-reporter": "^0.4.2" + }, + "resolutions": { + "nan": "github:jkleinsc/nan#remove_accessor_signature" } } diff --git a/spec/static/index.html b/spec/static/index.html index 7c316a69f130a..f69432535ac6a 100644 --- a/spec/static/index.html +++ b/spec/static/index.html @@ -24,7 +24,7 @@ // DO NOT MOVE, REMOVE OR EDIT THIS LINE require('chai').use(require('chai-as-promised')) - // Rediret all output to browser. + // Redirect all output to browser. const fakeConsole = {} for (const k in console) { if (console.hasOwnProperty(k) && k !== 'assert') { diff --git a/spec/static/main.js b/spec/static/main.js index 73839000d6279..262024a881094 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -93,8 +93,14 @@ app.on('window-all-closed', function () { app.quit(); }); -app.on('gpu-process-crashed', (event, killed) => { - console.log(`GPU process crashed (killed=${killed})`); +app.on('child-process-gone', (event, details) => { + if (details.type === 'GPU' && details.reason !== 'clean-exit') { + if (details.reason === 'crashed') { + console.log('GPU process crashed'); + } else { + console.log(`GPU process exited with code ${details.exitCode}`); + } + } }); app.on('renderer-process-crashed', (event, contents, killed) => { @@ -130,7 +136,7 @@ app.whenReady().then(async function () { const chosen = dialog.showMessageBox(window, { type: 'warning', buttons: ['Close', 'Keep Waiting'], - message: 'Window is not responsing', + message: 'Window is not responding', detail: 'The window is not responding. Would you like to force close it or just keep waiting?' }); if (chosen === 0) window.destroy(); @@ -162,7 +168,6 @@ ipcMain.on('disable-preload-on-next-will-attach-webview', (event, id) => { event.sender.once('will-attach-webview', (event, webPreferences, params) => { params.src = `file://${path.join(__dirname, '..', 'fixtures', 'pages', 'webview-stripped-preload.html')}`; delete webPreferences.preload; - delete webPreferences.preloadURL; }); }); diff --git a/spec/ts-smoke/electron/main.ts b/spec/ts-smoke/electron/main.ts index 6992f92e8b2f8..6cd4db3b71efd 100644 --- a/spec/ts-smoke/electron/main.ts +++ b/spec/ts-smoke/electron/main.ts @@ -60,9 +60,9 @@ app.whenReady().then(() => { // and load the index.html of the app. mainWindow.loadURL(`file://${__dirname}/index.html`) - mainWindow.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greateRefferer' }) - mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greateRefferer' }) - mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greateRefferer', postData: [{ type: 'rawData', bytes: Buffer.from([123]) }] }) + mainWindow.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer' }) + mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer' }) + mainWindow.webContents.loadURL('file://foo/bar', { userAgent: 'cool-agent', httpReferrer: 'greatReferrer', postData: [{ type: 'rawData', bytes: Buffer.from([123]) }] }) mainWindow.webContents.openDevTools() mainWindow.webContents.toggleDevTools() @@ -86,10 +86,11 @@ app.whenReady().then(() => { mainWindow.webContents.print() mainWindow.webContents.printToPDF({ - marginsType: 1, - pageSize: 'A3', + margins: { + top: 1 + }, printBackground: true, - printSelectionOnly: true, + pageRanges: '1-3', landscape: true }).then((data: Buffer) => console.log(data)) @@ -512,7 +513,7 @@ dialog.showOpenDialog(win3, { const ret = globalShortcut.register('ctrl+x', () => { console.log('ctrl+x is pressed') }) -if (!ret) { console.log('registerion fails') } +if (!ret) { console.log('registration fails') } // Check whether a shortcut is registered. console.log(globalShortcut.isRegistered('ctrl+x')) @@ -939,7 +940,7 @@ app.whenReady().then(() => { appIcon.displayBalloon({ title: 'Hello World!', - content: 'This the the balloon content.', + content: 'This is the balloon content.', iconType: 'error', icon: 'path/to/icon', respectQuietTime: true, diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 0b649d1bd77ad..9f53a7603e49b 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -7,7 +7,7 @@ const { emittedOnce, waitForEvent } = require('./events-helpers'); const { ifdescribe, ifit, delay } = require('./spec-helpers'); const features = process._linkedBinding('electron_common_features'); -const nativeModulesEnabled = process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS; +const nativeModulesEnabled = !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS; /* Most of the APIs here don't use standard callbacks */ /* eslint-disable standard/no-callback-literal */ @@ -233,7 +233,7 @@ describe(' tag', function () { const types = JSON.parse(message); expect(types).to.include({ - require: 'function', // arguments passed to it should be availale + require: 'function', // arguments passed to it should be available electron: 'undefined', // objects from the scope it is called from should not be available window: 'object', // the window object should be available localVar: 'undefined' // but local variables should not be exposed to the window @@ -243,6 +243,7 @@ describe(' tag', function () { it('preload script can require modules that still use "process" and "Buffer" when nodeintegration is off', async () => { const message = await startLoadingWebViewAndWaitForMessage(webview, { preload: `${fixtures}/module/preload-node-off-wrapper.js`, + webpreferences: 'sandbox=no', src: `file://${fixtures}/api/blank.html` }); @@ -288,6 +289,7 @@ describe(' tag', function () { it('works without script tag in page', async () => { const message = await startLoadingWebViewAndWaitForMessage(webview, { preload: `${fixtures}/module/preload.js`, + webpreferences: 'sandbox=no', src: `file://${fixtures}pages/base-page.html` }); @@ -303,6 +305,7 @@ describe(' tag', function () { it('resolves relative URLs', async () => { const message = await startLoadingWebViewAndWaitForMessage(webview, { preload: '../fixtures/module/preload.js', + webpreferences: 'sandbox=no', src: `file://${fixtures}/pages/e.html` }); @@ -390,6 +393,7 @@ describe(' tag', function () { const message = await startLoadingWebViewAndWaitForMessage(webview, { disablewebsecurity: '', preload: `${fixtures}/module/preload.js`, + webpreferences: 'sandbox=no', src: `file://${fixtures}/pages/e.html` }); @@ -554,12 +558,12 @@ describe(' tag', function () { }); }); - describe('page-title-set event', () => { + describe('page-title-updated event', () => { it('emits when title is set', async () => { loadWebView(webview, { src: `file://${fixtures}/pages/a.html` }); - const { title, explicitSet } = await waitForEvent(webview, 'page-title-set'); + const { title, explicitSet } = await waitForEvent(webview, 'page-title-updated'); expect(title).to.equal('test'); expect(explicitSet).to.be.true(); @@ -622,7 +626,7 @@ describe(' tag', function () { }); describe('will-navigate event', () => { - it('emits when a url that leads to oustide of the page is clicked', async () => { + it('emits when a url that leads to outside of the page is clicked', async () => { loadWebView(webview, { src: `file://${fixtures}/pages/webview-will-navigate.html` }); @@ -910,20 +914,6 @@ describe(' tag', function () { }); describe('executeJavaScript', () => { - it('should support user gesture', async () => { - await loadWebView(webview, { - src: `file://${fixtures}/pages/fullscreen.html` - }); - - // Event handler has to be added before js execution. - const waitForEnterHtmlFullScreen = waitForEvent(webview, 'enter-html-full-screen'); - - const jsScript = "document.querySelector('video').webkitRequestFullscreen()"; - webview.executeJavaScript(jsScript, true); - - return waitForEnterHtmlFullScreen; - }); - it('can return the result of the executed script', async () => { await loadWebView(webview, { src: 'about:blank' @@ -1110,14 +1100,16 @@ describe(' tag', function () { ifdescribe(features.isPrintingEnabled())('.printToPDF()', () => { it('rejects on incorrectly typed parameters', async () => { const badTypes = { - marginsType: 'terrible', - scaleFactor: 'not-a-number', landscape: [], - pageRanges: { oops: 'im-not-the-right-key' }, - headerFooter: '123', - printSelectionOnly: 1, + displayHeaderFooter: '123', printBackground: 2, - pageSize: 'IAmAPageSize' + scale: 'not-a-number', + pageSize: 'IAmAPageSize', + margins: 'terrible', + pageRanges: { oops: 'im-not-the-right-key' }, + headerTemplate: [1, 2, 3], + footerTemplate: [4, 5, 6], + preferCSSPageSize: 'no' }; // These will hard crash in Chromium unless we type-check diff --git a/spec/yarn.lock b/spec/yarn.lock index 79ba3ebb64ecd..3bb7e4d164a92 100644 --- a/spec/yarn.lock +++ b/spec/yarn.lock @@ -12,27 +12,28 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== -"abstract-socket@github:saghul/node-abstractsocket#35b1b1491fabc04899bde5be3428abf5cf9cd528": - version "2.1.0" - resolved "https://codeload.github.com/saghul/node-abstractsocket/tar.gz/35b1b1491fabc04899bde5be3428abf5cf9cd528" +abstract-socket@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/abstract-socket/-/abstract-socket-2.1.1.tgz#243a7e6e6ff65bb9eab16a22fa90699b91e528f7" + integrity sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA== dependencies: bindings "^1.2.1" nan "^2.12.1" ajv@^6.5.5: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" + integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== ansi-regex@^5.0.0: version "5.0.0" @@ -212,9 +213,9 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -"dbus-native@github:jkleinsc/dbus-native#master": +"dbus-native@github:nornagon/dbus-native#master": version "0.4.0" - resolved "https://codeload.github.com/jkleinsc/dbus-native/tar.gz/bb7cba24533fac70f81b92f8357211a84f6e0c1f" + resolved "https://codeload.github.com/nornagon/dbus-native/tar.gz/b90ed62d0b5cb93909173c3e0551d9bff0602a90" dependencies: "@nornagon/put" "0.0.8" event-stream "^4.0.0" @@ -224,7 +225,7 @@ dashdash@^1.12.0: safe-buffer "^5.1.1" xml2js "^0.4.17" optionalDependencies: - abstract-socket "github:saghul/node-abstractsocket#35b1b1491fabc04899bde5be3428abf5cf9cd528" + abstract-socket "^2.0.0" debug@2.6.9, debug@^2.2.0: version "2.6.9" @@ -355,15 +356,15 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== file-uri-to-path@1.0.0: version "1.0.0" @@ -685,10 +686,9 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -nan@2.x, nan@^2.12.1: - version "2.14.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" - integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== +nan@2.x, nan@^2.12.1, "nan@github:jkleinsc/nan#remove_accessor_signature": + version "2.16.0" + resolved "https://codeload.github.com/jkleinsc/nan/tar.gz/6a2f95a6a2209d8aa7542fb18099fd808a802059" oauth-sign@~0.9.0: version "0.9.0" @@ -723,9 +723,9 @@ path-is-absolute@^1.0.0: integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= pathval@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== pause-stream@^0.0.11: version "0.0.11" @@ -962,9 +962,9 @@ type-detect@^4.0.0, type-detect@^4.0.5: integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" diff --git a/typings/internal-ambient.d.ts b/typings/internal-ambient.d.ts index 77a53136ff732..6dcf6de2ca985 100644 --- a/typings/internal-ambient.d.ts +++ b/typings/internal-ambient.d.ts @@ -27,7 +27,6 @@ declare namespace NodeJS { isPictureInPictureEnabled(): boolean; isExtensionsEnabled(): boolean; isComponentBuild(): boolean; - isWinDarkModeWindowUiEnabled(): boolean; } interface IpcRendererBinding { @@ -108,8 +107,6 @@ declare namespace NodeJS { isWebView: boolean; hiddenPage: boolean; nodeIntegration: boolean; - preload: string - preloadScripts: string[]; webviewTag: boolean; } @@ -181,12 +178,6 @@ declare namespace NodeJS { _linkedBinding(name: 'electron_common_environment'): EnvironmentBinding; _linkedBinding(name: 'electron_common_features'): FeaturesBinding; _linkedBinding(name: 'electron_common_native_image'): { nativeImage: typeof Electron.NativeImage }; - _linkedBinding(name: 'electron_common_native_theme'): { nativeTheme: Electron.NativeTheme }; - _linkedBinding(name: 'electron_common_notification'): { - isSupported(): boolean; - Notification: typeof Electron.Notification; - } - _linkedBinding(name: 'electron_common_screen'): { createScreen(): Electron.Screen }; _linkedBinding(name: 'electron_common_shell'): Electron.Shell; _linkedBinding(name: 'electron_common_v8_util'): V8UtilBinding; _linkedBinding(name: 'electron_browser_app'): { app: Electron.App, App: Function }; @@ -218,18 +209,26 @@ declare namespace NodeJS { _linkedBinding(name: 'electron_browser_message_port'): { createPair(): { port1: Electron.MessagePortMain, port2: Electron.MessagePortMain }; }; + _linkedBinding(name: 'electron_browser_native_theme'): { nativeTheme: Electron.NativeTheme }; _linkedBinding(name: 'electron_browser_net'): { isOnline(): boolean; isValidHeaderName: (headerName: string) => boolean; isValidHeaderValue: (headerValue: string) => boolean; + fileURLToFilePath: (url: string) => string; Net: any; net: any; createURLLoader(options: CreateURLLoaderOptions): URLLoader; }; + _linkedBinding(name: 'electron_browser_notification'): { + isSupported(): boolean; + Notification: typeof Electron.Notification; + } _linkedBinding(name: 'electron_browser_power_monitor'): PowerMonitorBinding; _linkedBinding(name: 'electron_browser_power_save_blocker'): { powerSaveBlocker: Electron.PowerSaveBlocker }; + _linkedBinding(name: 'electron_browser_push_notifications'): { pushNotifications: Electron.PushNotifications }; _linkedBinding(name: 'electron_browser_safe_storage'): { safeStorage: Electron.SafeStorage }; _linkedBinding(name: 'electron_browser_session'): typeof Electron.Session; + _linkedBinding(name: 'electron_browser_screen'): { createScreen(): Electron.Screen }; _linkedBinding(name: 'electron_browser_system_preferences'): { systemPreferences: Electron.SystemPreferences }; _linkedBinding(name: 'electron_browser_tray'): { Tray: Electron.Tray }; _linkedBinding(name: 'electron_browser_view'): { View: Electron.View }; @@ -238,6 +237,7 @@ declare namespace NodeJS { _linkedBinding(name: 'electron_browser_web_frame_main'): { WebFrameMain: typeof Electron.WebFrameMain; fromId(processId: number, routingId: number): Electron.WebFrameMain; + fromIdOrNull(processId: number, routingId: number): Electron.WebFrameMain | null; } _linkedBinding(name: 'electron_renderer_crash_reporter'): Electron.CrashReporter; _linkedBinding(name: 'electron_renderer_ipc'): { ipc: IpcRendererBinding }; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 666775c16a257..7789f297e55e4 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -63,10 +63,9 @@ declare namespace Electron { equal(other: WebContents): boolean; browserWindowOptions: BrowserWindowConstructorOptions; _windowOpenHandler: ((details: Electron.HandlerDetails) => any) | null; - _callWindowOpenHandler(event: any, details: Electron.HandlerDetails): Electron.BrowserWindowConstructorOptions | null; + _callWindowOpenHandler(event: any, details: Electron.HandlerDetails): {browserWindowConstructorOptions: Electron.BrowserWindowConstructorOptions | null, outlivesOpener: boolean}; _setNextChildWebPreferences(prefs: Partial & Pick): void; _send(internal: boolean, channel: string, args: any): boolean; - _sendToFrameInternal(frameId: number | [number, number], channel: string, ...args: any[]): boolean; _sendInternal(channel: string, ...args: any[]): void; _printToPDF(options: any): Promise; _print(options: any, callback?: (success: boolean, failureReason: string) => void): void; @@ -81,7 +80,6 @@ declare namespace Electron { attachToIframe(embedderWebContents: Electron.WebContents, embedderFrameId: number): void; detachFromOuterFrame(): void; setEmbedder(embedder: Electron.WebContents): void; - attachParams?: { instanceId: number; src: string, opts: LoadURLOptions }; viewInstanceId: number; } @@ -97,7 +95,6 @@ declare namespace Electron { interface WebPreferences { disablePopups?: boolean; - preloadURL?: string; embedder?: Electron.WebContents; type?: 'backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'; } @@ -265,6 +262,11 @@ declare namespace ElectronInternal { is_default?: 'true', } + type PageSize = { + width: number, + height: number, + } + type ModuleLoader = () => any; interface ModuleEntry { diff --git a/vsts-arm-test-steps.yml b/vsts-arm-test-steps.yml deleted file mode 100644 index 5985e4d2637e4..0000000000000 --- a/vsts-arm-test-steps.yml +++ /dev/null @@ -1,110 +0,0 @@ -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 - 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.bin --dest=$CROSS_ARCH_SNAPSHOTS - displayName: 'Download cross arch snapshot files' - env: - CIRCLE_TOKEN: $(CIRCLECI_TOKEN) - -- bash: | - export NATIVE_UNITTESTS_DEST=$PWD/src/out/Default - cd src/electron - node script/download-circleci-artifacts.js --buildNum=$CIRCLE_BUILD_NUM --name=shell_browser_ui_unittests --dest=$NATIVE_UNITTESTS_DEST - chmod +x $NATIVE_UNITTESTS_DEST/shell_browser_ui_unittests - displayName: 'Download native unittest executables' - env: - CIRCLE_TOKEN: $(CIRCLECI_TOKEN) - -- bash: | - sh -e /etc/init.d/xvfb start - displayName: Setup for headless testing - env: - DISPLAY: ":99.0" - -- bash: | - # Next line needed to avoid crash on arm32 - sudo gdk-pixbuf-query-loaders --update-cache - cd src - export ELECTRON_OUT_DIR=Default - (cd electron && node script/yarn test -- --enable-logging) - displayName: 'Run Electron tests' - timeoutInMinutes: 20 - env: - ELECTRON_DISABLE_SECURITY_WARNINGS: 1 - IGNORE_YARN_INSTALL_ERROR: 1 - ELECTRON_TEST_RESULTS_DIR: junit - CI: 1 - -- 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 - -- 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 - -- task: PublishTestResults@2 - displayName: 'Publish Test Results' - inputs: - testResultsFiles: '*.xml' - - searchFolder: '$(System.DefaultWorkingDirectory)/src/junit/' - - condition: succeededOrFailed() - -- task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 - displayName: 'Clean Agent Directories' - - condition: always() diff --git a/vsts-arm32v7.yml b/vsts-arm32v7.yml deleted file mode 100644 index feeb920ba8f39..0000000000000 --- a/vsts-arm32v7.yml +++ /dev/null @@ -1,13 +0,0 @@ -resources: - containers: - - container: arm32v7-test-container - image: ghcr.io/electron/build:arm32v7-27db4a3e3512bfd2e47f58cea69922da0835f1d9 - options: --shm-size 128m - -jobs: -- job: Test_Arm32v7 - container: arm32v7-test-container - displayName: Test Arm on Arm32v7 hardware - timeoutInMinutes: 30 - steps: - - template: vsts-arm-test-steps.yml diff --git a/vsts-arm64v8.yml b/vsts-arm64v8.yml deleted file mode 100644 index e64708663b393..0000000000000 --- a/vsts-arm64v8.yml +++ /dev/null @@ -1,13 +0,0 @@ -resources: - containers: - - container: arm64v8-test-container - image: ghcr.io/electron/build:arm64v8-27db4a3e3512bfd2e47f58cea69922da0835f1d9 - options: --shm-size 128m - -jobs: -- job: Test_Arm64 - container: arm64v8-test-container - displayName: Test Arm64 on Arm64 hardware - timeoutInMinutes: 30 - steps: - - template: vsts-arm-test-steps.yml diff --git a/yarn.lock b/yarn.lock index 1e4fb68649e10..88ae9c5a8583d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -106,10 +106,10 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@electron/docs-parser@^0.12.3": - version "0.12.3" - resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.12.3.tgz#a984c5ebc60348683b2acdbb0ebb73414b6763fd" - integrity sha512-e7OKn/NNAHMZ4Pw1702MHd2VE3Z5NKdXIIDxg9nWsDBUuSCuOKRCb4i0Ev8Eev0V0nKLaH+NMz6yzovpx0PrHg== +"@electron/docs-parser@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.12.4.tgz#cca403c8c2200181339c3115cdd25f3fbfc7dea3" + integrity sha512-vdkjcvkI7zTd2v1A8qsl5+HY+9AQCrW5Eh60I9rhPtUPoxo2V1pQwogTW6kzc3XZ54crTa7R3KxwkZpSbcGCug== dependencies: "@types/markdown-it" "^10.0.0" chai "^4.2.0" @@ -286,6 +286,11 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -293,6 +298,13 @@ dependencies: defer-to-connect "^1.0.1" +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -320,6 +332,16 @@ dependencies: "@types/node" "*" +"@types/cacheable-request@^6.0.1": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9" + integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "*" + "@types/node" "*" + "@types/responselike" "*" + "@types/chai-as-promised@*": version "7.1.1" resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.1.tgz#004c27a4ac640e9590e25d8b0980cb0a6609bfd8" @@ -423,6 +445,11 @@ resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.4.tgz#8c3496bd1b50cc04aeefd691140aa571d4dbfa34" integrity sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww== +"@types/http-cache-semantics@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" + integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== + "@types/is-empty@^1.0.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@types/is-empty/-/is-empty-1.2.0.tgz#16bc578060c9b0b6953339eea906c255a375bf86" @@ -433,6 +460,11 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.2.tgz#4117a7a378593a218e9d6f0ef44ce6d5d9edf7fa" integrity sha512-KbeHS/Y4R+k+5sWXEYzAZKuB1yQlZtEghuhRxrVRLaqhtoG5+26JwQsa4HyS3AWX8v1Uwukma5HheduUDskasA== +"@types/json-buffer@~3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/json-buffer/-/json-buffer-3.0.0.tgz#85c1ff0f0948fc159810d4b5be35bf8c20875f64" + integrity sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ== + "@types/json-schema@^7.0.3": version "7.0.3" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" @@ -455,6 +487,13 @@ dependencies: "@types/node" "*" +"@types/keyv@*": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + "@types/klaw@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/klaw/-/klaw-3.0.1.tgz#29f90021c0234976aa4eb97efced9cb6db9fa8b3" @@ -577,6 +616,13 @@ resolved "https://registry.yarnpkg.com/@types/repeat-string/-/repeat-string-1.6.1.tgz#8bb5686e662ce1d962271b0b043623bf51404cdc" integrity sha512-vdna8kjLGljgtPnYN6MBD2UwX62QE0EFLj9QlLXvg6dEu66NksXB900BNguBCMZZY2D9SSqncUskM23vT3uvWQ== +"@types/responselike@*", "@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== + dependencies: + "@types/node" "*" + "@types/semver@^7.3.3": version "7.3.3" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.3.tgz#3ad6ed949e7487e7bda6f886b4a2434a2c3d7b1a" @@ -983,40 +1029,10 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== -ajv@^6.1.0: - version "6.10.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.1.tgz#ebf8d3af22552df9dd049bfbe50cc2390e823593" - integrity sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^6.10.0: - version "6.12.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706" - integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^6.10.2: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^6.12.2: - version "6.12.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" - integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -1450,7 +1466,12 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= -buffer-from@^1.0.0, buffer-from@^1.1.0: +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-from@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -1522,6 +1543,11 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -1535,6 +1561,19 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -1550,11 +1589,6 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -capture-stack-trace@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" - integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== - chai@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" @@ -1836,9 +1870,9 @@ combined-stream@^1.0.8: delayed-stream "~1.0.0" commander@^2.20.0, commander@^2.9.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== commander@^4.1.0: version "4.1.1" @@ -1865,6 +1899,14 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +compress-brotli@^1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/compress-brotli/-/compress-brotli-1.3.8.tgz#0c0a60c97a989145314ec381e84e26682e7b38db" + integrity sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ== + dependencies: + "@types/json-buffer" "~3.0.0" + json-buffer "~3.0.1" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1975,13 +2017,6 @@ create-ecdh@^4.0.0: bn.js "^4.1.0" elliptic "^6.0.0" -create-error-class@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= - dependencies: - capture-stack-trace "^1.0.0" - create-hash@^1.1.0, create-hash@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -2102,6 +2137,13 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -2136,6 +2178,11 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -2971,15 +3018,10 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - fast-deep-equal@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" - integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.1.1: version "3.2.4" @@ -2994,9 +3036,9 @@ fast-glob@^3.1.1: picomatch "^2.2.1" fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" @@ -3305,11 +3347,6 @@ get-stdin@~8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -3317,14 +3354,7 @@ get-stream@^4.1.0: dependencies: pump "^3.0.0" -get-stream@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" - integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: +get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== @@ -3437,22 +3467,22 @@ globby@^11.0.0, globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" -got@^6.3.0: - version "6.7.1" - resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" - integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= - dependencies: - create-error-class "^3.0.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-redirect "^1.0.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - unzip-response "^2.0.1" - url-parse-lax "^1.0.0" +got@^11.8.5: + version "11.8.5" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" + integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" got@^9.6.0: version "9.6.0" @@ -3623,6 +3653,14 @@ http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" @@ -3633,10 +3671,10 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -husky@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/husky/-/husky-6.0.0.tgz#810f11869adf51604c32ea577edbc377d7f9319e" - integrity sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ== +husky@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9" + integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw== iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" @@ -3992,11 +4030,6 @@ is-plain-object@^4.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-4.1.1.tgz#1a14d6452cbd50790edc7fdaa0aed5a40a35ebb5" integrity sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA== -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= - is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -4016,16 +4049,6 @@ is-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= -is-retry-allowed@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== - -is-stream@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - is-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" @@ -4113,6 +4136,11 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-buffer@3.0.1, json-buffer@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -4218,6 +4246,14 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.0.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.3.1.tgz#7970672f137d987945821b1a07b524ce5a4edd27" + integrity sha512-nwP7AQOxFzELXsNq3zCx/oh81zu4DHWwCE6W9RaeHb7OHO0JpmKS8n801ovVQC7PTsZDWtPA5j1QY+/WWtARYg== + dependencies: + compress-brotli "^1.3.8" + json-buffer "3.0.1" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -4985,6 +5021,11 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -5002,15 +5043,10 @@ minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.0.0, minimist@^1.2.5, minimist@~1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minimist@^1.2.0, minimist@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.0.0, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.0, minimist@~1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" @@ -5090,10 +5126,9 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== +nan@^2.12.1, nan@nodejs/nan#16fa32231e2ccd89d2804b3f765319128b20c4ac: + version "2.15.0" + resolved "https://codeload.github.com/nodejs/nan/tar.gz/16fa32231e2ccd89d2804b3f765319128b20c4ac" nanomatch@^1.2.9: version "1.2.13" @@ -5228,6 +5263,11 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-bundled@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" @@ -5461,6 +5501,11 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -5657,9 +5702,9 @@ path-type@^4.0.0: integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== pathval@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== pbkdf2@^3.0.3: version "3.0.17" @@ -5759,11 +5804,6 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" @@ -5897,6 +5937,11 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + ramda@^0.27.0: version "0.27.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.0.tgz#915dc29865c0800bf3f69b8fd6c279898b59de43" @@ -6600,6 +6645,11 @@ requireindex@~1.1.0: resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162" integrity sha1-5UBLgVV+91225JxacgBIk/4D4WI= +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -6660,6 +6710,13 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +responselike@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723" + integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw== + dependencies: + lowercase-keys "^2.0.0" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -7019,18 +7076,10 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.6: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@~0.5.12: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== +source-map-support@^0.5.6, source-map-support@~0.5.12: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -7447,9 +7496,9 @@ terser-webpack-plugin@^1.4.3: worker-farm "^1.7.0" terser@^4.1.2: - version "4.6.7" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.7.tgz#478d7f9394ec1907f0e488c5f6a6a9a2bad55e72" - integrity sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g== + version "4.8.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f" + integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -7473,11 +7522,6 @@ through@^2.3.6, through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -timed-out@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - timers-browserify@1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" @@ -7887,20 +7931,15 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -unzip-response@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" - integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= - upath@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" @@ -7909,13 +7948,6 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"