HostInterface: Make SetUserDirectory() overridable by frontends

This commit is contained in:
Connor McLaughlin 2020-04-05 22:59:06 +10:00
parent 11e8a91e30
commit e7640d5367
13 changed files with 188 additions and 108 deletions

View File

@ -49,14 +49,7 @@ static std::string GetRelativePath(const std::string& path, const char* new_file
#endif #endif
HostInterface::HostInterface() HostInterface::HostInterface() = default;
{
SetUserDirectory();
CreateUserDirectorySubdirectories();
m_game_list = std::make_unique<GameList>();
m_game_list->SetCacheFilename(GetGameListCacheFileName());
m_game_list->SetDatabaseFilename(GetGameListDatabaseFileName());
}
HostInterface::~HostInterface() HostInterface::~HostInterface()
{ {
@ -64,6 +57,21 @@ HostInterface::~HostInterface()
Assert(!m_system && !m_audio_stream && !m_display); Assert(!m_system && !m_audio_stream && !m_display);
} }
bool HostInterface::Initialize()
{
SetUserDirectory();
InitializeUserDirectory();
m_game_list = std::make_unique<GameList>();
m_game_list->SetCacheFilename(GetGameListCacheFileName());
m_game_list->SetDatabaseFilename(GetGameListDatabaseFileName());
return true;
}
void HostInterface::Shutdown()
{
}
void HostInterface::CreateAudioStream() void HostInterface::CreateAudioStream()
{ {
m_audio_stream = CreateAudioStream(m_settings.audio_backend); 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); m_user_directory = StringUtil::StdStringFromFormat("%s/Library/Application Support/DuckStation", home_path);
#endif #endif
} }
}
void HostInterface::InitializeUserDirectory()
{
Log_InfoPrintf("User directory: \"%s\"", m_user_directory.c_str()); Log_InfoPrintf("User directory: \"%s\"", m_user_directory.c_str());
if (m_user_directory.empty()) 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()); 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; bool result = true;
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("bios").c_str(), false); result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("bios").c_str(), false);

View File

@ -44,6 +44,12 @@ public:
/// Access to emulated system. /// Access to emulated system.
ALWAYS_INLINE System* GetSystem() const { return m_system.get(); } 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); bool BootSystem(const SystemBootParameters& parameters);
void PauseSystem(bool paused); void PauseSystem(bool paused);
void ResetSystem(); void ResetSystem();
@ -149,7 +155,8 @@ protected:
virtual void OnControllerTypeChanged(u32 slot); virtual void OnControllerTypeChanged(u32 slot);
virtual void DrawImGuiWindows(); 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. /// Ensures all subdirectories of the user directory are created.
void CreateUserDirectorySubdirectories(); void CreateUserDirectorySubdirectories();
@ -231,6 +238,7 @@ protected:
std::mutex m_osd_messages_lock; std::mutex m_osd_messages_lock;
private: private:
void InitializeUserDirectory();
void CreateAudioStream(); void CreateAudioStream();
bool SaveState(const char* filename); bool SaveState(const char* filename);
}; };

View File

@ -2,6 +2,7 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "qthostinterface.h" #include "qthostinterface.h"
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>
#include <memory> #include <memory>
static void InitLogging() static void InitLogging()
@ -34,11 +35,22 @@ int main(int argc, char* argv[])
#endif #endif
std::unique_ptr<QtHostInterface> host_interface = std::make_unique<QtHostInterface>(); std::unique_ptr<QtHostInterface> host_interface = std::make_unique<QtHostInterface>();
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<MainWindow> window = std::make_unique<MainWindow>(host_interface.get()); std::unique_ptr<MainWindow> window = std::make_unique<MainWindow>(host_interface.get());
window->show(); window->show();
host_interface->refreshGameList(); host_interface->refreshGameList();
return app.exec(); int result = app.exec();
window.reset();
host_interface->Shutdown();
return result;
} }

View File

@ -29,36 +29,58 @@ Log_SetChannel(QtHostInterface);
#include "d3d11displaywidget.h" #include "d3d11displaywidget.h"
#endif #endif
QtHostInterface::QtHostInterface(QObject* parent) QtHostInterface::QtHostInterface(QObject* parent) : QObject(parent), CommonHostInterface()
: QObject(parent), CommonHostInterface(),
m_qsettings(QString::fromStdString(GetSettingsFileName()), QSettings::IniFormat)
{ {
qRegisterMetaType<SystemBootParameters>(); qRegisterMetaType<SystemBootParameters>();
// TODO: This probably should wait until the thread finishes initializing.
loadSettings();
createThread();
} }
QtHostInterface::~QtHostInterface() QtHostInterface::~QtHostInterface()
{ {
Assert(!m_display_widget); Assert(!m_display_widget);
stopThread();
} }
bool QtHostInterface::Initialize() bool QtHostInterface::Initialize()
{
createThread();
return m_worker_thread->waitForInit();
}
void QtHostInterface::Shutdown()
{
stopThread();
}
bool QtHostInterface::initializeOnThread()
{ {
if (!CommonHostInterface::Initialize()) if (!CommonHostInterface::Initialize())
return false; return false;
// make sure the controllers have been detected
if (m_controller_interface) if (m_controller_interface)
m_controller_interface->PollEvents(); m_controller_interface->PollEvents();
// no need to lock here because the main thread is waiting for us
m_qsettings = std::make_unique<QSettings>(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(); updateInputMap();
return true; return true;
} }
void QtHostInterface::Shutdown() void QtHostInterface::shutdownOnThread()
{ {
CommonHostInterface::Shutdown(); CommonHostInterface::Shutdown();
} }
@ -101,19 +123,19 @@ bool QtHostInterface::ConfirmMessage(const char* message)
QVariant QtHostInterface::getSettingValue(const QString& name, const QVariant& default_value) QVariant QtHostInterface::getSettingValue(const QString& name, const QVariant& default_value)
{ {
std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex); std::lock_guard<std::recursive_mutex> 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) void QtHostInterface::putSettingValue(const QString& name, const QVariant& value)
{ {
std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex); std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex);
m_qsettings.setValue(name, value); m_qsettings->setValue(name, value);
} }
void QtHostInterface::removeSettingValue(const QString& name) void QtHostInterface::removeSettingValue(const QString& name)
{ {
std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex); std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex);
m_qsettings.remove(name); m_qsettings->remove(name);
} }
void QtHostInterface::setDefaultSettings() void QtHostInterface::setDefaultSettings()
@ -125,7 +147,7 @@ void QtHostInterface::setDefaultSettings()
} }
std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex); std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex);
QtSettingsInterface si(m_qsettings); QtSettingsInterface si(m_qsettings.get());
UpdateSettings([this, &si]() { m_settings.Load(si); }); UpdateSettings([this, &si]() { m_settings.Load(si); });
CommonHostInterface::UpdateInputMap(si); CommonHostInterface::UpdateInputMap(si);
} }
@ -139,12 +161,12 @@ void QtHostInterface::applySettings()
} }
std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex); std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex);
QtSettingsInterface si(m_qsettings); QtSettingsInterface si(m_qsettings.get());
UpdateSettings([this, &si]() { m_settings.Load(si); }); UpdateSettings([this, &si]() { m_settings.Load(si); });
CommonHostInterface::UpdateInputMap(si); CommonHostInterface::UpdateInputMap(si);
// detect when render-to-main flag changes // 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) 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; 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 */) void QtHostInterface::refreshGameList(bool invalidate_cache /* = false */, bool invalidate_database /* = false */)
{ {
Assert(!isOnWorkerThread()); Assert(!isOnWorkerThread());
std::lock_guard<std::recursive_mutex> lock(m_qsettings_mutex); std::lock_guard<std::recursive_mutex> lock(m_qsettings_mutex);
QtSettingsInterface si(m_qsettings); QtSettingsInterface si(m_qsettings.get());
m_game_list->SetSearchDirectoriesFromSettings(si); m_game_list->SetSearchDirectoriesFromSettings(si);
QtProgressCallback progress(m_main_window); QtProgressCallback progress(m_main_window);
@ -434,7 +438,7 @@ void QtHostInterface::updateInputMap()
} }
std::lock_guard<std::recursive_mutex> lock(m_qsettings_mutex); std::lock_guard<std::recursive_mutex> lock(m_qsettings_mutex);
QtSettingsInterface si(m_qsettings); QtSettingsInterface si(m_qsettings.get());
CommonHostInterface::UpdateInputMap(si); CommonHostInterface::UpdateInputMap(si);
} }
@ -757,8 +761,7 @@ void QtHostInterface::threadEntryPoint()
m_worker_thread_event_loop = new QEventLoop(); m_worker_thread_event_loop = new QEventLoop();
// set up controller interface and immediate poll to pick up the controller attached events // set up controller interface and immediate poll to pick up the controller attached events
if (!Initialize()) m_worker_thread->setInitResult(initializeOnThread());
Panic("Failed to initialize host interface");
// TODO: Event which flags the thread as ready // TODO: Event which flags the thread as ready
while (!m_shutdown_flag.load()) while (!m_shutdown_flag.load())
@ -784,7 +787,7 @@ void QtHostInterface::threadEntryPoint()
m_controller_interface->PollEvents(); m_controller_interface->PollEvents();
} }
Shutdown(); shutdownOnThread();
delete m_worker_thread_event_loop; delete m_worker_thread_event_loop;
m_worker_thread_event_loop = nullptr; m_worker_thread_event_loop = nullptr;
@ -820,3 +823,15 @@ void QtHostInterface::Thread::run()
{ {
m_parent->threadEntryPoint(); 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();
}

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "core/host_interface.h" #include "core/host_interface.h"
#include "core/system.h" #include "core/system.h"
#include "common/event.h"
#include "frontend-common/common_host_interface.h" #include "frontend-common/common_host_interface.h"
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
#include <QtCore/QObject> #include <QtCore/QObject>
@ -151,24 +152,30 @@ private:
Thread(QtHostInterface* parent); Thread(QtHostInterface* parent);
~Thread(); ~Thread();
void setInitResult(bool result);
bool waitForInit();
protected: protected:
void run() override; void run() override;
private: private:
QtHostInterface* m_parent; QtHostInterface* m_parent;
std::atomic_bool m_init_result{ false };
Common::Event m_init_event;
}; };
void loadSettings();
void createBackgroundControllerPollTimer(); void createBackgroundControllerPollTimer();
void destroyBackgroundControllerPollTimer(); void destroyBackgroundControllerPollTimer();
void createThread(); void createThread();
void stopThread(); void stopThread();
void threadEntryPoint(); void threadEntryPoint();
bool initializeOnThread();
void shutdownOnThread();
void renderDisplay(); void renderDisplay();
void wakeThread(); void wakeThread();
QSettings m_qsettings; std::unique_ptr<QSettings> m_qsettings;
std::recursive_mutex m_qsettings_mutex; std::recursive_mutex m_qsettings_mutex;
MainWindow* m_main_window = nullptr; MainWindow* m_main_window = nullptr;

View File

@ -7,18 +7,18 @@ static QString GetFullKey(const char* section, const char* key)
return QStringLiteral("%1/%2").arg(section, 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; QtSettingsInterface::~QtSettingsInterface() = default;
void QtSettingsInterface::Clear() void QtSettingsInterface::Clear()
{ {
m_settings.clear(); m_settings->clear();
} }
int QtSettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/) 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()) if (!value.isValid())
return default_value; 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*/) 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()) if (!value.isValid())
return default_value; 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*/) 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; return value.isValid() ? value.toBool() : default_value;
} }
std::string QtSettingsInterface::GetStringValue(const char* section, const char* key, std::string QtSettingsInterface::GetStringValue(const char* section, const char* key,
const char* default_value /*= ""*/) 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); return value.isValid() ? value.toString().toStdString() : std::string(default_value);
} }
void QtSettingsInterface::SetIntValue(const char* section, const char* key, int 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) 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) 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) 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<std::string> QtSettingsInterface::GetStringList(const char* section, const char* key) std::vector<std::string> 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) if (value.type() == QVariant::String)
return {value.toString().toStdString()}; return {value.toString().toStdString()};
else if (value.type() != QVariant::StringList) 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); QString full_key = GetFullKey(section, key);
if (items.empty()) if (items.empty())
{ {
m_settings.remove(full_key); m_settings->remove(full_key);
return; 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) { std::transform(items.begin(), items.end(), std::back_inserter(sl), [](const std::string_view& sv) {
return QString::fromLocal8Bit(sv.data(), static_cast<int>(sv.size())); return QString::fromLocal8Bit(sv.data(), static_cast<int>(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) bool QtSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
{ {
QString full_key = GetFullKey(section, key); QString full_key = GetFullKey(section, key);
QVariant var = m_settings.value(full_key); QVariant var = m_settings->value(full_key);
QStringList sl = var.toStringList(); QStringList sl = var.toStringList();
if (sl.removeAll(item) == 0) if (sl.removeAll(item) == 0)
return false; return false;
if (sl.isEmpty()) if (sl.isEmpty())
m_settings.remove(full_key); m_settings->remove(full_key);
else else
m_settings.setValue(full_key, sl); m_settings->setValue(full_key, sl);
return true; return true;
} }
bool QtSettingsInterface::AddToStringList(const char* section, const char* key, const char* item) bool QtSettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
{ {
QString full_key = GetFullKey(section, key); 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(); QStringList sl = (var.type() == QVariant::StringList) ? var.toStringList() : QStringList();
QString qitem(item); QString qitem(item);
@ -137,11 +137,11 @@ bool QtSettingsInterface::AddToStringList(const char* section, const char* key,
return false; return false;
sl.push_back(qitem); sl.push_back(qitem);
m_settings.setValue(full_key, sl); m_settings->setValue(full_key, sl);
return true; return true;
} }
void QtSettingsInterface::DeleteValue(const char* section, const char* key) void QtSettingsInterface::DeleteValue(const char* section, const char* key)
{ {
m_settings.remove(GetFullKey(section, key)); m_settings->remove(GetFullKey(section, key));
} }

View File

@ -6,7 +6,7 @@ class QSettings;
class QtSettingsInterface : public SettingsInterface class QtSettingsInterface : public SettingsInterface
{ {
public: public:
QtSettingsInterface(QSettings& settings); QtSettingsInterface(QSettings* settings);
~QtSettingsInterface(); ~QtSettingsInterface();
void Clear() override; void Clear() override;
@ -29,5 +29,5 @@ public:
void DeleteValue(const char* section, const char* key) override; void DeleteValue(const char* section, const char* key) override;
private: private:
QSettings& m_settings; QSettings* m_settings;
}; };

View File

@ -37,9 +37,10 @@ static int Run(int argc, char* argv[])
// create display and host interface // create display and host interface
std::unique_ptr<SDLHostInterface> host_interface = SDLHostInterface::Create(); std::unique_ptr<SDLHostInterface> 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(); SDL_Quit();
return -1; return -1;
} }
@ -61,6 +62,7 @@ static int Run(int argc, char* argv[])
host_interface->Run(); host_interface->Run();
// done // done
host_interface->Shutdown();
host_interface.reset(); host_interface.reset();
SDL_Quit(); SDL_Quit();
return 0; return 0;

View File

@ -31,6 +31,8 @@ public:
void SetVSync(bool enabled) override; void SetVSync(bool enabled) override;
void Render() override;
private: private:
const char* GetGLSLVersionString() const; const char* GetGLSLVersionString() const;
std::string GetGLSLVersionHeader() const; std::string GetGLSLVersionHeader() const;
@ -39,7 +41,6 @@ private:
bool CreateImGuiContext(); bool CreateImGuiContext();
bool CreateGLResources(); bool CreateGLResources();
void Render() override;
void RenderDisplay(); void RenderDisplay();
SDL_Window* m_window = nullptr; SDL_Window* m_window = nullptr;

View File

@ -1,6 +1,7 @@
#include "sdl_host_interface.h" #include "sdl_host_interface.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/byte_stream.h" #include "common/byte_stream.h"
#include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/controller.h" #include "core/controller.h"
@ -30,17 +31,7 @@ SDLHostInterface::SDLHostInterface()
m_run_later_event_id = SDL_RegisterEvents(1); m_run_later_event_id = SDL_RegisterEvents(1);
} }
SDLHostInterface::~SDLHostInterface() SDLHostInterface::~SDLHostInterface() = default;
{
if (m_display)
{
DestroyDisplay();
ImGui::DestroyContext();
}
if (m_window)
DestroySDLWindow();
}
float SDLHostInterface::GetDPIScaleFactor(SDL_Window* window) float SDLHostInterface::GetDPIScaleFactor(SDL_Window* window)
{ {
@ -292,30 +283,55 @@ void SDLHostInterface::SetFullscreen(bool enabled)
std::unique_ptr<SDLHostInterface> SDLHostInterface::Create() std::unique_ptr<SDLHostInterface> SDLHostInterface::Create()
{ {
std::unique_ptr<SDLHostInterface> intf = std::make_unique<SDLHostInterface>(); return std::make_unique<SDLHostInterface>();
}
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. // Settings need to be loaded prior to creating the window for OpenGL bits.
INISettingsInterface si(intf->GetSettingsFileName()); INISettingsInterface si(GetSettingsFileName());
intf->m_settings_copy.Load(si); m_settings_copy.Load(si);
intf->m_settings = intf->m_settings_copy; m_settings = m_settings_copy;
intf->m_fullscreen = intf->m_settings_copy.start_fullscreen; m_fullscreen = m_settings_copy.start_fullscreen;
if (!intf->CreateSDLWindow()) if (!CreateSDLWindow())
{ {
Log_ErrorPrintf("Failed to create SDL window"); Log_ErrorPrintf("Failed to create SDL window");
return nullptr; return false;
} }
intf->CreateImGuiContext(); CreateImGuiContext();
if (!intf->CreateDisplay()) if (!CreateDisplay())
{ {
Log_ErrorPrintf("Failed to create host display"); Log_ErrorPrintf("Failed to create host display");
return nullptr; return false;
} }
ImGui::NewFrame(); 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) void SDLHostInterface::ReportError(const char* message)
@ -356,7 +372,7 @@ bool SDLHostInterface::ConfirmMessage(const char* message)
void SDLHostInterface::HandleSDLEvent(const SDL_Event* event) void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
{ {
ImGui_ImplSDL2_ProcessEvent(event); ImGui_ImplSDL2_ProcessEvent(event);
//g_sdl_controller_interface.ProcessSDLEvent(event); // g_sdl_controller_interface.ProcessSDLEvent(event);
switch (event->type) switch (event->type)
{ {
@ -388,7 +404,7 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED: case SDL_CONTROLLERDEVICEREMOVED:
//g_sdl_controller_interface.SetDefaultBindings(); // g_sdl_controller_interface.SetDefaultBindings();
break; break;
case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONDOWN:
@ -1425,7 +1441,7 @@ void SDLHostInterface::Run()
} }
} }
//g_sdl_controller_interface.UpdateControllerRumble(); // g_sdl_controller_interface.UpdateControllerRumble();
// rendering // rendering
{ {

View File

@ -29,6 +29,9 @@ public:
void ReportMessage(const char* message) override; void ReportMessage(const char* message) override;
bool ConfirmMessage(const char* message) override; bool ConfirmMessage(const char* message) override;
bool Initialize();
void Shutdown() override;
void Run(); void Run();
protected: protected:

View File

@ -1,6 +1,7 @@
#include "common_host_interface.h" #include "common_host_interface.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/audio_stream.h" #include "common/audio_stream.h"
#include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "controller_interface.h" #include "controller_interface.h"
@ -21,6 +22,13 @@ CommonHostInterface::~CommonHostInterface() = default;
bool CommonHostInterface::Initialize() 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(); RegisterGeneralHotkeys();
RegisterGraphicsHotkeys(); RegisterGraphicsHotkeys();
RegisterSaveStateHotkeys(); RegisterSaveStateHotkeys();
@ -41,8 +49,12 @@ bool CommonHostInterface::Initialize()
void CommonHostInterface::Shutdown() void CommonHostInterface::Shutdown()
{ {
HostInterface::Shutdown();
m_system.reset(); m_system.reset();
m_audio_stream.reset(); m_audio_stream.reset();
if (m_display)
ReleaseHostDisplay();
if (m_controller_interface) if (m_controller_interface)
{ {

View File

@ -33,8 +33,8 @@ public:
using HotkeyInfoList = std::vector<HotkeyInfo>; using HotkeyInfoList = std::vector<HotkeyInfo>;
virtual bool Initialize(); virtual bool Initialize() override;
virtual void Shutdown(); virtual void Shutdown() override;
/// Returns a list of all available hotkeys. /// Returns a list of all available hotkeys.
ALWAYS_INLINE const HotkeyInfoList& GetHotkeyInfoList() const { return m_hotkeys; } ALWAYS_INLINE const HotkeyInfoList& GetHotkeyInfoList() const { return m_hotkeys; }