mirror of https://github.com/mgba-emu/mgba.git
Qt: Save and quit on Stop call
This commit is contained in:
parent
393252718f
commit
7015f38b37
|
@ -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) {
|
static THREAD_ENTRY _GBAThreadRun(void* context) {
|
||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
pthread_once(&_contextOnce, _createTLS);
|
pthread_once(&_contextOnce, _createTLS);
|
||||||
|
@ -129,6 +141,14 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
|
||||||
gba.logLevel = threadContext->logLevel;
|
gba.logLevel = threadContext->logLevel;
|
||||||
gba.logHandler = threadContext->logHandler;
|
gba.logHandler = threadContext->logHandler;
|
||||||
gba.stream = threadContext->stream;
|
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;
|
gba.idleOptimization = threadContext->idleOptimization;
|
||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
pthread_setspecific(_contextKey, threadContext);
|
pthread_setspecific(_contextKey, threadContext);
|
||||||
|
|
|
@ -21,6 +21,7 @@ struct GBACheatSet;
|
||||||
struct GBAOptions;
|
struct GBAOptions;
|
||||||
|
|
||||||
typedef void (*ThreadCallback)(struct GBAThread* threadContext);
|
typedef void (*ThreadCallback)(struct GBAThread* threadContext);
|
||||||
|
typedef bool (*ThreadStopCallback)(struct GBAThread* threadContext);
|
||||||
|
|
||||||
enum ThreadState {
|
enum ThreadState {
|
||||||
THREAD_INITIALIZED = -1,
|
THREAD_INITIALIZED = -1,
|
||||||
|
@ -86,6 +87,7 @@ struct GBAThread {
|
||||||
ThreadCallback startCallback;
|
ThreadCallback startCallback;
|
||||||
ThreadCallback cleanCallback;
|
ThreadCallback cleanCallback;
|
||||||
ThreadCallback frameCallback;
|
ThreadCallback frameCallback;
|
||||||
|
ThreadStopCallback stopCallback;
|
||||||
void* userData;
|
void* userData;
|
||||||
void (*run)(struct GBAThread*);
|
void (*run)(struct GBAThread*);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "AudioProcessor.h"
|
#include "AudioProcessor.h"
|
||||||
#include "InputController.h"
|
#include "InputController.h"
|
||||||
|
#include "LogController.h"
|
||||||
#include "MultiplayerController.h"
|
#include "MultiplayerController.h"
|
||||||
#include "VFileDevice.h"
|
#include "VFileDevice.h"
|
||||||
|
|
||||||
|
@ -92,6 +93,13 @@ GameController::GameController(QObject* parent)
|
||||||
context->gba->rumble = controller->m_inputController->rumble();
|
context->gba->rumble = controller->m_inputController->rumble();
|
||||||
context->gba->rotationSource = controller->m_inputController->rotationSource();
|
context->gba->rotationSource = controller->m_inputController->rotationSource();
|
||||||
controller->m_fpsTarget = context->fpsTarget;
|
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);
|
controller->gameStarted(context);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -113,8 +121,22 @@ GameController::GameController(QObject* parent)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
m_threadContext.stopCallback = [](GBAThread* context) {
|
||||||
|
if (!context) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GameController* controller = static_cast<GameController*>(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) {
|
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) {
|
if (!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -125,6 +147,25 @@ GameController::GameController(QObject* parent)
|
||||||
int immediate = va_arg(argc, int);
|
int immediate = va_arg(argc, int);
|
||||||
va_end(argc);
|
va_end(argc);
|
||||||
controller->unimplementedBiosCall(immediate);
|
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) {
|
if (level == GBA_LOG_FATAL) {
|
||||||
QMetaObject::invokeMethod(controller, "crashGame", Q_ARG(const QString&, QString().vsprintf(format, args)));
|
QMetaObject::invokeMethod(controller, "crashGame", Q_ARG(const QString&, QString().vsprintf(format, args)));
|
||||||
|
|
Loading…
Reference in New Issue