forked from cztomczak/cefpython
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwindow_info.pyx
More file actions
215 lines (201 loc) · 10.2 KB
/
Copy pathwindow_info.pyx
File metadata and controls
215 lines (201 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# Copyright (c) 2013 CEF Python, see the Authors file.
# All rights reserved. Licensed under BSD 3-clause license.
# Project website: https://github.com/cztomczak/cefpython
include "cefpython.pyx"
cdef void SetCefWindowInfo(
CefWindowInfo& cefWindowInfo,
WindowInfo windowInfo
) except *:
# Note on runtime_style = CEF_RUNTIME_STYLE_ALLOY (set below in every
# windowed branch):
#
# The cef_window_info_t.runtime_style field was added in CEF
# commit dca0435d2 "chrome: Add support for Alloy style browsers
# and windows" (issue #3681, 2024-04-17, first shipping in CEF
# branch 6422 / Chromium 125). See the enum doc in
# include/internal/cef_types_runtime.h: Chrome style provides the
# full Chrome UI; Alloy style provides the content-layer view with
# additional client callbacks and supports windowless rendering.
#
# Since the chrome bootstrap (the default for CEF builds since
# branch 6478 / Chromium 125) makes windowed parent windows default
# to Chrome style, cefpython must opt back into Alloy style
# explicitly. Without it, SetAsChild() would get a Chrome-style
# Views window that can't be parented into the host GTK/Qt window,
# and the LifeSpanHandler / RequestHandler / etc. callbacks
# cefpython exposes would not fire as expected. Off-screen
# rendering is documented to always use Alloy style anyway, but the
# field is harmless to set there too.
if not windowInfo.windowType:
raise Exception("WindowInfo: windowType is not set")
# It is allowed to pass 0 as parentWindowHandle in OSR mode, but then
# some things like context menus and plugins may not display correctly.
if windowInfo.windowType != "offscreen":
if not windowInfo.parentWindowHandle:
# raise Exception("WindowInfo: parentWindowHandle is not set")
pass
IF UNAME_SYSNAME == "Windows":
cdef CefRect windowRect
cdef CefString windowName
cdef RECT rect
ELIF UNAME_SYSNAME == "Darwin":
cdef CefRect windowRect
ELIF UNAME_SYSNAME == "Linux":
cdef CefRect windowRect
# CHILD WINDOW
if windowInfo.windowType == "child":
IF UNAME_SYSNAME == "Windows":
if windowInfo.windowRect:
rect.left = int(windowInfo.windowRect[0])
rect.top = int(windowInfo.windowRect[1])
rect.right = int(windowInfo.windowRect[2])
rect.bottom = int(windowInfo.windowRect[3])
else:
GetClientRect(<CefWindowHandle>windowInfo.parentWindowHandle,
&rect)
windowRect = CefRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top)
cefWindowInfo.SetAsChild(
<CefWindowHandle>windowInfo.parentWindowHandle,
windowRect)
cefWindowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY
ELIF UNAME_SYSNAME == "Darwin":
x = int(windowInfo.windowRect[0])
y = int(windowInfo.windowRect[1])
width = int(windowInfo.windowRect[2] - windowInfo.windowRect[0])
height = int(windowInfo.windowRect[3] - windowInfo.windowRect[1])
windowRect = CefRect(x, y, width, height)
cefWindowInfo.SetAsChild(
<CefWindowHandle>windowInfo.parentWindowHandle,
windowRect)
cefWindowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY
ELIF UNAME_SYSNAME == "Linux":
x = int(windowInfo.windowRect[0])
y = int(windowInfo.windowRect[1])
width = int(windowInfo.windowRect[2] - windowInfo.windowRect[0])
height = int(windowInfo.windowRect[3] - windowInfo.windowRect[1])
windowRect = CefRect(x, y, width, height)
cefWindowInfo.SetAsChild(
<CefWindowHandle>windowInfo.parentWindowHandle,
windowRect)
cefWindowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY
# POPUP WINDOW - Windows only
IF UNAME_SYSNAME == "Windows":
if windowInfo.windowType == "popup":
PyToCefString(windowInfo.windowName, windowName)
cefWindowInfo.SetAsPopup(
<CefWindowHandle>windowInfo.parentWindowHandle,
windowName)
cefWindowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY
if windowInfo.windowType == "offscreen":
cefWindowInfo.SetAsWindowless(
<CefWindowHandle>windowInfo.parentWindowHandle)
cdef class WindowInfo:
cdef public str windowType
cdef public WindowHandle parentWindowHandle
cdef public list windowRect # [left, top, right, bottom]
cdef public object windowName
# Linux Xwayland embedding: when SetAsChild() substitutes the root window
# as CEF's parent, this dict holds the real parent XID and embed size so
# BrowserProcessHandler_CreatePendingBrowsers can schedule the deferred
# XReparentWindow after browser creation. None on all other platforms.
cdef public object _linux_embed_info
def __init__(self, title=""):
self.windowName = ""
if title:
self.windowName = title
self._linux_embed_info = None
cpdef py_void SetAsChild(self, WindowHandle parentWindowHandle,
list windowRect=None):
# Allow parent window handle to be 0, in such case CEF will
# create top window automatically as in hello_world.py example.
if sys.platform == "win32":
# On Windows when parent window handle is 0 then SetAsPopup()
# must be called instead.
if parentWindowHandle == 0:
self.SetAsPopup(parentWindowHandle, "")
return
if parentWindowHandle != 0\
and not WindowUtils.IsWindowHandle(parentWindowHandle):
raise Exception("Invalid parentWindowHandle: %s"\
% parentWindowHandle)
self.windowType = "child"
IF UNAME_SYSNAME == "Linux":
if parentWindowHandle == 0:
import os as _os
import warnings
# In native Wayland mode, parentWindowHandle=0 is correct and
# expected — CEF creates its own xdg_toplevel surface. Only
# warn when the user is likely using an X11-incompatible toolkit
# without having opted into native Wayland.
if "WAYLAND_DISPLAY" in _os.environ and not _g_linux_wayland_mode:
warnings.warn(
"WindowInfo.SetAsChild: parentWindowHandle is 0 on Linux "
"in a Wayland session. The GUI toolkit is likely using the "
"native Wayland backend where winId()/GetHandle() returns 0 "
"instead of an X11 window ID — CEF will open a detached "
"window instead of embedding. Force X11 (XWayland) before "
"initialising the toolkit:\n"
" Qt (PyQt5/PyQt6/PySide2/PySide6): "
"os.environ[\"QT_QPA_PLATFORM\"] = \"xcb\"\n"
" GTK (wxPython/PyGTK): "
"os.environ[\"GDK_BACKEND\"] = \"x11\"\n"
" SDL2 (pysdl2): "
"os.environ[\"SDL_VIDEODRIVER\"] = \"x11\"",
stacklevel=2,
)
if parentWindowHandle != 0:
# Xwayland cross-client restriction: Chrome's internal XCB
# connection cannot create a child window under a window owned
# by GDK's separate Xlib connection — the server returns
# MatchError(bad_value=parent_XID). Workaround: tell CEF to
# use the X11 root window (accessible from any client) as its
# parent, then XReparentWindow into the real parent after the
# browser is created. See _linux_schedule_xembed().
_wr = windowRect if windowRect else [0, 0, 800, 600]
self._linux_embed_info = {
'real_parent': parentWindowHandle,
'width': int(_wr[2]) - int(_wr[0]),
'height': int(_wr[3]) - int(_wr[1]),
}
parentWindowHandle = _linux_get_root_xid()
self.parentWindowHandle = parentWindowHandle
if sys.platform != "win32":
if not windowRect:
windowRect = [0,0,0,0]
if windowRect:
if type(windowRect) == list and len(windowRect) == 4:
self.windowRect = [windowRect[0], windowRect[1],
windowRect[2], windowRect[3]]
else:
raise Exception("WindowInfo.SetAsChild() failed: "
"windowRect: invalid value")
cpdef py_void SetAsPopup(self, WindowHandle parentWindowHandle,
object windowName):
# Allow parent window handle to be 0, in such case CEF will
# create top window automatically as in hello_world.py example.
if parentWindowHandle != 0\
and not WindowUtils.IsWindowHandle(parentWindowHandle):
raise Exception("Invalid parentWindowHandle: %s"\
% parentWindowHandle)
self.parentWindowHandle = parentWindowHandle
self.windowType = "popup"
if windowName:
self.windowName = str(windowName)
cpdef py_void SetAsOffscreen(self,
WindowHandle parentWindowHandle):
# It is allowed to pass 0 as parentWindowHandle in OSR mode
if parentWindowHandle and \
not WindowUtils.IsWindowHandle(parentWindowHandle):
raise Exception("Invalid parentWindowHandle: %s" \
% parentWindowHandle)
self.parentWindowHandle = parentWindowHandle
self.windowType = "offscreen"
cpdef py_void SetTransparentPainting(self,
py_bool transparentPainting):
"""Deprecated."""
if transparentPainting:
# Do nothing, since v66 OSR windows are transparent by default
pass
else:
raise Exception("This method is deprecated since v66, see "
"Migration Guide document.")