Host: Add ReportFatalError()

This commit is contained in:
Stenzek 2024-02-25 18:19:54 +10:00
parent 18ba2032ad
commit 9ac9fc0a1e
No known key found for this signature in database
4 changed files with 46 additions and 1 deletions

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "nogui_host.h" #include "nogui_host.h"
@ -327,6 +327,12 @@ void NoGUIHost::SetDefaultSettings(SettingsInterface& si, bool system, bool cont
g_nogui_window->SetDefaultConfig(si); g_nogui_window->SetDefaultConfig(si);
} }
void Host::ReportFatalError(const std::string_view& title, const std::string_view& message)
{
Log_ErrorPrintf("ReportFatalError: %.*s", static_cast<int>(message.size()), message.data());
abort();
}
void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message) void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message)
{ {
if (!title.empty() && !message.empty()) if (!title.empty() && !message.empty())

View file

@ -1553,6 +1553,34 @@ void EmuThread::wakeThread()
QMetaObject::invokeMethod(m_event_loop, "quit", Qt::QueuedConnection); QMetaObject::invokeMethod(m_event_loop, "quit", Qt::QueuedConnection);
} }
void Host::ReportFatalError(const std::string_view& title, const std::string_view& message)
{
auto cb = [title = QtUtils::StringViewToQString(title), message = QtUtils::StringViewToQString(message)]() {
QMessageBox::critical(g_main_window && g_main_window->isVisible() ? g_main_window : nullptr, title, message);
#ifndef __APPLE__
std::quick_exit(EXIT_FAILURE);
#else
_exit(EXIT_FAILURE);
#endif
};
// https://stackoverflow.com/questions/34135624/how-to-properly-execute-gui-operations-in-qt-main-thread
QTimer* timer = new QTimer();
QThread* ui_thread = qApp->thread();
if (QThread::currentThread() == ui_thread)
{
// On UI thread, we can do it straight away.
cb();
}
else
{
timer->moveToThread(ui_thread);
timer->setSingleShot(true);
QObject::connect(timer, &QTimer::timeout, std::move(cb));
QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}
}
void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message) void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message)
{ {
if (!title.empty() && !message.empty()) if (!title.empty() && !message.empty())

View file

@ -17,6 +17,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/crash_handler.h" #include "common/crash_handler.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/memory_settings_interface.h" #include "common/memory_settings_interface.h"
@ -114,6 +115,12 @@ bool RegTestHost::InitializeConfig()
return true; return true;
} }
void Host::ReportFatalError(const std::string_view& title, const std::string_view& message)
{
Log_ErrorPrintf("ReportFatalError: %.*s", static_cast<int>(message.size()), message.data());
abort();
}
void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message) void Host::ReportErrorAsync(const std::string_view& title, const std::string_view& message)
{ {
if (!title.empty() && !message.empty()) if (!title.empty() && !message.empty())

View file

@ -25,6 +25,10 @@ std::optional<std::string> ReadResourceFileToString(std::string_view filename, b
/// Returns the modified time of a resource. /// Returns the modified time of a resource.
std::optional<std::time_t> GetResourceFileTimestamp(std::string_view filename, bool allow_override); std::optional<std::time_t> GetResourceFileTimestamp(std::string_view filename, bool allow_override);
/// Reports a fatal error on the main thread. This does not assume that the main window exists,
/// unlike ReportErrorAsync(), and will exit the application after the popup is closed.
void ReportFatalError(const std::string_view& title, const std::string_view& message);
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller. /// 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 ReportErrorAsync(const std::string_view& title, const std::string_view& message);
void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...); void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...);