Qt: Handle a game crash without crashing
Jeffrey Pfau jeffrey@endrift.com
Fri, 19 Dec 2014 20:34:48 -0800
5 files changed,
27 insertions(+),
2 deletions(-)
M
src/platform/qt/GameController.cpp
→
src/platform/qt/GameController.cpp
@@ -73,7 +73,12 @@ };
m_threadContext.logHandler = [] (GBAThread* context, enum GBALogLevel level, const char* format, va_list args) { GameController* controller = static_cast<GameController*>(context->userData); - if (!(controller->m_logLevels & level)) { + if (level == GBA_LOG_FATAL) { + MutexLock(&controller->m_threadContext.stateMutex); + controller->m_threadContext.state = THREAD_EXITING; + MutexUnlock(&controller->m_threadContext.stateMutex); + QMetaObject::invokeMethod(controller, "crashGame", Q_ARG(const QString&, QString().vsprintf(format, args))); + } else if (!(controller->m_logLevels & level)) { return; } controller->postLog(level, QString().vsprintf(format, args));@@ -205,6 +210,11 @@ m_patch = QString();
m_gameOpen = false; emit gameStopped(&m_threadContext); +} + +void GameController::crashGame(const QString& crashMessage) { + closeGame(); + emit gameCrashed(crashMessage); } bool GameController::isPaused() {
M
src/platform/qt/GameController.h
→
src/platform/qt/GameController.h
@@ -64,6 +64,7 @@ void gameStarted(GBAThread*);
void gameStopped(GBAThread*); void gamePaused(GBAThread*); void gameUnpaused(GBAThread*); + void gameCrashed(const QString& errorMessage); void stateLoaded(GBAThread*); void postLog(int level, const QString& log);@@ -94,8 +95,10 @@ void setLogLevel(int);
void enableLogLevel(int); void disableLogLevel(int); -#ifdef BUILD_SDL private slots: + void crashGame(const QString& crashMessage); + +#ifdef BUILD_SDL void testSDLEvents(); private:
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -9,6 +9,7 @@ #include <QFileDialog>
#include <QKeyEvent> #include <QKeySequence> #include <QMenuBar> +#include <QMessageBox> #include <QStackedLayout> #include "ConfigController.h"@@ -74,6 +75,7 @@ #endif
connect(m_controller, SIGNAL(gameUnpaused(GBAThread*)), m_display, SLOT(unpauseDrawing())); connect(m_controller, SIGNAL(postLog(int, const QString&)), m_logView, SLOT(postLog(int, const QString&))); connect(m_controller, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(recordFrame())); + connect(m_controller, SIGNAL(gameCrashed(const QString&)), this, SLOT(gameCrashed(const QString&))); connect(m_logView, SIGNAL(levelsSet(int)), m_controller, SLOT(setLogLevel(int))); connect(m_logView, SIGNAL(levelsEnabled(int)), m_controller, SLOT(enableLogLevel(int))); connect(m_logView, SIGNAL(levelsDisabled(int)), m_controller, SLOT(disableLogLevel(int)));@@ -323,6 +325,14 @@ m_screenWidget->setScaledContents(false);
redoLogo(); m_fpsTimer.stop(); +} + +void Window::gameCrashed(const QString& errorMessage) { + QMessageBox* crash = new QMessageBox(QMessageBox::Critical, tr("Crash"), + tr("The game has crashed with the following error:\n\n%1").arg(errorMessage), + QMessageBox::Ok, this, Qt::Sheet); + crash->setAttribute(Qt::WA_DeleteOnClose); + crash->show(); } void Window::redoLogo() {
M
src/platform/qt/Window.h
→
src/platform/qt/Window.h
@@ -87,6 +87,7 @@
private slots: void gameStarted(GBAThread*); void gameStopped(); + void gameCrashed(const QString&); void redoLogo(); void recordFrame();