diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index 7b6919d56c..92a7ec0020 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include @@ -37,6 +38,8 @@ #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "UICommon/UICommon.h" + MainWindow::MainWindow() : QMainWindow(nullptr) { setWindowTitle(QString::fromStdString(scm_rev_str)); @@ -92,6 +95,8 @@ void MainWindow::ShutdownControllers() void MainWindow::InitCoreCallbacks() { Core::SetOnStoppedCallback([this] { emit EmulationStopped(); }); + installEventFilter(this); + m_render_widget->installEventFilter(this); } static void InstallHotkeyFilter(QWidget* dialog) @@ -198,6 +203,11 @@ void MainWindow::ConnectToolBar() connect(this, &MainWindow::EmulationStarted, m_tool_bar, &ToolBar::EmulationStarted); connect(this, &MainWindow::EmulationPaused, m_tool_bar, &ToolBar::EmulationPaused); connect(this, &MainWindow::EmulationStopped, m_tool_bar, &ToolBar::EmulationStopped); + + connect(this, &MainWindow::EmulationStopped, [this] { + m_stop_requested = false; + m_render_widget->hide(); + }); } void MainWindow::ConnectGameList() @@ -272,25 +282,54 @@ void MainWindow::Pause() bool MainWindow::Stop() { - bool stop = true; + if (!Core::IsRunning()) + return true; + if (Settings::Instance().GetConfirmStop()) { - // We could pause the game here and resume it if they say no. + const Core::State state = Core::GetState(); + // Set to false when Netplay is running as a CPU thread + bool pause = true; + + if (pause) + Core::SetState(Core::State::Paused); + QMessageBox::StandardButton confirm; - confirm = QMessageBox::question(m_render_widget, tr("Confirm"), tr("Stop emulation?")); - stop = (confirm == QMessageBox::Yes); + confirm = QMessageBox::question(m_render_widget, tr("Confirm"), + m_stop_requested ? + tr("A shutdown is already in progress. Unsaved data " + "may be lost if you stop the current emulation " + "before it completes. Force stop?") : + tr("Do you want to stop the current emulation?")); + if (confirm != QMessageBox::Yes) + return false; + + if (pause) + Core::SetState(state); } - if (stop) + // TODO: Add Movie shutdown + // TODO: Add Debugger shutdown + + if (!m_stop_requested && UICommon::TriggerSTMPowerEvent()) { - ForceStop(); + m_stop_requested = true; + + // Unpause because gracefully shutting down needs the game to actually request a shutdown. + // Do not unpause in debug mode to allow debugging until the complete shutdown. + if (Core::GetState() == Core::State::Paused) + Core::SetState(Core::State::Running); + + return false; + } + + ForceStop(); #ifdef Q_OS_WIN - // Allow windows to idle or turn off display again - SetThreadExecutionState(ES_CONTINUOUS); + // Allow windows to idle or turn off display again + SetThreadExecutionState(ES_CONTINUOUS); #endif - } - return stop; + return true; } void MainWindow::ForceStop() @@ -480,3 +519,14 @@ void MainWindow::SetStateSlot(int slot) Settings::Instance().SetStateSlot(slot); m_state_slot = slot; } + +bool MainWindow::eventFilter(QObject* object, QEvent* event) +{ + if (event->type() == QEvent::Close && !Stop()) + { + static_cast(event)->ignore(); + return true; + } + + return false; +} diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index 7577be2be7..0ed44fc19c 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -27,6 +27,8 @@ public: explicit MainWindow(); ~MainWindow(); + bool eventFilter(QObject* object, QEvent* event) override; + signals: void EmulationStarted(); void EmulationPaused(); @@ -86,6 +88,7 @@ private: GameList* m_game_list; RenderWidget* m_render_widget; bool m_rendering_to_main; + bool m_stop_requested = false; int m_state_slot = 1; HotkeyScheduler* m_hotkey_scheduler; diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index f5d0b59e06..26fdf74455 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -253,7 +253,6 @@ private: void DoFullscreen(bool enable_fullscreen); void DoExclusiveFullscreen(bool enable_fullscreen); void ToggleDisplayMode(bool bFullscreen); - bool TriggerSTMPowerEvent(); void OnStopped(); void OnRenderWindowSizeRequest(int width, int height); void UpdateTitle(const wxString& str); diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 46acd65278..b33ed2cf2f 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -86,6 +86,7 @@ #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "UICommon/UICommon.h" #include "UICommon/WiiUtils.h" #include "VideoCommon/RenderBase.h" @@ -880,36 +881,24 @@ void CFrame::DoStop() if (NetPlayDialog::GetNetPlayClient()) NetPlayDialog::GetNetPlayClient()->Stop(); - if (!m_tried_graceful_shutdown && TriggerSTMPowerEvent()) + if (!m_tried_graceful_shutdown && UICommon::TriggerSTMPowerEvent()) { m_tried_graceful_shutdown = true; + m_confirm_stop = false; + + // Unpause because gracefully shutting down needs the game to actually request a shutdown. + // Do not unpause in debug mode to allow debugging until the complete shutdown. + if (Core::GetState() == Core::State::Paused && !m_use_debugger) + Core::SetState(Core::State::Running); + return; } + Core::Stop(); UpdateGUI(); } } -bool CFrame::TriggerSTMPowerEvent() -{ - const auto ios = IOS::HLE::GetIOS(); - if (!ios) - return false; - - const auto stm = ios->GetDeviceByName("/dev/stm/eventhook"); - if (!stm || !std::static_pointer_cast(stm)->HasHookInstalled()) - return false; - - Core::DisplayMessage("Shutting down", 30000); - // Unpause because gracefully shutting down needs the game to actually request a shutdown. - // Do not unpause in debug mode to allow debugging until the complete shutdown. - if (Core::GetState() == Core::State::Paused && !m_use_debugger) - DoPause(); - ProcessorInterface::PowerButton_Tap(); - m_confirm_stop = false; - return true; -} - void CFrame::OnStopped() { m_confirm_stop = false; diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index ba4aa4a390..9c45a5c0d9 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #ifdef _WIN32 #include // for SHGetFolderPath #endif @@ -14,7 +15,11 @@ #include "Core/ConfigLoaders/BaseConfigLoader.h" #include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/HW/ProcessorInterface.h" #include "Core/HW/Wiimote.h" +#include "Core/IOS/IOS.h" +#include "Core/IOS/STM/STM.h" #include "InputCommon/GCAdapter.h" @@ -225,4 +230,20 @@ void SaveWiimoteSources() inifile.Save(ini_filename); } +bool TriggerSTMPowerEvent() +{ + const auto ios = IOS::HLE::GetIOS(); + if (!ios) + return false; + + const auto stm = ios->GetDeviceByName("/dev/stm/eventhook"); + if (!stm || !std::static_pointer_cast(stm)->HasHookInstalled()) + return false; + + Core::DisplayMessage("Shutting down", 30000); + ProcessorInterface::PowerButton_Tap(); + + return true; +} + } // namespace UICommon diff --git a/Source/Core/UICommon/UICommon.h b/Source/Core/UICommon/UICommon.h index 20c8ba0bcb..3781c2c58f 100644 --- a/Source/Core/UICommon/UICommon.h +++ b/Source/Core/UICommon/UICommon.h @@ -12,5 +12,7 @@ void Shutdown(); void CreateDirectories(); void SetUserDirectory(const std::string& custom_path); +bool TriggerSTMPowerEvent(); + void SaveWiimoteSources(); } // namespace UICommon