From e41151420f30c9da4473446da034ebbd642ef51d Mon Sep 17 00:00:00 2001 From: Pengfei Date: Tue, 13 Jul 2021 21:55:35 +0800 Subject: [PATCH] Fix Flatpak user path --- src/common/common_paths.h | 1 + src/common/file_util.cpp | 64 +++++++++++++++++++++++++--------- src/common/file_util.h | 12 +++++-- src/frontend/import_dialog.cpp | 5 ++- src/frontend/main.cpp | 21 ++++++++--- 5 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/common/common_paths.h b/src/common/common_paths.h index a4ee74a..e518874 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h @@ -23,6 +23,7 @@ #define EMU_DATA_DIR "citra-emu" #endif #endif +#define CITRA_EXECUTABLE "citra-qt" // Subdirs in the User dir returned by GetUserPath(UserPath::UserDir) #define CONFIG_DIR "config" diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index c5e22cc..23490b4 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -694,9 +694,36 @@ std::string GetSysDirectory() { namespace { std::unordered_map g_paths; -bool g_portable_user_directory = false; } // namespace +UserPathType GetUserPathType() { +#ifdef _WIN32 + const auto user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; + if (FileUtil::Exists(user_path)) { + return UserPathType::Portable; + } else { + return UserPathType::Normal; + } +#elif ANDROID + UNREACHABLE_MSG("Android is not supported (yet)"); +#else + if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP)) { + return UserPathType::Portable; + } else if (FileUtil::Exists(ROOT_DIR DIR_SEP CITRA_EXECUTABLE)) { + return UserPathType::Normal; + } + + const bool normal_exists = + FileUtil::Exists(GetUserDirectory("XDG_DATA_HOME") + DIR_SEP EMU_DATA_DIR DIR_SEP); + const bool flatpak_exists = FileUtil::Exists( + GetHomeDirectory() + "/.var/app/org.citra_emu.citra/data" + DIR_SEP EMU_DATA_DIR DIR_SEP); + if (!normal_exists || flatpak_exists) { // Flatpak takes precedence + return UserPathType::Flatpak; + } + return UserPathType::Normal; +#endif +} + void SetUserPath(const std::string& path) { if (!g_paths.empty()) { g_paths.clear(); @@ -711,27 +738,26 @@ void SetUserPath(const std::string& path) { g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP); } else { #ifdef _WIN32 - user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; - if (!FileUtil::IsDirectory(user_path)) { - user_path = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP; - } else { + if (GetUserPathType() == UserPathType::Portable) { LOG_INFO(Common_Filesystem, "Using the local user directory"); - g_portable_user_directory = true; + user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; + } else { + user_path = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP; } g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP); g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP); #elif ANDROID - ASSERT_MSG(false, "Specified path {} is not valid", path); + UNREACHABLE_MSG("Android is not supported (yet)"); #else - if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) { + switch (GetUserPathType()) { + case UserPathType::Portable: { user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP); g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP); - - LOG_INFO(Common_Filesystem, "Using the local user directory"); - g_portable_user_directory = true; - } else { + break; + } + case UserPathType::Normal: { std::string data_dir = GetUserDirectory("XDG_DATA_HOME"); std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME"); std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME"); @@ -739,6 +765,16 @@ void SetUserPath(const std::string& path) { user_path = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; g_paths.emplace(UserPath::ConfigDir, config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP); g_paths.emplace(UserPath::CacheDir, cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP); + break; + } + case UserPathType::Flatpak: { + const auto base_path = GetHomeDirectory() + "/.var/app/org.citra_emu.citra/"; + user_path = base_path + "data/citra-emu/"; + + g_paths.emplace(UserPath::ConfigDir, base_path + "config/citra-emu/"); + g_paths.emplace(UserPath::CacheDir, base_path + "cache/citra-emu/"); + break; + } } #endif } @@ -758,10 +794,6 @@ const std::string& GetUserPath(UserPath path) { return g_paths[path]; } -bool IsPortableUserDirectory() { - return g_portable_user_directory; -} - std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str) { return IOFile(filename, text_file ? "w" : "wb").WriteString(str); } diff --git a/src/common/file_util.h b/src/common/file_util.h index d698bc7..3e1696e 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -129,6 +129,15 @@ void CopyDir(const std::string& source_path, const std::string& dest_path); // Set the current directory to given directory bool SetCurrentDir(const std::string& directory); +enum class UserPathType { + Normal, /// user-wide normal install + Portable, /// portable install + Flatpak, /// Flatpak install (Linux only) +}; + +// Determine type of the user path that should be used. +UserPathType GetUserPathType(); + // User paths are not directly used by us, and are only preserved here to match Citra's // user folder and tell where to copy the files to. @@ -138,9 +147,6 @@ void SetUserPath(const std::string& path = ""); // directory. To be used in "multi-user" mode (that is, installed). const std::string& GetUserPath(UserPath path); -// Whetehr we are using the portable user directory. -bool IsPortableUserDirectory(); - // Returns the path to where the sys file are std::string GetSysDirectory(); diff --git a/src/frontend/import_dialog.cpp b/src/frontend/import_dialog.cpp index 3c7ed06..b7f2031 100644 --- a/src/frontend/import_dialog.cpp +++ b/src/frontend/import_dialog.cpp @@ -256,9 +256,8 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe encryption.clear(); } - auto* item = new QTreeWidgetItem{ - {QString{}, name, ReadableByteSize(content.maximum_size), encryption, - content.already_exists ? QStringLiteral("Yes") : QStringLiteral("No")}}; + auto* item = new QTreeWidgetItem{{QString{}, name, ReadableByteSize(content.maximum_size), + encryption, content.already_exists ? tr("Yes") : tr("No")}}; QPixmap icon; if (replace_icon.isNull()) { diff --git a/src/frontend/main.cpp b/src/frontend/main.cpp index cd52960..474b5f6 100644 --- a/src/frontend/main.cpp +++ b/src/frontend/main.cpp @@ -11,6 +11,7 @@ #include #include #include +#include "common/assert.h" #include "common/file_util.h" #include "frontend/import_dialog.h" #include "frontend/main.h" @@ -60,10 +61,22 @@ MainDialog::MainDialog(QWidget* parent) : QDialog(parent), ui(std::make_uniqueimportDestination->setText(tr("Import Destination: %1") - .arg(FileUtil::IsPortableUserDirectory() - ? tr("Portable Citra Install") - : tr("User-wide Citra Install"))); + QString destination_text{}; + const auto destination = FileUtil::GetUserPathType(); + if (destination == FileUtil::UserPathType::Normal) { +#ifdef __linux__ + destination_text = tr("Non-Flatpak Citra Install"); +#else + destination_text = tr("User-wide Citra Install"); +#endif + } else if (destination == FileUtil::UserPathType::Portable) { + destination_text = tr("Portable Citra Install"); + } else if (destination == FileUtil::UserPathType::Flatpak) { + destination_text = tr("Flatpak Citra Install"); + } else { + UNREACHABLE(); + } + ui->importDestination->setText(tr("Import Destination: %1").arg(destination_text)); connect(ui->main, &QTreeWidget::itemSelectionChanged, [this] { ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok)