What kind of GUI's are there for SDL?
There are several GUI libraries written for SDL available from the SDL libraries page at http://www.libsdl.org/libraries.php .
This thread (1) mentions Guichan (C++) and Agar (C).
How to integrate SDL into an existing GUI application?
Sometimes, for example in the case of a game editor, it may be useful to use a windowed SDL for the graphics and a general-purpose GUI toolkit for the user interface.
There is no perfect solution for this, but there exists various ways to work around this.
Manually copy from non-window SDL_Surface to the GUI toolkit
You manipulate a SDL_Surface as usual, but you manually copy it as a pixel array to your tookit widget. This is the only technique that allow you to use SDL in several windows.
There is a nice demo for wxWidgets at http://code.technoplaza.net/wx-sdl/part1/ . The demo has some limitations:
It does not use SetVideoMode(), which apparently may break some features such as SDL_DisplayYUVOverlay (1). One can try to add putenv("SDL_VIDEODRIVER=dummy"); before SDL_Init(...);.
The code specifies no depth:
wxBitmap bmp(wxImage(screen->w, screen->h, static_cast<unsigned char *>(screen->pixels), true));
This works because the code in wxImage and wxBitmap hard-codes a 24bit depth with RGB byte order. This implies you need to use that depth spec; it won't work with another depth for your target SDL_Surface. You'll need to fix this in the demo code when creating the target SDL_Surface, otherwise colors may get swapped (blue<->red, etc.)
Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x00000000; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0x00000000; #endif screen = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, rmask, gmask, bmask, amask);
The mouse or keyboard events are caught by the GUI toolkit only, not by SDL.
Use MDI instead of SDI
That is, Multiple Document Interface instead of Single Document Interface (think Gimp vs. Photoshop).
You initialize SDL as usual, and call your favorite toolkit to create toolbars around the main SDL window.
See the double loop section for examples and limitations.
The SDL_WINDOWID hack
This makes SDL use an existing window instead of creating a new one. This works under X11 and Win32. Basically you putenv("SDL_WINDOWID=XXX") where XXX is an existing window's ID. You can only use it on one existing window (not several).
Code can be found for various toolkits:
- Gtk+ (v1):
draw on the window: http://www.libsdl.org/projects/gtk-demo/
new widget: http://gtksdl.sourceforge.net/
Compiler fixes: http://gtk.developpez.com/faq/?page=gtksdl (french)
Win32 issues: http://www.developpez.net/forums/showthread.php?t=202660 (french)
Proof-of-concept: http://sparcs.kaist.ac.kr/~tinuviel/devel/gtksdl.py (does not handle expose issues 1 2)
Similar code that disable DirectX: http://osdir.com/ml/python.pygame/2003-01/msg00107.html
gtkmm: http://lists.libsdl.org/pipermail/sdl-libsdl.org/2007-October/062896.html
gtmmm + Gtk plug/socket: http://www.mail-archive.com/gtkmm-list@gnome.org/msg08601.html
wxWidgets: http://lists.wxwidgets.org/archive/wx-users/msg81102.html
You do not receive the usual SDL events for this solution.
Gtk socket
Using Gtk socket is mentioned in the SDL_WINDOWID section, because you can put SDL in a socket by passing the socket id to SDL_WINDOWID.
The other way around, does not involved SDL_WINDOWID, somewhat works too: passing the SDL window ID (pygame.display.get_wm_info().get("window")) to a Gtk socket (socket.add_id()). Since you "steal" SDL out of an existing window, you get a now-empty original SDL window lying around.
1 implies input can work with the Gtk socket technique. According to my tests, the window events are handled by the original empty window, and the mouse / keyboard events by the stolen graphics display in the socket window.
Double event loop issue
When combining SDL and a GUI, and where your technique supports SDL events, there will be two event loops. Both need to run at the same time!
Work-arounds:
- Grab one toolkit event at a time, instead of starting the main "magic" tookit event loop.
This Tcl/Tk + SDL hack written by Kent Mein use the MDI technique: http://www.libsdl.org/projects/tcl-demo/ . It grabs one Tk event (Tk_DoOneEvent) in an otherwise classic SDL_PollEvent loop. Your toolkit has to support such a fine-grained rewrite of the main event loop.
This snippet uses PyGtk's gtk.main_iteration(block=False). The author reports priority conflicts though.
- Poll the SDL events when inside toolkit event loop:
wxWidgets: the example from technoplaza displays the updated SDL surface during wxWindow's OnIdle: you can easily add a PollEvent() there.
Gtk2: there's a similar function called g_idle_add
- Set an arbitrary timer (e.g. 70ms) with your toolkit (QTimer, g_timeout_add...) and check SDL events in the timer callback.
You'll need to read the events if you want SDL to refresh the window when it's repainted (hidden behind another window, etc.).
putenv or SDL_putenv?
Apparently SDL_putenv takes care of tricky situations where the environment is not the same in the application and in the library: http://lists.libsdl.org/htdig.cgi/sdl-libsdl.org/2005-September/051604.html
Not tested though.
