Merge pull request #9476 from liamwhite/async-shutdown
qt: continue event loop during game close
This commit is contained in:
		@@ -1550,8 +1550,9 @@ void GMainWindow::AllowOSSleep() {
 | 
			
		||||
 | 
			
		||||
bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index) {
 | 
			
		||||
    // Shutdown previous session if the emu thread is still active...
 | 
			
		||||
    if (emu_thread != nullptr)
 | 
			
		||||
    if (emu_thread != nullptr) {
 | 
			
		||||
        ShutdownGame();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!render_window->InitRenderTarget()) {
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -1784,7 +1785,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
 | 
			
		||||
    OnStartGame();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::ShutdownGame() {
 | 
			
		||||
void GMainWindow::OnShutdownBegin() {
 | 
			
		||||
    if (!emulation_running) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1807,13 +1808,40 @@ void GMainWindow::ShutdownGame() {
 | 
			
		||||
 | 
			
		||||
    emit EmulationStopping();
 | 
			
		||||
 | 
			
		||||
    // Wait for emulation thread to complete and delete it
 | 
			
		||||
    if (system->DebuggerEnabled() || !emu_thread->wait(5000)) {
 | 
			
		||||
    shutdown_timer.setSingleShot(true);
 | 
			
		||||
    shutdown_timer.start(system->DebuggerEnabled() ? 0 : 5000);
 | 
			
		||||
    connect(&shutdown_timer, &QTimer::timeout, this, &GMainWindow::OnEmulationStopTimeExpired);
 | 
			
		||||
    connect(emu_thread.get(), &QThread::finished, this, &GMainWindow::OnEmulationStopped);
 | 
			
		||||
 | 
			
		||||
    // Disable everything to prevent anything from being triggered here
 | 
			
		||||
    ui->action_Pause->setEnabled(false);
 | 
			
		||||
    ui->action_Restart->setEnabled(false);
 | 
			
		||||
    ui->action_Stop->setEnabled(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnShutdownBeginDialog() {
 | 
			
		||||
    shutdown_dialog = new OverlayDialog(this, *system, QString{}, tr("Closing software..."),
 | 
			
		||||
                                        QString{}, QString{}, Qt::AlignHCenter | Qt::AlignVCenter);
 | 
			
		||||
    shutdown_dialog->open();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnEmulationStopTimeExpired() {
 | 
			
		||||
    if (emu_thread) {
 | 
			
		||||
        emu_thread->ForceStop();
 | 
			
		||||
        emu_thread->wait();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnEmulationStopped() {
 | 
			
		||||
    shutdown_timer.stop();
 | 
			
		||||
    emu_thread->disconnect();
 | 
			
		||||
    emu_thread->wait();
 | 
			
		||||
    emu_thread = nullptr;
 | 
			
		||||
 | 
			
		||||
    if (shutdown_dialog) {
 | 
			
		||||
        shutdown_dialog->deleteLater();
 | 
			
		||||
        shutdown_dialog = nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emulation_running = false;
 | 
			
		||||
 | 
			
		||||
    discord_rpc->Update();
 | 
			
		||||
@@ -1859,6 +1887,20 @@ void GMainWindow::ShutdownGame() {
 | 
			
		||||
 | 
			
		||||
    // When closing the game, destroy the GLWindow to clear the context after the game is closed
 | 
			
		||||
    render_window->ReleaseRenderTarget();
 | 
			
		||||
 | 
			
		||||
    Settings::RestoreGlobalState(system->IsPoweredOn());
 | 
			
		||||
    system->HIDCore().ReloadInputDevices();
 | 
			
		||||
    UpdateStatusButtons();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::ShutdownGame() {
 | 
			
		||||
    if (!emulation_running) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    OnShutdownBegin();
 | 
			
		||||
    OnEmulationStopTimeExpired();
 | 
			
		||||
    OnEmulationStopped();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::StoreRecentFile(const QString& filename) {
 | 
			
		||||
@@ -2961,11 +3003,8 @@ void GMainWindow::OnStopGame() {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ShutdownGame();
 | 
			
		||||
 | 
			
		||||
    Settings::RestoreGlobalState(system->IsPoweredOn());
 | 
			
		||||
    system->HIDCore().ReloadInputDevices();
 | 
			
		||||
    UpdateStatusButtons();
 | 
			
		||||
    OnShutdownBegin();
 | 
			
		||||
    OnShutdownBeginDialog();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnLoadComplete() {
 | 
			
		||||
@@ -4052,10 +4091,6 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
 | 
			
		||||
    // Shutdown session if the emu thread is active...
 | 
			
		||||
    if (emu_thread != nullptr) {
 | 
			
		||||
        ShutdownGame();
 | 
			
		||||
 | 
			
		||||
        Settings::RestoreGlobalState(system->IsPoweredOn());
 | 
			
		||||
        system->HIDCore().ReloadInputDevices();
 | 
			
		||||
        UpdateStatusButtons();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render_window->close();
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ class GImageInfo;
 | 
			
		||||
class GRenderWindow;
 | 
			
		||||
class LoadingScreen;
 | 
			
		||||
class MicroProfileDialog;
 | 
			
		||||
class OverlayDialog;
 | 
			
		||||
class ProfilerWidget;
 | 
			
		||||
class ControllerDialog;
 | 
			
		||||
class QLabel;
 | 
			
		||||
@@ -335,6 +336,10 @@ private slots:
 | 
			
		||||
    void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
 | 
			
		||||
    void OnLanguageChanged(const QString& locale);
 | 
			
		||||
    void OnMouseActivity();
 | 
			
		||||
    void OnShutdownBegin();
 | 
			
		||||
    void OnShutdownBeginDialog();
 | 
			
		||||
    void OnEmulationStopped();
 | 
			
		||||
    void OnEmulationStopTimeExpired();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    QString GetGameListErrorRemoving(InstalledEntryType type) const;
 | 
			
		||||
@@ -384,6 +389,8 @@ private:
 | 
			
		||||
    GRenderWindow* render_window;
 | 
			
		||||
    GameList* game_list;
 | 
			
		||||
    LoadingScreen* loading_screen;
 | 
			
		||||
    QTimer shutdown_timer;
 | 
			
		||||
    OverlayDialog* shutdown_dialog{};
 | 
			
		||||
 | 
			
		||||
    GameListPlaceholder* game_list_placeholder;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
 | 
			
		||||
#include <QKeyEvent>
 | 
			
		||||
#include <QScreen>
 | 
			
		||||
#include <QWindow>
 | 
			
		||||
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hid/hid_types.h"
 | 
			
		||||
@@ -162,7 +163,7 @@ void OverlayDialog::MoveAndResizeWindow() {
 | 
			
		||||
    const auto height = static_cast<float>(parentWidget()->height());
 | 
			
		||||
 | 
			
		||||
    // High DPI
 | 
			
		||||
    const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f;
 | 
			
		||||
    const float dpi_scale = parentWidget()->windowHandle()->screen()->logicalDotsPerInch() / 96.0f;
 | 
			
		||||
 | 
			
		||||
    const auto title_text_font_size = BASE_TITLE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
 | 
			
		||||
    const auto body_text_font_size =
 | 
			
		||||
@@ -259,3 +260,9 @@ void OverlayDialog::InputThread() {
 | 
			
		||||
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OverlayDialog::keyPressEvent(QKeyEvent* e) {
 | 
			
		||||
    if (!ui->buttonsDialog->isHidden() || e->key() != Qt::Key_Escape) {
 | 
			
		||||
        QDialog::keyPressEvent(e);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -94,6 +94,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    /// The thread where input is being polled and processed.
 | 
			
		||||
    void InputThread();
 | 
			
		||||
    void keyPressEvent(QKeyEvent* e) override;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::OverlayDialog> ui;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user