wxWidgets external mainloop

Started by
1 comment, last by remdul 14 years, 6 months ago
I'm trying to implement a build-in text editor into our game engine, but having trouble to integrate it. The editor is build with wxWidgets, but wx documentation on how to implement external main loops is scarce (demo/code samples seem to be non-existent). CEditor is a wrapper class that will implement a simple wx based text editor (CEditApp, derived from wxApp), which sits in it's own independent window. I can already compile it as stand-alone application via IMPLEMENT_APP(CEditApp) without changes, so I know the code is functional (and dare I say, bug-free). Some pseudo-code: (Warning to googlers from the future; the below code will probably not work for you!)

// initialize wx application
bool CEditor::Init(HINSTANCE blah)
{
 app = new CEditApp;
 wxApp::SetInstance( app );  // supposedly this is not needed, but harmless
 wxEntry(inst,blah);         // <--- crash!
 return true;
}

// handle all wx application related events
void CEditor::ProcessEvents()
{
 if (!app) return;
 
 // process events here:
 // * mouse/keyboard input
 // * redraw window/controls etc.
 
 // no idea how to do this at all
}

// unload wx application
void CEditor::Unload()
{
 if (!app) return;
 app->OnExit();
 //wxApp::CleanUp();           // <--- does not even compile
 delete app;
 app = NULL;
}

// and this is the 
int WinMain(HINSTANCE inst, blah)
{
 // init stuff
 Simulation.Init();
 Editor.Init( inst );
 
 // engine main loop
 while (!exit)
 {
  // do lots of stuff
  Simulation.Input();
  Simulation.Integrate(timestep);
  Simulation.Draw();
  // etc.  
  
  // and also handle editor events
  Editor.ProcessEvents();
 }
 
 // shutdown
 Editor.Unload();
 Simulation.Unload();
 
 return 0;
}
The parts I'm struggling with: 1) Crash when wxEntry is called. I've tried both the cross platform version and the Windows version of this function. In either case, a crash occurs which I can trace to the editor window resize event (::OnResize). But I know the app runs flawlessly stand-alone, so this is probably related to the wxApp initialization (or lack thereof). I also create a window via SDL, GL context and render to it, but I think it should not interfere (I'll test this to be sure). 2) The main loop. wxWidgets prefers you to surrender your own mainloop to the build-in wx mainloop (aka MessageLoop/EventLoop). However, I cannot change my entire engine framework just for this, and also, the engine can be compiled without editor (thus without wxWidgets dependency). Button clicks, dropdown menus, common dialogs, etc. halting the game mainloop is not a problem, and in fact is desirable (I would run the editor in a separate thread if do not I want that). The only documentation I can find about this is to override the internal wx MainLoop, but that's not what I'm looking for. What I need is something like wxApp::ProcessEvents(), that processes all pending window messages, and redraws the window and controls. I guess I will have to manually implement that, but I cannot find exactly what the default wx MainLoop is supposed to call (I guess I will have to dig into the guts of wxWidgets itself). Any pointers? 3) Cleanup. The wxWiki refers to wxApp::CleanUp() but I have no idea in what context it is intended to be used. I cannot produce any code with this line that compiles. Many thanks if you can help me out! :) [Edited by - remdul on June 25, 2009 1:45:05 PM]
Advertisement
*nudge*
Found a solution: custom implementation of the WX functions, and replacing GetMessage with PeekMessage. Sadly, Windows-only code, but likely you can do the equivalent on other platforms, or even more likely you won't have this problem on any platform but Windows anyway.

Code snippet:
// initializes editorbool CEditor::Init(){ // already initialized if (app) return true;  // create app app = new CEditApp;  // initialize wxWidgets if (wxInitialize(0,0)) {  Console.Printf(">>> wxWidgets initialized.\n"); } else {  Console.Printf(">>> Failed to initialize wxWidgets.\n");  return false; }  // initialize app app->OnInit(); // success return true;}// processes events for editorvoid CEditor::ProcessEvents(){ if (!app) return; MSG msg; HWND hwnd = (HWND)app->GetWindowHandle(); while (true) {  if (!PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) break;  ::TranslateMessage(&msg);  ::DispatchMessage(&msg); }}// unloads editorvoid CEditor::Unload(){ if (!app) return; wxTheApp->OnExit(); delete app; app = NULL;}

If you use SDL like I did, you must call run the PeekMessage loop before SDL_PollEvents, because SDL will steal *all* messages headed to the application, not only the SDL window. Make sure to pass the WX window handle to PeekMessage, or you will intercept the messages intended for the SDL window in the same way, and your SDL window will starve to death.

*Edit: It appears that "wxCheckForInterrupt" can replace the entire content of CEditor::ProcessEvents() in the above code, it does the exact same and is cross-platform.

[Edited by - remdul on October 14, 2009 12:00:46 PM]

This topic is closed to new replies.

Advertisement