Lessons on native window/SDL integration.

05 May 2011
Tags: rlvm

libSDL is great for doing simple, cross-platform game development, though it’s currently showing its age a bit. I recently tried ripping out a set of in game widgets from rlvm and replaced them with native GTK+ and Cocoa interfaces. I had to backtrack because fullscreen broke HARD, though I’m putting down these notes so the next brave soul to come through knows the ups and downs.

SDL doesn’t make this easy, but you can sort of do this as long as you don’t want to mix SDL content and native widgets in the same window and you don’t have a fullscreen option. Native right-click menus and dialogs are possible. It just takes a bit of work on each platform. This is more a rambling list of things you might want to keep in mind.

  • The Cocoa port of SDL gives you a real NSWindow; if you’re using the Cocoa SDLMain library you already have a real NSApplication too, which you can customize and add categories to. Interacting with Cocoa elements (NSAlerts, NSMenus, etc) seems to pause the SDL’s timer. I’m not sure if most actions are spinning up a nested runloop, but the programmer doesn’t need to do anything custom event handling to get NSAlerts and NSMenus running.

  • The X11 port of SDL gives you no such help if you want to integrate with GTK+. Any interaction you want to do needs to be through raw xlib calls. You’ll need to consider the following:

    a. You’ll need to collaborate with GTK’s runloop, which means calling while (gtk_events_pending()) gtk_main_iteration(); each iteration through the gameloop to handle events on GTK+ windows.

    b. You’ll need to pause your game manually while native dialogs are up. Make sure to offset the number of ticks supplied by SDL_GetTicks() if you use that for animation or other timing.

    c. You’ll need to manually do all window management. GTK+ has nice functions for hinting to the OS that one window is a dialog of another window. You will need to do all the emulation of this yourself. You’ll need to handle the position of dialogs manually and you’ll need to emulate dialog modality by bringing the current GTK+ dialog window to the front on mouse and activate events.

    d. If you have right click menus that are dismissed on mousedown, the mouseup event might get passed to SDL. Your SDL event handling has to deal with this case.

    e. Relatively minor, but SDL_WM_SetIcon() only takes a single SDL_Surface for its icon. Most modern applications have their icons drawn in multiple sizes. rlvm’s 16x16 small application icon is different from its 64x64 and larger icon. If you want to handle this correctly, you’ll need to set this manually in raw xlib.

  • Make sure to call SDL_WM_SetCaption() after calling SDL_Init(), but before calling SDL_SetVideoMode() with the correct iconified name of your program. Some newer Linux docks will get confused and won’t attribute your new window to your application if you’ve already opened up a GTK+ window.

  • If you have a fullscreen option, you should either disable it or give up on your native dialog integration project. In both the X11 and Cocoa ports, trying to bring up a dialog while the SDL window is fullscreen doesn’t display the dialog. This made me abandon dialogs during gameplay, but you can still use some of the above to show native dialogs before you bring up your SDL window. ( If you want an example of how something like this is implemented, the platform directories in rlvm (Cocoa, GTK+) make good reading.)