Skip to content

Commit a3472b7

Browse files
committed
Added new methods to Browser: GetSize(), SetSize(), Invalidate(), GetImage().
Added RenderHandler, for use with off-screen rendering (not all methods yet ready). Added Panda3D example & screenshot. Added more wxpython examples (cefwxpanel_sample1 & 2), cefwxpanel.py is a helper api that simplifies integration with cefpython, samples provided by Greg Kacy. Renamed libcpp types from "c_" to "cpp_".
1 parent e0abf89 commit a3472b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1041
-332
lines changed

cefpython/browser.pyx

Lines changed: 155 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# License: New BSD License.
33
# Website: http://code.google.com/p/cefpython/
44

5-
# If you try to keep PyBrowser() objects inside c_vector you will
5+
# If you try to keep PyBrowser() objects inside cpp_vector you will
66
# get segmentation faults, as they will be garbage collected.
77

88
cdef dict g_pyBrowsers = {}
@@ -23,7 +23,8 @@ cdef PyBrowser GetPyBrowser(CefRefPtr[CefBrowser] cefBrowser):
2323

2424
for id, pyBrowser in g_pyBrowsers.items():
2525
if not pyBrowser.cefBrowser.get():
26-
Debug("GetPyBrowser(): removing an empty CefBrowser reference, browserId=%s" % id)
26+
Debug("GetPyBrowser(): removing an empty CefBrowser reference, "
27+
"browserId=%s" % id)
2728
del g_pyBrowsers[id]
2829

2930
Debug("GetPyBrowser(): creating new PyBrowser, browserId=%s" % browserId)
@@ -74,11 +75,13 @@ IF CEF_VERSION == 3:
7475

7576
cdef CefRefPtr[CefBrowserHost] GetCefBrowserHost(
7677
CefRefPtr[CefBrowser] cefBrowser) except *:
77-
cdef CefRefPtr[CefBrowserHost] cefBrowserHost = cefBrowser.get().GetHost()
78+
cdef CefRefPtr[CefBrowserHost] cefBrowserHost = (
79+
cefBrowser.get().GetHost())
7880
if <void*>cefBrowserHost != NULL and cefBrowserHost.get():
7981
return cefBrowserHost
80-
raise Exception("GetCefBrowserHost() failed: this method of Browser object "
81-
"can only be called in the browser process.")
82+
raise Exception("GetCefBrowserHost() failed: this method of "
83+
"Browser object can only be called in the "
84+
"browser process.")
8285

8386
cdef class PyBrowser:
8487
cdef CefRefPtr[CefBrowser] cefBrowser
@@ -96,29 +99,38 @@ cdef class PyBrowser:
9699
cdef public int gwlExStyle
97100
cdef public tuple windowRect
98101

102+
cdef void* imageBuffer
103+
99104
cdef CefRefPtr[CefBrowser] GetCefBrowser(self) except *:
100105
if <void*>self.cefBrowser != NULL and self.cefBrowser.get():
101106
return self.cefBrowser
102-
raise Exception("PyBrowser.GetCefBrowser() failed: CefBrowser was destroyed")
107+
raise Exception("PyBrowser.GetCefBrowser() failed: CefBrowser "
108+
"was destroyed")
103109

104110
IF CEF_VERSION == 3:
105111

106112
cdef CefRefPtr[CefBrowserHost] GetCefBrowserHost(self) except *:
107-
cdef CefRefPtr[CefBrowserHost] cefBrowserHost = self.GetCefBrowser().get().GetHost()
113+
cdef CefRefPtr[CefBrowserHost] cefBrowserHost = (
114+
self.GetCefBrowser().get().GetHost())
108115
if <void*>cefBrowserHost != NULL and cefBrowserHost.get():
109116
return cefBrowserHost
110-
raise Exception("PyBrowser.GetCefBrowserHost() failed: this method "
111-
"can only be called in the browser process.")
117+
raise Exception("PyBrowser.GetCefBrowserHost() failed: this "
118+
"method can only be called in the browser process.")
112119

113120
def __init__(self):
114121
self.clientCallbacks = {}
115122
self.allowedClientCallbacks = []
116123
self.userData = {}
117124

125+
def __del__(self):
126+
if self.imageBuffer:
127+
free(self.imageBuffer)
128+
118129
cpdef py_void SetClientCallback(self, py_string name, object callback):
119130
if not self.allowedClientCallbacks:
120131
# CefLoadHandler.
121-
self.allowedClientCallbacks += ["OnLoadEnd", "OnLoadError", "OnLoadStart"]
132+
self.allowedClientCallbacks += ["OnLoadEnd", "OnLoadError",
133+
"OnLoadStart"]
122134

123135
# CefKeyboardHandler.
124136
self.allowedClientCallbacks += ["OnKeyEvent"]
@@ -127,32 +139,43 @@ cdef class PyBrowser:
127139
self.allowedClientCallbacks += ["OnUncaughtException"]
128140

129141
# CefRequestHandler.
130-
self.allowedClientCallbacks += ["OnBeforeBrowse", "OnBeforeResourceLoad",
131-
"OnResourceRedirect", "OnResourceResponse", "OnProtocolExecution",
132-
"GetDownloadHandler", "GetAuthCredentials", "GetCookieManager"]
142+
self.allowedClientCallbacks += ["OnBeforeBrowse",
143+
"OnBeforeResourceLoad", "OnResourceRedirect",
144+
"OnResourceResponse", "OnProtocolExecution",
145+
"GetDownloadHandler", "GetAuthCredentials",
146+
"GetCookieManager"]
133147

134148
# CefDisplayHandler.
135-
self.allowedClientCallbacks += ["OnAddressChange", "OnConsoleMessage",
136-
"OnContentsSizeChange", "OnNavStateChange", "OnStatusMessage",
137-
"OnTitleChange", "OnTooltip"]
149+
self.allowedClientCallbacks += ["OnAddressChange",
150+
"OnConsoleMessage", "OnContentsSizeChange",
151+
"OnNavStateChange", "OnStatusMessage", "OnTitleChange",
152+
"OnTooltip"]
138153

139154
# LifespanHandler.
140-
self.allowedClientCallbacks += ["DoClose", "OnAfterCreated", "OnBeforeClose",
141-
"RunModal"]
155+
self.allowedClientCallbacks += ["DoClose", "OnAfterCreated",
156+
"OnBeforeClose", "RunModal"]
157+
158+
# RenderHandler
159+
self.allowedClientCallbacks += ["GetViewRect", "GetScreenRect",
160+
"GetScreenPoint", "OnPopupShow", "OnPopupSize",
161+
"OnPaint", "OnCursorChange"]
142162

143163
if name not in self.allowedClientCallbacks:
144-
raise Exception("Browser.SetClientCallback() failed: unknown callback: %s" % name)
164+
raise Exception("Browser.SetClientCallback() failed: unknown "
165+
"callback: %s" % name)
145166

146167
self.clientCallbacks[name] = callback
147168

148169
cpdef py_void SetClientHandler(self, object clientHandler):
149170
if not hasattr(clientHandler, "__class__"):
150-
raise Exception("Browser.SetClientHandler() failed: __class__ attribute missing")
171+
raise Exception("Browser.SetClientHandler() failed: __class__ "
172+
"attribute missing")
151173
cdef dict methods = {}
152174
cdef py_string key
153175
cdef object method
154176
cdef tuple value
155-
for value in inspect.getmembers(clientHandler, predicate=inspect.ismethod):
177+
for value in inspect.getmembers(clientHandler,
178+
predicate=inspect.ismethod):
156179
key = value[0]
157180
method = value[1]
158181
if key and key[0] != '_':
@@ -192,8 +215,9 @@ cdef class PyBrowser:
192215
self.GetCefBrowser().get().ClearHistory()
193216

194217
cpdef py_void CloseBrowser(self):
195-
# In cefclient/cefclient_win.cpp there is only ParentWindowWillClose() called.
196-
# CloseBrowser() is called only for popups.
218+
# In cefclient/cefclient_win.cpp there is only
219+
# ParentWindowWillClose() called. CloseBrowser() is called
220+
# only for popups.
197221
if self.GetUserData("__outerWindowHandle"):
198222
IF CEF_VERSION == 1:
199223
Debug("CefBrowser::ParentWindowWillClose()")
@@ -214,29 +238,33 @@ cdef class PyBrowser:
214238
cpdef py_void CloseDevTools(self):
215239
self.GetCefBrowser().get().CloseDevTools()
216240

217-
cpdef py_void Find(self, int searchId, py_string searchText, py_bool forward,
218-
py_bool matchCase, py_bool findNext):
241+
cpdef py_void Find(self, int searchId, py_string searchText,
242+
py_bool forward, py_bool matchCase,
243+
py_bool findNext):
219244
cdef CefString cefSearchText
220245
PyToCefString(searchText, cefSearchText)
221-
self.GetCefBrowser().get().Find(searchId, cefSearchText, bool(forward),
222-
bool(matchCase), bool(findNext))
246+
self.GetCefBrowser().get().Find(searchId, cefSearchText,
247+
bool(forward), bool(matchCase), bool(findNext))
223248

224249
cpdef PyFrame GetFocusedFrame(self):
225-
assert IsCurrentThread(TID_UI), "Browser.GetFocusedFrame() may only be called on the UI thread"
250+
assert IsCurrentThread(TID_UI), (
251+
"Browser.GetFocusedFrame() may only be called on UI thread")
226252
return GetPyFrame(self.GetCefBrowser().get().GetFocusedFrame())
227253

228254
cpdef PyFrame GetFrame(self, py_string name):
229-
assert IsCurrentThread(TID_UI), "Browser.GetFrame() may only be called on the UI thread"
255+
assert IsCurrentThread(TID_UI), (
256+
"Browser.GetFrame() may only be called on the UI thread")
230257
cdef CefString cefName
231258
PyToCefString(name, cefName)
232259
return GetPyFrame(self.GetCefBrowser().get().GetFrame(cefName))
233260

234261
cpdef list GetFrameNames(self):
235-
assert IsCurrentThread(TID_UI), "Browser.GetFrameNames() may only be called on the UI thread"
236-
cdef c_vector[CefString] cefNames
262+
assert IsCurrentThread(TID_UI), (
263+
"Browser.GetFrameNames() may only be called on the UI thread")
264+
cdef cpp_vector[CefString] cefNames
237265
self.GetCefBrowser().get().GetFrameNames(cefNames)
238266
cdef list names = []
239-
cdef c_vector[CefString].iterator iterator = cefNames.begin()
267+
cdef cpp_vector[CefString].iterator iterator = cefNames.begin()
240268
cdef CefString cefString
241269
while iterator != cefNames.end():
242270
cefString = deref(iterator)
@@ -276,7 +304,8 @@ cdef class PyBrowser:
276304

277305
cpdef double GetZoomLevel(self) except *:
278306
IF CEF_VERSION == 1:
279-
assert IsCurrentThread(TID_UI), "Browser.GetZoomLevel() may only be called on the UI thread"
307+
assert IsCurrentThread(TID_UI), (
308+
"Browser.GetZoomLevel() may only be called on UI thread")
280309
cdef double zoomLevel
281310
IF CEF_VERSION == 1:
282311
zoomLevel = self.GetCefBrowser().get().GetZoomLevel()
@@ -307,7 +336,8 @@ cdef class PyBrowser:
307336
IF CEF_VERSION == 1:
308337

309338
cpdef py_bool IsPopupVisible(self):
310-
assert IsCurrentThread(TID_UI), "Browser.IsPopupVisible() may only be called on the UI thread"
339+
assert IsCurrentThread(TID_UI), (
340+
"Browser.IsPopupVisible() may only be called on UI thread")
311341
return self.GetCefBrowser().get().IsPopupVisible()
312342

313343
cpdef py_bool IsWindowRenderingDisabled(self):
@@ -359,7 +389,8 @@ cdef class PyBrowser:
359389
windowHandle = self.GetWindowHandle()
360390

361391
# Offscreen browser will have an empty window handle.
362-
assert windowHandle, "Browser.ToggleFullscreen() failed: no window handle found"
392+
assert windowHandle, (
393+
"Browser.ToggleFullscreen() failed: no window handle found")
363394

364395
cdef HWND hwnd = <HWND><int>int(windowHandle)
365396
cdef RECT rect
@@ -369,7 +400,8 @@ cdef class PyBrowser:
369400

370401
# Logic copied from chromium > fullscreen_handler.cc >
371402
# FullscreenHandler::SetFullscreenImpl:
372-
# http://src.chromium.org/viewvc/chrome/trunk/src/ui/views/win/fullscreen_handler.cc
403+
# http://src.chromium.org/viewvc/chrome/trunk/src/ui/views/win/
404+
# fullscreen_handler.cc
373405

374406
cdef py_bool for_metro = False
375407

@@ -389,11 +421,14 @@ cdef class PyBrowser:
389421
removeStyle = WS_CAPTION | WS_THICKFRAME
390422
removeExStyle = (WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE
391423
| WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)
392-
SetWindowLong(hwnd, GWL_STYLE, self.gwlStyle & ~(removeStyle))
393-
SetWindowLong(hwnd, GWL_EXSTYLE, self.gwlExStyle & ~(removeExStyle))
424+
SetWindowLong(hwnd, GWL_STYLE,
425+
self.gwlStyle & ~(removeStyle))
426+
SetWindowLong(hwnd, GWL_EXSTYLE,
427+
self.gwlExStyle & ~(removeExStyle))
394428

395429
if not for_metro:
396-
# MONITOR_DEFAULTTONULL, MONITOR_DEFAULTTOPRIMARY, MONITOR_DEFAULTTONEAREST
430+
# MONITOR_DEFAULTTONULL, MONITOR_DEFAULTTOPRIMARY,
431+
# MONITOR_DEFAULTTONEAREST
397432
monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
398433
GetMonitorInfo(monitor, &monitorInfo)
399434
left = monitorInfo.rcMonitor.left
@@ -408,10 +443,90 @@ cdef class PyBrowser:
408443

409444
if not for_metro:
410445
(left, top, right, bottom) = self.windowRect
411-
SetWindowPos(hwnd, NULL, int(left), int(top), int(right-left), int(bottom-top),
446+
SetWindowPos(hwnd, NULL,
447+
int(left), int(top),
448+
int(right-left), int(bottom-top),
412449
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED)
413450

414451
if self.maximized:
415452
SendMessage(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0)
416453

417454
self.isFullscreen = int(not bool(self.isFullscreen))
455+
456+
# Off-screen rendering.
457+
458+
IF CEF_VERSION == 1:
459+
460+
cpdef tuple GetSize(self, PaintElementType paintElementType):
461+
assert IsCurrentThread(TID_UI), (
462+
"Browser.GetSize(): this method should only be called "
463+
"on the UI thread")
464+
cdef int width = 0
465+
cdef int height = 0
466+
cdef cpp_bool ret = self.GetCefBrowser().get().GetSize(
467+
paintElementType, width, height)
468+
if ret:
469+
return (width, height)
470+
else:
471+
return ()
472+
473+
cpdef py_void SetSize(self, PaintElementType paintElementType,
474+
int width, int height):
475+
self.GetCefBrowser().get().SetSize(paintElementType, width, height)
476+
477+
cpdef py_void Invalidate(self, list dirtyRect):
478+
assert len(dirtyRect) == 4, (
479+
"Browser.Invalidate() failed, dirtyRect is invalid")
480+
cdef CefRect cefRect = CefRect(
481+
dirtyRect[0], dirtyRect[1], dirtyRect[2], dirtyRect[3])
482+
self.GetCefBrowser().get().Invalidate(cefRect)
483+
484+
cpdef PaintBuffer GetImage(self, PaintElementType paintElementType,
485+
int width, int height):
486+
assert IsCurrentThread(TID_UI), (
487+
"Browser.GetImage(): this method should only be called "
488+
"on the UI thread")
489+
490+
IF UNAME_SYSNAME == "Windows":
491+
return self.GetImage_Windows(paintElementType, width, height)
492+
ELSE:
493+
return None
494+
495+
IF CEF_VERSION == 1 and UNAME_SYSNAME == "Windows":
496+
497+
cdef PaintBuffer GetImage_Windows(self,
498+
PaintElementType paintElementType, int width, int height):
499+
if not self.imageBuffer:
500+
print("Browser.imageBuffer = malloc(%d)" % (width*height*4))
501+
self.imageBuffer = <void*>malloc(width*height*4)
502+
cdef cpp_bool ret = self.GetCefBrowser().get().GetImage(
503+
paintElementType, width, height, self.imageBuffer)
504+
cdef PaintBuffer paintBuffer
505+
if ret:
506+
paintBuffer = CreatePaintBuffer(
507+
self.imageBuffer, width, height)
508+
return paintBuffer
509+
else:
510+
return None
511+
512+
# Sending mouse/key events.
513+
514+
IF CEF_VERSION == 1:
515+
516+
cpdef py_void SendKeyEvent(self):
517+
pass
518+
519+
cpdef py_void SendMouseClickEvent(self):
520+
pass
521+
522+
cpdef py_void SendMouseMoveEvent(self):
523+
pass
524+
525+
cpdef py_void SendMouseWheelEvent(self):
526+
pass
527+
528+
cpdef py_void SendFocusEvent(self):
529+
pass
530+
531+
cpdef py_void SendCaptureLostEvent(self):
532+
pass

0 commit comments

Comments
 (0)