mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-04-27 14:35:41 -04:00
Qt: Ensure system is shut down before closing
Fixes crash on shutdown on Mac.
This commit is contained in:
parent
1371dcfa4a
commit
0ef24398f8
@ -481,7 +481,7 @@ void RequestResizeHostDisplay(s32 width, s32 height);
|
|||||||
|
|
||||||
/// Requests shut down and exit of the hosting application. This may not actually exit,
|
/// Requests shut down and exit of the hosting application. This may not actually exit,
|
||||||
/// if the user cancels the shutdown confirmation.
|
/// if the user cancels the shutdown confirmation.
|
||||||
void RequestExit(bool save_state_if_running);
|
void RequestExit(bool allow_confirm);
|
||||||
|
|
||||||
/// Requests shut down of the current virtual machine.
|
/// Requests shut down of the current virtual machine.
|
||||||
void RequestSystemShutdown(bool allow_confirm, bool save_state);
|
void RequestSystemShutdown(bool allow_confirm, bool save_state);
|
||||||
|
@ -981,11 +981,11 @@ std::optional<WindowInfo> Host::GetTopLevelWindowInfo()
|
|||||||
return g_nogui_window->GetPlatformWindowInfo();
|
return g_nogui_window->GetPlatformWindowInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::RequestExit(bool save_state_if_running)
|
void Host::RequestExit(bool allow_confirm)
|
||||||
{
|
{
|
||||||
if (System::IsValid())
|
if (System::IsValid())
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([save_state_if_running]() { System::ShutdownSystem(save_state_if_running); });
|
Host::RunOnCPUThread([]() { System::ShutdownSystem(g_settings.save_state_on_exit); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the running flag, this'll break out of the main CPU loop once the VM is shutdown.
|
// clear the running flag, this'll break out of the main CPU loop once the VM is shutdown.
|
||||||
@ -1022,7 +1022,7 @@ static void SignalHandler(int signal)
|
|||||||
{
|
{
|
||||||
std::fprintf(stderr, "Received CTRL+C, attempting graceful shutdown. Press CTRL+C again to force.\n");
|
std::fprintf(stderr, "Received CTRL+C, attempting graceful shutdown. Press CTRL+C again to force.\n");
|
||||||
graceful_shutdown_attempted = true;
|
graceful_shutdown_attempted = true;
|
||||||
Host::RequestExit(true);
|
Host::RequestExit(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ void WaylandNoGUIPlatform::TopLevelConfigure(void* data, struct xdg_toplevel* xd
|
|||||||
|
|
||||||
void WaylandNoGUIPlatform::TopLevelClose(void* data, struct xdg_toplevel* xdg_toplevel)
|
void WaylandNoGUIPlatform::TopLevelClose(void* data, struct xdg_toplevel* xdg_toplevel)
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([]() { Host::RequestExit(g_settings.save_state_on_exit); });
|
Host::RunOnCPUThread([]() { Host::RequestExit(false); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandNoGUIPlatform::SeatCapabilities(void* data, wl_seat* seat, uint32_t capabilities)
|
void WaylandNoGUIPlatform::SeatCapabilities(void* data, wl_seat* seat, uint32_t capabilities)
|
||||||
|
@ -399,7 +399,8 @@ LRESULT CALLBACK Win32NoGUIPlatform::WndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
case WM_QUIT:
|
case WM_QUIT:
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([]() { Host::RequestExit(g_settings.save_state_on_exit); });
|
Host::RunOnCPUThread([]() { Host::RequestExit(false); });
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ void X11NoGUIPlatform::ProcessXEvents()
|
|||||||
case ClientMessage:
|
case ClientMessage:
|
||||||
{
|
{
|
||||||
if (static_cast<Atom>(event.xclient.data.l[0]) == XInternAtom(m_display, "WM_DELETE_WINDOW", False))
|
if (static_cast<Atom>(event.xclient.data.l[0]) == XInternAtom(m_display, "WM_DELETE_WINDOW", False))
|
||||||
Host::RequestExit(true);
|
Host::RequestExit(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -615,6 +615,15 @@ void MainWindow::onSystemDestroyed()
|
|||||||
|
|
||||||
s_system_valid = false;
|
s_system_valid = false;
|
||||||
s_system_paused = false;
|
s_system_paused = false;
|
||||||
|
|
||||||
|
// If we're closing or in batch mode, quit the whole application now.
|
||||||
|
if (m_is_closing || QtHost::InBatchMode())
|
||||||
|
{
|
||||||
|
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||||
|
QCoreApplication::quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateEmulationActions(false, false, Achievements::ChallengeModeActive());
|
updateEmulationActions(false, false, Achievements::ChallengeModeActive());
|
||||||
if (m_display_widget)
|
if (m_display_widget)
|
||||||
updateDisplayWidgetCursor();
|
updateDisplayWidgetCursor();
|
||||||
@ -727,7 +736,12 @@ std::string MainWindow::getDeviceDiscPath(const QString& title)
|
|||||||
void MainWindow::recreate()
|
void MainWindow::recreate()
|
||||||
{
|
{
|
||||||
if (s_system_valid)
|
if (s_system_valid)
|
||||||
requestShutdown(false, true, true, true);
|
{
|
||||||
|
requestShutdown(false, true, true);
|
||||||
|
|
||||||
|
while (s_system_valid)
|
||||||
|
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// We need to close input sources, because e.g. DInput uses our window handle.
|
// We need to close input sources, because e.g. DInput uses our window handle.
|
||||||
g_emu_thread->closeInputSources();
|
g_emu_thread->closeInputSources();
|
||||||
@ -2375,16 +2389,24 @@ void MainWindow::showEvent(QShowEvent* event)
|
|||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent* event)
|
void MainWindow::closeEvent(QCloseEvent* event)
|
||||||
{
|
{
|
||||||
if (!requestShutdown(true, true, true))
|
// If there's no VM, we can just exit as normal.
|
||||||
|
if (!s_system_valid)
|
||||||
{
|
{
|
||||||
event->ignore();
|
QMainWindow::closeEvent(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// But if there is, we have to cancel the action, regardless of whether we ended exiting
|
||||||
|
// or not. The window still needs to be visible while GS is shutting down.
|
||||||
|
event->ignore();
|
||||||
|
|
||||||
|
// Exit cancelled?
|
||||||
|
if (!requestShutdown(true, true, g_settings.save_state_on_exit))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Application will be exited in VM stopped handler.
|
||||||
saveGeometryToConfig();
|
saveGeometryToConfig();
|
||||||
m_is_closing = true;
|
m_is_closing = true;
|
||||||
|
|
||||||
QMainWindow::closeEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::changeEvent(QEvent* event)
|
void MainWindow::changeEvent(QEvent* event)
|
||||||
@ -2473,7 +2495,7 @@ void MainWindow::runOnUIThread(const std::function<void()>& func)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */,
|
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */,
|
||||||
bool save_state /* = true */, bool block_until_done /* = false */)
|
bool save_state /* = true */)
|
||||||
{
|
{
|
||||||
if (!s_system_valid)
|
if (!s_system_valid)
|
||||||
return true;
|
return true;
|
||||||
@ -2518,33 +2540,20 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
|||||||
|
|
||||||
// Now we can actually shut down the VM.
|
// Now we can actually shut down the VM.
|
||||||
g_emu_thread->shutdownSystem(save_state);
|
g_emu_thread->shutdownSystem(save_state);
|
||||||
|
|
||||||
if (block_until_done || m_is_closing || QtHost::InBatchMode())
|
|
||||||
{
|
|
||||||
// We need to yield here, since the display gets destroyed.
|
|
||||||
while (s_system_valid || System::GetState() != System::State::Shutdown)
|
|
||||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_is_closing && QtHost::InBatchMode())
|
|
||||||
{
|
|
||||||
// Closing the window should shut down everything. If we don't set the closing flag here,
|
|
||||||
// the VM shutdown may not complete by the time closeEvent() is called, leading to a confirm.
|
|
||||||
m_is_closing = true;
|
|
||||||
QGuiApplication::quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::requestExit(bool allow_save_to_state /* = true */)
|
void MainWindow::requestExit(bool allow_confirm /* = true */)
|
||||||
{
|
{
|
||||||
// this is block, because otherwise closeEvent() will also prompt
|
// this is block, because otherwise closeEvent() will also prompt
|
||||||
if (!requestShutdown(true, allow_save_to_state, g_settings.save_state_on_exit))
|
if (!requestShutdown(allow_confirm, true, g_settings.save_state_on_exit))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We could use close here, but if we're not visible (e.g. quitting from fullscreen), closing the window
|
// VM stopped signal won't have fired yet, so queue an exit if we still have one.
|
||||||
// doesn't quit the application.
|
// Otherwise, immediately exit, because there's no VM to exit us later.
|
||||||
|
if (s_system_valid)
|
||||||
|
m_is_closing = true;
|
||||||
|
else
|
||||||
QGuiApplication::quit();
|
QGuiApplication::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +99,8 @@ public Q_SLOTS:
|
|||||||
void cancelGameListRefresh();
|
void cancelGameListRefresh();
|
||||||
|
|
||||||
void runOnUIThread(const std::function<void()>& func);
|
void runOnUIThread(const std::function<void()>& func);
|
||||||
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool save_state = true, bool block_until_done = false);
|
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool save_state = true);
|
||||||
void requestExit(bool allow_save_to_state = true);
|
void requestExit(bool allow_confirm = true);
|
||||||
void checkForSettingChanges();
|
void checkForSettingChanges();
|
||||||
void getWindowInfo(WindowInfo* wi);
|
void getWindowInfo(WindowInfo* wi);
|
||||||
|
|
||||||
|
@ -1746,12 +1746,12 @@ void Host::RequestSystemShutdown(bool allow_confirm, bool save_state)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
|
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
|
||||||
Q_ARG(bool, true), Q_ARG(bool, save_state), Q_ARG(bool, false));
|
Q_ARG(bool, true), Q_ARG(bool, save_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::RequestExit(bool save_state_if_running)
|
void Host::RequestExit(bool allow_confirm)
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, save_state_if_running));
|
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, allow_confirm));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<WindowInfo> Host::GetTopLevelWindowInfo()
|
std::optional<WindowInfo> Host::GetTopLevelWindowInfo()
|
||||||
|
@ -1073,7 +1073,7 @@ void FullscreenUI::DoToggleAnalogMode()
|
|||||||
|
|
||||||
void FullscreenUI::DoRequestExit()
|
void FullscreenUI::DoRequestExit()
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([]() { Host::RequestExit(g_settings.save_state_on_exit); });
|
Host::RunOnCPUThread([]() { Host::RequestExit(true); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::DoToggleFullscreen()
|
void FullscreenUI::DoToggleFullscreen()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user