mirror of https://github.com/PCSX2/pcsx2.git
Qt: Rework VM pausing when popup dialogs are opened
Also cleans up fullscreen transitions further.
This commit is contained in:
parent
ec0e9f078c
commit
90707c453d
|
@ -136,7 +136,7 @@ void EmuThread::setVMPaused(bool paused)
|
|||
}
|
||||
|
||||
// if we were surfaceless (view->game list, system->unpause), get our display widget back
|
||||
if (m_is_surfaceless)
|
||||
if (!paused && m_is_surfaceless)
|
||||
setSurfaceless(false);
|
||||
|
||||
VMManager::SetPaused(paused);
|
||||
|
@ -872,23 +872,6 @@ void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false
|
|||
Q_ARG(const std::function<void()>&, std::move(function)));
|
||||
}
|
||||
|
||||
ScopedVMPause::ScopedVMPause(bool was_paused, bool was_fullscreen)
|
||||
: m_was_paused(was_paused), m_was_fullscreen(was_fullscreen)
|
||||
{
|
||||
if (was_fullscreen)
|
||||
g_emu_thread->setFullscreen(false);
|
||||
if (!m_was_paused)
|
||||
g_emu_thread->setVMPaused(true);
|
||||
}
|
||||
|
||||
ScopedVMPause::~ScopedVMPause()
|
||||
{
|
||||
if (!m_was_paused)
|
||||
g_emu_thread->setVMPaused(false);
|
||||
if (m_was_fullscreen)
|
||||
g_emu_thread->setFullscreen(true);
|
||||
}
|
||||
|
||||
alignas(16) static SysMtgsThread s_mtgs_thread;
|
||||
|
||||
SysMtgsThread& GetMTGS()
|
||||
|
|
|
@ -167,21 +167,4 @@ private:
|
|||
int m_last_internal_height = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Helper class to pause/unpause the emulation thread.
|
||||
/// </summary>
|
||||
class ScopedVMPause
|
||||
{
|
||||
public:
|
||||
ScopedVMPause(bool was_paused, bool was_fullscreen);
|
||||
~ScopedVMPause();
|
||||
|
||||
__fi bool WasPaused() const { return m_was_paused; }
|
||||
__fi bool WasFullscreen() const { return m_was_fullscreen; }
|
||||
|
||||
private:
|
||||
bool m_was_paused;
|
||||
bool m_was_fullscreen;
|
||||
};
|
||||
|
||||
extern EmuThread* g_emu_thread;
|
||||
|
|
|
@ -740,8 +740,8 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
|||
// only confirm on UI thread because we need to display a msgbox
|
||||
if (allow_confirm && !GSDumpReplayer::IsReplayingDump() && QtHost::GetBaseBoolSettingValue("UI", "ConfirmShutdown", true))
|
||||
{
|
||||
ScopedVMPause pauser(m_vm_paused, isRenderingFullscreen());
|
||||
if (QMessageBox::question(m_display_widget, tr("Confirm Shutdown"),
|
||||
VMLock lock(pauseAndLockVM());
|
||||
if (QMessageBox::question(lock.getDialogParent(), tr("Confirm Shutdown"),
|
||||
tr("Are you sure you want to shut down the virtual machine?\n\nAll unsaved progress will be lost.")) != QMessageBox::Yes)
|
||||
{
|
||||
return false;
|
||||
|
@ -911,9 +911,8 @@ void MainWindow::onStartBIOSActionTriggered()
|
|||
|
||||
void MainWindow::onChangeDiscFromFileActionTriggered()
|
||||
{
|
||||
ScopedVMPause pauser(m_vm_paused, isRenderingFullscreen());
|
||||
|
||||
QString filename = QFileDialog::getOpenFileName(this, tr("Select Disc Image"), QString(), tr(DISC_IMAGE_FILTER), nullptr);
|
||||
VMLock lock(pauseAndLockVM());
|
||||
QString filename = QFileDialog::getOpenFileName(lock.getDialogParent(), tr("Select Disc Image"), QString(), tr(DISC_IMAGE_FILTER), nullptr);
|
||||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
|
@ -1102,6 +1101,8 @@ void MainWindow::onVMResumed()
|
|||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
m_status_fps_widget->setText(m_last_fps_status);
|
||||
if (m_display_widget)
|
||||
m_display_widget->setFocus();
|
||||
}
|
||||
|
||||
void MainWindow::onVMStopped()
|
||||
|
@ -1227,12 +1228,13 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
|||
|
||||
DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, bool surfaceless)
|
||||
{
|
||||
DevCon.WriteLn("updateDisplay(%u, %u, %u)", static_cast<u32>(fullscreen), static_cast<u32>(render_to_main), static_cast<u32>(surfaceless));
|
||||
DevCon.WriteLn("updateDisplay() fullscreen=%s render_to_main=%s surfaceless=%s",
|
||||
fullscreen ? "true" : "false", render_to_main ? "true" : "false", surfaceless ? "true" : "false");
|
||||
|
||||
HostDisplay* host_display = Host::GetHostDisplay();
|
||||
QWidget* container = m_display_container ? static_cast<QWidget*>(m_display_container) : static_cast<QWidget*>(m_display_widget);
|
||||
const bool is_fullscreen = (container && container->isFullScreen());
|
||||
const bool is_rendering_to_main = (!is_fullscreen && container && container->parent());
|
||||
const bool is_fullscreen = isRenderingFullscreen();
|
||||
const bool is_rendering_to_main = isRenderingToMain();
|
||||
const std::string fullscreen_mode(QtHost::GetBaseStringSettingValue("EmuCore/GS", "FullscreenMode", ""));
|
||||
const bool is_exclusive_fullscreen = (fullscreen && !fullscreen_mode.empty() && host_display->SupportsFullscreen());
|
||||
const bool changing_surfaceless = (!m_display_widget != surfaceless);
|
||||
|
@ -1245,10 +1247,14 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b
|
|||
const bool needs_container = DisplayContainer::IsNeeded(fullscreen, render_to_main);
|
||||
if (!is_rendering_to_main && !render_to_main && !is_exclusive_fullscreen && has_container == needs_container && !needs_container && !changing_surfaceless)
|
||||
{
|
||||
Console.WriteLn("Toggling to %s without recreating surface", (fullscreen ? "fullscreen" : "windowed"));
|
||||
DevCon.WriteLn("Toggling to %s without recreating surface", (fullscreen ? "fullscreen" : "windowed"));
|
||||
if (host_display->IsFullscreen())
|
||||
host_display->SetFullscreen(false, 0, 0, 0.0f);
|
||||
|
||||
// since we don't destroy the display widget, we need to save it here
|
||||
if (!is_fullscreen && !is_rendering_to_main)
|
||||
saveDisplayWindowGeometryToConfig();
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
container->showFullScreen();
|
||||
|
@ -1395,6 +1401,13 @@ QWidget* MainWindow::getDisplayContainer() const
|
|||
|
||||
void MainWindow::saveDisplayWindowGeometryToConfig()
|
||||
{
|
||||
QWidget* container = getDisplayContainer();
|
||||
if (container->windowState() & Qt::WindowFullScreen)
|
||||
{
|
||||
// if we somehow ended up here, don't save the fullscreen state to the config
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray geometry = getDisplayContainer()->saveGeometry();
|
||||
const QByteArray geometry_b64 = geometry.toBase64();
|
||||
const std::string old_geometry_b64 = QtHost::GetBaseStringSettingValue("UI", "DisplayWindowGeometry");
|
||||
|
@ -1408,9 +1421,17 @@ void MainWindow::restoreDisplayWindowGeometryFromConfig()
|
|||
const QByteArray geometry = QByteArray::fromBase64(QByteArray::fromStdString(geometry_b64));
|
||||
QWidget* container = getDisplayContainer();
|
||||
if (!geometry.isEmpty())
|
||||
{
|
||||
container->restoreGeometry(geometry);
|
||||
|
||||
// make sure we're not loading a dodgy config which had fullscreen set...
|
||||
container->setWindowState(container->windowState() & ~(Qt::WindowFullScreen | Qt::WindowActive));
|
||||
}
|
||||
else
|
||||
{
|
||||
// default size
|
||||
container->resize(640, 480);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplayWidget()
|
||||
|
@ -1418,8 +1439,7 @@ void MainWindow::destroyDisplayWidget()
|
|||
if (!m_display_widget)
|
||||
return;
|
||||
|
||||
const QWidget* container = m_display_container ? static_cast<QWidget*>(m_display_container) : static_cast<QWidget*>(m_display_widget);
|
||||
if (!container->parent() && !container->isFullScreen())
|
||||
if (!isRenderingFullscreen() && !isRenderingToMain())
|
||||
saveDisplayWindowGeometryToConfig();
|
||||
|
||||
if (m_display_container)
|
||||
|
@ -1720,3 +1740,48 @@ void MainWindow::doDiscChange(const QString& path)
|
|||
if (reset_system)
|
||||
g_emu_thread->resetVM();
|
||||
}
|
||||
|
||||
MainWindow::VMLock MainWindow::pauseAndLockVM()
|
||||
{
|
||||
const bool was_fullscreen = isRenderingFullscreen();
|
||||
const bool was_paused = m_vm_paused;
|
||||
|
||||
// We use surfaceless rather than switching out of fullscreen, because
|
||||
// we're paused, so we're not going to be rendering anyway.
|
||||
if (was_fullscreen)
|
||||
g_emu_thread->setSurfaceless(true);
|
||||
if (!was_paused)
|
||||
g_emu_thread->setVMPaused(true);
|
||||
|
||||
// We want to parent dialogs to the display widget, except if we were fullscreen,
|
||||
// since it's going to get destroyed by the surfaceless call above.
|
||||
QWidget* dialog_parent = was_fullscreen ? static_cast<QWidget*>(this) : getDisplayContainer();
|
||||
|
||||
return VMLock(dialog_parent, was_paused, was_fullscreen);
|
||||
}
|
||||
|
||||
MainWindow::VMLock::VMLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen)
|
||||
: m_dialog_parent(dialog_parent)
|
||||
, m_was_paused(was_paused)
|
||||
, m_was_fullscreen(was_fullscreen)
|
||||
{
|
||||
}
|
||||
|
||||
MainWindow::VMLock::VMLock(VMLock&& lock)
|
||||
: m_dialog_parent(lock.m_dialog_parent)
|
||||
, m_was_paused(lock.m_was_paused)
|
||||
, m_was_fullscreen(lock.m_was_fullscreen)
|
||||
{
|
||||
lock.m_dialog_parent = nullptr;
|
||||
lock.m_was_paused = false;
|
||||
lock.m_was_fullscreen = false;
|
||||
}
|
||||
|
||||
MainWindow::VMLock::~VMLock()
|
||||
{
|
||||
if (m_was_fullscreen)
|
||||
g_emu_thread->setSurfaceless(false);
|
||||
if (!m_was_paused)
|
||||
g_emu_thread->setVMPaused(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,33 @@ class MainWindow final : public QMainWindow
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// This class is a scoped lock on the VM, which prevents it from running while
|
||||
/// the object exists. Its purpose is to be used for blocking/modal popup boxes,
|
||||
/// where the VM needs to exit fullscreen temporarily.
|
||||
class VMLock
|
||||
{
|
||||
public:
|
||||
VMLock(VMLock&& lock);
|
||||
VMLock(const VMLock&) = delete;
|
||||
~VMLock();
|
||||
|
||||
/// Returns the parent widget, which can be used for any popup dialogs.
|
||||
__fi QWidget* getDialogParent() const { return m_dialog_parent; }
|
||||
|
||||
/// Cancels any pending unpause/fullscreen transition.
|
||||
/// Call when you're going to destroy the VM anyway.
|
||||
void cancelResume();
|
||||
|
||||
private:
|
||||
VMLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen);
|
||||
friend MainWindow;
|
||||
|
||||
QWidget* m_dialog_parent;
|
||||
bool m_was_paused;
|
||||
bool m_was_fullscreen;
|
||||
};
|
||||
|
||||
/// Default theme name for the platform.
|
||||
static const char* DEFAULT_THEME_NAME;
|
||||
|
||||
public:
|
||||
|
@ -52,6 +79,9 @@ public:
|
|||
void initialize();
|
||||
void connectVMThreadSignals(EmuThread* thread);
|
||||
|
||||
/// Locks the VM by pausing it, while a popup dialog is displayed.
|
||||
VMLock pauseAndLockVM();
|
||||
|
||||
public Q_SLOTS:
|
||||
void refreshGameList(bool invalidate_cache);
|
||||
void invalidateSaveStateCache();
|
||||
|
|
Loading…
Reference in New Issue