Frontends: Implement auto save on exit/resume

This commit is contained in:
Connor McLaughlin
2020-02-16 00:14:49 +09:00
parent e738b87a25
commit e01cf0dccb
9 changed files with 75 additions and 22 deletions

View File

@ -25,6 +25,7 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW
SettingWidgetBinder::BindWidgetToNormalizedSetting(m_host_interface, m_ui.emulationSpeed, "General/EmulationSpeed",
100.0f);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.pauseOnStart, "General/StartPaused");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.saveStateOnExit, "General/SaveStateOnExit");
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cpuExecutionMode, "CPU/ExecutionMode",
&Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName);

View File

@ -146,6 +146,13 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QCheckBox" name="saveStateOnExit">
<property name="text">
<string>Save State On Exit</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -298,7 +298,7 @@ void MainWindow::connectSignals()
&MainWindow::onChangeDiscFromGameListActionTriggered);
connect(m_ui.actionAddGameDirectory, &QAction::triggered,
[this]() { getSettingsDialog()->getGameListSettingsWidget()->addSearchDirectory(this); });
connect(m_ui.actionPowerOff, &QAction::triggered, [this]() { m_host_interface->destroySystem(true, false); });
connect(m_ui.actionPowerOff, &QAction::triggered, m_host_interface, &QtHostInterface::powerOffSystem);
connect(m_ui.actionReset, &QAction::triggered, m_host_interface, &QtHostInterface::resetSystem);
connect(m_ui.actionPause, &QAction::toggled, m_host_interface, &QtHostInterface::pauseSystem);
connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
@ -340,7 +340,10 @@ void MainWindow::connectSignals()
QString path = QString::fromStdString(entry->path);
if (!m_emulation_running)
{
m_host_interface->bootSystemFromFile(path);
if (m_host_interface->getSettingValue("General/SaveStateOnExit", true).toBool())
m_host_interface->resumeSystemFromState(path, true);
else
m_host_interface->bootSystemFromFile(path);
}
else
{
@ -433,6 +436,6 @@ void MainWindow::updateDebugMenuGPURenderer()
void MainWindow::closeEvent(QCloseEvent* event)
{
m_host_interface->destroySystem(true, true);
m_host_interface->synchronousPowerOffSystem();
QMainWindow::closeEvent(event);
}

View File

@ -76,10 +76,10 @@ void QtHostInterface::setDefaultSettings()
updateQSettingsFromCoreSettings();
}
QVariant QtHostInterface::getSettingValue(const QString& name)
QVariant QtHostInterface::getSettingValue(const QString& name, const QVariant& default_value)
{
std::lock_guard<std::mutex> guard(m_qsettings_mutex);
return m_qsettings.value(name);
return m_qsettings.value(name, default_value);
}
void QtHostInterface::putSettingValue(const QString& name, const QVariant& value)
@ -178,6 +178,21 @@ void QtHostInterface::bootSystemFromFile(const QString& filename)
HostInterface::BootSystemFromFile(filename.toStdString().c_str());
}
void QtHostInterface::resumeSystemFromState(const QString& filename, bool boot_on_failure)
{
if (!isOnWorkerThread())
{
QMetaObject::invokeMethod(this, "resumeSystemFromState", Qt::QueuedConnection, Q_ARG(const QString&, filename),
Q_ARG(bool, boot_on_failure));
return;
}
if (filename.isEmpty())
HostInterface::ResumeSystemFromMostRecentState();
else
HostInterface::ResumeSystemFromState(filename.toStdString().c_str(), boot_on_failure);
}
void QtHostInterface::bootSystemFromBIOS()
{
if (!isOnWorkerThread())
@ -485,22 +500,31 @@ void QtHostInterface::addButtonToInputMap(const QString& binding, InputButtonHan
}
}
void QtHostInterface::destroySystem(bool save_resume_state /* = false */, bool block_until_done /* = false */)
void QtHostInterface::powerOffSystem()
{
if (!isOnWorkerThread())
{
QMetaObject::invokeMethod(this, "destroySystem",
block_until_done ? Qt::BlockingQueuedConnection : Qt::QueuedConnection,
Q_ARG(bool, save_resume_state), Q_ARG(bool, block_until_done));
QMetaObject::invokeMethod(this, "powerOffSystem", Qt::QueuedConnection);
return;
}
if (!m_system)
return;
if (m_settings.save_state_on_exit)
SaveResumeSaveState();
DestroySystem();
}
void QtHostInterface::synchronousPowerOffSystem()
{
if (!isOnWorkerThread())
QMetaObject::invokeMethod(this, "powerOffSystem", Qt::BlockingQueuedConnection);
else
powerOffSystem();
}
void QtHostInterface::resetSystem()
{
if (!isOnWorkerThread())
@ -555,23 +579,26 @@ void QtHostInterface::populateSaveStateMenus(const char* game_code, QMenu* load_
if (!available_states.empty())
{
bool last_global = available_states.front().global;
s32 last_slot = available_states.front().slot;
for (const SaveStateInfo& ssi : available_states)
{
const s32 slot = ssi.slot;
const bool global = ssi.global;
const QDateTime timestamp(QDateTime::fromSecsSinceEpoch(static_cast<qint64>(ssi.timestamp)));
const QString timestamp_str(timestamp.toString(Qt::SystemLocaleShortDate));
const QString path(QString::fromStdString(ssi.path));
QString title = tr("%1 Save %2 (%3)")
.arg(global ? tr("Global") : tr("Game"))
.arg(slot)
.arg(timestamp.toString(Qt::SystemLocaleShortDate));
QString title;
if (slot < 0)
title = tr("Resume Save (%1)").arg(timestamp_str);
else
title = tr("%1 Save %2 (%3)").arg(global ? tr("Global") : tr("Game")).arg(slot).arg(timestamp_str);
if (global != last_global)
{
if (global != last_global || last_slot < 0)
load_menu->addSeparator();
last_global = global;
}
last_global = global;
last_slot = slot;
QAction* action = load_menu->addAction(title);
connect(action, &QAction::triggered, [this, path]() { loadState(path); });

View File

@ -35,7 +35,7 @@ public:
void setDefaultSettings();
/// Thread-safe QSettings access.
QVariant getSettingValue(const QString& name);
QVariant getSettingValue(const QString& name, const QVariant& default_value = QVariant());
void putSettingValue(const QString& name, const QVariant& value);
void removeSettingValue(const QString& name);
@ -77,8 +77,10 @@ Q_SIGNALS:
public Q_SLOTS:
void applySettings();
void bootSystemFromFile(const QString& filename);
void resumeSystemFromState(const QString& filename, bool boot_on_failure);
void bootSystemFromBIOS();
void destroySystem(bool save_resume_state = false, bool block_until_done = false);
void powerOffSystem();
void synchronousPowerOffSystem();
void resetSystem();
void pauseSystem(bool paused);
void changeDisc(const QString& new_disc_filename);