diff --git a/CHANGES b/CHANGES index ed9e0416213..ca205c4838b 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,7 @@ Misc: - GBA: Improve detection of valid ELF ROMs - mGUI: Enable auto-softpatching (closes mgba.io/i/2899) - Scripting: Add `callbacks:oneshot` for single-call callbacks + - Qt: Detect failed startup and prompt for safe mode 0.10.2: (2023-04-23) Emulation fixes: diff --git a/src/platform/qt/ConfigController.cpp b/src/platform/qt/ConfigController.cpp index 73097df0981..80a5769ebce 100644 --- a/src/platform/qt/ConfigController.cpp +++ b/src/platform/qt/ConfigController.cpp @@ -7,6 +7,7 @@ #include "ActionMapper.h" #include "CoreController.h" +#include "Display.h" #include #include @@ -114,6 +115,16 @@ ConfigController::ConfigController(QObject* parent) fileName.append("qt.ini"); m_settings = std::make_unique(fileName, QSettings::IniFormat); + if (getQtOption("loadStarted").toBool()) { + // If the loadStarted flag is lingering in qt.ini, then that indicates that + // the frontend crashed before clearing the flag. + // Prompt the user to enter into a safe mode to try to get safely started up. + setQtOption("safeModeWarning", true); + } else { + setQtOption("loadStarted", true); + m_settings->sync(); + } + mCoreConfigInit(&m_config, PORT); m_opts.audioSync = CoreController::AUDIO_SYNC; @@ -306,6 +317,16 @@ void ConfigController::setQtOption(const QString& key, const QVariant& value, co } } +void ConfigController::removeQtOption(const QString& key, const QString& group) { + if (!group.isNull()) { + m_settings->beginGroup(group); + } + m_settings->remove(key); + if (!group.isNull()) { + m_settings->endGroup(); + } +} + QStringList ConfigController::getMRU(ConfigController::MRU mruType) const { QStringList mru; m_settings->beginGroup(mruName(mruType)); @@ -354,6 +375,20 @@ void ConfigController::write() { mCoreConfigMap(&m_config, &m_opts); } +void ConfigController::setLoadingComplete() { + removeQtOption("loadStarted"); + write(); +} + +void ConfigController::setSafeMode() { + setQtOption("displayDriver", static_cast(Display::Driver::QT)); + removeQtOption("safeModeWarning"); +} + +void ConfigController::declineSafeMode() { + removeQtOption("safeModeWarning"); +} + void ConfigController::makePortable() { mCoreConfigMakePortable(&m_config); diff --git a/src/platform/qt/ConfigController.h b/src/platform/qt/ConfigController.h index ecd12686763..6eb5e7c633c 100644 --- a/src/platform/qt/ConfigController.h +++ b/src/platform/qt/ConfigController.h @@ -104,6 +104,10 @@ Q_OBJECT const mGraphicsOpts* graphicsOpts() const { return &m_graphicsOpts; } void usage(const char* arg0) const; + void setLoadingComplete(); + void setSafeMode(); + void declineSafeMode(); + static const QString& configDir(); static const QString& cacheDir(); static bool isPortable(); @@ -115,6 +119,7 @@ public slots: void setOption(const char* key, const char* value); void setOption(const char* key, const QVariant& value); void setQtOption(const QString& key, const QVariant& value, const QString& group = QString()); + void removeQtOption(const QString& key, const QString& group = QString()); void makePortable(); void write(); @@ -130,7 +135,7 @@ public slots: mGraphicsOpts m_graphicsOpts{}; std::array m_subparsers; bool m_parsed = false; - + QHash m_argvOptions; QHash m_optionSet; std::unique_ptr m_settings; diff --git a/src/platform/qt/GBAApp.cpp b/src/platform/qt/GBAApp.cpp index c7c380a7cb2..7805831efee 100644 --- a/src/platform/qt/GBAApp.cpp +++ b/src/platform/qt/GBAApp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -384,6 +385,19 @@ void GBAApp::finishJob(qint64 jobId) { m_workerJobCallbacks.remove(jobId); } +void GBAApp::checkSafeMode() { + if (m_configController->getQtOption("safeModeWarning").toBool()) { + int choice = QMessageBox::warning(nullptr, tr("Safe Mode"), + tr("mGBA detected a problem while starting.\n\nWould you like to reset settings to failsafe values?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (choice == QMessageBox::Yes) { + m_configController->setSafeMode(); + } else { + m_configController->declineSafeMode(); + } + } +} + GBAApp::WorkerJob::WorkerJob(qint64 id, std::function job, GBAApp* owner) : m_id(id) , m_job(job) diff --git a/src/platform/qt/GBAApp.h b/src/platform/qt/GBAApp.h index 3110b0733db..c3d593c7efd 100644 --- a/src/platform/qt/GBAApp.h +++ b/src/platform/qt/GBAApp.h @@ -82,6 +82,8 @@ Q_OBJECT ApplicationUpdater* updater() { return &m_updater; } QString invokeOnExit() { return m_invokeOnExit; } + void checkSafeMode(); + public slots: void restartForUpdate(); Window* newWindow(); diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index f10bdebb654..3c6229fc8b5 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -122,7 +122,7 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi if (value.toBool()) { attachWidget(m_libraryView); } else { - attachWidget(m_screenWidget); + attachWidget(m_screenWidget); } } }, this); @@ -130,9 +130,9 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi ConfigOption* showFilenameInLibrary = m_config->addOption("showFilenameInLibrary"); showFilenameInLibrary->connect([this](const QVariant& value) { - m_libraryView->setShowFilename(value.toBool()); - }, this); - m_config->updateOption("showFilenameInLibrary"); + m_libraryView->setShowFilename(value.toBool()); + }, this); + m_config->updateOption("showFilenameInLibrary"); ConfigOption* libraryStyle = m_config->addOption("libraryStyle"); libraryStyle->connect([this](const QVariant& value) { m_libraryView->setViewStyle(static_cast(value.toInt())); @@ -734,6 +734,7 @@ void Window::showEvent(QShowEvent* event) { } reloadDisplayDriver(); setFocus(); + m_config->setLoadingComplete(); } void Window::hideEvent(QHideEvent* event) { diff --git a/src/platform/qt/main.cpp b/src/platform/qt/main.cpp index 4343168a77c..38fee6cc659 100644 --- a/src/platform/qt/main.cpp +++ b/src/platform/qt/main.cpp @@ -118,6 +118,8 @@ int main(int argc, char* argv[]) { langTranslator.load(locale, binaryName, "-", ":/translations/"); application.installTranslator(&langTranslator); + application.checkSafeMode(); + Window* w = application.newWindow(); w->loadConfig(); w->argumentsPassed();