Skip to content

Commit ddd6264

Browse files
committed
Update pysdl2.py example and add link to README-Examples.md
1 parent acaf76b commit ddd6264

File tree

2 files changed

+85
-73
lines changed

2 files changed

+85
-73
lines changed

examples/README-examples.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ workarounds.
4343
library (GTK 2)
4444
- [gtk3.py](gtk3.py): example for [PyGObject / PyGI](https://wiki.gnome.org/Projects/PyGObject)
4545
library (GTK 3). Currently broken on Mac ([#310](../../../issues/310)).
46+
- [pysdl2.py](pysdl2.py): off-screen rendering example for
47+
[PySDL2](https://github.com/marcusva/py-sdl2) library. Currently tested
48+
only on Linux.
4649
- [pywin32.py](pywin32.py): example for [pywin32](https://github.com/mhammond/pywin32)
4750
library
4851
- [qt.py](qt.py): example for [PyQt4](https://wiki.python.org/moin/PyQt4),

examples/pysdl2.py

Lines changed: 82 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,68 @@
11
"""
2-
Simple SDL2 / cefpython3 example.
2+
Example of embedding CEF browser using PySDL2 library.
33
4-
Requires pysdl2 (and SDL2 library).
5-
6-
Tested configurations:
7-
- SDL2 2.0.5 with PySDL2 0.9.3 on Fedora 25 (x86_64)
8-
- SDL2 with PySDL2 0.9.5 on Ubuntu 14.04
4+
This example is incomplete, see "Missing functionality" section
5+
further down. Pull requests for the missing functionality are welcome.
96
10-
Install instructions.
11-
12-
1. Install SDL libraries for your OS, e.g:
7+
Requires PySDL2 and SDL2 libraries.
138
14-
Fedora:
15-
16-
sudo dnf install SDL2 SDL2_ttf SDL2_image SDL2_gfx SDL2_mixer
17-
18-
Ubuntu:
19-
20-
sudo apt-get install libsdl2-dev
21-
22-
2. Install PySDL via PIP:
9+
Tested configurations:
10+
- Fedora 25: SDL2 2.0.5 with PySDL2 0.9.3
11+
- Ubuntu 14.04: SDL2 with PySDL2 0.9.6
2312
24-
sudo pip2 install PySDL2
13+
Install instructions:
14+
1. Install SDL libraries for your OS, e.g:
15+
- Fedora: sudo dnf install SDL2 SDL2_ttf SDL2_image SDL2_gfx SDL2_mixer
16+
- Ubuntu: sudo apt-get install libsdl2-dev
17+
2. Install PySDL2 using pip package manager:
18+
pip install PySDL2
2519
26-
Event handling:
27-
28-
Where possible SDL2 events are mapped to CEF ones. Not all keyboard
29-
modifiers are handled in this example but these could be
30-
added by the reader (if desired). Modifiers that do not work
31-
for example:
32-
33-
- Ctrl
34-
- Mouse dragging
35-
- Marking text inputs with the shift key
36-
37-
Due to SDL2's lack of GUI widgets there are no GUI controls
38-
for the user. However, as an exercise this example could
39-
be extended by create some simple SDL2 widgets. An example of
40-
widgets made using PySDL2 can be found as part of the Pi
41-
Entertainment System at:
42-
https://github.com/neilmunday/pes/blob/master/lib/pes/ui.py
20+
Missing functionality:
21+
- Keyboard modifiers that are not yet handled in this example:
22+
ctrl, marking text inputs with the shift key.
23+
- Mouse dragging
24+
- Window size is fixed, cannot be resized
25+
26+
GUI controls:
27+
Due to SDL2's lack of GUI widgets there are no GUI controls
28+
for the user. However, as an exercise this example could
29+
be extended by create some simple SDL2 widgets. An example of
30+
widgets made using PySDL2 can be found as part of the Pi
31+
Entertainment System at:
32+
https://github.com/neilmunday/pes/blob/master/lib/pes/ui.py
4333
"""
4434

45-
import os
4635
import sys
4736
try:
37+
# noinspection PyUnresolvedReferences
4838
from cefpython3 import cefpython as cef
4939
except ImportError:
50-
print("cefpython3 module not found - please install")
40+
print("ERROR: cefpython3 package not found")
41+
print("To install type: `pip install cefpython3`")
5142
sys.exit(1)
5243
try:
44+
# noinspection PyUnresolvedReferences
5345
import sdl2
46+
# noinspection PyUnresolvedReferences
5447
import sdl2.ext
5548
except ImportError:
56-
print("SDL2 module not found - please install")
49+
print("ERROR: SDL2 package not found")
50+
print("To install type: `pip install PySDL2`")
5751
sys.exit(1)
5852
try:
53+
# noinspection PyUnresolvedReferences
5954
from PIL import Image
6055
except ImportError:
61-
print("PIL module not found - please install")
56+
print("ERROR: PIL package not found")
57+
print("To install type: pip install Pillow")
6258
sys.exit(1)
6359

60+
6461
def main():
6562
# The following variables control the dimensions of the window
6663
# and browser display area
67-
width = 1024
68-
height = 768
64+
width = 800
65+
height = 600
6966
# headerHeight is useful for leaving space for controls
7067
# at the top of the window (future implementation?)
7168
headerHeight = 0
@@ -74,7 +71,6 @@ def main():
7471
# Mouse wheel fudge to enhance scrolling
7572
scrollEnhance = 20
7673
# Initialise CEF for offscreen rendering
77-
WindowUtils = cef.WindowUtils()
7874
sys.excepthook = cef.ExceptHook
7975
cef.Initialize(settings={"windowless_rendering_enabled": True})
8076
window_info = cef.WindowInfo()
@@ -95,7 +91,8 @@ def main():
9591
# Define default background colour (black in this case)
9692
backgroundColour = sdl2.SDL_Color(0, 0, 0)
9793
# Create the renderer using hardware acceleration
98-
renderer = sdl2.SDL_CreateRenderer(window, -1, sdl2.render.SDL_RENDERER_ACCELERATED)
94+
renderer = sdl2.SDL_CreateRenderer(window, -1,
95+
sdl2.render.SDL_RENDERER_ACCELERATED)
9996
# Set-up the RenderHandler, passing in the SDL2 renderer
10097
renderHandler = RenderHandler(renderer, width, height - headerHeight)
10198
# Create the browser instance
@@ -107,15 +104,16 @@ def main():
107104
browser.SendFocusEvent(True)
108105
browser.WasResized()
109106
# Begin the main rendering loop
110-
shiftDown = False
111107
running = True
112108
while running:
113109
# Convert SDL2 events into CEF events (where appropriate)
114110
events = sdl2.ext.get_events()
115111
for event in events:
116-
if event.type == sdl2.SDL_QUIT or (event.type == sdl2.SDL_KEYDOWN and event.key.keysym.sym == sdl2.SDLK_ESCAPE):
117-
running = False
118-
break
112+
if (event.type == sdl2.SDL_QUIT
113+
or (event.type == sdl2.SDL_KEYDOWN
114+
and event.key.keysym.sym == sdl2.SDLK_ESCAPE)):
115+
running = False
116+
break
119117
if event.type == sdl2.SDL_MOUSEBUTTONDOWN:
120118
if event.button.button == sdl2.SDL_BUTTON_LEFT:
121119
if event.button.y > headerHeight:
@@ -141,7 +139,9 @@ def main():
141139
elif event.type == sdl2.SDL_MOUSEMOTION:
142140
if event.motion.y > headerHeight:
143141
# Mouse move triggered in browser region
144-
browser.SendMouseMoveEvent(event.motion.x, event.motion.y - headerHeight, False)
142+
browser.SendMouseMoveEvent(event.motion.x,
143+
event.motion.y - headerHeight,
144+
False)
145145
elif event.type == sdl2.SDL_MOUSEWHEEL:
146146
# Mouse wheel event
147147
x = event.wheel.x
@@ -156,7 +156,8 @@ def main():
156156
y += scrollEnhance
157157
browser.SendMouseWheelEvent(0, 0, x, y)
158158
elif event.type == sdl2.SDL_TEXTINPUT:
159-
# Handle text events to get actual characters typed rather than the key pressed
159+
# Handle text events to get actual characters typed rather
160+
# than the key pressed.
160161
keycode = ord(event.text.text)
161162
key_event = {
162163
"type": cef.KEYEVENT_CHAR,
@@ -196,8 +197,8 @@ def main():
196197
sdl2.SDLK_HOME,
197198
sdl2.SDLK_END
198199
]:
199-
keycode = getKeyCode(event.key.keysym.sym)
200-
if keycode != None:
200+
keycode = get_key_code(event.key.keysym.sym)
201+
if keycode is not None:
201202
key_event = {
202203
"type": cef.KEYEVENT_RAWKEYDOWN,
203204
"windows_key_code": keycode,
@@ -219,8 +220,8 @@ def main():
219220
sdl2.SDLK_HOME,
220221
sdl2.SDLK_END
221222
]:
222-
keycode = getKeyCode(event.key.keysym.sym)
223-
if keycode != None:
223+
keycode = get_key_code(event.key.keysym.sym)
224+
if keycode is not None:
224225
key_event = {
225226
"type": cef.KEYEVENT_KEYUP,
226227
"windows_key_code": keycode,
@@ -251,10 +252,11 @@ def main():
251252
sdl2.SDL_RenderPresent(renderer)
252253
# User exited
253254
exit_app()
254-
255-
def getKeyCode(key):
255+
256+
257+
def get_key_code(key):
256258
"""Helper function to convert SDL2 key codes to cef ones"""
257-
keyMap = {
259+
key_map = {
258260
sdl2.SDLK_RETURN: 13,
259261
sdl2.SDLK_DELETE: 46,
260262
sdl2.SDLK_BACKSPACE: 8,
@@ -265,26 +267,28 @@ def getKeyCode(key):
265267
sdl2.SDLK_HOME: 36,
266268
sdl2.SDLK_END: 35,
267269
}
268-
if key in keyMap:
269-
return keyMap[key]
270+
if key in key_map:
271+
return key_map[key]
270272
# Key not mapped, raise exception
271-
print("Keyboard mapping incomplete: \
272-
unsupported SDL key %d. \
273-
See https://wiki.libsdl.org/SDLKeycodeLookup for mapping."
274-
% key)
273+
print("[pysdl2.py] Keyboard mapping incomplete:"
274+
" unsupported SDL key %d."
275+
" See https://wiki.libsdl.org/SDLKeycodeLookup for mapping."
276+
% key)
275277
return None
276278

279+
277280
class LoadHandler(object):
278281
"""Simple handler for loading URLs."""
279282

280-
def OnLoadingStateChange(self, browser, is_loading, **_):
283+
def OnLoadingStateChange(self, is_loading, **_):
281284
if not is_loading:
282-
print("loading complete")
285+
print("[pysdl2.py] Page loading complete")
283286

284-
def OnLoadError(self, browser, frame, error_code, failed_url, **_):
287+
def OnLoadError(self, frame, failed_url, **_):
285288
if not frame.IsMain():
286289
return
287-
print("Failed to load %s" % failed_url)
290+
print("[pysdl2.py] Failed to load %s" % failed_url)
291+
288292

289293
class RenderHandler(object):
290294
"""
@@ -306,7 +310,7 @@ def GetViewRect(self, rect_out, **_):
306310
rect_out.extend([0, 0, self.__width, self.__height])
307311
return True
308312

309-
def OnPaint(self, browser, element_type, paint_buffer, **_):
313+
def OnPaint(self, element_type, paint_buffer, **_):
310314
"""
311315
Using the pixel data from CEF's offscreen rendering
312316
the data is converted by PIL into a SDL2 surface
@@ -323,6 +327,8 @@ def OnPaint(self, browser, element_type, paint_buffer, **_):
323327
# Following PIL to SDL2 surface code from pysdl2 source.
324328
mode = image.mode
325329
rmask = gmask = bmask = amask = 0
330+
depth = None
331+
pitch = None
326332
if mode == "RGB":
327333
# 3x8-bit, 24bpp
328334
if sdl2.endian.SDL_BYTEORDER == sdl2.endian.SDL_LIL_ENDIAN:
@@ -353,7 +359,7 @@ def OnPaint(self, browser, element_type, paint_buffer, **_):
353359
depth = 32
354360
pitch = self.__width * 4
355361
else:
356-
print("Unsupported mode: %s" % mode)
362+
print("[pysdl2.py] ERROR: Unsupported mode: %s" % mode)
357363
exit_app()
358364

359365
pxbuf = image.tobytes()
@@ -373,17 +379,20 @@ def OnPaint(self, browser, element_type, paint_buffer, **_):
373379
# free memory used by previous texture
374380
sdl2.SDL_DestroyTexture(self.texture)
375381
# Create texture
376-
self.texture = sdl2.SDL_CreateTextureFromSurface(self.__renderer, surface)
382+
self.texture = sdl2.SDL_CreateTextureFromSurface(self.__renderer,
383+
surface)
377384
# Free the surface
378385
sdl2.SDL_FreeSurface(surface)
379386
else:
380-
print("Unsupport element_type in OnPaint")
387+
print("[pysdl2.py] WARNING: Unsupport element_type in OnPaint")
388+
381389

382390
def exit_app():
383391
"""Tidy up SDL2 and CEF before exiting."""
384392
sdl2.SDL_Quit()
385393
cef.Shutdown()
386-
print("exited")
387-
394+
print("[pysdl2.py] Exited gracefully")
395+
396+
388397
if __name__ == "__main__":
389398
main()

0 commit comments

Comments
 (0)