Compare commits

..

26 Commits

Author SHA1 Message Date
Keeley Hammond
d608364b81 chore: patch upstreamed 2025-04-22 13:53:57 -07:00
Keeley Hammond
5622e6252a chore: cherry-pick 0333ecde9142 from chromium 2025-04-22 13:16:06 -07:00
trop[bot]
ee54727582 build: don't kill ssh sessions on checkout failure (#46717)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-22 11:31:35 -05:00
trop[bot]
f6f9e23fe2 fix: stop menu minimization if set false (#46715)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Michaela Laurencin <mlaurencin@electronjs.org>
2025-04-22 09:44:36 -05:00
trop[bot]
6e56fed2cb fix: file dialog filters not working correctly (#46721)
fix: fix file dialog filters not working correctly

If someone sets an `All filter` with `*` at the start of the filters all upcoming filters will be shifted and thus labels won't fit to the extensions they actually filter.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Kolja Lampe <razzeee@gmail.com>
2025-04-22 09:28:23 -05:00
trop[bot]
3437927a78 docs: cleanup docs/tutorial/custom-window-styles.md (#46711)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2025-04-22 10:32:54 +02:00
trop[bot]
1543089e2f perf: avoid triple map lookup in ElectronHidDelegate::GetContextObserver() (#46685)
perf: avoid triple map lookup in ElectronHidDelegate::GetContextObserver()

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-04-19 15:13:36 -05:00
trop[bot]
dc9f6ecd54 fix: do not run microtasks in V8Serializer in browser process (#46684)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: clavin <clavin@electronjs.org>
2025-04-19 12:18:42 -05:00
trop[bot]
6d07f541b1 refactor: remove WebContentsPermissionHelper::PermissionTypes::KEYBOARD_LOCK (#46679)
refactor: remove electron::WebContentsPermissionHelper::PermissionTypes::KEYBOARD_LOCK

This was added in 344aba0. In the time when this PR initially went up and
when 344aba0 landed, upstream added blink::PermissionTypes::KEYBOARD_LOCK.
Our duplicate copy can be removed.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-04-19 10:51:35 -05:00
trop[bot]
0675686451 fix: postMessage crash with invalid transferrable (#46666)
* fix: postMessage crash with invalid transferrable

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

* chore: address review feedback

Co-authored-by: Charles Kerr <charles@charleskerr.com>

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>
2025-04-17 18:23:26 +02:00
trop[bot]
ee04cb9ebe build: update build tools (#46662)
* build: update build tools

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* chore: fix core.fscache

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

* chore: fix core.preloadindex

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-17 10:56:35 -04:00
trop[bot]
592d0155f1 feat: expose nativeTheme.shouldUseDarkColorsForSystemIntegratedUI (#46599)
feat: expose shouldUseDarkColorsForSystemIntegratedUI

Closes https://github.com/electron/electron/issues/46429.
Refs https://github.com/electron/electron/pull/19735.

This PR adds a new API `shouldUseDarkColorsForSystemIntegratedUI` to the
`nativeTheme` module. This API returns a boolean indicating whether the
system is using dark colors for system integrated UI elements. This is
useful for applications that want to adapt their UI to match the system
theme, especially for those that use system integrated UI elements like
the shell theme or taskbar appearance.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-16 19:40:51 +02:00
electron-roller[bot]
1d2107ebff chore: bump chromium to 134.0.6998.205 (35-x-y) (#46655)
chore: bump chromium in DEPS to 134.0.6998.205

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2025-04-16 11:26:39 -05:00
Shelley Vohr
3d535afc28 fix: assert.ok in the renderer process (#46632)
* fix: assert.ok in the renderer process

* fix: patch indices
2025-04-15 17:01:34 -04:00
trop[bot]
88a1448b31 fix: window border on Gnome Wayland (#46644)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-15 20:56:30 +02:00
trop[bot]
b2e695c2e2 fix: paint and flash issues on macOS (#46628)
* fix: paint and flash issues on macOS

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

* Adhere to paintWhenInitiallyHidden

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

* fix: patch indices

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-15 20:33:15 +02:00
Filip Mösner
c438ed4790 docs: webContents.opener can be null (#46579) 2025-04-15 12:56:03 +02:00
trop[bot]
b1fdf2a8c7 build: roll build-images (#46635)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-15 11:30:19 +02:00
Shelley Vohr
48a7d5d45b fix: hard crash on invalid command line switches (#46631) 2025-04-14 23:46:24 -05:00
trop[bot]
f2a27511b1 fix: handle potential missing close event property (#46620)
fix: handle missing close event property

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-14 11:23:57 +02:00
trop[bot]
23035a587e refactor: use default printing path when no user options (#46616)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-11 16:15:38 -04:00
trop[bot]
f66c385080 build: ignore files in .git when running markdownlint-cli2 (#46609)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2025-04-11 11:21:26 +02:00
trop[bot]
323aca8822 fix: remove obsoleted --inspect-brk logic (#46583)
fix: remove obsoleted --inspect-brk logic

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-10 11:17:48 +02:00
trop[bot]
abef5d6eed fix: NativeWindow.window_id() returns same value for all windows (#46591)
fix: NativeWindow.window_id() returns same value for all windows

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-04-09 16:05:41 -05:00
electron-roller[bot]
c6c4ace8ef chore: bump chromium to 134.0.6998.196 (35-x-y) (#46572)
* chore: bump chromium in DEPS to 134.0.6998.196

* chore: e patches all

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-04-09 12:31:42 -04:00
trop[bot]
f26645e9ab fix: crash on parent window close and focur/blur (#46581)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-04-09 11:18:47 -05:00
50 changed files with 353 additions and 139 deletions

View File

@@ -2,7 +2,7 @@ version: '3'
services:
buildtools:
image: ghcr.io/electron/devcontainer:9f11982e806f439d0a0a8ebbbf566cd5e0d9e952
image: ghcr.io/electron/devcontainer:424eedbf277ad9749ffa9219068aa72ed4a5e373
volumes:
- ..:/workspaces/gclient/src/electron:cached

View File

@@ -179,3 +179,11 @@ runs:
else
echo "Cache key persisted in $final_cache_path"
fi
- name: Wait for active SSH sessions
shell: bash
if: always() && !cancelled()
run: |
while [ -f /var/.ssh-lock ]
do
sleep 60
done

View File

@@ -10,8 +10,10 @@ runs:
git config --global core.filemode false
git config --global core.autocrlf false
git config --global branch.autosetuprebase always
git config --global core.fscache true
git config --global core.preloadindex true
fi
export BUILD_TOOLS_SHA=8246e57791b0af4ae5975eb96f09855f9269b1cd
export BUILD_TOOLS_SHA=6e8526315ea3b4828882497e532b8340e64e053c
npm i -g @electron/build-tools
e auto-update disable
e d auto-update disable

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '9f11982e806f439d0a0a8ebbbf566cd5e0d9e952'
default: '424eedbf277ad9749ffa9219068aa72ed4a5e373'
required: true
skip-macos:
type: boolean
@@ -64,7 +64,7 @@ jobs:
id: set-output
run: |
if [ -z "${{ inputs.build-image-sha }}" ]; then
echo "build-image-sha=9f11982e806f439d0a0a8ebbbf566cd5e0d9e952" >> "$GITHUB_OUTPUT"
echo "build-image-sha=424eedbf277ad9749ffa9219068aa72ed4a5e373" >> "$GITHUB_OUTPUT"
else
echo "build-image-sha=${{ inputs.build-image-sha }}" >> "$GITHUB_OUTPUT"
fi

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '9f11982e806f439d0a0a8ebbbf566cd5e0d9e952'
default: '424eedbf277ad9749ffa9219068aa72ed4a5e373'
upload-to-storage:
description: 'Uploads to Azure storage'
required: false

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '9f11982e806f439d0a0a8ebbbf566cd5e0d9e952'
default: '424eedbf277ad9749ffa9219068aa72ed4a5e373'
required: true
upload-to-storage:
description: 'Uploads to Azure storage'

View File

@@ -134,6 +134,8 @@ jobs:
git config --global core.filemode false
git config --global core.autocrlf false
git config --global branch.autosetuprebase always
git config --global core.fscache true
git config --global core.preloadindex true
git clone --filter=tree:0 https://chromium.googlesource.com/chromium/tools/depot_tools.git
# Ensure depot_tools does not update.
test -d depot_tools && cd depot_tools

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '9f11982e806f439d0a0a8ebbbf566cd5e0d9e952'
default: '424eedbf277ad9749ffa9219068aa72ed4a5e373'
required: true
upload-to-storage:
description: 'Uploads to Azure storage'

2
DEPS
View File

@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'134.0.6998.179',
'134.0.6998.205',
'node_version':
'v22.14.0',
'nan_version':

View File

@@ -20,45 +20,87 @@ document.
#### `commandLine.appendSwitch(switch[, value])`
* `switch` string - A command-line switch, without the leading `--`
* `value` string (optional) - A value for the given switch
* `switch` string - A command-line switch, without the leading `--`.
* `value` string (optional) - A value for the given switch.
Append a switch (with optional `value`) to Chromium's command line.
**Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
```
#### `commandLine.appendArgument(value)`
* `value` string - The argument to append to the command line
* `value` string - The argument to append to the command line.
Append an argument to Chromium's command line. The argument will be quoted
correctly. Switches will precede arguments regardless of appending order.
If you're appending an argument like `--switch=value`, consider using `appendSwitch('switch', 'value')` instead.
```js
const { app } = require('electron')
app.commandLine.appendArgument('--enable-experimental-web-platform-features')
```
**Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior.
#### `commandLine.hasSwitch(switch)`
* `switch` string - A command-line switch
* `switch` string - A command-line switch.
Returns `boolean` - Whether the command-line switch is present.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
const hasPort = app.commandLine.hasSwitch('remote-debugging-port')
console.log(hasPort) // true
```
#### `commandLine.getSwitchValue(switch)`
* `switch` string - A command-line switch
* `switch` string - A command-line switch.
Returns `string` - The command-line switch value.
This function is meant to obtain Chromium command line switches. It is not
meant to be used for application-specific command line arguments. For the
latter, please use `process.argv`.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
const portValue = app.commandLine.getSwitchValue('remote-debugging-port')
console.log(portValue) // '8315'
```
**Note:** When the switch is not present or has no value, it returns empty string.
#### `commandLine.removeSwitch(switch)`
* `switch` string - A command-line switch
* `switch` string - A command-line switch.
Removes the specified switch from Chromium's command line.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
console.log(app.commandLine.hasSwitch('remote-debugging-port')) // true
app.commandLine.removeSwitch('remote-debugging-port')
console.log(app.commandLine.hasSwitch('remote-debugging-port')) // false
```
**Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior.

View File

@@ -63,6 +63,14 @@ Your application should then always use `shouldUseDarkColors` to determine what
A `boolean` for if the OS / Chromium currently has high-contrast mode enabled
or is being instructed to show a high-contrast UI.
### `nativeTheme.shouldUseDarkColorsForSystemIntegratedUI` _macOS_ _Windows_ _Readonly_
A `boolean` property indicating whether or not the system theme has been set to dark or light.
On Windows this property distinguishes between system and app light/dark theme, returning
`true` if the system theme is set to dark theme and `false` otherwise. On macOS the return
value will be the same as `nativeTheme.shouldUseDarkColors`.
### `nativeTheme.shouldUseInvertedColorScheme` _macOS_ _Windows_ _Readonly_
A `boolean` for if the OS / Chromium currently has an inverted color scheme

View File

@@ -2389,7 +2389,7 @@ A [`WebFrameMain`](web-frame-main.md) property that represents the top frame of
#### `contents.opener` _Readonly_
A [`WebFrameMain`](web-frame-main.md) property that represents the frame that opened this WebContents, either
A [`WebFrameMain | null`](web-frame-main.md) property that represents the frame that opened this WebContents, either
with open(), or by navigating a link with a target attribute.
[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent

View File

@@ -14,6 +14,14 @@ This document uses the following convention to categorize breaking changes:
## Planned Breaking API Changes (35.0)
### Behavior Changes: `app.commandLine`
`app.commandLine` will convert upper-cases switches and arguments to lowercase.
`app.commandLine` was only meant to handle chromium switches (which aren't case-sensitive) and switches passed via `app.commandLine` will not be passed down to any of the child processes.
If you were using `app.commandLine` to control the behavior of the main process, you should do this via `process.argv`.
### Behavior Changed: Dialog API's `defaultPath` option on Linux
On Linux, the required portal version for file dialogs has been reverted

View File

@@ -37,7 +37,6 @@ the illusion of a circular window.
open on the user's system).
* The window will not be transparent when DevTools is opened.
* On _Windows_:
* Transparent windows will not work when DWM is disabled.
* Transparent windows can not be maximized using the Windows system menu or by double
clicking the title bar. The reasoning behind this can be seen on
PR [#28207](https://github.com/electron/electron/pull/28207).

View File

@@ -54,7 +54,7 @@ BrowserWindow.prototype._init = function (this: BWT) {
});
this.on('close', (event) => {
queueMicrotask(() => {
if (!unresponsiveEvent && !event.defaultPrevented) {
if (!unresponsiveEvent && !event?.defaultPrevented) {
unresponsiveEvent = setTimeout(emitUnresponsiveEvent, 5000);
}
});

View File

@@ -78,7 +78,9 @@ export const roleList: Record<RoleId, Role> = {
minimize: {
label: 'Minimize',
accelerator: 'CommandOrControl+M',
windowMethod: w => w.minimize()
windowMethod: w => {
if (w.minimizable) w.minimize();
}
},
paste: {
label: 'Paste',

View File

@@ -267,8 +267,17 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
throw new TypeError('webContents.print(): Invalid print settings specified.');
}
const pageSize = options.pageSize ?? 'A4';
if (typeof pageSize === 'object') {
const { pageSize } = options;
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 if (typeof pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
throw new Error('height and width properties are required for pageSize');
}
@@ -290,16 +299,7 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
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 {
} else if (pageSize !== undefined) {
throw new Error(`Unsupported pageSize: ${pageSize}`);
}

View File

@@ -218,7 +218,6 @@ if (packagePath) {
} else {
// Call appCodeLoaded before just for safety, it doesn't matter here as _load is synchronous
appCodeLoaded!();
process._firstFileName = Module._resolveFilename(path.join(packagePath, mainStartupScript), null, false);
Module._load(path.join(packagePath, mainStartupScript), Module, true);
}
} else {

View File

@@ -131,7 +131,7 @@ osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch
feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch
chore_partial_revert_of.patch
fix_software_compositing_infinite_loop.patch
fix_add_method_which_disables_headless_mode_on_native_widget.patch
fix_adjust_headless_mode_handling_in_native_widget.patch
refactor_unfilter_unresponsive_events.patch
build_disable_thin_lto_mac.patch
build_add_public_config_simdutf_config.patch

View File

@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cezary Kulakowski <cezary@openfin.co>
Date: Mon, 22 Jul 2024 16:23:13 +0200
Subject: fix: add method which disables headless mode on native widget
Subject: fix: adjust headless mode handling in native widget
We need this method as we create window in headless mode and we
switch it back to normal mode only after inital paint is done in
@@ -9,8 +9,27 @@ order to get some events like WebContents.beginFrameSubscription.
If we don't set `is_headless_` to false then some child windows
e.g. autofill popups will be created in headless mode leading to
ui problems (like dissapearing popup during typing in html's
input list.
input list).
We also need to ensure that an initial paint is scheduled when
the compositor is unsuspended in headles mode.
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 fed3d6a70139443d76ce6181df69bb490c46a081..06783f617ec63702a95d460fc6f14dd94f95917e 100644
--- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm
+++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
@@ -654,9 +654,10 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
// case it will never become visible but we want its compositor to produce
// frames for screenshooting and screencasting.
UpdateCompositorProperties();
- layer()->SetVisible(is_visible_);
+ layer()->SetVisible(is_visible_ || is_headless_mode_window_);
if (is_visible_ || is_headless_mode_window_) {
compositor_->Unsuspend();
+ layer()->SchedulePaint(layer()->bounds());
}
// Register the CGWindowID (used to identify this window for video capture)
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 6dae25a61bfaf26c59f044628629771c36be73f3..2e76f18cf48303462c7489a01d002a3531695b83 100644
--- a/ui/views/widget/widget.h

View File

@@ -15,10 +15,10 @@ capturer was window or screen-specific, as the IDs remain valid for
generic capturer as well.
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index 56e7c4058bbdd4d13c5ac90eb41972ad63da8abf..f5d78bb1c70f656c91596fd389aa0b70533b6148 100644
index 60eabf1a69089049d4cddb81f87efca4f096a3b6..6618477648b7148ba66f5bb695be8eb6da045849 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -899,8 +899,14 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
@@ -811,8 +811,14 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
switch (source.type) {
case DesktopMediaID::TYPE_SCREEN: {
@@ -35,7 +35,7 @@ index 56e7c4058bbdd4d13c5ac90eb41972ad63da8abf..f5d78bb1c70f656c91596fd389aa0b70
if (screen_capturer && screen_capturer->SelectSource(source.id)) {
capturer = std::make_unique<webrtc::DesktopAndCursorComposer>(
std::move(screen_capturer), options);
@@ -913,8 +919,14 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
@@ -825,8 +831,14 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
}
case DesktopMediaID::TYPE_WINDOW: {

View File

@@ -7,24 +7,6 @@ This allows embedders to tell Node.js what the first "real" file is when
they use themselves as the entry point. We should try to upstream some form
of this.
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index 9b5772fe9b8babbb892c7a5ec79258472da55a76..3568fd6ea0816f62d97d46f5d497bb1b23bf4e25 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -1555,6 +1555,13 @@ Module.prototype._compile = function(content, filename, format) {
this[kIsExecuting] = true;
if (this[kIsMainSymbol] && getOptionValue('--inspect-brk')) {
const { callAndPauseOnStart } = internalBinding('inspector');
+ // process._firstFileName is used by Embedders to tell node what
+ // the first "real" file is when they use themselves as the entry
+ // point
+ if (process._firstFileName) {
+ resolvedArgv = process._firstFileName;
+ delete process._firstFileName;
+ }
result = callAndPauseOnStart(compiledWrapper, thisValue, exports,
require, module, filename, dirname,
process, localGlobal, localBuffer);
diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
index d1c05d1717cdc825c4e48885c963c9ed65bcf51c..278665921c5160ff10b3178db27d4df319fab6b3 100644
--- a/lib/internal/process/pre_execution.js

View File

@@ -13,7 +13,7 @@ To fix this issue, provide the interface oom_error_callback to enable a
custom oom error callback set from Electron.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 32fc075e97eebca6c47e796ac5308915746ffa2a..e72bee385865c7d34e9eea6b90c6d911d592f8af 100644
index fc9b056d2f7e25109100fbde5f3ab0aebc8c619a..9b155213ce301df7e396a4a113992499fc7e9910 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -241,7 +241,10 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {

View File

@@ -43,20 +43,6 @@ index 59b5a16f1309a5e4055bccfdb7a529045ad30402..bfdaf6211466a01b64b7942f7b16c480
let filename = call.getFileName();
const line = call.getLineNumber() - 1;
diff --git a/src/api/environment.cc b/src/api/environment.cc
index fc9b056d2f7e25109100fbde5f3ab0aebc8c619a..32fc075e97eebca6c47e796ac5308915746ffa2a 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -247,6 +247,9 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
s.prepare_stack_trace_callback : PrepareStackTraceCallback;
isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
+ } else {
+ auto env = Environment::GetCurrent(isolate);
+ env->set_prepare_stack_trace_callback(Local<Function>());
}
}
diff --git a/src/node_options.cc b/src/node_options.cc
index 3608ab2b4aeb09e985ca98e23f2dff23567ade71..620776c06d835eb1bfeed060751c570e8d435b29 100644
--- a/src/node_options.cc

View File

@@ -278,7 +278,7 @@ const LINTERS = [{
}, {
key: 'md',
roots: ['.'],
ignoreRoots: ['node_modules', 'spec/node_modules'],
ignoreRoots: ['.git', 'node_modules', 'spec/node_modules'],
test: filename => filename.endsWith('.md'),
run: async (opts, filenames) => {
let errors = false;

View File

@@ -47,7 +47,7 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
// Copy the show setting to webContents, but only if we don't want to paint
// when initially hidden
bool paint_when_initially_hidden = true;
options.Get("paintWhenInitiallyHidden", &paint_when_initially_hidden);
options.Get(options::kPaintWhenInitiallyHidden, &paint_when_initially_hidden);
if (!paint_when_initially_hidden) {
bool show = true;
options.Get(options::kShow, &show);
@@ -219,14 +219,14 @@ void BrowserWindow::CloseImmediately() {
}
void BrowserWindow::Focus() {
if (api_web_contents_->IsOffScreen())
if (api_web_contents_ && api_web_contents_->IsOffScreen())
FocusOnWebView();
else
BaseWindow::Focus();
}
void BrowserWindow::Blur() {
if (api_web_contents_->IsOffScreen())
if (api_web_contents_ && api_web_contents_->IsOffScreen())
BlurWebView();
else
BaseWindow::Blur();

View File

@@ -63,6 +63,10 @@ bool NativeTheme::ShouldUseHighContrastColors() {
return ui_theme_->UserHasContrastPreference();
}
bool NativeTheme::ShouldUseDarkColorsForSystemIntegratedUI() {
return ui_theme_->ShouldUseDarkColorsForSystemIntegratedUI();
}
bool NativeTheme::InForcedColorsMode() {
return ui_theme_->InForcedColorsMode();
}
@@ -109,6 +113,8 @@ gin::ObjectTemplateBuilder NativeTheme::GetObjectTemplateBuilder(
&NativeTheme::SetThemeSource)
.SetProperty("shouldUseHighContrastColors",
&NativeTheme::ShouldUseHighContrastColors)
.SetProperty("shouldUseDarkColorsForSystemIntegratedUI",
&NativeTheme::ShouldUseDarkColorsForSystemIntegratedUI)
.SetProperty("shouldUseInvertedColorScheme",
&NativeTheme::ShouldUseInvertedColorScheme)
.SetProperty("inForcedColorsMode", &NativeTheme::InForcedColorsMode)

View File

@@ -48,6 +48,7 @@ class NativeTheme final : public gin::Wrappable<NativeTheme>,
ui::NativeTheme::ThemeSource GetThemeSource() const;
bool ShouldUseDarkColors();
bool ShouldUseHighContrastColors();
bool ShouldUseDarkColorsForSystemIntegratedUI();
bool ShouldUseInvertedColorScheme();
bool InForcedColorsMode();
bool GetPrefersReducedTransparency();

View File

@@ -330,6 +330,9 @@ void UtilityProcessWrapper::PostMessage(gin::Arguments* args) {
return;
blink::TransferableMessage transferable_message;
gin_helper::ErrorThrower thrower(args->isolate());
// |message| is any value that can be serialized to StructuredClone.
v8::Local<v8::Value> message_value;
if (args->GetNext(&message_value)) {
if (!electron::SerializeV8Value(args->isolate(), message_value,
@@ -342,9 +345,25 @@ void UtilityProcessWrapper::PostMessage(gin::Arguments* args) {
v8::Local<v8::Value> transferables;
std::vector<gin::Handle<MessagePort>> wrapped_ports;
if (args->GetNext(&transferables)) {
std::vector<v8::Local<v8::Value>> wrapped_port_values;
if (!gin::ConvertFromV8(args->isolate(), transferables,
&wrapped_port_values)) {
thrower.ThrowTypeError("transferables must be an array of MessagePorts");
return;
}
for (size_t i = 0; i < wrapped_port_values.size(); ++i) {
if (!gin_helper::IsValidWrappable(wrapped_port_values[i],
&MessagePort::kWrapperInfo)) {
thrower.ThrowTypeError(
base::StrCat({"Port at index ", base::NumberToString(i),
" is not a valid port"}));
return;
}
}
if (!gin::ConvertFromV8(args->isolate(), transferables, &wrapped_ports)) {
gin_helper::ErrorThrower(args->isolate())
.ThrowTypeError("Invalid value for transfer");
thrower.ThrowTypeError("Passed an invalid MessagePort");
return;
}
}

View File

@@ -3035,9 +3035,8 @@ void OnGetDeviceNameToUse(base::WeakPtr<content::WebContents> web_contents,
return;
}
// If the user has passed a deviceName use it, otherwise use default printer.
// Use user-passed deviceName, otherwise default printer.
print_settings.Set(printing::kSettingDeviceName, info.second);
if (!print_settings.FindInt(printing::kSettingDpiHorizontal)) {
gfx::Size dpi = GetDefaultPrinterDPI(info.second);
print_settings.Set(printing::kSettingDpiHorizontal, dpi.width());
@@ -3096,6 +3095,17 @@ void WebContents::Print(gin::Arguments* args) {
return;
}
if (options.IsEmptyObject()) {
auto* print_view_manager =
PrintViewManagerElectron::FromWebContents(web_contents());
if (!print_view_manager)
return;
content::RenderFrameHost* rfh = GetRenderFrameHostToUse(web_contents());
print_view_manager->PrintNow(rfh, std::move(settings), std::move(callback));
return;
}
// Set optional silent printing.
bool silent = false;
options.Get("silent", &silent);

View File

@@ -17,6 +17,7 @@
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/error_thrower.h"
#include "shell/common/gin_helper/event_emitter_caller.h"
#include "shell/common/gin_helper/wrappable.h"
#include "shell/common/node_includes.h"
#include "shell/common/v8_util.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
@@ -26,25 +27,6 @@
namespace electron {
namespace {
bool IsValidWrappable(const v8::Local<v8::Value>& val) {
if (!val->IsObject())
return false;
v8::Local<v8::Object> port = val.As<v8::Object>();
if (port->InternalFieldCount() != gin::kNumberOfInternalFields)
return false;
const auto* info = static_cast<gin::WrapperInfo*>(
port->GetAlignedPointerFromInternalField(gin::kWrapperInfoIndex));
return info && info->embedder == gin::kEmbedderNativeGin;
}
} // namespace
gin::WrapperInfo MessagePort::kWrapperInfo = {gin::kEmbedderNativeGin};
MessagePort::MessagePort() = default;
@@ -77,16 +59,14 @@ void MessagePort::PostMessage(gin::Arguments* args) {
blink::TransferableMessage transferable_message;
gin_helper::ErrorThrower thrower(args->isolate());
// |message| is any value that can be serialized to StructuredClone.
v8::Local<v8::Value> message_value;
if (!args->GetNext(&message_value)) {
thrower.ThrowTypeError("Expected at least one argument to postMessage");
return;
}
if (!electron::SerializeV8Value(args->isolate(), message_value,
&transferable_message)) {
// SerializeV8Value sets an exception.
return;
if (args->GetNext(&message_value)) {
if (!electron::SerializeV8Value(args->isolate(), message_value,
&transferable_message)) {
// SerializeV8Value sets an exception.
return;
}
}
v8::Local<v8::Value> transferables;
@@ -100,7 +80,8 @@ void MessagePort::PostMessage(gin::Arguments* args) {
}
for (unsigned i = 0; i < wrapped_port_values.size(); ++i) {
if (!IsValidWrappable(wrapped_port_values[i])) {
if (!gin_helper::IsValidWrappable(wrapped_port_values[i],
&MessagePort::kWrapperInfo)) {
thrower.ThrowTypeError("Port at index " + base::NumberToString(i) +
" is not a valid port");
return;

View File

@@ -221,11 +221,10 @@ bool ElectronHidDelegate::IsServiceWorkerAllowedForOrigin(
ElectronHidDelegate::ContextObservation*
ElectronHidDelegate::GetContextObserver(
content::BrowserContext* browser_context) {
if (!observations_.contains(browser_context)) {
observations_.emplace(browser_context, std::make_unique<ContextObservation>(
this, browser_context));
}
return observations_[browser_context].get();
auto& observation = observations_[browser_context];
if (!observation)
observation = std::make_unique<ContextObservation>(this, browser_context);
return observation.get();
}
HidChooserController* ElectronHidDelegate::ControllerForFrame(

View File

@@ -94,8 +94,6 @@ gfx::Size GetExpandedWindowSize(const NativeWindow* window, gfx::Size size) {
NativeWindow::NativeWindow(const gin_helper::Dictionary& options,
NativeWindow* parent)
: widget_(std::make_unique<views::Widget>()), parent_(parent) {
++next_id_;
options.Get(options::kFrame, &has_frame_);
options.Get(options::kTransparent, &transparent_);
options.Get(options::kEnableLargerThanScreen, &enable_larger_than_screen_);
@@ -816,9 +814,6 @@ void NativeWindow::HandlePendingFullscreenTransitions() {
SetFullScreen(next_transition);
}
// static
int32_t NativeWindow::next_id_ = 0;
bool NativeWindow::IsTranslucent() const {
// Transparent windows are translucent
if (transparent()) {

View File

@@ -407,7 +407,7 @@ class NativeWindow : public base::SupportsUserData,
NativeWindow* parent() const { return parent_; }
bool is_modal() const { return is_modal_; }
int32_t window_id() const { return next_id_; }
int32_t window_id() const { return window_id_; }
void add_child_window(NativeWindow* child) {
child_windows_.push_back(child);
@@ -470,7 +470,8 @@ class NativeWindow : public base::SupportsUserData,
private:
std::unique_ptr<views::Widget> widget_;
static int32_t next_id_;
static inline int32_t next_id_ = 0;
const int32_t window_id_ = ++next_id_;
// The content view, weak ref.
raw_ptr<views::View> content_view_ = nullptr;

View File

@@ -154,6 +154,9 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
bool hiddenInMissionControl = false;
options.Get(options::kHiddenInMissionControl, &hiddenInMissionControl);
bool paint_when_initially_hidden = true;
options.Get(options::kPaintWhenInitiallyHidden, &paint_when_initially_hidden);
// The window without titlebar is treated the same with frameless window.
if (title_bar_style_ != TitleBarStyle::kNormal)
set_has_frame(false);
@@ -194,8 +197,8 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
params.bounds = bounds;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
// Allow painting before shown, to be later disabled in ElectronNSWindow.
params.headless_mode = true;
// Possibly allow painting before shown - later disabled in ElectronNSWindow.
params.headless_mode = paint_when_initially_hidden;
if (IsTranslucent()) {
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
}

View File

@@ -192,7 +192,7 @@ void ElectronDesktopWindowTreeHostLinux::UpdateFrameHints() {
if (ui::OzonePlatform::GetInstance()->IsWindowCompositingSupported()) {
// Set the opaque region.
std::vector<gfx::Rect> opaque_region;
if (!IsShowingFrame()) {
if (IsShowingFrame()) {
// The opaque region is a list of rectangles that contain only fully
// opaque pixels of the window. We need to convert the clipping
// rounded-rect into this format.

View File

@@ -44,14 +44,14 @@ ui::SelectFileDialog::FileTypeInfo GetFilterInfo(const Filters& filters) {
ui::SelectFileDialog::FileTypeInfo file_type_info;
for (const auto& [name, extension_group] : filters) {
file_type_info.extension_description_overrides.push_back(
base::UTF8ToUTF16(name));
const bool has_all_files_wildcard = std::ranges::any_of(
extension_group, [](const auto& ext) { return ext == "*"; });
if (has_all_files_wildcard) {
file_type_info.include_all_files = true;
} else {
file_type_info.extension_description_overrides.push_back(
base::UTF8ToUTF16(name));
file_type_info.extensions.emplace_back(extension_group);
}
}

View File

@@ -31,7 +31,6 @@ class WebContentsPermissionHelper
SERIAL,
HID,
USB,
KEYBOARD_LOCK,
FILE_SYSTEM,
};

View File

@@ -4,50 +4,59 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "services/network/public/cpp/network_switches.h"
#include "shell/common/gin_converters/base_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/node_includes.h"
#include "third_party/abseil-cpp/absl/strings/ascii.h"
namespace {
bool HasSwitch(const std::string& switch_string) {
auto switch_str = base::ToLowerASCII(switch_string);
bool HasSwitch(const std::string& name) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(name);
auto* command_line = base::CommandLine::ForCurrentProcess();
return command_line->HasSwitch(switch_str);
}
base::CommandLine::StringType GetSwitchValue(const std::string& name) {
return base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(name);
base::CommandLine::StringType GetSwitchValue(gin_helper::ErrorThrower thrower,
const std::string& switch_string) {
auto switch_str = base::ToLowerASCII(switch_string);
auto* command_line = base::CommandLine::ForCurrentProcess();
return command_line->GetSwitchValueNative(switch_str);
}
void AppendSwitch(const std::string& switch_string,
gin_helper::Arguments* args) {
auto switch_str = base::ToLowerASCII(switch_string);
auto* command_line = base::CommandLine::ForCurrentProcess();
if (base::EndsWith(switch_string, "-path",
base::CompareCase::INSENSITIVE_ASCII) ||
switch_string == network::switches::kLogNetLog) {
base::FilePath path;
args->GetNext(&path);
command_line->AppendSwitchPath(switch_string, path);
command_line->AppendSwitchPath(switch_str, path);
return;
}
base::CommandLine::StringType value;
if (args->GetNext(&value))
command_line->AppendSwitchNative(switch_string, value);
command_line->AppendSwitchNative(switch_str, value);
else
command_line->AppendSwitch(switch_string);
command_line->AppendSwitch(switch_str);
}
void RemoveSwitch(const std::string& switch_string) {
auto switch_str = base::ToLowerASCII(switch_string);
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->RemoveSwitch(switch_string);
command_line->RemoveSwitch(switch_str);
}
void AppendArg(const std::string& arg) {
auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendArg(arg);
}

View File

@@ -183,6 +183,16 @@ class Dictionary : public gin::Dictionary {
bool IsEmpty() const { return isolate() == nullptr || GetHandle().IsEmpty(); }
bool IsEmptyObject() const {
if (IsEmpty())
return true;
v8::Local<v8::Context> context = isolate()->GetCurrentContext();
v8::Local<v8::Array> props =
GetHandle()->GetOwnPropertyNames(context).ToLocalChecked();
return props->Length() == 0;
}
v8::Local<v8::Object> GetHandle() const {
return gin::ConvertToV8(isolate(),
*static_cast<const gin::Dictionary*>(this))

View File

@@ -10,6 +10,23 @@
namespace gin_helper {
bool IsValidWrappable(const v8::Local<v8::Value>& val,
const gin::WrapperInfo* wrapper_info) {
if (!val->IsObject())
return false;
v8::Local<v8::Object> port = val.As<v8::Object>();
if (port->InternalFieldCount() != gin::kNumberOfInternalFields)
return false;
const gin::WrapperInfo* info = static_cast<gin::WrapperInfo*>(
port->GetAlignedPointerFromInternalField(gin::kWrapperInfoIndex));
if (info != wrapper_info)
return false;
return true;
}
WrappableBase::WrappableBase() = default;
WrappableBase::~WrappableBase() {

View File

@@ -11,6 +11,9 @@
namespace gin_helper {
bool IsValidWrappable(const v8::Local<v8::Value>& obj,
const gin::WrapperInfo* wrapper_info);
namespace internal {
void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val);

View File

@@ -33,6 +33,10 @@ inline constexpr std::string_view kMaximizable = "maximizable";
inline constexpr std::string_view kFullScreenable = "fullscreenable";
inline constexpr std::string_view kClosable = "closable";
// Whether to paint when the window is initially hidden.
inline constexpr std::string_view kPaintWhenInitiallyHidden =
"paintWhenInitiallyHidden";
// whether to keep the window out of mission control
inline constexpr std::string_view kHiddenInMissionControl =
"hiddenInMissionControl";

View File

@@ -36,7 +36,7 @@ class V8Serializer : public v8::ValueSerializer::Delegate {
bool Serialize(v8::Local<v8::Value> value, blink::CloneableMessage* out) {
gin_helper::MicrotasksScope microtasks_scope{
isolate_->GetCurrentContext(), false,
isolate_->GetCurrentContext(), true,
v8::MicrotasksScope::kDoNotRunMicrotasks};
WriteBlinkEnvelope(19);

View File

@@ -4929,6 +4929,18 @@ describe('BrowserWindow module', () => {
expect(w.getChildWindows().length).to.equal(0);
});
it('can handle parent window close with focus or blur events', (done) => {
const w = new BrowserWindow({ show: false });
const c = new BrowserWindow({ show: false, parent: w });
c.on('closed', () => {
w.focus();
done();
});
w.close();
});
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 });
@@ -6462,6 +6474,31 @@ describe('BrowserWindow module', () => {
w.loadFile(path.join(fixtures, 'pages', 'send-after-node.html'));
});
// TODO(codebytere): fix on Windows and Linux too
ifdescribe(process.platform === 'darwin')('window.webContents initial paint', () => {
afterEach(closeAllWindows);
it('paints when a window is initially hidden', async () => {
const w = new BrowserWindow({ show: false });
await w.loadFile(path.join(fixtures, 'pages', 'a.html'));
const entries = await w.webContents.executeJavaScript(`
new Promise((resolve) => {
const observer = new PerformanceObserver((performance) => {
observer.disconnect();
resolve(performance.getEntries());
});
observer.observe({ entryTypes: ['paint'] });
});
const header = document.createElement('h1');
header.innerText = 'Paint me!!';
document.getElementById('div').appendChild(header);
`);
expect(JSON.stringify(entries)).to.eq('{}');
});
});
describe('window.webContents.focus()', () => {
afterEach(closeAllWindows);
it('focuses window', async () => {

View File

@@ -236,6 +236,23 @@ describe('ipc module', () => {
expect(ev.senderFrame.routingId).to.equal(w.webContents.mainFrame.routingId);
});
it('throws when the transferable is invalid', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
const p = once(ipcMain, 'port');
await w.webContents.executeJavaScript(`(${function () {
try {
const buffer = new ArrayBuffer(10);
// @ts-expect-error
require('electron').ipcRenderer.postMessage('port', '', [buffer]);
} catch (e) {
require('electron').ipcRenderer.postMessage('port', { error: (e as Error).message });
}
}})()`);
const [, msg] = await p;
expect(msg.error).to.eql('Invalid value for transfer');
});
it('can communicate between main and renderer', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
@@ -411,6 +428,20 @@ describe('ipc module', () => {
expect(port2).not.to.be.null();
});
it('should not throw when supported values are passed as message', () => {
const { port1 } = new MessageChannelMain();
// @ts-expect-error - this shouldn't crash.
expect(() => { port1.postMessage(); }).to.not.throw();
expect(() => { port1.postMessage(undefined); }).to.not.throw();
expect(() => { port1.postMessage(42); }).to.not.throw();
expect(() => { port1.postMessage(false); }).to.not.throw();
expect(() => { port1.postMessage([]); }).to.not.throw();
expect(() => { port1.postMessage('hello'); }).to.not.throw();
expect(() => { port1.postMessage({ hello: 'goodbye' }); }).to.not.throw();
});
it('throws an error when an invalid parameter is sent to postMessage', () => {
const { port1 } = new MessageChannelMain();

View File

@@ -2,7 +2,7 @@ import { BrowserWindow, app, Menu, MenuItem, MenuItemConstructorOptions } from '
import { expect } from 'chai';
import { ifdescribe } from './lib/spec-helpers';
import { ifit, ifdescribe } from './lib/spec-helpers';
import { closeAllWindows } from './lib/window-helpers';
import { roleList, execute } from '../lib/browser/api/menu-item-roles';
@@ -205,6 +205,22 @@ describe('MenuItems', () => {
const canExecute = execute(item.role as any, win, win.webContents);
expect(canExecute).to.be.true('can execute');
});
ifit(process.platform === 'win32')('does not execute minimize role when minimizable false', () => {
const win = new BrowserWindow({ minimizable: false });
const menu = Menu.buildFromTemplate([{
label: 'text',
role: 'minimize'
}]);
Menu.setApplicationMenu(menu);
menu._executeCommand({}, menu.items[0].commandId);
expect(win.isMinimized()).to.equal(false);
win.setMinimizable(true);
menu._executeCommand({}, menu.items[0].commandId);
expect(win.isMinimized()).to.equal(true);
});
});
describe('MenuItem command id', () => {

View File

@@ -102,6 +102,12 @@ describe('nativeTheme module', () => {
});
});
describe('nativeTheme.shouldUseDarkColorsForSystemIntegratedUI', () => {
it('returns a boolean', () => {
expect(nativeTheme.shouldUseDarkColorsForSystemIntegratedUI).to.be.a('boolean');
});
});
describe('nativeTheme.inForcedColorsMode', () => {
it('returns a boolean', () => {
expect(nativeTheme.inForcedColorsMode).to.be.a('boolean');

View File

@@ -983,6 +983,17 @@ describe('node feature', () => {
});
});
itremote('handles assert module assertions as expected', () => {
const assert = require('node:assert');
try {
assert.ok(false);
expect.fail('assert.ok(false) should throw');
} catch (err) {
console.log(err);
expect(err).to.be.instanceOf(assert.AssertionError);
}
});
it('Can find a module using a package.json main field', () => {
const result = childProcess.spawnSync(process.execPath, [path.resolve(fixtures, 'api', 'electron-main-module', 'app.asar')], { stdio: 'inherit' });
expect(result.status).to.equal(0);

View File

@@ -255,7 +255,6 @@ declare namespace NodeJS {
once(event: 'document-end', listener: () => any): this;
// Additional properties
_firstFileName?: string;
_serviceStartupScript: string;
_getOrCreateArchive?: (path: string) => NodeJS.AsarArchive | null;