Compare commits

..

44 Commits

Author SHA1 Message Date
electron-roller[bot]
4ceb644723 chore: bump chromium to 118.0.5993.89 (27-x-y) (#40240)
chore: bump chromium in DEPS to 118.0.5993.89

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-10-18 10:19:01 -04:00
trop[bot]
ae212f41ab fix: Windows Toast notification dismissal from Action Center (#40244)
* fix: Windows Toast notification dismissal from Action Center

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* docs: note Toast behavior in event

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: address feedback from review

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-18 10:03:54 +02:00
trop[bot]
1f64b7869c refactor: partition HidDelegate observers by browser context (#40237)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-17 18:58:59 -04:00
electron-roller[bot]
f282bdac65 chore: bump chromium to 118.0.5993.71 (27-x-y) (#40235)
chore: bump chromium in DEPS to 118.0.5993.71

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-10-17 18:58:40 -04:00
trop[bot]
c0ad9e154f docs: Update docs on testing Electron apps with WebdriverIO (#40226)
* docs: Updated docs on testing Electron using WebdriverIO

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* more updates

Co-authored-by: Christian Bromann <git@bromann.dev>

* address PR comments

Co-authored-by: Christian Bromann <git@bromann.dev>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Christian Bromann <github@christian-bromann.com>
Co-authored-by: Christian Bromann <git@bromann.dev>
2023-10-17 16:54:45 +02:00
trop[bot]
6304ea53ef fix: incorrect wco bounds in macOS fullscreen (#40217)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-16 13:11:37 +02:00
David Sanders
4c1e53dfa6 docs: fix some string union typings (#40202) 2023-10-16 14:10:10 +09:00
trop[bot]
96f9cc5157 fix: store portal restore token under the right source ID (#40193)
XDG Desktop Portal provides restore tokens to restore a previously
selected PipeWire stream instead of prompting the user again. This
restore token is single use only and it has to be replaced when the
stream is completed/stopped.

BaseCapturerPipewire maintains two source IDs: one is initialized by
the constructor for new sources (source_id_) and another is for
capturing previously selected sources (selected_source_id_). The
restore token was always being stored under `source_id_`, even if the
capture was ongoing for `selected_source_id_`. This prevents a stream
from being restored more than once. Fix that by storing the restore
token under the selected source ID if it exists.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Athul Iddya <athul@iddya.com>
2023-10-13 22:09:05 +02:00
trop[bot]
8890ab5119 fix: webContents.capturePage() for hidden windows on Windows/Linux (#40188)
fix: capturePage for hidden windows on Windows/Linux

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-12 13:54:48 +02:00
electron-roller[bot]
4bb80df378 chore: bump chromium to 118.0.5993.70 (27-x-y) (#40175)
* chore: bump chromium in DEPS to 118.0.5993.70

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-11 14:34:43 -04:00
trop[bot]
3d10512399 docs: update dates for E28 (#40168)
* docs: update dates for E28

Co-authored-by: VerteDinde <vertedinde@electronjs.org>

* docs: update node version

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: VerteDinde <vertedinde@electronjs.org>
2023-10-11 09:27:21 -07:00
trop[bot]
30305e4f2b test: make capturePage color matching timeouts consistent (#40166)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-10 19:26:20 -04:00
trop[bot]
40c21e02da fix: crash when calling non-reentrant function in loadURL (#40162)
fix: crash when calling non-reentrant function in loadURL

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-10 11:49:22 -04:00
trop[bot]
6de96fb83b ci: fixup diagnose_goma_log.py call (#40149)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-10-09 18:44:51 -04:00
trop[bot]
cf0e974ce1 fix: failing build with enable_electron_extensions=false (#40087)
* fix: ENABLE_EXTENSIONS -> ENABLE_ELECTRON_EXTENSIONS

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* fix: extension guard fixes

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: fix linker errors

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-09 18:43:40 -04:00
trop[bot]
7e2073226a fix: crashed events deprecation (#40111)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-10-09 15:19:53 +02:00
trop[bot]
8f370cd2e3 fix: fix vibrancy applying without transparency on MacOS (#40130)
* fix: fix vibrancy applying without transparency

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>

* fix: initiate backgroundMaterial and vibrancy earlier in native window

Co-authored-by: samuelmaddock <samuelmaddock@electronjs.org>

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2023-10-09 15:19:30 +02:00
Milan Burda
82d4e9427f test: fix "crashed event does not crash main process when destroying WebContents in it" (#40144) 2023-10-09 15:18:46 +02:00
trop[bot]
f0b742f2d6 test: add back smoke test for removed API (#40139)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2023-10-09 15:41:39 +09:00
trop[bot]
2bc07b098b chore: cherry-pick c03569f from libuv (#40126)
* chore: cherry-pick c03569f from libuv

Refs c03569f0df

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* chore: update .patches

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-09 08:45:34 +09:00
trop[bot]
d95f28c194 fix: toggling DevTools while minimized on Windows (#40116)
fix: toggling devtools while minimized on Windows

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-06 11:46:55 -04:00
trop[bot]
22ea11175b fix: error using webcrypto.subtle.importKey() (#40100)
* fix: error using webcrypto.subtle.importKey()

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: update .patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-10-06 10:42:49 -04:00
trop[bot]
5b44e82eb4 fix: all children showing when showing child window (#40105)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-06 09:56:23 -04:00
electron-roller[bot]
4c4a3e7594 chore: bump chromium to 118.0.5993.54 (27-x-y) (#40103)
* chore: bump chromium in DEPS to 118.0.5993.54

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-05 19:53:06 -04:00
trop[bot]
bf7474d3f4 feat: add tabbingIdentifier property to BrowserWindow (#40082)
feat: add tabbingIdentifier property to BrowserWindow

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-05 09:13:05 -04:00
George Xu
3f142ad039 feat: expose app accessibility transparency settings api (#40074)
feat: expose app accessibility transparency settings api (#39631)

* feat: expose app accessibility transparency settings api

* docs: fix typo

* chore: add doc

* change to property

* add as property instead of method

* chore: fix lint

* rename function name in header

---------

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2023-10-04 16:36:04 -07:00
electron-roller[bot]
10db23828e chore: bump chromium to 118.0.5993.32 (27-x-y) (#40044)
* chore: bump chromium in DEPS to 118.0.5993.32

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-10-02 14:37:40 -04:00
trop[bot]
43ba54e61f docs: add PipeWire integration instructions for snaps (#40068)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Athul Iddya <athul@iddya.com>
2023-10-02 11:05:52 -04:00
trop[bot]
3fdfcbb5dd chore: update extensions url handling to match upstream (#40063)
- https://chromium-review.googlesource.com/c/chromium/src/+/4772028
- https://chromium-review.googlesource.com/c/chromium/src/+/4264656
- https://chromium-review.googlesource.com/c/chromium/src/+/4712150

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-02 13:12:47 +02:00
trop[bot]
9e8cba981a fix: BroadcastChannel initialization location (#40067)
fix: `BroadcastChannel` initialization location (#37421)

* fix: BroadcastChannel initialization location

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-02 13:10:46 +02:00
trop[bot]
a85c6cf0e5 fix: detect screen readers by testing their existences (#40065)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2023-10-02 13:07:27 +02:00
trop[bot]
7e536dfd8e fix: propagate layout call to all children of InspectableWebContentsViewViews (#40037)
Propagate layout call to all children of InspectableWebContentsViewViews.

When BrowserView bounds are set from js, those might not trigger layout
immediately, sometimes propagating InvalidateLayout call to parent.
View is marked as needing layout, expecting to receive it from parent on
next layout call. The problem is that BrowserView's view is added as child
of InspectableWebContentsViews which does not call setBounds (which
would trigger layout) on all of it's children when doing it's layout,
so it skips propagating Layout call to its children BrowserViews views,
even though those were marked as needing layout.
Call base class View::Layout which will iterate over views' children
and call Layout on those that were marked as needing them.

Fixes #39993.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Marek Haranczyk <marek@openfin.co>
2023-09-28 18:55:24 -04:00
trop[bot]
7d21d113d2 fix: failure on immutable webContents.print(options) (#40030)
fix: failure on immutable webContents.print(options)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-09-28 12:48:44 -04:00
Samuel Attard
7ed33db12e chore: cherry-pick 3fbd1dca6a4d from libvpx (#40022)
* chore: cherry-pick 3fbd1dca6a4d from libvpx

* build: update patches config

* chore: update patches

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-09-28 03:31:46 -07:00
trop[bot]
66c4f9cb6f fix: rounded corners on vibrant macOS modals (#39996)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-09-28 10:33:39 +02:00
trop[bot]
a00155dcfc fix: set window contents as opaque to decrease DWM GPU usage (#40003)
* set window contents as opaque to decrease DWM GPU usage

Co-authored-by: brhenrique <bruno.d@miro.com>

* chore: add more context to ShouldWindowContentsBeTransparent

Co-authored-by: brhenrique <bruno.d@miro.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: brhenrique <bruno.d@miro.com>
2023-09-28 10:33:29 +02:00
trop[bot]
3e4adb91c5 feat: enable dark mode on GTK UIs (#40010)
feat: port DarkModeManagerLinux

This is needed after https://bugs.chromium.org/p/chromium/issues/detail?id=998903
and replaces the previous workaround to detect dark mode on GTK.
Detect system dark theme preference via xdg settings portal:
https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Settings

Closes: https://github.com/electron/electron/issues/38961
Closes: https://github.com/electron/electron/issues/28838

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Robert Günzler <r@gnzler.io>
2023-09-27 16:44:34 -04:00
trop[bot]
f63f02fbb2 docs: document type-specific module aliases (#40005)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2023-09-27 16:35:32 -04:00
trop[bot]
a3a6e8ff26 build: fix with enable_pdf_viewer = false (#40001)
build: fix with enable_pdf_viewer = false

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-09-27 19:57:48 +02:00
trop[bot]
e70a25d5a3 fix: apply size constraints to NSWindow (#39992)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2023-09-27 16:54:19 +02:00
Keeley Hammond
8e2cf54f29 fix: revert SameParty cookie attribute removal (#39976) 2023-09-26 14:17:23 -07:00
trop[bot]
a3614983de chore: add deprecated app.runningUnderRosettaTranslation to breaking-changes.md (#39984)
chore: add deprecated app.runningUnderRosettaTranslation to breaking-changes.md

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-09-26 16:57:42 -04:00
David Sanders
686adf9d15 chore: remove deprecated systemPreferences APIs (#39804)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-09-26 14:45:49 +09:00
John Kleinschmidt
25dccaa1b1 test: fixup parallel/test-node-output-error test (#39973) 2023-09-25 17:03:41 -04:00
79 changed files with 3655 additions and 591 deletions

View File

@@ -754,8 +754,8 @@ step-show-goma-stats: &step-show-goma-stats
command: |
set +e
set +o pipefail
$GOMA_DIR/goma_ctl.py stat
$GOMA_DIR/diagnose_goma_log.py
python3 $GOMA_DIR/goma_ctl.py stat
python3 $GOMA_DIR/diagnose_goma_log.py
true
when: always
background: true

2
DEPS
View File

@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'118.0.5993.18',
'118.0.5993.89',
'node_version':
'v18.17.1',
'nan_version':

View File

@@ -202,6 +202,10 @@ static_library("chrome") {
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc",
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h",
]
sources += [
"//chrome/browser/ui/views/dark_mode_manager_linux.cc",
"//chrome/browser/ui/views/dark_mode_manager_linux.h",
]
public_deps += [
"//components/dbus/menu",
"//components/dbus/thread_linux",
@@ -319,6 +323,34 @@ static_library("chrome") {
"//components/pdf/renderer",
]
}
} else {
# These are required by the webRequest module.
sources += [
"//extensions/browser/api/declarative_net_request/request_action.cc",
"//extensions/browser/api/declarative_net_request/request_action.h",
"//extensions/browser/api/web_request/form_data_parser.cc",
"//extensions/browser/api/web_request/form_data_parser.h",
"//extensions/browser/api/web_request/upload_data_presenter.cc",
"//extensions/browser/api/web_request/upload_data_presenter.h",
"//extensions/browser/api/web_request/web_request_api_constants.cc",
"//extensions/browser/api/web_request/web_request_api_constants.h",
"//extensions/browser/api/web_request/web_request_info.cc",
"//extensions/browser/api/web_request/web_request_info.h",
"//extensions/browser/api/web_request/web_request_resource_type.cc",
"//extensions/browser/api/web_request/web_request_resource_type.h",
"//extensions/browser/extension_api_frame_id_map.cc",
"//extensions/browser/extension_api_frame_id_map.h",
"//extensions/browser/extension_navigation_ui_data.cc",
"//extensions/browser/extension_navigation_ui_data.h",
"//extensions/browser/extensions_browser_client.cc",
"//extensions/browser/extensions_browser_client.h",
"//extensions/browser/guest_view/web_view/web_view_renderer_state.cc",
"//extensions/browser/guest_view/web_view/web_view_renderer_state.h",
]
public_deps += [
"//extensions/browser/api/declarative_net_request/flat:extension_ruleset",
]
}
if (!is_mas_build) {

View File

@@ -1134,11 +1134,11 @@ indicates success while any other value indicates failure according to Chromium
resolver will attempt to use the system's DNS settings to do DNS lookups
itself. Enabled by default on macOS, disabled by default on Windows and
Linux.
* `secureDnsMode` string (optional) - Can be "off", "automatic" or "secure".
Configures the DNS-over-HTTP mode. When "off", no DoH lookups will be
performed. When "automatic", DoH lookups will be performed first if DoH is
* `secureDnsMode` string (optional) - Can be 'off', 'automatic' or 'secure'.
Configures the DNS-over-HTTP mode. When 'off', no DoH lookups will be
performed. When 'automatic', DoH lookups will be performed first if DoH is
available, and insecure DNS lookups will be performed as a fallback. When
"secure", only DoH lookups will be performed. Defaults to "automatic".
'secure', only DoH lookups will be performed. Defaults to 'automatic'.
* `secureDnsServers` string[]&#32;(optional) - A list of DNS-over-HTTP
server templates. See [RFC8484 § 3][] for details on the template format.
Most servers support the POST method; the template for such servers is

View File

@@ -505,6 +505,10 @@ events.
A `Integer` property representing the unique ID of the window. Each ID is unique among all `BrowserWindow` instances of the entire Electron application.
#### `win.tabbingIdentifier` _macOS_ _Readonly_
A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set.
#### `win.autoHideMenuBar`
A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key.

View File

@@ -85,6 +85,8 @@ Emitted when the notification is closed by manual intervention from the user.
This event is not guaranteed to be emitted in all cases where the notification
is closed.
On Windows, the `close` event can be emitted in one of three ways: programmatic dismissal with `notification.close()`, by the user closing the notification, or via system timeout. If a notification is in the Action Center after the initial `close` event is emitted, a call to `notification.close()` will remove the notification from the action center but the `close` event will not be emitted again.
#### Event: 'reply' _macOS_
Returns:
@@ -127,6 +129,8 @@ shown notification and create a new one with identical properties.
Dismisses the notification.
On Windows, calling `notification.close()` while the notification is visible on screen will dismiss the notification and remove it from the Action Center. If `notification.close()` is called after the notification is no longer visible on screen, calling `notification.close()` will try remove it from the Action Center.
### Instance Properties
#### `notification.title`

View File

@@ -273,7 +273,6 @@ This API is only available on macOS 10.14 Mojave or newer.
* `window-frame` - Window frame.
* `window-text` - Text in windows.
* On **macOS**
* `alternate-selected-control-text` - The text on a selected surface in a list or table. _Deprecated_
* `control-background` - The background of a large interface element, such as a browser or table.
* `control` - The surface of a control.
* `control-text` -The text of a control that isnt disabled.
@@ -339,21 +338,6 @@ Returns `string` - Can be `dark`, `light` or `unknown`.
Gets the macOS appearance setting that is currently applied to your application,
maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc)
### `systemPreferences.getAppLevelAppearance()` _macOS_ _Deprecated_
Returns `string` | `null` - Can be `dark`, `light` or `unknown`.
Gets the macOS appearance setting that you have declared you want for
your application, maps to [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc).
You can use the `setAppLevelAppearance` API to set this value.
### `systemPreferences.setAppLevelAppearance(appearance)` _macOS_ _Deprecated_
* `appearance` string | null - Can be `dark` or `light`
Sets the appearance setting for your application, this should override the
system default and override the value of `getEffectiveAppearance`.
### `systemPreferences.canPromptTouchID()` _macOS_
Returns `boolean` - whether or not this device has the ability to use Touch ID.
@@ -417,15 +401,9 @@ Returns an object with system animation settings.
## Properties
### `systemPreferences.appLevelAppearance` _macOS_ _Deprecated_
### `systemPreferences.accessibilityDisplayShouldReduceTransparency()` _macOS_
A `string` property that can be `dark`, `light` or `unknown`. It determines the macOS appearance setting for
your application. This maps to values in: [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). Setting this will override the
system default as well as the value of `getEffectiveAppearance`.
Possible values that can be set are `dark` and `light`, and possible return values are `dark`, `light`, and `unknown`.
This property is only available on macOS 10.14 Mojave or newer.
A `boolean` property which determines whether the app avoids using semitransparent backgrounds. This maps to [NSWorkspace.accessibilityDisplayShouldReduceTransparency](https://developer.apple.com/documentation/appkit/nsworkspace/1533006-accessibilitydisplayshouldreduce)
### `systemPreferences.effectiveAppearance` _macOS_ _Readonly_

View File

@@ -1211,7 +1211,7 @@ Returns `string` - The user agent for this web page.
* `css` string
* `options` Object (optional)
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`.

View File

@@ -113,7 +113,7 @@ webFrame.setSpellCheckProvider('en-US', {
* `css` string
* `options` Object (optional)
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
Returns `string` - A key for the inserted CSS that can later be used to remove
the CSS via `webFrame.removeInsertedCSS(key)`.

View File

@@ -61,6 +61,41 @@ w.webContents.getPrintersAsync().then((printers) => {
})
```
### Removed: `systemPreferences.{get,set}AppLevelAppearance` and `systemPreferences.appLevelAppearance`
The `systemPreferences.getAppLevelAppearance` and `systemPreferences.setAppLevelAppearance`
methods have been removed, as well as the `systemPreferences.appLevelAppearance` property.
Use the `nativeTheme` module instead.
```js
// Removed
systemPreferences.getAppLevelAppearance()
// Replace with
nativeTheme.shouldUseDarkColors
// Removed
systemPreferences.appLevelAppearance
// Replace with
nativeTheme.shouldUseDarkColors
// Removed
systemPreferences.setAppLevelAppearance('dark')
// Replace with
nativeTheme.themeSource = 'dark'
```
### Removed: `alternate-selected-control-text` value for `systemPreferences.getColor`
The `alternate-selected-control-text` value for `systemPreferences.getColor`
has been removed. Use `selected-content-background` instead.
```js
// Removed
systemPreferences.getColor('alternate-selected-control-text')
// Replace with
systemPreferences.getColor('selected-content-background')
```
## Planned Breaking API Changes (26.0)
### Deprecated: `webContents.getPrinters`
@@ -635,6 +670,18 @@ to open synchronously scriptable child windows, among other incompatibilities.
See the documentation for [window.open in Electron](api/window-open.md)
for more details.
### Deprecated: `app.runningUnderRosettaTranslation`
The `app.runningUnderRosettaTranslation` property has been deprecated.
Use `app.runningUnderARM64Translation` instead.
```js
// Deprecated
console.log(app.runningUnderRosettaTranslation)
// Replace with
console.log(app.runningUnderARM64Translation)
```
## Planned Breaking API Changes (14.0)
### Removed: `remote` module

View File

@@ -22,34 +22,101 @@ There are a few ways that you can set up testing using WebDriver.
Node.js package for testing with WebDriver. Its ecosystem also includes various plugins
(e.g. reporter and services) that can help you put together your test setup.
If you already have an existing WebdriverIO setup, it is recommended to update your dependencies and validate your existing configuration with how it is [outlined in the docs](https://webdriver.io/docs/desktop-testing/electron#configuration).
#### Install the test runner
First you need to run the WebdriverIO starter toolkit in your project root directory:
If you don't use WebdriverIO in your project yet, you can add it by running the starter toolkit in your project root directory:
```sh npm2yarn
npx wdio . --yes
npm init wdio@latest ./
```
This installs all necessary packages for you and generates a `wdio.conf.js` configuration file.
This starts a configuration wizard that helps you put together the right setup, installs all necessary packages, and generates a `wdio.conf.js` configuration file. Make sure to select _"Desktop Testing - of Electron Applications"_ on one of the first questions asking _"What type of testing would you like to do?"_.
#### Connect WDIO to your Electron app
Update the capabilities in your configuration file to point to your Electron app binary:
After running the configuration wizard, your `wdio.conf.js` should include roughly the following content:
```javascript title='wdio.conf.js'
exports.config = {
```js title='wdio.conf.js' @ts-nocheck
export const config = {
// ...
services: ['electron'],
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': {
binary: '/path/to/your/electron/binary', // Path to your Electron binary.
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
browserName: 'electron',
'wdio:electronServiceOptions': {
// WebdriverIO can automatically find your bundled application
// if you use Electron Forge or electron-builder, otherwise you
// can define it here, e.g.:
// appBinaryPath: './path/to/bundled/application.exe',
appArgs: ['foo', 'bar=baz']
}
}]
// ...
}
```
#### Write your tests
Use the [WebdriverIO API](https://webdriver.io/docs/api) to interact with elements on the screen. The framework provides custom "matchers" that make asserting the state of your application easy, e.g.:
```js @ts-nocheck
import { browser, $, expect } from '@wdio/globals'
describe('keyboard input', () => {
it('should detect keyboard input', async () => {
await browser.keys(['y', 'o'])
await expect($('keypress-count')).toHaveText('YO')
})
})
```
Furthermore, WebdriverIO allows you to access Electron APIs to get static information about your application:
```js @ts-nocheck
import { browser, $, expect } from '@wdio/globals'
describe('when the make smaller button is clicked', () => {
it('should decrease the window height and width by 10 pixels', async () => {
const boundsBefore = await browser.electron.browserWindow('getBounds')
expect(boundsBefore.width).toEqual(210)
expect(boundsBefore.height).toEqual(310)
await $('.make-smaller').click()
const boundsAfter = await browser.electron.browserWindow('getBounds')
expect(boundsAfter.width).toEqual(200)
expect(boundsAfter.height).toEqual(300)
})
})
```
or to retrieve other Electron process information:
```js @ts-nocheck
import fs from 'node:fs'
import path from 'node:path'
import { browser, expect } from '@wdio/globals'
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), { encoding: 'utf-8' }))
const { name, version } = packageJson
describe('electron APIs', () => {
it('should retrieve app metadata through the electron API', async () => {
const appName = await browser.electron.app('getName')
expect(appName).toEqual(name)
const appVersion = await browser.electron.app('getVersion')
expect(appVersion).toEqual(version)
})
it('should pass args through to the launched application', async () => {
// custom args are set in the wdio.conf.js file as they need to be set before WDIO starts
const argv = await browser.electron.mainProcess('argv')
expect(argv).toContain('--foo')
expect(argv).toContain('--bar=baz')
})
})
```
#### Run your tests
To run your tests:
@@ -58,6 +125,12 @@ To run your tests:
$ npx wdio run wdio.conf.js
```
WebdriverIO helps launch and shut down the application for you.
#### More documentation
Find more documentation on Mocking Electron APIs and other useful resources in the [official WebdriverIO documentation](https://webdriver.io/docs/desktop-testing/electron).
### With Selenium
[Selenium](https://www.selenium.dev/) is a web automation framework that

View File

@@ -9,12 +9,13 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | TBD | M118 | TBD | ✅ |
| 28.0.0 | 2023-Oct-11 | 2023-Nov-6 | 2023-Dec-5 | TBD | M120 | TBD | ✅ |
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | 2024-Apr-16 | M118 | v18.17 | ✅ |
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-27 | M116 | v18.16 | ✅ |
| 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2024-Jan-02 | M114 | v18.15 | ✅ |
| 24.0.0 | 2023-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | |
| 24.0.0 | 2023-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | 🚫 |
| 23.0.0 | 2022-Dec-01 | 2023-Jan-10 | 2023-Feb-07 | 2023-Aug-15 | M110 | v18.12 | 🚫 |
| 22.0.0 | 2022-Sep-29 | 2022-Oct-25 | 2022-Nov-29 | 2023-Oct-10 | M108 | v16.17 | |
| 22.0.0 | 2022-Sep-29 | 2022-Oct-25 | 2022-Nov-29 | 2023-Oct-10 | M108 | v16.17 | 🚫 |
| 21.0.0 | 2022-Aug-04 | 2022-Aug-30 | 2022-Sep-27 | 2023-Apr-04 | M106 | v16.16 | 🚫 |
| 20.0.0 | 2022-May-26 | 2022-Jun-21 | 2022-Aug-02 | 2023-Feb-07 | M104 | v16.15 | 🚫 |
| 19.0.0 | 2022-Mar-31 | 2022-Apr-26 | 2022-May-24 | 2022-Nov-29 | M102 | v16.14 | 🚫 |

View File

@@ -228,6 +228,23 @@ channel with a renderer process using [`MessagePort`][]s. An Electron app can
always prefer the [UtilityProcess][] API over Node.js [`child_process.fork`][] API when
there is need to fork a child process from the main process.
## Process-specific module aliases (TypeScript)
Electron's npm package also exports subpaths that contain a subset of
Electron's TypeScript type definitions.
- `electron/main` includes types for all main process modules.
- `electron/renderer` includes types for all renderer process modules.
- `electron/common` includes types for modules that can run in main and renderer processes.
These aliases have no impact on runtime, but can be used for typechecking
and autocomplete.
```js title="Usage example"
const { app } = require('electron/main')
const { shell } = require('electron/common')
```
[window-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window
[`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
[`child_process.fork`]: https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html#child_processforkmodulepath-args-options

View File

@@ -91,14 +91,14 @@ version: '0.1'
summary: Hello World Electron app
description: |
Simple Hello World Electron app as an example
base: core18
base: core22
confinement: strict
grade: stable
apps:
electron-packager-hello-world:
command: electron-quick-start/electron-quick-start --no-sandbox
extensions: [gnome-3-34]
extensions: [gnome]
plugs:
- browser-support
- network
@@ -237,6 +237,34 @@ apps:
desktop: usr/share/applications/desktop.desktop
```
## Optional: Enabling desktop capture
Capturing the desktop requires PipeWire library in some Linux configurations that use
the Wayland protocol. To bundle PipeWire with your application, ensure that the base
snap is set to `core22` or newer. Next, create a part called `pipewire` and add it to
the `after` section of your application:
```yaml
pipewire:
plugin: nil
build-packages: [libpipewire-0.3-dev]
stage-packages: [pipewire]
prime:
- usr/lib/*/pipewire-*
- usr/lib/*/spa-*
- usr/lib/*/libpipewire*.so*
- usr/share/pipewire
```
Finally, configure your application's environment for PipeWire:
```yaml
environment:
SPA_PLUGIN_DIR: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/spa-0.2
PIPEWIRE_CONFIG_NAME: $SNAP/usr/share/pipewire/pipewire.conf
PIPEWIRE_MODULE_DIR: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/pipewire-0.3
```
[snapcraft-syntax]: https://docs.snapcraft.io/build-snaps/syntax
[electron-packager]: https://github.com/electron/electron-packager
[electron-forge]: https://github.com/electron/forge

View File

@@ -222,14 +222,26 @@ with CommonJS module syntax:
- [app][app], which controls your application's event lifecycle.
- [BrowserWindow][browser-window], which creates and manages app windows.
:::info Capitalization conventions
<details><summary>Module capitalization conventions</summary>
You might have noticed the capitalization difference between the **a**pp
and **B**rowser**W**indow modules. Electron follows typical JavaScript conventions here,
where PascalCase modules are instantiable class constructors (e.g. BrowserWindow, Tray,
Notification) whereas camelCase modules are not instantiable (e.g. app, ipcRenderer, webContents).
:::
</details>
<details><summary>Typed import aliases</summary>
For better type checking when writing TypeScript code, you can choose to import
main process modules from <code>electron/main</code>.
```js
const { app, BrowserWindow } = require('electron/main')
```
For more information, see the [Process Model docs](../tutorial/process-model.md#process-specific-module-aliases-typescript).
</details>
:::warning ES Modules in Electron

View File

@@ -114,5 +114,11 @@ for (const name of events) {
}
// Deprecation.
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone');
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone');
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone', () => {
// the old event is still emitted by App::OnGpuProcessCrashed()
return undefined;
});
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone', (event: Electron.Event, webContents: Electron.WebContents, details: Electron.RenderProcessGoneDetails) => {
return [event, webContents, details.reason === 'killed'];
});

View File

@@ -1,33 +1,5 @@
import * as deprecate from '@electron/internal/common/deprecate';
const { systemPreferences } = process._linkedBinding('electron_browser_system_preferences');
if ('getAppLevelAppearance' in systemPreferences) {
const nativeALAGetter = systemPreferences.getAppLevelAppearance;
const nativeALASetter = systemPreferences.setAppLevelAppearance;
const warnALA = deprecate.warnOnce('appLevelAppearance');
const warnALAGetter = deprecate.warnOnce('getAppLevelAppearance function');
const warnALASetter = deprecate.warnOnce('setAppLevelAppearance function');
Object.defineProperty(systemPreferences, 'appLevelAppearance', {
get: () => {
warnALA();
return nativeALAGetter.call(systemPreferences);
},
set: (appearance) => {
warnALA();
nativeALASetter.call(systemPreferences, appearance);
}
});
systemPreferences.getAppLevelAppearance = () => {
warnALAGetter();
return nativeALAGetter.call(systemPreferences);
};
systemPreferences.setAppLevelAppearance = (appearance) => {
warnALASetter();
nativeALASetter.call(systemPreferences, appearance);
};
}
if ('getEffectiveAppearance' in systemPreferences) {
const nativeEAGetter = systemPreferences.getEffectiveAppearance;
Object.defineProperty(systemPreferences, 'effectiveAppearance', {

View File

@@ -337,49 +337,53 @@ WebContents.prototype.printToPDF = async function (options) {
// TODO(codebytere): deduplicate argument sanitization by moving rest of
// print param logic into new file shared between printToPDF and print
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions, callback) {
if (typeof options === 'object') {
const pageSize = options.pageSize ?? 'A4';
if (typeof pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
throw new Error('height and width properties are required for pageSize');
}
if (typeof options !== 'object') {
throw new Error('webContents.print(): Invalid print settings specified.');
}
// Dimensions in Microns - 1 meter = 10^6 microns
const height = Math.ceil(pageSize.height);
const width = Math.ceil(pageSize.width);
if (!isValidCustomPageSize(width, height)) {
throw new Error('height and width properties must be minimum 352 microns.');
}
const printSettings: Record<string, any> = { ...options };
options.mediaSize = {
name: 'CUSTOM',
custom_display_name: 'Custom',
height_microns: height,
width_microns: width,
imageable_area_left_microns: 0,
imageable_area_bottom_microns: 0,
imageable_area_right_microns: width,
imageable_area_top_microns: height
};
} else if (typeof pageSize === 'string' && PDFPageSizes[pageSize]) {
const mediaSize = PDFPageSizes[pageSize];
options.mediaSize = {
...mediaSize,
imageable_area_left_microns: 0,
imageable_area_bottom_microns: 0,
imageable_area_right_microns: mediaSize.width_microns,
imageable_area_top_microns: mediaSize.height_microns
};
} else {
throw new Error(`Unsupported pageSize: ${pageSize}`);
const pageSize = options.pageSize ?? 'A4';
if (typeof pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
throw new Error('height and width properties are required for pageSize');
}
// Dimensions in Microns - 1 meter = 10^6 microns
const height = Math.ceil(pageSize.height);
const width = Math.ceil(pageSize.width);
if (!isValidCustomPageSize(width, height)) {
throw new Error('height and width properties must be minimum 352 microns.');
}
printSettings.mediaSize = {
name: 'CUSTOM',
custom_display_name: 'Custom',
height_microns: height,
width_microns: width,
imageable_area_left_microns: 0,
imageable_area_bottom_microns: 0,
imageable_area_right_microns: width,
imageable_area_top_microns: height
};
} else if (typeof pageSize === 'string' && PDFPageSizes[pageSize]) {
const mediaSize = PDFPageSizes[pageSize];
printSettings.mediaSize = {
...mediaSize,
imageable_area_left_microns: 0,
imageable_area_bottom_microns: 0,
imageable_area_right_microns: mediaSize.width_microns,
imageable_area_top_microns: mediaSize.height_microns
};
} else {
throw new Error(`Unsupported pageSize: ${pageSize}`);
}
if (this._print) {
if (callback) {
this._print(options, callback);
this._print(printSettings, callback);
} else {
this._print(options);
this._print(printSettings);
}
} else {
console.error('Error: Printing feature is disabled.');
@@ -653,8 +657,8 @@ WebContents.prototype._init = function () {
ipcMain.emit(channel, event, message);
});
this.on('crashed', (event, ...args) => {
app.emit('renderer-process-crashed', event, this, ...args);
deprecate.event(this, 'crashed', 'render-process-gone', (event: Electron.Event, details: Electron.RenderProcessGoneDetails) => {
return [event, details.reason === 'killed'];
});
this.on('render-process-gone', (event, details) => {

View File

@@ -66,14 +66,17 @@ export function renameFunction<T extends Function> (fn: T, newName: string): T {
}
// change the name of an event
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string) {
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string, transformer: (...args: any[]) => any[] | undefined = (...args) => args) {
const warn = newName.startsWith('-') /* internal event */
? warnOnce(`${oldName} event`)
: warnOnce(`${oldName} event`, `${newName} event`);
return emitter.on(newName, function (this: NodeJS.EventEmitter, ...args) {
if (this.listenerCount(oldName) !== 0) {
warn();
this.emit(oldName, ...args);
const transformedArgs = transformer(...args);
if (transformedArgs) {
this.emit(oldName, ...transformedArgs);
}
}
});
}

View File

@@ -131,3 +131,4 @@ build_remove_ent_content_analysis_assert.patch
fix_activate_background_material_on_windows.patch
fix_move_autopipsettingshelper_behind_branding_buildflag.patch
revert_remove_the_allowaggressivethrottlingwithwebsocket_feature.patch
revert_same_party_cookie_attribute_removal.patch

View File

@@ -33,10 +33,10 @@ index 41ce32113ec2679b76d5a4fd69a7109c832ac7a1..1cd35794bf78f3d92b42634d9494c85a
"//base",
"//build:branding_buildflags",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 9ab6c039d18f8759b8d7db9742d3570a7734f893..ae347df7a1b1a48723160787f71cfd1340f430ef 100644
index 31bf3d854d9a672e535f747fb8734d66ac0c37e9..cad2387217a73ec5a7533fc121ea7b77cd6995ae 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4725,7 +4725,7 @@ static_library("browser") {
@@ -4726,7 +4726,7 @@ static_library("browser") {
# On Windows, the hashes are embedded in //chrome:chrome_initial rather
# than here in :chrome_dll.
@@ -46,7 +46,7 @@ index 9ab6c039d18f8759b8d7db9742d3570a7734f893..ae347df7a1b1a48723160787f71cfd13
sources += [ "certificate_viewer_stub.cc" ]
}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8f9b476a538dd5a0e91edc725eed4463b4a92e05..be625ce71f271aa47444fff1dc8d861c6cf2f43a 100644
index a315f817a8977d36e52b8f7c81d9e6778d3dcca2..dc046a004d6f4b2e9f1ec4b9423f293cfecaff8d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6841,7 +6841,6 @@ test("unit_tests") {

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 ad0d9cd11022f4f35e717efc088593df41d46496..40b63b1fbde84b8b3f854ce763474cd044f6ea96 100644
index af16b1053e1f42887bf0fde97bba30a377857872..ef79bf0e27bd0c5eb9fe5f0aef1cf6c6a2900e13 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -8206,6 +8206,7 @@ void RenderFrameHostImpl::CreateNewWindow(
@@ -8224,6 +8224,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,

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 9e946e02bca276a877defacf6cf6cb54f882ceba..149ead7bbf52ad127747c5f80f0e35a13203502a 100644
index 916c3f324ed2161d1f9ad1a023cc0318a1b72628..2d946e29c94a07a1aa4f4b6018ab1b564440f55d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -801,6 +801,9 @@ void RenderWidgetHostImpl::WasHidden() {
@@ -807,6 +807,9 @@ void RenderWidgetHostImpl::WasHidden() {
return;
}

View File

@@ -514,7 +514,7 @@ index 796ae2688436eb07f19909641d1620dd02f10cdb..c9e0eee0b329caf46669b419b1cd10cf
waiting_on_draw_ack_ = true;
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index c70b0af70a68386c5d36833e621dd1b5cdc1522a..17e5c96cbb4ef2f575fd5ba7bd8b0c7bd58da5e7 100644
index 1c59eb0cdf1786a19f74f165acc3fb071dcf2fa1..ddb2389f548a8558f79d7cf32ffd6ce0a7751553 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -97,7 +97,8 @@ RootCompositorFrameSinkImpl::Create(

View File

@@ -17,7 +17,7 @@ policy->CanCommitOriginAndUrl.
Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3856266.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index e91fb6b203b55d4937e9f4b4ed8fd5e8efb5aa10..855cb90260de04b90b8bbf4a8733e0869cda551d 100644
index 5cf177fc73dd2b3038754b11d23ad637e7709f88..72103151867a9c1154b83da83b52a5b3b7b988ed 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -7543,10 +7543,11 @@ NavigationRequest::GetOriginForURLLoaderFactoryAfterResponseWithDebugInfo() {

View File

@@ -25,10 +25,10 @@ index c9a13aee1e64f359cd1d5c2e440b4df204420997..7790c311400fc84bfda6c99e1ebd8da7
// Returns true if duplex mode is set.
bool SetDuplexModeInPrintSettings(mojom::DuplexMode mode);
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index ee900c7541af99c61844920433ae39e2648ae90b..59137008aeddc03d60c58a463206dc91a0ef5c1f 100644
index 7c9204db9b4c8f36e4c7405e3bd9c8b311753f04..4bff296ea2c55175416aaa778856e6182866664f 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -464,7 +464,8 @@ void ApplySystemPrintDialogData(
@@ -473,7 +473,8 @@ void ApplySystemPrintDialogData(
!SetCollateInPrintSettings(settings_->collate()) ||
!SetDuplexModeInPrintSettings(settings_->duplex_mode()) ||
!SetOutputColor(static_cast<int>(settings_->color())) ||
@@ -38,7 +38,7 @@ index ee900c7541af99c61844920433ae39e2648ae90b..59137008aeddc03d60c58a463206dc91
return OnError();
}
}
@@ -617,6 +618,22 @@ void ApplySystemPrintDialogData(
@@ -626,6 +627,22 @@ void ApplySystemPrintDialogData(
return PMSetCopies(print_settings, copies, false) == noErr;
}

View File

@@ -238,7 +238,7 @@ index 835cce73b7ab8b38c37d3e2650e12303d9d918e3..4460a00497dfaee0ba90cd5d14888055
+
#endif // UI_BASE_COCOA_REMOTE_ACCESSIBILITY_API_H_
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.h b/ui/views/cocoa/native_widget_mac_ns_window_host.h
index 2daaf2b78b7a60d340c2ff1651f8b5450db4af0f..3080adea0402f9d57cbde5d4350605d463ee5c8e 100644
index 6c2761b68d895fb1964e98865dd96cc37226fce0..563ee4da217ff4aabf2ef3452322da9e9ccefe4f 100644
--- a/ui/views/cocoa/native_widget_mac_ns_window_host.h
+++ b/ui/views/cocoa/native_widget_mac_ns_window_host.h
@@ -30,7 +30,9 @@
@@ -251,7 +251,7 @@ index 2daaf2b78b7a60d340c2ff1651f8b5450db4af0f..3080adea0402f9d57cbde5d4350605d4
@class NSView;
namespace remote_cocoa {
@@ -454,10 +456,12 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost
@@ -456,10 +458,12 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost
mojo::AssociatedRemote<remote_cocoa::mojom::NativeWidgetNSWindow>
remote_ns_window_remote_;
@@ -265,10 +265,10 @@ index 2daaf2b78b7a60d340c2ff1651f8b5450db4af0f..3080adea0402f9d57cbde5d4350605d4
// Used to force the NSApplication's focused accessibility element to be the
// views::Views accessibility tree when the NSView for this is focused.
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
index 53bdb4d62294f128b8f4b7bdcddf1052e15f331f..d052f5bb619bf4092810c6d5dd489a38a60026b0 100644
index 6e0f07f5e1107341d0232e4a76b7332620315c04..0135aada72ef0c3a85ab8d134462754eb31ad2df 100644
--- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm
+++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
@@ -339,7 +339,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
@@ -352,7 +352,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
NativeWidgetMacNSWindowHost::GetNativeViewAccessibleForNSView() const {
if (in_process_ns_window_bridge_)
return in_process_ns_window_bridge_->ns_view();
@@ -280,7 +280,7 @@ index 53bdb4d62294f128b8f4b7bdcddf1052e15f331f..d052f5bb619bf4092810c6d5dd489a38
}
gfx::NativeViewAccessible
@@ -354,7 +358,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
@@ -367,7 +371,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
return [in_process_ns_window_bridge_->ns_view() window];
}
@@ -292,7 +292,7 @@ index 53bdb4d62294f128b8f4b7bdcddf1052e15f331f..d052f5bb619bf4092810c6d5dd489a38
}
remote_cocoa::mojom::NativeWidgetNSWindow*
@@ -1353,20 +1361,24 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
@@ -1382,20 +1390,24 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
void NativeWidgetMacNSWindowHost::SetRemoteAccessibilityTokens(
const std::vector<uint8_t>& window_token,
const std::vector<uint8_t>& view_token) {

View File

@@ -706,7 +706,7 @@ index 3f9a514fb41d72c5d06de6ac989f9d7c0513a4e7..0e7ada9df962808dad7caf074a08ebde
// Tells the browser printing failed.
PrintingFailed(int32 cookie, PrintFailureReason reason);
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a6700c81d 100644
index 5a58210461222ed431624bf161b32770c5ae97e6..aec69c525cefd73e50f50883ac0dc8bee94e78c0 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -45,6 +45,7 @@
@@ -717,7 +717,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
#include "printing/units.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -1279,14 +1280,14 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
@@ -1237,14 +1238,14 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
}
print_in_progress_ = true;
@@ -734,7 +734,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
if (!weak_this) {
return;
}
@@ -1317,7 +1318,7 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver(
@@ -1275,7 +1276,7 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver(
receivers_.Add(this, std::move(receiver));
}
@@ -743,7 +743,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
ScopedIPC scoped_ipc(weak_ptr_factory_.GetWeakPtr());
if (ipc_nesting_level_ > kAllowedIpcDepthForPrint)
return;
@@ -1332,7 +1333,7 @@ void PrintRenderFrameHelper::PrintRequestedPages() {
@@ -1290,7 +1291,7 @@ void PrintRenderFrameHelper::PrintRequestedPages() {
// plugin node and print that instead.
auto plugin = delegate_->GetPdfElement(frame);
@@ -752,7 +752,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
if (render_frame_gone_) {
return;
@@ -1419,7 +1420,8 @@ void PrintRenderFrameHelper::PrintForSystemDialog() {
@@ -1377,7 +1378,8 @@ void PrintRenderFrameHelper::PrintForSystemDialog() {
}
Print(frame, print_preview_context_.source_node(),
@@ -762,7 +762,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
if (render_frame_gone_) {
return;
}
@@ -1482,6 +1484,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) {
@@ -1440,6 +1442,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) {
if (ipc_nesting_level_ > kAllowedIpcDepthForPrint)
return;
@@ -771,7 +771,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
print_preview_context_.OnPrintPreview();
#if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -2107,7 +2111,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
@@ -2065,7 +2069,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
}
Print(duplicate_node.GetDocument().GetFrame(), duplicate_node,
@@ -781,7 +781,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
// Check if `this` is still valid.
if (!weak_this) {
return;
@@ -2123,7 +2128,9 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
@@ -2081,7 +2086,9 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
const blink::WebNode& node,
@@ -792,7 +792,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
// If still not finished with earlier print request simply ignore.
if (prep_frame_view_)
return;
@@ -2131,7 +2138,7 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
@@ -2089,7 +2096,7 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
FrameReference frame_ref(frame);
uint32_t expected_page_count = 0;
@@ -801,7 +801,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
DidFinishPrinting(PrintingResult::kFailPrintInit);
return; // Failed to init print page settings.
}
@@ -2150,8 +2157,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
@@ -2108,8 +2115,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
print_pages_params_->params->print_scaling_option;
auto self = weak_ptr_factory_.GetWeakPtr();
@@ -818,7 +818,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
// Check if `this` is still valid.
if (!self)
return;
@@ -2391,35 +2405,47 @@ void PrintRenderFrameHelper::IPCProcessed() {
@@ -2349,35 +2363,47 @@ void PrintRenderFrameHelper::IPCProcessed() {
}
}
@@ -876,7 +876,7 @@ index ec3c62f88268d6cf0d8abadf483dacb31ff09d3d..b0af8b9f2286c95efabe66ecfc0eaa8a
return false;
}
@@ -2524,7 +2550,7 @@ mojom::PrintPagesParamsPtr PrintRenderFrameHelper::GetPrintSettingsFromUser(
@@ -2482,7 +2508,7 @@ mojom::PrintPagesParamsPtr PrintRenderFrameHelper::GetPrintSettingsFromUser(
std::move(params),
base::BindOnce(
[](base::OnceClosure quit_closure, mojom::PrintPagesParamsPtr* output,

View File

@@ -30,10 +30,10 @@ index fe010b1f001130fbdeaf4ef9ce7798e4baf958b5..28f1305f439be7f669e482ac0e4804c0
// 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 149ead7bbf52ad127747c5f80f0e35a13203502a..0f2a73f990fd41112d18ab6a9ed5bc43b90c235a 100644
index 2d946e29c94a07a1aa4f4b6018ab1b564440f55d..b013e7eaa4a5db79d19378e437d8d3d18dd1b2aa 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2121,6 +2121,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) {
@@ -2127,6 +2127,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) {
if (view_) {
view_->UpdateCursor(cursor);
}

File diff suppressed because it is too large Load Diff

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 40b63b1fbde84b8b3f854ce763474cd044f6ea96..5e95682e793616c4d88f62ad4d69c8c9f547e000 100644
index ef79bf0e27bd0c5eb9fe5f0aef1cf6c6a2900e13..f121a6b0395d9ee1cf5d5c03ee1dc8968167428a 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -7417,6 +7417,17 @@ void RenderFrameHostImpl::EnterFullscreen(
@@ -7435,6 +7435,17 @@ void RenderFrameHostImpl::EnterFullscreen(
}
}

0
patches/libvpx/.patches Normal file
View File

View File

@@ -46,3 +46,6 @@ tls_ensure_tls_sockets_are_closed_if_the_underlying_wrap_closes.patch
test_deflake_test-tls-socket-close.patch
net_fix_crash_due_to_simultaneous_close_shutdown_on_js_stream.patch
net_use_asserts_in_js_socket_stream_to_catch_races_in_future.patch
lib_fix_broadcastchannel_initialization_location.patch
fix_handle_possible_disabled_sharedarraybuffer.patch
win_process_avoid_assert_after_spawning_store_app_4152.patch

View File

@@ -11,7 +11,7 @@ trying to see whether or not the lines are greyed out. One possibility
would be to upstream a changed test that doesn't hardcode line numbers.
diff --git a/test/fixtures/errors/force_colors.snapshot b/test/fixtures/errors/force_colors.snapshot
index 0334a0b4faa3633aa8617b9538873e7f3540513b..7f85ddc507c9c38ce85ed2a48f8152eef168717b 100644
index 0334a0b4faa3633aa8617b9538873e7f3540513b..fa9989f55980aeddd3fa944318488c0289e3ab6e 100644
--- a/test/fixtures/errors/force_colors.snapshot
+++ b/test/fixtures/errors/force_colors.snapshot
@@ -4,11 +4,12 @@ throw new Error('Should include grayed stack trace')
@@ -27,7 +27,7 @@ index 0334a0b4faa3633aa8617b9538873e7f3540513b..7f85ddc507c9c38ce85ed2a48f8152ee
+ at Object..js (node:internal*modules*cjs*loader:1326:10)
+ at Module.load (node:internal*modules*cjs*loader:1126:32)
+ at node:internal*modules*cjs*loader:967:12
+ at Function._load (node:electron*js2c*asar_bundle:757:32)
+ at Function._load (node:electron*js2c*asar_bundle:743:32)
+ at Function.executeUserEntryPoint [as runMain] (node:internal*modules*run_main:96:12)
 at node:internal*main*run_main_module:23:47

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Mon, 2 Oct 2023 16:03:43 +0200
Subject: fix: handle possible disabled SharedArrayBuffer
It's possible for SharedArrayBuffer to be disabled with the -no-harmony-sharedarraybuffer
flag, and so we should guard uses with a check for potential undefined-ness.
This should be upstreamed to Node.js.
diff --git a/lib/internal/crypto/webidl.js b/lib/internal/crypto/webidl.js
index 9f5340c223902c5ff61def05e8a4f470b4f328e8..d6dbfa482f9ebff3f99fb810e072cf9a03d1cd4d 100644
--- a/lib/internal/crypto/webidl.js
+++ b/lib/internal/crypto/webidl.js
@@ -183,7 +183,10 @@ function isNonSharedArrayBuffer(V) {
return ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V);
}
+// SharedArrayBuffers can be disabled with --no-harmony-sharedarraybuffer.
function isSharedArrayBuffer(V) {
+ if (SharedArrayBuffer === undefined)
+ return false;
return ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V);
}
diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js
index be4d82086199855a10108528b3dacc663b839454..10c33bacc0529e12f52aaf1baf6d42489b2a75a7 100644
--- a/lib/internal/main/worker_thread.js
+++ b/lib/internal/main/worker_thread.js
@@ -108,6 +108,7 @@ port.on('message', (message) => {
require('internal/worker').assignEnvironmentData(environmentData);
+ // SharedArrayBuffers can be disabled with --no-harmony-sharedarraybuffer.
if (SharedArrayBuffer !== undefined) {
// The counter is only passed to the workers created by the main thread,
// not to workers created by other workers.

View File

@@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Mon, 27 Feb 2023 12:56:15 +0100
Subject: lib: fix BroadcastChannel initialization location
Refs https://github.com/nodejs/node/pull/40532.
Fixes a bug in the above, wherein BroadcastChannel should have been
initialized in bootstrap/browser instead of bootstrap/node. That
inadvertently made it such that there was incorrect handling of the
DOM vs Node.js implementations of BroadcastChannel.
This will be upstreamed.
diff --git a/lib/internal/bootstrap/browser.js b/lib/internal/bootstrap/browser.js
index 5be4dd6176482c724455cbbeeaa9680e849a091b..29ccee75d77da072735032f0a25363ac88a023ba 100644
--- a/lib/internal/bootstrap/browser.js
+++ b/lib/internal/bootstrap/browser.js
@@ -12,6 +12,10 @@ const {
} = require('internal/util');
const config = internalBinding('config');
+// Non-standard extensions:
+const { BroadcastChannel } = require('internal/worker/io');
+exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
+
// https://console.spec.whatwg.org/#console-namespace
exposeNamespace(globalThis, 'console',
createGlobalConsole());
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
index 13ea68c96fd415f976aab0f291a1b7c688db1c58..0ca3de08fffb344c0330ce0f8d28b2d3d0b24350 100644
--- a/lib/internal/bootstrap/node.js
+++ b/lib/internal/bootstrap/node.js
@@ -238,10 +238,6 @@ const {
queueMicrotask,
} = require('internal/process/task_queues');
-// Non-standard extensions:
-const { BroadcastChannel } = require('internal/worker/io');
-exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
-
defineOperation(globalThis, 'queueMicrotask', queueMicrotask);
const timers = require('timers');

View File

@@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jameson Nash <vtjnash@gmail.com>
Date: Mon, 2 Oct 2023 15:15:18 +0200
Subject: win,process: avoid assert after spawning Store app (#4152)
Make sure this handle is functional. The Windows kernel seems to have a
bug that if the first use of AssignProcessToJobObject is for a Windows
Store program, subsequent attempts to use the handle with fail with
INVALID_PARAMETER (87). This is possilby because all uses of the handle
must be for the same Terminal Services session. We can ensure it is
tied to our current session now by adding ourself to it. We could
remove ourself afterwards, but there doesn't seem to be a reason to.
Secondly, we start the process suspended so that we can make sure we
added it to the job control object before it does anything itself (such
as launch more jobs or exit).
Fixes: https://github.com/JuliaLang/julia/issues/51461
diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c
index 24c633393fd15dcf87726b174d6b027a969e0f0d..4ad9fec900fa66b0e8c6894701e94f420de903a8 100644
--- a/deps/uv/src/win/process.c
+++ b/deps/uv/src/win/process.c
@@ -102,6 +102,21 @@ static void uv__init_global_job_handle(void) {
&info,
sizeof info))
uv_fatal_error(GetLastError(), "SetInformationJobObject");
+
+
+ if (!AssignProcessToJobObject(uv_global_job_handle_, GetCurrentProcess())) {
+ /* Make sure this handle is functional. The Windows kernel has a bug that
+ * if the first use of AssignProcessToJobObject is for a Windows Store
+ * program, subsequent attempts to use the handle with fail with
+ * INVALID_PARAMETER (87). This is possibly because all uses of the handle
+ * must be for the same Terminal Services session. We can ensure it is tied
+ * to our current session now by adding ourself to it. We could remove
+ * ourself afterwards, but there doesn't seem to be a reason to.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
+ }
}
@@ -1098,6 +1113,7 @@ int uv_spawn(uv_loop_t* loop,
* breakaway.
*/
process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
+ process_flags |= CREATE_SUSPENDED;
}
if (!CreateProcessW(application_path,
@@ -1115,11 +1131,6 @@ int uv_spawn(uv_loop_t* loop,
goto done;
}
- /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
-
- process->process_handle = info.hProcess;
- process->pid = info.dwProcessId;
-
/* If the process isn't spawned as detached, assign to the global job object
* so windows will kill it when the parent process dies. */
if (!(options->flags & UV_PROCESS_DETACHED)) {
@@ -1142,6 +1153,19 @@ int uv_spawn(uv_loop_t* loop,
}
}
+ if (process_flags & CREATE_SUSPENDED) {
+ if (ResumeThread(info.hThread) == ((DWORD)-1)) {
+ err = GetLastError();
+ TerminateProcess(info.hProcess, 1);
+ goto done;
+ }
+ }
+
+ /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
+
+ process->process_handle = info.hProcess;
+ process->pid = info.dwProcessId;
+
/* Set IPC pid to all IPC pipes. */
for (i = 0; i < options->stdio_count; i++) {
const uv_stdio_container_t* fdopt = &options->stdio[i];

View File

@@ -1,3 +1,4 @@
fix_fallback_to_x11_capturer_on_wayland.patch
fix_mark_pipewire_capturer_as_failed_after_session_is_closed.patch
fix_check_pipewire_init_before_creating_generic_capturer.patch
pipewire_capturer_make_restore_tokens_re-usable_more_than_one_time.patch

View File

@@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jan Grulich <grulja@gmail.com>
Date: Mon, 9 Oct 2023 18:54:31 +0200
Subject: PipeWire capturer: make restore tokens re-usable more than one time
Do not automatically remove all tokens once we attempt to use them. This
mitigates an issue with Google Meet where an additional instance of a
DesktopCapturer is created and destroyed right away, taking away the
token we would use otherwise. Also save the token under same SourceId
once we get a new (but could be same) token from the restored session.
Bug: webrtc:15544
Change-Id: I565b22f5bf6a4d8a3b7d6d757f9c1046c7a0557d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322621
Commit-Queue: Jan Grulich <grulja@gmail.com>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#40892}
diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
index 5a67c18c1d1f62aa5e3162d9778ca665bac4a1bb..a5df76b0cdecd1e2e68f2f25c80c6b17de8bc808 100644
--- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
+++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
@@ -82,8 +82,10 @@ void BaseCapturerPipeWire::OnScreenCastRequestResult(RequestResponse result,
<< static_cast<uint>(result);
} else if (ScreenCastPortal* screencast_portal = GetScreenCastPortal()) {
if (!screencast_portal->RestoreToken().empty()) {
+ const SourceId token_id =
+ selected_source_id_ ? selected_source_id_ : source_id_;
RestoreTokenManager::GetInstance().AddToken(
- source_id_, screencast_portal->RestoreToken());
+ token_id, screencast_portal->RestoreToken());
}
}
@@ -138,7 +140,7 @@ void BaseCapturerPipeWire::Start(Callback* callback) {
ScreenCastPortal::PersistMode::kTransient);
if (selected_source_id_) {
screencast_portal->SetRestoreToken(
- RestoreTokenManager::GetInstance().TakeToken(selected_source_id_));
+ RestoreTokenManager::GetInstance().GetToken(selected_source_id_));
}
}
diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.cc b/modules/desktop_capture/linux/wayland/restore_token_manager.cc
index 5ca9b957a9e4f436bc09d4bc16019b169ae9ba9f..a17d9a49bb031efa340bfd61b4a6f8f5a86d09da 100644
--- a/modules/desktop_capture/linux/wayland/restore_token_manager.cc
+++ b/modules/desktop_capture/linux/wayland/restore_token_manager.cc
@@ -23,10 +23,8 @@ void RestoreTokenManager::AddToken(DesktopCapturer::SourceId id,
restore_tokens_.insert({id, token});
}
-std::string RestoreTokenManager::TakeToken(DesktopCapturer::SourceId id) {
- std::string token = restore_tokens_[id];
- // Remove the token as it cannot be used anymore
- restore_tokens_.erase(id);
+std::string RestoreTokenManager::GetToken(DesktopCapturer::SourceId id) {
+ const std::string token = restore_tokens_[id];
return token;
}
diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.h b/modules/desktop_capture/linux/wayland/restore_token_manager.h
index 174bef121f74b7b2b529d681b86c4fb4218586ea..ad4f74790f2a5cfba304fc11d47c9924db9013d8 100644
--- a/modules/desktop_capture/linux/wayland/restore_token_manager.h
+++ b/modules/desktop_capture/linux/wayland/restore_token_manager.h
@@ -27,7 +27,7 @@ class RestoreTokenManager {
static RestoreTokenManager& GetInstance();
void AddToken(DesktopCapturer::SourceId id, const std::string& token);
- std::string TakeToken(DesktopCapturer::SourceId id);
+ std::string GetToken(DesktopCapturer::SourceId id);
// Returns a source ID which does not have any token associated with it yet.
DesktopCapturer::SourceId GetUnusedId();

View File

@@ -953,6 +953,14 @@ void BaseWindow::AddTabbedWindow(NativeWindow* window,
args->ThrowError("AddTabbedWindow cannot be called by a window on itself.");
}
v8::Local<v8::Value> BaseWindow::GetTabbingIdentifier() {
auto tabbing_id = window_->GetTabbingIdentifier();
if (!tabbing_id.has_value())
return v8::Undefined(isolate());
return gin::ConvertToV8(isolate(), tabbing_id.value());
}
void BaseWindow::SetAutoHideMenuBar(bool auto_hide) {
window_->SetAutoHideMenuBar(auto_hide);
}
@@ -1305,6 +1313,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("moveTabToNewWindow", &BaseWindow::MoveTabToNewWindow)
.SetMethod("toggleTabBar", &BaseWindow::ToggleTabBar)
.SetMethod("addTabbedWindow", &BaseWindow::AddTabbedWindow)
.SetProperty("tabbingIdentifier", &BaseWindow::GetTabbingIdentifier)
.SetMethod("setWindowButtonVisibility",
&BaseWindow::SetWindowButtonVisibility)
.SetMethod("_getWindowButtonVisibility",

View File

@@ -198,9 +198,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
bool GetWindowButtonVisibility() const;
void SetWindowButtonPosition(absl::optional<gfx::Point> position);
absl::optional<gfx::Point> GetWindowButtonPosition() const;
#endif
#if BUILDFLAG(IS_MAC)
bool IsHiddenInMissionControl();
void SetHiddenInMissionControl(bool hidden);
#endif
@@ -215,6 +213,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
void MoveTabToNewWindow();
void ToggleTabBar();
void AddTabbedWindow(NativeWindow* window, gin_helper::Arguments* args);
v8::Local<v8::Value> GetTabbingIdentifier();
void SetAutoHideMenuBar(bool auto_hide);
bool IsMenuBarAutoHide();
void SetMenuBarVisibility(bool visible);

View File

@@ -216,7 +216,11 @@ void Notification::NotificationClosed() {
void Notification::Close() {
if (notification_) {
notification_->Dismiss();
if (notification_->is_dismissed()) {
notification_->Remove();
} else {
notification_->Dismiss();
}
notification_->set_delegate(nullptr);
notification_.reset();
}

View File

@@ -90,16 +90,15 @@ gin::ObjectTemplateBuilder SystemPreferences::GetObjectTemplateBuilder(
&SystemPreferences::IsSwipeTrackingFromScrollEventsEnabled)
.SetMethod("getEffectiveAppearance",
&SystemPreferences::GetEffectiveAppearance)
.SetMethod("getAppLevelAppearance",
&SystemPreferences::GetAppLevelAppearance)
.SetMethod("setAppLevelAppearance",
&SystemPreferences::SetAppLevelAppearance)
.SetMethod("getSystemColor", &SystemPreferences::GetSystemColor)
.SetMethod("canPromptTouchID", &SystemPreferences::CanPromptTouchID)
.SetMethod("promptTouchID", &SystemPreferences::PromptTouchID)
.SetMethod("isTrustedAccessibilityClient",
&SystemPreferences::IsTrustedAccessibilityClient)
.SetMethod("askForMediaAccess", &SystemPreferences::AskForMediaAccess)
.SetProperty(
"accessibilityDisplayShouldReduceTransparency",
&SystemPreferences::AccessibilityDisplayShouldReduceTransparency)
#endif
.SetMethod("getAnimationSettings",
&SystemPreferences::GetAnimationSettings);

View File

@@ -96,6 +96,7 @@ class SystemPreferences
gin::Arguments* args);
void RemoveUserDefault(const std::string& name);
bool IsSwipeTrackingFromScrollEventsEnabled();
bool AccessibilityDisplayShouldReduceTransparency();
std::string GetSystemColor(gin_helper::ErrorThrower thrower,
const std::string& color);
@@ -112,8 +113,6 @@ class SystemPreferences
// TODO(MarshallOfSound): Write tests for these methods once we
// are running tests on a Mojave machine
v8::Local<v8::Value> GetEffectiveAppearance(v8::Isolate* isolate);
v8::Local<v8::Value> GetAppLevelAppearance(v8::Isolate* isolate);
void SetAppLevelAppearance(gin::Arguments* args);
#endif
v8::Local<v8::Value> GetAnimationSettings(v8::Isolate* isolate);

View File

@@ -475,14 +475,7 @@ bool SystemPreferences::IsTrustedAccessibilityClient(bool prompt) {
std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
const std::string& color) {
NSColor* sysColor = nil;
if (color == "alternate-selected-control-text") {
sysColor = [NSColor alternateSelectedControlTextColor];
EmitWarning(
node::Environment::GetCurrent(thrower.isolate()),
"'alternate-selected-control-text' is deprecated as an input to "
"getColor. Use 'selected-content-background' instead.",
"electron");
} else if (color == "control-background") {
if (color == "control-background") {
sysColor = [NSColor controlBackgroundColor];
} else if (color == "control") {
sysColor = [NSColor controlColor];
@@ -609,19 +602,9 @@ v8::Local<v8::Value> SystemPreferences::GetEffectiveAppearance(
isolate, [NSApplication sharedApplication].effectiveAppearance);
}
v8::Local<v8::Value> SystemPreferences::GetAppLevelAppearance(
v8::Isolate* isolate) {
return gin::ConvertToV8(isolate,
[NSApplication sharedApplication].appearance);
}
void SystemPreferences::SetAppLevelAppearance(gin::Arguments* args) {
NSAppearance* appearance;
if (args->GetNext(&appearance)) {
[[NSApplication sharedApplication] setAppearance:appearance];
} else {
args->ThrowError();
}
bool SystemPreferences::AccessibilityDisplayShouldReduceTransparency() {
return [[NSWorkspace sharedWorkspace]
accessibilityDisplayShouldReduceTransparency];
}
} // namespace electron::api

View File

@@ -33,6 +33,7 @@
#include "components/security_state/content/content_utils.h"
#include "components/security_state/core/security_state.h"
#include "content/browser/renderer_host/frame_tree_node.h" // nogncheck
#include "content/browser/renderer_host/navigation_controller_impl.h" // nogncheck
#include "content/browser/renderer_host/render_frame_host_manager.h" // nogncheck
#include "content/browser/renderer_host/render_widget_host_impl.h" // nogncheck
#include "content/browser/renderer_host/render_widget_host_view_base.h" // nogncheck
@@ -468,9 +469,16 @@ base::IDMap<WebContents*>& GetAllWebContents() {
void OnCapturePageDone(gin_helper::Promise<gfx::Image> promise,
base::ScopedClosureRunner capture_handle,
const SkBitmap& bitmap) {
auto ui_task_runner = content::GetUIThreadTaskRunner({});
if (!ui_task_runner->RunsTasksInCurrentSequence()) {
ui_task_runner->PostTask(
FROM_HERE, base::BindOnce(&OnCapturePageDone, std::move(promise),
std::move(capture_handle), bitmap));
return;
}
// Hack to enable transparency in captured image
promise.Resolve(gfx::Image::CreateFrom1xBitmap(bitmap));
capture_handle.RunAndReset();
}
@@ -1726,13 +1734,6 @@ void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
void WebContents::PrimaryMainFrameRenderProcessGone(
base::TerminationStatus status) {
auto weak_this = GetWeakPtr();
Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
// User might destroy WebContents in the crashed event.
if (!weak_this || !web_contents())
return;
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Dictionary details = gin_helper::Dictionary::CreateEmpty(isolate);
@@ -2406,8 +2407,20 @@ void WebContents::LoadURL(const GURL& url,
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
// Discard non-committed entries to ensure that we don't re-use a pending
// entry
// It's not safe to start a new navigation or otherwise discard the current
// one while the call that started it is still on the stack. See
// http://crbug.com/347742.
auto& ctrl_impl = static_cast<content::NavigationControllerImpl&>(
web_contents()->GetController());
if (ctrl_impl.in_navigate_to_pending_entry()) {
Emit("did-fail-load", static_cast<int>(net::ERR_FAILED),
net::ErrorToShortString(net::ERR_FAILED), url.possibly_invalid_spec(),
true);
return;
}
// Discard non-committed entries to ensure we don't re-use a pending entry.
web_contents()->GetController().DiscardNonCommittedEntries();
web_contents()->GetController().LoadURLWithParams(params);
@@ -3427,22 +3440,16 @@ v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
}
auto* const view = web_contents()->GetRenderWidgetHostView();
if (!view) {
if (!view || view->GetViewBounds().size().IsEmpty()) {
promise.Resolve(gfx::Image());
return handle;
}
#if !BUILDFLAG(IS_MAC)
// If the view's renderer is suspended this may fail on Windows/Linux -
// bail if so. See CopyFromSurface in
// content/public/browser/render_widget_host_view.h.
auto* rfh = web_contents()->GetPrimaryMainFrame();
if (rfh &&
rfh->GetVisibilityState() == blink::mojom::PageVisibilityState::kHidden) {
promise.Resolve(gfx::Image());
if (!view->IsSurfaceAvailableForCopy()) {
promise.RejectWithErrorMessage(
"Current display surface not available for capture");
return handle;
}
#endif // BUILDFLAG(IS_MAC)
auto capture_handle = web_contents()->IncrementCapturerCount(
rect.size(), stay_hidden, stay_awake);

View File

@@ -57,7 +57,7 @@
#include "crypto/crypto_buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "electron/shell/common/api/api.mojom.h"
#include "extensions/browser/api/messaging/messaging_api_message_filter.h"
#include "extensions/browser/extension_navigation_ui_data.h"
#include "mojo/public/cpp/bindings/binder_map.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_private_key.h"
@@ -114,6 +114,7 @@
#include "shell/common/options_switches.h"
#include "shell/common/platform_util.h"
#include "shell/common/thread_restrictions.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
#include "third_party/blink/public/common/tokens/tokens.h"
@@ -147,6 +148,7 @@
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/file_url_loader.h"
#include "content/public/browser/web_ui_url_loader_factory.h"
#include "extensions/browser/api/messaging/messaging_api_message_filter.h"
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
#include "extensions/browser/api/web_request/web_request_api.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
@@ -154,7 +156,6 @@
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/extension_navigation_throttle.h"
#include "extensions/browser/extension_navigation_ui_data.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_protocols.h"
#include "extensions/browser/extension_registry.h"
@@ -172,7 +173,6 @@
#include "shell/browser/extensions/electron_extension_message_filter.h"
#include "shell/browser/extensions/electron_extension_system.h"
#include "shell/browser/extensions/electron_extension_web_contents_observer.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
@@ -1220,12 +1220,12 @@ void ElectronBrowserClient::
protocol_registry->RegisterURLLoaderFactories(factories,
false /* allow_file_access */);
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
factories->emplace(
extensions::kExtensionScheme,
extensions::CreateExtensionServiceWorkerScriptURLLoaderFactory(
browser_context));
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
}
bool ElectronBrowserClient::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
@@ -1413,9 +1413,10 @@ void ElectronBrowserClient::OverrideURLLoaderFactoryParams(
factory_params->disable_web_security = true;
}
}
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
browser_context, origin, is_for_isolated_world, factory_params);
#endif
}
void ElectronBrowserClient::
@@ -1473,7 +1474,7 @@ void ElectronBrowserClient::
},
&render_frame_host));
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
associated_registry.AddInterface<extensions::mojom::LocalFrameHost>(
base::BindRepeating(
[](content::RenderFrameHost* render_frame_host,

View File

@@ -79,12 +79,12 @@
#if BUILDFLAG(IS_LINUX)
#include "base/environment.h"
#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h"
#include "electron/electron_gtk_stubs.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
#include "ui/gfx/color_utils.h"
#include "ui/gtk/gtk_compat.h" // nogncheck
#include "ui/gtk/gtk_util.h" // nogncheck
#include "ui/linux/linux_ui.h"
@@ -169,36 +169,8 @@ std::u16string MediaStringProvider(media::MessageId id) {
}
}
#if BUILDFLAG(IS_LINUX)
// GTK does not provide a way to check if current theme is dark, so we compare
// the text and background luminosity to get a result.
// This trick comes from FireFox.
void UpdateDarkThemeSetting() {
float bg = color_utils::GetRelativeLuminance(gtk::GetBgColor("GtkLabel"));
float fg = color_utils::GetRelativeLuminance(gtk::GetFgColor("GtkLabel"));
bool is_dark = fg > bg;
// Pass it to NativeUi theme, which is used by the nativeTheme module and most
// places in Electron.
ui::NativeTheme::GetInstanceForNativeUi()->set_use_dark_colors(is_dark);
// Pass it to Web Theme, to make "prefers-color-scheme" media query work.
ui::NativeTheme::GetInstanceForWeb()->set_use_dark_colors(is_dark);
}
#endif
} // namespace
#if BUILDFLAG(IS_LINUX)
class DarkThemeObserver : public ui::NativeThemeObserver {
public:
DarkThemeObserver() = default;
// ui::NativeThemeObserver:
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override {
UpdateDarkThemeSetting();
}
};
#endif
// static
ElectronBrowserMainParts* ElectronBrowserMainParts::self_ = nullptr;
@@ -432,17 +404,10 @@ void ElectronBrowserMainParts::ToolkitInitialized() {
CHECK(electron::IsElectron_gdk_pixbufInitialized())
<< "Failed to initialize libgdk_pixbuf-2.0.so.0";
// Chromium does not respect GTK dark theme setting, but they may change
// in future and this code might be no longer needed. Check the Chromium
// issue to keep updated:
// https://bugs.chromium.org/p/chromium/issues/detail?id=998903
UpdateDarkThemeSetting();
// Update the native theme when GTK theme changes. The GetNativeTheme
// here returns a NativeThemeGtk, which monitors GTK settings.
dark_theme_observer_ = std::make_unique<DarkThemeObserver>();
auto* linux_ui_theme = ui::LinuxUiTheme::GetForProfile(nullptr);
CHECK(linux_ui_theme);
linux_ui_theme->GetNativeTheme()->AddObserver(dark_theme_observer_.get());
// source theme changes from system settings, including settings portal:
// https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Settings
dark_mode_manager_ = std::make_unique<ui::DarkModeManagerLinux>();
ui::LinuxUi::SetInstance(linux_ui);
// Cursor theme changes are tracked by LinuxUI (via a CursorThemeManager

View File

@@ -43,7 +43,8 @@ class Environment;
namespace ui {
class LinuxUiGetter;
}
class DarkModeManagerLinux;
} // namespace ui
namespace electron {
@@ -65,10 +66,6 @@ class ViewsDelegate;
class ViewsDelegateMac;
#endif
#if BUILDFLAG(IS_LINUX)
class DarkThemeObserver;
#endif
class ElectronBrowserMainParts : public content::BrowserMainParts {
public:
ElectronBrowserMainParts();
@@ -145,9 +142,7 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
#endif
#if BUILDFLAG(IS_LINUX)
// Used to notify the native theme of changes to dark mode.
std::unique_ptr<DarkThemeObserver> dark_theme_observer_;
std::unique_ptr<ui::DarkModeManagerLinux> dark_mode_manager_;
std::unique_ptr<ui::LinuxUiGetter> linux_ui_getter_;
#endif

View File

@@ -13,15 +13,15 @@
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "components/zoom/page_zoom_constants.h"
#include "pdf/buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/webui/web_ui_util.h"
#if BUILDFLAG(ENABLE_PDF)
#if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "chrome/browser/pdf/pdf_extension_util.h"
#include "pdf/pdf_features.h"
#endif // BUILDFLAG(ENABLE_PDF)
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
// To add a new component to this API, simply:
// 1. Add your component to the Component enum in
@@ -48,7 +48,7 @@ ExtensionFunction::ResponseAction ResourcesPrivateGetStringsFunction::Run() {
switch (component) {
case api::resources_private::COMPONENT_PDF:
#if BUILDFLAG(ENABLE_PDF)
#if BUILDFLAG(ENABLE_PDF_VIEWER)
pdf_extension_util::AddStrings(
pdf_extension_util::PdfViewerContext::kPdfViewer, &dict);
pdf_extension_util::AddAdditionalData(true, false, &dict);

View File

@@ -7,20 +7,27 @@
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/strings/pattern.h"
#include "base/types/expected_macros.h"
#include "chrome/common/url_constants.h"
#include "components/url_formatter/url_fixer.h"
#include "content/public/browser/navigation_entry.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension_features.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/mojom/host_id.mojom.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/switches.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/native_window.h"
#include "shell/browser/web_contents_zoom_controller.h"
#include "shell/browser/window_list.h"
#include "shell/common/extensions/api/tabs.h"
#include "third_party/blink/public/common/chrome_debug_urls.h"
#include "third_party/blink/public/common/page/page_zoom.h"
#include "url/gurl.h"
@@ -468,17 +475,25 @@ bool IsKillURL(const GURL& url) {
DCHECK(url.IsAboutBlank() || url.IsAboutSrcdoc());
#endif
static const char* const kill_hosts[] = {
chrome::kChromeUICrashHost, chrome::kChromeUIDelayedHangUIHost,
chrome::kChromeUIHangUIHost, chrome::kChromeUIKillHost,
// Disallow common renderer debug URLs.
// Note: this would also disallow JavaScript URLs, but we already explicitly
// check for those before calling into here from PrepareURLForNavigation.
if (blink::IsRendererDebugURL(url)) {
return true;
}
if (!url.SchemeIs(content::kChromeUIScheme)) {
return false;
}
// Also disallow a few more hosts which are not covered by the check above.
static const char* const kKillHosts[] = {
chrome::kChromeUIDelayedHangUIHost, chrome::kChromeUIHangUIHost,
chrome::kChromeUIQuitHost, chrome::kChromeUIRestartHost,
content::kChromeUIBrowserCrashHost, content::kChromeUIMemoryExhaustHost,
};
if (!url.SchemeIs(content::kChromeUIScheme))
return false;
return base::Contains(kill_hosts, url.host_piece());
return base::Contains(kKillHosts, url.host_piece());
}
GURL ResolvePossiblyRelativeURL(const std::string& url_string,
@@ -489,10 +504,18 @@ GURL ResolvePossiblyRelativeURL(const std::string& url_string,
return url;
}
bool PrepareURLForNavigation(const std::string& url_string,
const Extension* extension,
GURL* return_url,
std::string* error) {
bool AllowFileAccess(const ExtensionId& extension_id,
content::BrowserContext* context) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableExtensionsFileAccessCheck) ||
ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
}
base::expected<GURL, std::string> PrepareURLForNavigation(
const std::string& url_string,
const Extension* extension,
content::BrowserContext* browser_context) {
GURL url = ResolvePossiblyRelativeURL(url_string, extension);
// Ideally, the URL would only be "fixed" for user input (e.g. for URLs
@@ -504,34 +527,62 @@ bool PrepareURLForNavigation(const std::string& url_string,
// Reject invalid URLs.
if (!url.is_valid()) {
const char kInvalidUrlError[] = "Invalid url: \"*\".";
*error = ErrorUtils::FormatErrorMessage(kInvalidUrlError, url_string);
return false;
return base::unexpected(
ErrorUtils::FormatErrorMessage(kInvalidUrlError, url_string));
}
// Don't let the extension use JavaScript URLs in API triggered navigations.
if (url.SchemeIs(url::kJavaScriptScheme)) {
const char kJavaScriptUrlsNotAllowedInExtensionNavigations[] =
"JavaScript URLs are not allowed in API based extension navigations. "
"Use "
"chrome.scripting.executeScript instead.";
return base::unexpected(kJavaScriptUrlsNotAllowedInExtensionNavigations);
}
// Don't let the extension crash the browser or renderers.
if (IsKillURL(url)) {
const char kNoCrashBrowserError[] =
"I'm sorry. I'm afraid I can't do that.";
*error = kNoCrashBrowserError;
return false;
return base::unexpected(kNoCrashBrowserError);
}
// Don't let the extension navigate directly to devtools scheme pages, unless
// they have applicable permissions.
if (url.SchemeIs(content::kChromeDevToolsScheme) &&
!(extension->permissions_data()->HasAPIPermission(
extensions::mojom::APIPermissionID::kDevtools) ||
extension->permissions_data()->HasAPIPermission(
extensions::mojom::APIPermissionID::kDebugger))) {
const char kCannotNavigateToDevtools[] =
"Cannot navigate to a devtools:// page without either the devtools or "
"debugger permission.";
*error = kCannotNavigateToDevtools;
return false;
if (url.SchemeIs(content::kChromeDevToolsScheme)) {
bool has_permission =
extension && (extension->permissions_data()->HasAPIPermission(
mojom::APIPermissionID::kDevtools) ||
extension->permissions_data()->HasAPIPermission(
mojom::APIPermissionID::kDebugger));
if (!has_permission) {
const char kCannotNavigateToDevtools[] =
"Cannot navigate to a devtools:// page without either the devtools "
"or "
"debugger permission.";
return base::unexpected(kCannotNavigateToDevtools);
}
}
return_url->Swap(&url);
return true;
// Don't let the extension navigate directly to chrome-untrusted scheme pages.
if (url.SchemeIs(content::kChromeUIUntrustedScheme)) {
const char kCannotNavigateToChromeUntrusted[] =
"Cannot navigate to a chrome-untrusted:// page.";
return base::unexpected(kCannotNavigateToChromeUntrusted);
}
// Don't let the extension navigate directly to file scheme pages, unless
// they have file access.
if (url.SchemeIsFile() &&
!AllowFileAccess(extension->id(), browser_context) &&
base::FeatureList::IsEnabled(
extensions_features::kRestrictFileURLNavigation)) {
const char kFileUrlsNotAllowedInExtensionNavigations[] =
"Cannot navigate to a file URL without local file access.";
return base::unexpected(kFileUrlsNotAllowedInExtensionNavigations);
}
return url;
}
TabsUpdateFunction::TabsUpdateFunction() : web_contents_(nullptr) {}
@@ -566,22 +617,14 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
bool TabsUpdateFunction::UpdateURL(const std::string& url_string,
int tab_id,
std::string* error) {
GURL url;
if (!PrepareURLForNavigation(url_string, extension(), &url, error)) {
auto url =
PrepareURLForNavigation(url_string, extension(), browser_context());
if (!url.has_value()) {
*error = std::move(url.error());
return false;
}
const bool is_javascript_scheme = url.SchemeIs(url::kJavaScriptScheme);
// JavaScript URLs are forbidden in chrome.tabs.update().
if (is_javascript_scheme) {
const char kJavaScriptUrlsNotAllowedInTabsUpdate[] =
"JavaScript URLs are not allowed in chrome.tabs.update. Use "
"chrome.tabs.executeScript instead.";
*error = kJavaScriptUrlsNotAllowedInTabsUpdate;
return false;
}
content::NavigationController::LoadURLParams load_params(url);
content::NavigationController::LoadURLParams load_params(*url);
// Treat extension-initiated navigations as renderer-initiated so that the URL
// does not show in the omnibox until it commits. This avoids URL spoofs

View File

@@ -9,8 +9,10 @@
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/scoped_observation.h"
#include "chrome/common/chrome_features.h"
#include "content/public/browser/web_contents.h"
#include "electron/buildflags/buildflags.h"
#include "services/device/public/cpp/hid/hid_switches.h"
#include "shell/browser/electron_permission_manager.h"
#include "shell/browser/hid/hid_chooser_context.h"
@@ -19,9 +21,9 @@
#include "shell/browser/web_contents_permission_helper.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "extensions/common/constants.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
namespace {
@@ -35,6 +37,70 @@ electron::HidChooserContext* GetChooserContext(
namespace electron {
// Manages the HidDelegate observers for a single browser context.
class ElectronHidDelegate::ContextObservation
: public HidChooserContext::DeviceObserver {
public:
ContextObservation(ElectronHidDelegate* parent,
content::BrowserContext* browser_context)
: parent_(parent), browser_context_(browser_context) {
auto* chooser_context = GetChooserContext(browser_context_);
device_observation_.Observe(chooser_context);
}
ContextObservation(ContextObservation&) = delete;
ContextObservation& operator=(ContextObservation&) = delete;
~ContextObservation() override = default;
// HidChooserContext::DeviceObserver:
void OnDeviceAdded(const device::mojom::HidDeviceInfo& device_info) override {
for (auto& observer : observer_list_)
observer.OnDeviceAdded(device_info);
}
void OnDeviceRemoved(
const device::mojom::HidDeviceInfo& device_info) override {
for (auto& observer : observer_list_)
observer.OnDeviceRemoved(device_info);
}
void OnDeviceChanged(
const device::mojom::HidDeviceInfo& device_info) override {
for (auto& observer : observer_list_)
observer.OnDeviceChanged(device_info);
}
void OnHidManagerConnectionError() override {
for (auto& observer : observer_list_)
observer.OnHidManagerConnectionError();
}
void OnHidChooserContextShutdown() override {
parent_->observations_.erase(browser_context_);
// Return since `this` is now deleted.
}
void AddObserver(content::HidDelegate::Observer* observer) {
observer_list_.AddObserver(observer);
}
void RemoveObserver(content::HidDelegate::Observer* observer) {
observer_list_.RemoveObserver(observer);
}
private:
// Safe because `parent_` owns `this`.
const raw_ptr<ElectronHidDelegate> parent_;
// Safe because `this` is destroyed when the context is lost.
const raw_ptr<content::BrowserContext> browser_context_;
base::ScopedObservation<HidChooserContext, HidChooserContext::DeviceObserver>
device_observation_{this};
base::ObserverList<content::HidDelegate::Observer> observer_list_;
};
ElectronHidDelegate::ElectronHidDelegate() = default;
ElectronHidDelegate::~ElectronHidDelegate() = default;
@@ -44,11 +110,11 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters,
content::HidChooser::Callback callback) {
DCHECK(render_frame_host);
auto* chooser_context =
GetChooserContext(render_frame_host->GetBrowserContext());
if (!device_observation_.IsObserving())
device_observation_.Observe(chooser_context);
auto* browser_context = render_frame_host->GetBrowserContext();
// Start observing HidChooserContext for permission and device events.
GetContextObserver(browser_context);
DCHECK(base::Contains(observations_, browser_context));
HidChooserController* controller = ControllerForFrame(render_frame_host);
if (controller) {
@@ -100,16 +166,14 @@ device::mojom::HidManager* ElectronHidDelegate::GetHidManager(
void ElectronHidDelegate::AddObserver(content::BrowserContext* browser_context,
Observer* observer) {
observer_list_.AddObserver(observer);
auto* chooser_context = GetChooserContext(browser_context);
if (!device_observation_.IsObserving())
device_observation_.Observe(chooser_context);
GetContextObserver(browser_context)->AddObserver(observer);
}
void ElectronHidDelegate::RemoveObserver(
content::BrowserContext* browser_context,
content::HidDelegate::Observer* observer) {
observer_list_.RemoveObserver(observer);
DCHECK(base::Contains(observations_, browser_context));
GetContextObserver(browser_context)->RemoveObserver(observer);
}
const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo(
@@ -128,44 +192,25 @@ bool ElectronHidDelegate::IsFidoAllowedForOrigin(
bool ElectronHidDelegate::IsServiceWorkerAllowedForOrigin(
const url::Origin& origin) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// WebHID is only available on extension service workers with feature flag
// enabled for now.
if (base::FeatureList::IsEnabled(
features::kEnableWebHidOnExtensionServiceWorker) &&
origin.scheme() == extensions::kExtensionScheme)
return true;
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
return false;
}
void ElectronHidDelegate::OnDeviceAdded(
const device::mojom::HidDeviceInfo& device_info) {
for (auto& observer : observer_list_)
observer.OnDeviceAdded(device_info);
}
void ElectronHidDelegate::OnDeviceRemoved(
const device::mojom::HidDeviceInfo& device_info) {
for (auto& observer : observer_list_)
observer.OnDeviceRemoved(device_info);
}
void ElectronHidDelegate::OnDeviceChanged(
const device::mojom::HidDeviceInfo& device_info) {
for (auto& observer : observer_list_)
observer.OnDeviceChanged(device_info);
}
void ElectronHidDelegate::OnHidManagerConnectionError() {
device_observation_.Reset();
for (auto& observer : observer_list_)
observer.OnHidManagerConnectionError();
}
void ElectronHidDelegate::OnHidChooserContextShutdown() {
device_observation_.Reset();
ElectronHidDelegate::ContextObservation*
ElectronHidDelegate::GetContextObserver(
content::BrowserContext* browser_context) {
if (!base::Contains(observations_, browser_context)) {
observations_.emplace(browser_context, std::make_unique<ContextObservation>(
this, browser_context));
}
return observations_[browser_context].get();
}
HidChooserController* ElectronHidDelegate::ControllerForFrame(

View File

@@ -10,17 +10,24 @@
#include <unordered_map>
#include <vector>
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "base/containers/flat_map.h"
#include "content/public/browser/hid_chooser.h"
#include "content/public/browser/hid_delegate.h"
#include "services/device/public/mojom/hid.mojom-forward.h"
#include "shell/browser/hid/hid_chooser_context.h"
#include "third_party/blink/public/mojom/hid/hid.mojom-forward.h"
#include "url/origin.h"
namespace content {
class BrowserContext;
class RenderFrameHost;
} // namespace content
namespace electron {
class HidChooserController;
class ElectronHidDelegate : public content::HidDelegate,
public HidChooserContext::DeviceObserver {
class ElectronHidDelegate : public content::HidDelegate {
public:
ElectronHidDelegate();
ElectronHidDelegate(ElectronHidDelegate&) = delete;
@@ -54,13 +61,6 @@ class ElectronHidDelegate : public content::HidDelegate,
bool IsFidoAllowedForOrigin(content::BrowserContext* browser_context,
const url::Origin& origin) override;
bool IsServiceWorkerAllowedForOrigin(const url::Origin& origin) override;
// HidChooserContext::DeviceObserver:
void OnDeviceAdded(const device::mojom::HidDeviceInfo&) override;
void OnDeviceRemoved(const device::mojom::HidDeviceInfo&) override;
void OnDeviceChanged(const device::mojom::HidDeviceInfo&) override;
void OnHidManagerConnectionError() override;
void OnHidChooserContextShutdown() override;
void IncrementConnectionCount(content::BrowserContext* browser_context,
const url::Origin& origin) override {}
void DecrementConnectionCount(content::BrowserContext* browser_context,
@@ -69,6 +69,14 @@ class ElectronHidDelegate : public content::HidDelegate,
void DeleteControllerForFrame(content::RenderFrameHost* render_frame_host);
private:
class ContextObservation;
ContextObservation* GetContextObserver(
content::BrowserContext* browser_context);
base::flat_map<content::BrowserContext*, std::unique_ptr<ContextObservation>>
observations_;
HidChooserController* ControllerForFrame(
content::RenderFrameHost* render_frame_host);
@@ -78,10 +86,6 @@ class ElectronHidDelegate : public content::HidDelegate,
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters,
content::HidChooser::Callback callback);
base::ScopedObservation<HidChooserContext, HidChooserContext::DeviceObserver>
device_observation_{this};
base::ObserverList<content::HidDelegate::Observer> observer_list_;
std::unordered_map<content::RenderFrameHost*,
std::unique_ptr<HidChooserController>>
controller_map_;
@@ -91,23 +95,4 @@ class ElectronHidDelegate : public content::HidDelegate,
} // namespace electron
namespace base {
template <>
struct ScopedObservationTraits<electron::HidChooserContext,
electron::HidChooserContext::DeviceObserver> {
static void AddObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->AddDeviceObserver(observer);
}
static void RemoveObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->RemoveDeviceObserver(observer);
}
};
} // namespace base
#endif // ELECTRON_SHELL_BROWSER_HID_ELECTRON_HID_DELEGATE_H_

View File

@@ -14,6 +14,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observation_traits.h"
#include "base/unguessable_token.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/web_contents.h"
@@ -138,4 +139,23 @@ class HidChooserContext : public KeyedService,
} // namespace electron
namespace base {
template <>
struct ScopedObservationTraits<electron::HidChooserContext,
electron::HidChooserContext::DeviceObserver> {
static void AddObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->AddDeviceObserver(observer);
}
static void RemoveObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->RemoveDeviceObserver(observer);
}
};
} // namespace base
#endif // ELECTRON_SHELL_BROWSER_HID_HID_CHOOSER_CONTEXT_H_

View File

@@ -10,6 +10,7 @@
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/hid_chooser.h"
#include "content/public/browser/web_contents.h"

View File

@@ -99,6 +99,11 @@ NativeWindow::NativeWindow(const gin_helper::Dictionary& options,
options.Get(options::kTransparent, &transparent_);
options.Get(options::kEnableLargerThanScreen, &enable_larger_than_screen_);
options.Get(options::kTitleBarStyle, &title_bar_style_);
#if BUILDFLAG(IS_WIN)
options.Get(options::kBackgroundMaterial, &background_material_);
#elif BUILDFLAG(IS_MAC)
options.Get(options::kVibrancyType, &vibrancy_);
#endif
v8::Local<v8::Value> titlebar_overlay;
if (options.Get(options::ktitleBarOverlay, &titlebar_overlay)) {
@@ -352,10 +357,14 @@ void NativeWindow::SetContentSizeConstraints(
size_constraints_.reset();
}
// Windows/Linux:
// The return value of GetContentSizeConstraints will be passed to Chromium
// to set min/max sizes of window. Note that we are returning content size
// instead of window size because that is what Chromium expects, see the
// comment of |WidgetSizeIsClientSize| in Chromium's codebase to learn more.
//
// macOS:
// The min/max sizes are set directly by calling NSWindow's methods.
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() const {
if (content_size_constraints_)
return *content_size_constraints_;
@@ -475,6 +484,10 @@ bool NativeWindow::AddTabbedWindow(NativeWindow* window) {
return true; // for non-Mac platforms
}
absl::optional<std::string> NativeWindow::GetTabbingIdentifier() const {
return ""; // for non-Mac platforms
}
void NativeWindow::SetVibrancy(const std::string& type) {
vibrancy_ = type;
}
@@ -522,7 +535,7 @@ void NativeWindow::PreviewFile(const std::string& path,
void NativeWindow::CloseFilePreview() {}
gfx::Rect NativeWindow::GetWindowControlsOverlayRect() {
absl::optional<gfx::Rect> NativeWindow::GetWindowControlsOverlayRect() {
return overlay_rect_;
}
@@ -650,6 +663,7 @@ void NativeWindow::NotifyWindowMoved() {
}
void NativeWindow::NotifyWindowEnterFullScreen() {
NotifyLayoutWindowControlsOverlay();
for (NativeWindowObserver& observer : observers_)
observer.OnWindowEnterFullScreen();
}
@@ -675,6 +689,7 @@ void NativeWindow::NotifyWindowSheetEnd() {
}
void NativeWindow::NotifyWindowLeaveFullScreen() {
NotifyLayoutWindowControlsOverlay();
for (NativeWindowObserver& observer : observers_)
observer.OnWindowLeaveFullScreen();
}
@@ -718,10 +733,10 @@ void NativeWindow::NotifyWindowSystemContextMenu(int x,
}
void NativeWindow::NotifyLayoutWindowControlsOverlay() {
gfx::Rect bounding_rect = GetWindowControlsOverlayRect();
if (!bounding_rect.IsEmpty()) {
auto bounding_rect = GetWindowControlsOverlayRect();
if (bounding_rect.has_value()) {
for (NativeWindowObserver& observer : observers_)
observer.UpdateWindowControlsOverlay(bounding_rect);
observer.UpdateWindowControlsOverlay(bounding_rect.value());
}
}

View File

@@ -255,6 +255,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void MoveTabToNewWindow();
virtual void ToggleTabBar();
virtual bool AddTabbedWindow(NativeWindow* window);
virtual absl::optional<std::string> GetTabbingIdentifier() const;
// Toggle the menu bar.
virtual void SetAutoHideMenuBar(bool auto_hide);
@@ -284,7 +285,7 @@ class NativeWindow : public base::SupportsUserData,
return weak_factory_.GetWeakPtr();
}
virtual gfx::Rect GetWindowControlsOverlayRect();
virtual absl::optional<gfx::Rect> GetWindowControlsOverlayRect();
virtual void SetWindowControlsOverlayRect(const gfx::Rect& overlay_rect);
// Methods called by the WebContents.

View File

@@ -58,6 +58,8 @@ class NativeWindowMac : public NativeWindow,
gfx::Rect GetBounds() override;
bool IsNormal() override;
gfx::Rect GetNormalBounds() override;
void SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) override;
void SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) override;
void SetResizable(bool resizable) override;
@@ -143,6 +145,7 @@ class NativeWindowMac : public NativeWindow,
void MoveTabToNewWindow() override;
void ToggleTabBar() override;
bool AddTabbedWindow(NativeWindow* window) override;
absl::optional<std::string> GetTabbingIdentifier() const override;
void SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) override;
void PreviewFile(const std::string& path,
@@ -150,7 +153,7 @@ class NativeWindowMac : public NativeWindow,
void CloseFilePreview() override;
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
gfx::Rect GetWindowControlsOverlayRect() override;
absl::optional<gfx::Rect> GetWindowControlsOverlayRect() override;
void NotifyWindowEnterFullScreen() override;
void NotifyWindowLeaveFullScreen() override;
void SetActive(bool is_key) override;
@@ -186,6 +189,9 @@ class NativeWindowMac : public NativeWindow,
has_deferred_window_close_ = defer_close;
}
void set_wants_to_be_visible(bool visible) { wants_to_be_visible_ = visible; }
bool wants_to_be_visible() const { return wants_to_be_visible_; }
enum class VisualEffectState {
kFollowWindow,
kActive,
@@ -252,6 +258,10 @@ class NativeWindowMac : public NativeWindow,
// transition is complete.
bool has_deferred_window_close_ = false;
// If true, the window is either visible, or wants to be visible but is
// currently hidden due to having a hidden parent.
bool wants_to_be_visible_ = false;
NSInteger attention_request_id_ = 0; // identifier from requestUserAttention
// The presentation options before entering kiosk mode.

View File

@@ -496,6 +496,8 @@ void NativeWindowMac::Show() {
return;
}
set_wants_to_be_visible(true);
// Reattach the window to the parent to actually show it.
if (parent())
InternalSetParentWindow(parent(), true);
@@ -528,6 +530,10 @@ void NativeWindowMac::Hide() {
return;
}
// If the window wants to be visible and has a parent, then the parent may
// order it back in (in the period between orderOut: and close).
set_wants_to_be_visible(false);
DetachChildren();
// Detach the window from the parent before.
@@ -663,6 +669,9 @@ void NativeWindowMac::RemoveChildFromParentWindow() {
void NativeWindowMac::AttachChildren() {
for (auto* child : child_windows_) {
if (!static_cast<NativeWindowMac*>(child)->wants_to_be_visible())
continue;
auto* child_nswindow = child->GetNativeWindow().GetNativeNSWindow();
if ([child_nswindow parentWindow] == window_)
continue;
@@ -676,8 +685,6 @@ void NativeWindowMac::AttachChildren() {
}
void NativeWindowMac::DetachChildren() {
DCHECK(child_windows_.size() == [[window_ childWindows] count]);
// Hide all children before hiding/minimizing the window.
// NativeWidgetNSWindowBridge::NotifyVisibilityChangeDown()
// will DCHECK otherwise.
@@ -774,6 +781,16 @@ gfx::Rect NativeWindowMac::GetNormalBounds() {
// return widget()->GetRestoredBounds();
}
void NativeWindowMac::SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) {
// Apply the size constraints to NSWindow.
if (window_constraints.HasMinimumSize())
[window_ setMinSize:window_constraints.GetMinimumSize().ToCGSize()];
if (window_constraints.HasMaximumSize())
[window_ setMaxSize:window_constraints.GetMaximumSize().ToCGSize()];
NativeWindow::SetSizeConstraints(window_constraints);
}
void NativeWindowMac::SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) {
auto convertSize = [this](const gfx::Size& size) {
@@ -788,6 +805,7 @@ void NativeWindowMac::SetContentSizeConstraints(
}
};
// Apply the size constraints to NSWindow.
NSView* content = [window_ contentView];
if (size_constraints.HasMinimumSize()) {
NSSize min_size = convertSize(size_constraints.GetMinimumSize());
@@ -1422,11 +1440,21 @@ void NativeWindowMac::UpdateVibrancyRadii(bool fullscreen) {
if (vibrantView != nil && !vibrancy_type_.empty()) {
const bool no_rounded_corner = !HasStyleMask(NSWindowStyleMaskTitled);
if (!has_frame() && !is_modal() && !no_rounded_corner) {
const int macos_version = base::mac::MacOSMajorVersion();
// Modal window corners are rounded on macOS >= 11 or higher if the user
// hasn't passed noRoundedCorners.
bool should_round_modal =
!no_rounded_corner && (macos_version >= 11 ? true : !is_modal());
// Nonmodal window corners are rounded if they're frameless and the user
// hasn't passed noRoundedCorners.
bool should_round_nonmodal = !no_rounded_corner && !has_frame();
if (should_round_nonmodal || should_round_modal) {
CGFloat radius;
if (fullscreen) {
radius = 0.0f;
} else if (@available(macOS 11.0, *)) {
} else if (macos_version >= 11) {
radius = 9.0f;
} else {
// Smaller corner radius on versions prior to Big Sur.
@@ -1635,6 +1663,13 @@ bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
return true;
}
absl::optional<std::string> NativeWindowMac::GetTabbingIdentifier() const {
if ([window_ tabbingMode] == NSWindowTabbingModeDisallowed)
return absl::nullopt;
return base::SysNSStringToUTF8([window_ tabbingIdentifier]);
}
void NativeWindowMac::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
@@ -1875,23 +1910,33 @@ void NativeWindowMac::SetForwardMouseMessages(bool forward) {
[window_ setAcceptsMouseMovedEvents:forward];
}
gfx::Rect NativeWindowMac::GetWindowControlsOverlayRect() {
if (titlebar_overlay_ && buttons_proxy_ &&
window_button_visibility_.value_or(true)) {
absl::optional<gfx::Rect> NativeWindowMac::GetWindowControlsOverlayRect() {
if (!titlebar_overlay_)
return absl::nullopt;
// On macOS, when in fullscreen mode, window controls (the menu bar, title
// bar, and toolbar) are attached to a separate NSView that slides down from
// the top of the screen, independent of, and overlapping the WebContents.
// Disable WCO when in fullscreen, because this space is inaccessible to
// WebContents. https://crbug.com/915110.
if (IsFullscreen())
return gfx::Rect();
if (buttons_proxy_ && window_button_visibility_.value_or(true)) {
NSRect buttons = [buttons_proxy_ getButtonsContainerBounds];
gfx::Rect overlay;
overlay.set_width(GetContentSize().width() - NSWidth(buttons));
if ([buttons_proxy_ useCustomHeight]) {
overlay.set_height(titlebar_overlay_height());
} else {
overlay.set_height(NSHeight(buttons));
}
overlay.set_height([buttons_proxy_ useCustomHeight]
? titlebar_overlay_height()
: NSHeight(buttons));
if (!base::i18n::IsRTL())
overlay.set_x(NSMaxX(buttons));
return overlay;
}
return gfx::Rect();
return absl::nullopt;
}
// static

View File

@@ -7,6 +7,7 @@
#include <wrl/client.h>
#include "base/win/atl.h" // Must be before UIAutomationCore.h
#include "base/win/scoped_handle.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "shell/browser/browser.h"
#include "shell/browser/native_window_views.h"
@@ -165,10 +166,41 @@ gfx::ResizeEdge GetWindowResizeEdge(WPARAM param) {
}
}
bool IsMutexPresent(const wchar_t* name) {
base::win::ScopedHandle mutex_holder(::CreateMutex(nullptr, false, name));
return ::GetLastError() == ERROR_ALREADY_EXISTS;
}
bool IsLibraryLoaded(const wchar_t* name) {
HMODULE hmodule = nullptr;
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, name,
&hmodule);
return hmodule != nullptr;
}
// The official way to get screen reader status is to call:
// SystemParametersInfo(SPI_GETSCREENREADER) && UiaClientsAreListening()
// However it has false positives (for example when user is using touch screens)
// and will cause performance issues in some apps.
bool IsScreenReaderActive() {
UINT screenReader = 0;
SystemParametersInfo(SPI_GETSCREENREADER, 0, &screenReader, 0);
return screenReader && UiaClientsAreListening();
if (IsMutexPresent(L"NarratorRunning"))
return true;
static const wchar_t* names[] = {// NVDA
L"nvdaHelperRemote.dll",
// JAWS
L"jhook.dll",
// Window-Eyes
L"gwhk64.dll", L"gwmhook.dll",
// ZoomText
L"AiSquared.Infuser.HookLib.dll"};
for (auto* name : names) {
if (IsLibraryLoaded(name))
return true;
}
return false;
}
} // namespace

View File

@@ -27,10 +27,14 @@ void Notification::NotificationClicked() {
Destroy();
}
void Notification::NotificationDismissed() {
void Notification::NotificationDismissed(bool should_destroy) {
if (delegate())
delegate()->NotificationClosed();
Destroy();
set_is_dismissed(true);
if (should_destroy)
Destroy();
}
void Notification::NotificationFailed(const std::string& error) {
@@ -39,6 +43,8 @@ void Notification::NotificationFailed(const std::string& error) {
Destroy();
}
void Notification::Remove() {}
void Notification::Destroy() {
presenter()->RemoveNotification(this);
}

View File

@@ -50,13 +50,19 @@ class Notification {
// Shows the notification.
virtual void Show(const NotificationOptions& options) = 0;
// Closes the notification, this instance will be destroyed after the
// notification gets closed.
// Dismisses the notification. On some platforms this will result in full
// removal and destruction of the notification, but if the initial dismissal
// does not fully get rid of the notification it will be destroyed in Remove.
virtual void Dismiss() = 0;
// Removes the notification if it was not fully removed during dismissal,
// as can happen on some platforms including Windows.
virtual void Remove();
// Should be called by derived classes.
void NotificationClicked();
void NotificationDismissed();
void NotificationDismissed(bool should_destroy = true);
void NotificationFailed(const std::string& error = "");
// delete this.
@@ -68,10 +74,12 @@ class Notification {
void set_delegate(NotificationDelegate* delegate) { delegate_ = delegate; }
void set_notification_id(const std::string& id) { notification_id_ = id; }
void set_is_dismissed(bool dismissed) { is_dismissed_ = dismissed; }
NotificationDelegate* delegate() const { return delegate_; }
NotificationPresenter* presenter() const { return presenter_; }
const std::string& notification_id() const { return notification_id_; }
bool is_dismissed() const { return is_dismissed_; }
// disable copy
Notification(const Notification&) = delete;
@@ -85,6 +93,7 @@ class Notification {
raw_ptr<NotificationDelegate> delegate_;
raw_ptr<NotificationPresenter> presenter_;
std::string notification_id_;
bool is_dismissed_ = false;
base::WeakPtrFactory<Notification> weak_factory_{this};
};

View File

@@ -8,6 +8,8 @@
#include "shell/browser/notifications/win/windows_toast_notification.h"
#include <string_view>
#include <shlobj.h>
#include <wrl\wrappers\corewrappers.h>
@@ -34,6 +36,8 @@ using ABI::Windows::Data::Xml::Dom::IXmlNodeList;
using ABI::Windows::Data::Xml::Dom::IXmlText;
using Microsoft::WRL::Wrappers::HStringReference;
namespace winui = ABI::Windows::UI;
#define RETURN_IF_FAILED(hr) \
do { \
HRESULT _hrTemp = hr; \
@@ -47,8 +51,7 @@ using Microsoft::WRL::Wrappers::HStringReference;
std::string _msgTemp = msg; \
if (FAILED(_hrTemp)) { \
std::string _err = _msgTemp + ",ERROR " + std::to_string(_hrTemp); \
if (IsDebuggingNotifications()) \
LOG(INFO) << _err; \
DebugLog(_err); \
Notification::NotificationFailed(_err); \
return _hrTemp; \
} \
@@ -58,17 +61,23 @@ namespace electron {
namespace {
bool IsDebuggingNotifications() {
return base::Environment::Create()->HasVar("ELECTRON_DEBUG_NOTIFICATIONS");
// This string needs to be max 16 characters to work on Windows 10 prior to
// applying Creators Update (build 15063).
constexpr wchar_t kGroup[] = L"Notifications";
void DebugLog(std::string_view log_msg) {
if (base::Environment::Create()->HasVar("ELECTRON_DEBUG_NOTIFICATIONS"))
LOG(INFO) << log_msg;
}
} // namespace
// static
ComPtr<ABI::Windows::UI::Notifications::IToastNotificationManagerStatics>
ComPtr<winui::Notifications::IToastNotificationManagerStatics>
WindowsToastNotification::toast_manager_;
// static
ComPtr<ABI::Windows::UI::Notifications::IToastNotifier>
ComPtr<winui::Notifications::IToastNotifier>
WindowsToastNotification::toast_notifier_;
// static
@@ -112,17 +121,37 @@ WindowsToastNotification::~WindowsToastNotification() {
void WindowsToastNotification::Show(const NotificationOptions& options) {
if (SUCCEEDED(ShowInternal(options))) {
if (IsDebuggingNotifications())
LOG(INFO) << "Notification created";
DebugLog("Notification created");
if (delegate())
delegate()->NotificationDisplayed();
}
}
void WindowsToastNotification::Remove() {
DebugLog("Removing notification from action center");
ComPtr<winui::Notifications::IToastNotificationManagerStatics2>
toast_manager2;
if (FAILED(toast_manager_.As(&toast_manager2)))
return;
ComPtr<winui::Notifications::IToastNotificationHistory> notification_history;
if (FAILED(toast_manager2->get_History(&notification_history)))
return;
ScopedHString app_id;
if (!GetAppUserModelID(&app_id))
return;
ScopedHString group(kGroup);
ScopedHString tag(base::as_wcstr(base::UTF8ToUTF16(notification_id())));
notification_history->RemoveGroupedTagWithId(tag, group, app_id);
}
void WindowsToastNotification::Dismiss() {
if (IsDebuggingNotifications())
LOG(INFO) << "Hiding notification";
DebugLog("Hiding notification");
toast_notifier_->Hide(toast_notification_.Get());
}
@@ -151,8 +180,7 @@ HRESULT WindowsToastNotification::ShowInternal(
return E_FAIL;
}
ComPtr<ABI::Windows::UI::Notifications::IToastNotificationFactory>
toast_factory;
ComPtr<winui::Notifications::IToastNotificationFactory> toast_factory;
REPORT_AND_RETURN_IF_FAILED(
Windows::Foundation::GetActivationFactory(toast_str, &toast_factory),
"WinAPI: GetActivationFactory failed");
@@ -161,6 +189,19 @@ HRESULT WindowsToastNotification::ShowInternal(
toast_xml.Get(), &toast_notification_),
"WinAPI: CreateToastNotification failed");
ComPtr<winui::Notifications::IToastNotification2> toast2;
REPORT_AND_RETURN_IF_FAILED(
toast_notification_->QueryInterface(IID_PPV_ARGS(&toast2)),
"WinAPI: Getting Notification interface failed");
ScopedHString group(kGroup);
REPORT_AND_RETURN_IF_FAILED(toast2->put_Group(group),
"WinAPI: Setting group failed");
ScopedHString tag(base::as_wcstr(base::UTF8ToUTF16(notification_id())));
REPORT_AND_RETURN_IF_FAILED(toast2->put_Tag(tag),
"WinAPI: Setting tag failed");
REPORT_AND_RETURN_IF_FAILED(SetupCallbacks(toast_notification_.Get()),
"WinAPI: SetupCallbacks failed");
@@ -170,22 +211,20 @@ HRESULT WindowsToastNotification::ShowInternal(
}
HRESULT WindowsToastNotification::GetToastXml(
ABI::Windows::UI::Notifications::IToastNotificationManagerStatics*
toastManager,
winui::Notifications::IToastNotificationManagerStatics* toastManager,
const std::u16string& title,
const std::u16string& msg,
const std::wstring& icon_path,
const std::u16string& timeout_type,
bool silent,
IXmlDocument** toast_xml) {
ABI::Windows::UI::Notifications::ToastTemplateType template_type;
winui::Notifications::ToastTemplateType template_type;
if (title.empty() || msg.empty()) {
// Single line toast.
template_type =
icon_path.empty()
? ABI::Windows::UI::Notifications::ToastTemplateType_ToastText01
: ABI::Windows::UI::Notifications::
ToastTemplateType_ToastImageAndText01;
? winui::Notifications::ToastTemplateType_ToastText01
: winui::Notifications::ToastTemplateType_ToastImageAndText01;
REPORT_AND_RETURN_IF_FAILED(
toast_manager_->GetTemplateContent(template_type, toast_xml),
"XML: Fetching XML ToastImageAndText01 template failed");
@@ -199,9 +238,8 @@ HRESULT WindowsToastNotification::GetToastXml(
// Title and body toast.
template_type =
icon_path.empty()
? ABI::Windows::UI::Notifications::ToastTemplateType_ToastText02
: ABI::Windows::UI::Notifications::
ToastTemplateType_ToastImageAndText02;
? winui::Notifications::ToastTemplateType_ToastText02
: winui::Notifications::ToastTemplateType_ToastImageAndText02;
REPORT_AND_RETURN_IF_FAILED(
toastManager->GetTemplateContent(template_type, toast_xml),
"XML: Fetching XML ToastImageAndText02 template failed");
@@ -567,7 +605,7 @@ HRESULT WindowsToastNotification::XmlDocumentFromString(
}
HRESULT WindowsToastNotification::SetupCallbacks(
ABI::Windows::UI::Notifications::IToastNotification* toast) {
winui::Notifications::IToastNotification* toast) {
event_handler_ = Make<ToastEventHandler>(this);
RETURN_IF_FAILED(
toast->add_Activated(event_handler_.Get(), &activated_token_));
@@ -578,7 +616,7 @@ HRESULT WindowsToastNotification::SetupCallbacks(
}
bool WindowsToastNotification::RemoveCallbacks(
ABI::Windows::UI::Notifications::IToastNotification* toast) {
winui::Notifications::IToastNotification* toast) {
if (FAILED(toast->remove_Activated(activated_token_)))
return false;
@@ -597,32 +635,29 @@ ToastEventHandler::ToastEventHandler(Notification* notification)
ToastEventHandler::~ToastEventHandler() = default;
IFACEMETHODIMP ToastEventHandler::Invoke(
ABI::Windows::UI::Notifications::IToastNotification* sender,
winui::Notifications::IToastNotification* sender,
IInspectable* args) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&Notification::NotificationClicked, notification_));
if (IsDebuggingNotifications())
LOG(INFO) << "Notification clicked";
DebugLog("Notification clicked");
return S_OK;
}
IFACEMETHODIMP ToastEventHandler::Invoke(
ABI::Windows::UI::Notifications::IToastNotification* sender,
ABI::Windows::UI::Notifications::IToastDismissedEventArgs* e) {
winui::Notifications::IToastNotification* sender,
winui::Notifications::IToastDismissedEventArgs* e) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&Notification::NotificationDismissed, notification_));
if (IsDebuggingNotifications())
LOG(INFO) << "Notification dismissed";
FROM_HERE, base::BindOnce(&Notification::NotificationDismissed,
notification_, false));
DebugLog("Notification dismissed");
return S_OK;
}
IFACEMETHODIMP ToastEventHandler::Invoke(
ABI::Windows::UI::Notifications::IToastNotification* sender,
ABI::Windows::UI::Notifications::IToastFailedEventArgs* e) {
winui::Notifications::IToastNotification* sender,
winui::Notifications::IToastFailedEventArgs* e) {
HRESULT error;
e->get_ErrorCode(&error);
std::string errorMessage =
@@ -630,8 +665,7 @@ IFACEMETHODIMP ToastEventHandler::Invoke(
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&Notification::NotificationFailed,
notification_, errorMessage));
if (IsDebuggingNotifications())
LOG(INFO) << errorMessage;
DebugLog(errorMessage);
return S_OK;
}

View File

@@ -52,6 +52,7 @@ class WindowsToastNotification : public Notification {
// Notification:
void Show(const NotificationOptions& options) override;
void Dismiss() override;
void Remove() override;
private:
friend class ToastEventHandler;

View File

@@ -9,11 +9,11 @@
#include "base/containers/contains.h"
#include "base/values.h"
#include "content/public/common/webplugininfo.h"
#include "extensions/buildflags/buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "url/gurl.h"
#include "url/origin.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_util.h"
#include "extensions/common/constants.h"
@@ -36,7 +36,7 @@ base::flat_map<std::string, std::string>
PluginUtils::GetMimeTypeToExtensionIdMap(
content::BrowserContext* browser_context) {
base::flat_map<std::string, std::string> mime_type_to_extension_id_map;
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
std::vector<std::string> allowed_extension_ids =
MimeTypesHandler::GetMIMETypeAllowlist();
// Go through the white-listed extensions and try to use them to intercept

View File

@@ -262,6 +262,7 @@ using FullScreenTransitionState =
[super windowDidMiniaturize:notification];
is_minimized_ = true;
shell_->set_wants_to_be_visible(false);
shell_->NotifyWindowMinimize();
}
@@ -269,6 +270,7 @@ using FullScreenTransitionState =
[super windowDidDeminiaturize:notification];
is_minimized_ = false;
shell_->set_wants_to_be_visible(true);
shell_->AttachChildren();
shell_->SetWindowLevel(level_);
shell_->NotifyWindowRestore();

View File

@@ -142,8 +142,11 @@ void InspectableWebContentsViewViews::CloseDevTools() {
devtools_visible_ = false;
if (devtools_window_) {
inspectable_web_contents()->SaveDevToolsBounds(
devtools_window_->GetWindowBoundsInScreen());
auto save_bounds = devtools_window_->IsMinimized()
? devtools_window_->GetRestoredBounds()
: devtools_window_->GetWindowBoundsInScreen();
inspectable_web_contents()->SaveDevToolsBounds(save_bounds);
devtools_window_.reset();
devtools_window_web_view_ = nullptr;
devtools_window_delegate_ = nullptr;
@@ -216,6 +219,8 @@ const std::u16string InspectableWebContentsViewViews::GetTitle() {
void InspectableWebContentsViewViews::Layout() {
if (!devtools_web_view_->GetVisible()) {
contents_web_view_->SetBoundsRect(GetContentsBounds());
// Propagate layout call to all children, for example browser views.
View::Layout();
return;
}
@@ -233,6 +238,9 @@ void InspectableWebContentsViewViews::Layout() {
devtools_web_view_->SetBoundsRect(new_devtools_bounds);
contents_web_view_->SetBoundsRect(new_contents_bounds);
// Propagate layout call to all children, for example browser views.
View::Layout();
if (GetDelegate())
GetDelegate()->DevToolsResized();
}

View File

@@ -133,4 +133,14 @@ void ElectronDesktopWindowTreeHostWin::OnNativeThemeUpdated(
}
}
bool ElectronDesktopWindowTreeHostWin::ShouldWindowContentsBeTransparent()
const {
// Window should be marked as opaque if no transparency setting has been set,
// otherwise videos rendered in the window will trigger a DirectComposition
// redraw for every frame.
// https://github.com/electron/electron/pull/39895
return native_window_view_->GetOpacity() < 1.0 ||
native_window_view_->transparent();
}
} // namespace electron

View File

@@ -40,6 +40,7 @@ class ElectronDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin,
// ui::NativeThemeObserver:
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
bool ShouldWindowContentsBeTransparent() const override;
private:
raw_ptr<NativeWindowViews> native_window_view_; // weak ref

View File

@@ -13,7 +13,7 @@
#include "base/scoped_observation.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/buildflags/buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "services/device/public/mojom/usb_enumeration_options.mojom.h"
#include "shell/browser/electron_permission_manager.h"
#include "shell/browser/usb/usb_chooser_context.h"
@@ -21,7 +21,7 @@
#include "shell/browser/usb/usb_chooser_controller.h"
#include "shell/browser/web_contents_permission_helper.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "base/containers/fixed_flat_set.h"
#include "chrome/common/chrome_features.h"
#include "extensions/browser/extension_registry.h"
@@ -41,7 +41,7 @@ electron::UsbChooserContext* GetChooserContext(
browser_context);
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// These extensions can claim the smart card USB class and automatically gain
// permissions for devices that have an interface with this class.
constexpr auto kSmartCardPrivilegedExtensionIds =
@@ -65,12 +65,12 @@ bool DeviceHasInterfaceWithClass(
}
return false;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
bool IsDevicePermissionAutoGranted(
const url::Origin& origin,
const device::mojom::UsbDeviceInfo& device_info) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// Note: The `DeviceHasInterfaceWithClass()` call is made after checking the
// origin, since that method call is expensive.
if (origin.scheme() == extensions::kExtensionScheme &&
@@ -79,7 +79,7 @@ bool IsDevicePermissionAutoGranted(
device::mojom::kUsbSmartCardClass)) {
return true;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
return false;
}
@@ -251,14 +251,14 @@ ElectronUsbDelegate::GetContextObserver(
bool ElectronUsbDelegate::IsServiceWorkerAllowedForOrigin(
const url::Origin& origin) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// WebUSB is only available on extension service workers for now.
if (base::FeatureList::IsEnabled(
features::kEnableWebUsbOnExtensionServiceWorker) &&
origin.scheme() == extensions::kExtensionScheme) {
return true;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
return false;
}
@@ -289,7 +289,7 @@ void ElectronUsbDelegate::DeleteControllerForFrame(
bool ElectronUsbDelegate::PageMayUseUsb(content::Page& page) {
content::RenderFrameHost& main_rfh = page.GetMainDocument();
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// WebViewGuests have no mechanism to show permission prompts and their
// embedder can't grant USB access through its permissionrequest API. Also
// since webviews use a separate StoragePartition, they must not gain access
@@ -297,7 +297,7 @@ bool ElectronUsbDelegate::PageMayUseUsb(content::Page& page) {
if (extensions::WebViewGuest::FromRenderFrameHost(&main_rfh)) {
return false;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// USB permissions are scoped to a BrowserContext instead of a
// StoragePartition, so we need to be careful about usage across

View File

@@ -7,15 +7,15 @@
#include <utility>
#include "content/public/renderer/render_frame.h"
#include "extensions/buildflags/buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "chrome/common/pdf_util.h"
#include "extensions/common/constants.h"
#include "extensions/renderer/guest_view/mime_handler_view/post_message_support.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
namespace electron {
@@ -26,14 +26,14 @@ PrintRenderFrameHelperDelegate::~PrintRenderFrameHelperDelegate() = default;
// Return the PDF object element if |frame| is the out of process PDF extension.
blink::WebElement PrintRenderFrameHelperDelegate::GetPdfElement(
blink::WebLocalFrame* frame) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
if (frame->Parent() &&
IsPdfInternalPluginAllowedOrigin(frame->Parent()->GetSecurityOrigin())) {
auto plugin_element = frame->GetDocument().QuerySelector("embed");
DCHECK(!plugin_element.IsNull());
return plugin_element;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
return blink::WebElement();
}
@@ -43,7 +43,7 @@ bool PrintRenderFrameHelperDelegate::IsPrintPreviewEnabled() {
bool PrintRenderFrameHelperDelegate::OverridePrint(
blink::WebLocalFrame* frame) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
auto* post_message_support =
extensions::PostMessageSupport::FromWebLocalFrame(frame);
if (post_message_support) {
@@ -56,7 +56,7 @@ bool PrintRenderFrameHelperDelegate::OverridePrint(
post_message_support->PostMessageFromValue(base::Value(std::move(message)));
return true;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
return false;
}

View File

@@ -235,14 +235,6 @@ void RendererClientBase::RenderThreadStarted() {
extensions::ExtensionsRendererClient::Set(extensions_renderer_client_.get());
thread->AddObserver(extensions_renderer_client_->GetDispatcher());
#endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
spellcheck_ = std::make_unique<SpellCheck>(this);
#endif
blink::WebCustomElement::AddEmbedderCustomElementName("webview");
blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin");
WTF::String extension_scheme(extensions::kExtensionScheme);
// Extension resources are HTTP-like and safe to expose to the fetch API. The
@@ -255,6 +247,14 @@ void RendererClientBase::RenderThreadStarted() {
extension_scheme);
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
extension_scheme);
#endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
spellcheck_ = std::make_unique<SpellCheck>(this);
#endif
blink::WebCustomElement::AddEmbedderCustomElementName("webview");
blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin");
std::vector<std::string> fetch_enabled_schemes =
ParseSchemesCLISwitch(command_line, switches::kFetchSchemes);

View File

@@ -2066,10 +2066,7 @@ describe('BrowserWindow module', () => {
beforeEach(() => {
w = new BrowserWindow({ show: false });
});
afterEach(async () => {
await closeWindow(w);
w = null as unknown as BrowserWindow;
});
afterEach(closeAllWindows);
describe('BrowserWindow.selectPreviousTab()', () => {
it('does not throw', () => {
@@ -2138,6 +2135,18 @@ describe('BrowserWindow module', () => {
}).to.throw('AddTabbedWindow cannot be called by a window on itself.');
});
});
describe('BrowserWindow.tabbingIdentifier', () => {
it('is undefined if no tabbingIdentifier was set', () => {
const w = new BrowserWindow({ show: false });
expect(w.tabbingIdentifier).to.be.undefined('tabbingIdentifier');
});
it('returns the window tabbingIdentifier', () => {
const w = new BrowserWindow({ show: false, tabbingIdentifier: 'group1' });
expect(w.tabbingIdentifier).to.equal('group1');
});
});
});
describe('autoHideMenuBar state', () => {
@@ -2221,7 +2230,22 @@ describe('BrowserWindow module', () => {
expect(visible).to.equal('hidden');
});
it('resolves after the window is hidden', async () => {
it('resolves when the window is occluded', async () => {
const w1 = new BrowserWindow({ show: false });
w1.loadFile(path.join(fixtures, 'pages', 'a.html'));
await once(w1, 'ready-to-show');
w1.show();
const w2 = new BrowserWindow({ show: false });
w2.loadFile(path.join(fixtures, 'pages', 'a.html'));
await once(w2, 'ready-to-show');
w2.show();
const visibleImage = await w1.capturePage();
expect(visibleImage.isEmpty()).to.equal(false);
});
it('resolves when the window is not visible', async () => {
const w = new BrowserWindow({ show: false });
w.loadFile(path.join(fixtures, 'pages', 'a.html'));
await once(w, 'ready-to-show');
@@ -2230,21 +2254,10 @@ describe('BrowserWindow module', () => {
const visibleImage = await w.capturePage();
expect(visibleImage.isEmpty()).to.equal(false);
w.hide();
w.minimize();
const hiddenImage = await w.capturePage();
const isEmpty = process.platform !== 'darwin';
expect(hiddenImage.isEmpty()).to.equal(isEmpty);
});
it('resolves after the window is hidden and capturer count is non-zero', async () => {
const w = new BrowserWindow({ show: false });
w.webContents.setBackgroundThrottling(false);
w.loadFile(path.join(fixtures, 'pages', 'a.html'));
await once(w, 'ready-to-show');
const image = await w.capturePage();
expect(image.isEmpty()).to.equal(false);
expect(hiddenImage.isEmpty()).to.equal(false);
});
it('preserves transparency', async () => {
@@ -4716,7 +4729,27 @@ describe('BrowserWindow module', () => {
expect(w.getChildWindows().length).to.equal(0);
});
ifit(process.platform === 'darwin')('child window matches visibility when visibility changes', async () => {
ifit(process.platform === 'darwin')('only shows the intended window when a child with siblings is shown', async () => {
const w = new BrowserWindow({ show: false });
const childOne = new BrowserWindow({ show: false, parent: w });
const childTwo = new BrowserWindow({ show: false, parent: w });
const parentShown = once(w, 'show');
w.show();
await parentShown;
expect(childOne.isVisible()).to.be.false('childOne is visible');
expect(childTwo.isVisible()).to.be.false('childTwo is visible');
const childOneShown = once(childOne, 'show');
childOne.show();
await childOneShown;
expect(childOne.isVisible()).to.be.true('childOne is not visible');
expect(childTwo.isVisible()).to.be.false('childTwo is visible');
});
ifit(process.platform === 'darwin')('child matches parent visibility when parent visibility changes', async () => {
const w = new BrowserWindow({ show: false });
const c = new BrowserWindow({ show: false, parent: w });
@@ -4743,7 +4776,7 @@ describe('BrowserWindow module', () => {
expect(c.isVisible()).to.be.true('child is visible');
});
ifit(process.platform === 'darwin')('matches child window visibility when visibility changes', async () => {
ifit(process.platform === 'darwin')('parent matches child visibility when child visibility changes', async () => {
const w = new BrowserWindow({ show: false });
const c = new BrowserWindow({ show: false, parent: w });
@@ -6375,7 +6408,7 @@ describe('BrowserWindow module', () => {
foregroundWindow.loadFile(path.join(__dirname, 'fixtures', 'pages', 'css-transparent.html'));
await once(ipcMain, 'set-transparent');
await setTimeout();
await setTimeout(1000);
const screenCapture = await captureScreen();
const centerColor = getPixelColor(screenCapture, {
x: display.size.width / 2,
@@ -6398,7 +6431,7 @@ describe('BrowserWindow module', () => {
await once(window, 'show');
await window.webContents.loadURL('data:text/html,<head><meta name="color-scheme" content="dark"></head>');
await setTimeout(500);
await setTimeout(1000);
const screenCapture = await captureScreen();
const centerColor = getPixelColor(screenCapture, {
x: display.size.width / 2,
@@ -6428,6 +6461,7 @@ describe('BrowserWindow module', () => {
w.loadURL('about:blank');
await once(w, 'ready-to-show');
await setTimeout(1000);
const screenCapture = await captureScreen();
const centerColor = getPixelColor(screenCapture, {
x: display.size.width / 2,

View File

@@ -1,11 +1,9 @@
import { expect } from 'chai';
import { nativeTheme, systemPreferences, BrowserWindow, ipcMain } from 'electron/main';
import { nativeTheme, BrowserWindow, ipcMain } from 'electron/main';
import { once } from 'node:events';
import * as path from 'node:path';
import { setTimeout } from 'node:timers/promises';
import { expectDeprecationMessages } from './lib/deprecate-helpers';
import { ifdescribe } from './lib/spec-helpers';
import { closeAllWindows } from './lib/window-helpers';
describe('nativeTheme module', () => {
@@ -59,20 +57,6 @@ describe('nativeTheme module', () => {
expect(called).to.equal(false);
});
ifdescribe(process.platform === 'darwin')('on macOS', () => {
it('should update appLevelAppearance when set', async () => {
await expectDeprecationMessages(
() => {
nativeTheme.themeSource = 'dark';
expect(systemPreferences.appLevelAppearance).to.equal('dark');
nativeTheme.themeSource = 'light';
expect(systemPreferences.appLevelAppearance).to.equal('light');
},
"(electron) 'appLevelAppearance' is deprecated and will be removed."
);
});
});
const getPrefersColorSchemeIsDark = async (w: Electron.BrowserWindow) => {
const isDark: boolean = await w.webContents.executeJavaScript(
'matchMedia("(prefers-color-scheme: dark)").matches'

View File

@@ -1,6 +1,5 @@
import { expect } from 'chai';
import { systemPreferences } from 'electron/main';
import { expectDeprecationMessages } from './lib/deprecate-helpers';
import { ifdescribe } from './lib/spec-helpers';
describe('systemPreferences module', () => {
@@ -215,52 +214,6 @@ describe('systemPreferences module', () => {
const sysColor = systemPreferences.getColor(color);
expect(sysColor).to.be.a('string');
});
await expectDeprecationMessages(
() => {
const sysColor = systemPreferences.getColor('alternate-selected-control-text');
expect(sysColor).to.be.a('string');
},
"'alternate-selected-control-text' is deprecated as an input to getColor. Use 'selected-content-background' instead."
);
});
});
ifdescribe(process.platform === 'darwin')('systemPreferences.appLevelAppearance', () => {
const options = ['dark', 'light', 'unknown', null];
describe('with properties', () => {
it('returns a valid appearance', () => {
const appearance = systemPreferences.appLevelAppearance;
expect(options).to.include(appearance);
});
it('can be changed', () => {
systemPreferences.appLevelAppearance = 'dark';
expect(systemPreferences.appLevelAppearance).to.eql('dark');
});
});
describe('with functions', () => {
it('returns a valid appearance', async () => {
await expectDeprecationMessages(
() => {
const appearance = systemPreferences.getAppLevelAppearance();
expect(options).to.include(appearance);
},
"(electron) 'getAppLevelAppearance function' is deprecated and will be removed."
);
});
it('can be changed', async () => {
await expectDeprecationMessages(
() => {
systemPreferences.setAppLevelAppearance('dark');
const appearance = systemPreferences.getAppLevelAppearance();
expect(appearance).to.eql('dark');
},
"(electron) 'setAppLevelAppearance function' is deprecated and will be removed."
);
});
});
});

View File

@@ -431,6 +431,19 @@ describe('webContents module', () => {
}
});
it('fails if loadURL is called inside a non-reentrant critical section', (done) => {
w.webContents.once('did-fail-load', (_event, _errorCode, _errorDescription, validatedURL) => {
expect(validatedURL).to.contain('blank.html');
done();
});
w.webContents.once('did-start-loading', () => {
w.loadURL(`file://${fixturesPath}/pages/blank.html`);
});
w.loadURL('data:text/html,<h1>HELLO</h1>');
});
it('sets appropriate error information on rejection', async () => {
let err: any;
try {
@@ -2270,13 +2283,13 @@ describe('webContents module', () => {
});
describe('crashed event', () => {
it('does not crash main process when destroying WebContents in it', async () => {
it('does not crash main process when destroying WebContents in it', (done) => {
const contents = (webContents as typeof ElectronInternal.WebContents).create({ nodeIntegration: true });
const crashEvent = once(contents, 'render-process-gone');
await contents.loadURL('about:blank');
contents.forcefullyCrashRenderer();
await crashEvent;
contents.destroy();
contents.once('crashed', () => {
contents.destroy();
done();
});
contents.loadURL('about:blank').then(() => contents.forcefullyCrashRenderer());
});
});

View File

@@ -1039,33 +1039,77 @@ describe('chrome extensions', () => {
});
});
it('update', async () => {
await w.loadURL(url);
describe('update', () => {
it('can update muted status', async () => {
await w.loadURL(url);
const message = { method: 'update', args: [{ muted: true }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const message = { method: 'update', args: [{ muted: true }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [,, responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
const [,, responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
expect(response).to.have.property('url').that.is.a('string');
expect(response).to.have.property('title').that.is.a('string');
expect(response).to.have.property('active').that.is.a('boolean');
expect(response).to.have.property('autoDiscardable').that.is.a('boolean');
expect(response).to.have.property('discarded').that.is.a('boolean');
expect(response).to.have.property('groupId').that.is.a('number');
expect(response).to.have.property('highlighted').that.is.a('boolean');
expect(response).to.have.property('id').that.is.a('number');
expect(response).to.have.property('incognito').that.is.a('boolean');
expect(response).to.have.property('index').that.is.a('number');
expect(response).to.have.property('pinned').that.is.a('boolean');
expect(response).to.have.property('selected').that.is.a('boolean');
expect(response).to.have.property('windowId').that.is.a('number');
expect(response).to.have.property('mutedInfo').that.is.a('object');
const { mutedInfo } = response;
expect(mutedInfo).to.deep.eq({
muted: true,
reason: 'user'
expect(response).to.have.property('mutedInfo').that.is.a('object');
const { mutedInfo } = response;
expect(mutedInfo).to.deep.eq({
muted: true,
reason: 'user'
});
});
it('fails when navigating to an invalid url', async () => {
await w.loadURL(url);
const message = { method: 'update', args: [{ url: 'chrome://crash' }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [,, responseString] = await once(w.webContents, 'console-message');
const { error } = JSON.parse(responseString);
expect(error).to.eq('I\'m sorry. I\'m afraid I can\'t do that.');
});
it('fails when navigating to prohibited url', async () => {
await w.loadURL(url);
const message = { method: 'update', args: [{ url: 'chrome://crash' }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [,, responseString] = await once(w.webContents, 'console-message');
const { error } = JSON.parse(responseString);
expect(error).to.eq('I\'m sorry. I\'m afraid I can\'t do that.');
});
it('fails when navigating to a devtools url without permission', async () => {
await w.loadURL(url);
const message = { method: 'update', args: [{ url: 'devtools://blah' }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [, , responseString] = await once(w.webContents, 'console-message');
const { error } = JSON.parse(responseString);
expect(error).to.eq('Cannot navigate to a devtools:// page without either the devtools or debugger permission.');
});
it('fails when navigating to a chrome-untrusted url', async () => {
await w.loadURL(url);
const message = { method: 'update', args: [{ url: 'chrome-untrusted://blah' }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [, , responseString] = await once(w.webContents, 'console-message');
const { error } = JSON.parse(responseString);
expect(error).to.eq('Cannot navigate to a chrome-untrusted:// page.');
});
it('fails when navigating to a file url withotut file access', async () => {
await w.loadURL(url);
const message = { method: 'update', args: [{ url: 'file://blah' }] };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [, , responseString] = await once(w.webContents, 'console-message');
const { error } = JSON.parse(responseString);
expect(error).to.eq('Cannot navigate to a file URL without local file access.');
});
});

View File

@@ -1,6 +1,6 @@
/* global chrome */
const handleRequest = (request, sender, sendResponse) => {
const handleRequest = async (request, sender, sendResponse) => {
const { method, args = [] } = request;
const tabId = sender.tab.id;
@@ -53,7 +53,12 @@ const handleRequest = (request, sender, sendResponse) => {
case 'update': {
const [params] = args;
chrome.tabs.update(tabId, params).then(sendResponse);
try {
const response = await chrome.tabs.update(tabId, params);
sendResponse(response);
} catch (error) {
sendResponse({ error: error.message });
}
break;
}
}

View File

@@ -377,6 +377,14 @@ if (process.platform === 'darwin') {
console.log(value);
const value2 = systemPreferences.getUserDefault('Foo', 'boolean');
console.log(value2);
// @ts-expect-error Removed API
console.log(systemPreferences.getAppLevelAppearance());
// @ts-expect-error Removed API
systemPreferences.setAppLevelAppearance('dark');
// @ts-expect-error Removed API
console.log(systemPreferences.appLevelAppearance);
// @ts-expect-error Removed API
console.log(systemPreferences.getColor('alternate-selected-control-text'));
}
// Create the window.
@@ -421,6 +429,11 @@ win2.once('ready-to-show', () => {
app.relaunch({ args: process.argv.slice(1).concat(['--relaunch']) });
app.exit(0);
app.configureHostResolver({ secureDnsMode: 'off' });
// @ts-expect-error Invalid type value
app.configureHostResolver({ secureDnsMode: 'foo' });
// auto-updater
// https://github.com/electron/electron/blob/main/docs/api/auto-updater.md
@@ -1273,6 +1286,11 @@ win4.webContents.on('devtools-open-url', (event, url) => {
console.log(url);
});
win4.webContents.insertCSS('body {}', { cssOrigin: 'user' });
// @ts-expect-error Invalid type value
win4.webContents.insertCSS('body {}', { cssOrigin: 'foo' });
win4.loadURL('http://github.com');
// @ts-expect-error Removed API