Compare commits

..

7 Commits

Author SHA1 Message Date
electron-roller[bot]
ad14d26256 chore: bump node in DEPS to v24.14.0 2026-02-25 13:00:38 +00:00
trop[bot]
cadea1da52 fix: prevent crash on Windows when closing child windows (#49929)
* guard against window destruction in min/max size checks

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

* use weakptr to prevent hit test crash on teardown

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

* revove web contents views during teardown

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

* fix test failure

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

* fix other tests

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>
2026-02-24 17:18:21 -05:00
trop[bot]
ed26c173b1 docs: fix some string enum typings (#49930)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-02-24 11:20:01 -05:00
trop[bot]
261f2fcc5e build: fix roller branch detection in CI (#49926)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-02-23 22:54:18 -08:00
trop[bot]
19a421a3fc ci: fix checking latest release for website docs update (#49922)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-02-23 18:09:48 -08:00
trop[bot]
c34188ffe9 fix: updated Alt detection to explicitly exclude AltGraph/AltGr (#49916)
fix: updated Alt detection to explicitly exclude AltGraph/AltGr (#49778)

Updated Alt detection to explicitly exclude AltGraph/AltGr

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shashwat Raj <65155843+darthvader58@users.noreply.github.com>
2026-02-23 15:27:21 -08:00
trop[bot]
e50f03eceb fix: apply zoomFactor from setWindowOpenHandler to window.open() windows (#49911)
fix: apply zoomFactor from setWindowOpenHandler to window.open() windows

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-02-23 15:41:25 +01:00
12 changed files with 118 additions and 32 deletions

View File

@@ -31,7 +31,7 @@ jobs:
echo "isLatestRelease=false" >> $GITHUB_OUTPUT
fi
- name: Trigger website docs update
if: ${{ steps.check-if-latest-release.outputs.isLatestRelease }}
if: ${{ steps.check-if-latest-release.outputs.isLatestRelease == 'true' }}
env:
GH_REPO: electron/website
GH_TOKEN: ${{ fromJSON(steps.secret-service.outputs.secrets).WEBSITE_DOCS_UPDATER_APP_TOKEN }}

2
DEPS
View File

@@ -4,7 +4,7 @@ vars = {
'chromium_version':
'146.0.7680.16',
'node_version':
'v24.13.1',
'v24.14.0',
'nan_version':
'675cefebca42410733da8a454c8d9391fcebfbc2',
'squirrel.mac_version':

View File

@@ -1332,7 +1332,7 @@ Returns `boolean` - Whether the current desktop environment is Unity launcher.
### `app.getLoginItemSettings([options])` _macOS_ _Windows_
* `options` Object (optional)
* `type` string (optional) _macOS_ - Can be one of `mainAppService`, `agentService`, `daemonService`, or `loginItemService`. Defaults to `mainAppService`. Only available on macOS 13 and up. See [app.setLoginItemSettings](app.md#appsetloginitemsettingssettings-macos-windows) for more information about each type.
* `type` string (optional) _macOS_ - Can be `mainAppService`, `agentService`, `daemonService`, or `loginItemService`. Defaults to `mainAppService`. Only available on macOS 13 and up. See [app.setLoginItemSettings](app.md#appsetloginitemsettingssettings-macos-windows) for more information about each type.
* `serviceName` string (optional) _macOS_ - The name of the service. Required if `type` is non-default. Only available on macOS 13 and up.
* `path` string (optional) _Windows_ - The executable path to compare against. Defaults to `process.execPath`.
* `args` string[] (optional) _Windows_ - The command-line arguments to compare against. Defaults to an empty array.
@@ -1347,13 +1347,13 @@ Returns `Object`:
* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically.
* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`.
* `status` string _macOS_ - can be `not-registered`, `enabled`, `requires-approval`, or `not-found`.
* `executableWillLaunchAtLogin` boolean _Windows_ - `true` if app is set to open at login and its run key is not deactivated. This differs from `openAtLogin` as it ignores the `args` option, this property will be true if the given executable would be launched at login with **any** arguments.
* `launchItems` Object[] _Windows_
* `name` string _Windows_ - name value of a registry entry.
* `path` string _Windows_ - The executable to an app that corresponds to a registry entry.
* `args` string[] _Windows_ - the command-line arguments to pass to the executable.
* `scope` string _Windows_ - one of `user` or `machine`. Indicates whether the registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`.
* `scope` string _Windows_ - can be `user` or `machine`. Indicates whether the registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`.
* `enabled` boolean _Windows_ - `true` if the app registry key is startup approved and therefore shows as `enabled` in Task Manager and Windows settings.
### `app.setLoginItemSettings(settings)` _macOS_ _Windows_

View File

@@ -14,6 +14,23 @@ const DEPS_REGEX = /chromium_version':\n +'(.+?)',/m;
const CL_REGEX = /https:\/\/chromium-review\.googlesource\.com\/c\/(?:chromium\/src|v8\/v8)\/\+\/(\d+)(#\S+)?/g;
const ROLLER_BRANCH_PATTERN = /^roller\/chromium\/(.+)$/;
function getCurrentBranch () {
// In CI, use `GITHUB_HEAD_REF` since we checkout the PR branch in detached HEAD state
if (process.env.GITHUB_HEAD_REF) {
return process.env.GITHUB_HEAD_REF;
}
try {
return execSync('git rev-parse --abbrev-ref HEAD', {
cwd: ELECTRON_DIR,
encoding: 'utf8'
}).trim();
} catch {
console.error('Could not determine current git branch');
process.exit(1);
}
}
function getCommitsSinceMergeBase (mergeBase) {
try {
const output = execSync(`git log --format=%H%n%B%n---COMMIT_END--- ${mergeBase}..HEAD`, {
@@ -92,17 +109,7 @@ async function getGerritPatchDetails (clUrl) {
}
async function main () {
let currentBranch;
try {
currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
cwd: ELECTRON_DIR,
encoding: 'utf8'
}).trim();
} catch {
console.error('Could not determine current git branch');
process.exit(1);
}
const currentBranch = getCurrentBranch();
// Check if we're on a roller/chromium/* branch
const branchMatch = ROLLER_BRANCH_PATTERN.exec(currentBranch);

View File

@@ -4742,6 +4742,19 @@ gin_helper::Handle<WebContents> WebContents::CreateFromWebPreferences(
existing_preferences->SetFromDictionary(web_preferences_dict);
web_contents->SetBackgroundColor(
existing_preferences->GetBackgroundColor());
double zoom_factor;
if (web_preferences.Get(options::kZoomFactor, &zoom_factor)) {
auto* zoom_controller = WebContentsZoomController::FromWebContents(
web_contents->web_contents());
if (zoom_controller) {
zoom_controller->SetDefaultZoomFactor(zoom_factor);
// Also set the current zoom level immediately, since the page
// has already navigated by the time we wrap the webContents.
zoom_controller->SetZoomLevel(
blink::ZoomFactorToZoomLevel(zoom_factor));
}
}
}
} else {
// Create one if not.

View File

@@ -33,7 +33,7 @@ WebContentsView::WebContentsView(v8::Isolate* isolate,
gin_helper::Handle<WebContents> web_contents)
: View(web_contents->inspectable_web_contents()->GetView()),
web_contents_(isolate, web_contents.ToV8()),
api_web_contents_(web_contents.get()) {
api_web_contents_(web_contents->GetWeakPtr()) {
set_delete_view(false);
view()->SetProperty(
views::kFlexBehaviorKey,

View File

@@ -7,7 +7,7 @@
#include <optional>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
#include "shell/browser/api/electron_api_view.h"
#include "shell/browser/draggable_region_provider.h"
@@ -63,7 +63,7 @@ class WebContentsView : public View,
// Keep a reference to v8 wrapper.
v8::Global<v8::Value> web_contents_;
raw_ptr<api::WebContents> api_web_contents_;
base::WeakPtr<api::WebContents> api_web_contents_;
};
} // namespace electron::api

View File

@@ -92,6 +92,13 @@ InspectableWebContentsView::InspectableWebContentsView(
}
InspectableWebContentsView::~InspectableWebContentsView() {
if (devtools_window_web_view_)
devtools_window_web_view_->SetWebContents(nullptr);
if (devtools_web_view_)
devtools_web_view_->SetWebContents(nullptr);
if (contents_web_view_)
contents_web_view_->SetWebContents(nullptr);
if (devtools_window_)
inspectable_web_contents()->SaveDevToolsBounds(
devtools_window_->GetWindowBoundsInScreen());

View File

@@ -9,6 +9,7 @@
#include "components/input/native_web_keyboard_event.h"
#include "shell/browser/native_window.h"
#include "shell/browser/ui/views/menu_bar.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/views/layout/box_layout.h"
namespace electron {
@@ -21,9 +22,21 @@ bool IsAltKey(const input::NativeWebKeyboardEvent& event) {
bool IsAltModifier(const input::NativeWebKeyboardEvent& event) {
using Mods = input::NativeWebKeyboardEvent::Modifiers;
// AltGraph (AltGr) should not be treated as a single Alt keypress for
// menu-bar toggling.
if (event.windows_key_code == ui::VKEY_ALTGR ||
ui::KeycodeConverter::DomKeyToKeyString(event.dom_key) == "AltGraph") {
return false;
}
return (event.GetModifiers() & Mods::kKeyModifiers) == Mods::kAltKey;
}
bool IsSingleAltKey(const input::NativeWebKeyboardEvent& event) {
return IsAltKey(event) && IsAltModifier(event);
}
} // namespace
RootView::RootView(NativeWindow* window)
@@ -98,7 +111,7 @@ void RootView::HandleKeyEvent(const input::NativeWebKeyboardEvent& event) {
return;
// Show accelerator when "Alt" is pressed.
if (menu_bar_visible_ && IsAltKey(event))
if (menu_bar_visible_ && IsSingleAltKey(event))
menu_bar_->SetAcceleratorVisibility(
event.GetType() == blink::WebInputEvent::Type::kRawKeyDown);
@@ -121,11 +134,11 @@ void RootView::HandleKeyEvent(const input::NativeWebKeyboardEvent& event) {
// Toggle the menu bar only when a single Alt is released.
if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown &&
IsAltKey(event)) {
IsSingleAltKey(event)) {
// When a single Alt is pressed:
menu_bar_alt_pressed_ = true;
} else if (event.GetType() == blink::WebInputEvent::Type::kKeyUp &&
IsAltKey(event) && menu_bar_alt_pressed_) {
IsSingleAltKey(event) && menu_bar_alt_pressed_) {
// When a single Alt is released right after a Alt is pressed:
menu_bar_alt_pressed_ = false;
if (menu_bar_autohide_)

View File

@@ -275,12 +275,16 @@ bool WinFrameView::GetShouldPaintAsActive() {
}
gfx::Size WinFrameView::GetMinimumSize() const {
if (!window_)
return gfx::Size();
// Chromium expects minimum size to be in content dimensions on Windows
// because it adds the frame border automatically in OnGetMinMaxInfo.
return window_->GetContentMinimumSize();
}
gfx::Size WinFrameView::GetMaximumSize() const {
if (!window_)
return gfx::Size();
// Chromium expects minimum size to be in content dimensions on Windows
// because it adds the frame border automatically in OnGetMinMaxInfo.
gfx::Size size = window_->GetContentMaximumSize();

View File

@@ -3977,6 +3977,28 @@ describe('BrowserWindow module', () => {
expect(webPreferences!.contextIsolation).to.equal(false);
});
it('should apply zoomFactor from setWindowOpenHandler overrideBrowserWindowOptions', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
sandbox: true
}
});
w.webContents.setWindowOpenHandler(() => ({
action: 'allow',
overrideBrowserWindowOptions: {
webPreferences: {
zoomFactor: 2.0
}
}
}));
w.loadFile(path.join(fixtures, 'api', 'new-window.html'));
const [childWindow] = await once(w.webContents, 'did-create-window') as [BrowserWindow, any];
await once(childWindow.webContents, 'did-finish-load');
expect(childWindow.webContents.getZoomFactor()).to.be.closeTo(2.0, 0.1);
});
it('should set ipc event sender correctly', async () => {
const w = new BrowserWindow({
show: false,
@@ -5903,6 +5925,23 @@ describe('BrowserWindow module', () => {
});
});
ifdescribe(process.platform === 'linux')('menu bar AltGr behavior', () => {
it('does not toggle auto-hide menu bar visibility', async () => {
const w = new BrowserWindow({ show: false, autoHideMenuBar: true });
w.setMenuBarVisibility(false);
expect(w.isMenuBarVisible()).to.be.false('isMenuBarVisible');
w.show();
await once(w, 'show');
w.webContents.focus();
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'AltGr' });
w.webContents.sendInputEvent({ type: 'keyUp', keyCode: 'AltGr' });
await setTimeout();
expect(w.isMenuBarVisible()).to.be.false('isMenuBarVisible');
});
});
ifdescribe(process.platform !== 'darwin')('when fullscreen state is changed', () => {
it('correctly remembers state prior to fullscreen change', async () => {
const w = new BrowserWindow({ show: false });

View File

@@ -59,10 +59,11 @@ describe('WebContentsView', () => {
const browserWindow = new BrowserWindow();
const webContentsView = new WebContentsView();
webContentsView.webContents.loadURL('about:blank');
webContentsView.webContents.destroy();
const wc = webContentsView.webContents;
wc.loadURL('about:blank');
wc.destroy();
const destroyed = once(webContentsView.webContents, 'destroyed');
const destroyed = once(wc, 'destroyed');
await destroyed;
expect(() => browserWindow.contentView.addChildView(webContentsView)).to.throw(
'Can\'t add a destroyed child view to a parent view'
@@ -90,13 +91,14 @@ describe('WebContentsView', () => {
const w = new BaseWindow({ show: false });
const v = new View();
const wcv = new WebContentsView();
const wc = wcv.webContents;
w.setContentView(v);
v.addChildView(wcv);
await wcv.webContents.loadURL('about:blank');
const destroyed = once(wcv.webContents, 'destroyed');
wcv.webContents.executeJavaScript('window.close()');
await wc.loadURL('about:blank');
const destroyed = once(wc, 'destroyed');
wc.executeJavaScript('window.close()');
await destroyed;
expect(wcv.webContents.isDestroyed()).to.be.true();
expect(wc.isDestroyed()).to.be.true();
v.removeChildView(wcv);
});
@@ -170,18 +172,19 @@ describe('WebContentsView', () => {
it('does not crash when closed via window.close()', async () => {
const bw = new BrowserWindow();
const wcv = new WebContentsView();
const wc = wcv.webContents;
await bw.loadURL('data:text/html,<h1>Main Window</h1>');
bw.contentView.addChildView(wcv);
const dto = new Promise<boolean>((resolve) => {
wcv.webContents.on('blur', () => {
const devToolsOpen = wcv.webContents.isDevToolsOpened();
wc.on('blur', () => {
const devToolsOpen = !wc.isDestroyed() && wc.isDevToolsOpened();
resolve(devToolsOpen);
});
});
wcv.webContents.loadURL('data:text/html,<script>window.close()</script>');
wc.loadURL('data:text/html,<script>window.close()</script>');
const open = await dto;
expect(open).to.be.false();