Compare commits

..

4 Commits

Author SHA1 Message Date
lizzie
3f449e5d77 fx 2025-11-08 05:34:54 +00:00
lizzie
ac4983d48f fx 2025-11-08 05:31:59 +00:00
lizzie
c5da21d064 rx 2025-11-08 05:30:44 +00:00
lizzie
1423619e61 [vk] custom border color fixes for turnip/qcom 2025-11-08 04:36:10 +00:00
68 changed files with 6242 additions and 5436 deletions

View File

@@ -586,7 +586,7 @@ else()
find_package(zstd 1.5 REQUIRED MODULE)
# wow
find_package(Boost 1.57.0 CONFIG REQUIRED OPTIONAL_COMPONENTS headers context system fiber filesystem)
find_package(Boost 1.57.0 CONFIG REQUIRED OPTIONAL_COMPONENTS headers context system fiber)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID)
find_package(gamemode 1.7 MODULE)

View File

@@ -20,7 +20,7 @@
"hash": "4fb7f6fde92762305aad8754d7643cd918dd1f3f67e104e9ab385b18c73178d72a17321354eb203b790b6702f2cf6d725a5d6e2dfbc63b1e35f9eb59fb42ece9",
"git_version": "1.89.0",
"version": "1.57",
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
"find_args": "CONFIG",
"patches": [
"0001-clang-cl.patch",
"0002-use-marmasm.patch",

0
dist/dev.eden_emu.eden.desktop vendored Executable file → Normal file
View File

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
dist/eden.icns vendored

Binary file not shown.

BIN
dist/eden.ico vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

After

Width:  |  Height:  |  Size: 403 KiB

83
dist/eden_named.svg vendored

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -821,6 +821,31 @@ QTabBar QToolButton::left-arrow:disabled {
image: url(:/qss_icons/rc/left_arrow_disabled.png);
}
QDockWidget {
background: #31363b;
border: 1px solid #403F3F;
titlebar-close-icon: url(:/qss_icons/rc/close.png);
titlebar-normal-icon: url(:/qss_icons/rc/undock.png);
}
QDockWidget::close-button,
QDockWidget::float-button {
border: 1px solid transparent;
border-radius: 2px;
background: transparent;
}
QDockWidget::close-button:hover,
QDockWidget::float-button:hover {
background: rgba(255, 255, 255, 10);
}
QDockWidget::close-button:pressed,
QDockWidget::float-button:pressed {
padding: 1px -1px -1px 1px;
background: rgba(255, 255, 255, 10);
}
QTreeView,
QListView {
border: 1px solid #54575B;

View File

@@ -1685,6 +1685,54 @@ QTabBar QToolButton::right-arrow:disabled {
image: url(":/qss_icons/rc/arrow_right_disabled.png");
}
/* QDockWiget -------------------------------------------------------------
--------------------------------------------------------------------------- */
QDockWidget {
outline: 1px solid #32414B;
background-color: #19232D;
border: 1px solid #32414B;
border-radius: 4px;
titlebar-close-icon: url(":/qss_icons/rc/window_close.png");
titlebar-normal-icon: url(":/qss_icons/rc/window_undock.png");
}
QDockWidget::title {
/* Better size for title bar */
padding: 6px;
spacing: 4px;
border: none;
background-color: #32414B;
}
QDockWidget::close-button {
background-color: #32414B;
border-radius: 4px;
border: none;
}
QDockWidget::close-button:hover {
image: url(":/qss_icons/rc/window_close_focus.png");
}
QDockWidget::close-button:pressed {
image: url(":/qss_icons/rc/window_close_pressed.png");
}
QDockWidget::float-button {
background-color: #32414B;
border-radius: 4px;
border: none;
}
QDockWidget::float-button:hover {
image: url(":/qss_icons/rc/window_undock_focus.png");
}
QDockWidget::float-button:pressed {
image: url(":/qss_icons/rc/window_undock_pressed.png");
}
/* QTreeView QListView QTableView -----------------------------------------
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview

BIN
dist/yuzu.bmp vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

BIN
dist/yuzu.icns vendored

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -252,13 +252,11 @@ if(CXX_CLANG)
endif()
if (BOOST_NO_HEADERS)
target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool Boost::filesystem)
target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool)
else()
target_link_libraries(common PUBLIC Boost::headers)
endif()
target_link_libraries(common PUBLIC Boost::filesystem)
if (lz4_ADDED)
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
endif()

View File

@@ -14,29 +14,16 @@ namespace fs = std::filesystem;
fs::path GetKvdbPath()
{
return GetKvdbPath(GetLegacyPath(EmuPath::RyujinxDir));
}
fs::path GetKvdbPath(const fs::path& path) {
return path / "bis" / "system" / "save" / "8000000000000000" / "0"
return GetLegacyPath(EmuPath::RyujinxDir) / "bis" / "system" / "save" / "8000000000000000" / "0"
/ "imkvdb.arc";
}
fs::path GetRyuPathFromSavePath(const fs::path& path) {
// This is a horrible hack, but I cba to find something better
return path.parent_path().parent_path().parent_path().parent_path().parent_path();
}
fs::path GetRyuSavePath(const u64 &save_id)
{
return GetRyuSavePath(GetLegacyPath(EmuPath::RyujinxDir), save_id);
}
std::filesystem::path GetRyuSavePath(const std::filesystem::path& path, const u64& save_id) {
std::string hex = fmt::format("{:016x}", save_id);
// TODO: what's the difference between 0 and 1?
return path / "bis" / "user" / "save" / hex / "0";
// TODO: what's the difference between 0 and 1?
return GetLegacyPath(EmuPath::RyujinxDir) / "bis" / "user" / "save" / hex / "0";
}
IMENReadResult ReadKvdb(const fs::path &path, std::vector<IMEN> &imens)

View File

@@ -7,17 +7,16 @@
#include <filesystem>
#include <vector>
namespace fs = std::filesystem;
namespace Common::FS {
constexpr const char IMEN_MAGIC[4] = {0x49, 0x4d, 0x45, 0x4e};
constexpr const char IMKV_MAGIC[4] = {0x49, 0x4d, 0x4b, 0x56};
constexpr const u8 IMEN_SIZE = 0x8c;
std::filesystem::path GetKvdbPath();
std::filesystem::path GetKvdbPath(const std::filesystem::path &path);
std::filesystem::path GetRyuPathFromSavePath(const std::filesystem::path &path);
std::filesystem::path GetRyuSavePath(const u64 &save_id);
std::filesystem::path GetRyuSavePath(const std::filesystem::path &path, const u64 &save_id);
fs::path GetKvdbPath();
fs::path GetRyuSavePath(const u64 &program_id);
enum class IMENReadResult {
Nonexistent, // ryujinx not found
@@ -36,6 +35,6 @@ struct IMEN
static_assert(sizeof(IMEN) == 0x10, "IMEN has incorrect size.");
IMENReadResult ReadKvdb(const std::filesystem::path &path, std::vector<IMEN> &imens);
IMENReadResult ReadKvdb(const fs::path &path, std::vector<IMEN> &imens);
} // namespace Common::FS

View File

@@ -4,12 +4,10 @@
#include "symlink.h"
#ifdef _WIN32
#include <fmt/format.h>
#include <windows.h>
#include <fmt/format.h>
#endif
#include <boost/filesystem.hpp>
namespace fs = std::filesystem;
// The sole purpose of this file is to treat symlinks like symlinks on POSIX,
@@ -17,40 +15,29 @@ namespace fs = std::filesystem;
// This is because, for some inexplicable reason, Microsoft has locked symbolic
// links behind a "security policy", whereas directory junctions--functionally identical
// for directories, by the way--are not. Why? I don't know.
// And no, they do NOT provide a standard API for this (at least to my knowledge).
// CreateSymbolicLink, even when EXPLICITLY TOLD to create a junction, still fails
// because of their security policy.
// I don't know what kind of drugs the Windows developers have been on since NT started.
// Microsoft still has not implemented any of this in their std::filesystem implemenation,
// which ALSO means that it DOES NOT FOLLOW ANY DIRECTORY JUNCTIONS... AT ALL.
// Nor does any of their command line utilities or APIs. So you're quite literally
// on your own.
namespace Common::FS {
bool CreateSymlink(fs::path from, fs::path to)
bool CreateSymlink(const fs::path &from, const fs::path &to)
{
from.make_preferred();
to.make_preferred();
#ifdef _WIN32
const std::string command = fmt::format("mklink /J {} {}", to.string(), from.string());
return system(command.c_str()) == 0;
#else
std::error_code ec;
fs::create_directory_symlink(from, to, ec);
#ifdef _WIN32
if (ec) {
const std::string command = fmt::format("mklink /J \"{}\" \"{}\"",
to.string(),
from.string());
return system(command.c_str()) == 0;
}
#endif
return !ec;
#endif
}
bool IsSymlink(const fs::path &path)
{
return boost::filesystem::is_symlink(boost::filesystem::path{path});
#ifdef _WIN32
auto attributes = GetFileAttributesW(path.wstring().c_str());
return attributes & FILE_ATTRIBUTE_REPARSE_POINT;
#else
return fs::is_symlink(path);
#endif
}
} // namespace Common::FS

View File

@@ -6,7 +6,7 @@
#include <filesystem>
namespace Common::FS {
bool CreateSymlink(std::filesystem::path from, std::filesystem::path to);
bool CreateSymlink(const std::filesystem::path &from, const std::filesystem::path &to);
bool IsSymlink(const std::filesystem::path &path);
} // namespace Common::FS

View File

@@ -7,6 +7,8 @@
#include <algorithm>
#include <cstring>
#include <filesystem>
#include <iostream>
#include <random>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/find.hpp>
@@ -16,11 +18,11 @@
#include "common/fs/fs.h"
#include "common/fs/fs_types.h"
#include "common/fs/path_util.h"
#include "common/fs/symlink.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/file_sys/savedata_factory.h"
#include "core/hle/service/acc/profile_manager.h"
#include <ranges>
namespace Service::Account {
@@ -490,32 +492,6 @@ void ProfileManager::ResetUserSaveFile()
ParseUserSaveFile();
}
std::vector<UUID> ProfileManager::FindExistingProfileUUIDs()
{
std::vector<UUID> uuids;
for (const ProfileInfo& p : profiles) {
auto uuid = p.user_uuid;
if (!uuid.IsInvalid()) {
uuids.emplace_back(uuid);
}
}
return uuids;
}
std::vector<std::string> ProfileManager::FindExistingProfileStrings()
{
std::vector<UUID> uuids = FindExistingProfileUUIDs();
std::vector<std::string> uuid_strings;
for (const UUID &uuid : uuids) {
auto user_id = uuid.AsU128();
uuid_strings.emplace_back(fmt::format("{:016X}{:016X}", user_id[1], user_id[0]));
}
return uuid_strings;
}
std::vector<std::string> ProfileManager::FindGoodProfiles()
{
namespace fs = std::filesystem;
@@ -525,17 +501,31 @@ std::vector<std::string> ProfileManager::FindGoodProfiles()
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
/ "user/save/0000000000000000";
// some exceptions, e.g. the "system" profile
static constexpr const std::array<const char* const, 1> EXCEPTION_UUIDS
= {"00000000000000000000000000000000"};
// some exceptions because certain games just LOVE TO CAUSE ISSUES
static constexpr const std::array<const char* const, 2> EXCEPTION_UUIDS
= {"5755CC2A545A87128500000000000000", "00000000000000000000000000000000"};
for (const char *const uuid : EXCEPTION_UUIDS) {
if (fs::exists(path / uuid))
good_uuids.emplace_back(uuid);
}
auto existing = FindExistingProfileStrings();
good_uuids.insert(good_uuids.end(), existing.begin(), existing.end());
for (const ProfileInfo& p : profiles) {
std::string uuid_string = [p]() -> std::string {
auto uuid = p.user_uuid;
// "ignore" invalid uuids
if (uuid.IsInvalid()) {
return "0";
}
auto user_id = uuid.AsU128();
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
}();
if (uuid_string != "0") good_uuids.emplace_back(uuid_string);
}
return good_uuids;
}
@@ -572,8 +562,7 @@ std::vector<std::string> ProfileManager::FindOrphanedProfiles()
override = true;
// if there are any regular files (NOT directories) there, do NOT delete it :p
// Also: check for symlinks
if (file.is_regular_file() || Common::FS::IsSymlink(file.path()))
if (file.is_regular_file())
return false;
}
} catch (const fs::filesystem_error& e) {

View File

@@ -105,8 +105,6 @@ public:
void ResetUserSaveFile();
std::vector<Common::UUID> FindExistingProfileUUIDs();
std::vector<std::string> FindExistingProfileStrings();
std::vector<std::string> FindGoodProfiles();
std::vector<std::string> FindOrphanedProfiles();

View File

@@ -125,10 +125,6 @@ struct Jit::Impl final {
current_state.exclusive_state = false;
}
std::string Disassemble() const {
return {};
}
private:
void PerformRequestedCacheInvalidation(HaltReason hr) {
if (Has(hr, HaltReason::CacheInvalidation)) {
@@ -235,8 +231,4 @@ void Jit::ClearExclusiveState() {
impl->ClearExclusiveState();
}
std::string Jit::Disassemble() const {
return impl->Disassemble();
}
} // namespace Dynarmic::A32

View File

@@ -152,7 +152,7 @@ struct Jit::Impl final {
}
std::string Disassemble() const {
return {};
UNREACHABLE();
}
private:

View File

@@ -28,7 +28,7 @@ const QString GetOpenFileName(const QString &title,
Options options)
{
#ifdef YUZU_QT_WIDGETS
return QFileDialog::getOpenFileName(rootObject, title, dir, filter, selectedFilter, options);
return QFileDialog::getOpenFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options);
#endif
}
@@ -39,14 +39,7 @@ const QString GetSaveFileName(const QString &title,
Options options)
{
#ifdef YUZU_QT_WIDGETS
return QFileDialog::getSaveFileName(rootObject, title, dir, filter, selectedFilter, options);
#endif
}
const QString GetExistingDirectory(const QString& caption, const QString& dir,
Options options) {
#ifdef YUZU_QT_WIDGETS
return QFileDialog::getExistingDirectory(rootObject, caption, dir, options);
return QFileDialog::getSaveFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options);
#endif
}

View File

@@ -135,9 +135,5 @@ const QString GetSaveFileName(const QString &title,
QString *selectedFilter = nullptr,
Options options = Options());
const QString GetExistingDirectory(const QString &caption = QString(),
const QString &dir = QString(),
Options options = Option::ShowDirsOnly);
} // namespace QtCommon::Frontend
#endif // FRONTEND_H

View File

@@ -294,17 +294,6 @@ void QtConfig::ReadUIGamelistValues() {
}
EndArray();
const int linked_size = BeginArray("ryujinx_linked");
for (int i = 0; i < linked_size; ++i) {
SetArrayIndex(i);
QDir ryu_dir = QString::fromStdString(ReadStringSetting("ryujinx_path"));
u64 program_id = ReadUnsignedIntegerSetting("program_id");
UISettings::values.ryujinx_link_paths.insert(program_id, ryu_dir);
}
EndArray();
EndGroup();
}
@@ -510,21 +499,6 @@ void QtConfig::SaveUIGamelistValues() {
}
EndArray(); // favorites
BeginArray(std::string("ryujinx_linked"));
int i = 0;
QMapIterator iter(UISettings::values.ryujinx_link_paths);
while (iter.hasNext()) {
iter.next();
SetArrayIndex(i);
WriteIntegerSetting("program_id", iter.key());
WriteStringSetting("ryujinx_path", iter.value().absolutePath().toStdString());
++i;
}
EndArray(); // ryujinx
EndGroup();
}

View File

@@ -28,54 +28,54 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject *parent);
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent);
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map = {
{Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "None"))},
{Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "FXAA"))},
{Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "SMAA"))},
{Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))},
{Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))},
{Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))},
};
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map = {
{Settings::ScalingFilter::NearestNeighbor,
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Nearest"))},
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))},
{Settings::ScalingFilter::Bilinear,
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Bilinear"))},
{Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Bicubic"))},
{Settings::ScalingFilter::ZeroTangent, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Zero-Tangent"))},
{Settings::ScalingFilter::BSpline, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "B-Spline"))},
{Settings::ScalingFilter::Mitchell, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Mitchell"))},
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))},
{Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))},
{Settings::ScalingFilter::ZeroTangent, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Zero-Tangent"))},
{Settings::ScalingFilter::BSpline, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "B-Spline"))},
{Settings::ScalingFilter::Mitchell, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Mitchell"))},
{Settings::ScalingFilter::Spline1,
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Spline-1"))},
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Spline-1"))},
{Settings::ScalingFilter::Gaussian,
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Gaussian"))},
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))},
{Settings::ScalingFilter::Lanczos,
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Lanczos"))},
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Lanczos"))},
{Settings::ScalingFilter::ScaleForce,
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "ScaleForce"))},
{Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "FSR"))},
{Settings::ScalingFilter::Area, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Area"))},
{Settings::ScalingFilter::Mmpx, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "MMPX"))},
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))},
{Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))},
{Settings::ScalingFilter::Area, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Area"))},
{Settings::ScalingFilter::Mmpx, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "MMPX"))},
};
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {
{Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Docked"))},
{Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Handheld"))},
{Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))},
{Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
};
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = {
{Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Normal"))},
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "High"))},
{Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Extreme"))},
{Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))},
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))},
{Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))},
};
static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map = {
{Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Vulkan"))},
{Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "OpenGL"))},
{Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Null"))},
{Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))},
{Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))},
{Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))},
};
static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map = {
{Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "GLSL"))},
{Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "GLASM"))},
{Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "SPIRV"))},
{Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
{Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
{Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
};
} // namespace ConfigurationShared

View File

@@ -14,7 +14,6 @@
#include <QString>
#include <QStringList>
#include <QVector>
#include <qdir.h>
#include "common/common_types.h"
#include "common/settings.h"
#include "common/settings_enums.h"
@@ -202,7 +201,6 @@ struct Values {
Setting<bool> cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
Setting<bool> favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
QVector<u64> favorited_ids;
QMap<u64, QDir> ryujinx_link_paths;
// Compatibility List
Setting<bool> show_compat{linkage, true, "show_compat", Category::UiGameList};

View File

@@ -8,12 +8,6 @@
#include "frozen/map.h"
#include "frozen/string.h"
/// Small helper to look up enums.
/// res = the result code
/// base = the base matching value in the StringKey table
#define LOOKUP_ENUM(res, base) StringLookup::Lookup( \
static_cast<StringLookup::StringKey>((int) res + (int) StringLookup::base))
namespace QtCommon::StringLookup {
Q_NAMESPACE

View File

@@ -25,7 +25,8 @@ enum class FirmwareInstallResult {
inline const QString GetFirmwareInstallResultString(FirmwareInstallResult result)
{
return LOOKUP_ENUM(result, FwInstallSuccess);
return QtCommon::StringLookup::Lookup(static_cast<StringLookup::StringKey>(
(int) result + (int) QtCommon::StringLookup::FwInstallSuccess));
}
/**
@@ -35,7 +36,9 @@ inline const QString GetFirmwareInstallResultString(FirmwareInstallResult result
*/
inline const QString GetKeyInstallResultString(FirmwareManager::KeyInstallResult result)
{
return LOOKUP_ENUM(result, KeyInstallSuccess);
// this can probably be made into a common function of sorts
return QtCommon::StringLookup::Lookup(static_cast<StringLookup::StringKey>(
(int) result + (int) QtCommon::StringLookup::KeyInstallSuccess));
}
void InstallFirmware(const QString &location, bool recursive);

View File

@@ -1,11 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm>
#include <filesystem>
#include "fs.h"
#include "common/fs/ryujinx_compat.h"
#include "common/fs/symlink.h"
#include "fs.h"
#include "frontend_common/data_manager.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/qt_string_lookup.h"
@@ -56,9 +56,6 @@ bool CheckUnlink(const fs::path &eden_dir, const fs::path &ryu_dir)
orig = eden_dir;
}
linked.make_preferred();
orig.make_preferred();
// first cleanup the symlink/junction,
try {
// NB: do NOT use remove_all, as Windows treats this as a remove_all to the target,
@@ -87,64 +84,47 @@ bool CheckUnlink(const fs::path &eden_dir, const fs::path &ryu_dir)
return true;
}
const fs::path GetRyujinxSavePath(const fs::path &path_hint, const u64 &program_id)
u64 GetRyujinxSaveID(const u64 &program_id)
{
auto ryu_path = path_hint;
auto kvdb_path = Common::FS::GetKvdbPath(ryu_path);
if (!fs::exists(kvdb_path)) {
using namespace QtCommon::Frontend;
auto res = Warning(
tr("Could not find Ryujinx installation"),
tr("Could not find a valid Ryujinx installation. This may typically occur if you are "
"using Ryujinx in portable mode.\n\nWould you like to manually select a portable "
"folder to use?"), StandardButton::Yes | StandardButton::No);
if (res == StandardButton::Yes) {
auto selected_path = GetExistingDirectory(tr("Ryujinx Portable Location"), QDir::homePath()).toStdString();
if (selected_path.empty())
return fs::path{};
ryu_path = selected_path;
// In case the user selects the actual ryujinx installation dir INSTEAD OF
// the portable dir
if (fs::exists(ryu_path / "portable")) {
ryu_path = ryu_path / "portable";
}
kvdb_path = Common::FS::GetKvdbPath(ryu_path);
if (!fs::exists(kvdb_path)) {
QtCommon::Frontend::Critical(
tr("Not a valid Ryujinx directory"),
tr("The specified directory does not contain valid Ryujinx data."));
return fs::path{};
}
} else {
return fs::path{};
}
}
auto path = Common::FS::GetKvdbPath();
std::vector<Common::FS::IMEN> imens;
Common::FS::IMENReadResult res = Common::FS::ReadKvdb(kvdb_path, imens);
Common::FS::IMENReadResult res = Common::FS::ReadKvdb(path, imens);
if (res == Common::FS::IMENReadResult::Success) {
// TODO: this can probably be done with std::find_if but I'm lazy
for (const Common::FS::IMEN &imen : imens) {
if (imen.title_id == program_id)
return Common::FS::GetRyuSavePath(ryu_path, imen.save_id);
return imen.save_id;
}
QtCommon::Frontend::Critical(
tr("Could not find Ryujinx save data"),
StringLookup::Lookup(StringLookup::RyujinxNoSaveId).arg(program_id, 0, 16));
} else {
QString caption = LOOKUP_ENUM(res, KvdbNonexistent);
// TODO: make this long thing a function or something
QString caption = StringLookup::Lookup(
static_cast<StringLookup::StringKey>((int) res + (int) StringLookup::KvdbNonexistent));
QtCommon::Frontend::Critical(tr("Could not find Ryujinx save data"), caption);
}
return fs::path{};
return -1;
}
std::optional<std::pair<fs::path, fs::path> > GetEmuPaths(
const u64 program_id, const u64 save_id, const std::string &user_id)
{
fs::path ryu_dir = Common::FS::GetRyuSavePath(save_id);
if (user_id.empty())
return std::nullopt;
std::string hex_program = fmt::format("{:016X}", program_id);
fs::path eden_dir
= FrontendCommon::DataManager::GetDataDir(FrontendCommon::DataManager::DataDir::Saves,
user_id)
/ hex_program;
return std::make_pair(eden_dir, ryu_dir);
}
} // namespace QtCommon::FS

View File

@@ -10,10 +10,13 @@
namespace QtCommon::FS {
void LinkRyujinx(std::filesystem::path &from, std::filesystem::path &to);
const std::filesystem::path GetRyujinxSavePath(const std::filesystem::path &path_hint, const u64 &program_id);
u64 GetRyujinxSaveID(const u64 &program_id);
/// @brief {eden, ryu}
std::optional<std::pair<std::filesystem::path, std::filesystem::path>> GetEmuPaths(
const u64 program_id, const u64 save_id, const std::string &user_id);
/// returns FALSE if the dirs are NOT linked
bool CheckUnlink(const std::filesystem::path& eden_dir,
const std::filesystem::path& ryu_dir);
bool CheckUnlink(const std::filesystem::path &eden_dir, const std::filesystem::path &ryu_dir);
} // namespace QtCommon::FS

View File

@@ -775,20 +775,65 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (extensions.memory_budget) {
flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
}
// Runtime sanity check: some drivers (notably Qualcomm and Turnip) advertise
// VK_EXT_custom_border_color but mis-implement it. Try creating a sampler
// with a formatless custom border color and disable the feature if it fails.
if (extensions.custom_border_color) {
VkSamplerCustomBorderColorCreateInfoEXT border_ci{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
.pNext = nullptr,
.customBorderColor = VkClearColorValue{{1.0f, 0.0f, 0.0f, 1.0f}},
.format = VK_FORMAT_UNDEFINED,
};
VkSamplerCreateInfo sampler_ci{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = &border_ci,
.flags = 0,
.magFilter = VK_FILTER_NEAREST,
.minFilter = VK_FILTER_NEAREST,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.mipLodBias = 0.0f,
.anisotropyEnable = VK_FALSE,
.maxAnisotropy = 1.0f,
.compareEnable = VK_FALSE,
.compareOp = VK_COMPARE_OP_ALWAYS,
.minLod = 0.0f,
.maxLod = 0.0f,
.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT,
.unnormalizedCoordinates = VK_FALSE,
};
try {
const auto test_sampler = logical.CreateSampler(sampler_ci);
// dson't allow to optimize away
(void)test_sampler;
// Destroy immediately; this is just a capability test.
test_sampler.~Handle();
LOG_INFO(Render_Vulkan, "VK_EXT_custom_border_color runtime test passed");
} catch (const vk::Exception& e) {
LOG_WARNING(Render_Vulkan, "VK_EXT_custom_border_color advertised but sampler create failed: {}. Disabling feature.", e.what());
// Disable the extension feature so the runtime falls back to fixed border colors.
RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
}
}
const VmaAllocatorCreateInfo allocator_info{
.flags = flags,
.physicalDevice = physical,
.device = *logical,
.preferredLargeHeapBlockSize = is_integrated
? (64u * 1024u * 1024u)
: (256u * 1024u * 1024u),
.pAllocationCallbacks = nullptr,
.pDeviceMemoryCallbacks = nullptr,
.pHeapSizeLimit = nullptr,
.pVulkanFunctions = &functions,
.instance = instance,
.vulkanApiVersion = ApiVersion(),
.pTypeExternalMemoryHandleTypes = nullptr,
.flags = flags,
.physicalDevice = physical,
.device = *logical,
.preferredLargeHeapBlockSize = is_integrated
? (64u * 1024u * 1024u)
: (256u * 1024u * 1024u),
.pAllocationCallbacks = nullptr,
.pDeviceMemoryCallbacks = nullptr,
.pHeapSizeLimit = nullptr,
.pVulkanFunctions = &functions,
.instance = instance,
.vulkanApiVersion = ApiVersion(),
.pTypeExternalMemoryHandleTypes = nullptr,
};
vk::Check(vmaCreateAllocator(&allocator_info, &allocator));

View File

@@ -12,8 +12,6 @@ if (YUZU_USE_BUNDLED_QT AND PLATFORM_LINUX)
set(CMAKE_BUILD_RPATH "${CMAKE_BINARY_DIR}/bin/lib/")
endif()
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(yuzu
Info.plist
about_dialog.cpp
@@ -158,6 +156,8 @@ add_executable(yuzu
debugger/console.h
debugger/controller.cpp
debugger/controller.h
debugger/wait_tree.cpp
debugger/wait_tree.h
game_list.cpp
game_list.h
@@ -171,9 +171,9 @@ add_executable(yuzu
loading_screen.cpp
loading_screen.h
loading_screen.ui
main.cpp
main.h
main.ui
multiplayer/chat_room.cpp
multiplayer/chat_room.h
multiplayer/chat_room.ui
@@ -237,7 +237,6 @@ add_executable(yuzu
data_dialog.h data_dialog.cpp data_dialog.ui
data_widget.ui
ryujinx_dialog.h ryujinx_dialog.cpp ryujinx_dialog.ui
main_window.h main_window.cpp
)
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
@@ -444,7 +443,6 @@ endif()
if (YUZU_ROOM)
target_link_libraries(yuzu PRIVATE yuzu-room)
target_link_libraries(yuzu PRIVATE Qt6::Widgets)
endif()
create_target_directory_groups(yuzu)

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -21,7 +18,7 @@
#include "web_service/web_backend.h"
#endif
#include "yuzu/applets/qt_amiibo_settings.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent,
Core::Frontend::CabinetParameters parameters_,
@@ -247,12 +244,12 @@ void QtAmiiboSettingsDialog::SetSettingsDescription() {
}
}
QtAmiiboSettings::QtAmiiboSettings(MainWindow& parent) {
QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) {
connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent,
&MainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection);
&GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection);
connect(this, &QtAmiiboSettings::MainWindowRequestExit, &parent,
&MainWindow::AmiiboSettingsRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::AmiiboSettingsFinished, this,
&GMainWindow::AmiiboSettingsRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::AmiiboSettingsFinished, this,
&QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection);
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,7 +8,7 @@
#include <QDialog>
#include "core/frontend/applets/cabinet.h"
class MainWindow;
class GMainWindow;
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
@@ -68,7 +65,7 @@ class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApp
Q_OBJECT
public:
explicit QtAmiiboSettings(MainWindow& parent);
explicit QtAmiiboSettings(GMainWindow& parent);
~QtAmiiboSettings() override;
void Close() const override;

View File

@@ -25,7 +25,7 @@
#include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "yuzu/util/controller_navigation.h"
namespace {
@@ -753,12 +753,12 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
}
}
QtControllerSelector::QtControllerSelector(MainWindow& parent) {
QtControllerSelector::QtControllerSelector(GMainWindow& parent) {
connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent,
&MainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
&GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
connect(this, &QtControllerSelector::MainWindowRequestExit, &parent,
&MainWindow::ControllerSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::ControllerSelectorReconfigureFinished, this,
&GMainWindow::ControllerSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this,
&QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection);
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,7 +8,7 @@
#include <QDialog>
#include "core/frontend/applets/controller.h"
class MainWindow;
class GMainWindow;
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
@@ -166,7 +163,7 @@ class QtControllerSelector final : public QObject, public Core::Frontend::Contro
Q_OBJECT
public:
explicit QtControllerSelector(MainWindow& parent);
explicit QtControllerSelector(GMainWindow& parent);
~QtControllerSelector() override;
void Close() const override;

View File

@@ -1,19 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QDateTime>
#include "yuzu/applets/qt_error.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
QtErrorDisplay::QtErrorDisplay(MainWindow& parent) {
QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) {
connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent,
&MainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection);
&GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection);
connect(this, &QtErrorDisplay::MainWindowRequestExit, &parent,
&MainWindow::ErrorDisplayRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::ErrorDisplayFinished, this,
&GMainWindow::ErrorDisplayRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ErrorDisplayFinished, this,
&QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection);
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,13 +7,13 @@
#include "core/frontend/applets/error.h"
class MainWindow;
class GMainWindow;
class QtErrorDisplay final : public QObject, public Core::Frontend::ErrorApplet {
Q_OBJECT
public:
explicit QtErrorDisplay(MainWindow& parent);
explicit QtErrorDisplay(GMainWindow& parent);
~QtErrorDisplay() override;
void Close() const override;

View File

@@ -20,7 +20,7 @@
#include "core/core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "yuzu/applets/qt_profile_select.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "yuzu/util/controller_navigation.h"
namespace {
@@ -230,12 +230,12 @@ void QtProfileSelectionDialog::SetDialogPurpose(
}
}
QtProfileSelector::QtProfileSelector(MainWindow& parent) {
QtProfileSelector::QtProfileSelector(GMainWindow& parent) {
connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent,
&MainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection);
&GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection);
connect(this, &QtProfileSelector::MainWindowRequestExit, &parent,
&MainWindow::ProfileSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::ProfileSelectorFinishedSelection, this,
&GMainWindow::ProfileSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this,
&QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection);
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -12,7 +9,7 @@
#include "core/frontend/applets/profile_select.h"
class ControllerNavigation;
class MainWindow;
class GMainWindow;
class QDialogButtonBox;
class QGraphicsScene;
class QLabel;
@@ -72,7 +69,7 @@ class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSe
Q_OBJECT
public:
explicit QtProfileSelector(MainWindow& parent);
explicit QtProfileSelector(GMainWindow& parent);
~QtProfileSelector() override;
void Close() const override;

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -18,7 +15,7 @@
#include "hid_core/hid_types.h"
#include "ui_qt_software_keyboard.h"
#include "yuzu/applets/qt_software_keyboard.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "yuzu/util/overlay_dialog.h"
namespace {
@@ -1544,24 +1541,24 @@ void QtSoftwareKeyboardDialog::InputThread() {
}
}
QtSoftwareKeyboard::QtSoftwareKeyboard(MainWindow& main_window) {
QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) {
connect(this, &QtSoftwareKeyboard::MainWindowInitializeKeyboard, &main_window,
&MainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection);
&GMainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowShowNormalKeyboard, &main_window,
&MainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection);
&GMainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowShowTextCheckDialog, &main_window,
&MainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection);
&GMainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowShowInlineKeyboard, &main_window,
&MainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection);
&GMainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowHideInlineKeyboard, &main_window,
&MainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection);
&GMainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowInlineTextChanged, &main_window,
&MainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection);
&GMainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowExitKeyboard, &main_window,
&MainWindow::SoftwareKeyboardExit, Qt::QueuedConnection);
connect(&main_window, &MainWindow::SoftwareKeyboardSubmitNormalText, this,
&GMainWindow::SoftwareKeyboardExit, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitNormalText, this,
&QtSoftwareKeyboard::SubmitNormalText, Qt::QueuedConnection);
connect(&main_window, &MainWindow::SoftwareKeyboardSubmitInlineText, this,
connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitInlineText, this,
&QtSoftwareKeyboard::SubmitInlineText, Qt::QueuedConnection);
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -30,7 +27,7 @@ namespace Ui {
class QtSoftwareKeyboardDialog;
}
class MainWindow;
class GMainWindow;
class QtSoftwareKeyboardDialog final : public QDialog {
Q_OBJECT
@@ -233,7 +230,7 @@ class QtSoftwareKeyboard final : public QObject, public Core::Frontend::Software
Q_OBJECT
public:
explicit QtSoftwareKeyboard(MainWindow& parent);
explicit QtSoftwareKeyboard(GMainWindow& parent);
~QtSoftwareKeyboard() override;
void Close() const override {

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -21,7 +18,7 @@
#endif
#include "yuzu/applets/qt_web_browser.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#ifdef YUZU_USE_QT_WEB_ENGINE
@@ -394,14 +391,14 @@ void QtNXWebEngineView::FocusFirstLinkElement() {
#endif
QtWebBrowser::QtWebBrowser(MainWindow& main_window) {
QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
connect(this, &QtWebBrowser::MainWindowOpenWebPage, &main_window,
&MainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection);
&GMainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection);
connect(this, &QtWebBrowser::MainWindowRequestExit, &main_window,
&MainWindow::WebBrowserRequestExit, Qt::QueuedConnection);
connect(&main_window, &MainWindow::WebBrowserExtractOfflineRomFS, this,
&GMainWindow::WebBrowserRequestExit, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::WebBrowserExtractOfflineRomFS, this,
&QtWebBrowser::MainWindowExtractOfflineRomFS, Qt::QueuedConnection);
connect(&main_window, &MainWindow::WebBrowserClosed, this,
connect(&main_window, &GMainWindow::WebBrowserClosed, this,
&QtWebBrowser::MainWindowWebBrowserClosed, Qt::QueuedConnection);
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -17,7 +14,7 @@
#include "core/frontend/applets/web_browser.h"
class MainWindow;
class GMainWindow;
class InputInterpreter;
class UrlRequestInterceptor;
@@ -196,7 +193,7 @@ class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserAppl
Q_OBJECT
public:
explicit QtWebBrowser(MainWindow& parent);
explicit QtWebBrowser(GMainWindow& parent);
~QtWebBrowser() override;
void Close() const override;

View File

@@ -57,7 +57,7 @@
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
#include "yuzu/bootmanager.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "qt_common/qt_common.h"
class QObject;
@@ -272,7 +272,7 @@ struct NullRenderWidget : public RenderWidget {
explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {}
};
GRenderWindow::GRenderWindow(MainWindow* parent, EmuThread* emu_thread_,
GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
Core::System& system_)
: QWidget(parent),
@@ -290,11 +290,11 @@ GRenderWindow::GRenderWindow(MainWindow* parent, EmuThread* emu_thread_,
strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland") ||
QGuiApplication::platformName() == QStringLiteral("wayland-egl");
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &MainWindow::OnLoadComplete);
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &MainWindow::OnExecuteProgram,
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
Qt::QueuedConnection);
connect(this, &GRenderWindow::ExitSignal, parent, &MainWindow::OnExit, Qt::QueuedConnection);
connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &MainWindow::OnTasStateChanged);
connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection);
connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged);
mouse_constrain_timer.setInterval(default_mouse_constrain_timeout);
connect(&mouse_constrain_timer, &QTimer::timeout, this, &GRenderWindow::ConstrainMouse);

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -32,7 +29,7 @@
#include "common/thread.h"
#include "core/frontend/emu_window.h"
class MainWindow;
class GMainWindow;
class QCamera;
class QCameraImageCapture;
class QCloseEvent;
@@ -149,7 +146,7 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT
public:
explicit GRenderWindow(MainWindow* parent, EmuThread* emu_thread_,
explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
Core::System& system_);
~GRenderWindow() override;

View File

@@ -2,11 +2,12 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "data_dialog.h"
#include "core/hle/service/acc/profile_manager.h"
#include "frontend_common/data_manager.h"
#include "qt_common/qt_common.h"
#include "qt_common/util/content.h"
#include "qt_common/qt_string_lookup.h"
#include "ui_data_dialog.h"
#include "util/util.h"
#include <QDesktopServices>
#include <QFileDialog>
@@ -25,18 +26,17 @@ DataDialog::DataDialog(QWidget *parent)
ui->setupUi(this);
// TODO: Should we make this a single widget that pulls data from a model?
#define WIDGET(label, name) \
#define WIDGET(name) \
ui->page->addWidget(new DataWidget(FrontendCommon::DataManager::DataDir::name, \
QtCommon::StringLookup::name##Tooltip, \
QStringLiteral(#name), \
this)); \
ui->labels->addItem(label);
this));
WIDGET(tr("Shaders"), Shaders)
WIDGET(tr("UserNAND"), UserNand)
WIDGET(tr("SysNAND"), SysNand)
WIDGET(tr("Mods"), Mods)
WIDGET(tr("Saves"), Saves)
WIDGET(Saves)
WIDGET(Shaders)
WIDGET(UserNand)
WIDGET(SysNand)
WIDGET(Mods)
#undef WIDGET
@@ -82,7 +82,7 @@ void DataWidget::clear()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
user_id = selectProfile();
}
QtCommon::Content::ClearDataDir(m_dir, user_id);
scan();
@@ -92,7 +92,7 @@ void DataWidget::open()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
user_id = selectProfile();
}
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FrontendCommon::DataManager::GetDataDirString(m_dir, user_id))));
@@ -102,7 +102,7 @@ void DataWidget::upload()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
user_id = selectProfile();
}
QtCommon::Content::ExportDataDir(m_dir, user_id, m_exportName);
}
@@ -111,7 +111,7 @@ void DataWidget::download()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
user_id = selectProfile();
}
QtCommon::Content::ImportDataDir(m_dir, user_id, std::bind(&DataWidget::scan, this));
}
@@ -131,3 +131,37 @@ void DataWidget::scan() {
watcher->setFuture(
QtConcurrent::run([this]() { return FrontendCommon::DataManager::DataDirSize(m_dir); }));
}
std::string DataWidget::selectProfile()
{
const auto select_profile = [this] {
const Core::Frontend::ProfileSelectParameters parameters{
.mode = Service::AM::Frontend::UiMode::UserSelector,
.invalid_uid_list = {},
.display_options = {},
.purpose = Service::AM::Frontend::UserSelectionPurpose::General,
};
QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint
| Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Rejected) {
return -1;
}
return dialog.GetIndex();
};
const auto index = select_profile();
if (index == -1) {
return "";
}
const auto uuid = QtCommon::system->GetProfileManager().GetUser(static_cast<std::size_t>(index));
ASSERT(uuid);
const auto user_id = uuid->AsU128();
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
}

View File

@@ -36,6 +36,31 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Saves</string>
</property>
</item>
<item>
<property name="text">
<string>Shaders</string>
</property>
</item>
<item>
<property name="text">
<string>UserNAND</string>
</property>
</item>
<item>
<property name="text">
<string>SysNAND</string>
</property>
</item>
<item>
<property name="text">
<string>Mods</string>
</property>
</item>
</widget>
</item>
<item>

View File

@@ -0,0 +1,434 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <fmt/ranges.h>
#include "yuzu/debugger/wait_tree.h"
#include "qt_common/config/uisettings.h"
#include "core/arm/debug.h"
#include "core/core.h"
#include "core/hle/kernel/k_class_token.h"
#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc_common.h"
#include "core/hle/kernel/svc_types.h"
#include "core/memory.h"
namespace {
constexpr std::array<std::array<Qt::GlobalColor, 2>, 10> WaitTreeColors{{
{Qt::GlobalColor::darkGreen, Qt::GlobalColor::green},
{Qt::GlobalColor::darkBlue, Qt::GlobalColor::cyan},
{Qt::GlobalColor::lightGray, Qt::GlobalColor::lightGray},
{Qt::GlobalColor::lightGray, Qt::GlobalColor::lightGray},
{Qt::GlobalColor::darkRed, Qt::GlobalColor::red},
{Qt::GlobalColor::darkYellow, Qt::GlobalColor::yellow},
{Qt::GlobalColor::red, Qt::GlobalColor::red},
{Qt::GlobalColor::darkCyan, Qt::GlobalColor::cyan},
{Qt::GlobalColor::gray, Qt::GlobalColor::gray},
}};
bool IsDarkTheme() {
const auto& theme = UISettings::values.theme;
return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") ||
theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue");
}
} // namespace
WaitTreeItem::WaitTreeItem() = default;
WaitTreeItem::~WaitTreeItem() = default;
QColor WaitTreeItem::GetColor() const {
if (IsDarkTheme()) {
return QColor(Qt::GlobalColor::white);
} else {
return QColor(Qt::GlobalColor::black);
}
}
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeItem::GetChildren() const {
return {};
}
void WaitTreeItem::Expand() {
if (IsExpandable() && !expanded) {
children = GetChildren();
for (std::size_t i = 0; i < children.size(); ++i) {
children[i]->parent = this;
children[i]->row = i;
}
expanded = true;
}
}
WaitTreeItem* WaitTreeItem::Parent() const {
return parent;
}
const std::vector<std::unique_ptr<WaitTreeItem>>& WaitTreeItem::Children() const {
return children;
}
bool WaitTreeItem::IsExpandable() const {
return false;
}
std::size_t WaitTreeItem::Row() const {
return row;
}
std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList(
Core::System& system) {
std::vector<std::unique_ptr<WaitTreeThread>> item_list;
std::size_t row = 0;
auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) {
for (std::size_t i = 0; i < threads.size(); ++i) {
if (threads[i]->GetThreadType() == Kernel::ThreadType::User) {
item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system));
item_list.back()->row = row;
}
++row;
}
};
add_threads(system.GlobalSchedulerContext().GetThreadList());
return item_list;
}
WaitTreeText::WaitTreeText(QString t) : text(std::move(t)) {}
WaitTreeText::~WaitTreeText() = default;
QString WaitTreeText::GetText() const {
return text;
}
WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread_, Core::System& system_)
: thread{thread_}, system{system_} {}
WaitTreeCallstack::~WaitTreeCallstack() = default;
QString WaitTreeCallstack::GetText() const {
return tr("Call stack");
}
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list;
if (thread.GetThreadType() != Kernel::ThreadType::User) {
return list;
}
if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64Bit()) {
return list;
}
auto backtrace = Core::GetBacktraceFromContext(thread.GetOwnerProcess(), thread.GetContext());
for (auto& entry : backtrace) {
std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
entry.original_address, entry.offset, entry.name);
list.push_back(std::make_unique<WaitTreeText>(QString::fromStdString(s)));
}
return list;
}
WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(
const Kernel::KSynchronizationObject& object_, Core::System& system_)
: object{object_}, system{system_} {}
WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default;
WaitTreeExpandableItem::WaitTreeExpandableItem() = default;
WaitTreeExpandableItem::~WaitTreeExpandableItem() = default;
bool WaitTreeExpandableItem::IsExpandable() const {
return true;
}
QString WaitTreeSynchronizationObject::GetText() const {
return tr("[%1] %2")
.arg(object.GetId())
.arg(QString::fromStdString(object.GetTypeObj().GetName()));
}
std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
const Kernel::KSynchronizationObject& object, Core::System& system) {
const auto type =
static_cast<Kernel::KClassTokenGenerator::ObjectType>(object.GetTypeObj().GetClassToken());
switch (type) {
case Kernel::KClassTokenGenerator::ObjectType::KReadableEvent:
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object),
system);
case Kernel::KClassTokenGenerator::ObjectType::KThread:
return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object),
system);
default:
return std::make_unique<WaitTreeSynchronizationObject>(object, system);
}
}
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list;
auto threads = object.GetWaitingThreadsForDebugging();
if (threads.empty()) {
list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread")));
} else {
list.push_back(std::make_unique<WaitTreeThreadList>(std::move(threads), system));
}
return list;
}
WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread, Core::System& system_)
: WaitTreeSynchronizationObject(thread, system_), system{system_} {}
WaitTreeThread::~WaitTreeThread() = default;
QString WaitTreeThread::GetText() const {
const auto& thread = static_cast<const Kernel::KThread&>(object);
QString status;
switch (thread.GetState()) {
case Kernel::ThreadState::Runnable:
if (!thread.IsSuspended()) {
status = tr("runnable");
} else {
status = tr("paused");
}
break;
case Kernel::ThreadState::Waiting:
switch (thread.GetWaitReasonForDebugging()) {
case Kernel::ThreadWaitReasonForDebugging::Sleep:
status = tr("sleeping");
break;
case Kernel::ThreadWaitReasonForDebugging::IPC:
status = tr("waiting for IPC reply");
break;
case Kernel::ThreadWaitReasonForDebugging::Synchronization:
status = tr("waiting for objects");
break;
case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
status = tr("waiting for condition variable");
break;
case Kernel::ThreadWaitReasonForDebugging::Arbitration:
status = tr("waiting for address arbiter");
break;
case Kernel::ThreadWaitReasonForDebugging::Suspended:
status = tr("waiting for suspend resume");
break;
default:
status = tr("waiting");
break;
}
break;
case Kernel::ThreadState::Initialized:
status = tr("initialized");
break;
case Kernel::ThreadState::Terminated:
status = tr("terminated");
break;
default:
status = tr("unknown");
break;
}
const auto& context = thread.GetContext();
const QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
.arg(context.pc, 8, 16, QLatin1Char{'0'})
.arg(context.lr, 8, 16, QLatin1Char{'0'});
return QStringLiteral("%1%2 (%3) ")
.arg(WaitTreeSynchronizationObject::GetText(), pc_info, status);
}
QColor WaitTreeThread::GetColor() const {
const std::size_t color_index = IsDarkTheme() ? 1 : 0;
const auto& thread = static_cast<const Kernel::KThread&>(object);
switch (thread.GetState()) {
case Kernel::ThreadState::Runnable:
if (!thread.IsSuspended()) {
return QColor(WaitTreeColors[0][color_index]);
} else {
return QColor(WaitTreeColors[2][color_index]);
}
case Kernel::ThreadState::Waiting:
switch (thread.GetWaitReasonForDebugging()) {
case Kernel::ThreadWaitReasonForDebugging::IPC:
return QColor(WaitTreeColors[4][color_index]);
case Kernel::ThreadWaitReasonForDebugging::Sleep:
return QColor(WaitTreeColors[5][color_index]);
case Kernel::ThreadWaitReasonForDebugging::Synchronization:
case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
case Kernel::ThreadWaitReasonForDebugging::Arbitration:
case Kernel::ThreadWaitReasonForDebugging::Suspended:
return QColor(WaitTreeColors[6][color_index]);
break;
default:
return QColor(WaitTreeColors[3][color_index]);
}
case Kernel::ThreadState::Initialized:
return QColor(WaitTreeColors[7][color_index]);
case Kernel::ThreadState::Terminated:
return QColor(WaitTreeColors[8][color_index]);
default:
return WaitTreeItem::GetColor();
}
}
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren());
const auto& thread = static_cast<const Kernel::KThread&>(object);
QString processor;
switch (thread.GetActiveCore()) {
case Kernel::Svc::IdealCoreUseProcessValue:
processor = tr("ideal");
break;
default:
processor = tr("core %1").arg(thread.GetActiveCore());
break;
}
list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor)));
list.push_back(std::make_unique<WaitTreeText>(
tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask())));
list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadId())));
list.push_back(std::make_unique<WaitTreeText>(tr("priority = %1(current) / %2(normal)")
.arg(thread.GetPriority())
.arg(thread.GetBasePriority())));
list.push_back(std::make_unique<WaitTreeText>(
tr("last running ticks = %1").arg(thread.GetLastScheduledTick())));
list.push_back(std::make_unique<WaitTreeCallstack>(thread, system));
return list;
}
WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object_, Core::System& system_)
: WaitTreeSynchronizationObject(object_, system_) {}
WaitTreeEvent::~WaitTreeEvent() = default;
WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list, Core::System& system_)
: thread_list(std::move(list)), system{system_} {}
WaitTreeThreadList::~WaitTreeThreadList() = default;
QString WaitTreeThreadList::GetText() const {
return tr("waited by thread");
}
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThreadList::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list(thread_list.size());
std::transform(thread_list.begin(), thread_list.end(), list.begin(),
[this](const auto& t) { return std::make_unique<WaitTreeThread>(*t, system); });
return list;
}
WaitTreeModel::WaitTreeModel(Core::System& system_, QObject* parent)
: QAbstractItemModel(parent), system{system_} {}
WaitTreeModel::~WaitTreeModel() = default;
QModelIndex WaitTreeModel::index(int row, int column, const QModelIndex& parent) const {
if (!hasIndex(row, column, parent))
return {};
if (parent.isValid()) {
WaitTreeItem* parent_item = static_cast<WaitTreeItem*>(parent.internalPointer());
parent_item->Expand();
return createIndex(row, column, parent_item->Children()[row].get());
}
return createIndex(row, column, thread_items[row].get());
}
QModelIndex WaitTreeModel::parent(const QModelIndex& index) const {
if (!index.isValid())
return {};
WaitTreeItem* parent_item = static_cast<WaitTreeItem*>(index.internalPointer())->Parent();
if (!parent_item) {
return QModelIndex();
}
return createIndex(static_cast<int>(parent_item->Row()), 0, parent_item);
}
int WaitTreeModel::rowCount(const QModelIndex& parent) const {
if (!parent.isValid())
return static_cast<int>(thread_items.size());
WaitTreeItem* parent_item = static_cast<WaitTreeItem*>(parent.internalPointer());
parent_item->Expand();
return static_cast<int>(parent_item->Children().size());
}
int WaitTreeModel::columnCount(const QModelIndex&) const {
return 1;
}
QVariant WaitTreeModel::data(const QModelIndex& index, int role) const {
if (!index.isValid())
return {};
switch (role) {
case Qt::DisplayRole:
return static_cast<WaitTreeItem*>(index.internalPointer())->GetText();
case Qt::ForegroundRole:
return static_cast<WaitTreeItem*>(index.internalPointer())->GetColor();
default:
return {};
}
}
void WaitTreeModel::ClearItems() {
thread_items.clear();
}
void WaitTreeModel::InitItems() {
thread_items = WaitTreeItem::MakeThreadItemList(system);
}
WaitTreeWidget::WaitTreeWidget(Core::System& system_, QWidget* parent)
: QDockWidget(tr("&Wait Tree"), parent), system{system_} {
setObjectName(QStringLiteral("WaitTreeWidget"));
view = new QTreeView(this);
view->setHeaderHidden(true);
setWidget(view);
setEnabled(false);
}
WaitTreeWidget::~WaitTreeWidget() = default;
void WaitTreeWidget::OnDebugModeEntered() {
if (!system.IsPoweredOn())
return;
model->InitItems();
view->setModel(model);
setEnabled(true);
}
void WaitTreeWidget::OnDebugModeLeft() {
setEnabled(false);
view->setModel(nullptr);
model->ClearItems();
}
void WaitTreeWidget::OnEmulationStarting(EmuThread* emu_thread) {
model = new WaitTreeModel(system, this);
view->setModel(model);
setEnabled(false);
}
void WaitTreeWidget::OnEmulationStopping() {
view->setModel(nullptr);
delete model;
setEnabled(false);
}

View File

@@ -0,0 +1,188 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cstddef>
#include <memory>
#include <vector>
#include <QDockWidget>
#include <QTreeView>
#include "common/common_types.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/svc_common.h"
class EmuThread;
namespace Core {
class System;
}
namespace Kernel {
class KHandleTable;
class KReadableEvent;
class KSynchronizationObject;
class KThread;
} // namespace Kernel
class WaitTreeThread;
class WaitTreeItem : public QObject {
Q_OBJECT
public:
WaitTreeItem();
~WaitTreeItem() override;
virtual bool IsExpandable() const;
virtual std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const;
virtual QString GetText() const = 0;
virtual QColor GetColor() const;
void Expand();
WaitTreeItem* Parent() const;
const std::vector<std::unique_ptr<WaitTreeItem>>& Children() const;
std::size_t Row() const;
static std::vector<std::unique_ptr<WaitTreeThread>> MakeThreadItemList(Core::System& system);
private:
std::size_t row;
bool expanded = false;
WaitTreeItem* parent = nullptr;
std::vector<std::unique_ptr<WaitTreeItem>> children;
};
class WaitTreeText : public WaitTreeItem {
Q_OBJECT
public:
explicit WaitTreeText(QString text);
~WaitTreeText() override;
QString GetText() const override;
private:
QString text;
};
class WaitTreeExpandableItem : public WaitTreeItem {
Q_OBJECT
public:
WaitTreeExpandableItem();
~WaitTreeExpandableItem() override;
bool IsExpandable() const override;
};
class WaitTreeCallstack : public WaitTreeExpandableItem {
Q_OBJECT
public:
explicit WaitTreeCallstack(const Kernel::KThread& thread_, Core::System& system_);
~WaitTreeCallstack() override;
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
private:
const Kernel::KThread& thread;
Core::System& system;
};
class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
Q_OBJECT
public:
explicit WaitTreeSynchronizationObject(const Kernel::KSynchronizationObject& object_,
Core::System& system_);
~WaitTreeSynchronizationObject() override;
static std::unique_ptr<WaitTreeSynchronizationObject> make(
const Kernel::KSynchronizationObject& object, Core::System& system);
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
protected:
const Kernel::KSynchronizationObject& object;
private:
Core::System& system;
};
class WaitTreeThread : public WaitTreeSynchronizationObject {
Q_OBJECT
public:
explicit WaitTreeThread(const Kernel::KThread& thread, Core::System& system_);
~WaitTreeThread() override;
QString GetText() const override;
QColor GetColor() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
private:
Core::System& system;
};
class WaitTreeEvent : public WaitTreeSynchronizationObject {
Q_OBJECT
public:
explicit WaitTreeEvent(const Kernel::KReadableEvent& object_, Core::System& system_);
~WaitTreeEvent() override;
};
class WaitTreeThreadList : public WaitTreeExpandableItem {
Q_OBJECT
public:
explicit WaitTreeThreadList(std::vector<Kernel::KThread*>&& list, Core::System& system_);
~WaitTreeThreadList() override;
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
private:
std::vector<Kernel::KThread*> thread_list;
Core::System& system;
};
class WaitTreeModel : public QAbstractItemModel {
Q_OBJECT
public:
explicit WaitTreeModel(Core::System& system_, QObject* parent = nullptr);
~WaitTreeModel() override;
QVariant data(const QModelIndex& index, int role) const override;
QModelIndex index(int row, int column, const QModelIndex& parent) const override;
QModelIndex parent(const QModelIndex& index) const override;
int rowCount(const QModelIndex& parent) const override;
int columnCount(const QModelIndex& parent) const override;
void ClearItems();
void InitItems();
private:
std::vector<std::unique_ptr<WaitTreeThread>> thread_items;
Core::System& system;
};
class WaitTreeWidget : public QDockWidget {
Q_OBJECT
public:
explicit WaitTreeWidget(Core::System& system_, QWidget* parent = nullptr);
~WaitTreeWidget() override;
public slots:
void OnDebugModeEntered();
void OnDebugModeLeft();
void OnEmulationStarting(EmuThread* emu_thread);
void OnEmulationStopping();
private:
QTreeView* view;
WaitTreeModel* model;
Core::System& system;
};

View File

@@ -18,7 +18,7 @@ DepsDialog::DepsDialog(QWidget* parent)
{
ui->setupUi(this);
constexpr int rows = (int) Common::dep_hashes.size();
constexpr size_t rows = Common::dep_hashes.size();
ui->tableDeps->setRowCount(rows);
QStringList labels;
@@ -29,7 +29,7 @@ DepsDialog::DepsDialog(QWidget* parent)
ui->tableDeps->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Fixed);
ui->tableDeps->horizontalHeader()->setMinimumSectionSize(200);
for (int i = 0; i < rows; ++i) {
for (size_t i = 0; i < rows; ++i) {
const std::string name = Common::dep_names.at(i);
const std::string sha = Common::dep_hashes.at(i);
const std::string url = Common::dep_urls.at(i);

View File

@@ -23,7 +23,7 @@
#include "yuzu/compatibility_list.h"
#include "yuzu/game_list_p.h"
#include "yuzu/game_list_worker.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "yuzu/util/controller_navigation.h"
#include <fmt/ranges.h>
#include <regex>
@@ -314,7 +314,7 @@ void GameList::OnFilterCloseClicked() {
GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvider* provider_,
PlayTime::PlayTimeManager& play_time_manager_, Core::System& system_,
MainWindow* parent)
GMainWindow* parent)
: QWidget{parent}, vfs{std::move(vfs_)}, provider{provider_},
play_time_manager{play_time_manager_}, system{system_} {
watcher = new QFileSystemWatcher(this);
@@ -347,7 +347,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
item_model->setSortRole(GameListItemPath::SortRole);
connect(main_window, &MainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry);
connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
@@ -943,8 +943,8 @@ void GameList::RemoveFavorite(u64 program_id) {
}
}
GameListPlaceholder::GameListPlaceholder(MainWindow* parent) : QWidget{parent} {
connect(parent, &MainWindow::UpdateThemedIcons, this,
GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} {
connect(parent, &GMainWindow::UpdateThemedIcons, this,
&GameListPlaceholder::onUpdateThemedIcons);
layout = new QVBoxLayout;

View File

@@ -33,7 +33,7 @@ class ControllerNavigation;
class GameListWorker;
class GameListSearchField;
class GameListDir;
class MainWindow;
class GMainWindow;
enum class AmLaunchType;
enum class StartGameType;
@@ -69,7 +69,7 @@ public:
explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs_,
FileSys::ManualContentProvider* provider_,
PlayTime::PlayTimeManager& play_time_manager_, Core::System& system_,
MainWindow* parent = nullptr);
GMainWindow* parent = nullptr);
~GameList() override;
QString GetLastFilterResultItem() const;
@@ -153,7 +153,7 @@ private:
std::shared_ptr<FileSys::VfsFilesystem> vfs;
FileSys::ManualContentProvider* provider;
GameListSearchField* search_field;
MainWindow* main_window = nullptr;
GMainWindow* main_window = nullptr;
QVBoxLayout* layout = nullptr;
QTreeView* tree_view = nullptr;
QStandardItemModel* item_model = nullptr;
@@ -171,7 +171,7 @@ private:
class GameListPlaceholder : public QWidget {
Q_OBJECT
public:
explicit GameListPlaceholder(MainWindow* parent = nullptr);
explicit GameListPlaceholder(GMainWindow* parent = nullptr);
~GameListPlaceholder();
signals:

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@
#include <QDBusObjectPath>
#include <QVariant>
#include <QtDBus/QDBusInterface>
#include <QSocketNotifier>
#include <QtDBus/QtDBus>
#endif
#ifdef ENABLE_UPDATE_CHECKER
@@ -38,6 +38,7 @@
#endif
class QtConfig;
class ClickableLabel;
class EmuThread;
class GameList;
class GImageInfo;
@@ -153,7 +154,7 @@ private:
constexpr static int MaxMultiplier = 8;
};
class MainWindow : public QMainWindow {
class GMainWindow : public QMainWindow {
Q_OBJECT
/// Max number of recently loaded items to keep track of
@@ -162,8 +163,8 @@ class MainWindow : public QMainWindow {
public:
void filterBarSetChecked(bool state);
void UpdateUITheme();
explicit MainWindow(bool has_broken_vulkan);
~MainWindow() override;
explicit GMainWindow(bool has_broken_vulkan);
~GMainWindow() override;
bool DropAction(QDropEvent* event);
void AcceptDropEvent(QDropEvent* event);
@@ -389,6 +390,7 @@ private slots:
void OnToggleFilterBar();
void OnToggleStatusBar();
void OnGameListRefresh();
void OnDisplayTitleBars(bool);
void InitializeHotkeys();
void ToggleFullscreen();
bool UsingExclusiveFullscreen();
@@ -466,9 +468,11 @@ private:
*/
bool question(QWidget* parent, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
std::string GetProfileID();
std::unique_ptr<Ui::MainWindow> ui;
std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
@@ -531,6 +535,7 @@ private:
QString startup_icon_theme;
// Debugger panes
WaitTreeWidget* waitTreeWidget;
ControllerDialog* controller_dialog;
QAction* actions_recent_files[max_recent_files_item];

File diff suppressed because it is too large Load Diff

View File

@@ -11,11 +11,11 @@
#include "common/fs/path_util.h"
MigrationWorker::MigrationWorker(const Emulator selected_emu_,
MigrationWorker::MigrationWorker(const Emulator selected_legacy_emu_,
const bool clear_shader_cache_,
const MigrationStrategy strategy_)
: QObject()
, selected_emu(selected_emu_)
, selected_legacy_emu(selected_legacy_emu_)
, clear_shader_cache(clear_shader_cache_)
, strategy(strategy_)
{}
@@ -25,20 +25,15 @@ void MigrationWorker::process()
namespace fs = std::filesystem;
constexpr auto copy_options = fs::copy_options::update_existing | fs::copy_options::recursive;
const fs::path legacy_user_dir = selected_emu.get_user_dir();
const fs::path legacy_config_dir = selected_emu.get_config_dir();
const fs::path legacy_cache_dir = selected_emu.get_cache_dir();
const fs::path legacy_user_dir = selected_legacy_emu.get_user_dir();
const fs::path legacy_config_dir = selected_legacy_emu.get_config_dir();
const fs::path legacy_cache_dir = selected_legacy_emu.get_cache_dir();
// TODO(crueter): Make these constexpr since they're defaulted
fs::path eden_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir);
fs::path config_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir);
fs::path cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
fs::path shader_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
eden_dir.make_preferred();
config_dir.make_preferred();
cache_dir.make_preferred();
shader_dir.make_preferred();
const fs::path eden_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir);
const fs::path config_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir);
const fs::path cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
const fs::path shader_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
try {
fs::remove_all(eden_dir);
@@ -60,8 +55,8 @@ void MigrationWorker::process()
std::exit(-1);
}
// Windows doesn't need any more links, because cache and config
// are already children of the root directory
// Windows doesn't need any more links, because cache and config
// are already children of the root directory
#ifndef WIN32
if (fs::is_directory(legacy_config_dir)) {
Common::FS::CreateSymlink(legacy_config_dir, config_dir);
@@ -74,7 +69,7 @@ void MigrationWorker::process()
success_text.append(tr("\n\nNote that your configuration and data will be shared with %1.\n"
"If this is not desirable, delete the following files:\n%2\n%3\n%4")
.arg(selected_emu.name(),
.arg(selected_legacy_emu.name(),
QString::fromStdString(eden_dir.string()),
QString::fromStdString(config_dir.string()),
QString::fromStdString(cache_dir.string())));
@@ -84,8 +79,8 @@ void MigrationWorker::process()
// Rename directories if deletion is requested (achieves the same result)
fs::rename(legacy_user_dir, eden_dir);
// Windows doesn't need any more renames, because cache and config
// are already children of the root directory
// Windows doesn't need any more renames, because cache and config
// are already children of the root directory
#ifndef WIN32
if (fs::is_directory(legacy_config_dir)) {
fs::rename(legacy_config_dir, config_dir);
@@ -101,8 +96,8 @@ void MigrationWorker::process()
// Default behavior: copy
fs::copy(legacy_user_dir, eden_dir, copy_options);
// Windows doesn't need any more copies, because cache and config
// are already children of the root directory
// Windows doesn't need any more copies, because cache and config
// are already children of the root directory
#ifndef WIN32
if (fs::is_directory(legacy_config_dir)) {
fs::copy(legacy_config_dir, config_dir, copy_options);

View File

@@ -7,12 +7,14 @@
#include <QObject>
#include "common/fs/path_util.h"
using namespace Common::FS;
typedef struct Emulator {
const char *m_name;
Common::FS::EmuPath e_user_dir;
Common::FS::EmuPath e_config_dir;
Common::FS::EmuPath e_cache_dir;
EmuPath e_user_dir;
EmuPath e_config_dir;
EmuPath e_cache_dir;
const std::string get_user_dir() const {
return Common::FS::GetLegacyPath(e_user_dir).string();
@@ -33,13 +35,11 @@ typedef struct Emulator {
}
} Emulator;
#define STRUCT_EMU(name, enumName) Emulator{name, Common::FS::enumName##Dir, Common::FS::enumName##ConfigDir, Common::FS::enumName##CacheDir}
static constexpr std::array<Emulator, 4> legacy_emus = {
STRUCT_EMU(QT_TR_NOOP("Citron"), Citron),
STRUCT_EMU(QT_TR_NOOP("Sudachi"), Sudachi),
STRUCT_EMU(QT_TR_NOOP("Suyu"), Suyu),
STRUCT_EMU(QT_TR_NOOP("Yuzu"), Yuzu),
Emulator{QT_TR_NOOP("Citron"), CitronDir, CitronConfigDir, CitronCacheDir},
Emulator{QT_TR_NOOP("Sudachi"), SudachiDir, SudachiConfigDir, SudachiCacheDir},
Emulator{QT_TR_NOOP("Suyu"), SuyuDir, SuyuConfigDir, SuyuCacheDir},
Emulator{QT_TR_NOOP("Yuzu"), YuzuDir, YuzuConfigDir, YuzuCacheDir},
};
class MigrationWorker : public QObject
@@ -52,7 +52,7 @@ public:
Link,
};
MigrationWorker(const Emulator selected_emu,
MigrationWorker(const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationStrategy strategy);
@@ -64,7 +64,7 @@ signals:
void error(const QString &error_message);
private:
Emulator selected_emu;
Emulator selected_legacy_emu;
bool clear_shader_cache;
MigrationStrategy strategy;
QString success_text = tr("Data was migrated successfully.");

View File

@@ -15,7 +15,7 @@
#include "core/internal_network/network_interface.h"
#include "network/network.h"
#include "ui_direct_connect.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "yuzu/multiplayer/client_room.h"
#include "yuzu/multiplayer/direct_connect.h"
#include "yuzu/multiplayer/message.h"

View File

@@ -20,7 +20,7 @@
#include "network/announce_multiplayer_session.h"
#include "ui_host_room.h"
#include "yuzu/game_list_p.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "yuzu/multiplayer/host_room.h"
#include "yuzu/multiplayer/message.h"
#include "yuzu/multiplayer/state.h"

View File

@@ -15,7 +15,7 @@
#include "network/network.h"
#include "ui_lobby.h"
#include "yuzu/game_list_p.h"
#include "yuzu/main_window.h"
#include "yuzu/main.h"
#include "yuzu/multiplayer/client_room.h"
#include "yuzu/multiplayer/lobby.h"
#include "yuzu/multiplayer/lobby_p.h"

View File

@@ -1,25 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "qt_common/abstract/frontend.h"
#include "ryujinx_dialog.h"
#include "qt_common/util/fs.h"
#include "ui_ryujinx_dialog.h"
#include <filesystem>
namespace fs = std::filesystem;
RyujinxDialog::RyujinxDialog(std::filesystem::path eden_path,
std::filesystem::path ryu_path,
QWidget *parent)
: QDialog(parent)
, ui(new Ui::RyujinxDialog)
, m_eden(eden_path.make_preferred())
, m_ryu(ryu_path.make_preferred())
, ui(new Ui::RyujinxDialog)
, m_eden(eden_path.make_preferred())
, m_ryu(ryu_path.make_preferred())
{
ui->setupUi(this);
connect(ui->eden, &QPushButton::clicked, this, &RyujinxDialog::fromEden);
connect(ui->ryujinx, &QPushButton::clicked, this, &RyujinxDialog::fromRyujinx);
connect(ui->cancel, &QPushButton::clicked, this, &RyujinxDialog::reject);
}
RyujinxDialog::~RyujinxDialog()
@@ -30,21 +30,7 @@ RyujinxDialog::~RyujinxDialog()
void RyujinxDialog::fromEden()
{
accept();
// Workaround: Ryujinx deletes and re-creates its directory structure???
// So we just copy Eden's data to Ryujinx and then link the other way
namespace fs = std::filesystem;
try {
fs::remove_all(m_ryu);
fs::create_directories(m_ryu);
fs::copy(m_eden, m_ryu, fs::copy_options::recursive);
} catch (std::exception &e) {
QtCommon::Frontend::Critical(tr("Failed to link save data"),
tr("OS returned error: %1").arg(QString::fromStdString(e.what())));
}
// ?ploo
QtCommon::FS::LinkRyujinx(m_ryu, m_eden);
QtCommon::FS::LinkRyujinx(m_eden, m_ryu);
}
void RyujinxDialog::fromRyujinx()

View File

@@ -23,6 +23,8 @@
#include <QThread>
#include <filesystem>
namespace fs = std::filesystem;
UserDataMigrator::UserDataMigrator(QMainWindow *main_window)
{
// NOTE: Logging is not initialized yet, do not produce logs here.
@@ -30,7 +32,7 @@ UserDataMigrator::UserDataMigrator(QMainWindow *main_window)
// Check migration if config directory does not exist
// TODO: ProfileManager messes with us a bit here, and force-creates the /nand/system/save/8000000000000010/su/avators/profiles.dat
// file. Find a way to reorder operations and have it create after this guy runs.
if (!std::filesystem::is_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir))) {
if (!fs::is_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir))) {
ShowMigrationPrompt(main_window);
}
}
@@ -38,7 +40,23 @@ UserDataMigrator::UserDataMigrator(QMainWindow *main_window)
void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
{
namespace fs = std::filesystem;
using namespace QtCommon::StringLookup;
// define strings here for easy access
QString prompt_prefix_text = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationPromptPrefix);
QString migration_prompt_message = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationPrompt);
QString clear_shader_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipClearShader);
QString keep_old_data_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipKeepOld);
QString clear_old_data_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipClearOld);
QString link_old_dir_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipLinkOld);
// actual migration code
MigrationDialog migration_prompt;
migration_prompt.setWindowTitle(QObject::tr("Migration"));
@@ -51,11 +69,11 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
#define BUTTON(clazz, name, text, tooltip, checkState) \
clazz *name = new clazz(&migration_prompt); \
name->setText(text); \
name->setToolTip(Lookup(tooltip)); \
name->setToolTip(tooltip); \
name->setChecked(checkState); \
migration_prompt.addBox(name);
BUTTON(QCheckBox, clear_shaders, QObject::tr("Clear Shader Cache"), MigrationTooltipClearShader, true)
BUTTON(QCheckBox, clear_shaders, QObject::tr("Clear Shader Cache"), clear_shader_tooltip, true)
u32 id = 0;
@@ -63,9 +81,9 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
BUTTON(QRadioButton, name, text, tooltip, checkState) \
group->addButton(name, ++id);
RADIO(keep_old, QObject::tr("Keep Old Data"), MigrationTooltipKeepOld, true)
RADIO(clear_old, QObject::tr("Clear Old Data"), MigrationTooltipClearOld, false)
RADIO(link_old, QObject::tr("Link Old Directory"), MigrationTooltipLinkOld, false)
RADIO(keep_old, QObject::tr("Keep Old Data"), keep_old_data_tooltip, true)
RADIO(clear_old, QObject::tr("Clear Old Data"), clear_old_data_tooltip, false)
RADIO(link_old, QObject::tr("Link Old Directory"), link_old_dir_tooltip, false)
#undef RADIO
#undef BUTTON
@@ -83,7 +101,7 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
// makes my life easier
qRegisterMetaType<Emulator>();
QString prompt_text = Lookup(MigrationPromptPrefix);
QString prompt_text = prompt_prefix_text;
// natural language processing is a nightmare
for (const Emulator &emu : found) {
@@ -96,7 +114,7 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
}
prompt_text.append(QObject::tr("\n\n"));
prompt_text = prompt_text % QStringLiteral("\n\n") % Lookup(MigrationPrompt);
prompt_text = prompt_text % QStringLiteral("\n\n") % migration_prompt_message;
migration_prompt.setText(prompt_text);
migration_prompt.addButton(QObject::tr("No"), true);
@@ -109,12 +127,24 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
return ShowMigrationCancelledMessage(main_window);
}
MigrationWorker::MigrationStrategy strategy = static_cast<MigrationWorker::MigrationStrategy>(
group->checkedId());
MigrationWorker::MigrationStrategy strategy;
selected_emu = button->property("emulator").value<Emulator>();
switch (group->checkedId()) {
default:
[[fallthrough]];
case 1:
strategy = MigrationWorker::MigrationStrategy::Copy;
break;
case 2:
strategy = MigrationWorker::MigrationStrategy::Move;
break;
case 3:
strategy = MigrationWorker::MigrationStrategy::Link;
break;
}
MigrateUserData(main_window,
button->property("emulator").value<Emulator>(),
clear_shaders->isChecked(),
strategy);
}
@@ -131,9 +161,12 @@ void UserDataMigrator::ShowMigrationCancelledMessage(QMainWindow *main_window)
}
void UserDataMigrator::MigrateUserData(QMainWindow *main_window,
const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationWorker::MigrationStrategy strategy)
{
selected_emu = selected_legacy_emu;
// Create a dialog to let the user know it's migrating
QProgressDialog *progress = new QProgressDialog(main_window);
progress->setWindowTitle(QObject::tr("Migrating"));
@@ -143,7 +176,7 @@ void UserDataMigrator::MigrateUserData(QMainWindow *main_window,
progress->setWindowModality(Qt::WindowModality::ApplicationModal);
QThread *thread = new QThread(main_window);
MigrationWorker *worker = new MigrationWorker(selected_emu, clear_shader_cache, strategy);
MigrationWorker *worker = new MigrationWorker(selected_legacy_emu, clear_shader_cache, strategy);
worker->moveToThread(thread);
thread->connect(thread, &QThread::started, worker, &MigrationWorker::process);

View File

@@ -22,6 +22,7 @@ private:
void ShowMigrationPrompt(QMainWindow* main_window);
void ShowMigrationCancelledMessage(QMainWindow* main_window);
void MigrateUserData(QMainWindow* main_window,
const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationWorker::MigrationStrategy strategy);
};

View File

@@ -8,11 +8,7 @@
#include <cmath>
#include <QPainter>
#include "applets/qt_profile_select.h"
#include "common/logging/log.h"
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/profile_manager.h"
#include "qt_common/qt_common.h"
#include "yuzu/util/util.h"
#ifdef _WIN32
@@ -157,49 +153,3 @@ bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image)
return false;
#endif
}
const std::optional<Common::UUID> GetProfileID() {
// if there's only a single profile, the user probably wants to use that... right?
const auto& profiles = QtCommon::system->GetProfileManager().FindExistingProfileUUIDs();
if (profiles.size() == 1) {
return profiles[0];
}
const auto select_profile = [] {
const Core::Frontend::ProfileSelectParameters parameters{
.mode = Service::AM::Frontend::UiMode::UserSelector,
.invalid_uid_list = {},
.display_options = {},
.purpose = Service::AM::Frontend::UserSelectionPurpose::General,
};
QtProfileSelectionDialog dialog(*QtCommon::system, QtCommon::rootObject, parameters);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Rejected) {
return -1;
}
return dialog.GetIndex();
};
const auto index = select_profile();
if (index == -1) {
return std::nullopt;
}
const auto uuid =
QtCommon::system->GetProfileManager().GetUser(static_cast<std::size_t>(index));
ASSERT(uuid);
return uuid;
}
std::string GetProfileIDString() {
const auto uuid = GetProfileID();
if (!uuid)
return "";
auto user_id = uuid->AsU128();
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
}

View File

@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -9,7 +6,6 @@
#include <filesystem>
#include <QFont>
#include <QString>
#include "common/uuid.h"
/// Returns a QFont object appropriate to use as a monospace font for debugging widgets, etc.
[[nodiscard]] QFont GetMonospaceFont();
@@ -31,15 +27,3 @@
* @return bool If the operation succeeded
*/
[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image);
/**
* Prompt the user for a profile ID. If there is only one valid profile, returns that profile.
* @return The selected profile, or an std::nullopt if none were selected
*/
const std::optional<Common::UUID> GetProfileID();
/**
* Prompt the user for a profile ID. If there is only one valid profile, returns that profile.
* @return A string representation of the selected profile, or an empty string if none were seleeced
*/
std::string GetProfileIDString();