From e7640d5367499a722c51d0e50e7dc39e5442a0b4 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 5 Apr 2020 22:59:06 +1000 Subject: [PATCH] HostInterface: Make SetUserDirectory() overridable by frontends --- src/core/host_interface.cpp | 34 ++++--- src/core/host_interface.h | 10 +- src/duckstation-qt/main.cpp | 14 ++- src/duckstation-qt/qthostinterface.cpp | 91 +++++++++++-------- src/duckstation-qt/qthostinterface.h | 11 ++- src/duckstation-qt/qtsettingsinterface.cpp | 38 ++++---- src/duckstation-qt/qtsettingsinterface.h | 4 +- src/duckstation-sdl/main.cpp | 6 +- src/duckstation-sdl/opengl_host_display.h | 3 +- src/duckstation-sdl/sdl_host_interface.cpp | 66 +++++++++----- src/duckstation-sdl/sdl_host_interface.h | 3 + src/frontend-common/common_host_interface.cpp | 12 +++ src/frontend-common/common_host_interface.h | 4 +- 13 files changed, 188 insertions(+), 108 deletions(-) diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 36c8e5a74..cd672a83d 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -49,14 +49,7 @@ static std::string GetRelativePath(const std::string& path, const char* new_file #endif -HostInterface::HostInterface() -{ - SetUserDirectory(); - CreateUserDirectorySubdirectories(); - m_game_list = std::make_unique(); - m_game_list->SetCacheFilename(GetGameListCacheFileName()); - m_game_list->SetDatabaseFilename(GetGameListDatabaseFileName()); -} +HostInterface::HostInterface() = default; HostInterface::~HostInterface() { @@ -64,6 +57,21 @@ HostInterface::~HostInterface() Assert(!m_system && !m_audio_stream && !m_display); } +bool HostInterface::Initialize() +{ + SetUserDirectory(); + InitializeUserDirectory(); + m_game_list = std::make_unique(); + m_game_list->SetCacheFilename(GetGameListCacheFileName()); + m_game_list->SetDatabaseFilename(GetGameListDatabaseFileName()); + return true; +} + +void HostInterface::Shutdown() +{ + +} + void HostInterface::CreateAudioStream() { m_audio_stream = CreateAudioStream(m_settings.audio_backend); @@ -660,7 +668,10 @@ void HostInterface::SetUserDirectory() m_user_directory = StringUtil::StdStringFromFormat("%s/Library/Application Support/DuckStation", home_path); #endif } +} +void HostInterface::InitializeUserDirectory() +{ Log_InfoPrintf("User directory: \"%s\"", m_user_directory.c_str()); if (m_user_directory.empty()) @@ -673,13 +684,6 @@ void HostInterface::SetUserDirectory() Log_ErrorPrintf("Failed to create user directory \"%s\".", m_user_directory.c_str()); } - // Change to the user directory so that all default/relative paths in the config are after this. - if (!FileSystem::SetWorkingDirectory(m_user_directory.c_str())) - Log_ErrorPrintf("Failed to set working directory to '%s'", m_user_directory.c_str()); -} - -void HostInterface::CreateUserDirectorySubdirectories() -{ bool result = true; result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("bios").c_str(), false); diff --git a/src/core/host_interface.h b/src/core/host_interface.h index f7eccffb9..c98c3a098 100644 --- a/src/core/host_interface.h +++ b/src/core/host_interface.h @@ -44,6 +44,12 @@ public: /// Access to emulated system. ALWAYS_INLINE System* GetSystem() const { return m_system.get(); } + /// Initializes the emulator frontend. + virtual bool Initialize(); + + /// Shuts down the emulator frontend. + virtual void Shutdown(); + bool BootSystem(const SystemBootParameters& parameters); void PauseSystem(bool paused); void ResetSystem(); @@ -149,7 +155,8 @@ protected: virtual void OnControllerTypeChanged(u32 slot); virtual void DrawImGuiWindows(); - void SetUserDirectory(); + /// Sets the base path for the user directory. Can be overridden by platform/frontend/command line. + virtual void SetUserDirectory(); /// Ensures all subdirectories of the user directory are created. void CreateUserDirectorySubdirectories(); @@ -231,6 +238,7 @@ protected: std::mutex m_osd_messages_lock; private: + void InitializeUserDirectory(); void CreateAudioStream(); bool SaveState(const char* filename); }; diff --git a/src/duckstation-qt/main.cpp b/src/duckstation-qt/main.cpp index 74e46dc4a..3b8053ab2 100644 --- a/src/duckstation-qt/main.cpp +++ b/src/duckstation-qt/main.cpp @@ -2,6 +2,7 @@ #include "mainwindow.h" #include "qthostinterface.h" #include +#include #include static void InitLogging() @@ -34,11 +35,22 @@ int main(int argc, char* argv[]) #endif std::unique_ptr host_interface = std::make_unique(); + if (!host_interface->Initialize()) + { + host_interface->Shutdown(); + QMessageBox::critical(nullptr, QObject::tr("DuckStation Error"), + QObject::tr("Failed to initialize host interface. Cannot continue."), QMessageBox::Ok); + return -1; + } std::unique_ptr window = std::make_unique(host_interface.get()); window->show(); host_interface->refreshGameList(); - return app.exec(); + int result = app.exec(); + + window.reset(); + host_interface->Shutdown(); + return result; } diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 9e026c816..c734d1f76 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -29,36 +29,58 @@ Log_SetChannel(QtHostInterface); #include "d3d11displaywidget.h" #endif -QtHostInterface::QtHostInterface(QObject* parent) - : QObject(parent), CommonHostInterface(), - m_qsettings(QString::fromStdString(GetSettingsFileName()), QSettings::IniFormat) +QtHostInterface::QtHostInterface(QObject* parent) : QObject(parent), CommonHostInterface() { qRegisterMetaType(); - - // TODO: This probably should wait until the thread finishes initializing. - loadSettings(); - createThread(); } QtHostInterface::~QtHostInterface() { Assert(!m_display_widget); - stopThread(); } bool QtHostInterface::Initialize() +{ + createThread(); + return m_worker_thread->waitForInit(); +} + +void QtHostInterface::Shutdown() +{ + stopThread(); +} + +bool QtHostInterface::initializeOnThread() { if (!CommonHostInterface::Initialize()) return false; + // make sure the controllers have been detected if (m_controller_interface) m_controller_interface->PollEvents(); + // no need to lock here because the main thread is waiting for us + m_qsettings = std::make_unique(QString::fromStdString(GetSettingsFileName()), QSettings::IniFormat); + QtSettingsInterface si(m_qsettings.get()); + + // check settings validity + const QSettings::Status settings_status = m_qsettings->status(); + if (settings_status != QSettings::NoError) + { + m_qsettings->clear(); + SetDefaultSettings(si); + } + + // load in settings + CheckSettings(si); + m_settings.Load(si); + + // bind buttons/axises updateInputMap(); return true; } -void QtHostInterface::Shutdown() +void QtHostInterface::shutdownOnThread() { CommonHostInterface::Shutdown(); } @@ -101,19 +123,19 @@ bool QtHostInterface::ConfirmMessage(const char* message) QVariant QtHostInterface::getSettingValue(const QString& name, const QVariant& default_value) { std::lock_guard guard(m_qsettings_mutex); - return m_qsettings.value(name, default_value); + return m_qsettings->value(name, default_value); } void QtHostInterface::putSettingValue(const QString& name, const QVariant& value) { std::lock_guard guard(m_qsettings_mutex); - m_qsettings.setValue(name, value); + m_qsettings->setValue(name, value); } void QtHostInterface::removeSettingValue(const QString& name) { std::lock_guard guard(m_qsettings_mutex); - m_qsettings.remove(name); + m_qsettings->remove(name); } void QtHostInterface::setDefaultSettings() @@ -125,7 +147,7 @@ void QtHostInterface::setDefaultSettings() } std::lock_guard guard(m_qsettings_mutex); - QtSettingsInterface si(m_qsettings); + QtSettingsInterface si(m_qsettings.get()); UpdateSettings([this, &si]() { m_settings.Load(si); }); CommonHostInterface::UpdateInputMap(si); } @@ -139,12 +161,12 @@ void QtHostInterface::applySettings() } std::lock_guard guard(m_qsettings_mutex); - QtSettingsInterface si(m_qsettings); + QtSettingsInterface si(m_qsettings.get()); UpdateSettings([this, &si]() { m_settings.Load(si); }); CommonHostInterface::UpdateInputMap(si); // detect when render-to-main flag changes - const bool render_to_main = m_qsettings.value("Main/RenderToMainWindow", true).toBool(); + const bool render_to_main = m_qsettings->value("Main/RenderToMainWindow", true).toBool(); if (m_system && m_display_widget && !m_is_fullscreen && render_to_main != m_is_rendering_to_main) { m_is_rendering_to_main = render_to_main; @@ -152,30 +174,12 @@ void QtHostInterface::applySettings() } } -void QtHostInterface::loadSettings() -{ - // no need to lock here because the emu thread doesn't exist yet - QtSettingsInterface si(m_qsettings); - - const QSettings::Status settings_status = m_qsettings.status(); - if (settings_status != QSettings::NoError) - { - m_qsettings.clear(); - SetDefaultSettings(si); - } - - CheckSettings(si); - m_settings.Load(si); - - // input map update is done on the emu thread -} - void QtHostInterface::refreshGameList(bool invalidate_cache /* = false */, bool invalidate_database /* = false */) { Assert(!isOnWorkerThread()); std::lock_guard lock(m_qsettings_mutex); - QtSettingsInterface si(m_qsettings); + QtSettingsInterface si(m_qsettings.get()); m_game_list->SetSearchDirectoriesFromSettings(si); QtProgressCallback progress(m_main_window); @@ -434,7 +438,7 @@ void QtHostInterface::updateInputMap() } std::lock_guard lock(m_qsettings_mutex); - QtSettingsInterface si(m_qsettings); + QtSettingsInterface si(m_qsettings.get()); CommonHostInterface::UpdateInputMap(si); } @@ -757,8 +761,7 @@ void QtHostInterface::threadEntryPoint() m_worker_thread_event_loop = new QEventLoop(); // set up controller interface and immediate poll to pick up the controller attached events - if (!Initialize()) - Panic("Failed to initialize host interface"); + m_worker_thread->setInitResult(initializeOnThread()); // TODO: Event which flags the thread as ready while (!m_shutdown_flag.load()) @@ -784,7 +787,7 @@ void QtHostInterface::threadEntryPoint() m_controller_interface->PollEvents(); } - Shutdown(); + shutdownOnThread(); delete m_worker_thread_event_loop; m_worker_thread_event_loop = nullptr; @@ -820,3 +823,15 @@ void QtHostInterface::Thread::run() { m_parent->threadEntryPoint(); } + +void QtHostInterface::Thread::setInitResult(bool result) +{ + m_init_result.store(result); + m_init_event.Signal(); +} + +bool QtHostInterface::Thread::waitForInit() +{ + m_init_event.Wait(); + return m_init_result.load(); +} diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h index 2c768c289..401725254 100644 --- a/src/duckstation-qt/qthostinterface.h +++ b/src/duckstation-qt/qthostinterface.h @@ -1,6 +1,7 @@ #pragma once #include "core/host_interface.h" #include "core/system.h" +#include "common/event.h" #include "frontend-common/common_host_interface.h" #include #include @@ -151,24 +152,30 @@ private: Thread(QtHostInterface* parent); ~Thread(); + void setInitResult(bool result); + bool waitForInit(); + protected: void run() override; private: QtHostInterface* m_parent; + std::atomic_bool m_init_result{ false }; + Common::Event m_init_event; }; - void loadSettings(); void createBackgroundControllerPollTimer(); void destroyBackgroundControllerPollTimer(); void createThread(); void stopThread(); void threadEntryPoint(); + bool initializeOnThread(); + void shutdownOnThread(); void renderDisplay(); void wakeThread(); - QSettings m_qsettings; + std::unique_ptr m_qsettings; std::recursive_mutex m_qsettings_mutex; MainWindow* m_main_window = nullptr; diff --git a/src/duckstation-qt/qtsettingsinterface.cpp b/src/duckstation-qt/qtsettingsinterface.cpp index fb30c8585..e770007a9 100644 --- a/src/duckstation-qt/qtsettingsinterface.cpp +++ b/src/duckstation-qt/qtsettingsinterface.cpp @@ -7,18 +7,18 @@ static QString GetFullKey(const char* section, const char* key) return QStringLiteral("%1/%2").arg(section, key); } -QtSettingsInterface::QtSettingsInterface(QSettings& settings) : m_settings(settings) {} +QtSettingsInterface::QtSettingsInterface(QSettings* settings) : m_settings(settings) {} QtSettingsInterface::~QtSettingsInterface() = default; void QtSettingsInterface::Clear() { - m_settings.clear(); + m_settings->clear(); } int QtSettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/) { - QVariant value = m_settings.value(GetFullKey(section, key)); + QVariant value = m_settings->value(GetFullKey(section, key)); if (!value.isValid()) return default_value; @@ -32,7 +32,7 @@ int QtSettingsInterface::GetIntValue(const char* section, const char* key, int d float QtSettingsInterface::GetFloatValue(const char* section, const char* key, float default_value /*= 0.0f*/) { - QVariant value = m_settings.value(GetFullKey(section, key)); + QVariant value = m_settings->value(GetFullKey(section, key)); if (!value.isValid()) return default_value; @@ -46,40 +46,40 @@ float QtSettingsInterface::GetFloatValue(const char* section, const char* key, f bool QtSettingsInterface::GetBoolValue(const char* section, const char* key, bool default_value /*= false*/) { - QVariant value = m_settings.value(GetFullKey(section, key)); + QVariant value = m_settings->value(GetFullKey(section, key)); return value.isValid() ? value.toBool() : default_value; } std::string QtSettingsInterface::GetStringValue(const char* section, const char* key, const char* default_value /*= ""*/) { - QVariant value = m_settings.value(GetFullKey(section, key)); + QVariant value = m_settings->value(GetFullKey(section, key)); return value.isValid() ? value.toString().toStdString() : std::string(default_value); } void QtSettingsInterface::SetIntValue(const char* section, const char* key, int value) { - m_settings.setValue(GetFullKey(section, key), QVariant(value)); + m_settings->setValue(GetFullKey(section, key), QVariant(value)); } void QtSettingsInterface::SetFloatValue(const char* section, const char* key, float value) { - m_settings.setValue(GetFullKey(section, key), QString::number(value)); + m_settings->setValue(GetFullKey(section, key), QString::number(value)); } void QtSettingsInterface::SetBoolValue(const char* section, const char* key, bool value) { - m_settings.setValue(GetFullKey(section, key), QVariant(value)); + m_settings->setValue(GetFullKey(section, key), QVariant(value)); } void QtSettingsInterface::SetStringValue(const char* section, const char* key, const char* value) { - m_settings.setValue(GetFullKey(section, key), QVariant(value)); + m_settings->setValue(GetFullKey(section, key), QVariant(value)); } std::vector QtSettingsInterface::GetStringList(const char* section, const char* key) { - QVariant value = m_settings.value(GetFullKey(section, key)); + QVariant value = m_settings->value(GetFullKey(section, key)); if (value.type() == QVariant::String) return {value.toString().toStdString()}; else if (value.type() != QVariant::StringList) @@ -99,7 +99,7 @@ void QtSettingsInterface::SetStringList(const char* section, const char* key, QString full_key = GetFullKey(section, key); if (items.empty()) { - m_settings.remove(full_key); + m_settings->remove(full_key); return; } @@ -108,28 +108,28 @@ void QtSettingsInterface::SetStringList(const char* section, const char* key, std::transform(items.begin(), items.end(), std::back_inserter(sl), [](const std::string_view& sv) { return QString::fromLocal8Bit(sv.data(), static_cast(sv.size())); }); - m_settings.setValue(full_key, sl); + m_settings->setValue(full_key, sl); } bool QtSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item) { QString full_key = GetFullKey(section, key); - QVariant var = m_settings.value(full_key); + QVariant var = m_settings->value(full_key); QStringList sl = var.toStringList(); if (sl.removeAll(item) == 0) return false; if (sl.isEmpty()) - m_settings.remove(full_key); + m_settings->remove(full_key); else - m_settings.setValue(full_key, sl); + m_settings->setValue(full_key, sl); return true; } bool QtSettingsInterface::AddToStringList(const char* section, const char* key, const char* item) { QString full_key = GetFullKey(section, key); - QVariant var = m_settings.value(full_key); + QVariant var = m_settings->value(full_key); QStringList sl = (var.type() == QVariant::StringList) ? var.toStringList() : QStringList(); QString qitem(item); @@ -137,11 +137,11 @@ bool QtSettingsInterface::AddToStringList(const char* section, const char* key, return false; sl.push_back(qitem); - m_settings.setValue(full_key, sl); + m_settings->setValue(full_key, sl); return true; } void QtSettingsInterface::DeleteValue(const char* section, const char* key) { - m_settings.remove(GetFullKey(section, key)); + m_settings->remove(GetFullKey(section, key)); } diff --git a/src/duckstation-qt/qtsettingsinterface.h b/src/duckstation-qt/qtsettingsinterface.h index 800e03ce9..f3df31465 100644 --- a/src/duckstation-qt/qtsettingsinterface.h +++ b/src/duckstation-qt/qtsettingsinterface.h @@ -6,7 +6,7 @@ class QSettings; class QtSettingsInterface : public SettingsInterface { public: - QtSettingsInterface(QSettings& settings); + QtSettingsInterface(QSettings* settings); ~QtSettingsInterface(); void Clear() override; @@ -29,5 +29,5 @@ public: void DeleteValue(const char* section, const char* key) override; private: - QSettings& m_settings; + QSettings* m_settings; }; \ No newline at end of file diff --git a/src/duckstation-sdl/main.cpp b/src/duckstation-sdl/main.cpp index 984145a24..d5f81d75c 100644 --- a/src/duckstation-sdl/main.cpp +++ b/src/duckstation-sdl/main.cpp @@ -37,9 +37,10 @@ static int Run(int argc, char* argv[]) // create display and host interface std::unique_ptr host_interface = SDLHostInterface::Create(); - if (!host_interface) + if (!host_interface->Initialize()) { - Panic("Failed to create host interface"); + host_interface->Shutdown(); + Panic("Failed to initialize host interface"); SDL_Quit(); return -1; } @@ -61,6 +62,7 @@ static int Run(int argc, char* argv[]) host_interface->Run(); // done + host_interface->Shutdown(); host_interface.reset(); SDL_Quit(); return 0; diff --git a/src/duckstation-sdl/opengl_host_display.h b/src/duckstation-sdl/opengl_host_display.h index a10b6d170..abb645a9c 100644 --- a/src/duckstation-sdl/opengl_host_display.h +++ b/src/duckstation-sdl/opengl_host_display.h @@ -31,6 +31,8 @@ public: void SetVSync(bool enabled) override; + void Render() override; + private: const char* GetGLSLVersionString() const; std::string GetGLSLVersionHeader() const; @@ -39,7 +41,6 @@ private: bool CreateImGuiContext(); bool CreateGLResources(); - void Render() override; void RenderDisplay(); SDL_Window* m_window = nullptr; diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index 9b20d4789..995726b00 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -1,6 +1,7 @@ #include "sdl_host_interface.h" #include "common/assert.h" #include "common/byte_stream.h" +#include "common/file_system.h" #include "common/log.h" #include "common/string_util.h" #include "core/controller.h" @@ -30,17 +31,7 @@ SDLHostInterface::SDLHostInterface() m_run_later_event_id = SDL_RegisterEvents(1); } -SDLHostInterface::~SDLHostInterface() -{ - if (m_display) - { - DestroyDisplay(); - ImGui::DestroyContext(); - } - - if (m_window) - DestroySDLWindow(); -} +SDLHostInterface::~SDLHostInterface() = default; float SDLHostInterface::GetDPIScaleFactor(SDL_Window* window) { @@ -292,30 +283,55 @@ void SDLHostInterface::SetFullscreen(bool enabled) std::unique_ptr SDLHostInterface::Create() { - std::unique_ptr intf = std::make_unique(); + return std::make_unique(); +} + +bool SDLHostInterface::Initialize() +{ + if (!HostInterface::Initialize()) + return false; + + // Change to the user directory so that all default/relative paths in the config are after this. + if (!FileSystem::SetWorkingDirectory(m_user_directory.c_str())) + Log_ErrorPrintf("Failed to set working directory to '%s'", m_user_directory.c_str()); // Settings need to be loaded prior to creating the window for OpenGL bits. - INISettingsInterface si(intf->GetSettingsFileName()); - intf->m_settings_copy.Load(si); - intf->m_settings = intf->m_settings_copy; - intf->m_fullscreen = intf->m_settings_copy.start_fullscreen; + INISettingsInterface si(GetSettingsFileName()); + m_settings_copy.Load(si); + m_settings = m_settings_copy; + m_fullscreen = m_settings_copy.start_fullscreen; - if (!intf->CreateSDLWindow()) + if (!CreateSDLWindow()) { Log_ErrorPrintf("Failed to create SDL window"); - return nullptr; + return false; } - intf->CreateImGuiContext(); - if (!intf->CreateDisplay()) + CreateImGuiContext(); + if (!CreateDisplay()) { Log_ErrorPrintf("Failed to create host display"); - return nullptr; + return false; } ImGui::NewFrame(); + return true; +} - return intf; +void SDLHostInterface::Shutdown() +{ + DestroySystem(); + + if (m_display) + { + DestroyDisplay(); + ImGui::DestroyContext(); + } + + if (m_window) + DestroySDLWindow(); + + HostInterface::Shutdown(); } void SDLHostInterface::ReportError(const char* message) @@ -356,7 +372,7 @@ bool SDLHostInterface::ConfirmMessage(const char* message) void SDLHostInterface::HandleSDLEvent(const SDL_Event* event) { ImGui_ImplSDL2_ProcessEvent(event); - //g_sdl_controller_interface.ProcessSDLEvent(event); + // g_sdl_controller_interface.ProcessSDLEvent(event); switch (event->type) { @@ -388,7 +404,7 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event) case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEREMOVED: - //g_sdl_controller_interface.SetDefaultBindings(); + // g_sdl_controller_interface.SetDefaultBindings(); break; case SDL_CONTROLLERBUTTONDOWN: @@ -1425,7 +1441,7 @@ void SDLHostInterface::Run() } } - //g_sdl_controller_interface.UpdateControllerRumble(); + // g_sdl_controller_interface.UpdateControllerRumble(); // rendering { diff --git a/src/duckstation-sdl/sdl_host_interface.h b/src/duckstation-sdl/sdl_host_interface.h index 8376237b9..147da2485 100644 --- a/src/duckstation-sdl/sdl_host_interface.h +++ b/src/duckstation-sdl/sdl_host_interface.h @@ -29,6 +29,9 @@ public: void ReportMessage(const char* message) override; bool ConfirmMessage(const char* message) override; + bool Initialize(); + void Shutdown() override; + void Run(); protected: diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 010f203dc..ab6b6445b 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -1,6 +1,7 @@ #include "common_host_interface.h" #include "common/assert.h" #include "common/audio_stream.h" +#include "common/file_system.h" #include "common/log.h" #include "common/string_util.h" #include "controller_interface.h" @@ -21,6 +22,13 @@ CommonHostInterface::~CommonHostInterface() = default; bool CommonHostInterface::Initialize() { + if (!HostInterface::Initialize()) + return false; + + // Change to the user directory so that all default/relative paths in the config are after this. + if (!FileSystem::SetWorkingDirectory(m_user_directory.c_str())) + Log_ErrorPrintf("Failed to set working directory to '%s'", m_user_directory.c_str()); + RegisterGeneralHotkeys(); RegisterGraphicsHotkeys(); RegisterSaveStateHotkeys(); @@ -41,8 +49,12 @@ bool CommonHostInterface::Initialize() void CommonHostInterface::Shutdown() { + HostInterface::Shutdown(); + m_system.reset(); m_audio_stream.reset(); + if (m_display) + ReleaseHostDisplay(); if (m_controller_interface) { diff --git a/src/frontend-common/common_host_interface.h b/src/frontend-common/common_host_interface.h index dafe2515d..618fd3807 100644 --- a/src/frontend-common/common_host_interface.h +++ b/src/frontend-common/common_host_interface.h @@ -33,8 +33,8 @@ public: using HotkeyInfoList = std::vector; - virtual bool Initialize(); - virtual void Shutdown(); + virtual bool Initialize() override; + virtual void Shutdown() override; /// Returns a list of all available hotkeys. ALWAYS_INLINE const HotkeyInfoList& GetHotkeyInfoList() const { return m_hotkeys; }