mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	HostInterface: Make SetUserDirectory() overridable by frontends
This commit is contained in:
		
							parent
							
								
									11e8a91e30
								
							
						
					
					
						commit
						e7640d5367
					
				|  | @ -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<GameList>(); | ||||
|   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<GameList>(); | ||||
|   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); | ||||
|  |  | |||
|  | @ -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); | ||||
| }; | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include "mainwindow.h" | ||||
| #include "qthostinterface.h" | ||||
| #include <QtWidgets/QApplication> | ||||
| #include <QtWidgets/QMessageBox> | ||||
| #include <memory> | ||||
| 
 | ||||
| static void InitLogging() | ||||
|  | @ -34,11 +35,22 @@ int main(int argc, char* argv[]) | |||
| #endif | ||||
| 
 | ||||
|   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()); | ||||
|   window->show(); | ||||
| 
 | ||||
|   host_interface->refreshGameList(); | ||||
| 
 | ||||
|   return app.exec(); | ||||
|   int result = app.exec(); | ||||
| 
 | ||||
|   window.reset(); | ||||
|   host_interface->Shutdown(); | ||||
|   return result; | ||||
| } | ||||
|  |  | |||
|  | @ -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<SystemBootParameters>(); | ||||
| 
 | ||||
|   // 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<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(); | ||||
|   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<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) | ||||
| { | ||||
|   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) | ||||
| { | ||||
|   std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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 <QtCore/QByteArray> | ||||
| #include <QtCore/QObject> | ||||
|  | @ -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<QSettings> m_qsettings; | ||||
|   std::recursive_mutex m_qsettings_mutex; | ||||
| 
 | ||||
|   MainWindow* m_main_window = nullptr; | ||||
|  |  | |||
|  | @ -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<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) | ||||
|     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<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) | ||||
| { | ||||
|   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)); | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
| }; | ||||
|  | @ -37,9 +37,10 @@ static int Run(int argc, char* argv[]) | |||
| 
 | ||||
|   // create display and host interface
 | ||||
|   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(); | ||||
|     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; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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> 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.
 | ||||
|   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
 | ||||
|     { | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
|  | @ -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) | ||||
|   { | ||||
|  |  | |||
|  | @ -33,8 +33,8 @@ public: | |||
| 
 | ||||
|   using HotkeyInfoList = std::vector<HotkeyInfo>; | ||||
| 
 | ||||
|   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; } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Connor McLaughlin
						Connor McLaughlin