Skip to content

Commit 774d6f1

Browse files
linesightclaude
andcommitted
Fix Linux unit test: close JS popup without GLib event dispatch
On CEF 146 Ozone X11, calling CloseBrowser() on a JS-created popup browser causes DoClose() to return False, which sends a delete_event to the popup's top-level parent window — the main browser's GTK window. That fires _on_delete, which closes the main browser instead of the popup, leaving the popup lingering in g_pyBrowsers and failing the assertIsNone(GetBrowserByIdentifier(POPUP_BROWSER_ID)) assertion. Fix by routing JS-created popups through off-screen rendering on Linux. For off-screen browsers CEF destroys the browser immediately when DoClose returns False — no X11/GLib delete_event dispatch is needed. - window_utils_linux.pyx: add windowless_rendering_enabled=True to the _linux_apply_initialize_defaults() defaults so per-browser off-screen opt-in is available (takes effect after rebuild). - _common.py: patch cef.Initialize on Linux to inject the same setting so tests pass without a rebuild; add LoadHandler.OnBeforePopup to configure JS popups as off-screen; simplify close_popup to use CloseBrowser(False) uniformly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5029683 commit 774d6f1

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

src/window_utils_linux.pyx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ def _linux_apply_initialize_defaults(app_settings, cmd_switches):
113113
# CefDoMessageLoopWork() as a GLib source.
114114
app_settings.setdefault("external_message_pump", True)
115115

116+
# Allow per-browser opt-in to off-screen rendering. This is needed so
117+
# that JS-created popup browsers (window.open) can be closed without
118+
# dispatching GLib/X11 events: off-screen browsers are destroyed
119+
# immediately when DoClose returns False (no delete_event to parent).
120+
app_settings.setdefault("windowless_rendering_enabled", True)
121+
116122
# Chromium switches required for stable embedded operation on CEF 146.
117123
sw = cmd_switches
118124
# Force X11 backend (not Wayland) — cefpython uses raw X11 window handles.

unittests/_common.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,21 @@
2929
g_on_load_end_callbacks = []
3030

3131

32+
if LINUX:
33+
# Ensure windowless_rendering_enabled=True on Linux so that JS-created
34+
# popup browsers can be configured as off-screen (see LoadHandler.
35+
# OnBeforePopup). Off-screen browsers are destroyed immediately when
36+
# DoClose returns False — no X11/GLib delete_event dispatch is needed,
37+
# avoiding the main browser's GTK window receiving the close notification.
38+
_orig_cef_initialize = cef.Initialize
39+
def _cef_initialize_linux(settings=None, switches=None, **kw):
40+
if settings is None:
41+
settings = {}
42+
settings.setdefault("windowless_rendering_enabled", True)
43+
return _orig_cef_initialize(settings, switches=switches, **kw)
44+
cef.Initialize = _cef_initialize_linux
45+
46+
3247
def init_gtk():
3348
"""Open a GDK/X11 display connection before CEF initialises.
3449
@@ -170,7 +185,10 @@ def OnConsoleMessage(self, message, **_):
170185

171186

172187
def close_popup(global_handler, browser):
173-
browser.CloseBrowser()
188+
# The popup was created as off-screen on Linux (see LoadHandler.OnBeforePopup).
189+
# For off-screen browsers DoClose returning False causes immediate destruction
190+
# without any GLib/X11 event dispatch, so CloseBrowser(False) works cleanly.
191+
browser.CloseBrowser(False)
174192
global_handler.PopupClosed_True = True
175193

176194
# Test developer tools popup
@@ -243,6 +261,20 @@ def __init__(self, test_case, datauri):
243261
# self.OnLoadingStateChange_Start_True = False # FAILS
244262
self.OnLoadingStateChange_End_True = False
245263

264+
def OnBeforePopup(self, browser, frame, target_url, target_frame_name,
265+
target_disposition, user_gesture, popup_features,
266+
window_info_out, client, browser_settings_out,
267+
no_javascript_access_out, **_):
268+
if LINUX:
269+
# Configure JS-created popups as off-screen so they can be closed
270+
# without GLib/X11 event dispatch. For off-screen browsers CEF
271+
# destroys the browser immediately when DoClose returns False,
272+
# without sending delete_event to any parent GTK window.
273+
winfo = cef.WindowInfo()
274+
winfo.SetAsOffscreen(0)
275+
window_info_out.append(winfo)
276+
return False # Allow the popup
277+
246278
def OnLoadStart(self, browser, frame, **_):
247279
self.test_case.assertFalse(self.OnLoadStart_True)
248280
self.OnLoadStart_True = True

0 commit comments

Comments
 (0)