Host: Add ConfirmMessage() and OpenURL()

This commit is contained in:
Connor McLaughlin 2022-08-20 20:20:36 +10:00 committed by refractionpcsx2
parent d18c8976b9
commit a19045f9d6
8 changed files with 98 additions and 1 deletions

View File

@ -91,6 +91,41 @@ void EmuThread::stopInThread()
m_shutdown_flag.store(true);
}
bool EmuThread::confirmMessage(const QString& title, const QString& message)
{
if (!isOnEmuThread())
{
// This is definitely deadlock risky, but unlikely to happen (why would GS be confirming?).
bool result = false;
QMetaObject::invokeMethod(g_emu_thread, "confirmMessage", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, result), Q_ARG(const QString&, title), Q_ARG(const QString&, message));
return result;
}
// Easy if there's no VM.
if (!VMManager::HasValidVM())
return emit messageConfirmed(title, message);
// Preemptively pause/set surfaceless on the emu thread, because it can't run while the popup is open.
const bool was_paused = (VMManager::GetState() == VMState::Paused);
const bool was_fullscreen = isFullscreen();
if (!was_paused)
VMManager::SetPaused(true);
if (was_fullscreen)
setSurfaceless(true);
// This won't return until the user confirms one way or another.
const bool result = emit messageConfirmed(title, message);
// Resume VM after confirming.
if (was_fullscreen)
setSurfaceless(false);
if (!was_paused)
VMManager::SetPaused(false);
return result;
}
void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
{
if (!isOnEmuThread())

View File

@ -61,6 +61,7 @@ public:
void updatePerformanceMetrics(bool force);
public Q_SLOTS:
bool confirmMessage(const QString& title, const QString& message);
void startVM(std::shared_ptr<VMBootParameters> boot_params);
void resetVM();
void setVMPaused(bool paused);
@ -88,6 +89,8 @@ public Q_SLOTS:
void queueSnapshot(quint32 gsdump_frames);
Q_SIGNALS:
bool messageConfirmed(const QString& title, const QString& message);
DisplayWidget* onCreateDisplayRequested(bool fullscreen, bool render_to_main);
DisplayWidget* onUpdateDisplayRequested(bool fullscreen, bool render_to_main, bool surfaceless);
void onResizeDisplayRequested(qint32 width, qint32 height);

View File

@ -354,6 +354,7 @@ void MainWindow::connectSignals()
void MainWindow::connectVMThreadSignals(EmuThread* thread)
{
connect(thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection);
connect(thread, &EmuThread::onCreateDisplayRequested, this, &MainWindow::createDisplay, Qt::BlockingQueuedConnection);
connect(thread, &EmuThread::onUpdateDisplayRequested, this, &MainWindow::updateDisplay, Qt::BlockingQueuedConnection);
connect(thread, &EmuThread::onDestroyDisplayRequested, this, &MainWindow::destroyDisplay, Qt::BlockingQueuedConnection);
@ -1002,6 +1003,12 @@ void MainWindow::reportError(const QString& title, const QString& message)
QMessageBox::critical(this, title, message);
}
bool MainWindow::confirmMessage(const QString& title, const QString& message)
{
VMLock lock(pauseAndLockVM());
return (QMessageBox::question(this, title, message) == QMessageBox::Yes);
}
void MainWindow::runOnUIThread(const std::function<void()>& func)
{
func();

View File

@ -102,6 +102,7 @@ public Q_SLOTS:
void cancelGameListRefresh();
void invalidateSaveStateCache();
void reportError(const QString& title, const QString& message);
bool confirmMessage(const QString& title, const QString& message);
void runOnUIThread(const std::function<void()>& func);
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool block_until_done = false);
void requestExit();

View File

@ -20,6 +20,7 @@
#include <QtCore/QTimer>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>
#include <QtGui/QClipboard>
#ifdef _WIN32
#include "common/RedtapeWindows.h"
@ -48,6 +49,7 @@
#include "GameList/GameListWidget.h"
#include "MainWindow.h"
#include "QtHost.h"
#include "QtUtils.h"
#include "svnrev.h"
static constexpr u32 SETTINGS_VERSION = 1;
@ -432,6 +434,30 @@ void Host::ReportErrorAsync(const std::string_view& title, const std::string_vie
Q_ARG(const QString&, message.empty() ? QString() : QString::fromUtf8(message.data(), message.size())));
}
bool Host::ConfirmMessage(const std::string_view& title, const std::string_view& message)
{
const QString qtitle(QString::fromUtf8(title.data(), title.size()));
const QString qmessage(QString::fromUtf8(message.data(), message.size()));
return g_emu_thread->confirmMessage(qtitle, qmessage);
}
void Host::OpenURL(const std::string_view& url)
{
QtHost::RunOnUIThread([url = QtUtils::StringViewToQString(url)]() {
QtUtils::OpenURL(g_main_window, QUrl(url));
});
}
bool Host::CopyTextToClipboard(const std::string_view& text)
{
QtHost::RunOnUIThread([text = QtUtils::StringViewToQString(text)]() {
QClipboard* clipboard = QGuiApplication::clipboard();
if (clipboard)
clipboard->setText(text);
});
return true;
}
void Host::OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name)
{
emit g_emu_thread->onInputDeviceConnected(

View File

@ -25,4 +25,14 @@ void Host::ReportFormattedErrorAsync(const std::string_view& title, const char*
std::string message(StringUtil::StdStringFromFormatV(format, ap));
va_end(ap);
ReportErrorAsync(title, message);
}
}
bool Host::ConfirmFormattedMessage(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
return ConfirmMessage(title, message);
}

View File

@ -62,4 +62,14 @@ namespace Host
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportErrorAsync(const std::string_view& title, const std::string_view& message);
void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...);
/// Displays a synchronous confirmation on the UI thread, i.e. blocks the caller.
bool ConfirmMessage(const std::string_view& title, const std::string_view& message);
bool ConfirmFormattedMessage(const std::string_view& title, const char* format, ...);
/// Opens a URL, using the default application.
void OpenURL(const std::string_view& url);
/// Copies the provided text to the host's clipboard, if present.
bool CopyTextToClipboard(const std::string_view& text);
} // namespace Host

View File

@ -102,6 +102,11 @@ void Host::ReportErrorAsync(const std::string_view& title, const std::string_vie
MsgButtons().OK()));
}
bool Host::ConfirmMessage(const std::string_view& title, const std::string_view& message)
{
return true;
}
static std::unique_ptr<HostDisplay> s_host_display;
HostDisplay* Host::AcquireHostDisplay(HostDisplay::RenderAPI api)