Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using SDL2 with wxWidgets 3.0

Tags:

c++

sdl

wxwidgets

My goal is to build a Game Boy emulator. In order to do this, I would like to embed an SDL2 surface into a wxWidgets window.

I found this tutorial: http://code.technoplaza.net/wx-sdl/part1/, but my program crashes as soon as I run it. However I suspect this was intended for SDL1.2. Part of the program is shown below.

It seems that if I call SDL_Init() and also attempt to show a wxFrame (which, in this case, is MainWindow), it shows the window for a second and then the program crashes. I commented all other calls to SDL in my program so far, so it seems the problem lies with calling Show() on a wxFrame and initing SDL2 in the same program.

So the question is: can SDL2 and wxWidgets 3 work together? If not, could you guys suggest to me good alternatives a GUI of a Game Boy emulator? Does wxWidgets have its own graphics frame like Qt does (I'd rather avoid Qt)?

Thanks very much!

#include "MainApp.h"
#include "MainWindow.h"

#include <stdexcept>

namespace GBEmu {


static void initSDL() {

    //This and SDL_Quit() are the only calls to the SDL library in my code
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
       throw std::runtime_error("Fatal Error: Could not init SDL");
    }
}


bool MainApp::OnInit()
{
    try {
        //If I comment out this line, the MainWindow wxFrame shows up fine.
        //If I leave both uncommented, the window shows up quickly and then 
        //crashes.
        initSDL();


        //If I comment out this line and leave initSDL() uncommented,
        //the program will not crash, but just run forever.
        (new MainWindow("GBEmu", {50,50}, {640,480}))->Show(); 


    } catch(std::exception &e) {
        wxLogMessage(_("Fatal Error: " + std::string(e.what())));
    }

    return true;
}

int MainApp::OnExit() {
    SDL_Quit();

    return wxApp::OnExit();
}


}


wxIMPLEMENT_APP(GBEmu::MainApp);

EDIT: Here is more information on how it crashes: It crashes with a Segfault in what seems to be the pthread_mutex_lock disassembly file. This is the output in the console with stack trace:

Starting /home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx...
The program has unexpectedly finished.
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx crashed

Stack trace:
Error: signal 11:
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx(_ZN5GBEmu7handlerEi+0x1c)[0x414805]
/lib/x86_64-linux-gnu/libc.so.6(+0x36ff0)[0x7fb88e136ff0]
/lib/x86_64-linux-gnu/libpthread.so.0(pthread_mutex_lock+0x30)[0x7fb88c12ffa0]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XrmQGetResource+0x3c)[0x7fb88d1ca15c]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XGetDefault+0xc2)[0x7fb88d1a7a92]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x94dcf)[0x7fb88af8edcf]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x97110)[0x7fb88af91110]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(cairo_surface_get_font_options+0x87)[0x7fb88af63e07]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2b61f)[0x7fb88af2561f]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2ef95)[0x7fb88af28f95]

This is a screenshot of where it seems to fail (line 7):

enter image description here

Update: In my MainWindow class, I attach a menu bar to the window. However, it seems when I comment out the setting of the menu bar, the window will show up fine even with initing of SDL. The menu bar will show up fine if I have initSDL() commented out but not the setting of the menu bar. Here is where I set the menu bar:

MainWindow::MainWindow(const wxString &title, const wxPoint &pos, const wxSize &size)
    :wxFrame(nullptr, wxIDs::MainWindow, title, pos, size){

  wxMenu *fileMenu = new wxMenu;
    fileMenu->Append(wxID_EXIT);

    wxMenuBar *menuBar = new wxMenuBar;

    menuBar->Append(fileMenu, "&File");

    //commenting this line out will allow the window to showup
    //and not crash the program
    SetMenuBar(menuBar);



}
like image 324
DanB91 Avatar asked Jul 19 '14 06:07

DanB91


1 Answers

You are experiencing an old heisenbug.

The workaround is simple: you have to initialize SDL before wxWidgets (basically, before GTK). To achieve this, you have to change

wxIMPLEMENT_APP(GBEmu::MainApp);

to

wxIMPLEMENT_APP_NO_MAIN(GBEmu::MainApp);

so that wxWidgets doesn't hijack your main().

Then you have to create main() manually. In it, initialize SDL, then call wxEntry():

int main(int argc, char** argv)
{
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    {
        std::cerr << "Could not initialize SDL.\n";
        return 1;
    }

    return wxEntry(argc, argv);
}

More about the bug:

I have googled around a bit and found that this bug has come up in a few places over the years. There are open reports in many bug trackers that have stack traces very similar to the one you get here (with debug symbols).

The oldest report I could find is from 2005 (!!) from the cairo bug tracker (https://bugs.freedesktop.org/show_bug.cgi?id=4373).

My best guess is that the real hiding place of this bug in either in GTK, cairo, or X. Unfortunately I do not currently have the time to look into it more in depth.

like image 104
RudolfW Avatar answered Sep 20 '22 16:09

RudolfW