Qt: Add shutdown hotkey

This commit is contained in:
Connor McLaughlin 2022-03-25 20:14:23 +10:00 committed by refractionpcsx2
parent d65950cda2
commit 551d013b63
6 changed files with 45 additions and 32 deletions

View File

@ -139,27 +139,8 @@ void EmuThread::setVMPaused(bool paused)
VMManager::SetPaused(paused); VMManager::SetPaused(paused);
} }
bool EmuThread::shutdownVM(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */, bool blocking /* = false */) bool EmuThread::shutdownVM(bool allow_save_to_state /* = true */)
{ {
if (!isOnEmuThread())
{
// only confirm on UI thread because we need to display a msgbox
if (allow_confirm && g_main_window && !g_main_window->confirmShutdown())
return false;
QMetaObject::invokeMethod(this, "shutdownVM", Qt::QueuedConnection, Q_ARG(bool, false),
Q_ARG(bool, allow_save_to_state), Q_ARG(bool, blocking));
if (blocking)
{
// we need to yield here, since the display gets destroyed
while (VMManager::HasValidVM())
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
}
return true;
}
const VMState state = VMManager::GetState(); const VMState state = VMManager::GetState();
if (state == VMState::Paused) if (state == VMState::Paused)
m_event_loop->quit(); m_event_loop->quit();
@ -550,7 +531,7 @@ void EmuThread::connectDisplaySignals(DisplayWidget* widget)
connect(widget, &DisplayWidget::windowFocusEvent, this, &EmuThread::onDisplayWindowFocused); connect(widget, &DisplayWidget::windowFocusEvent, this, &EmuThread::onDisplayWindowFocused);
connect(widget, &DisplayWidget::windowResizedEvent, this, &EmuThread::onDisplayWindowResized); connect(widget, &DisplayWidget::windowResizedEvent, this, &EmuThread::onDisplayWindowResized);
// connect(widget, &DisplayWidget::windowRestoredEvent, this, &EmuThread::redrawDisplayWindow); // connect(widget, &DisplayWidget::windowRestoredEvent, this, &EmuThread::redrawDisplayWindow);
connect(widget, &DisplayWidget::windowClosedEvent, []() { g_emu_thread->shutdownVM(true, true); }); connect(widget, &DisplayWidget::windowClosedEvent, []() { g_main_window->requestShutdown(); });
connect(widget, &DisplayWidget::windowKeyEvent, this, &EmuThread::onDisplayWindowKeyEvent); connect(widget, &DisplayWidget::windowKeyEvent, this, &EmuThread::onDisplayWindowKeyEvent);
connect(widget, &DisplayWidget::windowMouseMoveEvent, this, &EmuThread::onDisplayWindowMouseMoveEvent); connect(widget, &DisplayWidget::windowMouseMoveEvent, this, &EmuThread::onDisplayWindowMouseMoveEvent);
connect(widget, &DisplayWidget::windowMouseButtonEvent, this, &EmuThread::onDisplayWindowMouseButtonEvent); connect(widget, &DisplayWidget::windowMouseButtonEvent, this, &EmuThread::onDisplayWindowMouseButtonEvent);
@ -792,6 +773,14 @@ DEFINE_HOTKEY("Screenshot", "General", "Save Screenshot", [](bool pressed) {
// TODO // TODO
} }
}) })
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](bool pressed) {
if (!pressed)
{
// run it on the host thread, that way we get the confirm prompt (if enabled)
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection,
Q_ARG(bool, true), Q_ARG(bool, true), Q_ARG(bool, true));
}
})
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](bool pressed) { DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](bool pressed) {
if (!pressed) if (!pressed)
g_emu_thread->setVMPaused(VMManager::GetState() != VMState::Paused); g_emu_thread->setVMPaused(VMManager::GetState() != VMState::Paused);

View File

@ -57,7 +57,7 @@ public Q_SLOTS:
void startVM(std::shared_ptr<VMBootParameters> boot_params); void startVM(std::shared_ptr<VMBootParameters> boot_params);
void resetVM(); void resetVM();
void setVMPaused(bool paused); void setVMPaused(bool paused);
bool shutdownVM(bool allow_confirm = true, bool allow_save_to_state = true, bool blocking = false); bool shutdownVM(bool allow_save_to_state = true);
void loadState(const QString& filename); void loadState(const QString& filename);
void loadStateFromSlot(qint32 slot); void loadStateFromSlot(qint32 slot);
void saveState(const QString& filename); void saveState(const QString& filename);

View File

@ -27,6 +27,7 @@
#include "pcsx2/CDVD/CDVDaccess.h" #include "pcsx2/CDVD/CDVDaccess.h"
#include "pcsx2/Frontend/GameList.h" #include "pcsx2/Frontend/GameList.h"
#include "pcsx2/GSDumpReplayer.h"
#include "pcsx2/HostDisplay.h" #include "pcsx2/HostDisplay.h"
#include "AboutDialog.h" #include "AboutDialog.h"
@ -131,7 +132,7 @@ void MainWindow::connectSignals()
connect(m_ui.actionChangeDiscFromGameList, &QAction::triggered, this, &MainWindow::onChangeDiscFromGameListActionTriggered); connect(m_ui.actionChangeDiscFromGameList, &QAction::triggered, this, &MainWindow::onChangeDiscFromGameListActionTriggered);
connect(m_ui.menuChangeDisc, &QMenu::aboutToShow, this, &MainWindow::onChangeDiscMenuAboutToShow); connect(m_ui.menuChangeDisc, &QMenu::aboutToShow, this, &MainWindow::onChangeDiscMenuAboutToShow);
connect(m_ui.menuChangeDisc, &QMenu::aboutToHide, this, &MainWindow::onChangeDiscMenuAboutToHide); connect(m_ui.menuChangeDisc, &QMenu::aboutToHide, this, &MainWindow::onChangeDiscMenuAboutToHide);
connect(m_ui.actionPowerOff, &QAction::triggered, []() { g_emu_thread->shutdownVM(); }); connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(); });
connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); }); connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); }); connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close); connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
@ -236,7 +237,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
void MainWindow::recreate() void MainWindow::recreate()
{ {
if (m_vm_valid) if (m_vm_valid)
g_emu_thread->shutdownVM(false, true, true); requestShutdown(false, true, true);
close(); close();
g_main_window = nullptr; g_main_window = nullptr;
@ -659,20 +660,38 @@ void MainWindow::reportError(const QString& title, const QString& message)
QMessageBox::critical(this, title, message); QMessageBox::critical(this, title, message);
} }
bool MainWindow::confirmShutdown() bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */, bool block_until_done /* = false */)
{ {
if (!m_vm_valid || !QtHost::GetBaseBoolSettingValue("UI", "ConfirmShutdown", true)) if (!VMManager::HasValidVM())
return true; return true;
ScopedVMPause pauser(m_vm_paused); // only confirm on UI thread because we need to display a msgbox
if (allow_confirm && !GSDumpReplayer::IsReplayingDump() && QtHost::GetBaseBoolSettingValue("UI", "ConfirmShutdown", true))
{
ScopedVMPause pauser(m_vm_paused);
if (QMessageBox::question(g_main_window, tr("Confirm Shutdown"),
tr("Are you sure you want to shut down the virtual machine?\n\nAll unsaved progress will be lost.")) != QMessageBox::Yes)
{
return false;
}
}
return (QMessageBox::question(g_main_window, tr("Confirm Shutdown"), g_emu_thread->shutdownVM(allow_save_to_state);
tr("Are you sure you want to shut down the virtual machine?\n\nAll unsaved progress will be lost.")) == QMessageBox::Yes);
if (block_until_done)
{
// we need to yield here, since the display gets destroyed
while (VMManager::HasValidVM())
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
}
return true;
} }
void MainWindow::requestExit() void MainWindow::requestExit()
{ {
if (!g_emu_thread->shutdownVM(true, true, false)) // this is block, because otherwise closeEvent() will also prompt
if (!requestShutdown(true, true, true))
return; return;
close(); close();
@ -1021,7 +1040,7 @@ void MainWindow::onGameChanged(const QString& path, const QString& serial, const
void MainWindow::closeEvent(QCloseEvent* event) void MainWindow::closeEvent(QCloseEvent* event)
{ {
if (!g_emu_thread->shutdownVM(true, true, true)) if (!requestShutdown(true, true, true))
{ {
event->ignore(); event->ignore();
return; return;

View File

@ -54,7 +54,7 @@ public Q_SLOTS:
void refreshGameList(bool invalidate_cache); void refreshGameList(bool invalidate_cache);
void invalidateSaveStateCache(); void invalidateSaveStateCache();
void reportError(const QString& title, const QString& message); void reportError(const QString& title, const QString& message);
bool confirmShutdown(); bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool block_until_done = false);
void requestExit(); void requestExit();
private Q_SLOTS: private Q_SLOTS:

View File

@ -247,6 +247,7 @@ void PAD::SetDefaultConfig(SettingsInterface& si)
si.SetStringValue("Hotkeys", "TogglePause", "Keyboard/Space"); si.SetStringValue("Hotkeys", "TogglePause", "Keyboard/Space");
si.SetStringValue("Hotkeys", "ToggleSlowMotion", "Keyboard/Shift & Keyboard/Backtab"); si.SetStringValue("Hotkeys", "ToggleSlowMotion", "Keyboard/Shift & Keyboard/Backtab");
si.SetStringValue("Hotkeys", "ToggleTurbo", "Keyboard/Tab"); si.SetStringValue("Hotkeys", "ToggleTurbo", "Keyboard/Tab");
si.SetStringValue("Hotkeys", "ShutdownVM", "Keyboard/Escape");
} }
void PAD::Update() void PAD::Update()

View File

@ -1349,6 +1349,10 @@ DEFINE_HOTKEY("DecreaseSpeed", "System", "Decrease Target Speed", [](bool presse
if (!pressed) if (!pressed)
HotkeyAdjustTargetSpeed(-0.1); HotkeyAdjustTargetSpeed(-0.1);
}) })
DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](bool pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::Reset();
})
DEFINE_HOTKEY("PreviousSaveStateSlot", "Save States", "Select Previous Save Slot", [](bool pressed) { DEFINE_HOTKEY("PreviousSaveStateSlot", "Save States", "Select Previous Save Slot", [](bool pressed) {
if (!pressed) if (!pressed)