Compare commits

..

23 Commits

Author SHA1 Message Date
Keeley Hammond
ae1bf816f7 feat,refactor: rework getHistory, return Notification objects 2026-03-17 12:01:46 -07:00
Keeley Hammond
771a502c76 feat: add groupId support for remove (removeGroup) 2026-03-16 17:05:35 -07:00
Keeley Hammond
9e57b2bc04 feat: add static methods getHistory, remove, removeAll to Notification (macOS)
Add static methods for managing delivered notifications via the
UNUserNotificationCenter API:
- getHistory() returns all delivered notifications still in Notification Center
- remove(id) removes one or more notifications by identifier
- removeAll() removes all delivered notifications

These methods build on the custom id support to enable full notification
lifecycle management from the main process.
2026-03-16 16:37:49 -07:00
Keeley Hammond
958278c273 feat: add id and groupId options to macOS notifications (#50097)
* feat: add custom `id` property to Notification API (macOS only)

* feat: add `groupId` property to Notification API (macOS). Notifications with the same groupId will be visually grouped together in Notification Center

* fix: move validation to construction time, add empty string check, remove setters

* docs: clarify id/group id properties, make instance properties read-only

* test: update tests to reflect read-only properties
2026-03-16 21:24:29 +01:00
Shelley Vohr
b7e9bbed0c fix: restore sdk_inputs cross-toolchain deps for macOS (#50297)
fix: restore sdk_inputs cross-toolchain deps for macOS

The change in CL:7652975 restricted sdk_inputs public_deps
to iOS only, to avoid setting up Xcode symlinks for the Linux
toolchain when cross-building chrome/linux on Mac. However, this
also broke cross-arch macOS builds (e.g. ffmpeg with target_cpu=x64)
where the mig target in the clang_arm64 toolchain depends on
sdk_inputs from the default clang_x64 toolchain.

Add target_os == \"mac\" alongside the existing iOS check to preserve
the original intent while restoring the cross-toolchain dependency
for macOS builds.
2026-03-16 20:12:38 +00:00
Justin Mayfield
eec3fe967e fix: user resizable transparent windows on win32 (#49428)
test: revert win32 frameless and transparent resizable expectations
2026-03-16 15:31:07 -04:00
David Sanders
01714757e3 ci: ignore test timeouts in audit (#50259) 2026-03-16 14:33:37 -04:00
Shelley Vohr
ffad67222d test: fix esm issue in node-spec-runner (#50289)
Chromium added a top-level package.json in CL:7485999 that sets
the type to module and breaks commonjs tests run via
node-spec-runner.js. This commit temporarily changes the type to
commonjs while running the tests, then changes it back to module when done.
2026-03-16 12:55:03 -04:00
ZHUO Xu
078586fab0 docs: update the example of webContents.setWindowOpenHandler to cla… (#49379)
docs: reorganize the comments for clarifying `webContents.setWindowOpenHandler` example
2026-03-16 12:12:52 -04:00
Noah Gregory
a561dd97a6 fix: add ASAR support to additional copy methods (#50226)
* fix: add ASAR support for additional copy methods

* test: add tests for ASAR support for additional copy messages
2026-03-16 14:36:48 +01:00
Shelley Vohr
b9cbcde600 build: remove redundant bits of ncrypto node patch (#50252)
build: remove redundant ncrypto node patch
2026-03-16 12:13:47 +01:00
electron-roller[bot]
36b0709942 chore: bump chromium to 148.0.7733.0 (main) (#50197)
* chore: bump chromium in DEPS to 147.0.7727.2

* chore: bump chromium in DEPS to 148.0.7728.0

* chore: bump chromium in DEPS to 148.0.7729.0

* chore: bump chromium in DEPS to 148.0.7730.0

* chore: bump chromium in DEPS to 148.0.7732.0

* chore: update WrappablePointerTag patch
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7641766

* chore: update custom protocol patch for removed code
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7653454

* chore: update patches

* fix: cleanup removed CHILD_PLUGIN code
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7653455

* fix: move from int to ChildProcessId
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7621912

* fix: update extensions CreateTab signature
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7644389

* fix: draggable hit region test interface update for mac windows
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7655245

* chore: bump chromium in DEPS to 148.0.7733.0

* feat: restore macos child plugin process
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7653455

* fixup! chore: merge main

* chore: update patches

* fix: replace clipboard IsFormatAvailable with async GetAllAvailableFormats
Refs https://chromium-review.googlesource.com/c/chromium/src/+/7631097

Async API pending RFC https://github.com/electron/rfcs/pull/19

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Samuel Maddock <samuelmaddock@electronjs.org>
2026-03-16 10:55:06 +01:00
Shelley Vohr
cf84efbbb9 fix: prefer browser runtime over node in DevTools HostRuntime detection (#50241)
Upstream DevTools' HostRuntime checks `IS_NODE` before `IS_BROWSER` when
selecting the platform runtime. In Electron, `process` is available in
renderer processes, so `IS_NODE` evaluates to `true` in the DevTools
context. This causes DevTools to dynamically import the Node.js platform
runtime, which uses `node:worker_threads`. DevTools Web Workers running
under the `devtools://` protocol cannot load Node.js built-in modules,
so the import fails and breaks features like the formatter worker.

Fix by swapping the check order to prefer `IS_BROWSER` when both are
true. This is safe because in pure Node.js environments (the only case
where the node runtime is needed), `window` and `self` are both
undefined, so `IS_BROWSER` is always `false` regardless of check order.
2026-03-16 10:29:35 +01:00
David Sanders
58cd1aba10 ci: fix unsupported major in release board automation (#50260) 2026-03-14 15:34:50 -07:00
dependabot[bot]
26a3a8679a build(deps-dev): bump folder-hash from 4.1.1 to 4.1.2 (#50258)
Bumps [folder-hash](https://github.com/marc136/node-folder-hash) from 4.1.1 to 4.1.2.
- [Release notes](https://github.com/marc136/node-folder-hash/releases)
- [Changelog](https://github.com/marc136/node-folder-hash/blob/v5/CHANGELOG.md)
- [Commits](https://github.com/marc136/node-folder-hash/compare/v4.1.1...v4.1.2)

---
updated-dependencies:
- dependency-name: folder-hash
  dependency-version: 4.1.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-13 22:46:05 -07:00
John Kleinschmidt
a1e4c260ea ci: create PR triage project automation (#50248)
* ci: create PR triage project automation

* chore: use ubuntu-slim

---------

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-03-14 02:35:29 +00:00
Samuel Attard
f4a50a8fde build: skip archiving patch conflict fix artifact (#50251)
The update-patches artifact is a single .patch file, so zipping it
is unnecessary overhead. With archive: false, gh run download fetches
the raw file directly without requiring a decompression step.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-13 21:49:05 +00:00
Erick Zhao
b35ed6346e docs: point pull requests guide to build tools (#50198)
* docs: point pull requests guide to build tools

* update for `--fork`
2026-03-13 16:01:41 -04:00
Samuel Attard
816e5964fb build: add patch conflict resolution workflow with CI artifacts (#50235)
ci: upload patch conflict fix as artifact in apply-patches

When patch-up.js cannot auto-push the 3-way-merged patch diff (e.g. on
fork PRs), the checkout action already writes patches/update-patches.patch
and tells the user to check CI artifacts — but nothing was uploading it.

This adds the missing upload-artifact step to the apply-patches job so
the resolved diff is available for download, and documents in CLAUDE.md
that pulling this artifact and applying it with `git am` is the fast
path for fixing patch conflicts on PR branches without a full local sync.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-13 01:46:29 +00:00
Michaela Laurencin
3295d0d4b0 build(deps-dev): replace timers-browserify (#50203)
* build(deps-dev): replace timers-browserify

Co-Authored-By: Claude <noreply@anthropic.com>
Generated-By: GitHub Copilot

* update shim from js to ts

Co-Authored-By: Claude <noreply@anthropic.com>
Generated-By: GitHub Copilot

* remove timers-shim.js

* remove refs from package json and yarn lock

* update process in yarn lock

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-12 21:26:34 -04:00
John Kleinschmidt
3e72e2e8dd ci: update actions/cache to 5.0.3 (#50222)
chore: update actions/cache to 5.0.3

Needed due to https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
2026-03-12 20:45:01 -04:00
Erick Zhao
313e501454 feat: add ELECTRON_INSTALL_ env vars (#49981)
* feat: add `ELECTRON_INSTALL_` env vars

* add tip for available arches

* clarify!

* use `arm` instead of `armv7l`
2026-03-12 15:09:48 +01:00
Erick Zhao
1f6dbb0917 docs: add API history (G-I) (#50194) 2026-03-12 14:43:39 +01:00
94 changed files with 1661 additions and 372 deletions

View File

@@ -43,7 +43,7 @@ runs:
curl --unix-socket /var/run/sas/sas.sock --fail "http://foo/$CACHE_FILE?platform=${{ inputs.target-platform }}&getAccountName=true" > sas-token
- name: Save SAS Key
if: ${{ inputs.generate-sas-token == 'true' }}
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: sas-token
key: sas-key-${{ inputs.target-platform }}-${{ github.run_number }}-${{ github.run_attempt }}

View File

@@ -7,7 +7,7 @@ runs:
shell: bash
id: yarn-cache-dir-path
run: echo "dir=$(node src/electron/script/yarn.js config get cacheFolder)" >> $GITHUB_OUTPUT
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}

View File

@@ -71,3 +71,11 @@ jobs:
uses: ./src/electron/.github/actions/checkout
with:
target-platform: linux
- name: Upload Patch Conflict Fix
if: ${{ failure() }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: update-patches
path: patches/update-patches.patch
if-no-files-found: ignore
archive: false

View File

@@ -86,6 +86,7 @@ jobs:
!message.startsWith("Response status code does not indicate success") &&
!message.startsWith("The hosted runner lost communication with the server") &&
!message.startsWith("Dependabot encountered an error performing the update") &&
!message.startsWith("The action 'Run Electron Tests' has timed out") &&
!/Unable to make request/.test(message) &&
!/The requested URL returned error/.test(message),
)

View File

@@ -31,8 +31,8 @@ jobs:
else
echo "Not a release branch: $BRANCH_NAME"
fi
- name: Determine Unsupported Major Version
id: determine-unsupported-major
- name: Determine Next Unsupported Major Version
id: determine-next-unsupported-major
if: ${{ steps.check-major-version.outputs.MAJOR }}
env:
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
@@ -50,26 +50,27 @@ jobs:
# Find the oldest version where eolDate >= stableDate of the new major
# This gives us the oldest supported version when the new major goes stable
UNSUPPORTED_MAJOR=$(echo "$SCHEDULE" | jq -r --arg stableDate "$STABLE_DATE" '
NEXT_UNSUPPORTED_MAJOR=$(echo "$SCHEDULE" | jq -r --arg stableDate "$STABLE_DATE" '
[.[] | select(.eolDate != null and .eolDate >= $stableDate)] | sort_by(.version | split(".")[0] | tonumber) | first | .version | split(".")[0]
')
if [[ -z "$UNSUPPORTED_MAJOR" || "$UNSUPPORTED_MAJOR" == "null" ]]; then
if [[ -z "$NEXT_UNSUPPORTED_MAJOR" || "$NEXT_UNSUPPORTED_MAJOR" == "null" ]]; then
echo "Could not determine oldest supported version"
exit 1
fi
echo "SCHEDULE=$SCHEDULE" >> "$GITHUB_OUTPUT"
echo "UNSUPPORTED_MAJOR=$UNSUPPORTED_MAJOR" >> "$GITHUB_OUTPUT"
echo "NEXT_UNSUPPORTED_MAJOR=$NEXT_UNSUPPORTED_MAJOR" >> "$GITHUB_OUTPUT"
- name: New Release Branch Tasks
if: ${{ steps.check-major-version.outputs.MAJOR }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: electron/electron
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
UNSUPPORTED_MAJOR: ${{ steps.determine-unsupported-major.outputs.UNSUPPORTED_MAJOR }}
NEXT_UNSUPPORTED_MAJOR: ${{ steps.determine-next-unsupported-major.outputs.NEXT_UNSUPPORTED_MAJOR }}
run: |
PREVIOUS_MAJOR=$((MAJOR - 1))
UNSUPPORTED_MAJOR=$((NEXT_UNSUPPORTED_MAJOR - 1))
# Create new labels
gh label create $MAJOR-x-y --color 8d9ee8 || true
@@ -108,8 +109,8 @@ jobs:
id: generate-project-metadata
env:
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
UNSUPPORTED_MAJOR: ${{ steps.determine-unsupported-major.outputs.UNSUPPORTED_MAJOR }}
SCHEDULE: ${{ steps.determine-unsupported-major.outputs.SCHEDULE }}
NEXT_UNSUPPORTED_MAJOR: ${{ steps.determine-next-unsupported-major.outputs.NEXT_UNSUPPORTED_MAJOR }}
SCHEDULE: ${{ steps.determine-next-unsupported-major.outputs.SCHEDULE }}
with:
script: |
const schedule = JSON.parse(process.env.SCHEDULE)
@@ -144,7 +145,7 @@ jobs:
major,
"next-major": nextMajor,
"prev-major": prevMajor,
"ending-support-major": parseInt(process.env.UNSUPPORTED_MAJOR),
"ending-support-major": parseInt(process.env.NEXT_UNSUPPORTED_MAJOR),
"beta-date": betaDate,
"beta-prep-week": betaPrepWeek.toISOString().split('T')[0],
"beta-prep-week-end": betaPrepWeekEnd.toISOString().split('T')[0],

View File

@@ -0,0 +1,37 @@
name: PR Triage Automation
on:
pull_request_target:
types: [synchronize, review_requested]
issue_comment:
types: [created]
permissions: {}
jobs:
set-needs-review:
name: Set status to Needs Review
if: >-
(github.event_name == 'pull_request_target' && github.event.action == 'synchronize')
|| (github.event_name == 'pull_request_target' && github.event.action == 'review_requested')
|| (github.event_name == 'issue_comment'
&& github.event.issue.pull_request
&& github.event.comment.user.login == github.event.issue.user.login)
runs-on: ubuntu-slim
permissions:
contents: read
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Set status to Needs Review
uses: dsanders11/project-actions/edit-item@2134fe7cc71c58b7ae259c82a8e63c6058255678 # v1.7.0
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 118
field: Status
field-value: 🌀 Needs Review
fail-if-item-not-found: false

View File

@@ -127,6 +127,22 @@ patches/{target}/*.patch → [e sync --3] → target repo commits
2. Create a git commit
3. Run `e patches <target>` to export
**Fixing patch conflicts on an existing PR:**
If asked to fix a patch conflict on a branch that already has an open PR, check the PR's failed **Apply Patches** CI run for an `update-patches` artifact before running `e sync` locally. CI has already performed the 3-way merge and exported the resolved patch diff — applying it is much faster than a full local sync.
```bash
# Find the failed Apply Patches run for the PR and download the artifact
gh run list --repo electron/electron --branch <pr-branch> --workflow "Apply Patches" --limit 1
gh run download <run-id> --repo electron/electron --name update-patches
# Apply the CI-generated fix, then push
git am update-patches.patch
git push
```
If no artifact exists (e.g. the 3-way merge itself failed), fall back to `e sync --3` and resolve manually.
## Testing
**Test location:** `spec/` directory
@@ -192,6 +208,7 @@ gh label list --repo electron/electron --search target/ --json name,color --jq '
```bash
npm run lint # Run all linters
npm run lint:clang-format # C++ formatting
npm run lint:api-history # Validate API history YAML blocks in docs
```
## Key Files

2
DEPS
View File

@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'147.0.7727.0',
'148.0.7733.0',
'node_version':
'v24.14.0',
'nan_version':

View File

@@ -122,8 +122,8 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in
'electron/renderer$': electronAPIFile,
'electron/common$': electronAPIFile,
'electron/utility$': electronAPIFile,
// Force timers to resolve to our dependency that doesn't use window.postMessage
timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
// Force timers to resolve to our own shim that doesn't use window.postMessage
timers: path.resolve(electronRoot, 'lib', 'common', 'timers-shim.ts')
},
extensions: ['.ts', '.js'],
fallback: {

58
docs/CLAUDE.md Normal file
View File

@@ -0,0 +1,58 @@
# Electron Documentation Guide
## API History Migration
Guide: `docs/development/api-history-migration-guide.md`
Style rules: `docs/development/style-guide.md` (see "API History" section)
Schema: `docs/api-history.schema.json`
Lint: `npm run lint:api-history`
### Format
Place YAML history block directly after the Markdown header, before parameters:
````md
### `module.method(args)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/XXXXX
```
-->
* `arg` type - Description.
````
### Finding when an API was added
- `git log --all --reverse --oneline -S "methodName" -- docs/api/file.md` — find first commit adding a method name
- `git log --reverse -L :FunctionName:path/to/source.cc` — trace C++ implementation history
- `git log --grep="keyword" --oneline` — find merge commits referencing PRs
- `gh pr view <number> --repo electron/electron --json baseRefName` — verify PR targets main (not a backport)
- Always use the main-branch PR URL in history blocks, not backport PRs
### Cross-referencing breaking changes
- Search `docs/breaking-changes.md` for the API name to find deprecations/removals
- Use `git blame` on the breaking-changes entry to find the associated PR
- Add `breaking-changes-header` field using the heading ID from breaking-changes.md
### Placement rules
- Only add blocks to actual API entries (methods, events, properties with backtick signatures)
- Do NOT add blocks to section headers like `## Methods`, `### Instance Methods`, `## Events`
- Module-level blocks go after the `# moduleName` heading, before the module description quote
- For changes affecting multiple APIs, add a block under each affected top-level heading (see style guide "Change affecting multiple APIs")
### Key details
- `added` and `deprecated` arrays have `maxItems: 1`; `changes` can have multiple items
- `changes` entries require a `description` field; `added`/`deprecated` do not
- Wrap descriptions in double quotes to avoid YAML parsing issues with special characters
- Early Electron APIs (pre-2015) use merge-commit PRs (e.g., `Merge pull request #534`)
- Very early APIs (2013-2014, e.g., `ipcMain.on`, `ipcRenderer.send`) predate GitHub PRs — skip history blocks for these
- When multiple APIs were added in the same PR, they all reference the same PR URL
- Promisification PRs (e.g., #17355) count as `changes` entries with a description
- These PRs are breaking changes and should have their notes as "This method now returns a Promise instead of using a callback function."
- APIs that were deprecated and then removed from docs don't need history blocks (the removal is in `breaking-changes.md`)

View File

@@ -55,6 +55,13 @@ The `globalShortcut` module has the following methods:
### `globalShortcut.register(accelerator, callback)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/534
```
-->
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
* `callback` Function
@@ -77,6 +84,13 @@ the app has been authorized as a [trusted accessibility client](https://develope
### `globalShortcut.registerAll(accelerators, callback)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/15542
```
-->
* `accelerators` string[] - An array of [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcuts.
* `callback` Function
@@ -96,6 +110,13 @@ the app has been authorized as a [trusted accessibility client](https://develope
### `globalShortcut.isRegistered(accelerator)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/534
```
-->
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
Returns `boolean` - Whether this application has registered `accelerator`.
@@ -106,10 +127,24 @@ don't want applications to fight for global shortcuts.
### `globalShortcut.unregister(accelerator)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/534
```
-->
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
Unregisters the global shortcut of `accelerator`.
### `globalShortcut.unregisterAll()`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/534
```
-->
Unregisters all of the global shortcuts.

View File

@@ -35,6 +35,13 @@ webContentsView.webContents.loadURL('https://electronjs.org')
## Class: ImageView extends `View`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/46760
```
-->
> A View that displays an image.
Process: [Main](../glossary.md#main-process)
@@ -49,6 +56,13 @@ Process: [Main](../glossary.md#main-process)
### `new ImageView()` _Experimental_
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/46760
```
-->
Creates an ImageView.
### Instance Methods
@@ -58,6 +72,13 @@ addition to those inherited from [View](view.md):
#### `image.setImage(image)` _Experimental_
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/46760
```
-->
* `image` NativeImage
Sets the image for this `ImageView`. Note that only image formats supported by

View File

@@ -1,5 +1,12 @@
# inAppPurchase
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/11292
```
-->
> In-app purchases on Mac App Store.
Process: [Main](../glossary.md#main-process)
@@ -10,6 +17,13 @@ The `inAppPurchase` module emits the following events:
### Event: 'transactions-updated'
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/11292
```
-->
Returns:
* `event` Event
@@ -23,6 +37,19 @@ The `inAppPurchase` module has the following methods:
### `inAppPurchase.purchaseProduct(productID[, opts])`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/11292
changes:
- pr-url: https://github.com/electron/electron/pull/17355
description: "This method now returns a Promise instead of using a callback function."
breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis
- pr-url: https://github.com/electron/electron/pull/35902
description: "Added `username` option to `opts` parameter."
```
-->
* `productID` string
* `opts` Integer | Object (optional) - If specified as an integer, defines the quantity.
* `quantity` Integer (optional) - The number of items the user wants to purchase.
@@ -34,6 +61,17 @@ You should listen for the `transactions-updated` event as soon as possible and c
### `inAppPurchase.getProducts(productIDs)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/12464
changes:
- pr-url: https://github.com/electron/electron/pull/17355
description: "This method now returns a Promise instead of using a callback function."
breaking-changes-header: api-changed-callback-based-versions-of-promisified-apis
```
-->
* `productIDs` string[] - The identifiers of the products to get.
Returns `Promise<Product[]>` - Resolves with an array of [`Product`](structures/product.md) objects.
@@ -42,24 +80,59 @@ Retrieves the product descriptions.
### `inAppPurchase.canMakePayments()`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/11292
```
-->
Returns `boolean` - whether a user can make a payment.
### `inAppPurchase.restoreCompletedTransactions()`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/21461
```
-->
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](https://developer.apple.com/documentation/storekit/skpaymentqueue?language=objc) delivers a new transaction for each previously completed transaction that can be restored. Each transaction includes a copy of the original transaction.
### `inAppPurchase.getReceiptURL()`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/11292
```
-->
Returns `string` - the path to the receipt.
### `inAppPurchase.finishAllTransactions()`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/12464
```
-->
Completes all pending transactions.
### `inAppPurchase.finishTransactionByDate(date)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/12464
```
-->
* `date` string - The ISO formatted date of the transaction to finish.
Completes the pending transactions corresponding to the date.

View File

@@ -46,6 +46,13 @@ Listens to `channel`, when a new message arrives `listener` would be called with
### `ipcMain.off(channel, listener)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/44651
```
-->
* `channel` string
* `listener` Function
* `event` [IpcMainEvent][ipc-main-event]
@@ -89,6 +96,13 @@ Removes all listeners from the specified `channel`. Removes all listeners from a
### `ipcMain.handle(channel, listener)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/18449
```
-->
* `channel` string
* `listener` Function\<Promise\<any\> | any\>
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
@@ -126,6 +140,13 @@ provided to the renderer process. Please refer to
### `ipcMain.handleOnce(channel, listener)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/18449
```
-->
* `channel` string
* `listener` Function\<Promise\<any\> | any\>
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
@@ -136,6 +157,13 @@ Handles a single `invoke`able IPC message, then removes the listener. See
### `ipcMain.removeHandler(channel)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/18449
```
-->
* `channel` string
Removes any handler for `channel`, if present.

View File

@@ -59,6 +59,13 @@ for more info.
### `ipcRenderer.off(channel, listener)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/39816
```
-->
* `channel` string
* `listener` Function
* `event` [IpcRendererEvent][ipc-renderer-event]
@@ -79,6 +86,13 @@ only the next time a message is sent to `channel`, after which it is removed.
### `ipcRenderer.addListener(channel, listener)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/39816
```
-->
* `channel` string
* `listener` Function
* `event` [IpcRendererEvent][ipc-renderer-event]
@@ -129,6 +143,13 @@ If you want to receive a single response from the main process, like the result
### `ipcRenderer.invoke(channel, ...args)`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/18449
```
-->
* `channel` string
* `...args` any[]
@@ -209,6 +230,13 @@ and replies by setting `event.returnValue`.
### `ipcRenderer.postMessage(channel, message, [transfer])`
<!--
```YAML history
added:
- pr-url: https://github.com/electron/electron/pull/22404
```
-->
* `channel` string
* `message` any
* `transfer` MessagePort[] (optional)

View File

@@ -76,9 +76,87 @@ app.whenReady().then(() => {
})
```
#### `Notification.getHistory()` _macOS_
Returns `Promise<Notification[]>` - Resolves with an array of `Notification` objects representing all delivered notifications still present in Notification Center.
Each returned `Notification` is a live object connected to the corresponding delivered notification. Interaction events (`click`, `reply`, `action`, `close`) will fire on these objects when the user interacts with the notification in Notification Center. This is useful after an app restart to re-attach event handlers to notifications from a previous session.
The returned notifications have their `id`, `groupId`, `title`, `subtitle`, and `body` properties populated from what macOS provides. Other properties (e.g., `actions`, `silent`, `icon`) are not available from delivered notifications and will have default values.
> [!NOTE]
> Like all macOS notification APIs, this method requires the application to be
> code-signed. In unsigned development builds, notifications are not delivered
> to Notification Center and this method will resolve with an empty array.
> [!NOTE]
> Unlike notifications created with `new Notification()`, notifications returned
> by `getHistory()` will remain visible in Notification Center when the object
> is garbage collected.
```js
const { Notification, app } = require('electron')
app.whenReady().then(async () => {
// Restore notifications from a previous session
const notifications = await Notification.getHistory()
for (const n of notifications) {
console.log(`Found delivered notification: ${n.id} - ${n.title}`)
n.on('click', () => {
console.log(`User clicked: ${n.id}`)
})
n.on('reply', (event) => {
console.log(`User replied to ${n.id}: ${event.reply}`)
})
}
// Keep references so events continue to fire
})
```
#### `Notification.remove(id)` _macOS_
* `id` (string | string[]) - The notification identifier(s) to remove. These correspond to the `id` values set in the [`Notification` constructor](#new-notificationoptions).
Removes one or more delivered notifications from Notification Center by their identifier(s).
```js
const { Notification } = require('electron')
// Remove a single notification
Notification.remove('my-notification-id')
// Remove multiple notifications
Notification.remove(['msg-1', 'msg-2', 'msg-3'])
```
#### `Notification.removeAll()` _macOS_
Removes all of the app's delivered notifications from Notification Center.
```js
const { Notification } = require('electron')
Notification.removeAll()
```
#### `Notification.removeGroup(groupId)` _macOS_
* `groupId` string - The group identifier of the notifications to remove. This corresponds to the `groupId` value set in the [`Notification` constructor](#new-notificationoptions).
Removes all delivered notifications with the given `groupId` from Notification Center.
```js
const { Notification } = require('electron')
// Remove all notifications in the 'chat-thread-1' group
Notification.removeGroup('chat-thread-1')
```
### `new Notification([options])`
* `options` Object (optional)
* `id` string (optional) _macOS_ - A unique identifier for the notification, mapping to `UNNotificationRequest`'s [`identifier`](https://developer.apple.com/documentation/usernotifications/unnotificationrequest/identifier) property. Defaults to a random UUID if not provided or if an empty string is passed. Use this identifier with [`Notification.remove()`](#notificationremoveid-macos) to remove specific delivered notifications, or with [`Notification.getHistory()`](#notificationgethistory-macos) to identify them.
* `groupId` string (optional) _macOS_ - A string identifier used to visually group notifications together in Notification Center. Maps to `UNNotificationContent`'s [`threadIdentifier`](https://developer.apple.com/documentation/usernotifications/unnotificationcontent/threadidentifier) property. Use this identifier with [`Notification.removeGroup()`](#notificationremovegroupgroupid-macos) to remove all notifications in a group.
* `title` string (optional) - A title for the notification, which will be displayed at the top of the notification window when it is shown.
* `subtitle` string (optional) _macOS_ - A subtitle for the notification, which will be displayed below the title.
* `body` string (optional) - The body text of the notification, which will be displayed below the title or subtitle.
@@ -88,15 +166,11 @@ app.whenReady().then(() => {
* `timeoutType` string (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'.
* `replyPlaceholder` string (optional) _macOS_ - The placeholder to write in the inline reply input field.
* `sound` string (optional) _macOS_ - The name of the sound file to play when the notification is shown.
* `urgency` string (optional) _Linux_ _Windows_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
* `urgency` string (optional) _Linux_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
* `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation.
* `closeButtonText` string (optional) _macOS_ - A custom title for the close button of an alert. An empty string will cause the default localized text to be used.
* `toastXml` string (optional) _Windows_ - A custom description of the Notification on Windows superseding all properties above. Provides full customization of design and behavior of the notification.
> [!NOTE]
> On Windows, `urgency` type 'critical' sorts the notification higher in Action Center (above default priority notifications), but does not prevent auto-dismissal. To prevent auto-dismissal, you should also set
> `timeoutType` to 'never'.
### Instance Events
Objects created with `new Notification` emit the following events:
@@ -327,6 +401,14 @@ app.whenReady().then(() => {
### Instance Properties
#### `notification.id` _macOS_ _Readonly_
A `string` property representing the unique identifier of the notification. This is set at construction time — either from the `id` option or as a generated UUID if none was provided.
#### `notification.groupId` _macOS_ _Readonly_
A `string` property representing the group identifier of the notification. Notifications with the same `groupId` will be visually grouped together in Notification Center.
#### `notification.title`
A `string` property representing the title of the notification.

View File

@@ -1485,6 +1485,11 @@ mainWindow.webContents.setWindowOpenHandler((details) => {
const browserView = new BrowserView(options)
mainWindow.addBrowserView(browserView)
browserView.setBounds({ x: 0, y: 0, width: 640, height: 480 })
// For `background-tab` disposition (e.g., when middle-clicking or ctrl/cmd-clicking a link),
// `options.webContents` is undefined because its creation can be deferred. So load the URL manually.
if (details.disposition === 'background-tab') {
browserView.webContents.loadURL(details.url)
}
return browserView.webContents
}
}

View File

@@ -59,6 +59,17 @@ npm install electron --save-dev --ignore-scripts
npx install-electron --no
```
If you need to test changes across platforms or architectures, you should now use the
`ELECTRON_INSTALL_ARCH` and `ELECTRON_INSTALL_PLATFORM` environment variables.
```sh
# before: pass npm config flag on install command
npm install --platform=mas electron --save-dev
# after: add env var when you first run the Electron command
npm install electron --save-dev
ELECTRON_INSTALL_PLATFORM=mas npx electron . --no
```
### Removed: `quotas` object from `Session.clearStorageData(options)`
When calling `Session.clearStorageData(options)`, the `options.quotas` object is no longer supported because it has been

View File

@@ -21,24 +21,33 @@
### Step 1: Fork
Fork the project [on GitHub](https://github.com/electron/electron) and clone your fork
locally.
```sh
$ git clone git@github.com:username/electron.git
$ cd electron
$ git remote add upstream https://github.com/electron/electron.git
$ git fetch upstream
```
Fork Electron's [GitHub repository](https://github.com/electron/electron).
### Step 2: Build
Build steps and dependencies differ slightly depending on your operating system.
See these detailed guides on building Electron locally:
We recommend using [`@electron/build-tools`](https://github.com/electron/build-tools) to build
Electron itself.
* [Building on macOS](build-instructions-macos.md)
* [Building on Linux](build-instructions-linux.md)
* [Building on Windows](build-instructions-windows.md)
```sh
# Install build-tools package globally:
npm install -g @electron/build-tools
# Run the init script where you want to clone the project and point it to your fork:
e init --fork my-org/electron --bootstrap testing
```
This will create a new `electron` folder in your working directory and initialize the project.
Once the build completes, navigate to `electron/src/electron`, where your fork is actually cloned.
> [!IMPORTANT]
> Your Electron project has a complex folder structure with nested repositories.
> See the [Build Instructions](./build-instructions-gn.md) docs for detailed Build Tools
> usage instructions (e.g. how to sync dependencies or how to recompile the binary)
> and platform-specific notices.
There, you should have two `remote` URLs in git:
* `origin` will point to `electron/electron`
* `fork` will point to your fork (`my-org/electron`)
Once you've built the project locally, you're ready to start making changes!
@@ -48,7 +57,7 @@ To keep your development environment organized, create local branches to
hold your work. These should be branched directly off of the `main` branch.
```sh
$ git checkout -b my-branch -t upstream/main
git checkout -b my-branch
```
## Making Changes
@@ -60,7 +69,7 @@ changes to either the C/C++ code in the `shell/` folder,
the JavaScript code in the `lib/` folder, the documentation in `docs/api/`
or tests in the `spec/` folder.
Please be sure to run `npm run lint` from time to time on any code changes
Please be sure to run `yarn lint` from time to time on any code changes
to ensure that they follow the project's code style.
See [coding style](coding-style.md) for
@@ -75,8 +84,8 @@ across multiple commits. There is no limit to the number of commits in a
pull request.
```sh
$ git add my/changed/files
$ git commit
git add my/changed/files
git commit
```
Note that multiple commits get squashed when they are landed.
@@ -138,8 +147,8 @@ Once you have committed your changes, it is a good idea to use `git rebase`
(not `git merge`) to synchronize your work with the main repository.
```sh
$ git fetch upstream
$ git rebase upstream/main
git fetch origin
git rebase origin/main
```
This ensures that your working branch has the latest changes from `electron/electron`
@@ -156,7 +165,7 @@ Before submitting your changes in a pull request, always run the full
test suite. To run the tests:
```sh
$ npm run test
yarn test
```
Make sure the linter does not report any issues and that all tests pass.
@@ -165,7 +174,7 @@ Please do not submit patches that fail either check.
If you are updating tests and want to run a single spec to check it:
```sh
$ npm run test -match=menu
yarn test -match=menu
```
The above would only run spec modules matching `menu`, which is useful for
@@ -179,7 +188,7 @@ begin the process of opening a pull request by pushing your working branch
to your fork on GitHub.
```sh
$ git push origin my-branch
git push fork my-branch
```
### Step 9: Opening the Pull Request
@@ -203,9 +212,9 @@ branch, add a new commit with those changes, and push those to your fork.
GitHub will automatically update the pull request.
```sh
$ git add my/changed/files
$ git commit
$ git push origin my-branch
git add my/changed/files
git commit
git push fork my-branch
```
There are a number of more advanced mechanisms for managing commits using
@@ -213,8 +222,8 @@ There are a number of more advanced mechanisms for managing commits using
Feel free to post a comment in the pull request to ping reviewers if you are
awaiting an answer on something. If you encounter words or acronyms that
seem unfamiliar, refer to this
[glossary](https://sites.google.com/a/chromium.org/dev/glossary).
seem unfamiliar, refer to the
[Chromium glossary](https://sites.google.com/a/chromium.org/dev/glossary).
#### Approval and Request Changes Workflow

View File

@@ -51,20 +51,40 @@ any dependencies in your app will not be installed.
## Customization
If you want to change the architecture that is downloaded (e.g., `x64` on an
`arm64` machine), you can use the `--arch` flag with npm install or set the
`npm_config_arch` environment variable:
`arm64` machine), you can set the `ELECTRON_INSTALL_ARCH` environment variable:
```shell
npm install --arch=x64 electron
```sh
# Inside an npm script or with npx
ELECTRON_INSTALL_ARCH=x64 electron .
```
Supported architectures are a subset of Node.js [`process.arch`](https://nodejs.org/api/process.html#processarch)
values, and include:
* `x64` (Intel Mac and 64-bit Windows)
* `ia32` (32-bit Windows)
* `arm64` (Apple silicon, Windows on ARM, ARM64 Linux)
* `arm` (32-bit ARM)
In addition to changing the architecture, you can also specify the platform
(e.g., `win32`, `linux`, etc.) using the `--platform` flag:
```shell
npm install --platform=win32 electron
```sh
# Inside an npm script or with npx
ELECTRON_INSTALL_PLATFORM=mas electron .
```
Supported platforms are Node-like [platform strings](https://nodejs.org/api/process.html#processplatform):
* `darwin`
* `mas` ([Mac App Store](./mac-app-store-submission-guide.md))
* `win32`
* `linux`
> [!TIP]
> To see all available platform/architecture combinations for a particular release, see the artifacts
> on [Electron's GitHub Releases](https://github.com/electron/electron/releases).
## Proxies
If you need to use an HTTP proxy, you need to set the `ELECTRON_GET_USE_PROXY` variable to any

View File

@@ -78,6 +78,7 @@ auto_filenames = {
"docs/api/web-utils.md",
"docs/api/webview-tag.md",
"docs/api/window-open.md",
"docs/api/structures/activation-arguments.md",
"docs/api/structures/base-window-options.md",
"docs/api/structures/bluetooth-device.md",
"docs/api/structures/browser-window-options.md",

View File

@@ -2,6 +2,10 @@ const binding = process._linkedBinding('electron_browser_notification');
const ElectronNotification = binding.Notification;
ElectronNotification.isSupported = binding.isSupported;
ElectronNotification.getHistory = binding.getHistory;
ElectronNotification.remove = binding.remove;
ElectronNotification.removeAll = binding.removeAll;
ElectronNotification.removeGroup = binding.removeGroup;
if (process.platform === 'win32' && binding.handleActivation) {
ElectronNotification.handleActivation = binding.handleActivation;

102
lib/common/timers-shim.ts Normal file
View File

@@ -0,0 +1,102 @@
// Drop-in replacement for timers-browserify@1.4.2.
// Provides the Node.js 'timers' API surface for renderer/web webpack bundles
// without relying on window.postMessage (which the newer timers-browserify 2.x
// polyfill uses and can interfere with Electron IPC).
const immediateIds: Record<number, boolean> = {};
let nextImmediateId = 0;
// --- DOM timer wrappers ------------------------------------------------
// Wrap the global setTimeout/setInterval so we return Timeout objects that
// expose ref/unref/close matching the Node.js API shape.
class Timeout {
_id: ReturnType<typeof globalThis.setTimeout>;
_clearFn: (id: ReturnType<typeof globalThis.setTimeout>) => void;
constructor (id: ReturnType<typeof globalThis.setTimeout>, clearFn: (id: ReturnType<typeof globalThis.setTimeout>) => void) {
this._id = id;
this._clearFn = clearFn;
}
unref () {}
ref () {}
close () {
this._clearFn.call(globalThis, this._id);
}
}
export const setTimeout = function (...args: Parameters<typeof globalThis.setTimeout>): Timeout {
return new Timeout(globalThis.setTimeout(...args), globalThis.clearTimeout);
};
export const setInterval = function (...args: Parameters<typeof globalThis.setInterval>): Timeout {
return new Timeout(globalThis.setInterval(...args), globalThis.clearInterval);
};
export const clearTimeout = function (timeout: Timeout | undefined) {
if (timeout) timeout.close();
};
export const clearInterval = clearTimeout;
// --- Legacy enroll/unenroll (Node < 11 API, preserved for compatibility) ------
interface EnrollableItem {
_idleTimeoutId?: ReturnType<typeof setTimeout>;
_idleTimeout?: number;
_onTimeout?: () => void;
}
export const enroll = function (item: EnrollableItem, msecs: number) {
clearTimeout(item._idleTimeoutId);
item._idleTimeout = msecs;
};
export const unenroll = function (item: EnrollableItem) {
clearTimeout(item._idleTimeoutId);
item._idleTimeout = -1;
};
export const active = function (item: EnrollableItem) {
clearTimeout(item._idleTimeoutId);
const msecs = item._idleTimeout;
if (msecs !== undefined && msecs >= 0) {
item._idleTimeoutId = setTimeout(function onTimeout () {
if (item._onTimeout) item._onTimeout();
}, msecs);
}
};
export const _unrefActive = active;
// --- setImmediate / clearImmediate -------------------------------------
// Prefer the native implementations when available. Fall back to a
// nextTick-based shim that avoids window.postMessage.
const clearImmediateFallback = function (id: number) {
delete immediateIds[id];
};
export const setImmediate = typeof globalThis.setImmediate === 'function'
? globalThis.setImmediate
: function (fn: (...args: unknown[]) => void, ...rest: unknown[]) {
const id = nextImmediateId++;
immediateIds[id] = true;
Promise.resolve().then(function onMicrotask () {
if (immediateIds[id]) {
fn(...rest);
clearImmediateFallback(id);
}
});
return id;
};
export const clearImmediate = typeof globalThis.clearImmediate === 'function'
? globalThis.clearImmediate
: clearImmediateFallback;

View File

@@ -1232,6 +1232,8 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
// has filesystem caching.
overrideAPI(fs, 'copyFile');
overrideAPISync(fs, 'copyFileSync');
overrideAPI(fs, 'cp');
overrideAPISync(fs, 'cpSync');
overrideAPI(fs, 'open');
overrideAPISync(process, 'dlopen', 1);

View File

@@ -21,8 +21,11 @@ if (isInstalled()) {
process.exit(0);
}
const platform = process.env.npm_config_platform || process.platform;
let arch = process.env.npm_config_arch || process.arch;
const platform = process.env.ELECTRON_INSTALL_PLATFORM || process.env.npm_config_platform || process.platform;
let arch =
process.env.ELECTRON_INSTALL_ARCH ||
process.env.npm_config_arch ||
process.arch;
if (platform === 'darwin' && process.platform === 'darwin' && arch === 'x64' &&
process.env.npm_config_arch === undefined) {

View File

@@ -35,7 +35,7 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.6.0",
"events": "^3.2.0",
"folder-hash": "^4.1.1",
"folder-hash": "^4.1.2",
"got": "^11.8.5",
"husky": "^9.1.7",
"lint-staged": "^16.1.0",
@@ -49,7 +49,6 @@
"stream-json": "^1.9.1",
"tap-xunit": "^2.4.1",
"temp": "^0.9.4",
"timers-browserify": "1.4.2",
"ts-loader": "^8.0.2",
"ts-node": "6.2.0",
"typescript": "^5.8.3",

View File

@@ -148,3 +148,5 @@ fix_wayland_test_crash_on_teardown.patch
fix_set_correct_app_id_on_linux.patch
fix_pass_trigger_for_global_shortcuts_on_wayland.patch
feat_plumb_node_integration_in_worker_through_workersettings.patch
feat_restore_macos_child_plugin_process.patch
fix_restore_sdk_inputs_cross-toolchain_deps_for_macos.patch

View File

@@ -123,10 +123,10 @@ index 9bdfacfc0270bf4ac3a965f6308e4cfc19193f4f..ea9e16b6dd6c96333c653fc602edfbd8
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 b1f17f3abd6763deaee274dd41693f0e6e420865..1e844f4709bc9e616711f717b4a79daf26c561fd 100644
index 1f9061d660d7395a6a9e32d783228fc5ae85c898..f762722e2e2a27db2488aae25d78e79598f6a4b4 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -423,6 +423,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
@@ -422,6 +422,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
void DidCreateScriptContext(v8::Local<v8::Context>,
int32_t world_id) override {}

View File

@@ -116,7 +116,7 @@ index 932658273154ef2e022358e493a8e7c00c86e732..57bbfb5cde62c9496c351c861880a189
// 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 f5bdcb8176a94705a3710ba5dbc536a96b35fed9..657a0e059f954a72d4f8654d1a8938ff255ec193 100644
index 6e86be68d08cec8bcfc0221ef8d702e4a9ab0b28..beeae11dbf256443ceb3d6eb56afa6386eb32f30 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -2502,6 +2502,10 @@ void WebViewImpl::SetPageLifecycleStateInternal(

View File

@@ -49,10 +49,10 @@ index 901b727ed898cdd840df5ff7e2380fbee5d7fde2..1caacaeed9ddf1162cfa393fe4a7c86a
// 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 44bd9c7356a30394f4bfa5333743619443d42216..91fa883ae557d3341789c006c3791f8788e39238 100644
index 85b472e644c4e705b5a176a6c8bcbdf15cdded54..4af17ceeb6e6eb6cf07c6e8723a2065671d12d13 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -779,10 +779,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
@@ -757,10 +757,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
}
DCHECK(!view_ || !view_->IsAttached());
@@ -63,7 +63,7 @@ index 44bd9c7356a30394f4bfa5333743619443d42216..91fa883ae557d3341789c006c3791f87
if (!Client())
return false;
@@ -839,6 +835,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
@@ -817,6 +813,11 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
DCHECK(!view_->IsAttached());
Client()->WillBeDetached();

View File

@@ -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 31174ca1c75252b226af14548324d50744ac8c35..8469a37a4e50c76751160ab6ef484662c3626296 100644
index 708bb2066269b57ff54649638938a1719d657b6a..7485078ed7a4cfdc8bfecf2d3a4a009e10ca4893 100644
--- a/third_party/boringssl/BUILD.gn
+++ b/third_party/boringssl/BUILD.gn
@@ -48,6 +48,21 @@ all_sources = bcm_internal_headers + bcm_sources + crypto_internal_headers +

View File

@@ -33,10 +33,10 @@ index 4b1fd316496e33f9e805aec89a91062587e6ee16..1b6fce9e2780a37e1e8bf3f8a62dc6bc
"//base",
"//build:branding_buildflags",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 589d635d17884050b20b491d65833b7893f5e3e6..672da0774617ae3ac79983aa460b333d6aa325f2 100644
index 8e3ef4d024dcf59f3a3d481312dc27521e313162..befd4aa9b849fcb6c249048095d55b4b7688550e 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4637,7 +4637,7 @@ static_library("browser") {
@@ -4588,7 +4588,7 @@ static_library("browser") {
]
}
@@ -46,10 +46,10 @@ index 589d635d17884050b20b491d65833b7893f5e3e6..672da0774617ae3ac79983aa460b333d
# than here in :chrome_dll.
deps += [ "//chrome:packed_resources_integrity_header" ]
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cfea9608df1620632dfe6f225e857e32ff0fab4f..3cb2213bc57db3b0c01f75c06a8a07609a1cfa86 100644
index b800bca928e2c9c5e843fbf7b29d42e397c5f351..bd4a891a764152dc08b2ee08a09e5430bd83040e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -7776,9 +7776,12 @@ test("unit_tests") {
@@ -7757,9 +7757,12 @@ test("unit_tests") {
"//chrome/notification_helper",
]
@@ -63,7 +63,7 @@ index cfea9608df1620632dfe6f225e857e32ff0fab4f..3cb2213bc57db3b0c01f75c06a8a0760
"//chrome//services/util_win:unit_tests",
"//chrome/app:chrome_dll_resources",
"//chrome/app:win_unit_tests",
@@ -8773,6 +8776,10 @@ test("unit_tests") {
@@ -8753,6 +8756,10 @@ test("unit_tests") {
"../browser/performance_manager/policies/background_tab_loading_policy_unittest.cc",
]
@@ -74,7 +74,7 @@ index cfea9608df1620632dfe6f225e857e32ff0fab4f..3cb2213bc57db3b0c01f75c06a8a0760
sources += [
# The importer code is not used on Android.
"../common/importer/firefox_importer_utils_unittest.cc",
@@ -8830,7 +8837,6 @@ test("unit_tests") {
@@ -8810,7 +8817,6 @@ test("unit_tests") {
# TODO(crbug.com/417513088): Maybe merge with the non-android `deps` declaration above?
deps += [
"../browser/screen_ai:screen_ai_install_state",

View File

@@ -7,7 +7,7 @@ These are variables we add to the root BUILDCONFIG so that they're available
everywhere, without having to import("//electron/.../flags.gni").
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 4d1ac59b9b7dc05a20a3bb523b17706a00761cde..23af9a129531a06dc87573b18b44a921e7fb11ea 100644
index cc00f84630e063fee2b1897eced42c6a53a3a79e..5d4a82783dbe86636bbef47f2fb26ff9147ea57b 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -123,6 +123,9 @@ if (current_os == "") {

View File

@@ -11,7 +11,7 @@ solution is put in place.
This reverts commit 8c004781dde7d42d9a3fed8cafcaa4929943dd69.
diff --git a/components/remote_cocoa/app_shim/bridged_content_view.mm b/components/remote_cocoa/app_shim/bridged_content_view.mm
index 98fccf63096e970ef5f7e7bd58b9db88e48920dd..d1a79368a2a0d60b8d9e128df21cc169e1da793a 100644
index c8e9717e6612291256d0c12613d5d1cf927b890b..7359eb46eb40933d2ec9bd664ec87139af5260df 100644
--- a/components/remote_cocoa/app_shim/bridged_content_view.mm
+++ b/components/remote_cocoa/app_shim/bridged_content_view.mm
@@ -305,14 +305,6 @@ - (NSView*)hitTest:(NSPoint)point {

View File

@@ -9,10 +9,10 @@ potentially prevent a window from being created.
TODO(loc): this patch is currently broken.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index c5ee522e5ffb316bebfce23adb116b0b7cbd8ab8..f92fc4bbddd99bcd4b3e38d59e8c8df4ef6f59e4 100644
index 12304d459b01d0e951065f90c98f4d24c4b138d3..43d64ce77ce86b961bbfd0e0e661577dae0708ca 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -10124,6 +10124,7 @@ void RenderFrameHostImpl::CreateNewWindow(
@@ -10134,6 +10134,7 @@ void RenderFrameHostImpl::CreateNewWindow(
last_committed_origin_, params->window_container_type,
params->target_url, params->referrer.To<Referrer>(),
params->frame_name, params->disposition, *params->features,
@@ -21,10 +21,10 @@ index c5ee522e5ffb316bebfce23adb116b0b7cbd8ab8..f92fc4bbddd99bcd4b3e38d59e8c8df4
&no_javascript_access);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 382b9ad9c6e8df480f6b36df04f799318233e249..310d4cdd98bd0808e3d414b07bc3c14dc64482a1 100644
index b0f3579f18f3b6dd5a9b328324348770319ccf67..1567ac2a65d222080430a47dce97b6d387ebe49d 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5377,6 +5377,10 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5385,6 +5385,10 @@ FrameTree* WebContentsImpl::CreateNewWindow(
create_params.initially_hidden = renderer_started_hidden;
create_params.initial_popup_url = params.target_url;
@@ -35,7 +35,7 @@ index 382b9ad9c6e8df480f6b36df04f799318233e249..310d4cdd98bd0808e3d414b07bc3c14d
// Even though all codepaths leading here are in response to a renderer
// trying to open a new window, if the new window ends up in a different
// browsing instance, then the RenderViewHost, RenderWidgetHost,
@@ -5431,6 +5435,12 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5439,6 +5443,12 @@ FrameTree* WebContentsImpl::CreateNewWindow(
// Sets the newly created WebContents WindowOpenDisposition.
new_contents_impl->original_window_open_disposition_ = params.disposition;
@@ -48,7 +48,7 @@ index 382b9ad9c6e8df480f6b36df04f799318233e249..310d4cdd98bd0808e3d414b07bc3c14d
// If the new frame has a name, make sure any SiteInstances that can find
// this named frame have proxies for it. Must be called after
// SetSessionStorageNamespace, since this calls CreateRenderView, which uses
@@ -5472,12 +5482,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5480,12 +5490,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
AddWebContentsDestructionObserver(new_contents_impl);
}
@@ -198,10 +198,10 @@ index 7a57cb3a1414a77704c42ae01a9dc89fae4ad4a3..769601c2749f0781317f668cf806042d
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 790f004d2a3a9ae5a3588fda097732a5daac0c75..83fcc9418b89b669863e730f2049a1d836eef260 100644
index 25e88c235485f75831bc67d72e9c10f67561ba99..f64dd47225c47407bef3a6d942903ee8b7a4cf20 100644
--- a/content/web_test/browser/web_test_content_browser_client.h
+++ b/content/web_test/browser/web_test_content_browser_client.h
@@ -98,6 +98,8 @@ class WebTestContentBrowserClient : public ShellContentBrowserClient {
@@ -101,6 +101,8 @@ class WebTestContentBrowserClient : public ShellContentBrowserClient {
const std::string& frame_name,
WindowOpenDisposition disposition,
const blink::mojom::WindowFeatures& features,
@@ -224,7 +224,7 @@ index d92bab531c12c62a5321a23f4a0cb89691668127..2060e04795ba8e7a923fd0fe3485b8c5
} // 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 06efc300ee7a014759de6d0d61d0ced6c8bb965f..d8354c7554750bd17c5ad67db2a07453e7a4e5ca 100644
index 3fbc88748183fee47003947a9c2c3f9c2d768a59..90d6ef7e75a1765be57bdc4e28aeed69bd3289c2 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -2341,6 +2341,8 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,

View File

@@ -8,14 +8,14 @@ electron objects that extend gin::Wrappable and gets
allocated on the cpp heap
diff --git a/gin/public/wrappable_pointer_tags.h b/gin/public/wrappable_pointer_tags.h
index c29e8554933994ff56ccea394af34e17c4e9fc2c..6befb717f83d93d97033c240aa281e0bcb94e69c 100644
index fee622ebde42211de6f702b754cfa38595df5a1c..6b524632ebb405e473cf4fe8e253bd13bf7b67e5 100644
--- a/gin/public/wrappable_pointer_tags.h
+++ b/gin/public/wrappable_pointer_tags.h
@@ -76,7 +76,20 @@ enum WrappablePointerTag : uint16_t {
kTextInputControllerBindings, // content::TextInputControllerBindings
@@ -77,7 +77,20 @@ enum WrappablePointerTag : uint16_t {
kWebAXObjectProxy, // content::WebAXObjectProxy
kWrappedExceptionHandler, // extensions::WrappedExceptionHandler
- kLastPointerTag = kWrappedExceptionHandler,
kIndigoContext, // indigo::IndigoContext
- kLastPointerTag = kIndigoContext,
+ kElectronApp, // electron::api::App
+ kElectronDataPipeHolder, // electron::api::DataPipeHolder
+ kElectronDebugger, // electron::api::Debugger

View File

@@ -103,7 +103,7 @@ index 8482d7fab12634e6b9a8d5f9bab6c7e428bb99ee..4f131fbfc9350352bce4430f92b9f2cf
void WillInitializeWorkerContext() override;
void WillDestroyWorkerContext(v8::Local<v8::Context> context) override;
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index ae561f1b8555a93bf42efc0c93b89ba19c505f36..4fa04862fa3bed662dbc92422dfd1c7e808e74ba 100644
index df4634ffecb4b58885374199a863092bfdecf681..33e0ed7a7beae556328ec8bff5e8101acc4b3d26 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -530,6 +530,7 @@ void Dispatcher::DidInitializeServiceWorkerContextOnWorkerThread(
@@ -115,7 +115,7 @@ index ae561f1b8555a93bf42efc0c93b89ba19c505f36..4fa04862fa3bed662dbc92422dfd1c7e
int64_t service_worker_version_id,
const GURL& service_worker_scope,
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index a3445e12264a410dd9d8ba8459c2e27851b03144..271eb740ebf29445a2f1ace81b84d37597a75809 100644
index c2a6eb257469647183167dad78f1ea42fa3922bb..3423e3a8315c5fc5958ec75adf3a844f487680fa 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -151,6 +151,7 @@ class Dispatcher : public content::RenderThreadObserver,
@@ -245,10 +245,10 @@ index ea9e16b6dd6c96333c653fc602edfbd84cd9e5de..78c7c3a446a531fb7c77813f4cae4554
// Returns true if we should allow register V8 extensions to be added.
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index 1e844f4709bc9e616711f717b4a79daf26c561fd..3e22bc128660e8de8e4198bf26e78af7161e811f 100644
index f762722e2e2a27db2488aae25d78e79598f6a4b4..477a22d283796e60762d3be2a951bca58bfce182 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -425,7 +425,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
@@ -424,7 +424,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
int32_t world_id) override {}
void DidInstallConditionalFeatures(v8::Local<v8::Context>,
int32_t world_id) override {}

View File

@@ -10,7 +10,7 @@ Subject: chore: "grandfather in" Electron Views and Delegates
6448510: Lock further access to View::set_owned_by_client(). | https://chromium-review.googlesource.com/c/chromium/src/+/6448510
diff --git a/ui/views/view.h b/ui/views/view.h
index 97c8014fadf2231321c05a1f74d91418946bf9fc..5263aaef4498ae7a19842dd3eb90a09629c28f28 100644
index ea27a73076554aa286c67a506fe5e0f60986d733..ec39e28eaa08e22ad87adce8f4def74d34505a7d 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -77,6 +77,19 @@ class ArcNotificationContentView;

View File

@@ -14,10 +14,10 @@ track down the source of this problem & figure out if we can fix it
by changing something in Electron.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index d4d4bd6ad9098db89b47264821f008868eda9b9b..a663f42e3b9e7bcaf8e463439ada312938f2cf15 100644
index b3215ec81f8d750cfaa9b66a4880c6a90a6e183d..2d993b4265f6be26da1f0bc98520eec3fe393645 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5348,7 +5348,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5356,7 +5356,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
: IsGuest();
// While some guest types do not have a guest SiteInstance, the ones that
// don't all override WebContents creation above.

View File

@@ -14,7 +14,7 @@ This change patches it out to prevent the DCHECK.
It can be removed once/if we see a better solution to the problem.
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index c12fcb91069e601f2e42f31cc1ac9d18dfc3ca3b..085e87b694f42cbbd4fd37cbb17f9977e3bb1586 100644
index 9392365ed456aaa94806cef60a935df1c77617d2..31b7a42424fb0935df44747169b4a2d9336170a2 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -224,7 +224,7 @@ scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::CreateForGuest(

View File

@@ -80,10 +80,10 @@ index 39fa45f0a0f9076bd7ac0be6f455dd540a276512..3d0381d463eed73470b28085830f2a23
content::WebContents* source,
const content::OpenURLParams& params,
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index dd77f2fda3db2e7974003085a22981cad3f6c794..793b0d4d0d03f42a7c646bed931969e4b29d2891 100644
index f47a1155907d92146dabd72b5c7e8120a2b71c77..9122edca238bffc3b0949d71a217f2e6414d3fa9 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2292,7 +2292,8 @@ bool Browser::IsWebContentsCreationOverridden(
@@ -2288,7 +2288,8 @@ bool Browser::IsWebContentsCreationOverridden(
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
@@ -93,7 +93,7 @@ index dd77f2fda3db2e7974003085a22981cad3f6c794..793b0d4d0d03f42a7c646bed931969e4
if (HasActorTaskPreventingNewWebContents(profile(), opener)) {
// If an ExecutionEngine is acting on the opener, prevent it from creating a
// new WebContents. We'll instead force the navigation to happen in the same
@@ -2305,7 +2306,7 @@ bool Browser::IsWebContentsCreationOverridden(
@@ -2301,7 +2302,7 @@ bool Browser::IsWebContentsCreationOverridden(
return (window_container_type ==
content::mojom::WindowContainerType::BACKGROUND &&
ShouldCreateBackgroundContents(source_site_instance, opener_url,
@@ -223,10 +223,10 @@ index b969f1d97b7e3396119b579cfbe61e19ff7d2dd4..b8d6169652da28266a514938b45b39c5
content::WebContents* AddNewContents(
content::WebContents* source,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index ebb64bfdabfd22146cac139b7800714e7648d31b..6a2444ad5d20164be9877cf6b856d2bf762dcd26 100644
index f605f46115cda0f8f06e5274a26e3b997ca4c62e..16c4c2f73643314a9b8287e13a6472dff2671652 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5312,8 +5312,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5320,8 +5320,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
if (delegate_ &&
delegate_->IsWebContentsCreationOverridden(
opener, source_site_instance, params.window_container_type,

View File

@@ -8,10 +8,10 @@ Allow registering custom protocols to handle service worker main script fetching
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 884c9c6cf1e7a46a2a375d53b4b8761c769f2992..46d2505f8ac3aeccc2003763fecb78aedce53575 100644
index 59b61e92921c2a21ec6d0d98fecc27cb2465d917..a527eb1558a070361285070e047587a122423654 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -1956,6 +1956,26 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
@@ -1958,6 +1958,26 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
loader_factory_bundle_info =
context()->loader_factory_bundle_for_update_check()->Clone();
@@ -38,7 +38,7 @@ index 884c9c6cf1e7a46a2a375d53b4b8761c769f2992..46d2505f8ac3aeccc2003763fecb78ae
if (auto* config = content::WebUIConfigMap::GetInstance().GetConfig(
browser_context(), scope)) {
// If this is a Service Worker for a WebUI, the WebUI's URLDataSource
@@ -1975,9 +1995,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
@@ -1977,9 +1997,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
features::kEnableServiceWorkersForChromeScheme) &&
scope.scheme() == kChromeUIScheme) {
config->RegisterURLDataSource(browser_context());
@@ -49,14 +49,3 @@ index 884c9c6cf1e7a46a2a375d53b4b8761c769f2992..46d2505f8ac3aeccc2003763fecb78ae
.emplace(kChromeUIScheme, CreateWebUIServiceWorkerLoaderFactory(
browser_context(), kChromeUIScheme,
base::flat_set<std::string>()));
@@ -1985,9 +2003,7 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
features::kEnableServiceWorkersForChromeUntrusted) &&
scope.scheme() == kChromeUIUntrustedScheme) {
config->RegisterURLDataSource(browser_context());
- static_cast<blink::PendingURLLoaderFactoryBundle*>(
- loader_factory_bundle_info.get())
- ->pending_scheme_specific_factories()
+ pending_scheme_specific_factories
.emplace(kChromeUIUntrustedScheme,
CreateWebUIServiceWorkerLoaderFactory(
browser_context(), kChromeUIUntrustedScheme,

View File

@@ -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 5f820ecdcb99e57d1d51cd28fff7874f9ba58e23..1455aa5083f8eef7bf9644a1cc522db3e67b0227 100644
index 60c27d90b3c78e0d119fe02f7ee3547d19344fc0..64b3baf601e20381e7dd18facded2066a50a82c6 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -848,6 +848,10 @@ void RenderWidgetHostImpl::WasHidden() {
@@ -810,6 +810,10 @@ void RenderWidgetHostImpl::WasHidden() {
return;
}
@@ -21,7 +21,7 @@ index 5f820ecdcb99e57d1d51cd28fff7874f9ba58e23..1455aa5083f8eef7bf9644a1cc522db3
// Prompts should remain open and functional across tab switches.
if (!delegate_ || !delegate_->IsWaitingForPointerLockPrompt(this)) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index bd0f3ec2116a137d2a24e81e6bf0b5854a47f2f9..e1585de8fad7b11174d51666e7dce681f39b0815 100644
index 8fc7d892a54e0890e86b01713f0cf6b75aa14ab0..d60b540934b290e9303b1dacfa990e85ce47b4e0 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -1042,6 +1042,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl

View File

@@ -15,7 +15,7 @@ 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 657a0e059f954a72d4f8654d1a8938ff255ec193..a2fec97ec08ca8eb83218baffabab65e0768a130 100644
index beeae11dbf256443ceb3d6eb56afa6386eb32f30..48b3afb91a599c95fd34441b6dc6a80c5d695d85 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1886,6 +1886,8 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,

View File

@@ -46,10 +46,10 @@ index 6e60de1319c5506d7180719fa230ab9cf537b832..e570e335fbd413340ddedeee423eca71
'internal-forced-visited-'):
internal_visited_order = 0
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index e388ec680c1492b7ef7f3428f16d35f4d13c4b53..56cabedc4588cefd69f7b5509eb093b42c122a92 100644
index bce3a012ce093c64b273045a9fbcd4db88c4c365..6175f0d0ddbfbc6a4e43f0135c6b84f39efcecb0 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -9596,6 +9596,27 @@
@@ -9606,6 +9606,27 @@
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
},
@@ -91,10 +91,10 @@ index 2afe18e9e4a5404ed184aeedc1c02a313853f463..7c3b0c2da6ded539764ce59bc43f49e9
return a.EmptyCells() == b.EmptyCells();
case CSSPropertyID::kFill:
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 44288dcc847fd9328d15c4576de6d7c98e8cb662..35c2ef984401b51c2d688cef7e56e89b5660e27b 100644
index 59a95a74f542eea6b1a1ee85f77b6f8c124ebcad..6a6ab6dec5d9496380c876c1aef70ee75e1777c0 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -13206,5 +13206,36 @@ const CSSValue* InternalEmptyLineHeight::ParseSingleValue(
@@ -13252,5 +13252,36 @@ const CSSValue* InternalEmptyLineHeight::ParseSingleValue(
CSSValueID::kNone>(stream);
}
@@ -203,10 +203,10 @@ index 19cda703154dab9397827ab6ea66c2ca446c644d..dd5943c511886f4e39b2e7f10e67e60f
return result;
}
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index eb2472737bd6e20a6bf9fdb311a412036d7dbff7..1872c87c8ec04263ab40072bdbc28520f6fd7c83 100644
index 784ce295c0bca0a7bd096585c0f6ff603f688abc..aeb07b03395d0ea4fd2ca229aed1da4ec80dd969 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1671,6 +1671,8 @@ component("platform") {
@@ -1673,6 +1673,8 @@ component("platform") {
"widget/widget_base.h",
"widget/widget_base_client.h",
"windows_keyboard_codes.h",
@@ -314,7 +314,7 @@ index 18f283e625101318ee14b50e6e765dfd1c9a1a44..44a3a55974c9e4b9e715574075f25661
auto DrawAsSinglePath = [&]() {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 19184b04ae49211d339b71af9141b4425059d522..7ea37369440109fe7dad2cbeb2e910f26d3a73eb 100644
index 7afb28fffccf3c117d742f08b31c1365e84af4b0..35bcd34d7a281a95c12c5831dc97a601715157b5 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -214,6 +214,10 @@

View File

@@ -0,0 +1,68 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Maddock <smaddock@slack-corp.com>
Date: Fri, 13 Mar 2026 15:35:48 -0400
Subject: feat: restore macos child plugin process
Chromium has removed upstream support for child plugin processes
without library validation; see https://crbug.com/461717105.
This patch partially reverts
https://chromium-review.googlesource.com/c/chromium/src/+/7653455
diff --git a/content/browser/child_process_host_impl.cc b/content/browser/child_process_host_impl.cc
index efd3d6686fa2b3ca121e63ac674fed2d57e82c0c..645434ac6a872bf3f67dd1edd987c19fbb4b0ef6 100644
--- a/content/browser/child_process_host_impl.cc
+++ b/content/browser/child_process_host_impl.cc
@@ -87,6 +87,8 @@ base::FilePath ChildProcessHost::GetChildPath(int flags) {
child_base_name += kMacHelperSuffix_renderer;
} else if (flags == CHILD_GPU) {
child_base_name += kMacHelperSuffix_gpu;
+ } else if (flags == CHILD_PLUGIN) {
+ child_base_name += kMacHelperSuffix_plugin;
} else if (flags > CHILD_EMBEDDER_FIRST) {
child_base_name +=
GetContentClient()->browser()->GetChildProcessSuffix(flags);
diff --git a/content/public/app/mac_helpers.gni b/content/public/app/mac_helpers.gni
index d9588d963684354e9564ccce5a8f8371c144a58e..027158994bb7207125ca819f9f226b9fb691037a 100644
--- a/content/public/app/mac_helpers.gni
+++ b/content/public/app/mac_helpers.gni
@@ -45,4 +45,16 @@ content_mac_helpers = [
"",
" (GPU)",
],
+
+ # A helper that does not perform library validation, allowing code not signed
+ # by either Apple or the signing identity to be loaded, and that can execute
+ # unsigned memory.
+ #
+ # This was removed upstream and is now maintained for Electron; see
+ # https://crbug.com/461717105.
+ [
+ "plugin",
+ ".plugin",
+ " (Plugin)",
+ ],
]
diff --git a/content/public/browser/child_process_host.h b/content/public/browser/child_process_host.h
index 2028deaf624bbfc75b2fa563298f3f4f65b1d65f..5ee19fbca0a73bb81273d162b2c304427b1b85cb 100644
--- a/content/public/browser/child_process_host.h
+++ b/content/public/browser/child_process_host.h
@@ -97,6 +97,18 @@ class CONTENT_EXPORT ChildProcessHost {
// allow-jit entitlement instead.
CHILD_GPU,
+ // Starts a child process with the macOS entitlement that ignores the
+ // library validation code signing enforcement.
+ //
+ // Library validation mandates that all executable pages be backed by a code
+ // signature of either 1) Apple, or 2) the same Team ID as the main
+ // executable. Third-party plug-ins are not signed by the same Team ID as
+ // the main binary, so this flag must be used when loading them.
+ //
+ // This was removed upstream and is now maintained for Electron; see
+ // https://crbug.com/461717105.
+ CHILD_PLUGIN,
+
// Marker for the start of embedder-specific helper child process types.
// Values greater than CHILD_EMBEDDER_FIRST are reserved to be used by the
// embedder to add custom process types and will be resolved via

View File

@@ -170,7 +170,7 @@ index e62f180fd782f29c25cf47a4e6be0cce46c99b17..b65d050fee7a607658efa6914c35186d
if (params.opacity == views::Widget::InitParams::WindowOpacity::kInferred &&
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 285cd57cf18d7cb5cbe787194def75efbd0ceacb..9b7043f23498dd04c05a89f373f019c210cc246d 100644
index 964bbba8f17fb613521c05e5de2c11740ea69bcf..7aa208025162bf1deba59760403542ec61034937 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -324,6 +324,11 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
@@ -207,7 +207,7 @@ index 285cd57cf18d7cb5cbe787194def75efbd0ceacb..9b7043f23498dd04c05a89f373f019c2
// True if the window size will follow the content preferred size.
bool is_autosized() const { return is_autosized_; }
@@ -1740,6 +1753,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
@@ -1737,6 +1750,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// If true, the mouse is currently down.
bool is_mouse_button_pressed_ = false;

View File

@@ -49,10 +49,10 @@ index 42e37564e585987d367921568f0f1d2b7507f953..9baf89efbade01e8b60c579255f10799
}
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.cc
index 16b11c6115cc5504dbd15d58c4b9786633e90e96..7c0a2308d437a2d9cec433c6ab0fd6a9d0c08845 100644
index 0e9bffaf0203d39d9fb82d717f36b449d5566181..5cf3d98f4679a252290a34c15491a8a4a619ac1c 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.cc
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.cc
@@ -64,6 +64,22 @@ void GlobalAcceleratorListener::UnregisterAccelerator(
@@ -62,6 +62,22 @@ void GlobalAcceleratorListener::UnregisterAccelerator(
}
}
@@ -73,10 +73,10 @@ index 16b11c6115cc5504dbd15d58c4b9786633e90e96..7c0a2308d437a2d9cec433c6ab0fd6a9
+}
+
void GlobalAcceleratorListener::UnregisterAccelerators(Observer* observer) {
if (IsShortcutHandlingSuspended()) {
return;
auto it = accelerator_map_.begin();
while (it != accelerator_map_.end()) {
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.h b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.h
index 99fdad04b8f336ef526902fc6a3b44954c02cf0c..1cf8f9cd6c07d161f5dadcb2752a59aebadaf2ac 100644
index 4a343f4e701928644ff3f2a855cc04c3fea2932a..a48b7b73508942cc05e0dcf0fe108313f265c7c6 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.h
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.h
@@ -9,6 +9,7 @@

View File

@@ -64,7 +64,7 @@ index 705a2ee24e463a65784a48844d7c9c26ae7b48db..87bf9b64616688152bd681cb57cefbc6
TextInputManager::SelectionRegion::SelectionRegion(
diff --git a/content/browser/renderer_host/text_input_manager.h b/content/browser/renderer_host/text_input_manager.h
index 5158897a7a7af9f29580faa17498a8dbab40af87..96617b9bb0275144b0e9ed18547d9982aa05baea 100644
index a4768b51dae6817c9e9a467e9b16e827e0bfebda..83c42b5062aa8193fe2f56e407abe67da3e96b86 100644
--- a/content/browser/renderer_host/text_input_manager.h
+++ b/content/browser/renderer_host/text_input_manager.h
@@ -69,6 +69,10 @@ class CONTENT_EXPORT TextInputManager {
@@ -87,10 +87,10 @@ index 5158897a7a7af9f29580faa17498a8dbab40af87..96617b9bb0275144b0e9ed18547d9982
// The view with active text input state, i.e., a focused <input> element.
// It will be nullptr if no such view exists. Note that the active view
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 3413e339934bab9df03d241213d27221bb5eaa20..d4d4bd6ad9098db89b47264821f008868eda9b9b 100644
index 76def190aabe280bb8e0971dc5c72643bbce8f53..b3215ec81f8d750cfaa9b66a4880c6a90a6e183d 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -10276,7 +10276,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame(
@@ -10284,7 +10284,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame(
"WebContentsImpl::OnFocusedElementChangedInFrame",
"render_frame_host", frame);
RenderWidgetHostViewBase* root_view =

View File

@@ -11,10 +11,10 @@ This patch should be upstreamed as a conditional revert of the logic in desktop
vs mobile runtimes. i.e. restore the old logic only on desktop platforms
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 5df63357160d96b77c8c123a984aeef9850b1ae2..9b598ba34285bfe04c7c45557dd51af73bece3fe 100644
index 05b0f0e5fd4f7b9351573f1736de322a90a7c296..1e3a09e4293b8925512f64ad2a78bccce2c83fca 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2192,9 +2192,8 @@ RenderWidgetHostImpl::GetWidgetInputHandler() {
@@ -2148,9 +2148,8 @@ RenderWidgetHostImpl::GetWidgetInputHandler() {
void RenderWidgetHostImpl::NotifyScreenInfoChanged() {
// The resize message (which may not happen immediately) will carry with it
// the screen info as well as the new size (if the screen has changed scale

View File

@@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Mon, 16 Mar 2026 18:57:00 +0100
Subject: fix: restore sdk_inputs cross-toolchain deps for macOS
The change in CL:7652975 restricted sdk_inputs public_deps
to iOS only, to avoid setting up Xcode symlinks for the Linux
toolchain when cross-building chrome/linux on Mac. However, this
also broke cross-arch macOS builds (e.g. ffmpeg with target_cpu=x64)
where the mig target in the clang_arm64 toolchain depends on
sdk_inputs from the default clang_x64 toolchain.
Add target_os == \"mac\" alongside the existing iOS check to preserve
the original intent while restoring the cross-toolchain dependency
for macOS builds.
We should try to upstream this.
diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn
index 56238a14ae8fb0a8fc9bba6553b99c199080e7af..22c628c3b4a3d1072b382ffc0fd0ce5bb85de9b5 100644
--- a/build/config/mac/BUILD.gn
+++ b/build/config/mac/BUILD.gn
@@ -120,7 +120,8 @@ if (mac_use_xcode_symlinks && current_toolchain == default_toolchain) {
}
} else {
group("sdk_inputs") {
- if (current_toolchain != default_toolchain && target_os == "ios") {
+ if (current_toolchain != default_toolchain &&
+ (target_os == "ios" || target_os == "mac")) {
public_deps = [ ":sdk_inputs($default_toolchain)" ]
}
}

View File

@@ -59,10 +59,10 @@ index cba373664bec3a32abad6fe0396bd67b53b7e67f..a54f1b3351efd2d8f324436f7f35cd43
#endif // THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SCRIPT_EXECUTION_CALLBACK_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 91fa883ae557d3341789c006c3791f8788e39238..bc265108b668b3843c0113792b547f93cfc66bdf 100644
index 4af17ceeb6e6eb6cf07c6e8723a2065671d12d13..b8973d07dd6beedf26a943149f856da7bd546cf9 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -3222,6 +3222,7 @@ void LocalFrame::RequestExecuteScript(
@@ -3200,6 +3200,7 @@ void LocalFrame::RequestExecuteScript(
mojom::blink::EvaluationTiming evaluation_timing,
mojom::blink::LoadEventBlockingOption blocking_option,
WebScriptExecutionCallback callback,
@@ -70,7 +70,7 @@ index 91fa883ae557d3341789c006c3791f8788e39238..bc265108b668b3843c0113792b547f93
BackForwardCacheAware back_forward_cache_aware,
mojom::blink::WantResultOption want_result_option,
mojom::blink::PromiseResultOption promise_behavior) {
@@ -3279,7 +3280,7 @@ void LocalFrame::RequestExecuteScript(
@@ -3257,7 +3258,7 @@ void LocalFrame::RequestExecuteScript(
PausableScriptExecutor::CreateAndRun(
script_state, std::move(script_sources), execute_script_policy,
user_gesture, evaluation_timing, blocking_option, want_result_option,
@@ -80,7 +80,7 @@ index 91fa883ae557d3341789c006c3791f8788e39238..bc265108b668b3843c0113792b547f93
void LocalFrame::SetEvictCachedSessionStorageOnFreezeOrUnload() {
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index feb469a17af253cf72975f0d1a049beab6a2c53e..1497d0529b6b9a0e4ac14b89157ab52c20985d9c 100644
index d48612c83ed164949227ca70aac6deaaa5388a36..c7efc832a839056dfb479df8e9955adecae07e7c 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -835,6 +835,7 @@ class CORE_EXPORT LocalFrame final
@@ -211,7 +211,7 @@ index f2c94689450f0333a144ccf82cf147c194896e6b..1c2e9fe36c297f7d614d9ca290e4d13c
const mojom::blink::UserActivationOption user_activation_option_;
const mojom::blink::LoadEventBlockingOption blocking_option_;
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 782fe8b0931884226d19ad7224d7ec576ca78113..fd36db08a2f9900685280d72fe55bcd062c9060c 100644
index e281d26513e644465359d9c99e7240d24f6aaace..1688b62c0dd283f9d6a5190e7e269c8551c0f6f6 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -298,6 +298,7 @@ void ExecuteScriptsInMainWorld(
@@ -223,7 +223,7 @@ index 782fe8b0931884226d19ad7224d7ec576ca78113..fd36db08a2f9900685280d72fe55bcd0
mojom::blink::WantResultOption::kWantResult, wait_for_promise);
}
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 5670b632ec9b8139885c81ff867a4fc1556c08a5..24a172f8fc2b643d4d0f6073e120d6f553c5c8f9 100644
index 6ce6c0af328f722d02228feae910b129e0f41a74..d4a11cc2cd9be3a97058ec800ff23bc2ce33b12b 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
@@ -1128,14 +1128,15 @@ void WebLocalFrameImpl::RequestExecuteScript(

View File

@@ -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 0e6f4713d61c4ac6d1ea174abc451617a6863829..2deacd7c4b527b197be02df7e218028d6963e2de 100644
index a5165a08f161844898281c18d3963f8abffd58a8..c4d995aec772a6818c747adceb9fc63fe8d272e2 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -4923,6 +4923,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
@@ -4925,6 +4925,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
request->ResetStateForSiteInstanceChange();
}

View File

@@ -50,7 +50,7 @@ system font by checking if it's kCTFontPriorityAttribute is set to
system priority.
diff --git a/base/BUILD.gn b/base/BUILD.gn
index c9811ba7835ed8f96dbde412543e86dc3b5ab13b..2786fa35b0ccf210af0e2ba4b423952211676614 100644
index 7ab4379d92fdaa2e7047100c18df204265656cf1..1590dd3ae2ee86daff32edb14281589bb34df3df 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1082,6 +1082,7 @@ component("base") {
@@ -129,10 +129,10 @@ index 416e541436d201aabca26cdbf7e8477103bd014c..8c5f92b03d67e5f0587b0e9420969061
}
diff --git a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn
index 275d6dbe1b05f806278c14e2ec5df5d550be787b..750ba56ec139679b994aec04938858c064c76d69 100644
index 1f8256fdf364c34406fd5639057acca8d52cb474..2df7110c18569323199ec227891362c248237b2f 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn
+++ b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn
@@ -972,6 +972,7 @@ if (is_clang_or_gcc) {
@@ -974,6 +974,7 @@ if (is_clang_or_gcc) {
":allocator_base",
":allocator_core",
":buildflags",
@@ -974,7 +974,7 @@ index 2f1fcace77c403c0e136ae2fc40633cccccce038..9ce9c1771310e81b18ba6fe4569544ff
return kAttributes;
}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 3913f68ccd32442c16b50b7a48a1876da3061f3b..013b1ba6cffa8ad0040b7939289199a5dfd4563d 100644
index 6c20db955545b37cb1fd6fcc9b280aa1c7a14ae9..c5b6e15d3e6826f31b4237668e38449f31663639 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -362,6 +362,7 @@ source_set("browser") {
@@ -1095,10 +1095,10 @@ index 29fe3bd4d8a63c5bd51536a904d191fef0c4e4a1..a36dd07237392e537c389628b5814e20
///////////////////////////////////////////////////////////////////////////////
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 5487c3756c60389a3442c2e59a08c91890fb6f87..f17ed8c3485102ac63f34239b3b31a3a322088f9 100644
index 691fb357cb6865cc0b47d37a509a440b52475493..3377fbe048b4e6945ca4790aa2dadde7dd9f47ea 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -279,6 +279,7 @@ source_set("common") {
@@ -280,6 +280,7 @@ source_set("common") {
"//ui/shell_dialogs",
"//url",
"//url/ipc:url_ipc",
@@ -1189,10 +1189,10 @@ index a1068589ad844518038ee7bc15a3de9bc5cba525..1ff781c49f086ec8015c7d3c44567dbe
} // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index be65cd3d0696c7df1fa7548e6b0461f81f505287..29e30240e271fc7cad600de7ce5895ef2ff9ba46 100644
index ce7596c707fea72a6cf90b851c411e21999fdadd..707885fc25831eb012efb902211f198a585e2817 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -700,6 +700,7 @@ static_library("test_support") {
@@ -701,6 +701,7 @@ static_library("test_support") {
"//url",
"//url/mojom:url_mojom_gurl",
"//v8",
@@ -1200,7 +1200,7 @@ index be65cd3d0696c7df1fa7548e6b0461f81f505287..29e30240e271fc7cad600de7ce5895ef
]
data_deps = [
@@ -1175,6 +1176,8 @@ static_library("browsertest_support") {
@@ -1176,6 +1177,8 @@ static_library("browsertest_support") {
# TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
# enable the diagnostic by removing this line.
configs += [ "//build/config/compiler:no_exit_time_destructors" ]
@@ -1209,7 +1209,7 @@ index be65cd3d0696c7df1fa7548e6b0461f81f505287..29e30240e271fc7cad600de7ce5895ef
}
mojom("content_test_mojo_bindings") {
@@ -2072,6 +2075,7 @@ test("content_browsertests") {
@@ -2075,6 +2078,7 @@ test("content_browsertests") {
"//ui/shell_dialogs",
"//ui/snapshot",
"//ui/webui:test_support",
@@ -1217,7 +1217,7 @@ index be65cd3d0696c7df1fa7548e6b0461f81f505287..29e30240e271fc7cad600de7ce5895ef
]
if (!(is_chromeos && target_cpu == "arm64" && current_cpu == "arm")) {
@@ -3423,6 +3427,7 @@ test("content_unittests") {
@@ -3426,6 +3430,7 @@ test("content_unittests") {
"//ui/shell_dialogs",
"//ui/webui:test_support",
"//url",
@@ -1378,7 +1378,7 @@ index 3a079b0fc34031d062045510fe0e2444792ff942..1be75833d46aaa124e5467904f68e46c
} // namespace
#endif
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index d8509119f1c9e527d2a89faad239e13dead54257..7d55ecc59bcd535599ed37c7dd684ae571258c9a 100644
index aa3411b03b674479df96af0d182ffa8e35c9f3be..79167ca3638a13aeb0f3e07b064afaa88cad3b2c 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -207,6 +207,8 @@ source_set("dns") {
@@ -1789,10 +1789,10 @@ index eb81a70e4d5d5cd3e6ae9b45f8cd1c795ea76c51..9921ccb10d3455600eddd85f77f10228
} // namespace sandbox
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 66ed65def5c45d87f2e6357228cfcafdd784ed9a..0ad8271d301d91b2b24b5efed01242426e48aa5b 100644
index 9b399ad326a19af7fd5e717bf8940ec562338f6d..96cc912489ab4423e0592d9c90c3d38f57131087 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -439,6 +439,7 @@ component("core") {
@@ -444,6 +444,7 @@ component("core") {
"//ui/gfx/geometry",
"//ui/gfx/geometry:geometry_skia",
"//ui/strings",
@@ -1801,10 +1801,10 @@ index 66ed65def5c45d87f2e6357228cfcafdd784ed9a..0ad8271d301d91b2b24b5efed0124242
if (is_mac) {
diff --git a/third_party/blink/renderer/core/editing/build.gni b/third_party/blink/renderer/core/editing/build.gni
index 4f04476e9175bae9e89eb9ea4316bffe49a9eb91..e77615c7b26518f4930ac1b004b413173fa0f46b 100644
index cb1c907e6244cc5955edcc251db292198ba01e42..82df6d9e5c71e9e1b098fc4747b072e85e68114a 100644
--- a/third_party/blink/renderer/core/editing/build.gni
+++ b/third_party/blink/renderer/core/editing/build.gni
@@ -362,10 +362,14 @@ blink_core_sources_editing = [
@@ -368,10 +368,14 @@ blink_core_sources_editing = [
if (is_mac) {
blink_core_sources_editing += [
"commands/smart_replace_cf.cc",

View File

@@ -133,7 +133,7 @@ index 9bf238e64af483294ae3c3f18a4e9aed49a8658d..b9b2a4c8c387b8e8b4eb1f02fc0f891c
const GURL& document_url,
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 3b307edcc8e5c29b1b2d2a0fb1410ae37fed986c..51207bea3a7f345e38503f50e25e60ea0425a1a5 100644
index 99ced941ed095fdb2b6c3c5599733ac1f3ec73c0..c56d8ce7b8d346357ad9f8293b252eaae0c8655d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2376,7 +2376,7 @@ void RenderProcessHostImpl::CreateNotificationService(

View File

@@ -30,10 +30,10 @@ index 4dad6bbade99a00b5ae0f45d4de34d866918545c..6c7ec195fa64e3a1a718811192c9f6fd
// 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 1455aa5083f8eef7bf9644a1cc522db3e67b0227..5df63357160d96b77c8c123a984aeef9850b1ae2 100644
index 64b3baf601e20381e7dd18facded2066a50a82c6..05b0f0e5fd4f7b9351573f1736de322a90a7c296 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2103,6 +2103,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) {
@@ -2059,6 +2059,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) {
if (view_) {
view_->UpdateCursor(cursor);
}
@@ -44,10 +44,10 @@ index 1455aa5083f8eef7bf9644a1cc522db3e67b0227..5df63357160d96b77c8c123a984aeef9
void RenderWidgetHostImpl::ShowContextMenuAtPoint(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 310d4cdd98bd0808e3d414b07bc3c14dc64482a1..ebb64bfdabfd22146cac139b7800714e7648d31b 100644
index 1567ac2a65d222080430a47dce97b6d387ebe49d..f605f46115cda0f8f06e5274a26e3b997ca4c62e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -6204,6 +6204,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
@@ -6212,6 +6212,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
return text_input_manager_.get();
}
@@ -60,10 +60,10 @@ index 310d4cdd98bd0808e3d414b07bc3c14dc64482a1..ebb64bfdabfd22146cac139b7800714e
RenderWidgetHostImpl* render_widget_host) {
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 e94fdbc3a434e6d1e7a82638bf01789545b2f7ce..8a9a4da89a73afe520d8a7532f456b62e78dee89 100644
index c1fdb7e3d899dbdd4413361040158395a6d4eb98..ce46eaa39b053850e2692c906a9e991052cd7195 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1201,6 +1201,7 @@ class CONTENT_EXPORT WebContentsImpl
@@ -1204,6 +1204,7 @@ class CONTENT_EXPORT WebContentsImpl
void SendScreenRects() override;
void SendActiveState(bool active) override;
TextInputManager* GetTextInputManager() override;

View File

@@ -7,7 +7,7 @@ Subject: refactor: expose HostImportModuleDynamically and
This is so that Electron can blend Blink's and Node's implementations of these isolate handlers.
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 832fbc9666cc3eac9c08a36a7014a6fb6f3aff39..1b1b13ff86db65197ae9544f25d1a49985c957ed 100644
index d2925a10c6242bff1de59fc681f549d3b0aa267e..97a49dd4904b7965ff716648d654e3464e2ebc58 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -738,8 +738,9 @@ bool WasmCustomDescriptorsEnabledCallback(v8::Local<v8::Context> context) {

View File

@@ -15,10 +15,10 @@ This CL removes these filters so the unresponsive event can still be
accessed from our JS event. The filtering is moved into Electron's code.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index a663f42e3b9e7bcaf8e463439ada312938f2cf15..b9a2f127138e78c1cea4af084f34421908e86224 100644
index 2d993b4265f6be26da1f0bc98520eec3fe393645..a526b1071029a33983060e3f379e3030ac723403 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -10438,25 +10438,13 @@ void WebContentsImpl::RendererUnresponsive(
@@ -10446,25 +10446,13 @@ void WebContentsImpl::RendererUnresponsive(
base::RepeatingClosure hang_monitor_restarter) {
OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RendererUnresponsive",
"render_widget_host", render_widget_host);

View File

@@ -245,10 +245,10 @@ index 1ef2c9052262eccdbc40030746a858b7f30ac469..c7101b0d71826b05f61bfe0e74429d92
}
diff --git a/content/common/features.cc b/content/common/features.cc
index bfc58f4a0b06033ce97b389f2e602453c1bcf061..1c5f81ee51036be1303c2f4f356f8da30cbb9614 100644
index 3b4ab9f49e73e4af20be84e53f8ff161f913a36c..defcfbb3683062fd80b166cf132458a805a8f365 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -369,6 +369,14 @@ BASE_FEATURE(kInterestGroupUpdateIfOlderThan, base::FEATURE_ENABLED_BY_DEFAULT);
@@ -364,6 +364,14 @@ BASE_FEATURE(kInterestGroupUpdateIfOlderThan, base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kIOSurfaceCapturer, base::FEATURE_ENABLED_BY_DEFAULT);
#endif
@@ -264,10 +264,10 @@ index bfc58f4a0b06033ce97b389f2e602453c1bcf061..1c5f81ee51036be1303c2f4f356f8da3
BASE_FEATURE(kKeepChildProcessAfterIPCReset, base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/content/common/features.h b/content/common/features.h
index 685d9f3bee3f1a1bd139b6c70447bfd059fdefcf..de268dc4d77ae479396dfcf56dbdf39f965ab707 100644
index a1592bb3f5f23af0c66744e9b7f9d6c199217082..ebe364d600bdd1db7beeb9a7cefdcb9c7c328889 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -143,6 +143,9 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kInterestGroupUpdateIfOlderThan);
@@ -142,6 +142,9 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kInterestGroupUpdateIfOlderThan);
#if BUILDFLAG(IS_MAC)
CONTENT_EXPORT BASE_DECLARE_FEATURE(kIOSurfaceCapturer);
#endif

View File

@@ -39,10 +39,10 @@ index 6c7ec195fa64e3a1a718811192c9f6fdbf9463c6..c11744d2246c3df138cdb91f1d4459c6
// event before sending it to the renderer. See enum for details on return
// value.
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 9b598ba34285bfe04c7c45557dd51af73bece3fe..c435d4441c99f87cc6a38fa73f73da6b34d9880a 100644
index 1e3a09e4293b8925512f64ad2a78bccce2c83fca..30ff1afa505be3d2a2c94526e96f6cd6a566a605 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1599,6 +1599,10 @@ void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo(
@@ -1555,6 +1555,10 @@ void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo(
CHECK_GE(mouse_event.GetType(), WebInputEvent::Type::kMouseTypeFirst);
CHECK_LE(mouse_event.GetType(), WebInputEvent::Type::kMouseTypeLast);
@@ -54,10 +54,10 @@ index 9b598ba34285bfe04c7c45557dd51af73bece3fe..c435d4441c99f87cc6a38fa73f73da6b
if (mouse_event_callback.Run(mouse_event)) {
return;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index b9a2f127138e78c1cea4af084f34421908e86224..3f767c219bdb6d73bff9942312736d9523bc6a02 100644
index a526b1071029a33983060e3f379e3030ac723403..28a98260183ad24529ef5848ffcb117e9e1a6e3b 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4475,6 +4475,12 @@ void WebContentsImpl::RenderWidgetWasResized(
@@ -4486,6 +4486,12 @@ void WebContentsImpl::RenderWidgetWasResized(
width_changed);
}
@@ -71,10 +71,10 @@ index b9a2f127138e78c1cea4af084f34421908e86224..3f767c219bdb6d73bff9942312736d95
const gfx::PointF& client_pt) {
if (delegate_) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 8a9a4da89a73afe520d8a7532f456b62e78dee89..289e4d4c39e46a08505cba2d92ae6ce83973e526 100644
index ce46eaa39b053850e2692c906a9e991052cd7195..953deca8142154ffd0a27c11e9beb42270107a8c 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1131,6 +1131,7 @@ class CONTENT_EXPORT WebContentsImpl
@@ -1134,6 +1134,7 @@ class CONTENT_EXPORT WebContentsImpl
double GetPendingZoomLevel(RenderWidgetHostImpl* rwh) override;

View File

@@ -10,10 +10,10 @@ on Windows. We should refactor our code so that this patch isn't
necessary.
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index bd2d3870edb37f32b97c4e5756ce12b44ee6ac2d..4e2ece73a02b7314d0eb3a61ef6958dcefdc2ef9 100644
index 7f5e80f63cea16d9c75237ebeb198e1cdba6e595..d3a292eb0200ae2e0b517d1549ba945475afae61 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -24326,6 +24326,21 @@
@@ -21997,6 +21997,21 @@
]
}
],

View File

@@ -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 1416e23beb20e7c18b5cfa61f922c68b7ce65c48..49f9f583c3261fe4d7036f9a91ec8c651a191858 100644
index 6d53d5eee871613dc885c4faa1c7dfd8372a3a4b..1593b0104855f17628fdc30f9dd59e6c4aa58188 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1138,11 +1138,11 @@ bool RenderThreadImpl::IsLcdTextEnabled() {
@@ -1132,11 +1132,11 @@ bool RenderThreadImpl::IsLcdTextEnabled() {
}
bool RenderThreadImpl::IsElasticOverscrollEnabledOnRoot() {

View File

@@ -22,7 +22,7 @@ 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 51207bea3a7f345e38503f50e25e60ea0425a1a5..c78e0dcfadcacc68f4d4c2e818e67f19dfba1a5c 100644
index c56d8ce7b8d346357ad9f8293b252eaae0c8655d..a5826fd8d3ae43d0fcd3190f28ecb20ceeade474 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1956,6 +1956,10 @@ bool RenderProcessHostImpl::Init() {

View File

@@ -9,10 +9,10 @@ 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 6a2444ad5d20164be9877cf6b856d2bf762dcd26..13a7c72b8e728ebe6e4fb3aa7af7ae5e652256d5 100644
index 16c4c2f73643314a9b8287e13a6472dff2671652..859643e7796440bf1966007c598effffba7e47c9 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4192,6 +4192,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
@@ -4203,6 +4203,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
params.main_frame_name, GetOpener(), primary_main_frame_policy,
base::UnguessableToken::Create());
@@ -26,7 +26,7 @@ index 6a2444ad5d20164be9877cf6b856d2bf762dcd26..13a7c72b8e728ebe6e4fb3aa7af7ae5e
std::unique_ptr<WebContentsViewDelegate> delegate =
GetContentClient()->browser()->GetWebContentsViewDelegate(this);
@@ -4202,6 +4209,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
@@ -4213,6 +4220,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
view_ = CreateWebContentsView(this, std::move(delegate),
&render_view_host_delegate_view_);
}
@@ -35,10 +35,10 @@ index 6a2444ad5d20164be9877cf6b856d2bf762dcd26..13a7c72b8e728ebe6e4fb3aa7af7ae5e
CHECK(view_.get());
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index f071103d3b15d46c96dc193bdbd657e00eb1083e..b0c7360c88bca2f0b3e902c14ade90cf11b17184 100644
index a02a9134feae75d4fe95f2d8163983bdec447b2b..055302c00a625f4570c57243be3bd0ae02a73347 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -129,11 +129,14 @@ class PrerenderHandle;
@@ -130,11 +130,14 @@ class PrerenderHandle;
class RenderFrameHost;
class RenderViewHost;
class RenderWidgetHost;
@@ -53,7 +53,7 @@ index f071103d3b15d46c96dc193bdbd657e00eb1083e..b0c7360c88bca2f0b3e902c14ade90cf
class WebUI;
struct DropData;
struct GlobalRenderFrameHostId;
@@ -291,6 +294,10 @@ class WebContents : public PageNavigator, public base::SupportsUserData {
@@ -296,6 +299,10 @@ class WebContents : public PageNavigator, public base::SupportsUserData {
network::mojom::WebSandboxFlags starting_sandbox_flags =
network::mojom::WebSandboxFlags::kNone;

View File

@@ -15,10 +15,10 @@ 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 f92fc4bbddd99bcd4b3e38d59e8c8df4ef6f59e4..cc07391a5901cb3823eb08c9487b0e90d7250fb1 100644
index 43d64ce77ce86b961bbfd0e0e661577dae0708ca..de6a1722a3dd3879549822893624dd5c4b8e33f6 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -9179,6 +9179,17 @@ void RenderFrameHostImpl::EnterFullscreen(
@@ -9189,6 +9189,17 @@ void RenderFrameHostImpl::EnterFullscreen(
}
}
@@ -37,10 +37,10 @@ index f92fc4bbddd99bcd4b3e38d59e8c8df4ef6f59e4..cc07391a5901cb3823eb08c9487b0e90
if (had_fullscreen_token && !GetView()->HasFocus()) {
GetView()->Focus();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 13a7c72b8e728ebe6e4fb3aa7af7ae5e652256d5..3413e339934bab9df03d241213d27221bb5eaa20 100644
index 859643e7796440bf1966007c598effffba7e47c9..76def190aabe280bb8e0971dc5c72643bbce8f53 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4492,21 +4492,25 @@ KeyboardEventProcessingResult WebContentsImpl::PreHandleKeyboardEvent(
@@ -4503,21 +4503,25 @@ KeyboardEventProcessingResult WebContentsImpl::PreHandleKeyboardEvent(
const input::NativeWebKeyboardEvent& event) {
OPTIONAL_TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("content.verbose"),
"WebContentsImpl::PreHandleKeyboardEvent");
@@ -80,7 +80,7 @@ index 13a7c72b8e728ebe6e4fb3aa7af7ae5e652256d5..3413e339934bab9df03d241213d27221
}
bool WebContentsImpl::HandleMouseEvent(const blink::WebMouseEvent& event) {
@@ -4682,7 +4686,7 @@ void WebContentsImpl::EnterFullscreenMode(
@@ -4690,7 +4694,7 @@ void WebContentsImpl::EnterFullscreenMode(
OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::EnterFullscreenMode");
DCHECK(CanEnterFullscreenMode(requesting_frame));
DCHECK(requesting_frame->IsActive());

View File

@@ -1 +1,2 @@
chore_expose_ui_to_allow_electron_to_set_dock_side.patch
fix_prefer_browser_runtime_over_node_in_hostruntime_detection.patch

View File

@@ -10,10 +10,10 @@ to handle this without patching, but this is fairly clean for now and no longer
patching legacy devtools code.
diff --git a/front_end/entrypoints/main/MainImpl.ts b/front_end/entrypoints/main/MainImpl.ts
index 61048eed79af294d250f5d01ac3f728e35f6f3e5..4c44415b01d779ad91da835e4de9737fbb310e65 100644
index f2554f8cabcfd0d0074e4e22de5de8716f1fcaf4..5b6c6056b575b14aa8b76d0238b4d83643db76f4 100644
--- a/front_end/entrypoints/main/MainImpl.ts
+++ b/front_end/entrypoints/main/MainImpl.ts
@@ -819,6 +819,8 @@ export class MainImpl {
@@ -818,6 +818,8 @@ export class MainImpl {
globalThis.Main = globalThis.Main || {};
// @ts-expect-error Exported for Tests.js
globalThis.Main.Main = MainImpl;

View File

@@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Thu, 12 Mar 2026 17:03:29 +0100
Subject: fix: prefer browser runtime over node in HostRuntime detection
In Electron, the `process` global is available in renderer processes,
including the DevTools renderer. This causes the IS_NODE check to pass,
leading DevTools to attempt importing the Node.js platform runtime
(which uses `node:worker_threads`). However, DevTools Web Workers
running under the `devtools://` protocol don't have access to Node.js
built-in modules, resulting in a failed dynamic import.
Fix by checking IS_BROWSER first, since DevTools always runs in a
browser-like environment. The Node.js runtime is only needed when
DevTools runs under pure Node.js (e.g., CLI tooling or testing).
diff --git a/front_end/core/platform/HostRuntime.ts b/front_end/core/platform/HostRuntime.ts
index 91adba7c966a9c4c0e5315d2cfee07f8f622b731..16822b8d4ea74a4ffd6870e5e95948d75918f5d2 100644
--- a/front_end/core/platform/HostRuntime.ts
+++ b/front_end/core/platform/HostRuntime.ts
@@ -14,12 +14,12 @@ export const IS_BROWSER =
typeof window !== 'undefined' || (typeof self !== 'undefined' && typeof self.postMessage === 'function');
export const HOST_RUNTIME = await (async(): Promise<Api.HostRuntime.HostRuntime> => {
- if (IS_NODE) {
- return (await import('./node/node.js')).HostRuntime.HOST_RUNTIME;
- }
if (IS_BROWSER) {
return (await import('./browser/browser.js')).HostRuntime.HOST_RUNTIME;
}
+ if (IS_NODE) {
+ return (await import('./node/node.js')).HostRuntime.HOST_RUNTIME;
+ }
throw new Error('Unknown runtime!');
})();

View File

@@ -17,7 +17,7 @@ Upstreams:
- https://github.com/nodejs/node/pull/39136
diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc
index 461819ce0fa732048e4365c40a86ef55d984c35f..fa55c980a9c4f373723a867fd41276d67b0b9413 100644
index 461819ce0fa732048e4365c40a86ef55d984c35f..f1c85e94cf526d0255f47c003664680d26413ec3 100644
--- a/deps/ncrypto/ncrypto.cc
+++ b/deps/ncrypto/ncrypto.cc
@@ -11,6 +11,7 @@
@@ -28,38 +28,6 @@ index 461819ce0fa732048e4365c40a86ef55d984c35f..fa55c980a9c4f373723a867fd41276d6
#if OPENSSL_VERSION_MAJOR >= 3
#include <openssl/core_names.h>
#include <openssl/params.h>
@@ -1130,7 +1131,9 @@ int64_t X509View::getValidToTime() const {
return tp;
#else
struct tm tp;
- ASN1_TIME_to_tm(X509_get0_notAfter(cert_), &tp);
+#ifndef OPENSSL_IS_BORINGSSL
+ ASN1_TIME_to_tm(X509_get0_notAfter(cert_), &tp);
+#endif
return PortableTimeGM(&tp);
#endif
}
@@ -1142,7 +1145,9 @@ int64_t X509View::getValidFromTime() const {
return tp;
#else
struct tm tp;
+#ifndef OPENSSL_IS_BORINGSSL
ASN1_TIME_to_tm(X509_get0_notBefore(cert_), &tp);
+#endif
return PortableTimeGM(&tp);
#endif
}
@@ -2886,10 +2891,6 @@ std::optional<uint32_t> SSLPointer::verifyPeerCertificate() const {
const char* SSLPointer::getClientHelloAlpn() const {
if (ssl_ == nullptr) return {};
#ifndef OPENSSL_IS_BORINGSSL
- const unsigned char* buf;
- size_t len;
- size_t rem;
-
if (!SSL_client_hello_get0_ext(
get(),
TLSEXT_TYPE_application_layer_protocol_negotiation,
@@ -3090,9 +3091,11 @@ const Cipher Cipher::AES_256_GCM = Cipher::FromNid(NID_aes_256_gcm);
const Cipher Cipher::AES_128_KW = Cipher::FromNid(NID_id_aes128_wrap);
const Cipher Cipher::AES_192_KW = Cipher::FromNid(NID_id_aes192_wrap);

View File

@@ -14,6 +14,7 @@ const args = minimist(process.argv.slice(2), {
const BASE = path.resolve(__dirname, '../..');
const ROOT_PACKAGE_JSON = path.resolve(BASE, 'package.json');
const NODE_DIR = path.resolve(BASE, 'third_party', 'electron_node');
const JUNIT_DIR = args.jUnitDir ? path.resolve(args.jUnitDir) : null;
const TAP_FILE_NAME = 'test.tap';
@@ -38,6 +39,18 @@ const defaultOptions = [
'-J'
];
// The root package.json is ESM, which breaks the test runner.
// Temporarily change it to CommonJS while running the tests, then
// change it back when done.
const resetPackageJson = ({ useESM }) => {
// This won't always exist in CI.
if (!fs.existsSync(ROOT_PACKAGE_JSON)) { return; }
const packageJson = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf-8'));
packageJson.type = useESM ? 'module' : 'commonjs';
fs.writeFileSync(ROOT_PACKAGE_JSON, JSON.stringify(packageJson, null, 2) + '\n');
};
const getCustomOptions = () => {
let customOptions = ['tools/test.py'];
@@ -79,6 +92,8 @@ async function main () {
const options = args.default ? defaultOptions : getCustomOptions();
resetPackageJson({ useESM: false });
const testChild = cp.spawn('python3', options, {
env: {
...process.env,
@@ -88,7 +103,10 @@ async function main () {
cwd: NODE_DIR,
stdio: 'inherit'
});
testChild.on('exit', (testCode) => {
resetPackageJson({ useESM: true });
if (JUNIT_DIR) {
fs.mkdirSync(JUNIT_DIR);
const converterStream = require('tap-xunit')();

View File

@@ -5,6 +5,7 @@
#include "shell/browser/api/electron_api_notification.h"
#include "base/functional/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/uuid.h"
#include "build/build_config.h"
#include "content/public/browser/browser_task_traits.h"
@@ -13,10 +14,12 @@
#include "shell/browser/browser.h"
#include "shell/browser/electron_browser_client.h"
#include "shell/common/gin_converters/image_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/handle.h"
#include "shell/common/gin_helper/object_template_builder.h"
#include "shell/common/gin_helper/promise.h"
#include "shell/common/node_includes.h"
#include "url/gurl.h"
@@ -72,21 +75,28 @@ Notification::Notification(gin::Arguments* args) {
presenter_ = static_cast<ElectronBrowserClient*>(ElectronBrowserClient::Get())
->GetNotificationPresenter();
gin::Dictionary opts(nullptr);
if (args->GetNext(&opts)) {
opts.Get("title", &title_);
opts.Get("subtitle", &subtitle_);
opts.Get("body", &body_);
opts.Get("icon", &icon_);
opts.Get("silent", &silent_);
opts.Get("replyPlaceholder", &reply_placeholder_);
opts.Get("urgency", &urgency_);
opts.Get("hasReply", &has_reply_);
opts.Get("timeoutType", &timeout_type_);
opts.Get("actions", &actions_);
opts.Get("sound", &sound_);
opts.Get("closeButtonText", &close_button_text_);
opts.Get("toastXml", &toast_xml_);
if (args) {
gin::Dictionary opts(nullptr);
if (args->GetNext(&opts)) {
opts.Get("id", &id_);
opts.Get("groupId", &group_id_);
opts.Get("title", &title_);
opts.Get("subtitle", &subtitle_);
opts.Get("body", &body_);
opts.Get("icon", &icon_);
opts.Get("silent", &silent_);
opts.Get("replyPlaceholder", &reply_placeholder_);
opts.Get("urgency", &urgency_);
opts.Get("hasReply", &has_reply_);
opts.Get("timeoutType", &timeout_type_);
opts.Get("actions", &actions_);
opts.Get("sound", &sound_);
opts.Get("closeButtonText", &close_button_text_);
opts.Get("toastXml", &toast_xml_);
}
if (id_.empty())
id_ = base::Uuid::GenerateRandomV4().AsLowercaseString();
}
}
@@ -236,8 +246,7 @@ void Notification::Close() {
void Notification::Show() {
Close();
if (presenter_) {
notification_ = presenter_->CreateNotification(
this, base::Uuid::GenerateRandomV4().AsLowercaseString());
notification_ = presenter_->CreateNotification(this, id_);
if (notification_) {
electron::NotificationOptions options;
options.title = title_;
@@ -254,6 +263,7 @@ void Notification::Show() {
options.close_button_text = close_button_text_;
options.urgency = urgency_;
options.toast_xml = toast_xml_;
options.group_id = group_id_;
notification_->Show(options);
}
}
@@ -337,11 +347,122 @@ void Notification::HandleActivation(v8::Isolate* isolate,
}
#endif
// static
v8::Local<v8::Promise> Notification::GetHistory(v8::Isolate* isolate) {
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
auto* presenter =
static_cast<ElectronBrowserClient*>(ElectronBrowserClient::Get())
->GetNotificationPresenter();
if (!presenter) {
promise.Resolve(v8::Array::New(isolate));
return handle;
}
presenter->GetDeliveredNotifications(base::BindOnce(
[](gin_helper::Promise<v8::Local<v8::Value>> promise,
electron::NotificationPresenter* presenter,
std::vector<electron::NotificationInfo> notifications) {
v8::Isolate* isolate = promise.isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Array> result =
v8::Array::New(isolate, notifications.size());
for (size_t i = 0; i < notifications.size(); i++) {
const auto& info = notifications[i];
// Create a live Notification object for each delivered notification.
auto* notif = new Notification(/*args=*/nullptr);
notif->id_ = info.id;
notif->group_id_ = info.group_id;
notif->title_ = base::UTF8ToUTF16(info.title);
notif->subtitle_ = base::UTF8ToUTF16(info.subtitle);
notif->body_ = base::UTF8ToUTF16(info.body);
// Register with the presenter so click/reply events route here.
if (presenter) {
notif->notification_ =
presenter->CreateNotification(notif, notif->id_);
if (notif->notification_)
notif->notification_->Restore();
}
auto handle = gin_helper::CreateHandle(isolate, notif);
result
->Set(isolate->GetCurrentContext(), static_cast<uint32_t>(i),
handle.ToV8())
.Check();
}
promise.Resolve(result.As<v8::Value>());
},
std::move(promise), presenter));
return handle;
}
// static
void Notification::Remove(gin::Arguments* args) {
auto* presenter =
static_cast<ElectronBrowserClient*>(ElectronBrowserClient::Get())
->GetNotificationPresenter();
if (!presenter)
return;
// Accept either a single string or an array of strings.
// Peek at the value type first to avoid gin::Arguments cursor issues.
v8::Local<v8::Value> val;
if (!args->GetNext(&val)) {
args->ThrowTypeError("Expected a string or array of strings");
return;
}
if (val->IsString()) {
std::string id;
gin::ConvertFromV8(args->isolate(), val, &id);
presenter->RemoveDeliveredNotifications({id});
} else if (val->IsArray()) {
std::vector<std::string> ids;
if (!gin::ConvertFromV8(args->isolate(), val, &ids)) {
args->ThrowTypeError("Expected a string or array of strings");
return;
}
presenter->RemoveDeliveredNotifications(ids);
} else {
args->ThrowTypeError("Expected a string or array of strings");
}
}
// static
void Notification::RemoveAll() {
auto* presenter =
static_cast<ElectronBrowserClient*>(ElectronBrowserClient::Get())
->GetNotificationPresenter();
if (!presenter)
return;
presenter->RemoveAllDeliveredNotifications();
}
// static
void Notification::RemoveGroup(const std::string& group_id) {
auto* presenter =
static_cast<ElectronBrowserClient*>(ElectronBrowserClient::Get())
->GetNotificationPresenter();
if (!presenter)
return;
presenter->RemoveDeliveredNotificationsByGroupId(group_id);
}
void Notification::FillObjectTemplate(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> templ) {
gin::ObjectTemplateBuilder(isolate, GetClassName(), templ)
.SetMethod("show", &Notification::Show)
.SetMethod("close", &Notification::Close)
.SetProperty("id", &Notification::id)
.SetProperty("groupId", &Notification::group_id)
.SetProperty("title", &Notification::title, &Notification::SetTitle)
.SetProperty("subtitle", &Notification::subtitle,
&Notification::SetSubtitle)
@@ -388,6 +509,10 @@ void Initialize(v8::Local<v8::Object> exports,
#if BUILDFLAG(IS_WIN)
dict.SetMethod("handleActivation", &Notification::HandleActivation);
#endif
dict.SetMethod("getHistory", &Notification::GetHistory);
dict.SetMethod("remove", &Notification::Remove);
dict.SetMethod("removeAll", &Notification::RemoveAll);
dict.SetMethod("removeGroup", &Notification::RemoveGroup);
}
} // namespace

View File

@@ -38,6 +38,10 @@ class Notification final : public gin_helper::DeprecatedWrappable<Notification>,
public NotificationDelegate {
public:
static bool IsSupported();
static v8::Local<v8::Promise> GetHistory(v8::Isolate* isolate);
static void Remove(gin::Arguments* args);
static void RemoveAll();
static void RemoveGroup(const std::string& group_id);
#if BUILDFLAG(IS_WIN)
// Register a callback to handle all notification activations.
@@ -83,6 +87,8 @@ class Notification final : public gin_helper::DeprecatedWrappable<Notification>,
void Close();
// Prop Getters
const std::string& id() const { return id_; }
const std::string& group_id() const { return group_id_; }
const std::u16string& title() const { return title_; }
const std::u16string& subtitle() const { return subtitle_; }
const std::u16string& body() const { return body_; }
@@ -113,6 +119,8 @@ class Notification final : public gin_helper::DeprecatedWrappable<Notification>,
void SetToastXml(const std::u16string& new_toast_xml);
private:
std::string id_;
std::string group_id_;
std::u16string title_;
std::u16string subtitle_;
std::u16string body_;

View File

@@ -47,6 +47,7 @@
#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/child_process_id.h"
#include "content/public/common/content_descriptors.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
@@ -1465,7 +1466,8 @@ void ElectronBrowserClient::RegisterAssociatedInterfaceBindersForServiceWorker(
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
associated_registry.AddInterface<extensions::mojom::RendererHost>(
base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
service_worker_version_info.process_id));
content::ChildProcessId::FromUnsafeValue(
service_worker_version_info.process_id)));
associated_registry.AddInterface<extensions::mojom::ServiceWorkerHost>(
base::BindRepeating(&extensions::ServiceWorkerHost::BindReceiver,
service_worker_version_info.process_id));
@@ -1540,7 +1542,8 @@ void ElectronBrowserClient::
&render_frame_host));
#endif
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
int render_process_id = render_frame_host.GetProcess()->GetDeprecatedID();
content::ChildProcessId render_process_id =
render_frame_host.GetProcess()->GetID();
associated_registry.AddInterface<extensions::mojom::EventRouter>(
base::BindRepeating(&extensions::EventRouter::BindForRenderer,
render_process_id));
@@ -1639,7 +1642,7 @@ void ElectronBrowserClient::ExposeInterfacesToRenderer(
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
associated_registry->AddInterface<extensions::mojom::RendererHost>(
base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
render_process_host->GetDeprecatedID()));
render_process_host->GetID()));
#endif
}

View File

@@ -29,7 +29,8 @@ void ElectronExtensionHostDelegate::OnExtensionHostCreated(
void ElectronExtensionHostDelegate::CreateTab(
std::unique_ptr<content::WebContents> web_contents,
const std::string& extension_id,
const GURL& target_url,
const ExtensionId& extension_id,
WindowOpenDisposition disposition,
const blink::mojom::WindowFeatures& window_features,
bool user_gesture) {

View File

@@ -26,7 +26,8 @@ class ElectronExtensionHostDelegate : public ExtensionHostDelegate {
// ExtensionHostDelegate implementation.
void OnExtensionHostCreated(content::WebContents* web_contents) override;
void CreateTab(std::unique_ptr<content::WebContents> web_contents,
const std::string& extension_id,
const GURL& target_url,
const ExtensionId& extension_id,
WindowOpenDisposition disposition,
const blink::mojom::WindowFeatures& window_features,
bool user_gesture) override;

View File

@@ -28,7 +28,6 @@
namespace electron {
class RootViewMac;
class NativeAppWindowFrameViewMacClient;
class NativeWindowMac : public NativeWindow,
public ui::NativeThemeObserver,
@@ -254,6 +253,8 @@ class NativeWindowMac : public NativeWindow,
void UpdateZoomButton();
std::optional<int> FrameViewNonClientHitTest(const gfx::Point& point);
ElectronNSWindow* window_; // Weak ref, managed by widget_.
ElectronNSWindowDelegate* __strong window_delegate_;
@@ -318,9 +319,6 @@ class NativeWindowMac : public NativeWindow,
// The presentation options before entering simple fullscreen mode.
NSApplicationPresentationOptions simple_fullscreen_options_;
// Client that provides app-specific frame behaviors to NativeFrameViewMac.
std::unique_ptr<NativeAppWindowFrameViewMacClient> frame_view_client_;
};
} // namespace electron

View File

@@ -114,41 +114,6 @@ struct Converter<electron::NativeWindowMac::VisualEffectState> {
namespace electron {
class NativeAppWindowFrameViewMacClient
: public views::NativeFrameViewMacClient {
public:
NativeAppWindowFrameViewMacClient(views::Widget* frame,
NativeWindowMac* window)
: frame_(frame), native_app_window_(window) {}
NativeAppWindowFrameViewMacClient(const NativeAppWindowFrameViewMacClient&) =
delete;
NativeAppWindowFrameViewMacClient& operator=(
const NativeAppWindowFrameViewMacClient&) = delete;
~NativeAppWindowFrameViewMacClient() override = default;
std::optional<int> NonClientHitTest(const gfx::Point& point) override {
if (frame_->IsFullscreen()) {
return HTCLIENT;
}
// Check for possible draggable region in the client area for the frameless
// window.
int contents_hit_test = native_app_window_->NonClientHitTest(point);
if (contents_hit_test != HTNOWHERE)
return contents_hit_test;
return HTCLIENT;
}
private:
const raw_ptr<views::Widget> frame_;
// Weak. Owned by extensions::AppWindow (which manages our Widget via its
// WebContents).
const raw_ptr<NativeWindowMac, DanglingUntriaged> native_app_window_;
};
NativeWindowMac::~NativeWindowMac() = default;
NativeWindowMac::NativeWindowMac(const int32_t base_window_id,
@@ -1734,11 +1699,25 @@ void NativeWindowMac::Cleanup() {
std::unique_ptr<views::FrameView> NativeWindowMac::CreateFrameView(
views::Widget* widget) {
CHECK(!frame_view_client_);
frame_view_client_ =
std::make_unique<NativeAppWindowFrameViewMacClient>(widget, this);
return std::make_unique<views::NativeFrameViewMac>(widget,
frame_view_client_.get());
auto frame_view = std::make_unique<views::NativeFrameViewMac>(widget);
frame_view->set_non_client_hit_test_callback(base::BindRepeating(
&NativeWindowMac::FrameViewNonClientHitTest, base::Unretained(this)));
return frame_view;
}
std::optional<int> NativeWindowMac::FrameViewNonClientHitTest(
const gfx::Point& point) {
if (widget()->IsFullscreen()) {
return HTCLIENT;
}
// Check for possible draggable region in the client area for the frameless
// window.
int contents_hit_test = NonClientHitTest(point);
if (contents_hit_test != HTNOWHERE)
return contents_hit_test;
return HTCLIENT;
}
bool NativeWindowMac::HasStyleMask(NSUInteger flag) const {

View File

@@ -1018,17 +1018,13 @@ void NativeWindowViews::MoveTop() {
bool NativeWindowViews::CanResize() const {
#if BUILDFLAG(IS_WIN)
return resizable_ && thick_frame_;
return has_frame() ? resizable_ && thick_frame_ : resizable_;
#else
return resizable_;
#endif
}
bool NativeWindowViews::IsResizable() const {
#if BUILDFLAG(IS_WIN)
if (has_frame())
return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME;
#endif
return CanResize();
}

View File

@@ -24,6 +24,7 @@ class CocoaNotification : public Notification {
// Notification:
void Show(const NotificationOptions& options) override;
void Dismiss() override;
void Restore() override;
void NotificationDisplayed();
void NotificationReplied(const std::string& reply);
@@ -38,6 +39,7 @@ class CocoaNotification : public Notification {
void LogAction(const char* action);
void ScheduleNotification(UNMutableNotificationContent* content);
bool is_restored_ = false;
UNNotificationRequest* __strong notification_request_;
};

View File

@@ -31,7 +31,10 @@ CocoaNotification::CocoaNotification(NotificationDelegate* delegate,
: Notification(delegate, presenter) {}
CocoaNotification::~CocoaNotification() {
if (notification_request_)
// Don't remove from Notification Center if this was a restored notification.
// Restored notifications are observed, not owned — destruction should just
// disconnect the event handler, not remove the visible notification.
if (notification_request_ && !is_restored_)
[[UNUserNotificationCenter currentNotificationCenter]
removeDeliveredNotificationsWithIdentifiers:@[
notification_request_.identifier
@@ -46,6 +49,10 @@ void CocoaNotification::Show(const NotificationOptions& options) {
content.subtitle = base::SysUTF16ToNSString(options.subtitle);
content.body = base::SysUTF16ToNSString(options.msg);
if (!options.group_id.empty()) {
content.threadIdentifier = base::SysUTF8ToNSString(options.group_id);
}
if (options.silent) {
content.sound = nil;
} else if (options.sound.empty()) {
@@ -174,10 +181,7 @@ void CocoaNotification::Show(const NotificationOptions& options) {
void CocoaNotification::ScheduleNotification(
UNMutableNotificationContent* content) {
NSString* identifier =
[NSString stringWithFormat:@"%@:notification:%@",
[[NSBundle mainBundle] bundleIdentifier],
[[NSUUID UUID] UUIDString]];
NSString* identifier = base::SysUTF8ToNSString(notification_id());
UNNotificationRequest* request =
[UNNotificationRequest requestWithIdentifier:identifier
@@ -232,6 +236,24 @@ void CocoaNotification::ScheduleNotification(
}];
}
void CocoaNotification::Restore() {
// Create a minimal UNNotificationRequest with just the identifier so that
// GetNotification() can match this object when the user interacts with the
// notification in Notification Center.
NSString* identifier = base::SysUTF8ToNSString(notification_id());
UNMutableNotificationContent* content =
[[UNMutableNotificationContent alloc] init];
notification_request_ =
[UNNotificationRequest requestWithIdentifier:identifier
content:content
trigger:nil];
is_restored_ = true;
if (electron::debug_notifications) {
LOG(INFO) << "Notification restored (" << [identifier UTF8String] << ")";
}
}
void CocoaNotification::Dismiss() {
if (notification_request_)
[[UNUserNotificationCenter currentNotificationCenter]

View File

@@ -24,6 +24,15 @@ class NotificationPresenterMac : public NotificationPresenter {
NotificationPresenterMac();
~NotificationPresenterMac() override;
// NotificationPresenter
void GetDeliveredNotifications(
GetDeliveredNotificationsCallback callback) override;
void RemoveDeliveredNotifications(
const std::vector<std::string>& identifiers) override;
void RemoveAllDeliveredNotifications() override;
void RemoveDeliveredNotificationsByGroupId(
const std::string& group_id) override;
NotificationImageRetainer* image_retainer() { return image_retainer_.get(); }
scoped_refptr<base::SequencedTaskRunner> image_task_runner() {
return image_task_runner_;

View File

@@ -2,11 +2,16 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "base/logging.h"
#include "base/task/thread_pool.h"
#include "shell/browser/notifications/mac/notification_presenter_mac.h"
#include <string>
#include <utility>
#include <vector>
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "shell/browser/notifications/mac/cocoa_notification.h"
#include "shell/browser/notifications/mac/notification_center_delegate.h"
@@ -80,4 +85,72 @@ Notification* NotificationPresenterMac::CreateNotificationObject(
return new CocoaNotification(delegate, this);
}
void NotificationPresenterMac::GetDeliveredNotifications(
GetDeliveredNotificationsCallback callback) {
scoped_refptr<base::SequencedTaskRunner> task_runner =
base::SequencedTaskRunner::GetCurrentDefault();
__block GetDeliveredNotificationsCallback block_callback =
std::move(callback);
[[UNUserNotificationCenter currentNotificationCenter]
getDeliveredNotificationsWithCompletionHandler:^(
NSArray<UNNotification*>* _Nonnull notifications) {
std::vector<NotificationInfo> results;
results.reserve([notifications count]);
for (UNNotification* notification in notifications) {
UNNotificationContent* content = notification.request.content;
NotificationInfo info;
info.id = base::SysNSStringToUTF8(notification.request.identifier);
info.title = base::SysNSStringToUTF8(content.title);
info.subtitle = base::SysNSStringToUTF8(content.subtitle);
info.body = base::SysNSStringToUTF8(content.body);
info.group_id = base::SysNSStringToUTF8(content.threadIdentifier);
results.push_back(std::move(info));
}
task_runner->PostTask(
FROM_HERE,
base::BindOnce(std::move(block_callback), std::move(results)));
}];
}
void NotificationPresenterMac::RemoveDeliveredNotifications(
const std::vector<std::string>& identifiers) {
NSMutableArray* ns_identifiers =
[NSMutableArray arrayWithCapacity:identifiers.size()];
for (const auto& id : identifiers) {
[ns_identifiers addObject:base::SysUTF8ToNSString(id)];
}
[[UNUserNotificationCenter currentNotificationCenter]
removeDeliveredNotificationsWithIdentifiers:ns_identifiers];
}
void NotificationPresenterMac::RemoveAllDeliveredNotifications() {
[[UNUserNotificationCenter currentNotificationCenter]
removeAllDeliveredNotifications];
}
void NotificationPresenterMac::RemoveDeliveredNotificationsByGroupId(
const std::string& group_id) {
NSString* target_group = base::SysUTF8ToNSString(group_id);
UNUserNotificationCenter* center =
[UNUserNotificationCenter currentNotificationCenter];
[center getDeliveredNotificationsWithCompletionHandler:^(
NSArray<UNNotification*>* _Nonnull notifications) {
NSMutableArray* matching_ids = [NSMutableArray array];
for (UNNotification* notification in notifications) {
if ([notification.request.content.threadIdentifier
isEqualToString:target_group]) {
[matching_ids addObject:notification.request.identifier];
}
}
if (matching_ids.count > 0) {
[center removeDeliveredNotificationsWithIdentifiers:matching_ids];
}
}];
}
} // namespace electron

View File

@@ -22,6 +22,15 @@ NotificationOptions& NotificationOptions::operator=(NotificationOptions&&) =
default;
NotificationOptions::~NotificationOptions() = default;
NotificationInfo::NotificationInfo() = default;
NotificationInfo::~NotificationInfo() = default;
NotificationInfo::NotificationInfo(const NotificationInfo&) = default;
NotificationInfo& NotificationInfo::operator=(const NotificationInfo&) =
default;
NotificationInfo::NotificationInfo(NotificationInfo&&) noexcept = default;
NotificationInfo& NotificationInfo::operator=(NotificationInfo&&) noexcept =
default;
NotificationAction::NotificationAction() = default;
NotificationAction::~NotificationAction() = default;
NotificationAction::NotificationAction(const NotificationAction&) = default;

View File

@@ -45,10 +45,11 @@ struct NotificationOptions {
std::u16string timeout_type;
std::u16string reply_placeholder;
std::u16string sound;
std::u16string urgency; // Linux/Windows
std::u16string urgency; // Linux
std::vector<NotificationAction> actions;
std::u16string close_button_text;
std::u16string toast_xml;
std::string group_id;
NotificationOptions();
NotificationOptions(const NotificationOptions&);
@@ -58,6 +59,21 @@ struct NotificationOptions {
~NotificationOptions();
};
struct NotificationInfo {
std::string id;
std::string title;
std::string subtitle;
std::string body;
std::string group_id;
NotificationInfo();
~NotificationInfo();
NotificationInfo(const NotificationInfo&);
NotificationInfo& operator=(const NotificationInfo&);
NotificationInfo(NotificationInfo&&) noexcept;
NotificationInfo& operator=(NotificationInfo&&) noexcept;
};
class Notification {
public:
virtual ~Notification();
@@ -74,6 +90,11 @@ class Notification {
// as can happen on some platforms including Windows.
virtual void Remove() {}
// Restores a previously delivered notification for event handling without
// re-showing it. Sets up platform state so interaction events (click, reply,
// etc.) route to this object.
virtual void Restore() {}
// Should be called by derived classes.
void NotificationClicked();
void NotificationDismissed(bool should_destroy = true,

View File

@@ -44,4 +44,24 @@ void NotificationPresenter::CloseNotificationWithId(
}
}
void NotificationPresenter::GetDeliveredNotifications(
GetDeliveredNotificationsCallback callback) {
// Default: return empty list. Overridden on macOS.
std::move(callback).Run({});
}
void NotificationPresenter::RemoveDeliveredNotifications(
const std::vector<std::string>& identifiers) {
// Default: no-op. Overridden on macOS.
}
void NotificationPresenter::RemoveAllDeliveredNotifications() {
// Default: no-op. Overridden on macOS.
}
void NotificationPresenter::RemoveDeliveredNotificationsByGroupId(
const std::string& group_id) {
// Default: no-op. Overridden on macOS.
}
} // namespace electron

View File

@@ -8,12 +8,14 @@
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "shell/browser/notifications/notification.h"
namespace electron {
class Notification;
class NotificationDelegate;
class NotificationPresenter {
@@ -22,11 +24,22 @@ class NotificationPresenter {
virtual ~NotificationPresenter();
using GetDeliveredNotificationsCallback =
base::OnceCallback<void(std::vector<NotificationInfo>)>;
base::WeakPtr<Notification> CreateNotification(
NotificationDelegate* delegate,
const std::string& notification_id);
void CloseNotificationWithId(const std::string& notification_id);
virtual void GetDeliveredNotifications(
GetDeliveredNotificationsCallback callback);
virtual void RemoveDeliveredNotifications(
const std::vector<std::string>& identifiers);
virtual void RemoveAllDeliveredNotifications();
virtual void RemoveDeliveredNotificationsByGroupId(
const std::string& group_id);
std::set<Notification*> notifications() const { return notifications_; }
// disable copy

View File

@@ -280,9 +280,8 @@ void WindowsToastNotification::CreateToastNotificationOnBackgroundThread(
// Continue to create the toast notification
ComPtr<ABI::Windows::UI::Notifications::IToastNotification>
toast_notification;
if (!CreateToastNotification(toast_xml, options, notification_id,
weak_notification, ui_task_runner,
&toast_notification)) {
if (!CreateToastNotification(toast_xml, notification_id, weak_notification,
ui_task_runner, &toast_notification)) {
return; // Error already posted to UI thread
}
@@ -350,7 +349,6 @@ bool WindowsToastNotification::CreateToastXmlDocument(
// returns the created notification via out parameter.
bool WindowsToastNotification::CreateToastNotification(
ComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocument> toast_xml,
const NotificationOptions& options,
const std::string& notification_id,
base::WeakPtr<Notification> weak_notification,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
@@ -418,27 +416,6 @@ bool WindowsToastNotification::CreateToastNotification(
return false;
}
ComPtr<winui::Notifications::IToastNotification4> toast4;
hr = (*toast_notification)->QueryInterface(IID_PPV_ARGS(&toast4));
if (SUCCEEDED(hr)) {
winui::Notifications::ToastNotificationPriority priority =
winui::Notifications::ToastNotificationPriority::
ToastNotificationPriority_Default;
if (options.urgency == u"critical") {
priority = winui::Notifications::ToastNotificationPriority::
ToastNotificationPriority_High;
}
hr = toast4->put_Priority(priority);
if (FAILED(hr)) {
std::string err = base::StrCat({"WinAPI: Setting priority failed, ERROR ",
FailureResultToString(hr)});
DebugLog(err);
PostNotificationFailedToUIThread(weak_notification, err, ui_task_runner);
return false;
}
}
return true;
}

View File

@@ -94,7 +94,6 @@ class WindowsToastNotification : public Notification {
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
static bool CreateToastNotification(
ComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocument> toast_xml,
const NotificationOptions& options,
const std::string& notification_id,
base::WeakPtr<Notification> weak_notification,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,

View File

@@ -6,6 +6,7 @@
#include <map>
#include "base/containers/flat_set.h"
#include "base/containers/to_vector.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
@@ -32,6 +33,25 @@ namespace {
: ui::ClipboardBuffer::kCopyPaste;
}
bool IsFormatAvailable(ui::Clipboard* clipboard,
const ui::ClipboardFormatType& format,
ui::ClipboardBuffer buffer) {
base::flat_set<ui::ClipboardFormatType> formats;
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
clipboard->GetAllAvailableFormats(
buffer, /* data_dst = */ std::nullopt,
base::BindOnce(
[](base::flat_set<ui::ClipboardFormatType>* out,
base::OnceClosure quit,
base::flat_set<ui::ClipboardFormatType> result) {
*out = std::move(result);
std::move(quit).Run();
},
&formats, run_loop.QuitClosure()));
run_loop.Run();
return formats.contains(format);
}
} // namespace
namespace electron::api {
@@ -64,8 +84,7 @@ bool Clipboard::Has(const std::string& format_string,
ui::ClipboardFormatType::CustomPlatformType(format_string);
if (format.GetName().empty())
format = ui::ClipboardFormatType::CustomPlatformType(format_string);
return clipboard->IsFormatAvailable(format, GetClipboardBuffer(args),
/* data_dst = */ nullptr);
return IsFormatAvailable(clipboard, format, GetClipboardBuffer(args));
}
std::string Clipboard::Read(const std::string& format_string) {
@@ -73,12 +92,12 @@ std::string Clipboard::Read(const std::string& format_string) {
// Prefer raw platform format names
ui::ClipboardFormatType rawFormat(
ui::ClipboardFormatType::CustomPlatformType(format_string));
bool rawFormatAvailable = clipboard->IsFormatAvailable(
rawFormat, ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr);
bool rawFormatAvailable =
IsFormatAvailable(clipboard, rawFormat, ui::ClipboardBuffer::kCopyPaste);
#if BUILDFLAG(IS_LINUX)
if (!rawFormatAvailable) {
rawFormatAvailable = clipboard->IsFormatAvailable(
rawFormat, ui::ClipboardBuffer::kSelection, /* data_dst = */ nullptr);
rawFormatAvailable = IsFormatAvailable(clipboard, rawFormat,
ui::ClipboardBuffer::kSelection);
}
#endif
if (rawFormatAvailable) {
@@ -210,8 +229,8 @@ std::u16string Clipboard::ReadText(gin::Arguments* const args) {
std::u16string data;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
auto type = GetClipboardBuffer(args);
if (clipboard->IsFormatAvailable(ui::ClipboardFormatType::PlainTextType(),
type, /* data_dst = */ nullptr)) {
if (IsFormatAvailable(clipboard, ui::ClipboardFormatType::PlainTextType(),
type)) {
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
clipboard->ReadText(type,
/* data_dst = */ std::nullopt,
@@ -225,9 +244,8 @@ std::u16string Clipboard::ReadText(gin::Arguments* const args) {
run_loop.Run();
} else {
#if BUILDFLAG(IS_WIN)
if (clipboard->IsFormatAvailable(ui::ClipboardFormatType::PlainTextAType(),
type,
/* data_dst = */ nullptr)) {
if (IsFormatAvailable(clipboard, ui::ClipboardFormatType::PlainTextAType(),
type)) {
std::string result;
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
clipboard->ReadAsciiText(

View File

@@ -5611,7 +5611,7 @@ describe('BrowserWindow module', () => {
thickFrame: true,
transparent: true
});
expect(w.isResizable()).to.be.false('resizable');
expect(w.isResizable()).to.be.true('resizable');
w.maximize();
expect(w.isMaximized()).to.be.true('maximized');
const bounds = w.getBounds();

View File

@@ -15,6 +15,75 @@ describe('Notification module', () => {
expect(Notification.isSupported()).to.be.a('boolean');
});
ifit(process.platform === 'darwin')('inits and gets id property', () => {
const n = new Notification({
id: 'my-custom-id',
title: 'title',
body: 'body'
});
expect(n.id).to.equal('my-custom-id');
});
ifit(process.platform === 'darwin')('id is read-only', () => {
const n = new Notification({
id: 'my-custom-id',
title: 'title',
body: 'body'
});
expect(() => { (n as any).id = 'new-id'; }).to.throw();
});
ifit(process.platform === 'darwin')('defaults id to a UUID when not provided', () => {
const n = new Notification({
title: 'title',
body: 'body'
});
expect(n.id).to.be.a('string').and.not.be.empty();
expect(n.id).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
});
ifit(process.platform === 'darwin')('defaults id to a UUID when empty string is provided', () => {
const n = new Notification({
id: '',
title: 'title',
body: 'body'
});
expect(n.id).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
});
ifit(process.platform === 'darwin')('inits and gets groupId property', () => {
const n = new Notification({
title: 'title',
body: 'body',
groupId: 'E017VKL2N8H|C07RBMNS9EK'
});
expect(n.groupId).to.equal('E017VKL2N8H|C07RBMNS9EK');
});
ifit(process.platform === 'darwin')('groupId is read-only', () => {
const n = new Notification({
title: 'title',
body: 'body',
groupId: 'E017VKL2N8H|C07RBMNS9EK'
});
expect(() => { (n as any).groupId = 'new-group'; }).to.throw();
});
ifit(process.platform === 'darwin')('defaults groupId to empty string when not provided', () => {
const n = new Notification({
title: 'title',
body: 'body'
});
expect(n.groupId).to.equal('');
});
it('inits, gets and sets basic string properties correctly', () => {
const n = new Notification({
title: 'title',
@@ -141,6 +210,45 @@ describe('Notification module', () => {
}
});
ifit(process.platform === 'darwin')('emits show and close events with custom id', async () => {
const n = new Notification({
id: 'test-custom-id',
title: 'test notification',
body: 'test body',
silent: true
});
{
const e = once(n, 'show');
n.show();
await e;
}
{
const e = once(n, 'close');
n.close();
await e;
}
});
ifit(process.platform === 'darwin')('emits show and close events with custom id and groupId', async () => {
const n = new Notification({
id: 'E017VKL2N8H|C07RBMNS9EK|1772656675.039',
groupId: 'E017VKL2N8H|C07RBMNS9EK',
title: 'test notification',
body: 'test body',
silent: true
});
{
const e = once(n, 'show');
n.show();
await e;
}
{
const e = once(n, 'close');
n.close();
await e;
}
});
ifit(process.platform === 'win32')('emits failed event', async () => {
const n = new Notification({
toastXml: 'not xml'
@@ -153,4 +261,223 @@ describe('Notification module', () => {
});
// TODO(sethlu): Find way to test init with notification icon?
describe('static methods', () => {
ifit(process.platform === 'darwin')('getHistory returns a promise that resolves to an array', async () => {
const result = Notification.getHistory();
expect(result).to.be.a('promise');
const history = await result;
expect(history).to.be.an('array');
});
ifit(process.platform === 'darwin')('remove does not throw with a string argument', () => {
expect(() => Notification.remove('nonexistent-id')).to.not.throw();
});
ifit(process.platform === 'darwin')('remove does not throw with an array argument', () => {
expect(() => Notification.remove(['id-1', 'id-2'])).to.not.throw();
});
ifit(process.platform === 'darwin')('remove throws with no arguments', () => {
expect(() => (Notification.remove as any)()).to.throw(/Expected a string or array of strings/);
});
ifit(process.platform === 'darwin')('remove throws with an invalid argument type', () => {
expect(() => (Notification.remove as any)(123)).to.throw(/Expected a string or array of strings/);
});
ifit(process.platform === 'darwin')('removeAll does not throw', () => {
expect(() => Notification.removeAll()).to.not.throw();
});
ifit(process.platform === 'darwin')('getHistory returns Notification instances with correct properties', async () => {
const n = new Notification({
id: 'history-test-id',
title: 'history test',
subtitle: 'history subtitle',
body: 'history body',
groupId: 'history-group',
silent: true
});
const shown = once(n, 'show');
n.show();
await shown;
const history = await Notification.getHistory();
// getHistory requires code-signed builds to return results;
// skip the content assertions if Notification Center is empty.
if (history.length > 0) {
const found = history.find((item: any) => item.id === 'history-test-id');
expect(found).to.not.be.undefined();
expect(found).to.be.an.instanceOf(Notification);
expect(found.title).to.equal('history test');
expect(found.subtitle).to.equal('history subtitle');
expect(found.body).to.equal('history body');
expect(found.groupId).to.equal('history-group');
}
n.close();
});
ifit(process.platform === 'darwin')('getHistory returned notifications can be shown and closed', async () => {
const n = new Notification({
id: 'history-show-close',
title: 'show close test',
body: 'body',
silent: true
});
const shown = once(n, 'show');
n.show();
await shown;
const history = await Notification.getHistory();
if (history.length > 0) {
const found = history.find((item: any) => item.id === 'history-show-close');
expect(found).to.not.be.undefined();
// Calling show() and close() on a restored notification should not throw
expect(() => {
found.show();
found.close();
}).to.not.throw();
}
Notification.removeAll();
});
ifit(process.platform === 'darwin')('remove removes a notification by id', async () => {
const n = new Notification({
id: 'remove-test-id',
title: 'remove test',
body: 'remove body',
silent: true
});
const shown = once(n, 'show');
n.show();
await shown;
Notification.remove('remove-test-id');
// Give the notification center a moment to process the removal
await new Promise(resolve => setTimeout(resolve, 100));
const history = await Notification.getHistory();
const found = history.find((item: any) => item.id === 'remove-test-id');
expect(found).to.be.undefined();
});
ifit(process.platform === 'darwin')('remove accepts an array of ids', async () => {
const n1 = new Notification({
id: 'remove-array-1',
title: 'test 1',
body: 'body 1',
silent: true
});
const n2 = new Notification({
id: 'remove-array-2',
title: 'test 2',
body: 'body 2',
silent: true
});
const shown1 = once(n1, 'show');
n1.show();
await shown1;
const shown2 = once(n2, 'show');
n2.show();
await shown2;
Notification.remove(['remove-array-1', 'remove-array-2']);
await new Promise(resolve => setTimeout(resolve, 100));
const history = await Notification.getHistory();
const found1 = history.find((item: any) => item.id === 'remove-array-1');
const found2 = history.find((item: any) => item.id === 'remove-array-2');
expect(found1).to.be.undefined();
expect(found2).to.be.undefined();
});
ifit(process.platform === 'darwin')('removeAll removes all notifications', async () => {
const n = new Notification({
id: 'remove-all-test',
title: 'removeAll test',
body: 'body',
silent: true
});
const shown = once(n, 'show');
n.show();
await shown;
Notification.removeAll();
await new Promise(resolve => setTimeout(resolve, 100));
const history = await Notification.getHistory();
const found = history.find((item: any) => item.id === 'remove-all-test');
expect(found).to.be.undefined();
});
ifit(process.platform === 'darwin')('remove does not throw with an empty array', () => {
expect(() => Notification.remove([])).to.not.throw();
});
ifit(process.platform === 'darwin')('remove does not throw with an empty string', () => {
expect(() => Notification.remove('')).to.not.throw();
});
ifit(process.platform === 'darwin')('removeGroup does not throw', () => {
expect(() => Notification.removeGroup('nonexistent-group')).to.not.throw();
});
ifit(process.platform === 'darwin')('removeGroup removes notifications by groupId', async () => {
const n1 = new Notification({
id: 'group-keep',
title: 'keep',
body: 'body',
groupId: 'group-a',
silent: true
});
const n2 = new Notification({
id: 'group-remove-1',
title: 'remove 1',
body: 'body',
groupId: 'group-b',
silent: true
});
const n3 = new Notification({
id: 'group-remove-2',
title: 'remove 2',
body: 'body',
groupId: 'group-b',
silent: true
});
for (const n of [n1, n2, n3]) {
const shown = once(n, 'show');
n.show();
await shown;
}
Notification.removeGroup('group-b');
// Give the notification center a moment to fetch and remove
await new Promise(resolve => setTimeout(resolve, 500));
const history = await Notification.getHistory();
// In code-signed builds, group-a notification should remain
// while group-b notifications should be gone
const foundB1 = history.find((item: any) => item.id === 'group-remove-1');
const foundB2 = history.find((item: any) => item.id === 'group-remove-2');
expect(foundB1).to.be.undefined();
expect(foundB2).to.be.undefined();
// Clean up
Notification.removeAll();
});
});
});

View File

@@ -407,6 +407,41 @@ describe('asar package', function () {
});
});
describe('fs.cpSync', function () {
itremote('copies a normal file', function () {
if (!fs.cpSync) return;
const p = path.join(asarDir, 'a.asar', 'file1');
const temp = require('temp').track();
const dest = temp.path();
fs.cpSync(p, dest);
expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
});
});
describe('fs.cp', function () {
itremote('copies a normal file', async function () {
if (!fs.cp) return;
const p = path.join(asarDir, 'a.asar', 'file1');
const temp = require('temp').track();
const dest = temp.path();
await new Promise<void>((resolve, reject) => {
fs.cp(p, dest, (err) => err ? reject(err) : resolve());
});
expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
});
});
describe('fs.promises.cp', function () {
itremote('copies a normal file', async function () {
if (!fs.promises.cp) return;
const p = path.join(asarDir, 'a.asar', 'file1');
const temp = require('temp').track();
const dest = temp.path();
await fs.promises.cp(p, dest);
expect(fs.readFileSync(p).equals(fs.readFileSync(dest))).to.be.true();
});
});
describe('fs.lstatSync', function () {
itremote('handles path with trailing slash correctly', function () {
const p = path.join(asarDir, 'a.asar', 'link2', 'link2', 'file1');

View File

@@ -118,6 +118,10 @@ declare namespace NodeJS {
interface NotificationBinding {
isSupported(): boolean;
getHistory(): Promise<Electron.Notification[]>;
remove(id: string | string[]): void;
removeAll(): void;
removeGroup(groupId: string): void;
Notification: typeof Electron.Notification;
// Windows-only callback for cold-start notification activation
handleActivation?: (callback: (details: ActivationArgumentsInternal) => void) => void;

View File

@@ -588,7 +588,7 @@ __metadata:
eslint-plugin-node: "npm:^11.1.0"
eslint-plugin-promise: "npm:^6.6.0"
events: "npm:^3.2.0"
folder-hash: "npm:^4.1.1"
folder-hash: "npm:^4.1.2"
got: "npm:^11.8.5"
husky: "npm:^9.1.7"
lint-staged: "npm:^16.1.0"
@@ -602,7 +602,6 @@ __metadata:
stream-json: "npm:^1.9.1"
tap-xunit: "npm:^2.4.1"
temp: "npm:^0.9.4"
timers-browserify: "npm:1.4.2"
ts-loader: "npm:^8.0.2"
ts-node: "npm:6.2.0"
typescript: "npm:^5.8.3"
@@ -3417,7 +3416,7 @@ __metadata:
languageName: node
linkType: hard
"brace-expansion@npm:^2.0.1":
"brace-expansion@npm:^2.0.1, brace-expansion@npm:^2.0.2":
version: 2.0.2
resolution: "brace-expansion@npm:2.0.2"
dependencies:
@@ -6181,15 +6180,15 @@ __metadata:
languageName: node
linkType: hard
"folder-hash@npm:^4.1.1":
version: 4.1.1
resolution: "folder-hash@npm:4.1.1"
"folder-hash@npm:^4.1.2":
version: 4.1.2
resolution: "folder-hash@npm:4.1.2"
dependencies:
debug: "npm:4.4.0"
minimatch: "npm:7.4.6"
minimatch: "npm:7.4.9"
bin:
folder-hash: bin/folder-hash
checksum: 10c0/71597548cccda43c3d4bda940fd1277f63839a86322d66dec2aa883dce4f51c4c0a6e274d7cb30cfbf4df9897d7a5649a09257e5ffada2fa50cd3a2b09da5a32
checksum: 10c0/7c26f7322820cff61745e168ed7c0d3fe9f9afafe7157d01de5cb708effc66761c2f4d1eda59d2925661baaac2adb8a04a51d0d1f01f8003d7e275610ca3f452
languageName: node
linkType: hard
@@ -9257,12 +9256,12 @@ __metadata:
languageName: node
linkType: hard
"minimatch@npm:7.4.6":
version: 7.4.6
resolution: "minimatch@npm:7.4.6"
"minimatch@npm:7.4.9":
version: 7.4.9
resolution: "minimatch@npm:7.4.9"
dependencies:
brace-expansion: "npm:^2.0.1"
checksum: 10c0/e587bf3d90542555a3d58aca94c549b72d58b0a66545dd00eef808d0d66e5d9a163d3084da7f874e83ca8cc47e91c670e6c6f6593a3e7bb27fcc0e6512e87c67
brace-expansion: "npm:^2.0.2"
checksum: 10c0/8d5406a9697edb9b7ea02697d58cabcb3d3a9a4a02caa1cf57b9ab5ae22c78b2945600661a78f91d1545f77521f97f3cb5f8cb066e58356a121b50e4e60ccdbe
languageName: node
linkType: hard
@@ -10614,7 +10613,7 @@ __metadata:
languageName: node
linkType: hard
"process@npm:^0.11.10, process@npm:~0.11.0":
"process@npm:^0.11.10":
version: 0.11.10
resolution: "process@npm:0.11.10"
checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
@@ -12462,15 +12461,6 @@ __metadata:
languageName: node
linkType: hard
"timers-browserify@npm:1.4.2":
version: 1.4.2
resolution: "timers-browserify@npm:1.4.2"
dependencies:
process: "npm:~0.11.0"
checksum: 10c0/96e9b6d629bbb8bed7c55745112d065a2abdc33f3c29354c62de2fb02916893994b28678d675cdfceb12ca8e26f5e77e41fda9b2aa449f74ba0bbf191735a656
languageName: node
linkType: hard
"tiny-async-pool@npm:^2.1.0":
version: 2.1.0
resolution: "tiny-async-pool@npm:2.1.0"