diff options
Diffstat (limited to 'olpcgames/canvas.py')
-rwxr-xr-x | olpcgames/canvas.py | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/olpcgames/canvas.py b/olpcgames/canvas.py new file mode 100755 index 0000000..eda64a2 --- /dev/null +++ b/olpcgames/canvas.py @@ -0,0 +1,111 @@ +"""Implements bridge connection between Sugar/GTK and PyGame""" +import os +import sys +import threading +from pprint import pprint + +import pygtk +pygtk.require('2.0') +import gtk +import gobject +import pygame + +from olpcgames import gtkEvent, video + +__all__ = ['PyGameCanvas'] + +class PyGameCanvas(gtk.EventBox): + """Canvas providing bridge methods to run PyGame in GTK + + The PyGameCanvas creates a secondary thread in which the Pygame instance will + live, providing synthetic PyGame events to that thread via a Queue. The GUI + connection is done by having the PyGame canvas use a GTK Port object as it's + window pointer, it draws to that X-level window in order to produce output. + """ + def __init__(self, width, height): + """Initializes the Canvas Object + + width,height -- passed to the inner EventBox in order to request a given size, + the Socket is the only child of this EventBox, and the PyGame commands + will be writing to the Window ID of the socket. The internal EventBox is + centered via an Alignment instance within the PyGameCanvas instance. + + XXX Should refactor so that the internal setup can be controlled by the + sub-class, e.g. to get size from the host window, or something similar. + """ + # Build the main widget + super(PyGameCanvas,self).__init__() + self.set_flags(gtk.CAN_FOCUS) + + # Build the sub-widgets + self._align = gtk.Alignment(0.5, 0.5) + self._inner_evb = gtk.EventBox() + self._socket = gtk.Socket() + + + # Add internal widgets + self._inner_evb.set_size_request(width, height) + self._inner_evb.add(self._socket) + + self._socket.show() + + self._align.add(self._inner_evb) + self._inner_evb.show() + + self._align.show() + + self.add(self._align) + + # Construct a gtkEvent.Translator + self._translator = gtkEvent.Translator(self, self._inner_evb) + # <Cue Thus Spract Zarathustra> + self.show() + def connect_game(self, app): + """Imports the given main-loop and starts processing in secondary thread + + app -- fully-qualified Python path-name for the game's main-loop, with + name within module as :functionname, if no : character is present then + :main will be assumed. + + Side effects: + + Sets the SDL_WINDOWID variable to our socket's window ID + Calls PyGame init + Causes the gtkEvent.Translator to "hook" PyGame + Creates and starts secondary thread for Game/PyGame event processing. + """ + # Setup the embedding + os.environ['SDL_WINDOWID'] = str(self._socket.get_id()) + #print 'Socket ID=%s'%os.environ['SDL_WINDOWID'] + pygame.init() + + self._translator.hook_pygame() + + # Load the modules + # NOTE: This is delayed because pygame.init() must come after the embedding is up + if ':' not in app: + app += ':main' + mod_name, fn_name = app.split(':') + mod = __import__(mod_name, globals(), locals(), []) + fn = getattr(mod, fn_name) + + # Start Pygame + self.__thread = threading.Thread(target=self._start, args=[fn]) + self.__thread.start() + + def _start(self, fn): + """The method that actually runs in the background thread""" + import olpcgames + olpcgames.widget = self + try: + import sugar.activity.activity,os + except ImportError, err: + log.info( """Running outside Sugar""" ) + else: + os.chdir(sugar.activity.activity.get_bundle_path()) + + try: + fn() + finally: + gtk.main_quit() + |