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
4635import sys
4736try :
37+ # noinspection PyUnresolvedReferences
4838 from cefpython3 import cefpython as cef
4939except 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 )
5243try :
44+ # noinspection PyUnresolvedReferences
5345 import sdl2
46+ # noinspection PyUnresolvedReferences
5447 import sdl2 .ext
5548except 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 )
5852try :
53+ # noinspection PyUnresolvedReferences
5954 from PIL import Image
6055except 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+
6461def 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+
277280class 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
289293class 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
382390def 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+
388397if __name__ == "__main__" :
389398 main ()
0 commit comments