From 7015f38b37a7d33fc8412e4ef66911aae7e4936b Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 19 Jul 2015 18:35:18 -0700 Subject: [PATCH] Qt: Save and quit on Stop call --- src/gba/supervisor/thread.c | 20 ++++++++++++++ src/gba/supervisor/thread.h | 2 ++ src/platform/qt/GameController.cpp | 43 +++++++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/gba/supervisor/thread.c b/src/gba/supervisor/thread.c index e617b1afd..08b5b7402 100644 --- a/src/gba/supervisor/thread.c +++ b/src/gba/supervisor/thread.c @@ -96,6 +96,18 @@ static void _pauseThread(struct GBAThread* threadContext, bool onThread) { } } +struct GBAThreadStop { + struct GBAStopCallback d; + struct GBAThread* p; +}; + +static void _stopCallback(struct GBAStopCallback* stop) { + struct GBAThreadStop* callback = (struct GBAThreadStop*) stop; + if (callback->p->stopCallback(callback->p)) { + _changeState(callback->p, THREAD_EXITING, false); + } +} + static THREAD_ENTRY _GBAThreadRun(void* context) { #ifdef USE_PTHREADS pthread_once(&_contextOnce, _createTLS); @@ -129,6 +141,14 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { gba.logLevel = threadContext->logLevel; gba.logHandler = threadContext->logHandler; gba.stream = threadContext->stream; + + struct GBAThreadStop stop; + if (threadContext->stopCallback) { + stop.d.stop = _stopCallback; + stop.p = threadContext; + gba.stopCallback = &stop.d; + } + gba.idleOptimization = threadContext->idleOptimization; #ifdef USE_PTHREADS pthread_setspecific(_contextKey, threadContext); diff --git a/src/gba/supervisor/thread.h b/src/gba/supervisor/thread.h index aa86940f2..f9dab3248 100644 --- a/src/gba/supervisor/thread.h +++ b/src/gba/supervisor/thread.h @@ -21,6 +21,7 @@ struct GBACheatSet; struct GBAOptions; typedef void (*ThreadCallback)(struct GBAThread* threadContext); +typedef bool (*ThreadStopCallback)(struct GBAThread* threadContext); enum ThreadState { THREAD_INITIALIZED = -1, @@ -86,6 +87,7 @@ struct GBAThread { ThreadCallback startCallback; ThreadCallback cleanCallback; ThreadCallback frameCallback; + ThreadStopCallback stopCallback; void* userData; void (*run)(struct GBAThread*); diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index cbb2b1718..33ad8ba33 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -7,6 +7,7 @@ #include "AudioProcessor.h" #include "InputController.h" +#include "LogController.h" #include "MultiplayerController.h" #include "VFileDevice.h" @@ -92,6 +93,13 @@ GameController::GameController(QObject* parent) context->gba->rumble = controller->m_inputController->rumble(); context->gba->rotationSource = controller->m_inputController->rotationSource(); controller->m_fpsTarget = context->fpsTarget; + + if (GBALoadState(context, context->stateDir, 0)) { + VFile* vf = GBAGetState(context->gba, context->stateDir, 0, true); + if (vf) { + vf->truncate(vf, 0); + } + } controller->gameStarted(context); }; @@ -113,8 +121,22 @@ GameController::GameController(QObject* parent) } }; + m_threadContext.stopCallback = [](GBAThread* context) { + if (!context) { + return false; + } + GameController* controller = static_cast(context->userData); + if (!GBASaveState(context, context->stateDir, 0, true)) { + return false; + } + QMetaObject::invokeMethod(controller, "closeGame"); + return true; + }; + m_threadContext.logHandler = [](GBAThread* context, enum GBALogLevel level, const char* format, va_list args) { - static const char* stubMessage = "Stub software interrupt"; + static const char* stubMessage = "Stub software interrupt: %02X"; + static const char* savestateMessage = "State %i loaded"; + static const char* savestateFailedMessage = "State %i failed to load"; if (!context) { return; } @@ -125,6 +147,25 @@ GameController::GameController(QObject* parent) int immediate = va_arg(argc, int); va_end(argc); controller->unimplementedBiosCall(immediate); + } else if (level == GBA_LOG_STATUS) { + // Slot 0 is reserved for suspend points + if (strncmp(savestateMessage, format, strlen(savestateMessage)) == 0) { + va_list argc; + va_copy(argc, args); + int slot = va_arg(argc, int); + va_end(argc); + if (slot == 0) { + format = "Loaded suspend state"; + } + } else if (strncmp(savestateFailedMessage, format, strlen(savestateFailedMessage)) == 0) { + va_list argc; + va_copy(argc, args); + int slot = va_arg(argc, int); + va_end(argc); + if (slot == 0) { + return; + } + } } if (level == GBA_LOG_FATAL) { QMetaObject::invokeMethod(controller, "crashGame", Q_ARG(const QString&, QString().vsprintf(format, args)));