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