diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index 81c9d16d3b..9c262373da 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -357,21 +357,34 @@ bool gs_frame::get_mouse_lock_state() return isActive() && m_mouse_hide_and_lock; } +void gs_frame::hide_on_close() +{ + if (!(+g_progr)) + { + // Hide the dialog before stopping if no progress bar is being shown. + // Otherwise users might think that the game softlocked if stopping takes too long. + QWindow::hide(); + } +} + void gs_frame::close() { + if (m_is_closing.exchange(true)) + { + gui_log.notice("Closing game window (ignored, already closing)"); + return; + } + gui_log.notice("Closing game window"); Emu.CallFromMainThread([this]() { - if (!(+g_progr)) - { - // Hide the dialog before stopping if no progress bar is being shown. - // Otherwise users might think that the game softlocked if stopping takes too long. - QWindow::hide(); - } + // Hide window if necessary + hide_on_close(); if (!Emu.IsStopped()) { + // Blocking shutdown request. Obsolete, but I'm keeping it here as last resort. Emu.GracefulShutdown(true, false); } @@ -838,7 +851,23 @@ bool gs_frame::event(QEvent* ev) } gui_log.notice("Game window close event issued"); - close(); + + if (Emu.IsStopped()) + { + // This should be unreachable, but never say never. Properly close the window anyway. + close(); + } + else + { + // Issue async shutdown + Emu.GracefulShutdown(true, true); + + // Hide window if necessary + hide_on_close(); + + // Do not propagate the close event. It will be closed by the rsx_thread. + return true; + } } else if (ev->type() == QEvent::MouseMove && (!m_show_mouse || m_mousehide_timer.isActive())) { diff --git a/rpcs3/rpcs3qt/gs_frame.h b/rpcs3/rpcs3qt/gs_frame.h index dec383267b..0d57b02e7a 100644 --- a/rpcs3/rpcs3qt/gs_frame.h +++ b/rpcs3/rpcs3qt/gs_frame.h @@ -41,6 +41,7 @@ private: u64 m_frames = 0; std::string m_window_title; QWindow::Visibility m_last_visibility = Visibility::Windowed; + atomic_t m_is_closing = false; atomic_t m_show_mouse = true; bool m_disable_mouse = false; bool m_disable_kb_hotkeys = false; @@ -97,6 +98,7 @@ protected: bool event(QEvent* ev) override; private: + void hide_on_close(); void toggle_mouselock(); void update_cursor(); void handle_cursor(QWindow::Visibility visibility, bool from_event, bool start_idle_timer); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 9d6b5ad4a0..1787ab334c 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -73,6 +73,10 @@ extern void process_qt_events() { if (thread_ctrl::is_main()) { + // NOTE: + // I noticed that calling this from an Emu callback can cause the + // caller to get stuck for a while during newly opened Qt dialogs. + // Adding a timeout here doesn't seem to do anything in that case. QApplication::processEvents(); } }