diff --git a/Source/Core/Common/CommonPaths.h b/Source/Core/Common/CommonPaths.h index 0f6b7adfb6..937d461642 100644 --- a/Source/Core/Common/CommonPaths.h +++ b/Source/Core/Common/CommonPaths.h @@ -108,6 +108,9 @@ #define FREELOOK_CONFIG "FreeLook.ini" #define RETROACHIEVEMENTS_CONFIG "RetroAchievements.ini" +// Files in the directory returned by GetUserPath(D_APPLICATIONSTATE_IDX) +#define QSETTINGS_CONFIG "Qt.ini" + // Files in the directory returned by GetUserPath(D_LOGS_IDX) #define MAIN_LOG "dolphin.log" diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 51a841ddec..727254d015 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -847,6 +847,7 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[D_CONFIG_IDX] = s_user_paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; s_user_paths[D_GAMESETTINGS_IDX] = s_user_paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP; s_user_paths[D_MAPS_IDX] = s_user_paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + s_user_paths[D_APPLICATIONSTATE_IDX] = s_user_paths[D_USER_IDX] + DIR_SEP; s_user_paths[D_CACHE_IDX] = s_user_paths[D_USER_IDX] + CACHE_DIR DIR_SEP; s_user_paths[D_COVERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + COVERCACHE_DIR DIR_SEP; s_user_paths[D_REDUMPCACHE_IDX] = s_user_paths[D_CACHE_IDX] + REDUMPCACHE_DIR DIR_SEP; @@ -888,6 +889,7 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[F_GCKEYBOARDCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + GCKEYBOARD_CONFIG; s_user_paths[F_GFXCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + GFX_CONFIG; s_user_paths[F_LOGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + LOGGER_CONFIG; + s_user_paths[F_QSETTINGSCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + QSETTINGS_CONFIG; s_user_paths[F_DUALSHOCKUDPCLIENTCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DUALSHOCKUDPCLIENT_CONFIG; s_user_paths[F_FREELOOKCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + FREELOOK_CONFIG; @@ -932,12 +934,29 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[D_CONFIG_IDX] + RETROACHIEVEMENTS_CONFIG; break; + case D_APPLICATIONSTATE_IDX: + // Use legacy locations if they already exist. + if (!Exists(s_user_paths[F_QSETTINGSCONFIG_IDX])) + s_user_paths[F_QSETTINGSCONFIG_IDX] = s_user_paths[D_APPLICATIONSTATE_IDX] + QSETTINGS_CONFIG; + if (!Exists(s_user_paths[D_LOGS_IDX])) + { + s_user_paths[D_LOGS_IDX] = s_user_paths[D_APPLICATIONSTATE_IDX] + LOGS_DIR DIR_SEP; + s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG; + s_user_paths[D_MAILLOGS_IDX] = s_user_paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP; + } + break; + case D_CACHE_IDX: - s_user_paths[D_COVERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + COVERCACHE_DIR DIR_SEP; - s_user_paths[D_REDUMPCACHE_IDX] = s_user_paths[D_CACHE_IDX] + REDUMPCACHE_DIR DIR_SEP; - s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP; - s_user_paths[D_RETROACHIEVEMENTSCACHE_IDX] = - s_user_paths[D_CACHE_IDX] + RETROACHIEVEMENTSCACHE_DIR DIR_SEP; + // Use legacy locations if they already exist. + if (!Exists(s_user_paths[D_COVERCACHE_IDX])) + s_user_paths[D_COVERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + COVERCACHE_DIR DIR_SEP; + if (!Exists(s_user_paths[D_REDUMPCACHE_IDX])) + s_user_paths[D_REDUMPCACHE_IDX] = s_user_paths[D_CACHE_IDX] + REDUMPCACHE_DIR DIR_SEP; + if (!Exists(s_user_paths[D_SHADERCACHE_IDX])) + s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP; + if (!Exists(s_user_paths[D_RETROACHIEVEMENTSCACHE_IDX])) + s_user_paths[D_RETROACHIEVEMENTSCACHE_IDX] = + s_user_paths[D_CACHE_IDX] + RETROACHIEVEMENTSCACHE_DIR DIR_SEP; break; case D_GCUSER_IDX: diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index a887ffd8f3..780a62ab91 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -28,11 +28,12 @@ enum { D_USER_IDX, D_GCUSER_IDX, - D_WIIROOT_IDX, // always points to User/Wii or global user-configured directory - D_SESSION_WIIROOT_IDX, // may point to minimal temporary directory for determinism - D_CONFIG_IDX, // global settings - D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default - // settings (per game) + D_WIIROOT_IDX, // always points to User/Wii or global user-configured directory + D_SESSION_WIIROOT_IDX, // may point to minimal temporary directory for determinism + D_CONFIG_IDX, // global settings + D_APPLICATIONSTATE_IDX, // data that is not portable (window positions, open recent, etc.) + D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default + // settings (per game) D_SKYLANDERS_IDX, D_MAPS_IDX, @@ -96,6 +97,7 @@ enum F_FREELOOKCONFIG_IDX, F_GBABIOS_IDX, F_RETROACHIEVEMENTSCONFIG_IDX, + F_QSETTINGSCONFIG_IDX, NUM_PATH_INDICES }; diff --git a/Source/Core/DolphinQt/Settings.cpp b/Source/Core/DolphinQt/Settings.cpp index 993f53b621..b472348a23 100644 --- a/Source/Core/DolphinQt/Settings.cpp +++ b/Source/Core/DolphinQt/Settings.cpp @@ -112,9 +112,8 @@ Settings& Settings::Instance() QSettings& Settings::GetQSettings() { - static QSettings settings( - QStringLiteral("%1/Qt.ini").arg(QString::fromStdString(File::GetUserPath(D_CONFIG_IDX))), - QSettings::IniFormat); + const QString filename = QString::fromStdString(File::GetUserPath(F_QSETTINGSCONFIG_IDX)); + static QSettings settings(filename, QSettings::IniFormat); return settings; } diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 309d563864..6c391437e9 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -298,6 +298,9 @@ void SetUserDirectory(std::string custom_path) } std::string user_path; + std::optional application_state_path; + std::optional config_path; + std::optional cache_path; #ifdef _WIN32 // Detect where the User directory is. There are five different cases // (on top of the command line flag, which overrides all this): @@ -305,19 +308,25 @@ void SetUserDirectory(std::string custom_path) // -> Use GetExeDirectory()\User // 2. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true // -> Use GetExeDirectory()\User - // 3. HKCU\Software\Dolphin Emulator\UserConfigPath exists + // 3. HKCU\Software\Dolphin Emulator\UserConfigPath exists and isn't the same as + // AppData\Roaming // -> Use this as the user directory path // 4. My Documents\Dolphin Emulator exists (default user folder before PR 10708) // -> Use this as the user directory path // 5. AppData\Roaming exists // -> Use AppData\Roaming\Dolphin Emulator as the User directory path + // 5.1 AppData\Local exists, + // -> Use AppData\Local\Dolphin Emulator as the Application State and Cache directory paths // 6. Default // -> Use GetExeDirectory()\User // Get AppData path in case we need it. + std::string appdata_path; wil::unique_cotaskmem_string appdata; bool appdata_found = SUCCEEDED( SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, nullptr, appdata.put())); + if (appdata_found) + appdata_path = TStrToUTF8(appdata.get()) + DIR_SEP NORMAL_USER_DIR DIR_SEP; // Check our registry keys wil::unique_hkey hkey; @@ -360,7 +369,7 @@ void SetUserDirectory(std::string custom_path) { user_path = File::GetExeDirectory() + DIR_SEP PORTABLE_USER_DIR DIR_SEP; } - else if (configPath) // Case 3 + else if (configPath && appdata_path != TStrToUTF8(configPath.get())) // Case 3 { user_path = TStrToUTF8(configPath.get()); } @@ -370,7 +379,20 @@ void SetUserDirectory(std::string custom_path) } else if (appdata_found) // Case 5 { - user_path = TStrToUTF8(appdata.get()) + DIR_SEP NORMAL_USER_DIR DIR_SEP; + user_path = appdata_path; + + wil::unique_cotaskmem_string localappdata; + bool localappdata_found = SUCCEEDED( + SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_DEFAULT, nullptr, localappdata.put())); + + if (localappdata_found) // Case 5.1 + { + const std::string localappdata_path = + TStrToUTF8(localappdata.get()) + DIR_SEP NORMAL_USER_DIR DIR_SEP; + + application_state_path = localappdata_path; + cache_path = localappdata_path + CACHE_DIR DIR_SEP; + } // Set the UserConfigPath value in the registry for backwards compatibility with older Dolphin // builds, which will look for the default User directory in Documents. If we set this key, @@ -441,32 +463,38 @@ void SetUserDirectory(std::string custom_path) if (File::Exists("/.flatpak-info") || !File::Exists(user_path)) { const char* data_home = getenv("XDG_DATA_HOME"); - std::string data_path = + user_path = std::string(data_home && data_home[0] == '/' ? data_home : (home_path + ".local" DIR_SEP "share")) + DIR_SEP NORMAL_USER_DIR DIR_SEP; const char* config_home = getenv("XDG_CONFIG_HOME"); - std::string config_path = - std::string(config_home && config_home[0] == '/' ? config_home : - (home_path + ".config")) + - DIR_SEP NORMAL_USER_DIR DIR_SEP; + config_path = std::string(config_home && config_home[0] == '/' ? config_home : + (home_path + ".config")) + + DIR_SEP NORMAL_USER_DIR DIR_SEP; const char* cache_home = getenv("XDG_CACHE_HOME"); - std::string cache_path = + cache_path = std::string(cache_home && cache_home[0] == '/' ? cache_home : (home_path + ".cache")) + DIR_SEP NORMAL_USER_DIR DIR_SEP; - File::SetUserPath(D_USER_IDX, data_path); - File::SetUserPath(D_CONFIG_IDX, config_path); - File::SetUserPath(D_CACHE_IDX, cache_path); - return; + const char* state_home = getenv("XDG_STATE_HOME"); + application_state_path = std::string(state_home && state_home[0] == '/' ? + state_home : + (home_path + ".local" DIR_SEP "state")) + + DIR_SEP NORMAL_USER_DIR DIR_SEP; } } #endif } #endif File::SetUserPath(D_USER_IDX, std::move(user_path)); + if (config_path) + File::SetUserPath(D_CONFIG_IDX, std::move(*config_path)); + if (cache_path) + File::SetUserPath(D_CACHE_IDX, std::move(*cache_path)); + if (application_state_path) + File::SetUserPath(D_APPLICATIONSTATE_IDX, std::move(*application_state_path)); } bool TriggerSTMPowerEvent()