mirror of https://github.com/mgba-emu/mgba.git
Qt: Handle a game crash without crashing
This commit is contained in:
parent
802e4b8720
commit
9aed9754d0
1
CHANGES
1
CHANGES
|
@ -12,6 +12,7 @@ Bugfixes:
|
||||||
Misc:
|
Misc:
|
||||||
- Qt: Disable sync to video by default
|
- Qt: Disable sync to video by default
|
||||||
- GBA: Exit cleanly on FATAL if the port supports it
|
- GBA: Exit cleanly on FATAL if the port supports it
|
||||||
|
- Qt: Handle a game crash without crashing
|
||||||
|
|
||||||
0.1.0: (2014-12-13)
|
0.1.0: (2014-12-13)
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|
|
@ -73,7 +73,12 @@ GameController::GameController(QObject* parent)
|
||||||
|
|
||||||
m_threadContext.logHandler = [] (GBAThread* context, enum GBALogLevel level, const char* format, va_list args) {
|
m_threadContext.logHandler = [] (GBAThread* context, enum GBALogLevel level, const char* format, va_list args) {
|
||||||
GameController* controller = static_cast<GameController*>(context->userData);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
controller->postLog(level, QString().vsprintf(format, args));
|
controller->postLog(level, QString().vsprintf(format, args));
|
||||||
|
@ -207,6 +212,11 @@ void GameController::closeGame() {
|
||||||
emit gameStopped(&m_threadContext);
|
emit gameStopped(&m_threadContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameController::crashGame(const QString& crashMessage) {
|
||||||
|
closeGame();
|
||||||
|
emit gameCrashed(crashMessage);
|
||||||
|
}
|
||||||
|
|
||||||
bool GameController::isPaused() {
|
bool GameController::isPaused() {
|
||||||
if (!m_gameOpen) {
|
if (!m_gameOpen) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -64,6 +64,7 @@ signals:
|
||||||
void gameStopped(GBAThread*);
|
void gameStopped(GBAThread*);
|
||||||
void gamePaused(GBAThread*);
|
void gamePaused(GBAThread*);
|
||||||
void gameUnpaused(GBAThread*);
|
void gameUnpaused(GBAThread*);
|
||||||
|
void gameCrashed(const QString& errorMessage);
|
||||||
void stateLoaded(GBAThread*);
|
void stateLoaded(GBAThread*);
|
||||||
|
|
||||||
void postLog(int level, const QString& log);
|
void postLog(int level, const QString& log);
|
||||||
|
@ -94,8 +95,10 @@ public slots:
|
||||||
void enableLogLevel(int);
|
void enableLogLevel(int);
|
||||||
void disableLogLevel(int);
|
void disableLogLevel(int);
|
||||||
|
|
||||||
#ifdef BUILD_SDL
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void crashGame(const QString& crashMessage);
|
||||||
|
|
||||||
|
#ifdef BUILD_SDL
|
||||||
void testSDLEvents();
|
void testSDLEvents();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QKeySequence>
|
#include <QKeySequence>
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QStackedLayout>
|
#include <QStackedLayout>
|
||||||
|
|
||||||
#include "ConfigController.h"
|
#include "ConfigController.h"
|
||||||
|
@ -74,6 +75,7 @@ Window::Window(ConfigController* config, QWidget* parent)
|
||||||
connect(m_controller, SIGNAL(gameUnpaused(GBAThread*)), m_display, SLOT(unpauseDrawing()));
|
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(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(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(levelsSet(int)), m_controller, SLOT(setLogLevel(int)));
|
||||||
connect(m_logView, SIGNAL(levelsEnabled(int)), m_controller, SLOT(enableLogLevel(int)));
|
connect(m_logView, SIGNAL(levelsEnabled(int)), m_controller, SLOT(enableLogLevel(int)));
|
||||||
connect(m_logView, SIGNAL(levelsDisabled(int)), m_controller, SLOT(disableLogLevel(int)));
|
connect(m_logView, SIGNAL(levelsDisabled(int)), m_controller, SLOT(disableLogLevel(int)));
|
||||||
|
@ -325,6 +327,14 @@ void Window::gameStopped() {
|
||||||
m_fpsTimer.stop();
|
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() {
|
void Window::redoLogo() {
|
||||||
if (m_controller->isLoaded()) {
|
if (m_controller->isLoaded()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -87,6 +87,7 @@ protected:
|
||||||
private slots:
|
private slots:
|
||||||
void gameStarted(GBAThread*);
|
void gameStarted(GBAThread*);
|
||||||
void gameStopped();
|
void gameStopped();
|
||||||
|
void gameCrashed(const QString&);
|
||||||
void redoLogo();
|
void redoLogo();
|
||||||
|
|
||||||
void recordFrame();
|
void recordFrame();
|
||||||
|
|
Loading…
Reference in New Issue