mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
1 Commits
main
...
build/gn-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa00a51914 |
29
.github/workflows/build.yml
vendored
29
.github/workflows/build.yml
vendored
@@ -442,7 +442,34 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, windows-x64, windows-x86, windows-arm64]
|
needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, windows-x64, windows-x86, windows-arm64]
|
||||||
if: always() && github.repository == 'electron/electron' && !contains(needs.*.result, 'failure')
|
if: always() && github.repository == 'electron/electron' && !contains(needs.*.result, 'failure')
|
||||||
steps:
|
steps:
|
||||||
- name: GitHub Actions Jobs Done
|
- name: GitHub Actions Jobs Done
|
||||||
run: |
|
run: |
|
||||||
echo "All GitHub Actions Jobs are done"
|
echo "All GitHub Actions Jobs are done"
|
||||||
|
|
||||||
|
check-signed-commits:
|
||||||
|
name: Check signed commits in green PR
|
||||||
|
needs: gha-done
|
||||||
|
if: ${{ contains(github.event.pull_request.labels.*.name, 'needs-signed-commits')}}
|
||||||
|
runs-on: ubuntu-slim
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Check signed commits in PR
|
||||||
|
uses: 1Password/check-signed-commits-action@ed2885f3ed2577a4f5d3c3fe895432a557d23d52 # v1
|
||||||
|
with:
|
||||||
|
comment: |
|
||||||
|
⚠️ This PR contains unsigned commits. This repository enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification)
|
||||||
|
for all incoming PRs. To get your PR merged, please sign those commits
|
||||||
|
(`git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}`) and force push them to this branch
|
||||||
|
(`git push --force-with-lease`)
|
||||||
|
|
||||||
|
For more information on signing commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key).
|
||||||
|
|
||||||
|
- name: Remove needs-signed-commits label
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||||
|
run: |
|
||||||
|
gh pr edit $PR_URL --remove-label needs-signed-commits
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ permissions: {}
|
|||||||
jobs:
|
jobs:
|
||||||
check-signed-commits:
|
check-signed-commits:
|
||||||
name: Check signed commits in PR
|
name: Check signed commits in PR
|
||||||
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'needs-signed-commits')}}
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-slim
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -22,9 +23,9 @@ jobs:
|
|||||||
uses: 1Password/check-signed-commits-action@ed2885f3ed2577a4f5d3c3fe895432a557d23d52 # v1
|
uses: 1Password/check-signed-commits-action@ed2885f3ed2577a4f5d3c3fe895432a557d23d52 # v1
|
||||||
with:
|
with:
|
||||||
comment: |
|
comment: |
|
||||||
⚠️ This PR contains unsigned commits. This repository enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification)
|
⚠️ This PR contains unsigned commits. This repository enforces [commit signatures](https://docs.github.com/en/authentication/managing-commit-signature-verification)
|
||||||
for all incoming PRs. To get your PR merged, please sign those commits
|
for all incoming PRs. To get your PR merged, please sign those commits
|
||||||
(`git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}`) and force push them to this branch
|
(`git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}`) and force push them to this branch
|
||||||
(`git push --force-with-lease`)
|
(`git push --force-with-lease`)
|
||||||
|
|
||||||
For more information on signing commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key).
|
For more information on signing commits, see GitHub's documentation on [Telling Git about your signing key](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key).
|
||||||
@@ -36,11 +37,3 @@ jobs:
|
|||||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||||
run: |
|
run: |
|
||||||
gh pr edit $PR_URL --add-label needs-signed-commits
|
gh pr edit $PR_URL --add-label needs-signed-commits
|
||||||
|
|
||||||
- name: Remove needs-signed-commits label
|
|
||||||
if: ${{ success() && contains(github.event.pull_request.labels.*.name, 'needs-signed-commits') }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
||||||
run: |
|
|
||||||
gh pr edit $PR_URL --remove-label needs-signed-commits
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { shell } from 'electron/common';
|
import { shell } from 'electron/common';
|
||||||
import { app, dialog, BrowserWindow, ipcMain, Menu } from 'electron/main';
|
import { app, dialog, BrowserWindow, ipcMain } from 'electron/main';
|
||||||
|
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import * as url from 'node:url';
|
import * as url from 'node:url';
|
||||||
@@ -11,53 +11,6 @@ app.on('window-all-closed', () => {
|
|||||||
app.quit();
|
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) {
|
function decorateURL (url: string) {
|
||||||
// safely add `?utm_source=default_app
|
// safely add `?utm_source=default_app
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ this has the additional effect of removing the menu bar from the window.
|
|||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> The default menu will be created automatically if the app does not set one.
|
> The default menu will be created automatically if the app does not set one.
|
||||||
> It contains standard items such as `File`, `Edit`, `View`, and `Window`.
|
> It contains standard items such as `File`, `Edit`, `View`, `Window` and `Help`.
|
||||||
|
|
||||||
#### `Menu.getApplicationMenu()`
|
#### `Menu.getApplicationMenu()`
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Menu } from 'electron/main';
|
import { shell } from 'electron/common';
|
||||||
|
import { app, Menu } from 'electron/main';
|
||||||
|
|
||||||
const isMac = process.platform === 'darwin';
|
const isMac = process.platform === 'darwin';
|
||||||
|
|
||||||
@@ -11,13 +12,47 @@ export const setApplicationMenuWasSet = () => {
|
|||||||
export const setDefaultApplicationMenu = () => {
|
export const setDefaultApplicationMenu = () => {
|
||||||
if (applicationMenuWasSet) return;
|
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 macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' };
|
||||||
const template: Electron.MenuItemConstructorOptions[] = [
|
const template: Electron.MenuItemConstructorOptions[] = [
|
||||||
...(isMac ? [macAppMenu] : []),
|
...(isMac ? [macAppMenu] : []),
|
||||||
{ role: 'fileMenu' },
|
{ role: 'fileMenu' },
|
||||||
{ role: 'editMenu' },
|
{ role: 'editMenu' },
|
||||||
{ role: 'viewMenu' },
|
{ role: 'viewMenu' },
|
||||||
{ role: 'windowMenu' }
|
{ role: 'windowMenu' },
|
||||||
|
helpMenu
|
||||||
];
|
];
|
||||||
|
|
||||||
const menu = Menu.buildFromTemplate(template);
|
const menu = Menu.buildFromTemplate(template);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"@types/stream-json": "^1.7.8",
|
"@types/stream-json": "^1.7.8",
|
||||||
"@types/temp": "^0.9.4",
|
"@types/temp": "^0.9.4",
|
||||||
"@xmldom/xmldom": "^0.8.12",
|
"@xmldom/xmldom": "^0.8.11",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"check-for-leaks": "^1.2.1",
|
"check-for-leaks": "^1.2.1",
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ feat_separate_content_settings_callback_for_sync_and_async_clipboard.patch
|
|||||||
fix_win32_synchronous_spellcheck.patch
|
fix_win32_synchronous_spellcheck.patch
|
||||||
chore_grandfather_in_electron_views_and_delegates.patch
|
chore_grandfather_in_electron_views_and_delegates.patch
|
||||||
refactor_patch_electron_permissiontypes_into_blink.patch
|
refactor_patch_electron_permissiontypes_into_blink.patch
|
||||||
|
revert_views_remove_desktopwindowtreehostwin_window_enlargement.patch
|
||||||
fix_add_macos_memory_query_fallback_to_avoid_crash.patch
|
fix_add_macos_memory_query_fallback_to_avoid_crash.patch
|
||||||
fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch
|
fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch
|
||||||
feat_add_support_for_embedder_snapshot_validation.patch
|
feat_add_support_for_embedder_snapshot_validation.patch
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ electron objects that extend gin::Wrappable and gets
|
|||||||
allocated on the cpp heap
|
allocated on the cpp heap
|
||||||
|
|
||||||
diff --git a/gin/public/wrappable_pointer_tags.h b/gin/public/wrappable_pointer_tags.h
|
diff --git a/gin/public/wrappable_pointer_tags.h b/gin/public/wrappable_pointer_tags.h
|
||||||
index fee622ebde42211de6f702b754cfa38595df5a1c..9f7e1b1b8d871721891255c1f21de825d0df1e30 100644
|
index fee622ebde42211de6f702b754cfa38595df5a1c..6b524632ebb405e473cf4fe8e253bd13bf7b67e5 100644
|
||||||
--- a/gin/public/wrappable_pointer_tags.h
|
--- a/gin/public/wrappable_pointer_tags.h
|
||||||
+++ b/gin/public/wrappable_pointer_tags.h
|
+++ b/gin/public/wrappable_pointer_tags.h
|
||||||
@@ -77,7 +77,21 @@ enum WrappablePointerTag : uint16_t {
|
@@ -77,7 +77,20 @@ enum WrappablePointerTag : uint16_t {
|
||||||
kWebAXObjectProxy, // content::WebAXObjectProxy
|
kWebAXObjectProxy, // content::WebAXObjectProxy
|
||||||
kWrappedExceptionHandler, // extensions::WrappedExceptionHandler
|
kWrappedExceptionHandler, // extensions::WrappedExceptionHandler
|
||||||
kIndigoContext, // indigo::IndigoContext
|
kIndigoContext, // indigo::IndigoContext
|
||||||
@@ -24,7 +24,6 @@ index fee622ebde42211de6f702b754cfa38595df5a1c..9f7e1b1b8d871721891255c1f21de825
|
|||||||
+ kElectronNetLog, // electron::api::NetLog
|
+ kElectronNetLog, // electron::api::NetLog
|
||||||
+ kElectronPowerMonitor, // electron::api::PowerMonitor
|
+ kElectronPowerMonitor, // electron::api::PowerMonitor
|
||||||
+ kElectronPowerSaveBlocker, // electron::api::PowerSaveBlocker
|
+ kElectronPowerSaveBlocker, // electron::api::PowerSaveBlocker
|
||||||
+ kElectronProtocol, // electron::api::Protocol
|
|
||||||
+ kElectronReplyChannel, // gin_helper::internal::ReplyChannel
|
+ kElectronReplyChannel, // gin_helper::internal::ReplyChannel
|
||||||
+ kElectronScreen, // electron::api::Screen
|
+ kElectronScreen, // electron::api::Screen
|
||||||
+ kElectronSession, // electron::api::Session
|
+ kElectronSession, // electron::api::Session
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ such as the background turning black when maximizing the window and
|
|||||||
dynamic background material settings not taking effect.
|
dynamic background material settings not taking effect.
|
||||||
|
|
||||||
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||||
index e4da40256ce94d6a0896792a8ef2faa18e1fa5d2..3a5833fcc018f32e86c0a95a42937fb9ac6c5a40 100644
|
index d1e06b675b19226cf3b78e1aada8d8f2d684fada..ce810555b8501797643987916a728cad8f5adaa5 100644
|
||||||
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||||
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||||
@@ -167,6 +167,10 @@ void DesktopWindowTreeHostWin::FinishTouchDrag(gfx::Point screen_point) {
|
@@ -184,6 +184,10 @@ void DesktopWindowTreeHostWin::FinishTouchDrag(gfx::Point screen_point) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ index e4da40256ce94d6a0896792a8ef2faa18e1fa5d2..3a5833fcc018f32e86c0a95a42937fb9
|
|||||||
|
|
||||||
void DesktopWindowTreeHostWin::Init(const Widget::InitParams& params) {
|
void DesktopWindowTreeHostWin::Init(const Widget::InitParams& params) {
|
||||||
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
||||||
index 27322ef34edf3fa8bfbd20b1baddcaf3b7555618..b8d1fa863fd05ebc3ab8ac5ef8c4d81361ce45fe 100644
|
index a40bd9f25fa07a553c011cf19f155f8158f4ae5f..ae2baec731b5fcd8be97f2177d23b860d67ab8bc 100644
|
||||||
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
||||||
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
||||||
@@ -93,6 +93,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
|
@@ -93,6 +93,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
|
||||||
|
|||||||
@@ -620,7 +620,7 @@ index 2a477e820d9f0126a05f86cd44f02c2189275bad..a2e9442ff9f5acf8e301f457b1806251
|
|||||||
|
|
||||||
#if BUILDFLAG(IS_CHROMEOS)
|
#if BUILDFLAG(IS_CHROMEOS)
|
||||||
diff --git a/chrome/browser/printing/printer_query_oop.cc b/chrome/browser/printing/printer_query_oop.cc
|
diff --git a/chrome/browser/printing/printer_query_oop.cc b/chrome/browser/printing/printer_query_oop.cc
|
||||||
index dc2a15ab4d784b0b6c85b84a30c3c08a17ed8e3d..5ca7920c8525c3c72fd96b14709fb35a9cc28daf 100644
|
index dc2a15ab4d784b0b6c85b84a30c3c08a17ed8e3d..e197026e8a7f132c1bf90a0f5f1eabb4f5f064ee 100644
|
||||||
--- a/chrome/browser/printing/printer_query_oop.cc
|
--- a/chrome/browser/printing/printer_query_oop.cc
|
||||||
+++ b/chrome/browser/printing/printer_query_oop.cc
|
+++ b/chrome/browser/printing/printer_query_oop.cc
|
||||||
@@ -126,7 +126,7 @@ void PrinterQueryOop::OnDidAskUserForSettings(
|
@@ -126,7 +126,7 @@ void PrinterQueryOop::OnDidAskUserForSettings(
|
||||||
@@ -632,7 +632,7 @@ index dc2a15ab4d784b0b6c85b84a30c3c08a17ed8e3d..5ca7920c8525c3c72fd96b14709fb35a
|
|||||||
// Want the same PrintBackend service as the query so that we use the same
|
// Want the same PrintBackend service as the query so that we use the same
|
||||||
// device context.
|
// device context.
|
||||||
print_document_client_id_ =
|
print_document_client_id_ =
|
||||||
@@ -189,6 +189,28 @@ void PrinterQueryOop::GetSettingsWithUI(uint32_t document_page_count,
|
@@ -189,6 +189,21 @@ void PrinterQueryOop::GetSettingsWithUI(uint32_t document_page_count,
|
||||||
// browser process.
|
// browser process.
|
||||||
// - Other platforms don't have a system print UI or do not use OOP
|
// - Other platforms don't have a system print UI or do not use OOP
|
||||||
// printing, so this does not matter.
|
// printing, so this does not matter.
|
||||||
@@ -643,19 +643,12 @@ index dc2a15ab4d784b0b6c85b84a30c3c08a17ed8e3d..5ca7920c8525c3c72fd96b14709fb35a
|
|||||||
+ // remote service context, not the local one used by the native dialog.
|
+ // remote service context, not the local one used by the native dialog.
|
||||||
+ if (settings().dpi()) {
|
+ if (settings().dpi()) {
|
||||||
+ printing_context()->SetPrintSettings(settings());
|
+ printing_context()->SetPrintSettings(settings());
|
||||||
+ if (printing_context()->UpdatePrinterSettings(
|
+ printing_context()->UpdatePrinterSettings(PrintingContext::PrinterSettings{
|
||||||
+ PrintingContext::PrinterSettings{
|
|
||||||
+#if BUILDFLAG(IS_MAC)
|
+#if BUILDFLAG(IS_MAC)
|
||||||
+ .external_preview = false,
|
+ .external_preview = false,
|
||||||
+#endif
|
+#endif
|
||||||
+ .show_system_dialog = false,
|
+ .show_system_dialog = false,
|
||||||
+ }) != mojom::ResultCode::kSuccess) {
|
+ });
|
||||||
+ // Prefilling failed (e.g. the printer does not support the requested
|
|
||||||
+ // resolution). Reinitialize with defaults so that AskUserForSettings
|
|
||||||
+ // does not crash due to a null print_info_. The dialog will simply
|
|
||||||
+ // open without prefilled values.
|
|
||||||
+ printing_context()->UseDefaultSettings();
|
|
||||||
+ }
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
PrinterQuery::GetSettingsWithUI(
|
PrinterQuery::GetSettingsWithUI(
|
||||||
|
|||||||
@@ -0,0 +1,285 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Kleinschmidt <jkleinsc@electronjs.org>
|
||||||
|
Date: Sat, 14 Jun 2025 16:21:07 -0400
|
||||||
|
Subject: Revert "[views] Remove DesktopWindowTreeHostWin::window_enlargement_"
|
||||||
|
|
||||||
|
This reverts commit 1771dbae6961e7bb7c22bbc6c77f84d90ef2be46.
|
||||||
|
|
||||||
|
Electron needs this patch to allow windows smaller than 64x64
|
||||||
|
on Windows. We should refactor our code so that this patch isn't
|
||||||
|
necessary.
|
||||||
|
|
||||||
|
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
|
||||||
|
index 988866d79a5d1dbd366ebdbff0e8eb2c0c498168..5761ac48be0a64618be0a94606149dd944e46e27 100644
|
||||||
|
--- a/testing/variations/fieldtrial_testing_config.json
|
||||||
|
+++ b/testing/variations/fieldtrial_testing_config.json
|
||||||
|
@@ -22626,6 +22626,21 @@
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
+ "TransparentHwndEnlargement": [
|
||||||
|
+ {
|
||||||
|
+ "platforms": [
|
||||||
|
+ "windows"
|
||||||
|
+ ],
|
||||||
|
+ "experiments": [
|
||||||
|
+ {
|
||||||
|
+ "name": "DisableTransparentHwndEnlargement",
|
||||||
|
+ "disable_features": [
|
||||||
|
+ "EnableTransparentHwndEnlargement"
|
||||||
|
+ ]
|
||||||
|
+ }
|
||||||
|
+ ]
|
||||||
|
+ }
|
||||||
|
+ ],
|
||||||
|
"TransportSecurityFileWriterScheduleAndroid": [
|
||||||
|
{
|
||||||
|
"platforms": [
|
||||||
|
diff --git a/ui/views/views_features.cc b/ui/views/views_features.cc
|
||||||
|
index 47077e16870889ef8f8c8b2adf58015bd5aff7fa..ba59e6e1609e61579bf49aca095490b083d72051 100644
|
||||||
|
--- a/ui/views/views_features.cc
|
||||||
|
+++ b/ui/views/views_features.cc
|
||||||
|
@@ -30,6 +30,14 @@ BASE_FEATURE(kEnableInputProtection, base::FEATURE_DISABLED_BY_DEFAULT);
|
||||||
|
// crbug.com/370856871.
|
||||||
|
BASE_FEATURE(kEnableTouchDragCursorSync, base::FEATURE_ENABLED_BY_DEFAULT);
|
||||||
|
|
||||||
|
+// Enables enlargement of HWNDs to a minimum size of 64x64 to handle reported
|
||||||
|
+// graphical glitches on certain hardware.
|
||||||
|
+// TODO(crbug.com/401996981): Remove this once enlargement is confirmed to no
|
||||||
|
+// longer be needed.
|
||||||
|
+BASE_FEATURE(kEnableTransparentHwndEnlargement,
|
||||||
|
+ "EnableTransparentHwndEnlargement",
|
||||||
|
+ base::FEATURE_DISABLED_BY_DEFAULT);
|
||||||
|
+
|
||||||
|
// Used to enable keyboard-accessible tooltips in Views UI, as opposed
|
||||||
|
// to kKeyboardAccessibleTooltip in //ui/base/ui_base_features.cc.
|
||||||
|
BASE_FEATURE(kKeyboardAccessibleTooltipInViews,
|
||||||
|
diff --git a/ui/views/views_features.h b/ui/views/views_features.h
|
||||||
|
index 888a16fb6213eceb131ae636dc643d7f2d5bcad9..6077412165081cd4abeaf0b061feb2f795ee8131 100644
|
||||||
|
--- a/ui/views/views_features.h
|
||||||
|
+++ b/ui/views/views_features.h
|
||||||
|
@@ -15,6 +15,7 @@ namespace views::features {
|
||||||
|
VIEWS_EXPORT BASE_DECLARE_FEATURE(kApplyInitialUrlToWebContents);
|
||||||
|
VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableInputProtection);
|
||||||
|
VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableTouchDragCursorSync);
|
||||||
|
+VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableTransparentHwndEnlargement);
|
||||||
|
VIEWS_EXPORT BASE_DECLARE_FEATURE(kKeyboardAccessibleTooltipInViews);
|
||||||
|
|
||||||
|
} // namespace views::features
|
||||||
|
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||||
|
index e4da40256ce94d6a0896792a8ef2faa18e1fa5d2..d1e06b675b19226cf3b78e1aada8d8f2d684fada 100644
|
||||||
|
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||||
|
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||||
|
@@ -85,6 +85,23 @@ namespace {
|
||||||
|
// This constant controls how many pixels wide that border is.
|
||||||
|
const int kMouseCaptureRegionBorder = 5;
|
||||||
|
|
||||||
|
+gfx::Size GetExpandedWindowSize(bool is_translucent, gfx::Size size) {
|
||||||
|
+ if (!base::FeatureList::IsEnabled(
|
||||||
|
+ features::kEnableTransparentHwndEnlargement) ||
|
||||||
|
+ !is_translucent) {
|
||||||
|
+ return size;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Some AMD drivers can't display windows that are less than 64x64 pixels,
|
||||||
|
+ // so expand them to be at least that size. http://crbug.com/286609
|
||||||
|
+ gfx::Size expanded(std::max(size.width(), 64), std::max(size.height(), 64));
|
||||||
|
+ return expanded;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void InsetBottomRight(gfx::Rect* rect, const gfx::Vector2d& vector) {
|
||||||
|
+ rect->Inset(gfx::Insets::TLBR(0, 0, vector.y(), vector.x()));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// Updates the cursor clip region. Used for mouse locking.
|
||||||
|
void UpdateMouseLockRegion(aura::Window* window, bool locked) {
|
||||||
|
if (!locked) {
|
||||||
|
@@ -342,9 +359,14 @@ bool DesktopWindowTreeHostWin::IsVisible() const {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopWindowTreeHostWin::SetSize(const gfx::Size& size) {
|
||||||
|
- const gfx::Size size_in_pixels =
|
||||||
|
+ gfx::Size size_in_pixels =
|
||||||
|
display::win::GetScreenWin()->DIPToScreenSize(GetHWND(), size);
|
||||||
|
- message_handler_->SetSize(size_in_pixels);
|
||||||
|
+ gfx::Size expanded =
|
||||||
|
+ GetExpandedWindowSize(message_handler_->is_translucent(), size_in_pixels);
|
||||||
|
+ window_enlargement_ =
|
||||||
|
+ gfx::Vector2d(expanded.width() - size_in_pixels.width(),
|
||||||
|
+ expanded.height() - size_in_pixels.height());
|
||||||
|
+ message_handler_->SetSize(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopWindowTreeHostWin::StackAbove(aura::Window* window) {
|
||||||
|
@@ -359,30 +381,40 @@ void DesktopWindowTreeHostWin::StackAtTop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopWindowTreeHostWin::CenterWindow(const gfx::Size& size) {
|
||||||
|
- const gfx::Size size_in_pixels =
|
||||||
|
+ gfx::Size size_in_pixels =
|
||||||
|
display::win::GetScreenWin()->DIPToScreenSize(GetHWND(), size);
|
||||||
|
- message_handler_->CenterWindow(size_in_pixels);
|
||||||
|
+ gfx::Size expanded_size;
|
||||||
|
+ expanded_size =
|
||||||
|
+ GetExpandedWindowSize(message_handler_->is_translucent(), size_in_pixels);
|
||||||
|
+ window_enlargement_ =
|
||||||
|
+ gfx::Vector2d(expanded_size.width() - size_in_pixels.width(),
|
||||||
|
+ expanded_size.height() - size_in_pixels.height());
|
||||||
|
+ message_handler_->CenterWindow(expanded_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopWindowTreeHostWin::GetWindowPlacement(
|
||||||
|
gfx::Rect* bounds,
|
||||||
|
ui::mojom::WindowShowState* show_state) const {
|
||||||
|
message_handler_->GetWindowPlacement(bounds, show_state);
|
||||||
|
+ InsetBottomRight(bounds, window_enlargement_);
|
||||||
|
*bounds = display::win::GetScreenWin()->ScreenToDIPRect(GetHWND(), *bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Rect DesktopWindowTreeHostWin::GetWindowBoundsInScreen() const {
|
||||||
|
gfx::Rect pixel_bounds = message_handler_->GetWindowBoundsInScreen();
|
||||||
|
+ InsetBottomRight(&pixel_bounds, window_enlargement_);
|
||||||
|
return display::win::GetScreenWin()->ScreenToDIPRect(GetHWND(), pixel_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Rect DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() const {
|
||||||
|
gfx::Rect pixel_bounds = message_handler_->GetClientAreaBoundsInScreen();
|
||||||
|
+ InsetBottomRight(&pixel_bounds, window_enlargement_);
|
||||||
|
return display::win::GetScreenWin()->ScreenToDIPRect(GetHWND(), pixel_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Rect DesktopWindowTreeHostWin::GetRestoredBounds() const {
|
||||||
|
gfx::Rect pixel_bounds = message_handler_->GetRestoredBounds();
|
||||||
|
+ InsetBottomRight(&pixel_bounds, window_enlargement_);
|
||||||
|
return display::win::GetScreenWin()->ScreenToDIPRect(GetHWND(), pixel_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -701,37 +733,44 @@ void DesktopWindowTreeHostWin::HideImpl() {
|
||||||
|
// other get/set methods work in DIP.
|
||||||
|
|
||||||
|
gfx::Rect DesktopWindowTreeHostWin::GetBoundsInPixels() const {
|
||||||
|
- const gfx::Rect bounds_px(message_handler_->GetClientAreaBounds());
|
||||||
|
+ gfx::Rect bounds(message_handler_->GetClientAreaBounds());
|
||||||
|
// If the window bounds were expanded we need to return the original bounds
|
||||||
|
// To achieve this we do the reverse of the expansion, i.e. add the
|
||||||
|
// window_expansion_top_left_delta_ to the origin and subtract the
|
||||||
|
// window_expansion_bottom_right_delta_ from the width and height.
|
||||||
|
- const gfx::Rect without_expansion_bounds_px(
|
||||||
|
- bounds_px.x() + window_expansion_top_left_delta_.x(),
|
||||||
|
- bounds_px.y() + window_expansion_top_left_delta_.y(),
|
||||||
|
- bounds_px.width() - window_expansion_bottom_right_delta_.x(),
|
||||||
|
- bounds_px.height() - window_expansion_bottom_right_delta_.y());
|
||||||
|
- return without_expansion_bounds_px;
|
||||||
|
+ gfx::Rect without_expansion(
|
||||||
|
+ bounds.x() + window_expansion_top_left_delta_.x(),
|
||||||
|
+ bounds.y() + window_expansion_top_left_delta_.y(),
|
||||||
|
+ bounds.width() - window_expansion_bottom_right_delta_.x() -
|
||||||
|
+ window_enlargement_.x(),
|
||||||
|
+ bounds.height() - window_expansion_bottom_right_delta_.y() -
|
||||||
|
+ window_enlargement_.y());
|
||||||
|
+ return without_expansion;
|
||||||
|
}
|
||||||
|
|
||||||
|
-void DesktopWindowTreeHostWin::SetBoundsInPixels(
|
||||||
|
- const gfx::Rect& bounds_in_pixels) {
|
||||||
|
+void DesktopWindowTreeHostWin::SetBoundsInPixels(const gfx::Rect& bounds) {
|
||||||
|
// If the window bounds have to be expanded we need to subtract the
|
||||||
|
// window_expansion_top_left_delta_ from the origin and add the
|
||||||
|
// window_expansion_bottom_right_delta_ to the width and height
|
||||||
|
- const gfx::Size old_content_size_px = GetBoundsInPixels().size();
|
||||||
|
-
|
||||||
|
- const gfx::Rect expanded_bounds_px(
|
||||||
|
- bounds_in_pixels.x() - window_expansion_top_left_delta_.x(),
|
||||||
|
- bounds_in_pixels.y() - window_expansion_top_left_delta_.y(),
|
||||||
|
- bounds_in_pixels.width() + window_expansion_bottom_right_delta_.x(),
|
||||||
|
- bounds_in_pixels.height() + window_expansion_bottom_right_delta_.y());
|
||||||
|
-
|
||||||
|
- // When `expanded_bounds_px` causes the window to be moved to a display with a
|
||||||
|
+ gfx::Size old_content_size = GetBoundsInPixels().size();
|
||||||
|
+
|
||||||
|
+ gfx::Rect expanded(
|
||||||
|
+ bounds.x() - window_expansion_top_left_delta_.x(),
|
||||||
|
+ bounds.y() - window_expansion_top_left_delta_.y(),
|
||||||
|
+ bounds.width() + window_expansion_bottom_right_delta_.x(),
|
||||||
|
+ bounds.height() + window_expansion_bottom_right_delta_.y());
|
||||||
|
+
|
||||||
|
+ gfx::Rect new_expanded(
|
||||||
|
+ expanded.origin(),
|
||||||
|
+ GetExpandedWindowSize(message_handler_->is_translucent(),
|
||||||
|
+ expanded.size()));
|
||||||
|
+ window_enlargement_ =
|
||||||
|
+ gfx::Vector2d(new_expanded.width() - expanded.width(),
|
||||||
|
+ new_expanded.height() - expanded.height());
|
||||||
|
+ // When |new_expanded| causes the window to be moved to a display with a
|
||||||
|
// different DSF, HWNDMessageHandler::OnDpiChanged() will be called and the
|
||||||
|
// window size will be scaled automatically.
|
||||||
|
- message_handler_->SetBounds(expanded_bounds_px,
|
||||||
|
- old_content_size_px != bounds_in_pixels.size());
|
||||||
|
+ message_handler_->SetBounds(new_expanded, old_content_size != bounds.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Rect
|
||||||
|
@@ -943,18 +982,26 @@ int DesktopWindowTreeHostWin::GetNonClientComponent(
|
||||||
|
|
||||||
|
void DesktopWindowTreeHostWin::GetWindowMask(const gfx::Size& size_px,
|
||||||
|
SkPath* path) {
|
||||||
|
- Widget* widget = GetWidget();
|
||||||
|
- if (!widget || !widget->non_client_view()) {
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
+ // Request the window mask for hwnd of `size_px`. The hwnd size must be
|
||||||
|
+ // adjusted by `window_enlargement` to return to the client-expected window
|
||||||
|
+ // size (see crbug.com/41047830).
|
||||||
|
+ const gfx::Size adjusted_size_in_px =
|
||||||
|
+ size_px - gfx::Size(window_enlargement_.x(), window_enlargement_.y());
|
||||||
|
|
||||||
|
- widget->non_client_view()->GetWindowMask(
|
||||||
|
- display::win::GetScreenWin()->ScreenToDIPSize(GetHWND(), size_px), path);
|
||||||
|
- // Convert path in DIPs to pixels.
|
||||||
|
- if (!path->isEmpty()) {
|
||||||
|
- const float scale =
|
||||||
|
- display::win::GetScreenWin()->GetScaleFactorForHWND(GetHWND());
|
||||||
|
- *path = path->makeTransform(SkMatrix::Scale(scale, scale));
|
||||||
|
+ if (Widget* widget = GetWidget(); widget && widget->non_client_view()) {
|
||||||
|
+ widget->non_client_view()->GetWindowMask(
|
||||||
|
+ display::win::GetScreenWin()->ScreenToDIPSize(GetHWND(),
|
||||||
|
+ adjusted_size_in_px),
|
||||||
|
+ path);
|
||||||
|
+ // Convert path in DIPs to pixels.
|
||||||
|
+ if (!path->isEmpty()) {
|
||||||
|
+ const float scale =
|
||||||
|
+ display::win::GetScreenWin()->GetScaleFactorForHWND(GetHWND());
|
||||||
|
+ *path = path->makeTransform(SkMatrix::Scale(scale, scale));
|
||||||
|
+ }
|
||||||
|
+ } else if (!window_enlargement_.IsZero()) {
|
||||||
|
+ *path = SkPath::Rect(SkRect::MakeXYWH(0, 0, adjusted_size_in_px.width(),
|
||||||
|
+ adjusted_size_in_px.height()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
||||||
|
index 27322ef34edf3fa8bfbd20b1baddcaf3b7555618..a40bd9f25fa07a553c011cf19f155f8158f4ae5f 100644
|
||||||
|
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
||||||
|
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
|
||||||
|
@@ -175,7 +175,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
|
||||||
|
void ShowImpl() override;
|
||||||
|
void HideImpl() override;
|
||||||
|
gfx::Rect GetBoundsInPixels() const override;
|
||||||
|
- void SetBoundsInPixels(const gfx::Rect& bounds_in_pixels) override;
|
||||||
|
+ void SetBoundsInPixels(const gfx::Rect& bounds) override;
|
||||||
|
gfx::Rect GetBoundsInAcceleratedWidgetPixelCoordinates() override;
|
||||||
|
gfx::Point GetLocationOnScreenInPixels() const override;
|
||||||
|
void SetCapture() override;
|
||||||
|
@@ -330,6 +330,12 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
|
||||||
|
gfx::Vector2d window_expansion_top_left_delta_;
|
||||||
|
gfx::Vector2d window_expansion_bottom_right_delta_;
|
||||||
|
|
||||||
|
+ // Windows are enlarged to be at least 64x64 pixels, so keep track of the
|
||||||
|
+ // extra added here.
|
||||||
|
+ // TODO(crbug.com/401996981): This is likely no longer necessary and should be
|
||||||
|
+ // removed.
|
||||||
|
+ gfx::Vector2d window_enlargement_;
|
||||||
|
+
|
||||||
|
// Whether the window close should be converted to a hide, and then actually
|
||||||
|
// closed on the completion of the hide animation. This is cached because
|
||||||
|
// the property is set on the contained window which has a shorter lifetime.
|
||||||
@@ -11,10 +11,9 @@ const path = require('node:path');
|
|||||||
|
|
||||||
const args = minimist(process.argv.slice(2), { string: ['outDir'] });
|
const args = minimist(process.argv.slice(2), { string: ['outDir'] });
|
||||||
|
|
||||||
const { getOutDir } = require('./lib/utils');
|
const { getDepotToolsEnv, getOutDir } = require('./lib/utils');
|
||||||
|
|
||||||
const SOURCE_ROOT = path.normalize(path.dirname(__dirname));
|
const SOURCE_ROOT = path.normalize(path.dirname(__dirname));
|
||||||
const DEPOT_TOOLS = path.resolve(SOURCE_ROOT, '..', 'third_party', 'depot_tools');
|
|
||||||
|
|
||||||
const OUT_DIR = getOutDir({ outDir: args.outDir });
|
const OUT_DIR = getOutDir({ outDir: args.outDir });
|
||||||
if (!OUT_DIR) {
|
if (!OUT_DIR) {
|
||||||
@@ -22,12 +21,10 @@ if (!OUT_DIR) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const env = {
|
const env = {
|
||||||
|
...getDepotToolsEnv(),
|
||||||
CHROMIUM_BUILDTOOLS_PATH: path.resolve(SOURCE_ROOT, '..', 'buildtools'),
|
CHROMIUM_BUILDTOOLS_PATH: path.resolve(SOURCE_ROOT, '..', 'buildtools'),
|
||||||
DEPOT_TOOLS_WIN_TOOLCHAIN: '0',
|
DEPOT_TOOLS_WIN_TOOLCHAIN: '0',
|
||||||
...process.env
|
|
||||||
};
|
};
|
||||||
// Users may not have depot_tools in PATH.
|
|
||||||
env.PATH = `${env.PATH}${path.delimiter}${DEPOT_TOOLS}`;
|
|
||||||
|
|
||||||
const gnCheckDirs = [
|
const gnCheckDirs = [
|
||||||
'//electron:electron_lib',
|
'//electron:electron_lib',
|
||||||
|
|||||||
@@ -205,11 +205,37 @@ def get_buildtools_executable(name):
|
|||||||
path += '.exe'
|
path += '.exe'
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def get_depot_tools_executable(name):
|
def get_depot_tools_env():
|
||||||
buildtools = os.path.realpath(
|
def find_depot_tools_on_path():
|
||||||
os.path.join(ELECTRON_DIR, '..', 'third_party', 'depot_tools'))
|
cmd = 'where' if sys.platform == 'win32' else 'which'
|
||||||
|
try:
|
||||||
|
subprocess.check_call([cmd, 'gclient'])
|
||||||
|
return os.environ.copy()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return None
|
||||||
|
|
||||||
path = os.path.join(buildtools, name)
|
def check_for_build_tools():
|
||||||
if sys.platform == 'win32':
|
try:
|
||||||
path += '.bat'
|
output = subprocess.check_output(
|
||||||
return path
|
'electron-build-tools show env --json',
|
||||||
|
shell=True, stderr=subprocess.DEVNULL
|
||||||
|
)
|
||||||
|
env = os.environ.copy()
|
||||||
|
env.update(json.loads(output.decode().strip()))
|
||||||
|
return env
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
depot_tools_env = check_for_build_tools()
|
||||||
|
if depot_tools_env is None:
|
||||||
|
depot_tools_env = find_depot_tools_on_path()
|
||||||
|
|
||||||
|
if depot_tools_env is None:
|
||||||
|
raise RuntimeError("Couldn't find depot_tools, ensure it's on your PATH")
|
||||||
|
|
||||||
|
if 'CHROMIUM_BUILDTOOLS_PATH' not in depot_tools_env:
|
||||||
|
raise RuntimeError(
|
||||||
|
'CHROMIUM_BUILDTOOLS_PATH environment variable must be set'
|
||||||
|
)
|
||||||
|
|
||||||
|
return depot_tools_env
|
||||||
|
|||||||
@@ -168,12 +168,60 @@ function getChromiumVersionFromDEPS (depsContent) {
|
|||||||
return CHROMIUM_VERSION_DEPS_REGEX.exec(depsContent)?.[1] ?? null;
|
return CHROMIUM_VERSION_DEPS_REGEX.exec(depsContent)?.[1] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDepotToolsEnv () {
|
||||||
|
let depotToolsEnv;
|
||||||
|
|
||||||
|
const findDepotToolsOnPath = () => {
|
||||||
|
const result = childProcess.spawnSync(
|
||||||
|
os.platform() === 'win32' ? 'where' : 'which',
|
||||||
|
['gclient']
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.status === 0) {
|
||||||
|
return process.env;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkForBuildTools = () => {
|
||||||
|
const result = childProcess.spawnSync(
|
||||||
|
'electron-build-tools',
|
||||||
|
['show', 'env', '--json'],
|
||||||
|
{ shell: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.status === 0) {
|
||||||
|
return {
|
||||||
|
...process.env,
|
||||||
|
...JSON.parse(result.stdout.toString().trim())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
depotToolsEnv = checkForBuildTools();
|
||||||
|
if (!depotToolsEnv) depotToolsEnv = findDepotToolsOnPath();
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
if (!depotToolsEnv) {
|
||||||
|
throw new Error("Couldn't find depot_tools, ensure it's on your PATH");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!('CHROMIUM_BUILDTOOLS_PATH' in depotToolsEnv)) {
|
||||||
|
throw new Error(
|
||||||
|
'CHROMIUM_BUILDTOOLS_PATH environment variable must be set'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return depotToolsEnv;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
chunkFilenames,
|
chunkFilenames,
|
||||||
compareVersions,
|
compareVersions,
|
||||||
findMatchingFiles,
|
findMatchingFiles,
|
||||||
getChromiumVersionFromDEPS,
|
getChromiumVersionFromDEPS,
|
||||||
getCurrentBranch,
|
getCurrentBranch,
|
||||||
|
getDepotToolsEnv,
|
||||||
getElectronExec,
|
getElectronExec,
|
||||||
getOutDir,
|
getOutDir,
|
||||||
getAbsoluteElectronExec,
|
getAbsoluteElectronExec,
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
SRC_DIR = Path(__file__).resolve().parents[3]
|
SRC_DIR = Path(__file__).resolve().parents[3]
|
||||||
sys.path.append(os.path.join(SRC_DIR, 'third_party/electron_node/tools'))
|
sys.path.append(os.path.join(SRC_DIR, 'third_party/electron_node/tools'))
|
||||||
sys.path.append(str(Path(__file__).resolve().parents[1])) # electron/script/
|
|
||||||
|
|
||||||
from lib.util import get_out_dir
|
|
||||||
import install
|
import install
|
||||||
|
|
||||||
class LoadPythonDictionaryError(Exception):
|
class LoadPythonDictionaryError(Exception):
|
||||||
@@ -33,6 +31,13 @@ def LoadPythonDictionary(path):
|
|||||||
)
|
)
|
||||||
return file_data
|
return file_data
|
||||||
|
|
||||||
|
def get_out_dir():
|
||||||
|
out_dir = 'Testing'
|
||||||
|
override = os.environ.get('ELECTRON_OUT_DIR')
|
||||||
|
if override is not None:
|
||||||
|
out_dir = override
|
||||||
|
return os.path.join(SRC_DIR, 'out', out_dir)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
node_root_dir = os.path.join(SRC_DIR, 'third_party/electron_node')
|
node_root_dir = os.path.join(SRC_DIR, 'third_party/electron_node')
|
||||||
out = {}
|
out = {}
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ import { streamArray as streamJsonStreamArray } from 'stream-json/streamers/Stre
|
|||||||
|
|
||||||
import * as childProcess from 'node:child_process';
|
import * as childProcess from 'node:child_process';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import * as os from 'node:os';
|
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
|
|
||||||
import { chunkFilenames, findMatchingFiles } from './lib/utils';
|
import { chunkFilenames, findMatchingFiles, getDepotToolsEnv } from './lib/utils';
|
||||||
|
|
||||||
const SOURCE_ROOT = path.normalize(path.dirname(__dirname));
|
const SOURCE_ROOT = path.normalize(path.dirname(__dirname));
|
||||||
const LLVM_BIN = path.resolve(
|
const LLVM_BIN = path.resolve(
|
||||||
@@ -20,7 +19,6 @@ const LLVM_BIN = path.resolve(
|
|||||||
'Release+Asserts',
|
'Release+Asserts',
|
||||||
'bin'
|
'bin'
|
||||||
);
|
);
|
||||||
const PLATFORM = os.platform();
|
|
||||||
|
|
||||||
type SpawnAsyncResult = {
|
type SpawnAsyncResult = {
|
||||||
stdout: string;
|
stdout: string;
|
||||||
@@ -63,53 +61,6 @@ async function spawnAsync (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDepotToolsEnv (): NodeJS.ProcessEnv {
|
|
||||||
let depotToolsEnv;
|
|
||||||
|
|
||||||
const findDepotToolsOnPath = () => {
|
|
||||||
const result = childProcess.spawnSync(
|
|
||||||
PLATFORM === 'win32' ? 'where' : 'which',
|
|
||||||
['gclient']
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.status === 0) {
|
|
||||||
return process.env;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkForBuildTools = () => {
|
|
||||||
const result = childProcess.spawnSync(
|
|
||||||
'electron-build-tools',
|
|
||||||
['show', 'env', '--json'],
|
|
||||||
{ shell: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.status === 0) {
|
|
||||||
return {
|
|
||||||
...process.env,
|
|
||||||
...JSON.parse(result.stdout.toString().trim())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
depotToolsEnv = findDepotToolsOnPath();
|
|
||||||
if (!depotToolsEnv) depotToolsEnv = checkForBuildTools();
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
if (!depotToolsEnv) {
|
|
||||||
throw new Error("Couldn't find depot_tools, ensure it's on your PATH");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!('CHROMIUM_BUILDTOOLS_PATH' in depotToolsEnv)) {
|
|
||||||
throw new Error(
|
|
||||||
'CHROMIUM_BUILDTOOLS_PATH environment variable must be set'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return depotToolsEnv;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function runClangTidy (
|
async function runClangTidy (
|
||||||
outDir: string,
|
outDir: string,
|
||||||
filenames: string[],
|
filenames: string[],
|
||||||
|
|||||||
@@ -2,23 +2,22 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from lib.util import get_depot_tools_executable
|
from lib.util import get_depot_tools_env
|
||||||
|
|
||||||
SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))
|
SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
# Helper to run gn format on multiple files
|
# Helper to run gn format on multiple files
|
||||||
# (gn only formats a single file at a time)
|
# (gn only formats a single file at a time)
|
||||||
def main():
|
def main():
|
||||||
new_env = os.environ.copy()
|
new_env = get_depot_tools_env()
|
||||||
new_env['DEPOT_TOOLS_WIN_TOOLCHAIN'] = '0'
|
new_env['DEPOT_TOOLS_WIN_TOOLCHAIN'] = '0'
|
||||||
new_env['CHROMIUM_BUILDTOOLS_PATH'] = os.path.realpath(
|
new_env['CHROMIUM_BUILDTOOLS_PATH'] = os.path.realpath(
|
||||||
os.path.join(SOURCE_ROOT, '..', 'buildtools')
|
os.path.join(SOURCE_ROOT, '..', 'buildtools')
|
||||||
)
|
)
|
||||||
|
|
||||||
gn_path = get_depot_tools_executable('gn')
|
|
||||||
for gn_file in sys.argv[1:]:
|
for gn_file in sys.argv[1:]:
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
[gn_path, 'format', gn_file],
|
['gn', 'format', gn_file],
|
||||||
env=new_env
|
env=new_env
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "base/no_destructor.h"
|
#include "base/no_destructor.h"
|
||||||
#include "content/common/url_schemes.h"
|
#include "content/common/url_schemes.h"
|
||||||
#include "content/public/browser/child_process_security_policy.h"
|
#include "content/public/browser/child_process_security_policy.h"
|
||||||
#include "gin/converter.h"
|
|
||||||
#include "gin/object_template_builder.h"
|
#include "gin/object_template_builder.h"
|
||||||
#include "shell/browser/browser.h"
|
#include "shell/browser/browser.h"
|
||||||
#include "shell/browser/javascript_environment.h"
|
#include "shell/browser/javascript_environment.h"
|
||||||
@@ -20,13 +19,13 @@
|
|||||||
#include "shell/common/gin_converters/callback_converter.h"
|
#include "shell/common/gin_converters/callback_converter.h"
|
||||||
#include "shell/common/gin_converters/net_converter.h"
|
#include "shell/common/gin_converters/net_converter.h"
|
||||||
#include "shell/common/gin_helper/dictionary.h"
|
#include "shell/common/gin_helper/dictionary.h"
|
||||||
|
#include "shell/common/gin_helper/handle.h"
|
||||||
#include "shell/common/gin_helper/object_template_builder.h"
|
#include "shell/common/gin_helper/object_template_builder.h"
|
||||||
#include "shell/common/gin_helper/promise.h"
|
#include "shell/common/gin_helper/promise.h"
|
||||||
#include "shell/common/node_includes.h"
|
#include "shell/common/node_includes.h"
|
||||||
#include "shell/common/node_util.h"
|
#include "shell/common/node_util.h"
|
||||||
#include "shell/common/options_switches.h"
|
#include "shell/common/options_switches.h"
|
||||||
#include "url/url_util.h"
|
#include "url/url_util.h"
|
||||||
#include "v8/include/cppgc/allocation.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -82,8 +81,7 @@ struct Converter<CustomScheme> {
|
|||||||
|
|
||||||
namespace electron::api {
|
namespace electron::api {
|
||||||
|
|
||||||
const gin::WrapperInfo Protocol::kWrapperInfo = {{gin::kEmbedderNativeGin},
|
gin::DeprecatedWrapperInfo Protocol::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||||
gin::kElectronProtocol};
|
|
||||||
|
|
||||||
std::vector<std::string>& GetStandardSchemes() {
|
std::vector<std::string>& GetStandardSchemes() {
|
||||||
static base::NoDestructor<std::vector<std::string>> g_standard_schemes;
|
static base::NoDestructor<std::vector<std::string>> g_standard_schemes;
|
||||||
@@ -298,22 +296,23 @@ void Protocol::HandleOptionalCallback(gin::Arguments* args, Error error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Protocol* Protocol::Create(v8::Isolate* isolate,
|
gin_helper::Handle<Protocol> Protocol::Create(
|
||||||
ProtocolRegistry* protocol_registry) {
|
v8::Isolate* isolate,
|
||||||
return cppgc::MakeGarbageCollected<Protocol>(
|
ProtocolRegistry* protocol_registry) {
|
||||||
isolate->GetCppHeap()->GetAllocationHandle(), protocol_registry);
|
return gin_helper::CreateHandle(isolate, new Protocol{protocol_registry});
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Protocol* Protocol::New(gin_helper::ErrorThrower thrower) {
|
gin_helper::Handle<Protocol> Protocol::New(gin_helper::ErrorThrower thrower) {
|
||||||
thrower.ThrowError("Protocol cannot be created from JS");
|
thrower.ThrowError("Protocol cannot be created from JS");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Protocol::FillObjectTemplate(v8::Isolate* isolate,
|
v8::Local<v8::ObjectTemplate> Protocol::FillObjectTemplate(
|
||||||
v8::Local<v8::ObjectTemplate> tmpl) {
|
v8::Isolate* isolate,
|
||||||
gin::ObjectTemplateBuilder(isolate, GetClassName(), tmpl)
|
v8::Local<v8::ObjectTemplate> tmpl) {
|
||||||
|
return gin::ObjectTemplateBuilder(isolate, GetClassName(), tmpl)
|
||||||
.SetMethod("registerStringProtocol",
|
.SetMethod("registerStringProtocol",
|
||||||
&Protocol::RegisterProtocolFor<ProtocolType::kString>)
|
&Protocol::RegisterProtocolFor<ProtocolType::kString>)
|
||||||
.SetMethod("registerBufferProtocol",
|
.SetMethod("registerBufferProtocol",
|
||||||
@@ -346,12 +345,8 @@ void Protocol::FillObjectTemplate(v8::Isolate* isolate,
|
|||||||
.Build();
|
.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
const gin::WrapperInfo* Protocol::wrapper_info() const {
|
const char* Protocol::GetTypeName() {
|
||||||
return &kWrapperInfo;
|
return GetClassName();
|
||||||
}
|
|
||||||
|
|
||||||
const char* Protocol::GetHumanReadableName() const {
|
|
||||||
return "Electron / Protocol";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace electron::api
|
} // namespace electron::api
|
||||||
@@ -377,8 +372,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||||||
v8::Isolate* const isolate = electron::JavascriptEnvironment::GetIsolate();
|
v8::Isolate* const isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||||
gin_helper::Dictionary dict{isolate, exports};
|
gin_helper::Dictionary dict{isolate, exports};
|
||||||
dict.Set("Protocol",
|
dict.Set("Protocol",
|
||||||
electron::api::Protocol::GetConstructor(
|
electron::api::Protocol::GetConstructor(isolate, context));
|
||||||
isolate, context, &electron::api::Protocol::kWrapperInfo));
|
|
||||||
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
|
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
|
||||||
dict.SetMethod("getStandardSchemes", &electron::api::GetStandardSchemes);
|
dict.SetMethod("getStandardSchemes", &electron::api::GetStandardSchemes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,20 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/memory/raw_ptr.h"
|
#include "base/memory/raw_ptr.h"
|
||||||
#include "gin/wrappable.h"
|
#include "content/public/browser/content_browser_client.h"
|
||||||
#include "shell/browser/net/electron_url_loader_factory.h"
|
#include "shell/browser/net/electron_url_loader_factory.h"
|
||||||
#include "shell/common/gin_helper/constructible.h"
|
#include "shell/common/gin_helper/constructible.h"
|
||||||
|
#include "shell/common/gin_helper/wrappable.h"
|
||||||
|
|
||||||
namespace gin {
|
namespace gin {
|
||||||
class Arguments;
|
class Arguments;
|
||||||
} // namespace gin
|
} // namespace gin
|
||||||
|
|
||||||
|
namespace gin_helper {
|
||||||
|
template <typename T>
|
||||||
|
class Handle;
|
||||||
|
} // namespace gin_helper
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
class ProtocolRegistry;
|
class ProtocolRegistry;
|
||||||
@@ -32,25 +38,23 @@ void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower,
|
|||||||
v8::Local<v8::Value> val);
|
v8::Local<v8::Value> val);
|
||||||
|
|
||||||
// Protocol implementation based on network services.
|
// Protocol implementation based on network services.
|
||||||
class Protocol final : public gin::Wrappable<Protocol>,
|
class Protocol final : public gin_helper::DeprecatedWrappable<Protocol>,
|
||||||
public gin_helper::Constructible<Protocol> {
|
public gin_helper::Constructible<Protocol> {
|
||||||
public:
|
public:
|
||||||
static Protocol* Create(v8::Isolate* isolate,
|
static gin_helper::Handle<Protocol> Create(
|
||||||
ProtocolRegistry* protocol_registry);
|
v8::Isolate* isolate,
|
||||||
|
ProtocolRegistry* protocol_registry);
|
||||||
|
|
||||||
// gin_helper::Constructible
|
// gin_helper::Constructible
|
||||||
static Protocol* New(gin_helper::ErrorThrower thrower);
|
static gin_helper::Handle<Protocol> New(gin_helper::ErrorThrower thrower);
|
||||||
static void FillObjectTemplate(v8::Isolate* isolate,
|
static v8::Local<v8::ObjectTemplate> FillObjectTemplate(
|
||||||
v8::Local<v8::ObjectTemplate> tmpl);
|
v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> tmpl);
|
||||||
static const char* GetClassName() { return "Protocol"; }
|
static const char* GetClassName() { return "Protocol"; }
|
||||||
|
|
||||||
// gin::Wrappable
|
// gin_helper::Wrappable
|
||||||
static const gin::WrapperInfo kWrapperInfo;
|
static gin::DeprecatedWrapperInfo kWrapperInfo;
|
||||||
const gin::WrapperInfo* wrapper_info() const override;
|
const char* GetTypeName() override;
|
||||||
const char* GetHumanReadableName() const override;
|
|
||||||
|
|
||||||
explicit Protocol(ProtocolRegistry* protocol_registry);
|
|
||||||
~Protocol() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Possible errors.
|
// Possible errors.
|
||||||
@@ -66,6 +70,9 @@ class Protocol final : public gin::Wrappable<Protocol>,
|
|||||||
using CompletionCallback =
|
using CompletionCallback =
|
||||||
base::RepeatingCallback<void(v8::Local<v8::Value>)>;
|
base::RepeatingCallback<void(v8::Local<v8::Value>)>;
|
||||||
|
|
||||||
|
explicit Protocol(ProtocolRegistry* protocol_registry);
|
||||||
|
~Protocol() override;
|
||||||
|
|
||||||
[[nodiscard]] static std::string_view ErrorCodeToString(Error error);
|
[[nodiscard]] static std::string_view ErrorCodeToString(Error error);
|
||||||
|
|
||||||
// JS APIs.
|
// JS APIs.
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "base/files/file_enumerator.h"
|
#include "base/files/file_enumerator.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
#include "base/memory/weak_ptr.h"
|
|
||||||
#include "base/scoped_observation.h"
|
#include "base/scoped_observation.h"
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
#include "base/types/pass_key.h"
|
#include "base/types/pass_key.h"
|
||||||
@@ -77,7 +76,6 @@
|
|||||||
#include "shell/browser/media/media_device_id_salt.h"
|
#include "shell/browser/media/media_device_id_salt.h"
|
||||||
#include "shell/browser/net/cert_verifier_client.h"
|
#include "shell/browser/net/cert_verifier_client.h"
|
||||||
#include "shell/browser/net/resolve_host_function.h"
|
#include "shell/browser/net/resolve_host_function.h"
|
||||||
#include "shell/browser/net/resolve_proxy_helper.h"
|
|
||||||
#include "shell/browser/session_preferences.h"
|
#include "shell/browser/session_preferences.h"
|
||||||
#include "shell/common/gin_converters/callback_converter.h"
|
#include "shell/common/gin_converters/callback_converter.h"
|
||||||
#include "shell/common/gin_converters/content_converter.h"
|
#include "shell/common/gin_converters/content_converter.h"
|
||||||
@@ -560,7 +558,9 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
|
|||||||
|
|
||||||
SessionPreferences::CreateForBrowserContext(browser_context);
|
SessionPreferences::CreateForBrowserContext(browser_context);
|
||||||
|
|
||||||
protocol_ = Protocol::Create(isolate, browser_context->protocol_registry());
|
protocol_.Reset(
|
||||||
|
isolate,
|
||||||
|
Protocol::Create(isolate, browser_context->protocol_registry()).ToV8());
|
||||||
|
|
||||||
browser_context->SetUserData(
|
browser_context->SetUserData(
|
||||||
kElectronApiSessionKey,
|
kElectronApiSessionKey,
|
||||||
@@ -1354,8 +1354,8 @@ v8::Local<v8::Value> Session::Extensions(v8::Isolate* isolate) {
|
|||||||
return extensions_.Get(isolate);
|
return extensions_.Get(isolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
api::Protocol* Session::Protocol() {
|
v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
|
||||||
return protocol_.Get();
|
return protocol_.Get(isolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
|
v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/memory/raw_ptr.h"
|
#include "base/memory/raw_ptr.h"
|
||||||
|
#include "base/memory/weak_ptr.h"
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "content/public/browser/download_manager.h"
|
#include "content/public/browser/download_manager.h"
|
||||||
#include "electron/buildflags/buildflags.h"
|
#include "electron/buildflags/buildflags.h"
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
#include "services/network/public/mojom/ssl_config.mojom-forward.h"
|
#include "services/network/public/mojom/ssl_config.mojom-forward.h"
|
||||||
#include "shell/browser/api/ipc_dispatcher.h"
|
#include "shell/browser/api/ipc_dispatcher.h"
|
||||||
#include "shell/browser/event_emitter_mixin.h"
|
#include "shell/browser/event_emitter_mixin.h"
|
||||||
|
#include "shell/browser/net/resolve_proxy_helper.h"
|
||||||
#include "shell/common/gin_helper/constructible.h"
|
#include "shell/common/gin_helper/constructible.h"
|
||||||
#include "shell/common/gin_helper/self_keep_alive.h"
|
#include "shell/common/gin_helper/self_keep_alive.h"
|
||||||
|
|
||||||
@@ -58,7 +60,6 @@ struct PreloadScript;
|
|||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
class NetLog;
|
class NetLog;
|
||||||
class Protocol;
|
|
||||||
class WebRequest;
|
class WebRequest;
|
||||||
|
|
||||||
class Session final : public gin::Wrappable<Session>,
|
class Session final : public gin::Wrappable<Session>,
|
||||||
@@ -166,7 +167,7 @@ class Session final : public gin::Wrappable<Session>,
|
|||||||
const gin_helper::Dictionary& options);
|
const gin_helper::Dictionary& options);
|
||||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||||
v8::Local<v8::Value> Extensions(v8::Isolate* isolate);
|
v8::Local<v8::Value> Extensions(v8::Isolate* isolate);
|
||||||
api::Protocol* Protocol();
|
v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
|
||||||
v8::Local<v8::Value> ServiceWorkerContext(v8::Isolate* isolate);
|
v8::Local<v8::Value> ServiceWorkerContext(v8::Isolate* isolate);
|
||||||
WebRequest* WebRequest(v8::Isolate* isolate);
|
WebRequest* WebRequest(v8::Isolate* isolate);
|
||||||
api::NetLog* NetLog(v8::Isolate* isolate);
|
api::NetLog* NetLog(v8::Isolate* isolate);
|
||||||
@@ -213,7 +214,7 @@ class Session final : public gin::Wrappable<Session>,
|
|||||||
// Cached gin_helper::Wrappable objects.
|
// Cached gin_helper::Wrappable objects.
|
||||||
v8::TracedReference<v8::Value> cookies_;
|
v8::TracedReference<v8::Value> cookies_;
|
||||||
v8::TracedReference<v8::Value> extensions_;
|
v8::TracedReference<v8::Value> extensions_;
|
||||||
cppgc::Member<api::Protocol> protocol_;
|
v8::TracedReference<v8::Value> protocol_;
|
||||||
cppgc::Member<api::NetLog> net_log_;
|
cppgc::Member<api::NetLog> net_log_;
|
||||||
v8::TracedReference<v8::Value> service_worker_context_;
|
v8::TracedReference<v8::Value> service_worker_context_;
|
||||||
cppgc::Member<api::WebRequest> web_request_;
|
cppgc::Member<api::WebRequest> web_request_;
|
||||||
|
|||||||
@@ -972,12 +972,11 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||||||
|
|
||||||
void WebContents::InitZoomController(content::WebContents* web_contents,
|
void WebContents::InitZoomController(content::WebContents* web_contents,
|
||||||
const gin_helper::Dictionary& options) {
|
const gin_helper::Dictionary& options) {
|
||||||
WebContentsZoomController* const zoom_controller =
|
WebContentsZoomController::CreateForWebContents(web_contents);
|
||||||
WebContentsZoomController::GetOrCreateForWebContents(web_contents);
|
zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents);
|
||||||
|
|
||||||
double zoom_factor;
|
double zoom_factor;
|
||||||
if (options.Get(options::kZoomFactor, &zoom_factor))
|
if (options.Get(options::kZoomFactor, &zoom_factor))
|
||||||
zoom_controller->SetDefaultZoomFactor(zoom_factor);
|
zoom_controller_->SetDefaultZoomFactor(zoom_factor);
|
||||||
|
|
||||||
// Nothing to do with ZoomController, but this function gets called in all
|
// Nothing to do with ZoomController, but this function gets called in all
|
||||||
// init cases!
|
// init cases!
|
||||||
@@ -2890,8 +2889,8 @@ v8::Local<v8::Promise> WebContents::SavePage(
|
|||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* handler = new SavePageHandler{std::move(promise)};
|
auto* handler = new SavePageHandler(web_contents(), std::move(promise));
|
||||||
handler->Handle(full_file_path, save_type, web_contents());
|
handler->Handle(full_file_path, save_type);
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
@@ -3153,18 +3152,16 @@ void OnGetDeviceNameToUse(base::WeakPtr<content::WebContents> web_contents,
|
|||||||
.Set(printing::kSettingMediaSizeIsDefault, true);
|
.Set(printing::kSettingMediaSizeIsDefault, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!print_settings.Find(printing::kSettingMediaSize)) {
|
const bool use_default_size =
|
||||||
const bool use_default_size =
|
print_settings.FindBool(kUseDefaultPrinterPageSize).value_or(false);
|
||||||
print_settings.FindBool(kUseDefaultPrinterPageSize).value_or(false);
|
std::optional<gfx::Size> paper_size;
|
||||||
std::optional<gfx::Size> paper_size;
|
if (use_default_size)
|
||||||
if (use_default_size)
|
paper_size = GetPrinterDefaultPaperSize(base::UTF16ToUTF8(info.second));
|
||||||
paper_size = GetPrinterDefaultPaperSize(base::UTF16ToUTF8(info.second));
|
|
||||||
|
|
||||||
print_settings.Set(
|
print_settings.Set(
|
||||||
printing::kSettingMediaSize,
|
printing::kSettingMediaSize,
|
||||||
paper_size ? make_media_size(paper_size->height(), paper_size->width())
|
paper_size ? make_media_size(paper_size->height(), paper_size->width())
|
||||||
: make_media_size(297000, 210000));
|
: make_media_size(297000, 210000));
|
||||||
}
|
|
||||||
|
|
||||||
content::RenderFrameHost* rfh = GetRenderFrameHostToUse(web_contents.get());
|
content::RenderFrameHost* rfh = GetRenderFrameHostToUse(web_contents.get());
|
||||||
if (!rfh)
|
if (!rfh)
|
||||||
@@ -3870,16 +3867,12 @@ gfx::Size WebContents::GetSizeForNewRenderView(content::WebContents* wc) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
WebContentsZoomController* WebContents::GetZoomController() const {
|
|
||||||
return WebContentsZoomController::FromWebContents(web_contents());
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebContents::SetZoomLevel(double level) {
|
void WebContents::SetZoomLevel(double level) {
|
||||||
GetZoomController()->SetZoomLevel(level);
|
zoom_controller_->SetZoomLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
double WebContents::GetZoomLevel() const {
|
double WebContents::GetZoomLevel() const {
|
||||||
return GetZoomController()->GetZoomLevel();
|
return zoom_controller_->GetZoomLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::SetZoomFactor(gin_helper::ErrorThrower thrower,
|
void WebContents::SetZoomFactor(gin_helper::ErrorThrower thrower,
|
||||||
@@ -3899,7 +3892,7 @@ double WebContents::GetZoomFactor() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::SetTemporaryZoomLevel(double level) {
|
void WebContents::SetTemporaryZoomLevel(double level) {
|
||||||
GetZoomController()->SetTemporaryZoomLevel(level);
|
zoom_controller_->SetTemporaryZoomLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<PreloadScript> WebContents::GetPreloadScript() const {
|
std::optional<PreloadScript> WebContents::GetPreloadScript() const {
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ class WebContents final : public ExclusiveAccessContext,
|
|||||||
content::RenderFrameHost* Opener();
|
content::RenderFrameHost* Opener();
|
||||||
content::RenderFrameHost* FocusedFrame();
|
content::RenderFrameHost* FocusedFrame();
|
||||||
|
|
||||||
[[nodiscard]] WebContentsZoomController* GetZoomController() const;
|
WebContentsZoomController* GetZoomController() { return zoom_controller_; }
|
||||||
|
|
||||||
void AddObserver(ExtendedWebContentsObserver* obs) {
|
void AddObserver(ExtendedWebContentsObserver* obs) {
|
||||||
observers_.AddObserver(obs);
|
observers_.AddObserver(obs);
|
||||||
@@ -858,6 +858,11 @@ class WebContents final : public ExclusiveAccessContext,
|
|||||||
// destroyed before dialog_manager_, otherwise a crash would happen.
|
// destroyed before dialog_manager_, otherwise a crash would happen.
|
||||||
std::unique_ptr<InspectableWebContents> inspectable_web_contents_;
|
std::unique_ptr<InspectableWebContents> inspectable_web_contents_;
|
||||||
|
|
||||||
|
// The zoom controller for this webContents.
|
||||||
|
// Note: owned by inspectable_web_contents_, so declare this *after*
|
||||||
|
// that field to ensure the dtor destroys them in the right order.
|
||||||
|
raw_ptr<WebContentsZoomController> zoom_controller_ = nullptr;
|
||||||
|
|
||||||
std::optional<GURL> pending_unload_url_ = std::nullopt;
|
std::optional<GURL> pending_unload_url_ = std::nullopt;
|
||||||
|
|
||||||
// Maps url to file path, used by the file requests sent from devtools.
|
// Maps url to file path, used by the file requests sent from devtools.
|
||||||
|
|||||||
@@ -12,8 +12,9 @@
|
|||||||
|
|
||||||
namespace electron::api {
|
namespace electron::api {
|
||||||
|
|
||||||
SavePageHandler::SavePageHandler(gin_helper::Promise<void> promise)
|
SavePageHandler::SavePageHandler(content::WebContents* web_contents,
|
||||||
: promise_{std::move(promise)} {}
|
gin_helper::Promise<void> promise)
|
||||||
|
: web_contents_(web_contents), promise_(std::move(promise)) {}
|
||||||
|
|
||||||
SavePageHandler::~SavePageHandler() = default;
|
SavePageHandler::~SavePageHandler() = default;
|
||||||
|
|
||||||
@@ -25,10 +26,9 @@ void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SavePageHandler::Handle(const base::FilePath& full_path,
|
bool SavePageHandler::Handle(const base::FilePath& full_path,
|
||||||
const content::SavePageType& save_type,
|
const content::SavePageType& save_type) {
|
||||||
content::WebContents* web_contents) {
|
|
||||||
auto* download_manager =
|
auto* download_manager =
|
||||||
web_contents->GetBrowserContext()->GetDownloadManager();
|
web_contents_->GetBrowserContext()->GetDownloadManager();
|
||||||
download_manager->AddObserver(this);
|
download_manager->AddObserver(this);
|
||||||
// Chromium will create a 'foo_files' directory under the directory of saving
|
// Chromium will create a 'foo_files' directory under the directory of saving
|
||||||
// page 'foo.html' for holding other resource files of 'foo.html'.
|
// page 'foo.html' for holding other resource files of 'foo.html'.
|
||||||
@@ -36,7 +36,7 @@ bool SavePageHandler::Handle(const base::FilePath& full_path,
|
|||||||
full_path.RemoveExtension().BaseName().value() +
|
full_path.RemoveExtension().BaseName().value() +
|
||||||
FILE_PATH_LITERAL("_files"));
|
FILE_PATH_LITERAL("_files"));
|
||||||
bool result =
|
bool result =
|
||||||
web_contents->SavePage(full_path, saved_main_directory_path, save_type);
|
web_contents_->SavePage(full_path, saved_main_directory_path, save_type);
|
||||||
download_manager->RemoveObserver(this);
|
download_manager->RemoveObserver(this);
|
||||||
// If initialization fails which means fail to create |DownloadItem|, we need
|
// If initialization fails which means fail to create |DownloadItem|, we need
|
||||||
// to delete the |SavePageHandler| instance to avoid memory-leak.
|
// to delete the |SavePageHandler| instance to avoid memory-leak.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#ifndef ELECTRON_SHELL_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
#ifndef ELECTRON_SHELL_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||||
#define ELECTRON_SHELL_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
#define ELECTRON_SHELL_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||||
|
|
||||||
|
#include "base/memory/raw_ptr.h"
|
||||||
#include "components/download/public/common/download_item.h"
|
#include "components/download/public/common/download_item.h"
|
||||||
#include "content/public/browser/download_manager.h"
|
#include "content/public/browser/download_manager.h"
|
||||||
#include "content/public/browser/save_page_type.h"
|
#include "content/public/browser/save_page_type.h"
|
||||||
@@ -25,12 +26,12 @@ namespace electron::api {
|
|||||||
class SavePageHandler : private content::DownloadManager::Observer,
|
class SavePageHandler : private content::DownloadManager::Observer,
|
||||||
private download::DownloadItem::Observer {
|
private download::DownloadItem::Observer {
|
||||||
public:
|
public:
|
||||||
explicit SavePageHandler(gin_helper::Promise<void> promise);
|
SavePageHandler(content::WebContents* web_contents,
|
||||||
|
gin_helper::Promise<void> promise);
|
||||||
~SavePageHandler() override;
|
~SavePageHandler() override;
|
||||||
|
|
||||||
bool Handle(const base::FilePath& full_path,
|
bool Handle(const base::FilePath& full_path,
|
||||||
const content::SavePageType& save_type,
|
const content::SavePageType& save_type);
|
||||||
content::WebContents* web_contents);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Destroy(download::DownloadItem* item);
|
void Destroy(download::DownloadItem* item);
|
||||||
@@ -42,6 +43,7 @@ class SavePageHandler : private content::DownloadManager::Observer,
|
|||||||
// download::DownloadItem::Observer:
|
// download::DownloadItem::Observer:
|
||||||
void OnDownloadUpdated(download::DownloadItem* item) override;
|
void OnDownloadUpdated(download::DownloadItem* item) override;
|
||||||
|
|
||||||
|
raw_ptr<content::WebContents> web_contents_; // weak
|
||||||
gin_helper::Promise<void> promise_;
|
gin_helper::Promise<void> promise_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,6 @@
|
|||||||
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
|
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
|
||||||
#include "net/ssl/ssl_cert_request_info.h"
|
#include "net/ssl/ssl_cert_request_info.h"
|
||||||
#include "net/ssl/ssl_private_key.h"
|
#include "net/ssl/ssl_private_key.h"
|
||||||
#include "pdf/pdf_features.h"
|
|
||||||
#include "printing/buildflags/buildflags.h"
|
#include "printing/buildflags/buildflags.h"
|
||||||
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
|
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
|
||||||
#include "services/device/public/cpp/geolocation/location_provider.h"
|
#include "services/device/public/cpp/geolocation/location_provider.h"
|
||||||
@@ -1592,46 +1591,6 @@ bool ElectronBrowserClient::ShouldEnableStrictSiteIsolation() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElectronBrowserClient::ShouldEnableSubframeZoom() {
|
|
||||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
||||||
return chrome_pdf::features::IsOopifPdfEnabled();
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
||||||
std::optional<network::CrossOriginEmbedderPolicy>
|
|
||||||
ElectronBrowserClient::MaybeOverrideLocalURLCrossOriginEmbedderPolicy(
|
|
||||||
content::NavigationHandle* navigation_handle) {
|
|
||||||
if (!chrome_pdf::features::IsOopifPdfEnabled() ||
|
|
||||||
!navigation_handle->IsPdf()) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
content::RenderFrameHost* pdf_extension = navigation_handle->GetParentFrame();
|
|
||||||
if (!pdf_extension) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
content::RenderFrameHost* pdf_embedder = pdf_extension->GetParent();
|
|
||||||
CHECK(pdf_embedder);
|
|
||||||
return pdf_embedder->GetCrossOriginEmbedderPolicy();
|
|
||||||
}
|
|
||||||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
||||||
|
|
||||||
bool ElectronBrowserClient::DoesSiteRequireDedicatedProcess(
|
|
||||||
content::BrowserContext* browser_context,
|
|
||||||
const GURL& effective_site_url) {
|
|
||||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
||||||
return GetEnabledExtensionFromEffectiveURL(browser_context,
|
|
||||||
effective_site_url) != nullptr;
|
|
||||||
#else
|
|
||||||
return content::ContentBrowserClient::DoesSiteRequireDedicatedProcess(
|
|
||||||
browser_context, effective_site_url);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ElectronBrowserClient::BindHostReceiverForRenderer(
|
void ElectronBrowserClient::BindHostReceiverForRenderer(
|
||||||
content::RenderProcessHost* render_process_host,
|
content::RenderProcessHost* render_process_host,
|
||||||
mojo::GenericPendingReceiver receiver) {
|
mojo::GenericPendingReceiver receiver) {
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ class FilePath;
|
|||||||
|
|
||||||
namespace content {
|
namespace content {
|
||||||
class ClientCertificateDelegate;
|
class ClientCertificateDelegate;
|
||||||
class NavigationHandle;
|
|
||||||
class PlatformNotificationService;
|
class PlatformNotificationService;
|
||||||
class NavigationThrottleRegistry;
|
class NavigationThrottleRegistry;
|
||||||
class QuotaPermissionContext;
|
class QuotaPermissionContext;
|
||||||
@@ -83,14 +82,6 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
|
|||||||
// content::ContentBrowserClient:
|
// content::ContentBrowserClient:
|
||||||
std::string GetApplicationLocale() override;
|
std::string GetApplicationLocale() override;
|
||||||
bool ShouldEnableStrictSiteIsolation() override;
|
bool ShouldEnableStrictSiteIsolation() override;
|
||||||
bool ShouldEnableSubframeZoom() override;
|
|
||||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
||||||
std::optional<network::CrossOriginEmbedderPolicy>
|
|
||||||
MaybeOverrideLocalURLCrossOriginEmbedderPolicy(
|
|
||||||
content::NavigationHandle* navigation_handle) override;
|
|
||||||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
||||||
bool DoesSiteRequireDedicatedProcess(content::BrowserContext* browser_context,
|
|
||||||
const GURL& effective_site_url) override;
|
|
||||||
void BindHostReceiverForRenderer(
|
void BindHostReceiverForRenderer(
|
||||||
content::RenderProcessHost* render_process_host,
|
content::RenderProcessHost* render_process_host,
|
||||||
mojo::GenericPendingReceiver receiver) override;
|
mojo::GenericPendingReceiver receiver) override;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
|
|||||||
std::move(transferrable_loader), original_url);
|
std::move(transferrable_loader), original_url);
|
||||||
|
|
||||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||||
if (chrome_pdf::features::IsOopifPdfEnabled() &&
|
if (base::FeatureList::IsEnabled(chrome_pdf::features::kPdfOopif) &&
|
||||||
extension_id == extension_misc::kPdfExtensionId) {
|
extension_id == extension_misc::kPdfExtensionId) {
|
||||||
pdf::PdfViewerStreamManager::Create(web_contents);
|
pdf::PdfViewerStreamManager::Create(web_contents);
|
||||||
pdf::PdfViewerStreamManager::FromWebContents(web_contents)
|
pdf::PdfViewerStreamManager::FromWebContents(web_contents)
|
||||||
|
|||||||
@@ -398,7 +398,9 @@ ExtensionFunction::ResponseAction TabsGetZoomFunction::Run() {
|
|||||||
if (!contents)
|
if (!contents)
|
||||||
return RespondNow(Error("No such tab"));
|
return RespondNow(Error("No such tab"));
|
||||||
|
|
||||||
const double zoom_factor = contents->GetZoomFactor();
|
double zoom_level = contents->GetZoomController()->GetZoomLevel();
|
||||||
|
double zoom_factor = blink::ZoomLevelToZoomFactor(zoom_level);
|
||||||
|
|
||||||
return RespondNow(ArgumentList(tabs::GetZoom::Results::Create(zoom_factor)));
|
return RespondNow(ArgumentList(tabs::GetZoom::Results::Create(zoom_factor)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,9 +414,9 @@ ExtensionFunction::ResponseAction TabsGetZoomSettingsFunction::Run() {
|
|||||||
if (!contents)
|
if (!contents)
|
||||||
return RespondNow(Error("No such tab"));
|
return RespondNow(Error("No such tab"));
|
||||||
|
|
||||||
const auto* zoom_controller = contents->GetZoomController();
|
auto* zoom_controller = contents->GetZoomController();
|
||||||
const WebContentsZoomController::ZoomMode zoom_mode =
|
WebContentsZoomController::ZoomMode zoom_mode =
|
||||||
zoom_controller->zoom_mode();
|
contents->GetZoomController()->zoom_mode();
|
||||||
tabs::ZoomSettings zoom_settings;
|
tabs::ZoomSettings zoom_settings;
|
||||||
ZoomModeToZoomSettings(zoom_mode, &zoom_settings);
|
ZoomModeToZoomSettings(zoom_mode, &zoom_settings);
|
||||||
zoom_settings.default_zoom_factor =
|
zoom_settings.default_zoom_factor =
|
||||||
|
|||||||
@@ -34,6 +34,10 @@
|
|||||||
#include "printing/printing_features.h"
|
#include "printing/printing_features.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
#include "ui/views/views_features.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
void InitializeFeatureList() {
|
void InitializeFeatureList() {
|
||||||
@@ -67,6 +71,13 @@ void InitializeFeatureList() {
|
|||||||
blink::features::kDropInputEventsWhilePaintHolding.name;
|
blink::features::kDropInputEventsWhilePaintHolding.name;
|
||||||
|
|
||||||
#if BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
// Refs https://issues.chromium.org/issues/401996981
|
||||||
|
// TODO(deepak1556): Remove this once test added in
|
||||||
|
// https://github.com/electron/electron/pull/12904
|
||||||
|
// can work without this feature.
|
||||||
|
enable_features += std::string(",") +
|
||||||
|
views::features::kEnableTransparentHwndEnlargement.name;
|
||||||
|
|
||||||
// See https://chromium-review.googlesource.com/c/chromium/src/+/7204292
|
// See https://chromium-review.googlesource.com/c/chromium/src/+/7204292
|
||||||
// This feature causes the following sandbox failure on Windows:
|
// This feature causes the following sandbox failure on Windows:
|
||||||
// sandbox\policy\win\sandbox_win.cc:777 Sandbox cannot access executable
|
// sandbox\policy\win\sandbox_win.cc:777 Sandbox cannot access executable
|
||||||
|
|||||||
@@ -31,6 +31,11 @@
|
|||||||
#include "shell/browser/ui/views/frameless_view.h"
|
#include "shell/browser/ui/views/frameless_view.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
#include "ui/display/win/screen_win.h"
|
||||||
|
#include "ui/views/views_features.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USE_OZONE)
|
#if defined(USE_OZONE)
|
||||||
#include "ui/base/ui_base_features.h"
|
#include "ui/base/ui_base_features.h"
|
||||||
#include "ui/ozone/public/ozone_platform.h"
|
#include "ui/ozone/public/ozone_platform.h"
|
||||||
@@ -66,6 +71,31 @@ struct Converter<electron::NativeWindow::TitleBarStyle> {
|
|||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
gfx::Size GetExpandedWindowSize(const NativeWindow* window,
|
||||||
|
bool transparent,
|
||||||
|
gfx::Size size) {
|
||||||
|
if (!base::FeatureList::IsEnabled(
|
||||||
|
views::features::kEnableTransparentHwndEnlargement) ||
|
||||||
|
!transparent) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Size min_size = display::win::GetScreenWin()->ScreenToDIPSize(
|
||||||
|
window->GetAcceleratedWidget(), gfx::Size{64, 64});
|
||||||
|
|
||||||
|
// Some AMD drivers can't display windows that are less than 64x64 pixels,
|
||||||
|
// so expand them to be at least that size. http://crbug.com/286609
|
||||||
|
gfx::Size expanded(std::max(size.width(), min_size.width()),
|
||||||
|
std::max(size.height(), min_size.height()));
|
||||||
|
return expanded;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
NativeWindow::NativeWindow(const int32_t base_window_id,
|
NativeWindow::NativeWindow(const int32_t base_window_id,
|
||||||
const gin_helper::Dictionary& options,
|
const gin_helper::Dictionary& options,
|
||||||
NativeWindow* parent)
|
NativeWindow* parent)
|
||||||
@@ -368,7 +398,15 @@ gfx::Size NativeWindow::GetContentMinimumSize() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfx::Size NativeWindow::GetContentMaximumSize() const {
|
gfx::Size NativeWindow::GetContentMaximumSize() const {
|
||||||
return GetContentSizeConstraints().GetMaximumSize();
|
const auto size_constraints = GetContentSizeConstraints();
|
||||||
|
gfx::Size maximum_size = size_constraints.GetMaximumSize();
|
||||||
|
|
||||||
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
if (size_constraints.HasMaximumSize())
|
||||||
|
maximum_size = GetExpandedWindowSize(this, transparent(), maximum_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return maximum_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindow::SetSheetOffset(const double offsetX, const double offsetY) {
|
void NativeWindow::SetSheetOffset(const double offsetX, const double offsetY) {
|
||||||
|
|||||||
@@ -440,11 +440,13 @@ NativeWindowViews::NativeWindowViews(const int32_t base_window_id,
|
|||||||
if (window)
|
if (window)
|
||||||
window->AddPreTargetHandler(this);
|
window->AddPreTargetHandler(this);
|
||||||
|
|
||||||
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_LINUX)
|
||||||
// The initial params.bounds was applied before the frame view existed, so
|
// We need to set bounds again after widget init for two reasons:
|
||||||
// non-client insets weren't accounted for and bounds need to be set again.
|
// 1. For CSD windows, user-specified bounds need to be inflated by frame
|
||||||
if (!GetRestoredFrameBorderInsets().IsEmpty())
|
// insets, but the frame view isn't available at first.
|
||||||
SetBounds(gfx::Rect(GetPosition(), size), false);
|
// 2. The widget clamps bounds to fit the screen, but we want to allow
|
||||||
|
// windows larger than the display.
|
||||||
|
SetBounds(gfx::Rect(GetPosition(), size), false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,9 +906,7 @@ gfx::Rect NativeWindowViews::GetNormalBounds() const {
|
|||||||
if (IsMaximized() && transparent())
|
if (IsMaximized() && transparent())
|
||||||
return restore_bounds_;
|
return restore_bounds_;
|
||||||
#endif
|
#endif
|
||||||
gfx::Rect bounds = widget()->GetRestoredBounds();
|
return WidgetToLogicalBounds(widget()->GetRestoredBounds());
|
||||||
bounds.Inset(GetRestoredFrameBorderInsets());
|
|
||||||
return bounds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowViews::SetContentSizeConstraints(
|
void NativeWindowViews::SetContentSizeConstraints(
|
||||||
@@ -1676,24 +1676,17 @@ NativeWindowHandle NativeWindowViews::GetNativeWindowHandle() const {
|
|||||||
|
|
||||||
gfx::Rect NativeWindowViews::LogicalToWidgetBounds(
|
gfx::Rect NativeWindowViews::LogicalToWidgetBounds(
|
||||||
const gfx::Rect& bounds) const {
|
const gfx::Rect& bounds) const {
|
||||||
// Use widget() directly since NativeWindowViews::IsMaximized() can
|
|
||||||
// call GetBounds and end up in a loop.
|
|
||||||
if (widget()->IsMaximized() || widget()->IsFullscreen())
|
|
||||||
return bounds;
|
|
||||||
|
|
||||||
gfx::Rect widget_bounds(bounds);
|
gfx::Rect widget_bounds(bounds);
|
||||||
const gfx::Insets frame_insets = GetRestoredFrameBorderInsets();
|
const gfx::Insets frame_insets = GetRestoredFrameBorderInsets();
|
||||||
widget_bounds.Outset(
|
widget_bounds.Outset(
|
||||||
gfx::Outsets::TLBR(frame_insets.top(), frame_insets.left(),
|
gfx::Outsets::TLBR(frame_insets.top(), frame_insets.left(),
|
||||||
frame_insets.bottom(), frame_insets.right()));
|
frame_insets.bottom(), frame_insets.right()));
|
||||||
|
|
||||||
return widget_bounds;
|
return widget_bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect NativeWindowViews::WidgetToLogicalBounds(
|
gfx::Rect NativeWindowViews::WidgetToLogicalBounds(
|
||||||
const gfx::Rect& bounds) const {
|
const gfx::Rect& bounds) const {
|
||||||
if (widget()->IsMaximized() || widget()->IsFullscreen())
|
|
||||||
return bounds;
|
|
||||||
|
|
||||||
gfx::Rect logical_bounds(bounds);
|
gfx::Rect logical_bounds(bounds);
|
||||||
logical_bounds.Inset(GetRestoredFrameBorderInsets());
|
logical_bounds.Inset(GetRestoredFrameBorderInsets());
|
||||||
return logical_bounds;
|
return logical_bounds;
|
||||||
|
|||||||
@@ -194,7 +194,6 @@ class NativeWindowViews : public NativeWindow,
|
|||||||
TaskbarHost& taskbar_host() { return taskbar_host_; }
|
TaskbarHost& taskbar_host() { return taskbar_host_; }
|
||||||
void UpdateThickFrame();
|
void UpdateThickFrame();
|
||||||
void SetLayered();
|
void SetLayered();
|
||||||
bool has_thick_frame() const { return thick_frame_; }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SkColor overlay_button_color() const { return overlay_button_color_; }
|
SkColor overlay_button_color() const { return overlay_button_color_; }
|
||||||
|
|||||||
@@ -158,43 +158,45 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
|
|||||||
windowSize.width() - contentSize.width() + extraSize.width();
|
windowSize.width() - contentSize.width() + extraSize.width();
|
||||||
double extraHeightPlusFrame = titleBarHeight + extraSize.height();
|
double extraHeightPlusFrame = titleBarHeight + extraSize.height();
|
||||||
|
|
||||||
auto widthForHeight = [&](double h) {
|
newSize.width =
|
||||||
return (h - extraHeightPlusFrame) * aspectRatio + extraWidthPlusFrame;
|
roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio +
|
||||||
};
|
extraWidthPlusFrame);
|
||||||
auto heightForWidth = [&](double w) {
|
newSize.height =
|
||||||
return (w - extraWidthPlusFrame) / aspectRatio + extraHeightPlusFrame;
|
roundf((newSize.width - 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.
|
// Clamp to minimum width/height while ensuring aspect ratio remains.
|
||||||
NSSize minSize = [window minSize];
|
NSSize minSize = [window minSize];
|
||||||
NSSize zeroSize =
|
NSSize zeroSize =
|
||||||
shell_->has_frame() ? NSMakeSize(0, titleBarHeight) : NSZeroSize;
|
shell_->has_frame() ? NSMakeSize(0, titleBarHeight) : NSZeroSize;
|
||||||
if (!NSEqualSizes(minSize, zeroSize)) {
|
if (!NSEqualSizes(minSize, zeroSize)) {
|
||||||
|
double minWidthForAspectRatio =
|
||||||
|
(minSize.height - titleBarHeight) * aspectRatio;
|
||||||
bool atMinHeight =
|
bool atMinHeight =
|
||||||
minSize.height > zeroSize.height && newSize.height <= minSize.height;
|
minSize.height > zeroSize.height && newSize.height <= minSize.height;
|
||||||
newSize.width = atMinHeight ? widthForHeight(minSize.height)
|
newSize.width = atMinHeight ? minWidthForAspectRatio
|
||||||
: std::max(newSize.width, minSize.width);
|
: std::max(newSize.width, minSize.width);
|
||||||
|
|
||||||
|
double minHeightForAspectRatio = minSize.width / aspectRatio;
|
||||||
bool atMinWidth =
|
bool atMinWidth =
|
||||||
minSize.width > zeroSize.width && newSize.width <= minSize.width;
|
minSize.width > zeroSize.width && newSize.width <= minSize.width;
|
||||||
newSize.height = atMinWidth ? heightForWidth(minSize.width)
|
newSize.height = atMinWidth ? minHeightForAspectRatio
|
||||||
: std::max(newSize.height, minSize.height);
|
: std::max(newSize.height, minSize.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamp to maximum width/height while ensuring aspect ratio remains.
|
// Clamp to maximum width/height while ensuring aspect ratio remains.
|
||||||
NSSize maxSize = [window maxSize];
|
NSSize maxSize = [window maxSize];
|
||||||
if (!NSEqualSizes(maxSize, NSMakeSize(FLT_MAX, FLT_MAX))) {
|
if (!NSEqualSizes(maxSize, NSMakeSize(FLT_MAX, FLT_MAX))) {
|
||||||
|
double maxWidthForAspectRatio = maxSize.height * aspectRatio;
|
||||||
bool atMaxHeight =
|
bool atMaxHeight =
|
||||||
maxSize.height < FLT_MAX && newSize.height >= maxSize.height;
|
maxSize.height < FLT_MAX && newSize.height >= maxSize.height;
|
||||||
newSize.width = atMaxHeight ? widthForHeight(maxSize.height)
|
newSize.width = atMaxHeight ? maxWidthForAspectRatio
|
||||||
: std::min(newSize.width, maxSize.width);
|
: std::min(newSize.width, maxSize.width);
|
||||||
|
|
||||||
|
double maxHeightForAspectRatio = maxSize.width / aspectRatio;
|
||||||
bool atMaxWidth =
|
bool atMaxWidth =
|
||||||
maxSize.width < FLT_MAX && newSize.width >= maxSize.width;
|
maxSize.width < FLT_MAX && newSize.width >= maxSize.width;
|
||||||
newSize.height = atMaxWidth ? heightForWidth(maxSize.width)
|
newSize.height = atMaxWidth ? maxHeightForAspectRatio
|
||||||
: std::min(newSize.height, maxSize.height);
|
: std::min(newSize.height, maxSize.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,19 +106,29 @@ int WinFrameView::NonClientHitTest(const gfx::Point& point) {
|
|||||||
if (SUCCEEDED(DwmGetWindowAttribute(
|
if (SUCCEEDED(DwmGetWindowAttribute(
|
||||||
views::HWNDForWidget(frame()), DWMWA_CAPTION_BUTTON_BOUNDS,
|
views::HWNDForWidget(frame()), DWMWA_CAPTION_BUTTON_BOUNDS,
|
||||||
&button_bounds, sizeof(button_bounds)))) {
|
&button_bounds, sizeof(button_bounds)))) {
|
||||||
gfx::Rect button_bounds_px(button_bounds);
|
gfx::RectF button_bounds_in_dips = gfx::ConvertRectToDips(
|
||||||
// There is a small one-pixel strip right above the caption buttons in
|
gfx::Rect(button_bounds), display::win::GetDPIScale());
|
||||||
// which the resize border "peeks" through. Inset in physical pixels
|
// TODO(crbug.com/1131681): GetMirroredRect() requires an integer rect,
|
||||||
// before converting to DIPs so the resize strip remains exposed at
|
// but the size in DIPs may not be an integer with a fractional device
|
||||||
// fractional scale factors.
|
// scale factor. If we want to keep using integers, the choice to use
|
||||||
button_bounds_px.Inset(gfx::Insets::TLBR(1, 0, 0, 0));
|
// ToFlooredRectDeprecated() seems to be doing the wrong thing given the
|
||||||
|
// comment below about insetting 1 DIP instead of 1 physical pixel. We
|
||||||
const gfx::RectF button_bounds_in_dips =
|
// should probably use ToEnclosedRect() and then we could have inset 1
|
||||||
gfx::ConvertRectToDips(button_bounds_px, display::win::GetDPIScale());
|
// physical pixel here.
|
||||||
// GetMirroredRect() requires an integer rect. Use ToEnclosedRect() so
|
|
||||||
// the top inset is preserved (rounded up) at fractional scale factors.
|
|
||||||
gfx::Rect buttons =
|
gfx::Rect buttons =
|
||||||
GetMirroredRect(gfx::ToEnclosedRect(button_bounds_in_dips));
|
GetMirroredRect(gfx::ToFlooredRectDeprecated(button_bounds_in_dips));
|
||||||
|
|
||||||
|
// There is a small one-pixel strip right above the caption buttons in
|
||||||
|
// which the resize border "peeks" through.
|
||||||
|
constexpr int kCaptionButtonTopInset = 1;
|
||||||
|
// The sizing region at the window edge above the caption buttons is
|
||||||
|
// 1 px regardless of scale factor. If we inset by 1 before converting
|
||||||
|
// to DIPs, the precision loss might eliminate this region entirely. The
|
||||||
|
// best we can do is to inset after conversion. This guarantees we'll
|
||||||
|
// show the resize cursor when resizing is possible. The cost of which
|
||||||
|
// is also maybe showing it over the portion of the DIP that isn't the
|
||||||
|
// outermost pixel.
|
||||||
|
buttons.Inset(gfx::Insets::TLBR(0, kCaptionButtonTopInset, 0, 0));
|
||||||
if (buttons.Contains(point))
|
if (buttons.Contains(point))
|
||||||
return HTNOWHERE;
|
return HTNOWHERE;
|
||||||
}
|
}
|
||||||
@@ -228,15 +238,14 @@ void WinFrameView::LayoutCaptionButtons() {
|
|||||||
int custom_height = window()->titlebar_overlay_height();
|
int custom_height = window()->titlebar_overlay_height();
|
||||||
int height = TitlebarHeight(custom_height);
|
int height = TitlebarHeight(custom_height);
|
||||||
|
|
||||||
// Insets place the resize hit targets outside of the frame, so the caption
|
// TODO(mlaurencin): This -1 creates a 1 pixel margin between the right
|
||||||
// buttons can go right at the edge. Without insets, the resize hit
|
// edge of the button container and the edge of the window, allowing for this
|
||||||
// targets are inside the frame, and a 1px margin is needed to click and drag
|
// edge portion to return the correct hit test and be manually resized
|
||||||
// next to the button container. The margin can be removed if support is added
|
// properly. Alternatives can be explored, but the differences in view
|
||||||
// for insets on non-thick frames.
|
// structures between Electron and Chromium may result in this as the best
|
||||||
int variable_width = !RestoredFrameBorderInsets().IsEmpty()
|
// option.
|
||||||
? preferred_size.width()
|
int variable_width =
|
||||||
: (IsMaximized() ? preferred_size.width()
|
IsMaximized() ? preferred_size.width() : preferred_size.width() - 1;
|
||||||
: preferred_size.width() - 1);
|
|
||||||
caption_button_container_->SetBounds(width() - preferred_size.width(),
|
caption_button_container_->SetBounds(width() - preferred_size.width(),
|
||||||
WindowTopY(), variable_width, height);
|
WindowTopY(), variable_width, height);
|
||||||
|
|
||||||
@@ -268,33 +277,22 @@ bool WinFrameView::GetShouldPaintAsActive() {
|
|||||||
gfx::Size WinFrameView::GetMinimumSize() const {
|
gfx::Size WinFrameView::GetMinimumSize() const {
|
||||||
if (!window_)
|
if (!window_)
|
||||||
return gfx::Size();
|
return gfx::Size();
|
||||||
// Chromium expects minimum size to be in content dimensions on Windows.
|
// Chromium expects minimum size to be in content dimensions on Windows
|
||||||
// If WidgetSizeIsClientSize() is true, it will account for frame borders and
|
// because it adds the frame border automatically in OnGetMinMaxInfo.
|
||||||
// insets automatically.
|
|
||||||
return window_->GetContentMinimumSize();
|
return window_->GetContentMinimumSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Size WinFrameView::GetMaximumSize() const {
|
gfx::Size WinFrameView::GetMaximumSize() const {
|
||||||
if (!window_)
|
if (!window_)
|
||||||
return gfx::Size();
|
return gfx::Size();
|
||||||
// See comment in GetMinimumSize().
|
// 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();
|
gfx::Size size = window_->GetContentMaximumSize();
|
||||||
// Electron public APIs returns (0, 0) when maximum size is not set, but it
|
// Electron public APIs returns (0, 0) when maximum size is not set, but it
|
||||||
// would break internal window APIs like HWNDMessageHandler::SetAspectRatio.
|
// would break internal window APIs like HWNDMessageHandler::SetAspectRatio.
|
||||||
return size.IsEmpty() ? gfx::Size(INT_MAX, INT_MAX) : size;
|
return size.IsEmpty() ? gfx::Size(INT_MAX, INT_MAX) : size;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Insets WinFrameView::RestoredFrameBorderInsets() const {
|
|
||||||
if (window_->has_frame() || !window_->has_thick_frame() ||
|
|
||||||
!window_->IsResizable())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const int thickness =
|
|
||||||
display::win::GetScreenWin()->GetSystemMetricsInDIP(SM_CXSIZEFRAME) +
|
|
||||||
display::win::GetScreenWin()->GetSystemMetricsInDIP(SM_CXPADDEDBORDER);
|
|
||||||
return gfx::Insets::TLBR(0, thickness, thickness, thickness);
|
|
||||||
}
|
|
||||||
|
|
||||||
BEGIN_METADATA(WinFrameView)
|
BEGIN_METADATA(WinFrameView)
|
||||||
END_METADATA
|
END_METADATA
|
||||||
|
|
||||||
|
|||||||
@@ -36,9 +36,6 @@ class WinFrameView : public FramelessView {
|
|||||||
gfx::Size GetMinimumSize() const override;
|
gfx::Size GetMinimumSize() const override;
|
||||||
gfx::Size GetMaximumSize() const override;
|
gfx::Size GetMaximumSize() const override;
|
||||||
|
|
||||||
// views::FramelessView:
|
|
||||||
gfx::Insets RestoredFrameBorderInsets() const override;
|
|
||||||
|
|
||||||
WinCaptionButtonContainer* caption_button_container() {
|
WinCaptionButtonContainer* caption_button_container() {
|
||||||
return caption_button_container_;
|
return caption_button_container_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,45 +89,24 @@ bool ElectronDesktopWindowTreeHostWin::GetDwmFrameInsetsInPixels(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElectronDesktopWindowTreeHostWin::WidgetSizeIsClientSize() const {
|
|
||||||
// For both framed and frameless windows with resize insets (thick frames),
|
|
||||||
// this should return true so that the aura layer is sized to the client area
|
|
||||||
// rather than the full HWND, and so insets are accounted for when handling
|
|
||||||
// size/aspect ratio constraints.
|
|
||||||
if (native_window_view_->has_thick_frame())
|
|
||||||
return true;
|
|
||||||
return views::DesktopWindowTreeHostWin::WidgetSizeIsClientSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ElectronDesktopWindowTreeHostWin::GetClientAreaInsets(
|
bool ElectronDesktopWindowTreeHostWin::GetClientAreaInsets(
|
||||||
gfx::Insets* insets,
|
gfx::Insets* insets,
|
||||||
int frame_thickness) const {
|
int frame_thickness) const {
|
||||||
if (!native_window_view_->has_frame()) {
|
// Windows by default extends the maximized window slightly larger than
|
||||||
|
// current workspace, for frameless window since the standard frame has been
|
||||||
|
// removed, the client area would then be drew outside current workspace.
|
||||||
|
//
|
||||||
|
// Indenting the client area can fix this behavior.
|
||||||
|
if (IsMaximized() && !native_window_view_->has_frame()) {
|
||||||
|
// The insets would be eventually passed to WM_NCCALCSIZE, which takes
|
||||||
|
// the metrics under the DPI of _main_ monitor instead of current monitor.
|
||||||
|
//
|
||||||
|
// Please make sure you tested maximized frameless window under multiple
|
||||||
|
// monitors with different DPIs before changing this code.
|
||||||
const int thickness = ::GetSystemMetrics(SM_CXSIZEFRAME) +
|
const int thickness = ::GetSystemMetrics(SM_CXSIZEFRAME) +
|
||||||
::GetSystemMetrics(SM_CXPADDEDBORDER);
|
::GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||||
|
*insets = gfx::Insets::TLBR(thickness, thickness, thickness, thickness);
|
||||||
if (IsMaximized()) {
|
return true;
|
||||||
// Windows by default extends the maximized window slightly larger than
|
|
||||||
// current workspace, for frameless window since the standard frame has
|
|
||||||
// been removed, the client area would then be drew outside current
|
|
||||||
// workspace.
|
|
||||||
//
|
|
||||||
// Indenting the client area can fix this behavior.
|
|
||||||
//
|
|
||||||
// The insets would be eventually passed to WM_NCCALCSIZE, which takes
|
|
||||||
// the metrics under the DPI of _main_ monitor instead of current monitor.
|
|
||||||
//
|
|
||||||
// Please make sure you tested maximized frameless window under multiple
|
|
||||||
// monitors with different DPIs before changing this code.
|
|
||||||
*insets = gfx::Insets::TLBR(thickness, thickness, thickness, thickness);
|
|
||||||
return true;
|
|
||||||
} else if (native_window_view_->has_thick_frame() &&
|
|
||||||
native_window_view_->IsResizable()) {
|
|
||||||
// Grow the insets to support resize targets past the frame edge like in
|
|
||||||
// windows with standard frames.
|
|
||||||
*insets = gfx::Insets::TLBR(0, thickness, thickness, thickness);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ class ElectronDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin,
|
|||||||
LRESULT* result) override;
|
LRESULT* result) override;
|
||||||
bool ShouldPaintAsActive() const override;
|
bool ShouldPaintAsActive() const override;
|
||||||
bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override;
|
bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override;
|
||||||
bool WidgetSizeIsClientSize() const override;
|
|
||||||
bool GetClientAreaInsets(gfx::Insets* insets,
|
bool GetClientAreaInsets(gfx::Insets* insets,
|
||||||
int frame_thickness) const override;
|
int frame_thickness) const override;
|
||||||
bool HandleMouseEventForCaption(UINT message) const override;
|
bool HandleMouseEventForCaption(UINT message) const override;
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
#include "shell/common/crash_keys.h"
|
#include "shell/common/crash_keys.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
|
#include "base/containers/circular_deque.h"
|
||||||
#include "base/environment.h"
|
#include "base/environment.h"
|
||||||
#include "base/no_destructor.h"
|
#include "base/no_destructor.h"
|
||||||
#include "base/strings/strcat.h"
|
#include "base/strings/strcat.h"
|
||||||
@@ -28,22 +28,17 @@ namespace electron::crash_keys {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Do NOT replace with base::circular_deque. CrashKeyString wraps a
|
|
||||||
// crashpad::Annotation that holds self-referential pointers and registers
|
|
||||||
// in a process-global linked list; relocating elements (as circular_deque
|
|
||||||
// does on growth) corrupts that list and hangs the crashpad handler.
|
|
||||||
// std::deque never relocates existing elements. See #50795.
|
|
||||||
auto& GetExtraCrashKeys() {
|
auto& GetExtraCrashKeys() {
|
||||||
constexpr size_t kMaxCrashKeyValueSize = 20320;
|
constexpr size_t kMaxCrashKeyValueSize = 20320;
|
||||||
static_assert(kMaxCrashKeyValueSize < crashpad::Annotation::kValueMaxSize,
|
static_assert(kMaxCrashKeyValueSize < crashpad::Annotation::kValueMaxSize,
|
||||||
"max crash key value length above what crashpad supports");
|
"max crash key value length above what crashpad supports");
|
||||||
using CrashKeyString = crash_reporter::CrashKeyString<kMaxCrashKeyValueSize>;
|
using CrashKeyString = crash_reporter::CrashKeyString<kMaxCrashKeyValueSize>;
|
||||||
static base::NoDestructor<std::deque<CrashKeyString>> extra_keys;
|
static base::NoDestructor<base::circular_deque<CrashKeyString>> extra_keys;
|
||||||
return *extra_keys;
|
return *extra_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& GetExtraCrashKeyNames() {
|
auto& GetExtraCrashKeyNames() {
|
||||||
static base::NoDestructor<std::deque<std::string>> crash_key_names;
|
static base::NoDestructor<base::circular_deque<std::string>> crash_key_names;
|
||||||
return *crash_key_names;
|
return *crash_key_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/functional/callback_helpers.h"
|
|
||||||
#include "base/strings/string_split.h"
|
#include "base/strings/string_split.h"
|
||||||
#include "components/network_hints/renderer/web_prescient_networking_impl.h"
|
#include "components/network_hints/renderer/web_prescient_networking_impl.h"
|
||||||
#include "content/common/buildflags.h"
|
#include "content/common/buildflags.h"
|
||||||
|
|||||||
@@ -5641,6 +5641,21 @@ describe('BrowserWindow module', () => {
|
|||||||
expectBoundsEqual(w.getSize(), [400, 300]);
|
expectBoundsEqual(w.getSize(), [400, 300]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ifit(process.platform !== 'darwin')('works for a window smaller than 64x64', () => {
|
||||||
|
const w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
frame: false,
|
||||||
|
resizable: false,
|
||||||
|
transparent: true
|
||||||
|
});
|
||||||
|
w.setContentSize(60, 60);
|
||||||
|
expectBoundsEqual(w.getContentSize(), [60, 60]);
|
||||||
|
w.setContentSize(30, 30);
|
||||||
|
expectBoundsEqual(w.getContentSize(), [30, 30]);
|
||||||
|
w.setContentSize(10, 10);
|
||||||
|
expectBoundsEqual(w.getContentSize(), [10, 10]);
|
||||||
|
});
|
||||||
|
|
||||||
ifit(process.platform === 'win32')('do not change window with frame bounds when maximized', () => {
|
ifit(process.platform === 'win32')('do not change window with frame bounds when maximized', () => {
|
||||||
const w = new BrowserWindow({
|
const w = new BrowserWindow({
|
||||||
show: true,
|
show: true,
|
||||||
|
|||||||
@@ -250,34 +250,6 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
|
|||||||
expect(crash.addedThenRemoved).to.be.undefined();
|
expect(crash.addedThenRemoved).to.be.undefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Regression: base::circular_deque relocates elements on growth,
|
|
||||||
// corrupting crashpad::Annotation's self-referential pointers and
|
|
||||||
// causing missing crash keys or a hung handler. See crash_keys.cc.
|
|
||||||
it('does not corrupt the crashpad annotation list after deque reallocation', async function () {
|
|
||||||
// Tight timeout so a hanging handler fails fast instead of waiting
|
|
||||||
// for the mocha default of 120s.
|
|
||||||
this.timeout(45000);
|
|
||||||
const { port, waitForCrash } = await startServer();
|
|
||||||
runCrashApp('renderer-dynamic-keys', port);
|
|
||||||
const crash = await Promise.race([
|
|
||||||
waitForCrash(),
|
|
||||||
new Promise<never>((_resolve, reject) => {
|
|
||||||
global.setTimeout(
|
|
||||||
() => reject(new Error('crashpad handler hung walking corrupted annotation list; crash upload did not arrive within 30s')),
|
|
||||||
30000
|
|
||||||
);
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
expect(crash.process_type).to.equal('renderer');
|
|
||||||
const missing: string[] = [];
|
|
||||||
for (let i = 0; i < 50; i++) {
|
|
||||||
if ((crash as any)[`dyn-key-${i}`] !== `val-${i}`) {
|
|
||||||
missing.push(`dyn-key-${i}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(missing, `missing dynamic crash keys: ${missing.join(', ')}`).to.be.empty();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('contains v8 crash keys when a v8 crash occurs', async () => {
|
it('contains v8 crash keys when a v8 crash occurs', async () => {
|
||||||
const { remotely } = await startRemoteControlApp();
|
const { remotely } = await startRemoteControlApp();
|
||||||
const { port, waitForCrash } = await startServer();
|
const { port, waitForCrash } = await startServer();
|
||||||
|
|||||||
13
spec/fixtures/apps/crash/main.js
vendored
13
spec/fixtures/apps/crash/main.js
vendored
@@ -51,19 +51,6 @@ app.whenReady().then(() => {
|
|||||||
});
|
});
|
||||||
w.loadURL(`about:blank?set_extra=${setExtraParameters ? 1 : 0}`);
|
w.loadURL(`about:blank?set_extra=${setExtraParameters ? 1 : 0}`);
|
||||||
w.webContents.on('render-process-gone', () => process.exit(0));
|
w.webContents.on('render-process-gone', () => process.exit(0));
|
||||||
} else if (crashType === 'renderer-dynamic-keys') {
|
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
|
|
||||||
w.webContents.on('render-process-gone', () => process.exit(0));
|
|
||||||
w.webContents.on('did-finish-load', () => {
|
|
||||||
w.webContents.executeJavaScript(`
|
|
||||||
const { crashReporter } = require('electron');
|
|
||||||
for (let i = 0; i < 50; i++) {
|
|
||||||
crashReporter.addExtraParameter('dyn-key-' + i, 'val-' + i);
|
|
||||||
}
|
|
||||||
process.crash();
|
|
||||||
`);
|
|
||||||
});
|
|
||||||
w.loadURL('about:blank');
|
|
||||||
} else if (crashType === 'node') {
|
} else if (crashType === 'node') {
|
||||||
const crashPath = path.join(__dirname, 'node-crash.js');
|
const crashPath = path.join(__dirname, 'node-crash.js');
|
||||||
const child = childProcess.fork(crashPath, { silent: true });
|
const child = childProcess.fork(crashPath, { silent: true });
|
||||||
|
|||||||
11
yarn.lock
11
yarn.lock
@@ -590,7 +590,7 @@ __metadata:
|
|||||||
"@types/semver": "npm:^7.5.8"
|
"@types/semver": "npm:^7.5.8"
|
||||||
"@types/stream-json": "npm:^1.7.8"
|
"@types/stream-json": "npm:^1.7.8"
|
||||||
"@types/temp": "npm:^0.9.4"
|
"@types/temp": "npm:^0.9.4"
|
||||||
"@xmldom/xmldom": "npm:^0.8.12"
|
"@xmldom/xmldom": "npm:^0.8.11"
|
||||||
buffer: "npm:^6.0.3"
|
buffer: "npm:^6.0.3"
|
||||||
chalk: "npm:^4.1.0"
|
chalk: "npm:^4.1.0"
|
||||||
check-for-leaks: "npm:^1.2.1"
|
check-for-leaks: "npm:^1.2.1"
|
||||||
@@ -2503,14 +2503,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@xmldom/xmldom@npm:^0.8.12":
|
"@xmldom/xmldom@npm:^0.8.11, @xmldom/xmldom@npm:^0.8.8":
|
||||||
version: 0.8.12
|
|
||||||
resolution: "@xmldom/xmldom@npm:0.8.12"
|
|
||||||
checksum: 10c0/b733c84292d1bee32ef21a05aba8f9063456b51a54068d0b4a1abf5545156ee0b9894b7ae23775b5881b11c35a8a03871d1b514fb7e1b11654cdbee57e1c2707
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@xmldom/xmldom@npm:^0.8.8":
|
|
||||||
version: 0.8.11
|
version: 0.8.11
|
||||||
resolution: "@xmldom/xmldom@npm:0.8.11"
|
resolution: "@xmldom/xmldom@npm:0.8.11"
|
||||||
checksum: 10c0/e768623de72c95d3dae6b5da8e33dda0d81665047811b5498d23a328d45b13feb5536fe921d0308b96a4a8dd8addf80b1f6ef466508051c0b581e63e0dc74ed5
|
checksum: 10c0/e768623de72c95d3dae6b5da8e33dda0d81665047811b5498d23a328d45b13feb5536fe921d0308b96a4a8dd8addf80b1f6ef466508051c0b581e63e0dc74ed5
|
||||||
|
|||||||
Reference in New Issue
Block a user