fix: paint and flash issues on macOS (#46615)

* fix: paint and flash issues on macOS

* Adhere to paintWhenInitiallyHidden
This commit is contained in:
Shelley Vohr 2025-04-14 16:29:07 +02:00 committed by GitHub
parent 62b5b5f99d
commit 51bffb533e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 57 additions and 6 deletions

View file

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

View file

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

View file

@ -47,7 +47,7 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
// Copy the show setting to webContents, but only if we don't want to paint
// when initially hidden
bool paint_when_initially_hidden = true;
options.Get("paintWhenInitiallyHidden", &paint_when_initially_hidden);
options.Get(options::kPaintWhenInitiallyHidden, &paint_when_initially_hidden);
if (!paint_when_initially_hidden) {
bool show = true;
options.Get(options::kShow, &show);

View file

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

View file

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

View file

@ -6475,6 +6475,31 @@ describe('BrowserWindow module', () => {
w.loadFile(path.join(fixtures, 'pages', 'send-after-node.html'));
});
// TODO(codebytere): fix on Windows and Linux too
ifdescribe(process.platform === 'darwin')('window.webContents initial paint', () => {
afterEach(closeAllWindows);
it('paints when a window is initially hidden', async () => {
const w = new BrowserWindow({ show: false });
await w.loadFile(path.join(fixtures, 'pages', 'a.html'));
const entries = await w.webContents.executeJavaScript(`
new Promise((resolve) => {
const observer = new PerformanceObserver((performance) => {
observer.disconnect();
resolve(performance.getEntries());
});
observer.observe({ entryTypes: ['paint'] });
});
const header = document.createElement('h1');
header.innerText = 'Paint me!!';
document.getElementById('div').appendChild(header);
`);
expect(JSON.stringify(entries)).to.eq('{}');
});
});
describe('window.webContents.focus()', () => {
afterEach(closeAllWindows);
it('focuses window', async () => {