diff --git a/Core/Config.cpp b/Core/Config.cpp index 27a5b7507d..5b2779e13a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -71,13 +71,15 @@ struct ConfigSetting { TYPE_FLOAT, TYPE_STRING, TYPE_TOUCH_POS, + TYPE_PATH, }; - union Value { + union DefaultValue { bool b; int i; uint32_t u; float f; const char *s; + const char *p; // not sure how much point.. ConfigTouchPos touchPos; }; union SettingPtr { @@ -86,6 +88,7 @@ struct ConfigSetting { uint32_t *u; float *f; std::string *s; + Path *p; ConfigTouchPos *touchPos; }; @@ -94,7 +97,8 @@ struct ConfigSetting { typedef uint32_t (*Uint32DefaultCallback)(); typedef float (*FloatDefaultCallback)(); typedef const char *(*StringDefaultCallback)(); - typedef ConfigTouchPos (*TouchPosDefaultCallback)(); + typedef ConfigTouchPos(*TouchPosDefaultCallback)(); + typedef const char *(*PathDefaultCallback)(); union Callback { BoolDefaultCallback b; @@ -102,102 +106,110 @@ struct ConfigSetting { Uint32DefaultCallback u; FloatDefaultCallback f; StringDefaultCallback s; + PathDefaultCallback p; TouchPosDefaultCallback touchPos; }; ConfigSetting(bool v) - : ini_(""), type_(TYPE_TERMINATOR), report_(false), save_(false), perGame_(false) { + : iniKey_(""), type_(TYPE_TERMINATOR), report_(false), save_(false), perGame_(false) { ptr_.b = nullptr; cb_.b = nullptr; } ConfigSetting(const char *ini, bool *v, bool def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_BOOL), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_BOOL), report_(false), save_(save), perGame_(perGame) { ptr_.b = v; cb_.b = nullptr; default_.b = def; } ConfigSetting(const char *ini, int *v, int def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame) { ptr_.i = v; cb_.i = nullptr; default_.i = def; } ConfigSetting(const char *ini, int *v, int def, std::function transTo, std::function transFrom, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame), translateTo_(transTo), translateFrom_(transFrom) { + : iniKey_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame), translateTo_(transTo), translateFrom_(transFrom) { ptr_.i = v; cb_.i = nullptr; default_.i = def; } ConfigSetting(const char *ini, uint32_t *v, uint32_t def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_UINT32), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_UINT32), report_(false), save_(save), perGame_(perGame) { ptr_.u = v; cb_.u = nullptr; default_.u = def; } ConfigSetting(const char *ini, float *v, float def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_FLOAT), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_FLOAT), report_(false), save_(save), perGame_(perGame) { ptr_.f = v; cb_.f = nullptr; default_.f = def; } ConfigSetting(const char *ini, std::string *v, const char *def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_STRING), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_STRING), report_(false), save_(save), perGame_(perGame) { ptr_.s = v; cb_.s = nullptr; default_.s = def; } + ConfigSetting(const char *ini, Path *p, const char *def, bool save = true, bool perGame = false) + : iniKey_(ini), type_(TYPE_PATH), report_(false), save_(save), perGame_(perGame) { + ptr_.p = p; + cb_.p = nullptr; + default_.p = def; + } + ConfigSetting(const char *iniX, const char *iniY, const char *iniScale, const char *iniShow, ConfigTouchPos *v, ConfigTouchPos def, bool save = true, bool perGame = false) - : ini_(iniX), ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(TYPE_TOUCH_POS), report_(false), save_(save), perGame_(perGame) { + : iniKey_(iniX), ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(TYPE_TOUCH_POS), report_(false), save_(save), perGame_(perGame) { ptr_.touchPos = v; cb_.touchPos = nullptr; default_.touchPos = def; } ConfigSetting(const char *ini, bool *v, BoolDefaultCallback def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_BOOL), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_BOOL), report_(false), save_(save), perGame_(perGame) { ptr_.b = v; cb_.b = def; } ConfigSetting(const char *ini, int *v, IntDefaultCallback def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame) { ptr_ .i = v; cb_.i = def; } ConfigSetting(const char *ini, int *v, IntDefaultCallback def, std::function transTo, std::function transFrom, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame), translateTo_(transTo), translateFrom_(transFrom) { + : iniKey_(ini), type_(TYPE_INT), report_(false), save_(save), perGame_(perGame), translateTo_(transTo), translateFrom_(transFrom) { ptr_.i = v; cb_.i = def; } ConfigSetting(const char *ini, uint32_t *v, Uint32DefaultCallback def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_UINT32), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_UINT32), report_(false), save_(save), perGame_(perGame) { ptr_ .u = v; cb_.u = def; } ConfigSetting(const char *ini, float *v, FloatDefaultCallback def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_FLOAT), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_FLOAT), report_(false), save_(save), perGame_(perGame) { ptr_.f = v; cb_.f = def; } ConfigSetting(const char *ini, std::string *v, StringDefaultCallback def, bool save = true, bool perGame = false) - : ini_(ini), type_(TYPE_STRING), report_(false), save_(save), perGame_(perGame) { + : iniKey_(ini), type_(TYPE_STRING), report_(false), save_(save), perGame_(perGame) { ptr_.s = v; cb_.s = def; } ConfigSetting(const char *iniX, const char *iniY, const char *iniScale, const char *iniShow, ConfigTouchPos *v, TouchPosDefaultCallback def, bool save = true, bool perGame = false) - : ini_(iniX), ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(TYPE_TOUCH_POS), report_(false), save_(save), perGame_(perGame) { + : iniKey_(iniX), ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(TYPE_TOUCH_POS), report_(false), save_(save), perGame_(perGame) { ptr_.touchPos = v; cb_.touchPos = def; } @@ -212,39 +224,39 @@ struct ConfigSetting { if (cb_.b) { default_.b = cb_.b(); } - return section->Get(ini_, ptr_.b, default_.b); + return section->Get(iniKey_, ptr_.b, default_.b); case TYPE_INT: if (cb_.i) { default_.i = cb_.i(); } if (translateFrom_) { std::string value; - if (section->Get(ini_, &value, nullptr)) { + if (section->Get(iniKey_, &value, nullptr)) { *ptr_.i = translateFrom_(value); return true; } } - return section->Get(ini_, ptr_.i, default_.i); + return section->Get(iniKey_, ptr_.i, default_.i); case TYPE_UINT32: if (cb_.u) { default_.u = cb_.u(); } - return section->Get(ini_, ptr_.u, default_.u); + return section->Get(iniKey_, ptr_.u, default_.u); case TYPE_FLOAT: if (cb_.f) { default_.f = cb_.f(); } - return section->Get(ini_, ptr_.f, default_.f); + return section->Get(iniKey_, ptr_.f, default_.f); case TYPE_STRING: if (cb_.s) { default_.s = cb_.s(); } - return section->Get(ini_, ptr_.s, default_.s); + return section->Get(iniKey_, ptr_.s, default_.s); case TYPE_TOUCH_POS: if (cb_.touchPos) { default_.touchPos = cb_.touchPos(); } - section->Get(ini_, &ptr_.touchPos->x, default_.touchPos.x); + section->Get(iniKey_, &ptr_.touchPos->x, default_.touchPos.x); section->Get(ini2_, &ptr_.touchPos->y, default_.touchPos.y); section->Get(ini3_, &ptr_.touchPos->scale, default_.touchPos.scale); if (ini4_) { @@ -253,6 +265,18 @@ struct ConfigSetting { ptr_.touchPos->show = default_.touchPos.show; } return true; + case TYPE_PATH: + { + std::string tmp; + if (cb_.p) { + default_.p = cb_.p(); + } + bool result = section->Get(iniKey_, &tmp, default_.p); + if (result) { + *ptr_.p = Path(tmp); + } + return result; + } default: _dbg_assert_msg_(false, "Unexpected ini setting type"); return false; @@ -265,21 +289,23 @@ struct ConfigSetting { switch (type_) { case TYPE_BOOL: - return section->Set(ini_, *ptr_.b); + return section->Set(iniKey_, *ptr_.b); case TYPE_INT: if (translateTo_) { std::string value = translateTo_(*ptr_.i); - return section->Set(ini_, value); + return section->Set(iniKey_, value); } - return section->Set(ini_, *ptr_.i); + return section->Set(iniKey_, *ptr_.i); case TYPE_UINT32: - return section->Set(ini_, *ptr_.u); + return section->Set(iniKey_, *ptr_.u); case TYPE_FLOAT: - return section->Set(ini_, *ptr_.f); + return section->Set(iniKey_, *ptr_.f); case TYPE_STRING: - return section->Set(ini_, *ptr_.s); + return section->Set(iniKey_, *ptr_.s); + case TYPE_PATH: + return section->Set(iniKey_, ptr_.p->ToString()); case TYPE_TOUCH_POS: - section->Set(ini_, ptr_.touchPos->x); + section->Set(iniKey_, ptr_.touchPos->x); section->Set(ini2_, ptr_.touchPos->y); section->Set(ini3_, ptr_.touchPos->scale); if (ini4_) { @@ -298,15 +324,17 @@ struct ConfigSetting { switch (type_) { case TYPE_BOOL: - return data.Add(prefix + ini_, *ptr_.b); + return data.Add(prefix + iniKey_, *ptr_.b); case TYPE_INT: - return data.Add(prefix + ini_, *ptr_.i); + return data.Add(prefix + iniKey_, *ptr_.i); case TYPE_UINT32: - return data.Add(prefix + ini_, *ptr_.u); + return data.Add(prefix + iniKey_, *ptr_.u); case TYPE_FLOAT: - return data.Add(prefix + ini_, *ptr_.f); + return data.Add(prefix + iniKey_, *ptr_.f); case TYPE_STRING: - return data.Add(prefix + ini_, *ptr_.s); + return data.Add(prefix + iniKey_, *ptr_.s); + case TYPE_PATH: + return data.Add(prefix + iniKey_, ptr_.p->ToString()); case TYPE_TOUCH_POS: // Doesn't report. return; @@ -316,7 +344,7 @@ struct ConfigSetting { } } - const char *ini_; + const char *iniKey_; const char *ini2_; const char *ini3_; const char *ini4_; @@ -325,7 +353,7 @@ struct ConfigSetting { bool save_; bool perGame_; SettingPtr ptr_; - Value default_; + DefaultValue default_; Callback cb_; // We only support transform for ints. @@ -1213,7 +1241,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { iRunCount++; if (!File::Exists(Path(currentDirectory))) - currentDirectory = ""; + currentDirectory = defaultCurrentDirectory; Section *log = iniFile.GetOrCreateSection(logSectionName); @@ -1595,7 +1623,7 @@ void Config::RestoreDefaults() { if (File::Exists(iniFilename_)) File::Delete(iniFilename_); recentIsos.clear(); - currentDirectory = ""; + currentDirectory = defaultCurrentDirectory; } Load(); } diff --git a/Core/Config.h b/Core/Config.h index be0fe9589c..d7500b7d6c 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -477,8 +477,9 @@ public: bool bShowFrameProfiler; // Various directories. Autoconfigured, not read from ini. - std::string currentDirectory; - Path externalDirectory; + Path currentDirectory; // The directory selected in the game browsing window. + Path defaultCurrentDirectory; // Platform dependent, initialized at startup. + Path memStickDirectory; Path flash0Directory; Path internalDataDirectory; diff --git a/Core/System.cpp b/Core/System.cpp index c6e510ed88..12473807b4 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -697,7 +697,7 @@ void InitSysDirectories() { File::CreateDir(GetSysDirectory(DIRECTORY_SAVESTATE)); if (g_Config.currentDirectory.empty()) { - g_Config.currentDirectory = GetSysDirectory(DIRECTORY_GAME).ToString(); + g_Config.currentDirectory = GetSysDirectory(DIRECTORY_GAME); } } #endif diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 0e7916b4bc..b642f74421 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -528,7 +528,7 @@ bool MainUI::event(QEvent *e) { QString fileName = QFileDialog::getOpenFileName(nullptr, "Load ROM", g_Config.currentDirectory.c_str(), "PSP ROMs (*.iso *.cso *.pbp *.elf *.zip *.ppdmp)"); if (QFile::exists(fileName)) { QDir newPath; - g_Config.currentDirectory = newPath.filePath(fileName).toStdString(); + g_Config.currentDirectory = Path(newPath.filePath(fileName).toStdString()); g_Config.Save("browseFileEvent"); NativeMessageReceived("boot", fileName.toStdString().c_str()); diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 53e18c23d4..8b766110db 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -122,7 +122,7 @@ void MainWindow::loadAct() if (QFile::exists(filename)) { QFileInfo info(filename); - g_Config.currentDirectory = info.absolutePath().toStdString(); + g_Config.currentDirectory = Path(info.absolutePath().toStdString()); NativeMessageReceived("boot", filename.toStdString().c_str()); } } @@ -252,7 +252,7 @@ void MainWindow::switchUMDAct() if (QFile::exists(filename)) { QFileInfo info(filename); - g_Config.currentDirectory = info.absolutePath().toStdString(); + g_Config.currentDirectory = Path(info.absolutePath().toStdString()); __UmdReplace(Path(filename.toStdString())); } } diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 337a356008..29baf2f2e9 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -592,7 +592,7 @@ void SystemInfoScreen::CreateViews() { storage->Add(new InfoItem("MemStickDirectory", g_Config.memStickDirectory.ToVisualString())); storage->Add(new InfoItem("InternalDataDirectory", g_Config.internalDataDirectory.ToVisualString())); storage->Add(new InfoItem("AppCacheDir", g_Config.appCacheDirectory.ToVisualString())); - storage->Add(new InfoItem("ExtStorageDir", g_Config.externalDirectory.ToVisualString())); + storage->Add(new InfoItem("DefaultCurrentDir", g_Config.defaultCurrentDirectory.ToVisualString())); #if PPSSPP_PLATFORM(ANDROID) storage->Add(new InfoItem("ExtFilesDir", g_extFilesDir)); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 5640fd622b..f88509276a 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -505,7 +505,7 @@ void GameBrowser::FocusGame(const Path &gamePath) { void GameBrowser::SetPath(const Path &path) { path_.SetPath(path); - g_Config.currentDirectory = path_.GetPath().ToString(); + g_Config.currentDirectory = path_.GetPath(); Refresh(); } @@ -905,7 +905,7 @@ UI::EventReturn GameBrowser::NavigateClick(UI::EventParams &e) { } else { path_.Navigate(text.ToString()); } - g_Config.currentDirectory = path_.GetPath().ToString(); + g_Config.currentDirectory = path_.GetPath(); Refresh(); return UI::EVENT_DONE; } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 608b803e49..065482d4a2 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -318,20 +318,9 @@ static bool CheckFontIsUsable(const wchar_t *fontFace) { static void PostLoadConfig() { // On Windows, we deal with currentDirectory in InitSysDirectories(). -#ifndef _WIN32 +#if !PPSSPP_PLATFORM(WINDOWS) if (g_Config.currentDirectory.empty()) { -#if defined(__ANDROID__) - g_Config.currentDirectory = g_Config.externalDirectory.ToString(); -#elif PPSSPP_PLATFORM(IOS) - g_Config.currentDirectory = g_Config.internalDataDirectory.ToString(); -#elif PPSSPP_PLATFORM(SWITCH) - g_Config.currentDirectory = "/"; -#else - if (getenv("HOME") != nullptr) - g_Config.currentDirectory = getenv("HOME"); - else - g_Config.currentDirectory = "./"; -#endif + g_Config.currentDirectory = g_Config.defaultCurrentDirectory; } #endif @@ -457,6 +446,9 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch user_data_path += "/"; #endif + // external_dir has all kinds of meanings depending on platform. + // on iOS it's even the path to bundled app assets. It's a mess. + // We want this to be FIRST. #if PPSSPP_PLATFORM(IOS) // Packed assets are included in app @@ -487,8 +479,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } #endif + g_Config.defaultCurrentDirectory = Path("/"); g_Config.internalDataDirectory = Path(savegame_dir); - g_Config.externalDirectory = Path(external_dir); #if defined(__ANDROID__) // TODO: This needs to change in Android 12. @@ -496,6 +488,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch // Maybe there should be an option to use internal memory instead, but I think // that for most people, using external memory (SDCard/USB Storage) makes the // most sense. + g_Config.defaultCurrentDirectory = Path(external_dir); g_Config.memStickDirectory = Path(external_dir); g_Config.flash0Directory = Path(external_dir) / "flash0"; @@ -511,6 +504,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } } #elif PPSSPP_PLATFORM(IOS) + g_Config.defaultCurrentDirectory = g_Config.internalDataDirectory; g_Config.memStickDirectory = Path(user_data_path); g_Config.flash0Directory = Path(std::string(external_dir)) / "flash0"; #elif PPSSPP_PLATFORM(SWITCH) @@ -527,6 +521,13 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch g_Config.memStickDirectory = Path(config) / "ppsspp"; g_Config.flash0Directory = File::GetExeDirectory() / "assets/flash0"; + if (getenv("HOME") != nullptr) { + g_Config.defaultCurrentDirectory = Path(getenv("HOME")); + } else { + // Hm, should probably actually explicitly set the current directory.. + // Though it's not many platforms that'll land us here. + g_Config.currentDirectory = Path("."); + } #endif if (cache_dir && strlen(cache_dir)) { diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 8eb098fea0..aa2caf6633 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -617,8 +617,8 @@ bool retro_load_game(const struct retro_game_info *game) if (retro_save_dir.empty()) retro_save_dir = Path(game->path).NavigateUp(); - g_Config.currentDirectory = retro_base_dir.ToString(); - g_Config.externalDirectory = retro_base_dir; + g_Config.currentDirectory = retro_base_dir; + g_Config.defaultCurrentDirectory = retro_base_dir; g_Config.memStickDirectory = retro_save_dir; g_Config.flash0Directory = retro_base_dir / "flash0"; g_Config.internalDataDirectory = retro_base_dir;