Concerning SDL2 as a GTK2 form control in Pascal/Lazarus
Skip table of contentsI hop between Windows 10 and Linux Mint constantly. The basic Lazarus components work fine without much changes need, if any at all. However, I wanted to use SDL2 as a form component because CPU rendering was too slow for my needs. I had for the first time to actually use compile time conditionals for these GTK2 specific problems to get SDL2 running without any issues on Linux Mint.
SDL2 for Pascal
Before continuing, I have to mention that I’m using the SDL2-for-Pascal units found on GitHub. There you can find more details about how to install and use the Pascal units. For more information visit FreePascal-meets-SDL.net.
Facing some problems
I’m using the bare minimum of SDL2 just to draw a single texture to screen. SDL2 works auto-magically on Windows, but I needed to do some actual work on Linux to make it work properly.
- acquiring the pointer needed for
SDL_CreateWindowFrom()was more complex and needed GTK2 specific libraries; - with trial and error I discovered that
TOpenGLControlfrom LazOpenGLContext package works best as an SDL2 window (while on Windows a simpleTPanelworks just fine); OnPaintdoesn’t seem to work onTOpenGLControlwhen callingInvalidate(). I only managed to get it working by assigning its Parent anOnPaintevent while also being forced to callInvalidate()on said Parent (but bothOnPaintandInvalidate()work onTOpenGLControlin Windows, go figure);- having to manually call
SDL_SetWindowSize()for proper control resizing (happens auto-magically in Windows).
Some relevant code
Starting with the uses block, these are the most relevant units for making SDL2 work as a form control.
uses
{$IFDEF LCLGTK2}
gtk2, gdk2x,
{$ENDIF}
OpenGLContext, SDL2;
Getting the pointer for the control handle is a bit more complicated in Mint than it is on Windows when it comes to SDL2 window creation (I found this snippet online but can’t recall where).
{$IFDEF LCLGTK2}
// Linux with GTK2 widget-set
sdlWindow := SDL_CreateWindowFrom(Pointer(GDK_WINDOW_XWINDOW(PGtkWidget(PtrUInt(OpenGLControl.Handle))^.window)));
{$ELSE}
// My targets are Windows and Linux (GTK2) so a simple ELSE works
sdlWindow := SDL_CreateWindowFrom(Pointer(OpenGLControl.Handle));
{$ENDIF}
Naturally, SDL_SetWindowSize() needs to be called preferably in the OnPaint event (keeping in mind that OnPaint nor Invalidate() seem to not be working with TOpenGLControl on Linux so assign/use them on the TOpenGLControl’s parent instead).
{$IFDEF LCLGTK2}
SDL_GetWindowSize(sdlWindow, @currentWidth, @currentHeight);
if (currentWidth <> actualWidth) or (currentHeight <> actualHeight) then
SDL_SetWindowSize(sdlWindow, actualWidth, actualHeight);
{$ENDIF}