Skip to content

Instantly share code, notes, and snippets.

@Smashbolt
Last active March 12, 2025 14:00
wxWindows + SDL
#include <wx/wx.h>
#include <SDL.h>
#include <iostream>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
class MyApp : public wxApp
{
public:
bool OnInit() override;
};
class MyFrame : public wxFrame
{
public:
MyFrame();
~MyFrame();
private:
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void OnRender(wxTimerEvent& event);
void InitSDL(wxPanel* sdlPanel);
SDL_Window* sdlWindow;
SDL_Renderer* sdlRenderer;
wxTimer renderTimer; // Timer used to drive SDL rendering
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
MyFrame* frame = new MyFrame();
frame->Show(true);
return true;
}
MyFrame::MyFrame()
: wxFrame(nullptr, wxID_ANY, "wxWidgets with Embedded SDL", wxDefaultPosition, wxSize(800, 600)),
sdlWindow(nullptr), sdlRenderer(nullptr)
{
// Setup menu bar
wxMenu* menuFile = new wxMenu;
menuFile->Append(wxID_EXIT);
wxMenu* menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
wxMenuBar* menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&File");
menuBar->Append(menuHelp, "&Help");
SetMenuBar(menuBar);
CreateStatusBar();
Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT);
Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT);
// Add a wxPanel in the frame for SDL content
auto* sdlPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxBORDER_NONE);
sdlPanel->SetBackgroundColour(*wxBLACK);
// Create a sizer to layout components properly
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(sdlPanel, 1, wxEXPAND); // SDL panel expands to fill the layout
SetSizer(sizer);
// Bind wxEVT_SHOW to initialize SDL after the frame is shown
this->Bind(wxEVT_SHOW, [this, sdlPanel](wxShowEvent& event) {
if (event.IsShown()) {
InitSDL(sdlPanel);
}
event.Skip();
});
}
void MyFrame::InitSDL(wxPanel* sdlPanel)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL_Init Error: " << SDL_GetError() << '\n';
Close(true);
return;
}
// Get the native handle of the wxPanel
auto windowHandle = sdlPanel->GetHandle();
if (!windowHandle) {
std::cerr << "Failed to retrieve wxPanel handle!\n";
Close(true);
return;
}
GtkWidget* widget = static_cast<GtkWidget*>(windowHandle);
gtk_widget_realize(widget); // Ensure the widget is realized before getting the GdkWindow
GdkWindow* gdkWindow = gtk_widget_get_window(widget);
if (!gdkWindow) {
std::cerr << "Failed to retrieve GDK window from GTK widget!\n";
Close(true);
return;
}
Window x11WindowHandle = GDK_WINDOW_XID(gdkWindow);
if (!x11WindowHandle) {
std::cerr << "Failed to retrieve X11 window handle!\n";
Close(true);
return;
}
// Create SDL window from X11 handle
sdlWindow = SDL_CreateWindowFrom(reinterpret_cast<void*>(x11WindowHandle));
if (!sdlWindow) {
std::cerr << "SDL_CreateWindowFrom failed" << SDL_GetError() << '\n';
SDL_Quit();
Close(true);
return;
}
sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (!sdlRenderer) {
// Fallback to software driver if accelerated renderer fails
std::cerr << "SDL_CreateRenderer failed: " << SDL_GetError() << '\n';
std::cerr << "Retrying with software renderer...\n";
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_SOFTWARE);
if (!sdlRenderer) {
std::cerr << "SDL_CreateRenderer (software fallback) failed: " << SDL_GetError() << '\n';
SDL_DestroyWindow(sdlWindow);
sdlWindow = nullptr;
SDL_Quit();
Close(true);
return;
}
}
std::cout << "SDL Renderer successfully created with driver" << SDL_GetCurrentVideoDriver() << '\n';
// Setup a wxTimer to drive SDL rendering
renderTimer.Bind(wxEVT_TIMER, &MyFrame::OnRender, this);
renderTimer.Start(16); // Approx 60 FPS
std::cout << "wxWidgets and SDL successfully initialized!\n";
}
MyFrame::~MyFrame()
{
renderTimer.Stop();
if (sdlRenderer)
{
SDL_DestroyRenderer(sdlRenderer);
sdlRenderer = nullptr;
}
if (sdlWindow)
{
SDL_DestroyWindow(sdlWindow);
sdlWindow = nullptr;
}
SDL_Quit();
}
void MyFrame::OnExit(wxCommandEvent& event)
{
Close(true);
}
void MyFrame::OnAbout(wxCommandEvent& event)
{
wxMessageBox("SDL embedded in wxWindows",
"About", wxOK | wxICON_INFORMATION);
}
void MyFrame::OnRender(wxTimerEvent& event)
{
if (!sdlRenderer)
return;
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_Rect rect = {100, 100, 200, 150};
SDL_SetRenderDrawColor(sdlRenderer, 255, 0, 0, 255);
SDL_RenderFillRect(sdlRenderer, &rect);
SDL_RenderPresent(sdlRenderer);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment