Compare commits

...

7 Commits

Author SHA1 Message Date
trop[bot]
93387921c0 fix: webContents.print() ignoring mediaSize when silent (#50856)
fix: webContents.print() ignoring mediaSize when silent

PR #49523 moved the default media size fallback into OnGetDeviceNameToUse,
but the new code unconditionally writes kSettingMediaSize — clobbering
any mediaSize the caller had already set in WebContents::Print() from
options.mediaSize / pageSize. As a result, silent prints with an
explicit pageSize (e.g. "Letter") fell back to A4 with tiny content.

Only populate the default/printer media size when the caller hasn't
already supplied one, preserving the precedence:
  1. user-supplied mediaSize / pageSize
  2. printer default (when usePrinterDefaultPageSize is true)
  3. A4 fallback

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-04-09 21:02:25 -05:00
trop[bot]
0bb55bb6f2 fix: move Electron help menu links to default app only (#50859)
fix: move Electron help menu links to default app only (#50629)

* fix: remove Electron links from default help menu

* fix: remove help menu entirely from default menu

* fix: move Electron help menu links to default app

* docs: update default menu items list in menu.md

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Zeenat Lawal <zeenatlawal82@gmail.com>
2026-04-09 15:13:32 -07:00
electron-roller[bot]
e9e28f4f8f chore: bump node to v24.14.1 (41-x-y) (#50478)
* chore: bump node in DEPS to v24.14.1

* 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>
2026-04-09 12:23:32 -04:00
electron-roller[bot]
f2cbab1115 chore: bump chromium to 146.0.7680.188 (41-x-y) (#50787)
* chore: bump chromium in DEPS to 146.0.7680.180

* chore: bump chromium in DEPS to 146.0.7680.188

* 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>
2026-04-09 15:32:20 +02:00
trop[bot]
9042667690 fix: account for extraSize in aspect ratio min/max clamping on macOS (#50835)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: clavin <clavin@electronjs.org>
2026-04-09 15:31:09 +02:00
trop[bot]
1ad20e5ba4 fix: menu items not cleaned up after rebuild (#50830)
Menu was holding a SelfKeepAlive to itself from construction, so any
Menu that was never opened (e.g. an application menu replaced before
being shown) stayed pinned in cppgc forever. Repeated calls to
Menu.setApplicationMenu leaked every prior Menu along with its model
and items.

Restore the original Pin/Unpin lifecycle: start keep_alive_ empty and
only assign `this` in OnMenuWillShow. OnMenuWillClose already clears
it.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-04-09 11:56:38 +02:00
trop[bot]
a26aee5a6d fix: devtools re-attaches on open when previously detached (#50816)
PR #50646 added a dock state allowlist in SetDockState() that collapsed any
non-matching value to "right". WebContents::OpenDevTools passes an empty
string when no `mode` option is given, which is the sentinel LoadCompleted()
uses to restore `currentDockState` from prefs. The allowlist clobbered that
sentinel to "right", so previously-undocked devtools would flash detached
and then snap back to the right dock.

Preserve the empty string through SetDockState() so the pref-restore path
runs; still reject any non-empty invalid value to keep the JS-injection
guard from #50646 intact.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-04-08 13:06:40 -07:00
17 changed files with 95 additions and 82 deletions

4
DEPS
View File

@@ -2,9 +2,9 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'146.0.7680.179',
'146.0.7680.188',
'node_version':
'v24.14.0',
'v24.14.1',
'nan_version':
'675cefebca42410733da8a454c8d9391fcebfbc2',
'squirrel.mac_version':

View File

@@ -1,5 +1,5 @@
import { shell } from 'electron/common';
import { app, dialog, BrowserWindow, ipcMain } from 'electron/main';
import { app, dialog, BrowserWindow, ipcMain, Menu } from 'electron/main';
import * as path from 'node:path';
import * as url from 'node:url';
@@ -11,6 +11,53 @@ app.on('window-all-closed', () => {
app.quit();
});
const isMac = process.platform === 'darwin';
app.whenReady().then(() => {
const helpMenu: Electron.MenuItemConstructorOptions = {
role: 'help',
submenu: [
{
label: 'Learn More',
click: async () => {
await shell.openExternal('https://electronjs.org');
}
},
{
label: 'Documentation',
click: async () => {
const version = process.versions.electron;
await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`);
}
},
{
label: 'Community Discussions',
click: async () => {
await shell.openExternal('https://discord.gg/electronjs');
}
},
{
label: 'Search Issues',
click: async () => {
await shell.openExternal('https://github.com/electron/electron/issues');
}
}
]
};
const macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' };
const template: Electron.MenuItemConstructorOptions[] = [
...(isMac ? [macAppMenu] : []),
{ role: 'fileMenu' },
{ role: 'editMenu' },
{ role: 'viewMenu' },
{ role: 'windowMenu' },
helpMenu
];
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
});
function decorateURL (url: string) {
// safely add `?utm_source=default_app
const parsedUrl = new URL(url);

View File

@@ -46,7 +46,7 @@ this has the additional effect of removing the menu bar from the window.
> [!NOTE]
> The default menu will be created automatically if the app does not set one.
> It contains standard items such as `File`, `Edit`, `View`, `Window` and `Help`.
> It contains standard items such as `File`, `Edit`, `View`, and `Window`.
#### `Menu.getApplicationMenu()`

View File

@@ -1,5 +1,4 @@
import { shell } from 'electron/common';
import { app, Menu } from 'electron/main';
import { Menu } from 'electron/main';
const isMac = process.platform === 'darwin';
@@ -12,47 +11,13 @@ export const setApplicationMenuWasSet = () => {
export const setDefaultApplicationMenu = () => {
if (applicationMenuWasSet) return;
const helpMenu: Electron.MenuItemConstructorOptions = {
role: 'help',
submenu: app.isPackaged
? []
: [
{
label: 'Learn More',
click: async () => {
await shell.openExternal('https://electronjs.org');
}
},
{
label: 'Documentation',
click: async () => {
const version = process.versions.electron;
await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`);
}
},
{
label: 'Community Discussions',
click: async () => {
await shell.openExternal('https://discord.gg/electronjs');
}
},
{
label: 'Search Issues',
click: async () => {
await shell.openExternal('https://github.com/electron/electron/issues');
}
}
]
};
const macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' };
const template: Electron.MenuItemConstructorOptions[] = [
...(isMac ? [macAppMenu] : []),
{ role: 'fileMenu' },
{ role: 'editMenu' },
{ role: 'viewMenu' },
{ role: 'windowMenu' },
helpMenu
{ role: 'windowMenu' }
];
const menu = Menu.buildFromTemplate(template);

View File

@@ -313,7 +313,7 @@ index 18f283e625101318ee14b50e6e765dfd1c9a1a44..44a3a55974c9e4b9e715574075f25661
auto DrawAsSinglePath = [&]() {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 640a50a1af53f0771da02de73d70a94c973aa624..f981c8dc7492872f296e01cd64692859671be5d5 100644
index 80b0abeb7f3c18019aca2f431240a84c6dd749d7..0ebf7f1be37e0b0fccb594e83ecaacc3d4c6f510 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -214,6 +214,10 @@

View File

@@ -533,10 +533,10 @@ index 55a0c986c5b6989ee9ce277bb6a9778abb2ad2ee..809d88f21e5572807e38132d40ee7587
READONLY_PROPERTY(target, "exitCodes", exit_codes);
diff --git a/src/node_file.cc b/src/node_file.cc
index ba6ffc2b6565dea500bc8dd4818c8fcb7648694a..e834325a763f7ea8f53210145b5edd134d6b67e6 100644
index 96aac2d86695732bf6805f2ad2168a62241b5045..547455bb5011677719a8de1f98cb447561bce6aa 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -3843,7 +3843,7 @@ void BindingData::Deserialize(Local<Context> context,
@@ -3850,7 +3850,7 @@ void BindingData::Deserialize(Local<Context> context,
int index,
InternalFieldInfoBase* info) {
DCHECK_IS_SNAPSHOT_SLOT(index);
@@ -686,7 +686,7 @@ index d33ee3c26c111e53edf27e6368ca8f64ff30a349..f1c53c44f201b295888e7932c5e3e2b1
Environment* env = Environment::GetCurrent(isolate);
diff --git a/src/node_url.cc b/src/node_url.cc
index 9d1e8ec05161570db11f7b662395509774668d78..9b91f83d879ea02fd3d61913c8dfd35b3bf1ac31 100644
index 9b676a0156ab8ef47f62627be953c23d4fcbf4f4..6294cd03667980e2ad23cae9e7961262369efb62 100644
--- a/src/node_url.cc
+++ b/src/node_url.cc
@@ -70,7 +70,7 @@ void BindingData::Deserialize(Local<Context> context,

View File

@@ -7,7 +7,7 @@ Subject: build: ensure native module compilation fails if not using a new
This should not be upstreamed, it is a quality-of-life patch for downstream module builders.
diff --git a/common.gypi b/common.gypi
index b3b5c23e471ece7584d209b3ae4197c46011d50e..bdcea65ad3e0315c85b1818e695d8b63093aed34 100644
index d9eb9527e3cbb3b101274ab19e6d6ace42f0e022..a1243ad39b8fcf564285ace0b51b1482bd85071b 100644
--- a/common.gypi
+++ b/common.gypi
@@ -89,6 +89,8 @@

View File

@@ -11,7 +11,7 @@ node-gyp will use the result of `process.config` that reflects the environment
in which the binary got built.
diff --git a/common.gypi b/common.gypi
index bdcea65ad3e0315c85b1818e695d8b63093aed34..0653735a0b154e326e5df7049a7beb395f0015c8 100644
index a1243ad39b8fcf564285ace0b51b1482bd85071b..60ac7a50718fd8239fd96b811cdccd1c73b2d606 100644
--- a/common.gypi
+++ b/common.gypi
@@ -128,6 +128,7 @@

View File

@@ -10,7 +10,7 @@ M151, and so we should allow for building until then.
This patch can be removed at the M151 branch point.
diff --git a/common.gypi b/common.gypi
index 0653735a0b154e326e5df7049a7beb395f0015c8..006f52ed18d955da0d9a06e881e86e6e724095ac 100644
index 60ac7a50718fd8239fd96b811cdccd1c73b2d606..709eb83801eeed81f79c4305a86d1a19710298c2 100644
--- a/common.gypi
+++ b/common.gypi
@@ -677,7 +677,7 @@

View File

@@ -7,7 +7,7 @@ common.gypi is a file that's included in the node header bundle, despite
the fact that we do not build node with gyp.
diff --git a/common.gypi b/common.gypi
index c5a7dc9cacf8b983984e7c7de9e63d26e418cc8d..b3b5c23e471ece7584d209b3ae4197c46011d50e 100644
index 283c60eab356a5befc15027cd186ea0416914ee6..d9eb9527e3cbb3b101274ab19e6d6ace42f0e022 100644
--- a/common.gypi
+++ b/common.gypi
@@ -91,6 +91,23 @@

View File

@@ -53,10 +53,10 @@ index 81799fc159cf20344aac64cd7129240deb9a4fe8..12b476ff97603718186dd25b1f435d37
const maybeMain = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ?
packageConfig.main || './' : '';
diff --git a/src/node_file.cc b/src/node_file.cc
index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb7648694a 100644
index c69b4eb461cab79906833152d02f76f81149ad7e..96aac2d86695732bf6805f2ad2168a62241b5045 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -3592,13 +3592,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
@@ -3599,13 +3599,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
}
BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
@@ -83,7 +83,7 @@ index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb
uv_fs_t req;
int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr);
@@ -3656,6 +3668,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -3663,6 +3675,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
std::optional<std::string> initial_file_path;
std::string file_path;
@@ -95,7 +95,7 @@ index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb
if (args.Length() >= 2 && args[1]->IsString()) {
auto package_config_main = Utf8Value(isolate, args[1]).ToString();
@@ -3676,7 +3693,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -3683,7 +3700,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
BufferValue buff_file_path(isolate, local_file_path);
ToNamespacedPath(env, &buff_file_path);
@@ -104,7 +104,7 @@ index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb
case BindingData::FilePathIsFileReturnType::kIsFile:
return args.GetReturnValue().Set(i);
case BindingData::FilePathIsFileReturnType::kIsNotFile:
@@ -3713,7 +3730,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -3720,7 +3737,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
BufferValue buff_file_path(isolate, local_file_path);
ToNamespacedPath(env, &buff_file_path);

View File

@@ -7,10 +7,10 @@ libc++ added [[nodiscard]] to std::filesystem::copy_options operator|=
which causes build failures with -Werror.
diff --git a/src/node_file.cc b/src/node_file.cc
index e834325a763f7ea8f53210145b5edd134d6b67e6..5197202255bcd9345ac19c7fb6106f49c2800770 100644
index 547455bb5011677719a8de1f98cb447561bce6aa..385db5fd6fe5db6bb7ff17e98309b6cd605a82d3 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -3453,11 +3453,11 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
@@ -3460,11 +3460,11 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
auto file_copy_opts = std::filesystem::copy_options::recursive;
if (force) {

View File

@@ -308,6 +308,7 @@ void Menu::OnMenuWillClose() {
}
void Menu::OnMenuWillShow() {
keep_alive_ = this;
Emit("menu-will-show");
}

View File

@@ -140,7 +140,7 @@ class Menu : public gin::Wrappable<Menu>,
bool IsVisibleAt(int index) const;
bool WorksWhenHiddenAt(int index) const;
gin_helper::SelfKeepAlive<Menu> keep_alive_{this};
gin_helper::SelfKeepAlive<Menu> keep_alive_{nullptr};
};
} // namespace electron::api

View File

@@ -3126,16 +3126,18 @@ void OnGetDeviceNameToUse(base::WeakPtr<content::WebContents> web_contents,
.Set(printing::kSettingMediaSizeIsDefault, true);
};
const bool use_default_size =
print_settings.FindBool(kUseDefaultPrinterPageSize).value_or(false);
std::optional<gfx::Size> paper_size;
if (use_default_size)
paper_size = GetPrinterDefaultPaperSize(base::UTF16ToUTF8(info.second));
if (!print_settings.Find(printing::kSettingMediaSize)) {
const bool use_default_size =
print_settings.FindBool(kUseDefaultPrinterPageSize).value_or(false);
std::optional<gfx::Size> paper_size;
if (use_default_size)
paper_size = GetPrinterDefaultPaperSize(base::UTF16ToUTF8(info.second));
print_settings.Set(
printing::kSettingMediaSize,
paper_size ? make_media_size(paper_size->height(), paper_size->width())
: make_media_size(297000, 210000));
print_settings.Set(
printing::kSettingMediaSize,
paper_size ? make_media_size(paper_size->height(), paper_size->width())
: make_media_size(297000, 210000));
}
content::RenderFrameHost* rfh = GetRenderFrameHostToUse(web_contents.get());
if (!rfh)

View File

@@ -158,45 +158,43 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
windowSize.width() - contentSize.width() + extraSize.width();
double extraHeightPlusFrame = titleBarHeight + extraSize.height();
newSize.width =
roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio +
extraWidthPlusFrame);
newSize.height =
roundf((newSize.width - extraWidthPlusFrame) / aspectRatio +
extraHeightPlusFrame);
auto widthForHeight = [&](double h) {
return (h - extraHeightPlusFrame) * aspectRatio + extraWidthPlusFrame;
};
auto heightForWidth = [&](double w) {
return (w - extraWidthPlusFrame) / aspectRatio + extraHeightPlusFrame;
};
newSize.width = roundf(widthForHeight(frameSize.height));
newSize.height = roundf(heightForWidth(newSize.width));
// Clamp to minimum width/height while ensuring aspect ratio remains.
NSSize minSize = [window minSize];
NSSize zeroSize =
shell_->has_frame() ? NSMakeSize(0, titleBarHeight) : NSZeroSize;
if (!NSEqualSizes(minSize, zeroSize)) {
double minWidthForAspectRatio =
(minSize.height - titleBarHeight) * aspectRatio;
bool atMinHeight =
minSize.height > zeroSize.height && newSize.height <= minSize.height;
newSize.width = atMinHeight ? minWidthForAspectRatio
newSize.width = atMinHeight ? widthForHeight(minSize.height)
: std::max(newSize.width, minSize.width);
double minHeightForAspectRatio = minSize.width / aspectRatio;
bool atMinWidth =
minSize.width > zeroSize.width && newSize.width <= minSize.width;
newSize.height = atMinWidth ? minHeightForAspectRatio
newSize.height = atMinWidth ? heightForWidth(minSize.width)
: std::max(newSize.height, minSize.height);
}
// Clamp to maximum width/height while ensuring aspect ratio remains.
NSSize maxSize = [window maxSize];
if (!NSEqualSizes(maxSize, NSMakeSize(FLT_MAX, FLT_MAX))) {
double maxWidthForAspectRatio = maxSize.height * aspectRatio;
bool atMaxHeight =
maxSize.height < FLT_MAX && newSize.height >= maxSize.height;
newSize.width = atMaxHeight ? maxWidthForAspectRatio
newSize.width = atMaxHeight ? widthForHeight(maxSize.height)
: std::min(newSize.width, maxSize.width);
double maxHeightForAspectRatio = maxSize.width / aspectRatio;
bool atMaxWidth =
maxSize.width < FLT_MAX && newSize.width >= maxSize.width;
newSize.height = atMaxWidth ? maxHeightForAspectRatio
newSize.height = atMaxWidth ? heightForWidth(maxSize.width)
: std::min(newSize.height, maxSize.height);
}
}

View File

@@ -402,7 +402,7 @@ void InspectableWebContents::SetDockState(const std::string& state) {
can_dock_ = false;
} else {
can_dock_ = true;
dock_state_ = IsValidDockState(state) ? state : "right";
dock_state_ = (state.empty() || IsValidDockState(state)) ? state : "right";
}
}